blob: a2486fdf5d709b4fa9a954f4947f32dd49b2fa88 [file] [log] [blame]
Dan Willemsen9fe14102021-07-13 21:52:04 -07001// Copyright (C) 2021 The Android Open Source Project
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 android_sdk
16
17import (
18 "fmt"
19 "io"
20 "path/filepath"
21 "strings"
22
23 "github.com/google/blueprint"
24 "github.com/google/blueprint/pathtools"
25 "github.com/google/blueprint/proptools"
26
27 "android/soong/android"
28 "android/soong/cc/config"
29)
30
31var pctx = android.NewPackageContext("android/soong/android_sdk")
32
33func init() {
34 registerBuildComponents(android.InitRegistrationContext)
35}
36
37func registerBuildComponents(ctx android.RegistrationContext) {
38 ctx.RegisterModuleType("android_sdk_repo_host", SdkRepoHostFactory)
39}
40
41type sdkRepoHost struct {
42 android.ModuleBase
43 android.PackagingBase
44
45 properties sdkRepoHostProperties
46
47 outputBaseName string
48 outputFile android.OptionalPath
Yu Liuddc28332024-08-09 22:48:30 +000049
50 // TODO(b/357908583): Temp field, remove this once we support Android Mk providers
51 installFile android.InstallPath
Dan Willemsen9fe14102021-07-13 21:52:04 -070052}
53
54type remapProperties struct {
55 From string
56 To string
57}
58
59type sdkRepoHostProperties struct {
60 // The top level directory to use for the SDK repo.
61 Base_dir *string
62
63 // List of src:dst mappings to rename files from `deps`.
64 Deps_remap []remapProperties `android:"arch_variant"`
65
66 // List of zip files to merge into the SDK repo.
67 Merge_zips []string `android:"arch_variant,path"`
68
69 // List of sources to include into the SDK repo. These are usually raw files, filegroups,
70 // or genrules, as most built modules should be referenced via `deps`.
71 Srcs []string `android:"arch_variant,path"`
72
73 // List of files to strip. This should be a list of files, not modules. This happens after
74 // `deps_remap` and `merge_zips` are applied, but before the `base_dir` is added.
75 Strip_files []string `android:"arch_variant"`
76}
77
78// android_sdk_repo_host defines an Android SDK repo containing host tools.
79//
80// This implementation is trying to be a faithful reproduction of how these sdk-repos were produced
81// in the Make system, which may explain some of the oddities (like `strip_files` not being
82// automatic)
83func SdkRepoHostFactory() android.Module {
84 return newSdkRepoHostModule()
85}
86
87func newSdkRepoHostModule() *sdkRepoHost {
88 s := &sdkRepoHost{}
89 s.AddProperties(&s.properties)
90 android.InitPackageModule(s)
91 android.InitAndroidMultiTargetsArchModule(s, android.HostSupported, android.MultilibCommon)
92 return s
93}
94
95type dependencyTag struct {
96 blueprint.BaseDependencyTag
97 android.PackagingItemAlwaysDepTag
98}
99
100// TODO(b/201696252): Evaluate whether licenses should be propagated through this dependency.
101func (d dependencyTag) PropagateLicenses() bool {
102 return false
103}
104
105var depTag = dependencyTag{}
106
107func (s *sdkRepoHost) DepsMutator(ctx android.BottomUpMutatorContext) {
108 s.AddDeps(ctx, depTag)
109}
110
111func (s *sdkRepoHost) GenerateAndroidBuildActions(ctx android.ModuleContext) {
112 dir := android.PathForModuleOut(ctx, "zip")
Bob Badoureef4c1c2022-05-16 12:20:04 -0700113 outputZipFile := dir.Join(ctx, "output.zip")
Dan Willemsen9fe14102021-07-13 21:52:04 -0700114 builder := android.NewRuleBuilder(pctx, ctx).
115 Sbox(dir, android.PathForModuleOut(ctx, "out.sbox.textproto")).
116 SandboxInputs()
117
118 // Get files from modules listed in `deps`
119 packageSpecs := s.GatherPackagingSpecs(ctx)
120
121 // Handle `deps_remap` renames
122 err := remapPackageSpecs(packageSpecs, s.properties.Deps_remap)
123 if err != nil {
124 ctx.PropertyErrorf("deps_remap", "%s", err.Error())
125 }
126
127 s.CopySpecsToDir(ctx, builder, packageSpecs, dir)
128
Colin Crossaa1cab02022-01-28 14:49:24 -0800129 noticeFile := android.PathForModuleOut(ctx, "NOTICES.txt")
Bob Badourc6ec9fb2022-06-08 15:59:35 -0700130 android.BuildNoticeTextOutputFromLicenseMetadata(
131 ctx, noticeFile, "", "",
132 []string{
133 android.PathForModuleInstall(ctx, "sdk-repo").String() + "/",
134 outputZipFile.String(),
135 })
Dan Willemsen9fe14102021-07-13 21:52:04 -0700136 builder.Command().Text("cp").
Colin Crossaa1cab02022-01-28 14:49:24 -0800137 Input(noticeFile).
Dan Willemsen9fe14102021-07-13 21:52:04 -0700138 Text(filepath.Join(dir.String(), "NOTICE.txt"))
139
140 // Handle `merge_zips` by extracting their contents into our tmpdir
141 for _, zip := range android.PathsForModuleSrc(ctx, s.properties.Merge_zips) {
142 builder.Command().
143 Text("unzip").
144 Flag("-DD").
145 Flag("-q").
146 FlagWithArg("-d ", dir.String()).
147 Input(zip)
148 }
149
150 // Copy files from `srcs` into our tmpdir
151 for _, src := range android.PathsForModuleSrc(ctx, s.properties.Srcs) {
152 builder.Command().
153 Text("cp").Input(src).Flag(dir.Join(ctx, src.Rel()).String())
154 }
155
156 // Handle `strip_files` by calling the necessary strip commands
157 //
158 // Note: this stripping logic was copied over from the old Make implementation
159 // It's not using the same flags as the regular stripping support, nor does it
160 // support the array of per-module stripping options. It would be nice if we
161 // pulled the stripped versions from the CC modules, but that doesn't exist
162 // for host tools today. (And not all the things we strip are CC modules today)
163 if ctx.Darwin() {
164 macStrip := config.MacStripPath(ctx)
165 for _, strip := range s.properties.Strip_files {
166 builder.Command().
167 Text(macStrip).Flag("-x").
168 Flag(dir.Join(ctx, strip).String())
169 }
170 } else {
Cole Faustdf34caf2023-12-05 14:44:42 -0800171 llvmObjCopy := config.ClangPath(ctx, "bin/llvm-objcopy")
Dan Willemsen9fe14102021-07-13 21:52:04 -0700172 llvmStrip := config.ClangPath(ctx, "bin/llvm-strip")
Yabin Cui294f8392023-06-07 21:58:46 +0000173 llvmLib := config.ClangPath(ctx, "lib/x86_64-unknown-linux-gnu/libc++.so")
Dan Willemsen9fe14102021-07-13 21:52:04 -0700174 for _, strip := range s.properties.Strip_files {
Cole Faustdf34caf2023-12-05 14:44:42 -0800175 cmd := builder.Command().Tool(llvmStrip).ImplicitTool(llvmLib).ImplicitTool(llvmObjCopy)
Dan Willemsen9fe14102021-07-13 21:52:04 -0700176 if !ctx.Windows() {
177 cmd.Flag("-x")
178 }
179 cmd.Flag(dir.Join(ctx, strip).String())
180 }
181 }
182
183 // Fix up the line endings of all text files. This also removes executable permissions.
184 builder.Command().
185 Text("find").
186 Flag(dir.String()).
187 Flag("-name '*.aidl' -o -name '*.css' -o -name '*.html' -o -name '*.java'").
188 Flag("-o -name '*.js' -o -name '*.prop' -o -name '*.template'").
189 Flag("-o -name '*.txt' -o -name '*.windows' -o -name '*.xml' -print0").
190 // Using -n 500 for xargs to limit the max number of arguments per call to line_endings
191 // to 500. This avoids line_endings failing with "arguments too long".
192 Text("| xargs -0 -n 500 ").
193 BuiltTool("line_endings").
194 Flag("unix")
195
196 // Exclude some file types (roughly matching sdk.exclude.atree)
197 builder.Command().
198 Text("find").
199 Flag(dir.String()).
200 Flag("'('").
201 Flag("-name '.*' -o -name '*~' -o -name 'Makefile' -o -name 'Android.mk' -o").
202 Flag("-name '.*.swp' -o -name '.DS_Store' -o -name '*.pyc' -o -name 'OWNERS' -o").
203 Flag("-name 'MODULE_LICENSE_*' -o -name '*.ezt' -o -name 'Android.bp'").
204 Flag("')' -print0").
205 Text("| xargs -0 -r rm -rf")
206 builder.Command().
207 Text("find").
208 Flag(dir.String()).
209 Flag("-name '_*' ! -name '__*' -print0").
210 Text("| xargs -0 -r rm -rf")
211
212 if ctx.Windows() {
213 // Fix EOL chars to make window users happy
214 builder.Command().
215 Text("find").
216 Flag(dir.String()).
217 Flag("-maxdepth 2 -name '*.bat' -type f -print0").
218 Text("| xargs -0 -r unix2dos")
219 }
220
221 // Zip up our temporary directory as the sdk-repo
Dan Willemsen9fe14102021-07-13 21:52:04 -0700222 builder.Command().
223 BuiltTool("soong_zip").
224 FlagWithOutput("-o ", outputZipFile).
225 FlagWithArg("-P ", proptools.StringDefault(s.properties.Base_dir, ".")).
226 FlagWithArg("-C ", dir.String()).
227 FlagWithArg("-D ", dir.String())
228 builder.Command().Text("rm").Flag("-rf").Text(dir.String())
229
230 builder.Build("build_sdk_repo", "Creating sdk-repo-"+s.BaseModuleName())
231
232 osName := ctx.Os().String()
233 if osName == "linux_glibc" {
234 osName = "linux"
235 }
236 name := fmt.Sprintf("sdk-repo-%s-%s", osName, s.BaseModuleName())
237
238 s.outputBaseName = name
239 s.outputFile = android.OptionalPathForPath(outputZipFile)
Yu Liuddc28332024-08-09 22:48:30 +0000240 installPath := android.PathForModuleInstall(ctx, "sdk-repo")
241 name = name + ".zip"
242 ctx.InstallFile(installPath, name, outputZipFile)
243 // TODO(b/357908583): Temp field, remove this once we support Android Mk providers
244 s.installFile = installPath.Join(ctx, name)
Dan Willemsen9fe14102021-07-13 21:52:04 -0700245}
246
247func (s *sdkRepoHost) AndroidMk() android.AndroidMkData {
248 return android.AndroidMkData{
249 Custom: func(w io.Writer, name, prefix, moduleDir string, data android.AndroidMkData) {
Dan Willemsen9fe14102021-07-13 21:52:04 -0700250 fmt.Fprintln(w, ".PHONY:", name, "sdk_repo", "sdk-repo-"+name)
Yu Liuddc28332024-08-09 22:48:30 +0000251 fmt.Fprintln(w, "sdk_repo", "sdk-repo-"+name+":", s.installFile.String())
Dan Willemsen9fe14102021-07-13 21:52:04 -0700252
Jeongik Cha4e49bbd2023-04-26 21:06:24 +0900253 fmt.Fprintf(w, "$(call dist-for-goals,sdk_repo sdk-repo-%s,%s:%s-FILE_NAME_TAG_PLACEHOLDER.zip)\n\n", s.BaseModuleName(), s.outputFile.String(), s.outputBaseName)
Dan Willemsen9fe14102021-07-13 21:52:04 -0700254 },
255 }
256}
257
258func remapPackageSpecs(specs map[string]android.PackagingSpec, remaps []remapProperties) error {
259 for _, remap := range remaps {
260 for path, spec := range specs {
261 if match, err := pathtools.Match(remap.From, path); err != nil {
262 return fmt.Errorf("Error parsing %q: %v", remap.From, err)
263 } else if match {
264 newPath := remap.To
265 if pathtools.IsGlob(remap.From) {
266 rel, err := filepath.Rel(constantPartOfPattern(remap.From), path)
267 if err != nil {
268 return fmt.Errorf("Error handling %q", path)
269 }
270 newPath = filepath.Join(remap.To, rel)
271 }
272 delete(specs, path)
273 spec.SetRelPathInPackage(newPath)
274 specs[newPath] = spec
275 }
276 }
277 }
278 return nil
279}
280
281func constantPartOfPattern(pattern string) string {
282 ret := ""
283 for pattern != "" {
284 var first string
285 first, pattern = splitFirst(pattern)
286 if pathtools.IsGlob(first) {
287 return ret
288 }
289 ret = filepath.Join(ret, first)
290 }
291 return ret
292}
293
294func splitFirst(path string) (string, string) {
295 i := strings.IndexRune(path, filepath.Separator)
296 if i < 0 {
297 return path, ""
298 }
299 return path[:i], path[i+1:]
300}