1// Copyright 2021 Google Inc. All rights reserved. 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. 14package cc 15 16import ( 17 "android/soong/android" 18 "android/soong/bazel" 19 "path/filepath" 20 "strings" 21) 22 23// bp2build functions and helpers for converting cc_* modules to Bazel. 24 25func init() { 26 android.DepsBp2BuildMutators(RegisterDepsBp2Build) 27} 28 29func RegisterDepsBp2Build(ctx android.RegisterMutatorsContext) { 30 ctx.BottomUp("cc_bp2build_deps", depsBp2BuildMutator) 31} 32 33// A naive deps mutator to add deps on all modules across all combinations of 34// target props for cc modules. This is needed to make module -> bazel label 35// resolution work in the bp2build mutator later. This is probably 36// the wrong way to do it, but it works. 37// 38// TODO(jingwen): can we create a custom os mutator in depsBp2BuildMutator to do this? 39func depsBp2BuildMutator(ctx android.BottomUpMutatorContext) { 40 module, ok := ctx.Module().(*Module) 41 if !ok { 42 // Not a cc module 43 return 44 } 45 46 if !module.ConvertWithBp2build(ctx) { 47 return 48 } 49 50 var allDeps []string 51 52 for _, p := range module.GetTargetProperties(&BaseLinkerProperties{}) { 53 // arch specific linker props 54 if baseLinkerProps, ok := p.(*BaseLinkerProperties); ok { 55 allDeps = append(allDeps, baseLinkerProps.Header_libs...) 56 allDeps = append(allDeps, baseLinkerProps.Export_header_lib_headers...) 57 allDeps = append(allDeps, baseLinkerProps.Static_libs...) 58 allDeps = append(allDeps, baseLinkerProps.Whole_static_libs...) 59 } 60 } 61 62 for _, p := range module.GetArchProperties(ctx, &BaseLinkerProperties{}) { 63 // arch specific linker props 64 if baseLinkerProps, ok := p.(*BaseLinkerProperties); ok { 65 allDeps = append(allDeps, baseLinkerProps.Header_libs...) 66 allDeps = append(allDeps, baseLinkerProps.Export_header_lib_headers...) 67 allDeps = append(allDeps, baseLinkerProps.Static_libs...) 68 allDeps = append(allDeps, baseLinkerProps.Whole_static_libs...) 69 } 70 } 71 72 // Deps in the static: { .. } and shared: { .. } props of a cc_library. 73 if lib, ok := module.compiler.(*libraryDecorator); ok { 74 allDeps = append(allDeps, lib.SharedProperties.Shared.Static_libs...) 75 allDeps = append(allDeps, lib.SharedProperties.Shared.Whole_static_libs...) 76 allDeps = append(allDeps, lib.SharedProperties.Shared.Shared_libs...) 77 allDeps = append(allDeps, lib.SharedProperties.Shared.System_shared_libs...) 78 79 allDeps = append(allDeps, lib.StaticProperties.Static.Static_libs...) 80 allDeps = append(allDeps, lib.StaticProperties.Static.Whole_static_libs...) 81 allDeps = append(allDeps, lib.StaticProperties.Static.Shared_libs...) 82 allDeps = append(allDeps, lib.StaticProperties.Static.System_shared_libs...) 83 } 84 85 ctx.AddDependency(module, nil, android.SortedUniqueStrings(allDeps)...) 86} 87 88type sharedAttributes struct { 89 copts bazel.StringListAttribute 90 srcs bazel.LabelListAttribute 91 staticDeps bazel.LabelListAttribute 92 dynamicDeps bazel.LabelListAttribute 93 wholeArchiveDeps bazel.LabelListAttribute 94} 95 96// bp2buildParseSharedProps returns the attributes for the shared variant of a cc_library. 97func bp2BuildParseSharedProps(ctx android.TopDownMutatorContext, module *Module) sharedAttributes { 98 lib, ok := module.compiler.(*libraryDecorator) 99 if !ok { 100 return sharedAttributes{} 101 } 102 103 copts := bazel.StringListAttribute{Value: lib.SharedProperties.Shared.Cflags} 104 105 srcs := bazel.LabelListAttribute{ 106 Value: android.BazelLabelForModuleSrc(ctx, lib.SharedProperties.Shared.Srcs)} 107 108 staticDeps := bazel.LabelListAttribute{ 109 Value: android.BazelLabelForModuleDeps(ctx, lib.SharedProperties.Shared.Static_libs)} 110 111 dynamicDeps := bazel.LabelListAttribute{ 112 Value: android.BazelLabelForModuleDeps(ctx, lib.SharedProperties.Shared.Shared_libs)} 113 114 wholeArchiveDeps := bazel.LabelListAttribute{ 115 Value: android.BazelLabelForModuleDeps(ctx, lib.SharedProperties.Shared.Whole_static_libs)} 116 117 return sharedAttributes{ 118 copts: copts, 119 srcs: srcs, 120 staticDeps: staticDeps, 121 dynamicDeps: dynamicDeps, 122 wholeArchiveDeps: wholeArchiveDeps, 123 } 124} 125 126type staticAttributes struct { 127 copts bazel.StringListAttribute 128 srcs bazel.LabelListAttribute 129 staticDeps bazel.LabelListAttribute 130 dynamicDeps bazel.LabelListAttribute 131 wholeArchiveDeps bazel.LabelListAttribute 132} 133 134// bp2buildParseStaticProps returns the attributes for the static variant of a cc_library. 135func bp2BuildParseStaticProps(ctx android.TopDownMutatorContext, module *Module) staticAttributes { 136 lib, ok := module.compiler.(*libraryDecorator) 137 if !ok { 138 return staticAttributes{} 139 } 140 141 copts := bazel.StringListAttribute{Value: lib.StaticProperties.Static.Cflags} 142 143 srcs := bazel.LabelListAttribute{ 144 Value: android.BazelLabelForModuleSrc(ctx, lib.StaticProperties.Static.Srcs)} 145 146 staticDeps := bazel.LabelListAttribute{ 147 Value: android.BazelLabelForModuleDeps(ctx, lib.StaticProperties.Static.Static_libs)} 148 149 dynamicDeps := bazel.LabelListAttribute{ 150 Value: android.BazelLabelForModuleDeps(ctx, lib.StaticProperties.Static.Shared_libs)} 151 152 wholeArchiveDeps := bazel.LabelListAttribute{ 153 Value: android.BazelLabelForModuleDeps(ctx, lib.StaticProperties.Static.Whole_static_libs)} 154 155 return staticAttributes{ 156 copts: copts, 157 srcs: srcs, 158 staticDeps: staticDeps, 159 dynamicDeps: dynamicDeps, 160 wholeArchiveDeps: wholeArchiveDeps, 161 } 162} 163 164// Convenience struct to hold all attributes parsed from compiler properties. 165type compilerAttributes struct { 166 copts bazel.StringListAttribute 167 srcs bazel.LabelListAttribute 168 includes bazel.StringListAttribute 169} 170 171// bp2BuildParseCompilerProps returns copts, srcs and hdrs and other attributes. 172func bp2BuildParseCompilerProps(ctx android.TopDownMutatorContext, module *Module) compilerAttributes { 173 var srcs bazel.LabelListAttribute 174 var copts bazel.StringListAttribute 175 176 // Creates the -I flag for a directory, while making the directory relative 177 // to the exec root for Bazel to work. 178 includeFlag := func(dir string) string { 179 // filepath.Join canonicalizes the path, i.e. it takes care of . or .. elements. 180 return "-I" + filepath.Join(ctx.ModuleDir(), dir) 181 } 182 183 // Parse the list of module-relative include directories (-I). 184 parseLocalIncludeDirs := func(baseCompilerProps *BaseCompilerProperties) []string { 185 // include_dirs are root-relative, not module-relative. 186 includeDirs := bp2BuildMakePathsRelativeToModule(ctx, baseCompilerProps.Include_dirs) 187 return append(includeDirs, baseCompilerProps.Local_include_dirs...) 188 } 189 190 // Parse the list of copts. 191 parseCopts := func(baseCompilerProps *BaseCompilerProperties) []string { 192 var copts []string 193 for _, flag := range append(baseCompilerProps.Cflags, baseCompilerProps.Cppflags...) { 194 // Soong's cflags can contain spaces, like `-include header.h`. For 195 // Bazel's copts, split them up to be compatible with the 196 // no_copts_tokenization feature. 197 copts = append(copts, strings.Split(flag, " ")...) 198 } 199 for _, dir := range parseLocalIncludeDirs(baseCompilerProps) { 200 copts = append(copts, includeFlag(dir)) 201 } 202 return copts 203 } 204 205 // baseSrcs contain the list of src files that are used for every configuration. 206 var baseSrcs []string 207 // baseExcludeSrcs contain the list of src files that are excluded for every configuration. 208 var baseExcludeSrcs []string 209 // baseSrcsLabelList is a clone of the base srcs LabelList, used for computing the 210 // arch or os specific srcs later. 211 var baseSrcsLabelList bazel.LabelList 212 213 // Parse srcs from an arch or OS's props value, taking the base srcs and 214 // exclude srcs into account. 215 parseSrcs := func(baseCompilerProps *BaseCompilerProperties) bazel.LabelList { 216 // Combine the base srcs and arch-specific srcs 217 allSrcs := append(baseSrcs, baseCompilerProps.Srcs...) 218 // Combine the base exclude_srcs and configuration-specific exclude_srcs 219 allExcludeSrcs := append(baseExcludeSrcs, baseCompilerProps.Exclude_srcs...) 220 return android.BazelLabelForModuleSrcExcludes(ctx, allSrcs, allExcludeSrcs) 221 } 222 223 for _, props := range module.compiler.compilerProps() { 224 if baseCompilerProps, ok := props.(*BaseCompilerProperties); ok { 225 srcs.Value = parseSrcs(baseCompilerProps) 226 copts.Value = parseCopts(baseCompilerProps) 227 228 // Used for arch-specific srcs later. 229 baseSrcs = baseCompilerProps.Srcs 230 baseExcludeSrcs = baseCompilerProps.Exclude_srcs 231 baseSrcsLabelList = parseSrcs(baseCompilerProps) 232 break 233 } 234 } 235 236 // Handle include_build_directory prop. If the property is true, then the 237 // target has access to all headers recursively in the package, and has 238 // "-I<module-dir>" in its copts. 239 if c, ok := module.compiler.(*baseCompiler); ok && c.includeBuildDirectory() { 240 copts.Value = append(copts.Value, includeFlag(".")) 241 } else if c, ok := module.compiler.(*libraryDecorator); ok && c.includeBuildDirectory() { 242 copts.Value = append(copts.Value, includeFlag(".")) 243 } 244 245 for arch, props := range module.GetArchProperties(ctx, &BaseCompilerProperties{}) { 246 if baseCompilerProps, ok := props.(*BaseCompilerProperties); ok { 247 // If there's arch specific srcs or exclude_srcs, generate a select entry for it. 248 // TODO(b/186153868): do this for OS specific srcs and exclude_srcs too. 249 if len(baseCompilerProps.Srcs) > 0 || len(baseCompilerProps.Exclude_srcs) > 0 { 250 srcsList := parseSrcs(baseCompilerProps) 251 srcs.SetValueForArch(arch.Name, srcsList) 252 // The base srcs value should not contain any arch-specific excludes. 253 srcs.Value = bazel.SubtractBazelLabelList(srcs.Value, bazel.LabelList{Includes: srcsList.Excludes}) 254 } 255 256 copts.SetValueForArch(arch.Name, parseCopts(baseCompilerProps)) 257 } 258 } 259 260 // After going through all archs, delete the duplicate files in the arch 261 // values that are already in the base srcs.Value. 262 for arch, props := range module.GetArchProperties(ctx, &BaseCompilerProperties{}) { 263 if _, ok := props.(*BaseCompilerProperties); ok { 264 srcs.SetValueForArch(arch.Name, bazel.SubtractBazelLabelList(srcs.GetValueForArch(arch.Name), srcs.Value)) 265 } 266 } 267 268 // Now that the srcs.Value list is finalized, compare it with the original 269 // list, and put the difference into the default condition for the arch 270 // select. 271 defaultsSrcs := bazel.SubtractBazelLabelList(baseSrcsLabelList, srcs.Value) 272 // TODO(b/186153868): handle the case with multiple variant types, e.g. when arch and os are both used. 273 srcs.SetValueForArch(bazel.CONDITIONS_DEFAULT, defaultsSrcs) 274 275 // Handle OS specific props. 276 for os, props := range module.GetTargetProperties(&BaseCompilerProperties{}) { 277 if baseCompilerProps, ok := props.(*BaseCompilerProperties); ok { 278 srcsList := parseSrcs(baseCompilerProps) 279 // TODO(b/186153868): add support for os-specific srcs and exclude_srcs 280 srcs.SetValueForOS(os.Name, bazel.SubtractBazelLabelList(srcsList, baseSrcsLabelList)) 281 copts.SetValueForOS(os.Name, parseCopts(baseCompilerProps)) 282 } 283 } 284 285 return compilerAttributes{ 286 srcs: srcs, 287 copts: copts, 288 } 289} 290 291// Convenience struct to hold all attributes parsed from linker properties. 292type linkerAttributes struct { 293 deps bazel.LabelListAttribute 294 dynamicDeps bazel.LabelListAttribute 295 wholeArchiveDeps bazel.LabelListAttribute 296 linkopts bazel.StringListAttribute 297 versionScript bazel.LabelAttribute 298} 299 300// FIXME(b/187655838): Use the existing linkerFlags() function instead of duplicating logic here 301func getBp2BuildLinkerFlags(linkerProperties *BaseLinkerProperties) []string { 302 flags := linkerProperties.Ldflags 303 if !BoolDefault(linkerProperties.Pack_relocations, true) { 304 flags = append(flags, "-Wl,--pack-dyn-relocs=none") 305 } 306 return flags 307} 308 309// bp2BuildParseLinkerProps parses the linker properties of a module, including 310// configurable attribute values. 311func bp2BuildParseLinkerProps(ctx android.TopDownMutatorContext, module *Module) linkerAttributes { 312 var deps bazel.LabelListAttribute 313 var dynamicDeps bazel.LabelListAttribute 314 var wholeArchiveDeps bazel.LabelListAttribute 315 var linkopts bazel.StringListAttribute 316 var versionScript bazel.LabelAttribute 317 318 for _, linkerProps := range module.linker.linkerProps() { 319 if baseLinkerProps, ok := linkerProps.(*BaseLinkerProperties); ok { 320 libs := baseLinkerProps.Header_libs 321 libs = append(libs, baseLinkerProps.Export_header_lib_headers...) 322 libs = append(libs, baseLinkerProps.Static_libs...) 323 wholeArchiveLibs := baseLinkerProps.Whole_static_libs 324 libs = android.SortedUniqueStrings(libs) 325 deps = bazel.MakeLabelListAttribute(android.BazelLabelForModuleDeps(ctx, libs)) 326 linkopts.Value = getBp2BuildLinkerFlags(baseLinkerProps) 327 wholeArchiveDeps = bazel.MakeLabelListAttribute(android.BazelLabelForModuleDeps(ctx, wholeArchiveLibs)) 328 329 if baseLinkerProps.Version_script != nil { 330 versionScript.Value = android.BazelLabelForModuleSrcSingle(ctx, *baseLinkerProps.Version_script) 331 } 332 333 sharedLibs := baseLinkerProps.Shared_libs 334 dynamicDeps = bazel.MakeLabelListAttribute(android.BazelLabelForModuleDeps(ctx, sharedLibs)) 335 336 break 337 } 338 } 339 340 for arch, p := range module.GetArchProperties(ctx, &BaseLinkerProperties{}) { 341 if baseLinkerProps, ok := p.(*BaseLinkerProperties); ok { 342 libs := baseLinkerProps.Header_libs 343 libs = append(libs, baseLinkerProps.Export_header_lib_headers...) 344 libs = append(libs, baseLinkerProps.Static_libs...) 345 wholeArchiveLibs := baseLinkerProps.Whole_static_libs 346 libs = android.SortedUniqueStrings(libs) 347 deps.SetValueForArch(arch.Name, android.BazelLabelForModuleDeps(ctx, libs)) 348 linkopts.SetValueForArch(arch.Name, getBp2BuildLinkerFlags(baseLinkerProps)) 349 wholeArchiveDeps.SetValueForArch(arch.Name, android.BazelLabelForModuleDeps(ctx, wholeArchiveLibs)) 350 351 if baseLinkerProps.Version_script != nil { 352 versionScript.SetValueForArch(arch.Name, 353 android.BazelLabelForModuleSrcSingle(ctx, *baseLinkerProps.Version_script)) 354 } 355 356 sharedLibs := baseLinkerProps.Shared_libs 357 dynamicDeps.SetValueForArch(arch.Name, android.BazelLabelForModuleDeps(ctx, sharedLibs)) 358 } 359 } 360 361 for os, p := range module.GetTargetProperties(&BaseLinkerProperties{}) { 362 if baseLinkerProps, ok := p.(*BaseLinkerProperties); ok { 363 libs := baseLinkerProps.Header_libs 364 libs = append(libs, baseLinkerProps.Export_header_lib_headers...) 365 libs = append(libs, baseLinkerProps.Static_libs...) 366 wholeArchiveLibs := baseLinkerProps.Whole_static_libs 367 libs = android.SortedUniqueStrings(libs) 368 wholeArchiveDeps.SetValueForOS(os.Name, android.BazelLabelForModuleDeps(ctx, wholeArchiveLibs)) 369 deps.SetValueForOS(os.Name, android.BazelLabelForModuleDeps(ctx, libs)) 370 371 linkopts.SetValueForOS(os.Name, getBp2BuildLinkerFlags(baseLinkerProps)) 372 373 sharedLibs := baseLinkerProps.Shared_libs 374 dynamicDeps.SetValueForOS(os.Name, android.BazelLabelForModuleDeps(ctx, sharedLibs)) 375 } 376 } 377 378 return linkerAttributes{ 379 deps: deps, 380 dynamicDeps: dynamicDeps, 381 wholeArchiveDeps: wholeArchiveDeps, 382 linkopts: linkopts, 383 versionScript: versionScript, 384 } 385} 386 387// Relativize a list of root-relative paths with respect to the module's 388// directory. 389// 390// include_dirs Soong prop are root-relative (b/183742505), but 391// local_include_dirs, export_include_dirs and export_system_include_dirs are 392// module dir relative. This function makes a list of paths entirely module dir 393// relative. 394// 395// For the `include` attribute, Bazel wants the paths to be relative to the 396// module. 397func bp2BuildMakePathsRelativeToModule(ctx android.BazelConversionPathContext, paths []string) []string { 398 var relativePaths []string 399 for _, path := range paths { 400 // Semantics of filepath.Rel: join(ModuleDir, rel(ModuleDir, path)) == path 401 relativePath, err := filepath.Rel(ctx.ModuleDir(), path) 402 if err != nil { 403 panic(err) 404 } 405 relativePaths = append(relativePaths, relativePath) 406 } 407 return relativePaths 408} 409 410// bp2BuildParseExportedIncludes creates a string list attribute contains the 411// exported included directories of a module. 412func bp2BuildParseExportedIncludes(ctx android.TopDownMutatorContext, module *Module) bazel.StringListAttribute { 413 libraryDecorator := module.linker.(*libraryDecorator) 414 415 // Export_system_include_dirs and export_include_dirs are already module dir 416 // relative, so they don't need to be relativized like include_dirs, which 417 // are root-relative. 418 includeDirs := libraryDecorator.flagExporter.Properties.Export_system_include_dirs 419 includeDirs = append(includeDirs, libraryDecorator.flagExporter.Properties.Export_include_dirs...) 420 includeDirsAttribute := bazel.MakeStringListAttribute(includeDirs) 421 422 for arch, props := range module.GetArchProperties(ctx, &FlagExporterProperties{}) { 423 if flagExporterProperties, ok := props.(*FlagExporterProperties); ok { 424 archIncludeDirs := flagExporterProperties.Export_system_include_dirs 425 archIncludeDirs = append(archIncludeDirs, flagExporterProperties.Export_include_dirs...) 426 427 // To avoid duplicate includes when base includes + arch includes are combined 428 // FIXME: This doesn't take conflicts between arch and os includes into account 429 archIncludeDirs = bazel.SubtractStrings(archIncludeDirs, includeDirs) 430 431 if len(archIncludeDirs) > 0 { 432 includeDirsAttribute.SetValueForArch(arch.Name, archIncludeDirs) 433 } 434 } 435 } 436 437 for os, props := range module.GetTargetProperties(&FlagExporterProperties{}) { 438 if flagExporterProperties, ok := props.(*FlagExporterProperties); ok { 439 osIncludeDirs := flagExporterProperties.Export_system_include_dirs 440 osIncludeDirs = append(osIncludeDirs, flagExporterProperties.Export_include_dirs...) 441 442 // To avoid duplicate includes when base includes + os includes are combined 443 // FIXME: This doesn't take conflicts between arch and os includes into account 444 osIncludeDirs = bazel.SubtractStrings(osIncludeDirs, includeDirs) 445 446 if len(osIncludeDirs) > 0 { 447 includeDirsAttribute.SetValueForOS(os.Name, osIncludeDirs) 448 } 449 } 450 } 451 452 return includeDirsAttribute 453} 454