• 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	"path/filepath"
19
20	"android/soong/android"
21
22	"github.com/google/blueprint"
23)
24
25var (
26	preprocessNdkHeader = pctx.AndroidStaticRule("preprocessNdkHeader",
27		blueprint.RuleParams{
28			Command:     "$preprocessor -o $out $in",
29			CommandDeps: []string{"$preprocessor"},
30		},
31		"preprocessor")
32)
33
34// Returns the NDK base include path for use with sdk_version current. Usable with -I.
35func getCurrentIncludePath(ctx android.PathContext) android.OutputPath {
36	return getNdkSysrootBase(ctx).Join(ctx, "usr/include")
37}
38
39type headerProperties struct {
40	// Base directory of the headers being installed. As an example:
41	//
42	// ndk_headers {
43	//     name: "foo",
44	//     from: "include",
45	//     to: "",
46	//     srcs: ["include/foo/bar/baz.h"],
47	// }
48	//
49	// Will install $SYSROOT/usr/include/foo/bar/baz.h. If `from` were instead
50	// "include/foo", it would have installed $SYSROOT/usr/include/bar/baz.h.
51	From *string
52
53	// Install path within the sysroot. This is relative to usr/include.
54	To *string
55
56	// List of headers to install. Glob compatible. Common case is "include/**/*.h".
57	Srcs []string `android:"path"`
58
59	// Source paths that should be excluded from the srcs glob.
60	Exclude_srcs []string `android:"path"`
61
62	// Path to the NOTICE file associated with the headers.
63	License *string `android:"path"`
64
65	// Set to true if the headers installed by this module should skip
66	// verification. This step ensures that each header is self-contained (can
67	// be #included alone) and is valid C. This should not be disabled except in
68	// rare cases. Outside bionic and external, if you're using this option
69	// you've probably made a mistake.
70	Skip_verification *bool
71}
72
73type headerModule struct {
74	android.ModuleBase
75
76	properties headerProperties
77
78	srcPaths     android.Paths
79	installPaths android.Paths
80	licensePath  android.Path
81}
82
83type NdkHeaderInfo struct {
84	SrcPaths     android.Paths
85	InstallPaths android.Paths
86	LicensePath  android.Path
87	// Set to true if the headers installed by this module should skip
88	// verification. This step ensures that each header is self-contained (can
89	// be #included alone) and is valid C. This should not be disabled except in
90	// rare cases. Outside bionic and external, if you're using this option
91	// you've probably made a mistake.
92	SkipVerification bool
93}
94
95var NdkHeaderInfoProvider = blueprint.NewProvider[NdkHeaderInfo]()
96
97func getHeaderInstallDir(ctx android.ModuleContext, header android.Path, from string,
98	to string) android.OutputPath {
99	// Output path is the sysroot base + "usr/include" + to directory + directory component
100	// of the file without the leading from directory stripped.
101	//
102	// Given:
103	// sysroot base = "ndk/sysroot"
104	// from = "include/foo"
105	// to = "bar"
106	// header = "include/foo/woodly/doodly.h"
107	// output path = "ndk/sysroot/usr/include/bar/woodly/doodly.h"
108
109	// full/platform/path/to/include/foo
110	fullFromPath := android.PathForModuleSrc(ctx, from)
111
112	// full/platform/path/to/include/foo/woodly
113	headerDir := filepath.Dir(header.String())
114
115	// woodly
116	strippedHeaderDir, err := filepath.Rel(fullFromPath.String(), headerDir)
117	if err != nil {
118		ctx.ModuleErrorf("filepath.Rel(%q, %q) failed: %s", headerDir,
119			fullFromPath.String(), err)
120	}
121
122	// full/platform/path/to/sysroot/usr/include/bar/woodly
123	installDir := getCurrentIncludePath(ctx).Join(ctx, to, strippedHeaderDir)
124
125	// full/platform/path/to/sysroot/usr/include/bar/woodly/doodly.h
126	return installDir
127}
128
129func (m *headerModule) GenerateAndroidBuildActions(ctx android.ModuleContext) {
130	if String(m.properties.License) == "" {
131		ctx.PropertyErrorf("license", "field is required")
132	}
133
134	m.licensePath = android.PathForModuleSrc(ctx, String(m.properties.License))
135
136	m.srcPaths = android.PathsForModuleSrcExcludes(ctx, m.properties.Srcs, m.properties.Exclude_srcs)
137	for _, header := range m.srcPaths {
138		installDir := getHeaderInstallDir(ctx, header, String(m.properties.From),
139			String(m.properties.To))
140		installPath := installDir.Join(ctx, header.Base())
141		ctx.Build(pctx, android.BuildParams{
142			Rule:   android.Cp,
143			Input:  header,
144			Output: installPath,
145		})
146		m.installPaths = append(m.installPaths, installPath)
147	}
148
149	if len(m.installPaths) == 0 {
150		ctx.ModuleErrorf("srcs %q matched zero files", m.properties.Srcs)
151	}
152
153	android.SetProvider(ctx, NdkHeaderInfoProvider, NdkHeaderInfo{
154		SrcPaths:         m.srcPaths,
155		InstallPaths:     m.installPaths,
156		LicensePath:      m.licensePath,
157		SkipVerification: Bool(m.properties.Skip_verification),
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
178// preprocessed_ndk_header {
179//
180//	name: "foo",
181//	preprocessor: "foo.sh",
182//	srcs: [...],
183//	to: "android",
184//
185// }
186//
187// Will invoke the preprocessor as:
188//
189//	$preprocessor -o $SYSROOT/usr/include/android/needs_preproc.h $src
190//
191// For each src in srcs.
192type preprocessedHeadersProperties struct {
193	// The preprocessor to run. Must be a program inside the source directory
194	// with no dependencies.
195	Preprocessor *string
196
197	// Source path to the files to be preprocessed.
198	Srcs []string
199
200	// Source paths that should be excluded from the srcs glob.
201	Exclude_srcs []string
202
203	// Install path within the sysroot. This is relative to usr/include.
204	To *string
205
206	// Path to the NOTICE file associated with the headers.
207	License *string
208
209	// Set to true if the headers installed by this module should skip
210	// verification. This step ensures that each header is self-contained (can
211	// be #included alone) and is valid C. This should not be disabled except in
212	// rare cases. Outside bionic and external, if you're using this option
213	// you've probably made a mistake.
214	Skip_verification *bool
215}
216
217type preprocessedHeadersModule struct {
218	android.ModuleBase
219
220	properties preprocessedHeadersProperties
221
222	srcPaths     android.Paths
223	installPaths android.Paths
224	licensePath  android.Path
225}
226
227var NdkPreprocessedHeaderInfoProvider = blueprint.NewProvider[NdkHeaderInfo]()
228
229func (m *preprocessedHeadersModule) GenerateAndroidBuildActions(ctx android.ModuleContext) {
230	if String(m.properties.License) == "" {
231		ctx.PropertyErrorf("license", "field is required")
232	}
233
234	preprocessor := android.PathForModuleSrc(ctx, String(m.properties.Preprocessor))
235	m.licensePath = android.PathForModuleSrc(ctx, String(m.properties.License))
236
237	m.srcPaths = android.PathsForModuleSrcExcludes(ctx, m.properties.Srcs, m.properties.Exclude_srcs)
238	installDir := getCurrentIncludePath(ctx).Join(ctx, String(m.properties.To))
239	for _, src := range m.srcPaths {
240		installPath := installDir.Join(ctx, src.Base())
241		m.installPaths = append(m.installPaths, installPath)
242
243		ctx.Build(pctx, android.BuildParams{
244			Rule:        preprocessNdkHeader,
245			Description: "preprocess " + src.Rel(),
246			Input:       src,
247			Output:      installPath,
248			Args: map[string]string{
249				"preprocessor": preprocessor.String(),
250			},
251		})
252	}
253
254	if len(m.installPaths) == 0 {
255		ctx.ModuleErrorf("srcs %q matched zero files", m.properties.Srcs)
256	}
257
258	android.SetProvider(ctx, NdkPreprocessedHeaderInfoProvider, NdkHeaderInfo{
259		SrcPaths:         m.srcPaths,
260		InstallPaths:     m.installPaths,
261		LicensePath:      m.licensePath,
262		SkipVerification: Bool(m.properties.Skip_verification),
263	})
264}
265
266// preprocessed_ndk_headers preprocesses all the ndk headers listed in the srcs
267// property by executing the command defined in the preprocessor property.
268func preprocessedNdkHeadersFactory() android.Module {
269	module := &preprocessedHeadersModule{}
270
271	module.AddProperties(&module.properties)
272
273	android.InitAndroidModule(module)
274
275	return module
276}
277