platform_build_soong/bpf/bpf.go
Connor O'Brien 6a288bc799 bpf: use PwdPrefix() helper
relPwd is only set if runtime.GOOS != "darwin" but is used
unconditionally. Instead, unconditionally set relPwd using the
cc.PwdPrefix() helper.

Bug: 238165437
Test: m timeInState.o
Signed-off-by: Connor O'Brien <connoro@google.com>
Change-Id: I5294bb6ea95dad60fbf64e9d958e1f1b32a02a48
2022-11-10 16:35:12 -08:00

336 lines
9.4 KiB
Go

// Copyright (C) 2018 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 bpf
import (
"fmt"
"io"
"path/filepath"
"runtime"
"strings"
"android/soong/android"
"android/soong/bazel"
"android/soong/bazel/cquery"
"android/soong/cc"
"github.com/google/blueprint"
"github.com/google/blueprint/proptools"
)
func init() {
registerBpfBuildComponents(android.InitRegistrationContext)
pctx.Import("android/soong/cc/config")
pctx.StaticVariable("relPwd", cc.PwdPrefix())
}
var (
pctx = android.NewPackageContext("android/soong/bpf")
ccRule = pctx.AndroidRemoteStaticRule("ccRule", android.RemoteRuleSupports{Goma: true},
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")
stripRule = pctx.AndroidStaticRule("stripRule",
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")
)
func registerBpfBuildComponents(ctx android.RegistrationContext) {
ctx.RegisterModuleType("bpf", BpfFactory)
}
var PrepareForTestWithBpf = android.FixtureRegisterWithContext(registerBpfBuildComponents)
// BpfModule interface is used by the apex package to gather information from a bpf module.
type BpfModule interface {
android.Module
OutputFiles(tag string) (android.Paths, error)
// Returns the sub install directory if the bpf module is included by apex.
SubDir() string
}
type BpfProperties struct {
// source paths to the files.
Srcs []string `android:"path"`
// additional cflags that should be used to build the bpf variant of
// the C/C++ module.
Cflags []string
// directories (relative to the root of the source tree) that will
// be added to the include paths using -I.
Include_dirs []string
// optional subdirectory under which this module is installed into.
Sub_dir string
// if set to true, generate BTF debug info for maps & programs.
Btf *bool
Vendor *bool
VendorInternal bool `blueprint:"mutated"`
}
type bpf struct {
android.ModuleBase
android.BazelModuleBase
properties BpfProperties
objs android.Paths
}
var _ android.ImageInterface = (*bpf)(nil)
func (bpf *bpf) ImageMutatorBegin(ctx android.BaseModuleContext) {}
func (bpf *bpf) CoreVariantNeeded(ctx android.BaseModuleContext) bool {
return !proptools.Bool(bpf.properties.Vendor)
}
func (bpf *bpf) RamdiskVariantNeeded(ctx android.BaseModuleContext) bool {
return false
}
func (bpf *bpf) VendorRamdiskVariantNeeded(ctx android.BaseModuleContext) bool {
return false
}
func (bpf *bpf) DebugRamdiskVariantNeeded(ctx android.BaseModuleContext) bool {
return false
}
func (bpf *bpf) RecoveryVariantNeeded(ctx android.BaseModuleContext) bool {
return false
}
func (bpf *bpf) ExtraImageVariations(ctx android.BaseModuleContext) []string {
if proptools.Bool(bpf.properties.Vendor) {
return []string{"vendor"}
}
return nil
}
func (bpf *bpf) SetImageVariation(ctx android.BaseModuleContext, variation string, module android.Module) {
bpf.properties.VendorInternal = variation == "vendor"
}
func (bpf *bpf) GenerateAndroidBuildActions(ctx android.ModuleContext) {
cflags := []string{
"-nostdlibinc",
// Make paths in deps files relative
"-no-canonical-prefixes",
"-O2",
"-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 frameworks/libs/net/common/native/bpf_headers/include/bpf",
// TODO(b/149785767): only give access to specific file with AID_* constants
"-I system/core/libcutils/include",
"-I " + ctx.ModuleDir(),
}
for _, dir := range android.PathsForSource(ctx, bpf.properties.Include_dirs) {
cflags = append(cflags, "-I "+dir.String())
}
cflags = append(cflags, bpf.properties.Cflags...)
if proptools.Bool(bpf.properties.Btf) {
cflags = append(cflags, "-g")
if runtime.GOOS != "darwin" {
cflags = append(cflags, "-fdebug-prefix-map=/proc/self/cwd=")
}
}
srcs := android.PathsForModuleSrc(ctx, bpf.properties.Srcs)
for _, src := range srcs {
if strings.ContainsRune(filepath.Base(src.String()), '_') {
ctx.ModuleErrorf("invalid character '_' in source name")
}
obj := android.ObjPathWithExt(ctx, "unstripped", src, "o")
ctx.Build(pctx, android.BuildParams{
Rule: ccRule,
Input: src,
Output: obj,
Args: map[string]string{
"cFlags": strings.Join(cflags, " "),
"ccCmd": "${config.ClangBin}/clang",
},
})
if proptools.Bool(bpf.properties.Btf) {
objStripped := android.ObjPathWithExt(ctx, "", src, "o")
ctx.Build(pctx, android.BuildParams{
Rule: stripRule,
Input: obj,
Output: objStripped,
Args: map[string]string{
"stripCmd": "${config.ClangBin}/llvm-strip",
},
})
bpf.objs = append(bpf.objs, objStripped.WithoutRel())
} else {
bpf.objs = append(bpf.objs, obj.WithoutRel())
}
}
}
func (bpf *bpf) 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
if bpf.properties.VendorInternal {
localModulePath = "LOCAL_MODULE_PATH := $(TARGET_OUT_VENDOR_ETC)/bpf"
} else {
localModulePath = "LOCAL_MODULE_PATH := $(TARGET_OUT_ETC)/bpf"
}
if len(bpf.properties.Sub_dir) > 0 {
localModulePath += "/" + bpf.properties.Sub_dir
}
for _, obj := range bpf.objs {
objName := name + "_" + obj.Base()
names = append(names, objName)
fmt.Fprintln(w, "include $(CLEAR_VARS)")
fmt.Fprintln(w, "LOCAL_MODULE := ", objName)
data.Entries.WriteLicenseVariables(w)
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)
fmt.Fprintln(w, "include $(BUILD_PREBUILT)")
fmt.Fprintln(w)
}
fmt.Fprintln(w, "include $(CLEAR_VARS)")
fmt.Fprintln(w, "LOCAL_MODULE := ", name)
data.Entries.WriteLicenseVariables(w)
fmt.Fprintln(w, "LOCAL_REQUIRED_MODULES :=", strings.Join(names, " "))
fmt.Fprintln(w, "include $(BUILD_PHONY_PACKAGE)")
},
}
}
var _ android.MixedBuildBuildable = (*bpf)(nil)
func (bpf *bpf) IsMixedBuildSupported(ctx android.BaseModuleContext) bool {
return true
}
func (bpf *bpf) QueueBazelCall(ctx android.BaseModuleContext) {
bazelCtx := ctx.Config().BazelContext
bazelCtx.QueueBazelRequest(
bpf.GetBazelLabel(ctx, bpf),
cquery.GetOutputFiles,
android.GetConfigKey(ctx))
}
func (bpf *bpf) ProcessBazelQueryResponse(ctx android.ModuleContext) {
bazelCtx := ctx.Config().BazelContext
objPaths, err := bazelCtx.GetOutputFiles(bpf.GetBazelLabel(ctx, bpf), android.GetConfigKey(ctx))
if err != nil {
ctx.ModuleErrorf(err.Error())
return
}
bazelOuts := android.Paths{}
for _, p := range objPaths {
bazelOuts = append(bazelOuts, android.PathForBazelOut(ctx, p))
}
bpf.objs = bazelOuts
}
// Implements OutputFileFileProducer interface so that the obj output can be used in the data property
// of other modules.
func (bpf *bpf) OutputFiles(tag string) (android.Paths, error) {
switch tag {
case "":
return bpf.objs, nil
default:
return nil, fmt.Errorf("unsupported module reference tag %q", tag)
}
}
func (bpf *bpf) SubDir() string {
return bpf.properties.Sub_dir
}
var _ android.OutputFileProducer = (*bpf)(nil)
func BpfFactory() android.Module {
module := &bpf{}
module.AddProperties(&module.properties)
android.InitAndroidArchModule(module, android.DeviceSupported, android.MultilibCommon)
android.InitBazelModule(module)
return module
}
type bazelBpfAttributes struct {
Srcs bazel.LabelListAttribute
Copts bazel.StringListAttribute
Absolute_includes bazel.StringListAttribute
Btf *bool
// TODO(b/249528391): Add support for sub_dir
}
// bpf bp2build converter
func (b *bpf) ConvertWithBp2build(ctx android.TopDownMutatorContext) {
if ctx.ModuleType() != "bpf" {
return
}
srcs := bazel.MakeLabelListAttribute(android.BazelLabelForModuleSrc(ctx, b.properties.Srcs))
copts := bazel.MakeStringListAttribute(b.properties.Cflags)
absolute_includes := bazel.MakeStringListAttribute(b.properties.Include_dirs)
btf := b.properties.Btf
attrs := bazelBpfAttributes{
Srcs: srcs,
Copts: copts,
Absolute_includes: absolute_includes,
Btf: btf,
}
props := bazel.BazelTargetModuleProperties{
Rule_class: "bpf",
Bzl_load_location: "//build/bazel/rules/bpf:bpf.bzl",
}
ctx.CreateBazelTargetModule(props, android.CommonAttributes{Name: b.Name()}, &attrs)
}