xref: /aosp_15_r20/build/soong/cc/ndk_headers.go (revision 333d2b3687b3a337dbcca9d65000bca186795e39)
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
83func getHeaderInstallDir(ctx android.ModuleContext, header android.Path, from string,
84	to string) android.OutputPath {
85	// Output path is the sysroot base + "usr/include" + to directory + directory component
86	// of the file without the leading from directory stripped.
87	//
88	// Given:
89	// sysroot base = "ndk/sysroot"
90	// from = "include/foo"
91	// to = "bar"
92	// header = "include/foo/woodly/doodly.h"
93	// output path = "ndk/sysroot/usr/include/bar/woodly/doodly.h"
94
95	// full/platform/path/to/include/foo
96	fullFromPath := android.PathForModuleSrc(ctx, from)
97
98	// full/platform/path/to/include/foo/woodly
99	headerDir := filepath.Dir(header.String())
100
101	// woodly
102	strippedHeaderDir, err := filepath.Rel(fullFromPath.String(), headerDir)
103	if err != nil {
104		ctx.ModuleErrorf("filepath.Rel(%q, %q) failed: %s", headerDir,
105			fullFromPath.String(), err)
106	}
107
108	// full/platform/path/to/sysroot/usr/include/bar/woodly
109	installDir := getCurrentIncludePath(ctx).Join(ctx, to, strippedHeaderDir)
110
111	// full/platform/path/to/sysroot/usr/include/bar/woodly/doodly.h
112	return installDir
113}
114
115func (m *headerModule) GenerateAndroidBuildActions(ctx android.ModuleContext) {
116	if String(m.properties.License) == "" {
117		ctx.PropertyErrorf("license", "field is required")
118	}
119
120	m.licensePath = android.PathForModuleSrc(ctx, String(m.properties.License))
121
122	m.srcPaths = android.PathsForModuleSrcExcludes(ctx, m.properties.Srcs, m.properties.Exclude_srcs)
123	for _, header := range m.srcPaths {
124		installDir := getHeaderInstallDir(ctx, header, String(m.properties.From),
125			String(m.properties.To))
126		installPath := installDir.Join(ctx, header.Base())
127		ctx.Build(pctx, android.BuildParams{
128			Rule:   android.Cp,
129			Input:  header,
130			Output: installPath,
131		})
132		m.installPaths = append(m.installPaths, installPath)
133	}
134
135	if len(m.installPaths) == 0 {
136		ctx.ModuleErrorf("srcs %q matched zero files", m.properties.Srcs)
137	}
138}
139
140// ndk_headers installs the sets of ndk headers defined in the srcs property
141// to the sysroot base + "usr/include" + to directory + directory component.
142// ndk_headers requires the license file to be specified. Example:
143//
144//	Given:
145//	sysroot base = "ndk/sysroot"
146//	from = "include/foo"
147//	to = "bar"
148//	header = "include/foo/woodly/doodly.h"
149//	output path = "ndk/sysroot/usr/include/bar/woodly/doodly.h"
150func NdkHeadersFactory() android.Module {
151	module := &headerModule{}
152	module.AddProperties(&module.properties)
153	android.InitAndroidModule(module)
154	return module
155}
156
157// preprocessed_ndk_header {
158//
159//	name: "foo",
160//	preprocessor: "foo.sh",
161//	srcs: [...],
162//	to: "android",
163//
164// }
165//
166// Will invoke the preprocessor as:
167//
168//	$preprocessor -o $SYSROOT/usr/include/android/needs_preproc.h $src
169//
170// For each src in srcs.
171type preprocessedHeadersProperties struct {
172	// The preprocessor to run. Must be a program inside the source directory
173	// with no dependencies.
174	Preprocessor *string
175
176	// Source path to the files to be preprocessed.
177	Srcs []string
178
179	// Source paths that should be excluded from the srcs glob.
180	Exclude_srcs []string
181
182	// Install path within the sysroot. This is relative to usr/include.
183	To *string
184
185	// Path to the NOTICE file associated with the headers.
186	License *string
187
188	// Set to true if the headers installed by this module should skip
189	// verification. This step ensures that each header is self-contained (can
190	// be #included alone) and is valid C. This should not be disabled except in
191	// rare cases. Outside bionic and external, if you're using this option
192	// you've probably made a mistake.
193	Skip_verification *bool
194}
195
196type preprocessedHeadersModule struct {
197	android.ModuleBase
198
199	properties preprocessedHeadersProperties
200
201	srcPaths     android.Paths
202	installPaths android.Paths
203	licensePath  android.Path
204}
205
206func (m *preprocessedHeadersModule) GenerateAndroidBuildActions(ctx android.ModuleContext) {
207	if String(m.properties.License) == "" {
208		ctx.PropertyErrorf("license", "field is required")
209	}
210
211	preprocessor := android.PathForModuleSrc(ctx, String(m.properties.Preprocessor))
212	m.licensePath = android.PathForModuleSrc(ctx, String(m.properties.License))
213
214	m.srcPaths = android.PathsForModuleSrcExcludes(ctx, m.properties.Srcs, m.properties.Exclude_srcs)
215	installDir := getCurrentIncludePath(ctx).Join(ctx, String(m.properties.To))
216	for _, src := range m.srcPaths {
217		installPath := installDir.Join(ctx, src.Base())
218		m.installPaths = append(m.installPaths, installPath)
219
220		ctx.Build(pctx, android.BuildParams{
221			Rule:        preprocessNdkHeader,
222			Description: "preprocess " + src.Rel(),
223			Input:       src,
224			Output:      installPath,
225			Args: map[string]string{
226				"preprocessor": preprocessor.String(),
227			},
228		})
229	}
230
231	if len(m.installPaths) == 0 {
232		ctx.ModuleErrorf("srcs %q matched zero files", m.properties.Srcs)
233	}
234}
235
236// preprocessed_ndk_headers preprocesses all the ndk headers listed in the srcs
237// property by executing the command defined in the preprocessor property.
238func preprocessedNdkHeadersFactory() android.Module {
239	module := &preprocessedHeadersModule{}
240
241	module.AddProperties(&module.properties)
242
243	android.InitAndroidModule(module)
244
245	return module
246}
247