xref: /aosp_15_r20/build/soong/bpf/libbpf/libbpf_prog.go (revision 333d2b3687b3a337dbcca9d65000bca186795e39)
1// Copyright (C) 2024 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 libbpf_prog
16
17import (
18	"fmt"
19	"io"
20	"runtime"
21	"strings"
22
23	"android/soong/android"
24	"android/soong/cc"
25	"android/soong/genrule"
26
27	"github.com/google/blueprint"
28)
29
30type libbpfProgDepType struct {
31	blueprint.BaseDependencyTag
32}
33
34func init() {
35	registerLibbpfProgBuildComponents(android.InitRegistrationContext)
36	pctx.Import("android/soong/cc/config")
37	pctx.StaticVariable("relPwd", cc.PwdPrefix())
38}
39
40var (
41	pctx = android.NewPackageContext("android/soong/bpf/libbpf_prog")
42
43	libbpfProgCcRule = pctx.AndroidStaticRule("libbpfProgCcRule",
44		blueprint.RuleParams{
45			Depfile:     "${out}.d",
46			Deps:        blueprint.DepsGCC,
47			Command:     "$relPwd $ccCmd --target=bpf -c $cFlags -MD -MF ${out}.d -o $out $in",
48			CommandDeps: []string{"$ccCmd"},
49		},
50		"ccCmd", "cFlags")
51
52	libbpfProgStripRule = pctx.AndroidStaticRule("libbpfProgStripRule",
53		blueprint.RuleParams{
54			Command: `$stripCmd --strip-unneeded --remove-section=.rel.BTF ` +
55				`--remove-section=.rel.BTF.ext --remove-section=.BTF.ext $in -o $out`,
56			CommandDeps: []string{"$stripCmd"},
57		},
58		"stripCmd")
59
60	libbpfProgDepTag = libbpfProgDepType{}
61)
62
63func registerLibbpfProgBuildComponents(ctx android.RegistrationContext) {
64	ctx.RegisterModuleType("libbpf_defaults", defaultsFactory)
65	ctx.RegisterModuleType("libbpf_prog", LibbpfProgFactory)
66}
67
68var PrepareForTestWithLibbpfProg = android.GroupFixturePreparers(
69	android.FixtureRegisterWithContext(registerLibbpfProgBuildComponents),
70	android.FixtureAddFile("libbpf_headers/Foo.h", nil),
71	android.FixtureAddFile("libbpf_headers/Android.bp", []byte(`
72		genrule {
73			name: "libbpf_headers",
74			out: ["foo.h",],
75		}
76	`)),
77	genrule.PrepareForTestWithGenRuleBuildComponents,
78)
79
80type LibbpfProgProperties struct {
81	// source paths to the files.
82	Srcs []string `android:"path"`
83
84	// additional cflags that should be used to build the libbpf variant of
85	// the C/C++ module.
86	Cflags []string `android:"arch_variant"`
87
88	// list of directories relative to the Blueprint file that will
89	// be added to the include path using -I
90	Local_include_dirs []string `android:"arch_variant"`
91
92	Header_libs []string `android:"arch_variant"`
93
94	// optional subdirectory under which this module is installed into.
95	Relative_install_path string
96}
97
98type libbpfProg struct {
99	android.ModuleBase
100	android.DefaultableModuleBase
101	properties LibbpfProgProperties
102	objs       android.Paths
103}
104
105var _ android.ImageInterface = (*libbpfProg)(nil)
106
107func (libbpf *libbpfProg) ImageMutatorBegin(ctx android.ImageInterfaceContext) {}
108
109func (libbpf *libbpfProg) VendorVariantNeeded(ctx android.ImageInterfaceContext) bool {
110	return false
111}
112
113func (libbpf *libbpfProg) ProductVariantNeeded(ctx android.ImageInterfaceContext) bool {
114	return false
115}
116
117func (libbpf *libbpfProg) CoreVariantNeeded(ctx android.ImageInterfaceContext) bool {
118	return true
119}
120
121func (libbpf *libbpfProg) RamdiskVariantNeeded(ctx android.ImageInterfaceContext) bool {
122	return false
123}
124
125func (libbpf *libbpfProg) VendorRamdiskVariantNeeded(ctx android.ImageInterfaceContext) bool {
126	return false
127}
128
129func (libbpf *libbpfProg) DebugRamdiskVariantNeeded(ctx android.ImageInterfaceContext) bool {
130	return false
131}
132
133func (libbpf *libbpfProg) RecoveryVariantNeeded(ctx android.ImageInterfaceContext) bool {
134	return false
135}
136
137func (libbpf *libbpfProg) ExtraImageVariations(ctx android.ImageInterfaceContext) []string {
138	return nil
139}
140
141func (libbpf *libbpfProg) SetImageVariation(ctx android.ImageInterfaceContext, variation string) {
142}
143
144func (libbpf *libbpfProg) DepsMutator(ctx android.BottomUpMutatorContext) {
145	ctx.AddDependency(ctx.Module(), libbpfProgDepTag, "libbpf_headers")
146	ctx.AddVariationDependencies(nil, cc.HeaderDepTag(), libbpf.properties.Header_libs...)
147}
148
149func (libbpf *libbpfProg) GenerateAndroidBuildActions(ctx android.ModuleContext) {
150	var cFlagsDeps android.Paths
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		// Flag to assist with the transition to libbpf
162		"-DENABLE_LIBBPF",
163		"-isystem bionic/libc/include",
164		"-isystem bionic/libc/kernel/uapi",
165		// The architecture doesn't matter here, but asm/types.h is included by linux/types.h.
166		"-isystem bionic/libc/kernel/uapi/asm-arm64",
167		"-isystem bionic/libc/kernel/android/uapi",
168		"-I " + ctx.ModuleDir(),
169		"-g", //Libbpf builds require BTF data
170	}
171
172	if runtime.GOOS != "darwin" {
173		cflags = append(cflags, "-fdebug-prefix-map=/proc/self/cwd=")
174	}
175
176	ctx.VisitDirectDeps(func(dep android.Module) {
177		depTag := ctx.OtherModuleDependencyTag(dep)
178		if depTag == libbpfProgDepTag {
179			if genRule, ok := dep.(genrule.SourceFileGenerator); ok {
180				cFlagsDeps = append(cFlagsDeps, genRule.GeneratedDeps()...)
181				dirs := genRule.GeneratedHeaderDirs()
182				for _, dir := range dirs {
183					cflags = append(cflags, "-I "+dir.String())
184				}
185			} else {
186				depName := ctx.OtherModuleName(dep)
187				ctx.ModuleErrorf("module %q is not a genrule", depName)
188			}
189		} else if depTag == cc.HeaderDepTag() {
190			depExporterInfo, _ := android.OtherModuleProvider(ctx, dep, cc.FlagExporterInfoProvider)
191			for _, dir := range depExporterInfo.IncludeDirs {
192				cflags = append(cflags, "-I "+dir.String())
193			}
194		}
195	})
196
197	for _, dir := range android.PathsForModuleSrc(ctx, libbpf.properties.Local_include_dirs) {
198		cflags = append(cflags, "-I "+dir.String())
199	}
200
201	cflags = append(cflags, libbpf.properties.Cflags...)
202
203	srcs := android.PathsForModuleSrc(ctx, libbpf.properties.Srcs)
204
205	for _, src := range srcs {
206		if strings.ContainsRune(src.Base(), '_') {
207			ctx.ModuleErrorf("invalid character '_' in source name")
208		}
209		obj := android.ObjPathWithExt(ctx, "unstripped", src, "bpf")
210
211		ctx.Build(pctx, android.BuildParams{
212			Rule:      libbpfProgCcRule,
213			Input:     src,
214			Implicits: cFlagsDeps,
215			Output:    obj,
216			Args: map[string]string{
217				"cFlags": strings.Join(cflags, " "),
218				"ccCmd":  "${config.ClangBin}/clang",
219			},
220		})
221
222		objStripped := android.ObjPathWithExt(ctx, "", src, "bpf")
223		ctx.Build(pctx, android.BuildParams{
224			Rule:   libbpfProgStripRule,
225			Input:  obj,
226			Output: objStripped,
227			Args: map[string]string{
228				"stripCmd": "${config.ClangBin}/llvm-strip",
229			},
230		})
231		libbpf.objs = append(libbpf.objs, objStripped.WithoutRel())
232	}
233
234	installDir := android.PathForModuleInstall(ctx, "etc", "bpf")
235	if len(libbpf.properties.Relative_install_path) > 0 {
236		installDir = installDir.Join(ctx, libbpf.properties.Relative_install_path)
237	}
238	for _, obj := range libbpf.objs {
239		ctx.PackageFile(installDir, obj.Base(), obj)
240	}
241
242	android.SetProvider(ctx, blueprint.SrcsFileProviderKey, blueprint.SrcsFileProviderData{SrcPaths: srcs.Strings()})
243
244	ctx.SetOutputFiles(libbpf.objs, "")
245}
246
247func (libbpf *libbpfProg) AndroidMk() android.AndroidMkData {
248	return android.AndroidMkData{
249		Custom: func(w io.Writer, name, prefix, moduleDir string, data android.AndroidMkData) {
250			var names []string
251			fmt.Fprintln(w)
252			fmt.Fprintln(w, "LOCAL_PATH :=", moduleDir)
253			fmt.Fprintln(w)
254			var localModulePath string
255			localModulePath = "LOCAL_MODULE_PATH := $(TARGET_OUT_ETC)/bpf"
256			if len(libbpf.properties.Relative_install_path) > 0 {
257				localModulePath += "/" + libbpf.properties.Relative_install_path
258			}
259			for _, obj := range libbpf.objs {
260				objName := name + "_" + obj.Base()
261				names = append(names, objName)
262				fmt.Fprintln(w, "include $(CLEAR_VARS)", " # libbpf.libbpf.obj")
263				fmt.Fprintln(w, "LOCAL_MODULE := ", objName)
264				fmt.Fprintln(w, "LOCAL_PREBUILT_MODULE_FILE :=", obj.String())
265				fmt.Fprintln(w, "LOCAL_MODULE_STEM :=", obj.Base())
266				fmt.Fprintln(w, "LOCAL_MODULE_CLASS := ETC")
267				fmt.Fprintln(w, localModulePath)
268				// AconfigUpdateAndroidMkData may have added elements to Extra.  Process them here.
269				for _, extra := range data.Extra {
270					extra(w, nil)
271				}
272				fmt.Fprintln(w, "include $(BUILD_PREBUILT)")
273				fmt.Fprintln(w)
274			}
275			fmt.Fprintln(w, "include $(CLEAR_VARS)", " # libbpf.libbpf")
276			fmt.Fprintln(w, "LOCAL_MODULE := ", name)
277			android.AndroidMkEmitAssignList(w, "LOCAL_REQUIRED_MODULES", names)
278			fmt.Fprintln(w, "include $(BUILD_PHONY_PACKAGE)")
279		},
280	}
281}
282
283type Defaults struct {
284	android.ModuleBase
285	android.DefaultsModuleBase
286}
287
288func defaultsFactory() android.Module {
289	return DefaultsFactory()
290}
291
292func DefaultsFactory(props ...interface{}) android.Module {
293	module := &Defaults{}
294
295	module.AddProperties(props...)
296	module.AddProperties(&LibbpfProgProperties{})
297
298	android.InitDefaultsModule(module)
299
300	return module
301}
302
303func LibbpfProgFactory() android.Module {
304	module := &libbpfProg{}
305
306	module.AddProperties(&module.properties)
307	android.InitAndroidArchModule(module, android.DeviceSupported, android.MultilibFirst)
308	android.InitDefaultableModule(module)
309
310	return module
311}
312