• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1// Copyright 2016 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 cc
16
17import (
18	"fmt"
19	"path/filepath"
20	"strings"
21
22	"github.com/google/blueprint"
23
24	"android/soong/android"
25)
26
27var (
28	versionBionicHeaders = pctx.AndroidStaticRule("versionBionicHeaders",
29		blueprint.RuleParams{
30			// The `&& touch $out` isn't really necessary, but Blueprint won't
31			// let us have only implicit outputs.
32			Command:     "$versionerCmd -o $outDir $srcDir $depsPath && touch $out",
33			CommandDeps: []string{"$versionerCmd"},
34		},
35		"depsPath", "srcDir", "outDir")
36
37	preprocessNdkHeader = pctx.AndroidStaticRule("preprocessNdkHeader",
38		blueprint.RuleParams{
39			Command:     "$preprocessor -o $out $in",
40			CommandDeps: []string{"$preprocessor"},
41		},
42		"preprocessor")
43)
44
45func init() {
46	pctx.SourcePathVariable("versionerCmd", "prebuilts/clang-tools/${config.HostPrebuiltTag}/bin/versioner")
47}
48
49// Returns the NDK base include path for use with sdk_version current. Usable with -I.
50func getCurrentIncludePath(ctx android.ModuleContext) android.InstallPath {
51	return getNdkSysrootBase(ctx).Join(ctx, "usr/include")
52}
53
54type headerProperties struct {
55	// Base directory of the headers being installed. As an example:
56	//
57	// ndk_headers {
58	//     name: "foo",
59	//     from: "include",
60	//     to: "",
61	//     srcs: ["include/foo/bar/baz.h"],
62	// }
63	//
64	// Will install $SYSROOT/usr/include/foo/bar/baz.h. If `from` were instead
65	// "include/foo", it would have installed $SYSROOT/usr/include/bar/baz.h.
66	From *string
67
68	// Install path within the sysroot. This is relative to usr/include.
69	To *string
70
71	// List of headers to install. Glob compatible. Common case is "include/**/*.h".
72	Srcs []string `android:"path"`
73
74	// Source paths that should be excluded from the srcs glob.
75	Exclude_srcs []string `android:"path"`
76
77	// Path to the NOTICE file associated with the headers.
78	License *string `android:"path"`
79
80	// True if this API is not yet ready to be shipped in the NDK. It will be
81	// available in the platform for testing, but will be excluded from the
82	// sysroot provided to the NDK proper.
83	Draft bool
84}
85
86type headerModule struct {
87	android.ModuleBase
88
89	properties headerProperties
90
91	installPaths android.Paths
92	licensePath  android.Path
93}
94
95func getHeaderInstallDir(ctx android.ModuleContext, header android.Path, from string,
96	to string) android.InstallPath {
97	// Output path is the sysroot base + "usr/include" + to directory + directory component
98	// of the file without the leading from directory stripped.
99	//
100	// Given:
101	// sysroot base = "ndk/sysroot"
102	// from = "include/foo"
103	// to = "bar"
104	// header = "include/foo/woodly/doodly.h"
105	// output path = "ndk/sysroot/usr/include/bar/woodly/doodly.h"
106
107	// full/platform/path/to/include/foo
108	fullFromPath := android.PathForModuleSrc(ctx, from)
109
110	// full/platform/path/to/include/foo/woodly
111	headerDir := filepath.Dir(header.String())
112
113	// woodly
114	strippedHeaderDir, err := filepath.Rel(fullFromPath.String(), headerDir)
115	if err != nil {
116		ctx.ModuleErrorf("filepath.Rel(%q, %q) failed: %s", headerDir,
117			fullFromPath.String(), err)
118	}
119
120	// full/platform/path/to/sysroot/usr/include/bar/woodly
121	installDir := getCurrentIncludePath(ctx).Join(ctx, to, strippedHeaderDir)
122
123	// full/platform/path/to/sysroot/usr/include/bar/woodly/doodly.h
124	return installDir
125}
126
127func (m *headerModule) GenerateAndroidBuildActions(ctx android.ModuleContext) {
128	if String(m.properties.License) == "" {
129		ctx.PropertyErrorf("license", "field is required")
130	}
131
132	m.licensePath = android.PathForModuleSrc(ctx, String(m.properties.License))
133
134	// When generating NDK prebuilts, skip installing MIPS headers,
135	// but keep them when doing regular platform build.
136	// Ndk_abis property is only set to true with build/soong/scripts/build-ndk-prebuilts.sh
137	// TODO: Revert this once MIPS is supported in NDK again.
138	if ctx.Config().NdkAbis() && strings.Contains(ctx.ModuleName(), "mips") {
139		return
140	}
141
142	srcFiles := android.PathsForModuleSrcExcludes(ctx, m.properties.Srcs, m.properties.Exclude_srcs)
143	for _, header := range srcFiles {
144		installDir := getHeaderInstallDir(ctx, header, String(m.properties.From),
145			String(m.properties.To))
146		installedPath := ctx.InstallFile(installDir, header.Base(), header)
147		installPath := installDir.Join(ctx, header.Base())
148		if installPath != installedPath {
149			panic(fmt.Sprintf(
150				"expected header install path (%q) not equal to actual install path %q",
151				installPath, installedPath))
152		}
153		m.installPaths = append(m.installPaths, installPath)
154	}
155
156	if len(m.installPaths) == 0 {
157		ctx.ModuleErrorf("srcs %q matched zero files", m.properties.Srcs)
158	}
159}
160
161// ndk_headers installs the sets of ndk headers defined in the srcs property
162// to the sysroot base + "usr/include" + to directory + directory component.
163// ndk_headers requires the license file to be specified. Example:
164//
165//    Given:
166//    sysroot base = "ndk/sysroot"
167//    from = "include/foo"
168//    to = "bar"
169//    header = "include/foo/woodly/doodly.h"
170//    output path = "ndk/sysroot/usr/include/bar/woodly/doodly.h"
171func ndkHeadersFactory() android.Module {
172	module := &headerModule{}
173	module.AddProperties(&module.properties)
174	android.InitAndroidModule(module)
175	return module
176}
177
178type versionedHeaderProperties struct {
179	// Base directory of the headers being installed. As an example:
180	//
181	// versioned_ndk_headers {
182	//     name: "foo",
183	//     from: "include",
184	//     to: "",
185	// }
186	//
187	// Will install $SYSROOT/usr/include/foo/bar/baz.h. If `from` were instead
188	// "include/foo", it would have installed $SYSROOT/usr/include/bar/baz.h.
189	From *string
190
191	// Install path within the sysroot. This is relative to usr/include.
192	To *string
193
194	// Path to the NOTICE file associated with the headers.
195	License *string
196
197	// True if this API is not yet ready to be shipped in the NDK. It will be
198	// available in the platform for testing, but will be excluded from the
199	// sysroot provided to the NDK proper.
200	Draft bool
201}
202
203// Like ndk_headers, but preprocesses the headers with the bionic versioner:
204// https://android.googlesource.com/platform/bionic/+/master/tools/versioner/README.md.
205//
206// Unlike ndk_headers, we don't operate on a list of sources but rather a whole directory, the
207// module does not have the srcs property, and operates on a full directory (the `from` property).
208//
209// Note that this is really only built to handle bionic/libc/include.
210type versionedHeaderModule struct {
211	android.ModuleBase
212
213	properties versionedHeaderProperties
214
215	installPaths android.Paths
216	licensePath  android.Path
217}
218
219func (m *versionedHeaderModule) GenerateAndroidBuildActions(ctx android.ModuleContext) {
220	if String(m.properties.License) == "" {
221		ctx.PropertyErrorf("license", "field is required")
222	}
223
224	m.licensePath = android.PathForModuleSrc(ctx, String(m.properties.License))
225
226	fromSrcPath := android.PathForModuleSrc(ctx, String(m.properties.From))
227	toOutputPath := getCurrentIncludePath(ctx).Join(ctx, String(m.properties.To))
228	srcFiles := ctx.GlobFiles(filepath.Join(fromSrcPath.String(), "**/*.h"), nil)
229	var installPaths []android.WritablePath
230	for _, header := range srcFiles {
231		installDir := getHeaderInstallDir(ctx, header, String(m.properties.From), String(m.properties.To))
232		installPath := installDir.Join(ctx, header.Base())
233		installPaths = append(installPaths, installPath)
234		m.installPaths = append(m.installPaths, installPath)
235	}
236
237	if len(m.installPaths) == 0 {
238		ctx.ModuleErrorf("glob %q matched zero files", String(m.properties.From))
239	}
240
241	processHeadersWithVersioner(ctx, fromSrcPath, toOutputPath, srcFiles, installPaths)
242}
243
244func processHeadersWithVersioner(ctx android.ModuleContext, srcDir, outDir android.Path,
245	srcFiles android.Paths, installPaths []android.WritablePath) android.Path {
246	// The versioner depends on a dependencies directory to simplify determining include paths
247	// when parsing headers. This directory contains architecture specific directories as well
248	// as a common directory, each of which contains symlinks to the actually directories to
249	// be included.
250	//
251	// ctx.Glob doesn't follow symlinks, so we need to do this ourselves so we correctly
252	// depend on these headers.
253	// TODO(http://b/35673191): Update the versioner to use a --sysroot.
254	depsPath := android.PathForSource(ctx, "bionic/libc/versioner-dependencies")
255	depsGlob := ctx.Glob(filepath.Join(depsPath.String(), "**/*"), nil)
256	for i, path := range depsGlob {
257		if ctx.IsSymlink(path) {
258			dest := ctx.Readlink(path)
259			// Additional .. to account for the symlink itself.
260			depsGlob[i] = android.PathForSource(
261				ctx, filepath.Clean(filepath.Join(path.String(), "..", dest)))
262		}
263	}
264
265	timestampFile := android.PathForModuleOut(ctx, "versioner.timestamp")
266	ctx.Build(pctx, android.BuildParams{
267		Rule:            versionBionicHeaders,
268		Description:     "versioner preprocess " + srcDir.Rel(),
269		Output:          timestampFile,
270		Implicits:       append(srcFiles, depsGlob...),
271		ImplicitOutputs: installPaths,
272		Args: map[string]string{
273			"depsPath": depsPath.String(),
274			"srcDir":   srcDir.String(),
275			"outDir":   outDir.String(),
276		},
277	})
278
279	return timestampFile
280}
281
282// versioned_ndk_headers preprocesses the headers with the bionic versioner:
283// https://android.googlesource.com/platform/bionic/+/master/tools/versioner/README.md.
284// Unlike the ndk_headers soong module, versioned_ndk_headers operates on a
285// directory level specified in `from` property. This is only used to process
286// the bionic/libc/include directory.
287func versionedNdkHeadersFactory() android.Module {
288	module := &versionedHeaderModule{}
289
290	module.AddProperties(&module.properties)
291
292	android.InitAndroidModule(module)
293
294	return module
295}
296
297// preprocessed_ndk_header {
298//     name: "foo",
299//     preprocessor: "foo.sh",
300//     srcs: [...],
301//     to: "android",
302// }
303//
304// Will invoke the preprocessor as:
305//     $preprocessor -o $SYSROOT/usr/include/android/needs_preproc.h $src
306// For each src in srcs.
307type preprocessedHeadersProperties struct {
308	// The preprocessor to run. Must be a program inside the source directory
309	// with no dependencies.
310	Preprocessor *string
311
312	// Source path to the files to be preprocessed.
313	Srcs []string
314
315	// Source paths that should be excluded from the srcs glob.
316	Exclude_srcs []string
317
318	// Install path within the sysroot. This is relative to usr/include.
319	To *string
320
321	// Path to the NOTICE file associated with the headers.
322	License *string
323
324	// True if this API is not yet ready to be shipped in the NDK. It will be
325	// available in the platform for testing, but will be excluded from the
326	// sysroot provided to the NDK proper.
327	Draft bool
328}
329
330type preprocessedHeadersModule struct {
331	android.ModuleBase
332
333	properties preprocessedHeadersProperties
334
335	installPaths android.Paths
336	licensePath  android.Path
337}
338
339func (m *preprocessedHeadersModule) GenerateAndroidBuildActions(ctx android.ModuleContext) {
340	if String(m.properties.License) == "" {
341		ctx.PropertyErrorf("license", "field is required")
342	}
343
344	preprocessor := android.PathForModuleSrc(ctx, String(m.properties.Preprocessor))
345	m.licensePath = android.PathForModuleSrc(ctx, String(m.properties.License))
346
347	srcFiles := android.PathsForModuleSrcExcludes(ctx, m.properties.Srcs, m.properties.Exclude_srcs)
348	installDir := getCurrentIncludePath(ctx).Join(ctx, String(m.properties.To))
349	for _, src := range srcFiles {
350		installPath := installDir.Join(ctx, src.Base())
351		m.installPaths = append(m.installPaths, installPath)
352
353		ctx.Build(pctx, android.BuildParams{
354			Rule:        preprocessNdkHeader,
355			Description: "preprocess " + src.Rel(),
356			Input:       src,
357			Output:      installPath,
358			Args: map[string]string{
359				"preprocessor": preprocessor.String(),
360			},
361		})
362	}
363
364	if len(m.installPaths) == 0 {
365		ctx.ModuleErrorf("srcs %q matched zero files", m.properties.Srcs)
366	}
367}
368
369// preprocessed_ndk_headers preprocesses all the ndk headers listed in the srcs
370// property by executing the command defined in the preprocessor property.
371func preprocessedNdkHeadersFactory() android.Module {
372	module := &preprocessedHeadersModule{}
373
374	module.AddProperties(&module.properties)
375
376	android.InitAndroidModule(module)
377
378	return module
379}
380