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