diff options
-rw-r--r-- | android/androidmk.go | 1 | ||||
-rw-r--r-- | bpf/libbpf/Android.bp | 38 | ||||
-rw-r--r-- | bpf/libbpf/libbpf_prog.go | 278 | ||||
-rw-r--r-- | bpf/libbpf/libbpf_prog_test.go | 69 |
4 files changed, 386 insertions, 0 deletions
diff --git a/android/androidmk.go b/android/androidmk.go index fb515313d..085899055 100644 --- a/android/androidmk.go +++ b/android/androidmk.go @@ -913,6 +913,7 @@ func translateAndroidModule(ctx SingletonContext, w io.Writer, moduleInfoJSONs * 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 000000000..f0ba90f52 --- /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 000000000..1fdb3d636 --- /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 000000000..f4f51672f --- /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) +} |