1// Copyright 2017 Google Inc. All rights reserved.
2//
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6//
7//     http://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
14
15package python
16
17// This file contains Ninja build actions for building Python program.
18
19import (
20	"strings"
21
22	"android/soong/android"
23
24	"github.com/google/blueprint"
25	_ "github.com/google/blueprint/bootstrap"
26)
27
28var (
29	pctx = android.NewPackageContext("android/soong/python")
30
31	zip = pctx.AndroidStaticRule("zip",
32		blueprint.RuleParams{
33			Command:     `$parCmd -o $out $args`,
34			CommandDeps: []string{"$parCmd"},
35		},
36		"args")
37
38	combineZip = pctx.AndroidStaticRule("combineZip",
39		blueprint.RuleParams{
40			Command:     `$mergeParCmd $out $in`,
41			CommandDeps: []string{"$mergeParCmd"},
42		},
43	)
44
45	hostPar = pctx.AndroidStaticRule("hostPar",
46		blueprint.RuleParams{
47			Command: `sed -e 's/%interpreter%/$interp/g' -e 's/%main%/$main/g' $template > $stub && ` +
48				`echo "#!/usr/bin/env python" >${out}.prefix &&` +
49				`$mergeParCmd -p --prefix ${out}.prefix -pm $stub $out $srcsZips && ` +
50				`chmod +x $out && (rm -f $stub; rm -f ${out}.prefix)`,
51			CommandDeps: []string{"$mergeParCmd"},
52		},
53		"interp", "main", "template", "stub", "srcsZips")
54
55	embeddedPar = pctx.AndroidStaticRule("embeddedPar",
56		blueprint.RuleParams{
57			Command: `rm -f $out.main && ` +
58				`sed 's/ENTRY_POINT/$main/' build/soong/python/scripts/main.py >$out.main &&` +
59				`$mergeParCmd -p -pm $out.main --prefix $launcher $out $srcsZips && ` +
60				`chmod +x $out && rm -rf $out.main`,
61			CommandDeps: []string{"$mergeParCmd", "$parCmd", "build/soong/python/scripts/main.py"},
62		},
63		"main", "srcsZips", "launcher")
64
65	embeddedParNoMain = pctx.AndroidStaticRule("embeddedParNoMain",
66		blueprint.RuleParams{
67			Command: `$mergeParCmd -p --prefix $launcher $out $srcsZips && ` +
68				`chmod +x $out`,
69			CommandDeps: []string{"$mergeParCmd"},
70		},
71		"srcsZips", "launcher")
72)
73
74func init() {
75	pctx.Import("github.com/google/blueprint/bootstrap")
76	pctx.Import("android/soong/android")
77
78	pctx.HostBinToolVariable("parCmd", "soong_zip")
79	pctx.HostBinToolVariable("mergeParCmd", "merge_zips")
80}
81
82func registerBuildActionForParFile(ctx android.ModuleContext, embeddedLauncher bool,
83	launcherPath android.OptionalPath, interpreter, main, binName string,
84	srcsZips android.Paths) android.Path {
85
86	// .intermediate output path for bin executable.
87	binFile := android.PathForModuleOut(ctx, binName)
88
89	// implicit dependency for parFile build action.
90	implicits := srcsZips
91
92	if !embeddedLauncher {
93		// the path of stub_template_host.txt from source tree.
94		template := android.PathForSource(ctx, StubTemplateHost)
95		implicits = append(implicits, template)
96
97		// intermediate output path for __main__.py
98		stub := android.PathForModuleOut(ctx, mainFileName).String()
99
100		ctx.Build(pctx, android.BuildParams{
101			Rule:        hostPar,
102			Description: "host python archive",
103			Output:      binFile,
104			Implicits:   implicits,
105			Args: map[string]string{
106				"interp":   strings.Replace(interpreter, "/", `\/`, -1),
107				"main":     strings.Replace(main, "/", `\/`, -1),
108				"template": template.String(),
109				"stub":     stub,
110				"srcsZips": strings.Join(srcsZips.Strings(), " "),
111			},
112		})
113	} else if launcherPath.Valid() {
114		// added launcherPath to the implicits Ninja dependencies.
115		implicits = append(implicits, launcherPath.Path())
116
117		if main == "" {
118			ctx.Build(pctx, android.BuildParams{
119				Rule:        embeddedParNoMain,
120				Description: "embedded python archive",
121				Output:      binFile,
122				Implicits:   implicits,
123				Args: map[string]string{
124					"srcsZips": strings.Join(srcsZips.Strings(), " "),
125					"launcher": launcherPath.String(),
126				},
127			})
128		} else {
129			ctx.Build(pctx, android.BuildParams{
130				Rule:        embeddedPar,
131				Description: "embedded python archive",
132				Output:      binFile,
133				Implicits:   implicits,
134				Args: map[string]string{
135					"main":     strings.Replace(strings.TrimSuffix(main, pyExt), "/", ".", -1),
136					"srcsZips": strings.Join(srcsZips.Strings(), " "),
137					"launcher": launcherPath.String(),
138				},
139			})
140		}
141	}
142
143	return binFile
144}
145