Merge "SOONG: BPF: add libbpf_prog soong module" into main
diff --git a/android/androidmk.go b/android/androidmk.go
index 6426835..fc628cb 100644
--- a/android/androidmk.go
+++ b/android/androidmk.go
@@ -913,6 +913,7 @@
case "*android_sdk.sdkRepoHost": // doesn't go through base_rules
case "*apex.apexBundle": // license properties written
case "*bpf.bpf": // license properties written (both for module and objs)
+ case "*libbpf_prog.libbpfProg": // license properties written (both for module and objs)
case "*genrule.Module": // writes non-custom before adding .phony
case "*java.SystemModules": // doesn't go through base_rules
case "*java.systemModulesImport": // doesn't go through base_rules
diff --git a/bpf/libbpf/Android.bp b/bpf/libbpf/Android.bp
new file mode 100644
index 0000000..f0ba90f
--- /dev/null
+++ b/bpf/libbpf/Android.bp
@@ -0,0 +1,38 @@
+//
+// Copyright (C) 2024 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+package {
+ default_applicable_licenses: ["Android-Apache-2.0"],
+}
+
+bootstrap_go_package {
+ name: "soong-libbpf",
+ pkgPath: "android/soong/bpf/libbpf",
+ deps: [
+ "blueprint",
+ "blueprint-proptools",
+ "soong-android",
+ "soong-cc",
+ "soong-cc-config",
+ ],
+ srcs: [
+ "libbpf_prog.go",
+ ],
+ testSrcs: [
+ "libbpf_prog_test.go",
+ ],
+ pluginFor: ["soong_build"],
+}
diff --git a/bpf/libbpf/libbpf_prog.go b/bpf/libbpf/libbpf_prog.go
new file mode 100644
index 0000000..1fdb3d6
--- /dev/null
+++ b/bpf/libbpf/libbpf_prog.go
@@ -0,0 +1,278 @@
+// Copyright (C) 2024 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package libbpf_prog
+
+import (
+ "fmt"
+ "io"
+ "runtime"
+ "strings"
+
+ "android/soong/android"
+ "android/soong/cc"
+ "android/soong/genrule"
+
+ "github.com/google/blueprint"
+)
+
+type libbpfProgDepType struct {
+ blueprint.BaseDependencyTag
+}
+
+func init() {
+ registerLibbpfProgBuildComponents(android.InitRegistrationContext)
+ pctx.Import("android/soong/cc/config")
+ pctx.StaticVariable("relPwd", cc.PwdPrefix())
+}
+
+var (
+ pctx = android.NewPackageContext("android/soong/bpf/libbpf_prog")
+
+ libbpfProgCcRule = pctx.AndroidStaticRule("libbpfProgCcRule",
+ blueprint.RuleParams{
+ Depfile: "${out}.d",
+ Deps: blueprint.DepsGCC,
+ Command: "$relPwd $ccCmd --target=bpf -c $cFlags -MD -MF ${out}.d -o $out $in",
+ CommandDeps: []string{"$ccCmd"},
+ },
+ "ccCmd", "cFlags")
+
+ libbpfProgStripRule = pctx.AndroidStaticRule("libbpfProgStripRule",
+ blueprint.RuleParams{
+ Command: `$stripCmd --strip-unneeded --remove-section=.rel.BTF ` +
+ `--remove-section=.rel.BTF.ext --remove-section=.BTF.ext $in -o $out`,
+ CommandDeps: []string{"$stripCmd"},
+ },
+ "stripCmd")
+
+ libbpfProgDepTag = libbpfProgDepType{}
+)
+
+func registerLibbpfProgBuildComponents(ctx android.RegistrationContext) {
+ ctx.RegisterModuleType("libbpf_prog", LibbpfProgFactory)
+}
+
+var PrepareForTestWithLibbpfProg = android.GroupFixturePreparers(
+ android.FixtureRegisterWithContext(registerLibbpfProgBuildComponents),
+ android.FixtureAddFile("libbpf_headers/Foo.h", nil),
+ android.FixtureAddFile("libbpf_headers/Android.bp", []byte(`
+ genrule {
+ name: "libbpf_headers",
+ out: ["foo.h",],
+ }
+ `)),
+ genrule.PrepareForTestWithGenRuleBuildComponents,
+)
+
+type LibbpfProgProperties struct {
+ // source paths to the files.
+ Srcs []string `android:"path"`
+
+ // additional cflags that should be used to build the libbpf variant of
+ // the C/C++ module.
+ Cflags []string `android:"arch_variant"`
+
+ // list of directories relative to the Blueprint file that will
+ // be added to the include path using -I
+ Local_include_dirs []string `android:"arch_variant"`
+
+ // optional subdirectory under which this module is installed into.
+ Relative_install_path string
+}
+
+type libbpfProg struct {
+ android.ModuleBase
+ properties LibbpfProgProperties
+ objs android.Paths
+}
+
+var _ android.ImageInterface = (*libbpfProg)(nil)
+
+func (libbpf *libbpfProg) ImageMutatorBegin(ctx android.BaseModuleContext) {}
+
+func (libbpf *libbpfProg) VendorVariantNeeded(ctx android.BaseModuleContext) bool {
+ return false
+}
+
+func (libbpf *libbpfProg) ProductVariantNeeded(ctx android.BaseModuleContext) bool {
+ return false
+}
+
+func (libbpf *libbpfProg) CoreVariantNeeded(ctx android.BaseModuleContext) bool {
+ return true
+}
+
+func (libbpf *libbpfProg) RamdiskVariantNeeded(ctx android.BaseModuleContext) bool {
+ return false
+}
+
+func (libbpf *libbpfProg) VendorRamdiskVariantNeeded(ctx android.BaseModuleContext) bool {
+ return false
+}
+
+func (libbpf *libbpfProg) DebugRamdiskVariantNeeded(ctx android.BaseModuleContext) bool {
+ return false
+}
+
+func (libbpf *libbpfProg) RecoveryVariantNeeded(ctx android.BaseModuleContext) bool {
+ return false
+}
+
+func (libbpf *libbpfProg) ExtraImageVariations(ctx android.BaseModuleContext) []string {
+ return nil
+}
+
+func (libbpf *libbpfProg) SetImageVariation(ctx android.BaseModuleContext, variation string) {
+}
+
+func (libbpf *libbpfProg) DepsMutator(ctx android.BottomUpMutatorContext) {
+ ctx.AddDependency(ctx.Module(), libbpfProgDepTag, "libbpf_headers")
+}
+
+func (libbpf *libbpfProg) GenerateAndroidBuildActions(ctx android.ModuleContext) {
+ var cFlagsDeps android.Paths
+ cflags := []string{
+ "-nostdlibinc",
+
+ // Make paths in deps files relative
+ "-no-canonical-prefixes",
+
+ "-O2",
+ "-Wall",
+ "-Werror",
+ "-Wextra",
+
+ "-isystem bionic/libc/include",
+ "-isystem bionic/libc/kernel/uapi",
+ // The architecture doesn't matter here, but asm/types.h is included by linux/types.h.
+ "-isystem bionic/libc/kernel/uapi/asm-arm64",
+ "-isystem bionic/libc/kernel/android/uapi",
+ "-I " + ctx.ModuleDir(),
+ "-g", //Libbpf builds require BTF data
+ }
+
+ if runtime.GOOS != "darwin" {
+ cflags = append(cflags, "-fdebug-prefix-map=/proc/self/cwd=")
+ }
+
+ ctx.VisitDirectDeps(func(dep android.Module) {
+ depTag := ctx.OtherModuleDependencyTag(dep)
+ if depTag == libbpfProgDepTag {
+ if genRule, ok := dep.(genrule.SourceFileGenerator); ok {
+ cFlagsDeps = append(cFlagsDeps, genRule.GeneratedDeps()...)
+ dirs := genRule.GeneratedHeaderDirs()
+ for _, dir := range dirs {
+ cflags = append(cflags, "-I "+dir.String())
+ }
+ } else {
+ depName := ctx.OtherModuleName(dep)
+ ctx.ModuleErrorf("module %q is not a genrule", depName)
+ }
+ }
+ })
+
+ for _, dir := range android.PathsForModuleSrc(ctx, libbpf.properties.Local_include_dirs) {
+ cflags = append(cflags, "-I "+dir.String())
+ }
+
+ cflags = append(cflags, libbpf.properties.Cflags...)
+
+ srcs := android.PathsForModuleSrc(ctx, libbpf.properties.Srcs)
+
+ for _, src := range srcs {
+ if strings.ContainsRune(src.Base(), '_') {
+ ctx.ModuleErrorf("invalid character '_' in source name")
+ }
+ obj := android.ObjPathWithExt(ctx, "unstripped", src, "o")
+
+ ctx.Build(pctx, android.BuildParams{
+ Rule: libbpfProgCcRule,
+ Input: src,
+ Implicits: cFlagsDeps,
+ Output: obj,
+ Args: map[string]string{
+ "cFlags": strings.Join(cflags, " "),
+ "ccCmd": "${config.ClangBin}/clang",
+ },
+ })
+
+ objStripped := android.ObjPathWithExt(ctx, "", src, "o")
+ ctx.Build(pctx, android.BuildParams{
+ Rule: libbpfProgStripRule,
+ Input: obj,
+ Output: objStripped,
+ Args: map[string]string{
+ "stripCmd": "${config.ClangBin}/llvm-strip",
+ },
+ })
+ libbpf.objs = append(libbpf.objs, objStripped.WithoutRel())
+ }
+
+ installDir := android.PathForModuleInstall(ctx, "etc", "bpf/libbpf")
+ if len(libbpf.properties.Relative_install_path) > 0 {
+ installDir = installDir.Join(ctx, libbpf.properties.Relative_install_path)
+ }
+ for _, obj := range libbpf.objs {
+ ctx.PackageFile(installDir, obj.Base(), obj)
+ }
+
+ android.SetProvider(ctx, blueprint.SrcsFileProviderKey, blueprint.SrcsFileProviderData{SrcPaths: srcs.Strings()})
+
+ ctx.SetOutputFiles(libbpf.objs, "")
+}
+
+func (libbpf *libbpfProg) AndroidMk() android.AndroidMkData {
+ return android.AndroidMkData{
+ Custom: func(w io.Writer, name, prefix, moduleDir string, data android.AndroidMkData) {
+ var names []string
+ fmt.Fprintln(w)
+ fmt.Fprintln(w, "LOCAL_PATH :=", moduleDir)
+ fmt.Fprintln(w)
+ var localModulePath string
+ localModulePath = "LOCAL_MODULE_PATH := $(TARGET_OUT_ETC)/bpf/libbpf"
+ if len(libbpf.properties.Relative_install_path) > 0 {
+ localModulePath += "/" + libbpf.properties.Relative_install_path
+ }
+ for _, obj := range libbpf.objs {
+ objName := name + "_" + obj.Base()
+ names = append(names, objName)
+ fmt.Fprintln(w, "include $(CLEAR_VARS)", " # libbpf.libbpf.obj")
+ fmt.Fprintln(w, "LOCAL_MODULE := ", objName)
+ fmt.Fprintln(w, "LOCAL_PREBUILT_MODULE_FILE :=", obj.String())
+ fmt.Fprintln(w, "LOCAL_MODULE_STEM :=", obj.Base())
+ fmt.Fprintln(w, "LOCAL_MODULE_CLASS := ETC")
+ fmt.Fprintln(w, localModulePath)
+ // AconfigUpdateAndroidMkData may have added elements to Extra. Process them here.
+ for _, extra := range data.Extra {
+ extra(w, nil)
+ }
+ fmt.Fprintln(w, "include $(BUILD_PREBUILT)")
+ fmt.Fprintln(w)
+ }
+ fmt.Fprintln(w, "include $(CLEAR_VARS)", " # libbpf.libbpf")
+ fmt.Fprintln(w, "LOCAL_MODULE := ", name)
+ android.AndroidMkEmitAssignList(w, "LOCAL_REQUIRED_MODULES", names)
+ fmt.Fprintln(w, "include $(BUILD_PHONY_PACKAGE)")
+ },
+ }
+}
+
+func LibbpfProgFactory() android.Module {
+ module := &libbpfProg{}
+
+ module.AddProperties(&module.properties)
+ android.InitAndroidArchModule(module, android.DeviceSupported, android.MultilibFirst)
+ return module
+}
diff --git a/bpf/libbpf/libbpf_prog_test.go b/bpf/libbpf/libbpf_prog_test.go
new file mode 100644
index 0000000..f4f5167
--- /dev/null
+++ b/bpf/libbpf/libbpf_prog_test.go
@@ -0,0 +1,69 @@
+// Copyright 2024 Google Inc. All rights reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package libbpf_prog
+
+import (
+ "os"
+ "testing"
+
+ "android/soong/android"
+ "android/soong/cc"
+)
+
+func TestMain(m *testing.M) {
+ os.Exit(m.Run())
+}
+
+var prepareForLibbpfProgTest = android.GroupFixturePreparers(
+ cc.PrepareForTestWithCcDefaultModules,
+ android.FixtureMergeMockFs(
+ map[string][]byte{
+ "bpf.c": nil,
+ "bpf_invalid_name.c": nil,
+ "BpfTest.cpp": nil,
+ },
+ ),
+ PrepareForTestWithLibbpfProg,
+)
+
+func TestLibbpfProgDataDependency(t *testing.T) {
+ bp := `
+ libbpf_prog {
+ name: "bpf.o",
+ srcs: ["bpf.c"],
+ }
+
+ cc_test {
+ name: "vts_test_binary_bpf_module",
+ srcs: ["BpfTest.cpp"],
+ data: [":bpf.o"],
+ gtest: false,
+ }
+ `
+
+ prepareForLibbpfProgTest.RunTestWithBp(t, bp)
+}
+
+func TestLibbpfProgSourceName(t *testing.T) {
+ bp := `
+ libbpf_prog {
+ name: "bpf_invalid_name.o",
+ srcs: ["bpf_invalid_name.c"],
+ }
+ `
+ prepareForLibbpfProgTest.ExtendWithErrorHandler(android.FixtureExpectsOneErrorPattern(
+ `invalid character '_' in source name`)).
+ RunTestWithBp(t, bp)
+}