xref: /aosp_15_r20/build/soong/bpf/bpf.go (revision 333d2b3687b3a337dbcca9d65000bca186795e39)
1// Copyright (C) 2018 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 bpf
16
17import (
18	"fmt"
19	"io"
20	"path/filepath"
21	"runtime"
22	"strings"
23
24	"android/soong/android"
25	"android/soong/cc"
26
27	"github.com/google/blueprint"
28	"github.com/google/blueprint/proptools"
29)
30
31func init() {
32	registerBpfBuildComponents(android.InitRegistrationContext)
33	pctx.Import("android/soong/cc/config")
34	pctx.StaticVariable("relPwd", cc.PwdPrefix())
35}
36
37var (
38	pctx = android.NewPackageContext("android/soong/bpf")
39
40	ccRule = pctx.AndroidRemoteStaticRule("ccRule", android.RemoteRuleSupports{Goma: true},
41		blueprint.RuleParams{
42			Depfile:     "${out}.d",
43			Deps:        blueprint.DepsGCC,
44			Command:     "$relPwd $ccCmd --target=bpf -c $cFlags -MD -MF ${out}.d -o $out $in",
45			CommandDeps: []string{"$ccCmd"},
46		},
47		"ccCmd", "cFlags")
48
49	stripRule = pctx.AndroidStaticRule("stripRule",
50		blueprint.RuleParams{
51			Command: `$stripCmd --strip-unneeded --remove-section=.rel.BTF ` +
52				`--remove-section=.rel.BTF.ext --remove-section=.BTF.ext $in -o $out`,
53			CommandDeps: []string{"$stripCmd"},
54		},
55		"stripCmd")
56)
57
58func registerBpfBuildComponents(ctx android.RegistrationContext) {
59	ctx.RegisterModuleType("bpf_defaults", defaultsFactory)
60	ctx.RegisterModuleType("bpf", BpfFactory)
61}
62
63var PrepareForTestWithBpf = android.FixtureRegisterWithContext(registerBpfBuildComponents)
64
65// BpfModule interface is used by the apex package to gather information from a bpf module.
66type BpfModule interface {
67	android.Module
68
69	// Returns the sub install directory if the bpf module is included by apex.
70	SubDir() string
71}
72
73type BpfProperties struct {
74	// source paths to the files.
75	Srcs []string `android:"path"`
76
77	// additional cflags that should be used to build the bpf variant of
78	// the C/C++ module.
79	Cflags []string
80
81	// list of directories relative to the root of the source tree that
82	// will be added to the include paths using -I.
83	// If possible, don't use this. If adding paths from the current
84	// directory, use local_include_dirs. If adding paths from other
85	// modules, use export_include_dirs in that module.
86	Include_dirs []string
87
88	// list of directories relative to the Blueprint file that will be
89	// added to the include path using -I.
90	Local_include_dirs []string
91	// optional subdirectory under which this module is installed into.
92	Sub_dir string
93
94	// if set to true, generate BTF debug info for maps & programs.
95	Btf *bool
96
97	Vendor *bool
98
99	VendorInternal bool `blueprint:"mutated"`
100}
101
102type bpf struct {
103	android.ModuleBase
104	android.DefaultableModuleBase
105	properties BpfProperties
106
107	objs android.Paths
108}
109
110var _ android.ImageInterface = (*bpf)(nil)
111
112func (bpf *bpf) ImageMutatorBegin(ctx android.ImageInterfaceContext) {}
113
114func (bpf *bpf) VendorVariantNeeded(ctx android.ImageInterfaceContext) bool {
115	return proptools.Bool(bpf.properties.Vendor)
116}
117
118func (bpf *bpf) ProductVariantNeeded(ctx android.ImageInterfaceContext) bool {
119	return false
120}
121
122func (bpf *bpf) CoreVariantNeeded(ctx android.ImageInterfaceContext) bool {
123	return !proptools.Bool(bpf.properties.Vendor)
124}
125
126func (bpf *bpf) RamdiskVariantNeeded(ctx android.ImageInterfaceContext) bool {
127	return false
128}
129
130func (bpf *bpf) VendorRamdiskVariantNeeded(ctx android.ImageInterfaceContext) bool {
131	return false
132}
133
134func (bpf *bpf) DebugRamdiskVariantNeeded(ctx android.ImageInterfaceContext) bool {
135	return false
136}
137
138func (bpf *bpf) RecoveryVariantNeeded(ctx android.ImageInterfaceContext) bool {
139	return false
140}
141
142func (bpf *bpf) ExtraImageVariations(ctx android.ImageInterfaceContext) []string {
143	return nil
144}
145
146func (bpf *bpf) SetImageVariation(ctx android.ImageInterfaceContext, variation string) {
147	bpf.properties.VendorInternal = variation == "vendor"
148}
149
150func (bpf *bpf) GenerateAndroidBuildActions(ctx android.ModuleContext) {
151	cflags := []string{
152		"-nostdlibinc",
153
154		// Make paths in deps files relative
155		"-no-canonical-prefixes",
156
157		"-O2",
158		"-Wall",
159		"-Werror",
160		"-Wextra",
161
162		"-isystem bionic/libc/include",
163		"-isystem bionic/libc/kernel/uapi",
164		// The architecture doesn't matter here, but asm/types.h is included by linux/types.h.
165		"-isystem bionic/libc/kernel/uapi/asm-arm64",
166		"-isystem bionic/libc/kernel/android/uapi",
167		"-I       packages/modules/Connectivity/bpf/headers/include",
168		// TODO(b/149785767): only give access to specific file with AID_* constants
169		"-I       system/core/libcutils/include",
170		"-I " + ctx.ModuleDir(),
171	}
172
173	for _, dir := range android.PathsForModuleSrc(ctx, bpf.properties.Local_include_dirs) {
174		cflags = append(cflags, "-I "+dir.String())
175	}
176
177	for _, dir := range android.PathsForSource(ctx, bpf.properties.Include_dirs) {
178		cflags = append(cflags, "-I "+dir.String())
179	}
180
181	cflags = append(cflags, bpf.properties.Cflags...)
182
183	if proptools.BoolDefault(bpf.properties.Btf, true) {
184		cflags = append(cflags, "-g")
185		if runtime.GOOS != "darwin" {
186			cflags = append(cflags, "-fdebug-prefix-map=/proc/self/cwd=")
187		}
188	}
189
190	srcs := android.PathsForModuleSrc(ctx, bpf.properties.Srcs)
191
192	for _, src := range srcs {
193		if strings.ContainsRune(filepath.Base(src.String()), '_') {
194			ctx.ModuleErrorf("invalid character '_' in source name")
195		}
196		obj := android.ObjPathWithExt(ctx, "unstripped", src, "o")
197
198		ctx.Build(pctx, android.BuildParams{
199			Rule:   ccRule,
200			Input:  src,
201			Output: obj,
202			Args: map[string]string{
203				"cFlags": strings.Join(cflags, " "),
204				"ccCmd":  "${config.ClangBin}/clang",
205			},
206		})
207
208		if proptools.BoolDefault(bpf.properties.Btf, true) {
209			objStripped := android.ObjPathWithExt(ctx, "", src, "o")
210			ctx.Build(pctx, android.BuildParams{
211				Rule:   stripRule,
212				Input:  obj,
213				Output: objStripped,
214				Args: map[string]string{
215					"stripCmd": "${config.ClangBin}/llvm-strip",
216				},
217			})
218			bpf.objs = append(bpf.objs, objStripped.WithoutRel())
219		} else {
220			bpf.objs = append(bpf.objs, obj.WithoutRel())
221		}
222
223	}
224
225	installDir := android.PathForModuleInstall(ctx, "etc", "bpf")
226	if len(bpf.properties.Sub_dir) > 0 {
227		installDir = installDir.Join(ctx, bpf.properties.Sub_dir)
228	}
229	for _, obj := range bpf.objs {
230		ctx.PackageFile(installDir, obj.Base(), obj)
231	}
232
233	android.SetProvider(ctx, blueprint.SrcsFileProviderKey, blueprint.SrcsFileProviderData{SrcPaths: srcs.Strings()})
234
235	ctx.SetOutputFiles(bpf.objs, "")
236}
237
238func (bpf *bpf) AndroidMk() android.AndroidMkData {
239	return android.AndroidMkData{
240		Custom: func(w io.Writer, name, prefix, moduleDir string, data android.AndroidMkData) {
241			var names []string
242			fmt.Fprintln(w)
243			fmt.Fprintln(w, "LOCAL_PATH :=", moduleDir)
244			fmt.Fprintln(w)
245			var localModulePath string
246			if bpf.properties.VendorInternal {
247				localModulePath = "LOCAL_MODULE_PATH := $(TARGET_OUT_VENDOR_ETC)/bpf"
248			} else {
249				localModulePath = "LOCAL_MODULE_PATH := $(TARGET_OUT_ETC)/bpf"
250			}
251			if len(bpf.properties.Sub_dir) > 0 {
252				localModulePath += "/" + bpf.properties.Sub_dir
253			}
254			for _, obj := range bpf.objs {
255				objName := name + "_" + obj.Base()
256				names = append(names, objName)
257				fmt.Fprintln(w, "include $(CLEAR_VARS)", " # bpf.bpf.obj")
258				fmt.Fprintln(w, "LOCAL_MODULE := ", objName)
259				fmt.Fprintln(w, "LOCAL_PREBUILT_MODULE_FILE :=", obj.String())
260				fmt.Fprintln(w, "LOCAL_MODULE_STEM :=", obj.Base())
261				fmt.Fprintln(w, "LOCAL_MODULE_CLASS := ETC")
262				fmt.Fprintln(w, localModulePath)
263				// AconfigUpdateAndroidMkData may have added elements to Extra.  Process them here.
264				for _, extra := range data.Extra {
265					extra(w, nil)
266				}
267				fmt.Fprintln(w, "include $(BUILD_PREBUILT)")
268				fmt.Fprintln(w)
269			}
270			fmt.Fprintln(w, "include $(CLEAR_VARS)", " # bpf.bpf")
271			fmt.Fprintln(w, "LOCAL_MODULE := ", name)
272			android.AndroidMkEmitAssignList(w, "LOCAL_REQUIRED_MODULES", names)
273			fmt.Fprintln(w, "include $(BUILD_PHONY_PACKAGE)")
274		},
275	}
276}
277
278type Defaults struct {
279	android.ModuleBase
280	android.DefaultsModuleBase
281}
282
283func defaultsFactory() android.Module {
284	return DefaultsFactory()
285}
286
287func DefaultsFactory(props ...interface{}) android.Module {
288	module := &Defaults{}
289
290	module.AddProperties(props...)
291	module.AddProperties(&BpfProperties{})
292
293	android.InitDefaultsModule(module)
294
295	return module
296}
297
298func (bpf *bpf) SubDir() string {
299	return bpf.properties.Sub_dir
300}
301
302func BpfFactory() android.Module {
303	module := &bpf{}
304
305	module.AddProperties(&module.properties)
306
307	android.InitAndroidArchModule(module, android.DeviceSupported, android.MultilibCommon)
308	android.InitDefaultableModule(module)
309
310	return module
311}
312