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 "fmt" 18 "path/filepath" 19 "strings" 20 21 "android/soong/android" 22 "android/soong/bazel" 23 24 "github.com/google/blueprint" 25 26 "github.com/google/blueprint/proptools" 27) 28 29const ( 30 cSrcPartition = "c" 31 asSrcPartition = "as" 32 cppSrcPartition = "cpp" 33 protoSrcPartition = "proto" 34) 35 36// staticOrSharedAttributes are the Bazel-ified versions of StaticOrSharedProperties -- 37// properties which apply to either the shared or static version of a cc_library module. 38type staticOrSharedAttributes struct { 39 Srcs bazel.LabelListAttribute 40 Srcs_c bazel.LabelListAttribute 41 Srcs_as bazel.LabelListAttribute 42 Hdrs bazel.LabelListAttribute 43 Copts bazel.StringListAttribute 44 45 Deps bazel.LabelListAttribute 46 Implementation_deps bazel.LabelListAttribute 47 Dynamic_deps bazel.LabelListAttribute 48 Implementation_dynamic_deps bazel.LabelListAttribute 49 Whole_archive_deps bazel.LabelListAttribute 50 Implementation_whole_archive_deps bazel.LabelListAttribute 51 52 System_dynamic_deps bazel.LabelListAttribute 53 54 Enabled bazel.BoolAttribute 55 56 sdkAttributes 57} 58 59// groupSrcsByExtension partitions `srcs` into groups based on file extension. 60func groupSrcsByExtension(ctx android.BazelConversionPathContext, srcs bazel.LabelListAttribute) bazel.PartitionToLabelListAttribute { 61 // Convert filegroup dependencies into extension-specific filegroups filtered in the filegroup.bzl 62 // macro. 63 addSuffixForFilegroup := func(suffix string) bazel.LabelMapper { 64 return func(ctx bazel.OtherModuleContext, label bazel.Label) (string, bool) { 65 m, exists := ctx.ModuleFromName(label.OriginalModuleName) 66 labelStr := label.Label 67 if !exists || !android.IsFilegroup(ctx, m) { 68 return labelStr, false 69 } 70 return labelStr + suffix, true 71 } 72 } 73 74 // TODO(b/190006308): Handle language detection of sources in a Bazel rule. 75 labels := bazel.LabelPartitions{ 76 protoSrcPartition: android.ProtoSrcLabelPartition, 77 cSrcPartition: bazel.LabelPartition{Extensions: []string{".c"}, LabelMapper: addSuffixForFilegroup("_c_srcs")}, 78 asSrcPartition: bazel.LabelPartition{Extensions: []string{".s", ".S"}, LabelMapper: addSuffixForFilegroup("_as_srcs")}, 79 // C++ is the "catch-all" group, and comprises generated sources because we don't 80 // know the language of these sources until the genrule is executed. 81 cppSrcPartition: bazel.LabelPartition{Extensions: []string{".cpp", ".cc", ".cxx", ".mm"}, LabelMapper: addSuffixForFilegroup("_cpp_srcs"), Keep_remainder: true}, 82 } 83 84 return bazel.PartitionLabelListAttribute(ctx, &srcs, labels) 85} 86 87// bp2BuildParseLibProps returns the attributes for a variant of a cc_library. 88func bp2BuildParseLibProps(ctx android.BazelConversionPathContext, module *Module, isStatic bool) staticOrSharedAttributes { 89 lib, ok := module.compiler.(*libraryDecorator) 90 if !ok { 91 return staticOrSharedAttributes{} 92 } 93 return bp2buildParseStaticOrSharedProps(ctx, module, lib, isStatic) 94} 95 96// bp2buildParseSharedProps returns the attributes for the shared variant of a cc_library. 97func bp2BuildParseSharedProps(ctx android.BazelConversionPathContext, module *Module) staticOrSharedAttributes { 98 return bp2BuildParseLibProps(ctx, module, false) 99} 100 101// bp2buildParseStaticProps returns the attributes for the static variant of a cc_library. 102func bp2BuildParseStaticProps(ctx android.BazelConversionPathContext, module *Module) staticOrSharedAttributes { 103 return bp2BuildParseLibProps(ctx, module, true) 104} 105 106type depsPartition struct { 107 export bazel.LabelList 108 implementation bazel.LabelList 109} 110 111type bazelLabelForDepsFn func(android.BazelConversionPathContext, []string) bazel.LabelList 112 113func maybePartitionExportedAndImplementationsDeps(ctx android.BazelConversionPathContext, exportsDeps bool, allDeps, exportedDeps []string, fn bazelLabelForDepsFn) depsPartition { 114 if !exportsDeps { 115 return depsPartition{ 116 implementation: fn(ctx, allDeps), 117 } 118 } 119 120 implementation, export := android.FilterList(allDeps, exportedDeps) 121 122 return depsPartition{ 123 export: fn(ctx, export), 124 implementation: fn(ctx, implementation), 125 } 126} 127 128type bazelLabelForDepsExcludesFn func(android.BazelConversionPathContext, []string, []string) bazel.LabelList 129 130func maybePartitionExportedAndImplementationsDepsExcludes(ctx android.BazelConversionPathContext, exportsDeps bool, allDeps, excludes, exportedDeps []string, fn bazelLabelForDepsExcludesFn) depsPartition { 131 if !exportsDeps { 132 return depsPartition{ 133 implementation: fn(ctx, allDeps, excludes), 134 } 135 } 136 implementation, export := android.FilterList(allDeps, exportedDeps) 137 138 return depsPartition{ 139 export: fn(ctx, export, excludes), 140 implementation: fn(ctx, implementation, excludes), 141 } 142} 143 144// Parses properties common to static and shared libraries. Also used for prebuilt libraries. 145func bp2buildParseStaticOrSharedProps(ctx android.BazelConversionPathContext, module *Module, lib *libraryDecorator, isStatic bool) staticOrSharedAttributes { 146 attrs := staticOrSharedAttributes{} 147 148 setAttrs := func(axis bazel.ConfigurationAxis, config string, props StaticOrSharedProperties) { 149 attrs.Copts.SetSelectValue(axis, config, parseCommandLineFlags(props.Cflags, filterOutStdFlag)) 150 attrs.Srcs.SetSelectValue(axis, config, android.BazelLabelForModuleSrc(ctx, props.Srcs)) 151 attrs.System_dynamic_deps.SetSelectValue(axis, config, bazelLabelForSharedDeps(ctx, props.System_shared_libs)) 152 153 staticDeps := maybePartitionExportedAndImplementationsDeps(ctx, true, props.Static_libs, props.Export_static_lib_headers, bazelLabelForStaticDeps) 154 attrs.Deps.SetSelectValue(axis, config, staticDeps.export) 155 attrs.Implementation_deps.SetSelectValue(axis, config, staticDeps.implementation) 156 157 sharedDeps := maybePartitionExportedAndImplementationsDeps(ctx, true, props.Shared_libs, props.Export_shared_lib_headers, bazelLabelForSharedDeps) 158 attrs.Dynamic_deps.SetSelectValue(axis, config, sharedDeps.export) 159 attrs.Implementation_dynamic_deps.SetSelectValue(axis, config, sharedDeps.implementation) 160 161 attrs.Whole_archive_deps.SetSelectValue(axis, config, bazelLabelForWholeDeps(ctx, props.Whole_static_libs)) 162 attrs.Enabled.SetSelectValue(axis, config, props.Enabled) 163 } 164 // system_dynamic_deps distinguishes between nil/empty list behavior: 165 // nil -> use default values 166 // empty list -> no values specified 167 attrs.System_dynamic_deps.ForceSpecifyEmptyList = true 168 169 if isStatic { 170 for axis, configToProps := range module.GetArchVariantProperties(ctx, &StaticProperties{}) { 171 for config, props := range configToProps { 172 if staticOrSharedProps, ok := props.(*StaticProperties); ok { 173 setAttrs(axis, config, staticOrSharedProps.Static) 174 } 175 } 176 } 177 } else { 178 for axis, configToProps := range module.GetArchVariantProperties(ctx, &SharedProperties{}) { 179 for config, props := range configToProps { 180 if staticOrSharedProps, ok := props.(*SharedProperties); ok { 181 setAttrs(axis, config, staticOrSharedProps.Shared) 182 } 183 } 184 } 185 } 186 187 partitionedSrcs := groupSrcsByExtension(ctx, attrs.Srcs) 188 attrs.Srcs = partitionedSrcs[cppSrcPartition] 189 attrs.Srcs_c = partitionedSrcs[cSrcPartition] 190 attrs.Srcs_as = partitionedSrcs[asSrcPartition] 191 192 if !partitionedSrcs[protoSrcPartition].IsEmpty() { 193 // TODO(b/208815215): determine whether this is used and add support if necessary 194 ctx.ModuleErrorf("Migrating static/shared only proto srcs is not currently supported") 195 } 196 197 return attrs 198} 199 200// Convenience struct to hold all attributes parsed from prebuilt properties. 201type prebuiltAttributes struct { 202 Src bazel.LabelAttribute 203 Enabled bazel.BoolAttribute 204} 205 206// NOTE: Used outside of Soong repo project, in the clangprebuilts.go bootstrap_go_package 207func Bp2BuildParsePrebuiltLibraryProps(ctx android.BazelConversionPathContext, module *Module, isStatic bool) prebuiltAttributes { 208 manySourceFileError := func(axis bazel.ConfigurationAxis, config string) { 209 ctx.ModuleErrorf("Bp2BuildParsePrebuiltLibraryProps: Expected at most one source file for %s %s\n", axis, config) 210 } 211 var srcLabelAttribute bazel.LabelAttribute 212 213 parseSrcs := func(ctx android.BazelConversionPathContext, axis bazel.ConfigurationAxis, config string, srcs []string) { 214 if len(srcs) > 1 { 215 manySourceFileError(axis, config) 216 return 217 } else if len(srcs) == 0 { 218 return 219 } 220 if srcLabelAttribute.SelectValue(axis, config) != nil { 221 manySourceFileError(axis, config) 222 return 223 } 224 225 src := android.BazelLabelForModuleSrcSingle(ctx, srcs[0]) 226 srcLabelAttribute.SetSelectValue(axis, config, src) 227 } 228 229 bp2BuildPropParseHelper(ctx, module, &prebuiltLinkerProperties{}, func(axis bazel.ConfigurationAxis, config string, props interface{}) { 230 if prebuiltLinkerProperties, ok := props.(*prebuiltLinkerProperties); ok { 231 parseSrcs(ctx, axis, config, prebuiltLinkerProperties.Srcs) 232 } 233 }) 234 235 var enabledLabelAttribute bazel.BoolAttribute 236 parseAttrs := func(axis bazel.ConfigurationAxis, config string, props StaticOrSharedProperties) { 237 if props.Enabled != nil { 238 enabledLabelAttribute.SetSelectValue(axis, config, props.Enabled) 239 } 240 parseSrcs(ctx, axis, config, props.Srcs) 241 } 242 243 if isStatic { 244 bp2BuildPropParseHelper(ctx, module, &StaticProperties{}, func(axis bazel.ConfigurationAxis, config string, props interface{}) { 245 if staticProperties, ok := props.(*StaticProperties); ok { 246 parseAttrs(axis, config, staticProperties.Static) 247 } 248 }) 249 } else { 250 bp2BuildPropParseHelper(ctx, module, &SharedProperties{}, func(axis bazel.ConfigurationAxis, config string, props interface{}) { 251 if sharedProperties, ok := props.(*SharedProperties); ok { 252 parseAttrs(axis, config, sharedProperties.Shared) 253 } 254 }) 255 } 256 257 return prebuiltAttributes{ 258 Src: srcLabelAttribute, 259 Enabled: enabledLabelAttribute, 260 } 261} 262 263func bp2BuildPropParseHelper(ctx android.ArchVariantContext, module *Module, propsType interface{}, parseFunc func(axis bazel.ConfigurationAxis, config string, props interface{})) { 264 for axis, configToProps := range module.GetArchVariantProperties(ctx, propsType) { 265 for config, props := range configToProps { 266 parseFunc(axis, config, props) 267 } 268 } 269} 270 271type baseAttributes struct { 272 compilerAttributes 273 linkerAttributes 274 275 protoDependency *bazel.LabelAttribute 276} 277 278// Convenience struct to hold all attributes parsed from compiler properties. 279type compilerAttributes struct { 280 // Options for all languages 281 copts bazel.StringListAttribute 282 // Assembly options and sources 283 asFlags bazel.StringListAttribute 284 asSrcs bazel.LabelListAttribute 285 // C options and sources 286 conlyFlags bazel.StringListAttribute 287 cSrcs bazel.LabelListAttribute 288 // C++ options and sources 289 cppFlags bazel.StringListAttribute 290 srcs bazel.LabelListAttribute 291 292 hdrs bazel.LabelListAttribute 293 294 rtti bazel.BoolAttribute 295 296 // Not affected by arch variants 297 stl *string 298 cStd *string 299 cppStd *string 300 301 localIncludes bazel.StringListAttribute 302 absoluteIncludes bazel.StringListAttribute 303 304 includes BazelIncludes 305 306 protoSrcs bazel.LabelListAttribute 307 308 stubsSymbolFile *string 309 stubsVersions bazel.StringListAttribute 310} 311 312type filterOutFn func(string) bool 313 314func filterOutStdFlag(flag string) bool { 315 return strings.HasPrefix(flag, "-std=") 316} 317 318func parseCommandLineFlags(soongFlags []string, filterOut filterOutFn) []string { 319 var result []string 320 for _, flag := range soongFlags { 321 if filterOut != nil && filterOut(flag) { 322 continue 323 } 324 // Soong's cflags can contain spaces, like `-include header.h`. For 325 // Bazel's copts, split them up to be compatible with the 326 // no_copts_tokenization feature. 327 result = append(result, strings.Split(flag, " ")...) 328 } 329 return result 330} 331 332func (ca *compilerAttributes) bp2buildForAxisAndConfig(ctx android.BazelConversionPathContext, axis bazel.ConfigurationAxis, config string, props *BaseCompilerProperties) { 333 // If there's arch specific srcs or exclude_srcs, generate a select entry for it. 334 // TODO(b/186153868): do this for OS specific srcs and exclude_srcs too. 335 if srcsList, ok := parseSrcs(ctx, props); ok { 336 ca.srcs.SetSelectValue(axis, config, srcsList) 337 } 338 339 localIncludeDirs := props.Local_include_dirs 340 if axis == bazel.NoConfigAxis { 341 ca.cStd, ca.cppStd = bp2buildResolveCppStdValue(props.C_std, props.Cpp_std, props.Gnu_extensions) 342 if includeBuildDirectory(props.Include_build_directory) { 343 localIncludeDirs = append(localIncludeDirs, ".") 344 } 345 } 346 347 ca.absoluteIncludes.SetSelectValue(axis, config, props.Include_dirs) 348 ca.localIncludes.SetSelectValue(axis, config, localIncludeDirs) 349 350 // In Soong, cflags occur on the command line before -std=<val> flag, resulting in the value being 351 // overridden. In Bazel we always allow overriding, via flags; however, this can cause 352 // incompatibilities, so we remove "-std=" flags from Cflag properties while leaving it in other 353 // cases. 354 ca.copts.SetSelectValue(axis, config, parseCommandLineFlags(props.Cflags, filterOutStdFlag)) 355 ca.asFlags.SetSelectValue(axis, config, parseCommandLineFlags(props.Asflags, nil)) 356 ca.conlyFlags.SetSelectValue(axis, config, parseCommandLineFlags(props.Conlyflags, nil)) 357 ca.cppFlags.SetSelectValue(axis, config, parseCommandLineFlags(props.Cppflags, nil)) 358 ca.rtti.SetSelectValue(axis, config, props.Rtti) 359} 360 361func (ca *compilerAttributes) convertStlProps(ctx android.ArchVariantContext, module *Module) { 362 stlPropsByArch := module.GetArchVariantProperties(ctx, &StlProperties{}) 363 for _, configToProps := range stlPropsByArch { 364 for _, props := range configToProps { 365 if stlProps, ok := props.(*StlProperties); ok { 366 if stlProps.Stl == nil { 367 continue 368 } 369 if ca.stl == nil { 370 ca.stl = stlProps.Stl 371 } else if ca.stl != stlProps.Stl { 372 ctx.ModuleErrorf("Unsupported conversion: module with different stl for different variants: %s and %s", *ca.stl, stlProps.Stl) 373 } 374 } 375 } 376 } 377} 378 379func (ca *compilerAttributes) convertProductVariables(ctx android.BazelConversionPathContext, productVariableProps android.ProductConfigProperties) { 380 productVarPropNameToAttribute := map[string]*bazel.StringListAttribute{ 381 "Cflags": &ca.copts, 382 "Asflags": &ca.asFlags, 383 "CppFlags": &ca.cppFlags, 384 } 385 for propName, attr := range productVarPropNameToAttribute { 386 if productConfigProps, exists := productVariableProps[propName]; exists { 387 for productConfigProp, prop := range productConfigProps { 388 flags, ok := prop.([]string) 389 if !ok { 390 ctx.ModuleErrorf("Could not convert product variable %s property", proptools.PropertyNameForField(propName)) 391 } 392 newFlags, _ := bazel.TryVariableSubstitutions(flags, productConfigProp.Name) 393 attr.SetSelectValue(productConfigProp.ConfigurationAxis(), productConfigProp.SelectKey(), newFlags) 394 } 395 } 396 } 397} 398 399func (ca *compilerAttributes) finalize(ctx android.BazelConversionPathContext, implementationHdrs bazel.LabelListAttribute) { 400 ca.srcs.ResolveExcludes() 401 partitionedSrcs := groupSrcsByExtension(ctx, ca.srcs) 402 403 ca.protoSrcs = partitionedSrcs[protoSrcPartition] 404 405 for p, lla := range partitionedSrcs { 406 // if there are no sources, there is no need for headers 407 if lla.IsEmpty() { 408 continue 409 } 410 lla.Append(implementationHdrs) 411 partitionedSrcs[p] = lla 412 } 413 414 ca.srcs = partitionedSrcs[cppSrcPartition] 415 ca.cSrcs = partitionedSrcs[cSrcPartition] 416 ca.asSrcs = partitionedSrcs[asSrcPartition] 417 418 ca.absoluteIncludes.DeduplicateAxesFromBase() 419 ca.localIncludes.DeduplicateAxesFromBase() 420} 421 422// Parse srcs from an arch or OS's props value. 423func parseSrcs(ctx android.BazelConversionPathContext, props *BaseCompilerProperties) (bazel.LabelList, bool) { 424 anySrcs := false 425 // Add srcs-like dependencies such as generated files. 426 // First create a LabelList containing these dependencies, then merge the values with srcs. 427 generatedSrcsLabelList := android.BazelLabelForModuleDepsExcludes(ctx, props.Generated_sources, props.Exclude_generated_sources) 428 if len(props.Generated_sources) > 0 || len(props.Exclude_generated_sources) > 0 { 429 anySrcs = true 430 } 431 432 allSrcsLabelList := android.BazelLabelForModuleSrcExcludes(ctx, props.Srcs, props.Exclude_srcs) 433 if len(props.Srcs) > 0 || len(props.Exclude_srcs) > 0 { 434 anySrcs = true 435 } 436 return bazel.AppendBazelLabelLists(allSrcsLabelList, generatedSrcsLabelList), anySrcs 437} 438 439func bp2buildResolveCppStdValue(c_std *string, cpp_std *string, gnu_extensions *bool) (*string, *string) { 440 var cStdVal, cppStdVal string 441 // If c{,pp}std properties are not specified, don't generate them in the BUILD file. 442 // Defaults are handled by the toolchain definition. 443 // However, if gnu_extensions is false, then the default gnu-to-c version must be specified. 444 if cpp_std != nil { 445 cppStdVal = parseCppStd(cpp_std) 446 } else if gnu_extensions != nil && !*gnu_extensions { 447 cppStdVal = "c++17" 448 } 449 if c_std != nil { 450 cStdVal = parseCStd(c_std) 451 } else if gnu_extensions != nil && !*gnu_extensions { 452 cStdVal = "c99" 453 } 454 455 cStdVal, cppStdVal = maybeReplaceGnuToC(gnu_extensions, cStdVal, cppStdVal) 456 var c_std_prop, cpp_std_prop *string 457 if cStdVal != "" { 458 c_std_prop = &cStdVal 459 } 460 if cppStdVal != "" { 461 cpp_std_prop = &cppStdVal 462 } 463 464 return c_std_prop, cpp_std_prop 465} 466 467// packageFromLabel extracts package from a fully-qualified or relative Label and whether the label 468// is fully-qualified. 469// e.g. fully-qualified "//a/b:foo" -> "a/b", true, relative: ":bar" -> ".", false 470func packageFromLabel(label string) (string, bool) { 471 split := strings.Split(label, ":") 472 if len(split) != 2 { 473 return "", false 474 } 475 if split[0] == "" { 476 return ".", false 477 } 478 // remove leading "//" 479 return split[0][2:], true 480} 481 482// includesFromLabelList extracts relative/absolute includes from a bazel.LabelList> 483func includesFromLabelList(labelList bazel.LabelList) (relative, absolute []string) { 484 for _, hdr := range labelList.Includes { 485 if pkg, hasPkg := packageFromLabel(hdr.Label); hasPkg { 486 absolute = append(absolute, pkg) 487 } else if pkg != "" { 488 relative = append(relative, pkg) 489 } 490 } 491 return relative, absolute 492} 493 494// bp2BuildParseBaseProps returns all compiler, linker, library attributes of a cc module.. 495func bp2BuildParseBaseProps(ctx android.Bp2buildMutatorContext, module *Module) baseAttributes { 496 archVariantCompilerProps := module.GetArchVariantProperties(ctx, &BaseCompilerProperties{}) 497 archVariantLinkerProps := module.GetArchVariantProperties(ctx, &BaseLinkerProperties{}) 498 archVariantLibraryProperties := module.GetArchVariantProperties(ctx, &LibraryProperties{}) 499 500 var implementationHdrs bazel.LabelListAttribute 501 502 axisToConfigs := map[bazel.ConfigurationAxis]map[string]bool{} 503 allAxesAndConfigs := func(cp android.ConfigurationAxisToArchVariantProperties) { 504 for axis, configMap := range cp { 505 if _, ok := axisToConfigs[axis]; !ok { 506 axisToConfigs[axis] = map[string]bool{} 507 } 508 for config, _ := range configMap { 509 axisToConfigs[axis][config] = true 510 } 511 } 512 } 513 allAxesAndConfigs(archVariantCompilerProps) 514 allAxesAndConfigs(archVariantLinkerProps) 515 allAxesAndConfigs(archVariantLibraryProperties) 516 517 compilerAttrs := compilerAttributes{} 518 linkerAttrs := linkerAttributes{} 519 520 for axis, configs := range axisToConfigs { 521 for config, _ := range configs { 522 var allHdrs []string 523 if baseCompilerProps, ok := archVariantCompilerProps[axis][config].(*BaseCompilerProperties); ok { 524 allHdrs = baseCompilerProps.Generated_headers 525 526 (&compilerAttrs).bp2buildForAxisAndConfig(ctx, axis, config, baseCompilerProps) 527 } 528 529 var exportHdrs []string 530 531 if baseLinkerProps, ok := archVariantLinkerProps[axis][config].(*BaseLinkerProperties); ok { 532 exportHdrs = baseLinkerProps.Export_generated_headers 533 534 (&linkerAttrs).bp2buildForAxisAndConfig(ctx, module.Binary(), axis, config, baseLinkerProps) 535 } 536 headers := maybePartitionExportedAndImplementationsDeps(ctx, !module.Binary(), allHdrs, exportHdrs, android.BazelLabelForModuleDeps) 537 implementationHdrs.SetSelectValue(axis, config, headers.implementation) 538 compilerAttrs.hdrs.SetSelectValue(axis, config, headers.export) 539 540 exportIncludes, exportAbsoluteIncludes := includesFromLabelList(headers.export) 541 compilerAttrs.includes.Includes.SetSelectValue(axis, config, exportIncludes) 542 compilerAttrs.includes.AbsoluteIncludes.SetSelectValue(axis, config, exportAbsoluteIncludes) 543 544 includes, absoluteIncludes := includesFromLabelList(headers.implementation) 545 currAbsoluteIncludes := compilerAttrs.absoluteIncludes.SelectValue(axis, config) 546 currAbsoluteIncludes = android.FirstUniqueStrings(append(currAbsoluteIncludes, absoluteIncludes...)) 547 compilerAttrs.absoluteIncludes.SetSelectValue(axis, config, currAbsoluteIncludes) 548 currIncludes := compilerAttrs.localIncludes.SelectValue(axis, config) 549 currIncludes = android.FirstUniqueStrings(append(currIncludes, includes...)) 550 compilerAttrs.localIncludes.SetSelectValue(axis, config, currIncludes) 551 552 if libraryProps, ok := archVariantLibraryProperties[axis][config].(*LibraryProperties); ok { 553 if axis == bazel.NoConfigAxis { 554 compilerAttrs.stubsSymbolFile = libraryProps.Stubs.Symbol_file 555 compilerAttrs.stubsVersions.SetSelectValue(axis, config, libraryProps.Stubs.Versions) 556 } 557 } 558 } 559 } 560 561 compilerAttrs.convertStlProps(ctx, module) 562 (&linkerAttrs).convertStripProps(ctx, module) 563 564 productVariableProps := android.ProductVariableProperties(ctx) 565 566 (&compilerAttrs).convertProductVariables(ctx, productVariableProps) 567 (&linkerAttrs).convertProductVariables(ctx, productVariableProps) 568 569 (&compilerAttrs).finalize(ctx, implementationHdrs) 570 (&linkerAttrs).finalize(ctx) 571 572 protoDep := bp2buildProto(ctx, module, compilerAttrs.protoSrcs) 573 574 // bp2buildProto will only set wholeStaticLib or implementationWholeStaticLib, but we don't know 575 // which. This will add the newly generated proto library to the appropriate attribute and nothing 576 // to the other 577 (&linkerAttrs).wholeArchiveDeps.Add(protoDep.wholeStaticLib) 578 (&linkerAttrs).implementationWholeArchiveDeps.Add(protoDep.implementationWholeStaticLib) 579 580 return baseAttributes{ 581 compilerAttrs, 582 linkerAttrs, 583 protoDep.protoDep, 584 } 585} 586 587func bp2BuildParseSdkAttributes(module *Module) sdkAttributes { 588 return sdkAttributes{ 589 Sdk_version: module.Properties.Sdk_version, 590 Min_sdk_version: module.Properties.Min_sdk_version, 591 } 592} 593 594type sdkAttributes struct { 595 Sdk_version *string 596 Min_sdk_version *string 597} 598 599// Convenience struct to hold all attributes parsed from linker properties. 600type linkerAttributes struct { 601 deps bazel.LabelListAttribute 602 implementationDeps bazel.LabelListAttribute 603 dynamicDeps bazel.LabelListAttribute 604 implementationDynamicDeps bazel.LabelListAttribute 605 wholeArchiveDeps bazel.LabelListAttribute 606 implementationWholeArchiveDeps bazel.LabelListAttribute 607 systemDynamicDeps bazel.LabelListAttribute 608 usedSystemDynamicDepAsDynamicDep map[string]bool 609 610 linkCrt bazel.BoolAttribute 611 useLibcrt bazel.BoolAttribute 612 useVersionLib bazel.BoolAttribute 613 linkopts bazel.StringListAttribute 614 additionalLinkerInputs bazel.LabelListAttribute 615 stripKeepSymbols bazel.BoolAttribute 616 stripKeepSymbolsAndDebugFrame bazel.BoolAttribute 617 stripKeepSymbolsList bazel.StringListAttribute 618 stripAll bazel.BoolAttribute 619 stripNone bazel.BoolAttribute 620 features bazel.StringListAttribute 621} 622 623var ( 624 soongSystemSharedLibs = []string{"libc", "libm", "libdl"} 625) 626 627func (la *linkerAttributes) bp2buildForAxisAndConfig(ctx android.BazelConversionPathContext, isBinary bool, axis bazel.ConfigurationAxis, config string, props *BaseLinkerProperties) { 628 // Use a single variable to capture usage of nocrt in arch variants, so there's only 1 error message for this module 629 var axisFeatures []string 630 631 wholeStaticLibs := android.FirstUniqueStrings(props.Whole_static_libs) 632 la.wholeArchiveDeps.SetSelectValue(axis, config, bazelLabelForWholeDepsExcludes(ctx, wholeStaticLibs, props.Exclude_static_libs)) 633 // Excludes to parallel Soong: 634 // https://cs.android.com/android/platform/superproject/+/master:build/soong/cc/linker.go;l=247-249;drc=088b53577dde6e40085ffd737a1ae96ad82fc4b0 635 staticLibs := android.FirstUniqueStrings(android.RemoveListFromList(props.Static_libs, wholeStaticLibs)) 636 637 staticDeps := maybePartitionExportedAndImplementationsDepsExcludes(ctx, !isBinary, staticLibs, props.Exclude_static_libs, props.Export_static_lib_headers, bazelLabelForStaticDepsExcludes) 638 639 headerLibs := android.FirstUniqueStrings(props.Header_libs) 640 hDeps := maybePartitionExportedAndImplementationsDeps(ctx, !isBinary, headerLibs, props.Export_header_lib_headers, bazelLabelForHeaderDeps) 641 642 (&hDeps.export).Append(staticDeps.export) 643 la.deps.SetSelectValue(axis, config, hDeps.export) 644 645 (&hDeps.implementation).Append(staticDeps.implementation) 646 la.implementationDeps.SetSelectValue(axis, config, hDeps.implementation) 647 648 systemSharedLibs := props.System_shared_libs 649 // systemSharedLibs distinguishes between nil/empty list behavior: 650 // nil -> use default values 651 // empty list -> no values specified 652 if len(systemSharedLibs) > 0 { 653 systemSharedLibs = android.FirstUniqueStrings(systemSharedLibs) 654 } 655 la.systemDynamicDeps.SetSelectValue(axis, config, bazelLabelForSharedDeps(ctx, systemSharedLibs)) 656 657 sharedLibs := android.FirstUniqueStrings(props.Shared_libs) 658 excludeSharedLibs := props.Exclude_shared_libs 659 usedSystem := android.FilterListPred(sharedLibs, func(s string) bool { 660 return android.InList(s, soongSystemSharedLibs) && !android.InList(s, excludeSharedLibs) 661 }) 662 for _, el := range usedSystem { 663 if la.usedSystemDynamicDepAsDynamicDep == nil { 664 la.usedSystemDynamicDepAsDynamicDep = map[string]bool{} 665 } 666 la.usedSystemDynamicDepAsDynamicDep[el] = true 667 } 668 669 sharedDeps := maybePartitionExportedAndImplementationsDepsExcludes(ctx, !isBinary, sharedLibs, props.Exclude_shared_libs, props.Export_shared_lib_headers, bazelLabelForSharedDepsExcludes) 670 la.dynamicDeps.SetSelectValue(axis, config, sharedDeps.export) 671 la.implementationDynamicDeps.SetSelectValue(axis, config, sharedDeps.implementation) 672 673 if !BoolDefault(props.Pack_relocations, packRelocationsDefault) { 674 axisFeatures = append(axisFeatures, "disable_pack_relocations") 675 } 676 677 if Bool(props.Allow_undefined_symbols) { 678 axisFeatures = append(axisFeatures, "-no_undefined_symbols") 679 } 680 681 var linkerFlags []string 682 if len(props.Ldflags) > 0 { 683 linkerFlags = append(linkerFlags, proptools.NinjaEscapeList(props.Ldflags)...) 684 // binaries remove static flag if -shared is in the linker flags 685 if isBinary && android.InList("-shared", linkerFlags) { 686 axisFeatures = append(axisFeatures, "-static_flag") 687 } 688 } 689 if props.Version_script != nil { 690 label := android.BazelLabelForModuleSrcSingle(ctx, *props.Version_script) 691 la.additionalLinkerInputs.SetSelectValue(axis, config, bazel.LabelList{Includes: []bazel.Label{label}}) 692 linkerFlags = append(linkerFlags, fmt.Sprintf("-Wl,--version-script,$(location %s)", label.Label)) 693 } 694 la.linkopts.SetSelectValue(axis, config, linkerFlags) 695 la.useLibcrt.SetSelectValue(axis, config, props.libCrt()) 696 697 if axis == bazel.NoConfigAxis { 698 la.useVersionLib.SetSelectValue(axis, config, props.Use_version_lib) 699 } 700 701 // it's very unlikely for nocrt to be arch variant, so bp2build doesn't support it. 702 if props.crt() != nil { 703 if axis == bazel.NoConfigAxis { 704 la.linkCrt.SetSelectValue(axis, config, props.crt()) 705 } else if axis == bazel.ArchConfigurationAxis { 706 ctx.ModuleErrorf("nocrt is not supported for arch variants") 707 } 708 } 709 710 if axisFeatures != nil { 711 la.features.SetSelectValue(axis, config, axisFeatures) 712 } 713} 714 715func (la *linkerAttributes) convertStripProps(ctx android.BazelConversionPathContext, module *Module) { 716 for axis, configToProps := range module.GetArchVariantProperties(ctx, &StripProperties{}) { 717 for config, props := range configToProps { 718 if stripProperties, ok := props.(*StripProperties); ok { 719 la.stripKeepSymbols.SetSelectValue(axis, config, stripProperties.Strip.Keep_symbols) 720 la.stripKeepSymbolsList.SetSelectValue(axis, config, stripProperties.Strip.Keep_symbols_list) 721 la.stripKeepSymbolsAndDebugFrame.SetSelectValue(axis, config, stripProperties.Strip.Keep_symbols_and_debug_frame) 722 la.stripAll.SetSelectValue(axis, config, stripProperties.Strip.All) 723 la.stripNone.SetSelectValue(axis, config, stripProperties.Strip.None) 724 } 725 } 726 } 727} 728 729func (la *linkerAttributes) convertProductVariables(ctx android.BazelConversionPathContext, productVariableProps android.ProductConfigProperties) { 730 731 type productVarDep struct { 732 // the name of the corresponding excludes field, if one exists 733 excludesField string 734 // reference to the bazel attribute that should be set for the given product variable config 735 attribute *bazel.LabelListAttribute 736 737 depResolutionFunc func(ctx android.BazelConversionPathContext, modules, excludes []string) bazel.LabelList 738 } 739 740 productVarToDepFields := map[string]productVarDep{ 741 // product variables do not support exclude_shared_libs 742 "Shared_libs": {attribute: &la.implementationDynamicDeps, depResolutionFunc: bazelLabelForSharedDepsExcludes}, 743 "Static_libs": {"Exclude_static_libs", &la.implementationDeps, bazelLabelForStaticDepsExcludes}, 744 "Whole_static_libs": {"Exclude_static_libs", &la.wholeArchiveDeps, bazelLabelForWholeDepsExcludes}, 745 } 746 747 for name, dep := range productVarToDepFields { 748 props, exists := productVariableProps[name] 749 excludeProps, excludesExists := productVariableProps[dep.excludesField] 750 // if neither an include or excludes property exists, then skip it 751 if !exists && !excludesExists { 752 continue 753 } 754 // Collect all the configurations that an include or exclude property exists for. 755 // We want to iterate all configurations rather than either the include or exclude because, for a 756 // particular configuration, we may have either only an include or an exclude to handle. 757 productConfigProps := make(map[android.ProductConfigProperty]bool, len(props)+len(excludeProps)) 758 for p := range props { 759 productConfigProps[p] = true 760 } 761 for p := range excludeProps { 762 productConfigProps[p] = true 763 } 764 765 for productConfigProp := range productConfigProps { 766 prop, includesExists := props[productConfigProp] 767 excludesProp, excludesExists := excludeProps[productConfigProp] 768 var includes, excludes []string 769 var ok bool 770 // if there was no includes/excludes property, casting fails and that's expected 771 if includes, ok = prop.([]string); includesExists && !ok { 772 ctx.ModuleErrorf("Could not convert product variable %s property", name) 773 } 774 if excludes, ok = excludesProp.([]string); excludesExists && !ok { 775 ctx.ModuleErrorf("Could not convert product variable %s property", dep.excludesField) 776 } 777 778 dep.attribute.EmitEmptyList = productConfigProp.AlwaysEmit() 779 dep.attribute.SetSelectValue( 780 productConfigProp.ConfigurationAxis(), 781 productConfigProp.SelectKey(), 782 dep.depResolutionFunc(ctx, android.FirstUniqueStrings(includes), excludes), 783 ) 784 } 785 } 786} 787 788func (la *linkerAttributes) finalize(ctx android.BazelConversionPathContext) { 789 // if system dynamic deps have the default value, any use of a system dynamic library used will 790 // result in duplicate library errors for bionic OSes. Here, we explicitly exclude those libraries 791 // from bionic OSes. 792 if la.systemDynamicDeps.IsNil() && len(la.usedSystemDynamicDepAsDynamicDep) > 0 { 793 toRemove := bazelLabelForSharedDeps(ctx, android.SortedStringKeys(la.usedSystemDynamicDepAsDynamicDep)) 794 la.dynamicDeps.Exclude(bazel.OsConfigurationAxis, "android", toRemove) 795 la.dynamicDeps.Exclude(bazel.OsConfigurationAxis, "linux_bionic", toRemove) 796 la.implementationDynamicDeps.Exclude(bazel.OsConfigurationAxis, "android", toRemove) 797 la.implementationDynamicDeps.Exclude(bazel.OsConfigurationAxis, "linux_bionic", toRemove) 798 } 799 800 la.deps.ResolveExcludes() 801 la.implementationDeps.ResolveExcludes() 802 la.dynamicDeps.ResolveExcludes() 803 la.implementationDynamicDeps.ResolveExcludes() 804 la.wholeArchiveDeps.ResolveExcludes() 805 la.systemDynamicDeps.ForceSpecifyEmptyList = true 806 807} 808 809// Relativize a list of root-relative paths with respect to the module's 810// directory. 811// 812// include_dirs Soong prop are root-relative (b/183742505), but 813// local_include_dirs, export_include_dirs and export_system_include_dirs are 814// module dir relative. This function makes a list of paths entirely module dir 815// relative. 816// 817// For the `include` attribute, Bazel wants the paths to be relative to the 818// module. 819func bp2BuildMakePathsRelativeToModule(ctx android.BazelConversionPathContext, paths []string) []string { 820 var relativePaths []string 821 for _, path := range paths { 822 // Semantics of filepath.Rel: join(ModuleDir, rel(ModuleDir, path)) == path 823 relativePath, err := filepath.Rel(ctx.ModuleDir(), path) 824 if err != nil { 825 panic(err) 826 } 827 relativePaths = append(relativePaths, relativePath) 828 } 829 return relativePaths 830} 831 832// BazelIncludes contains information about -I and -isystem paths from a module converted to Bazel 833// attributes. 834type BazelIncludes struct { 835 AbsoluteIncludes bazel.StringListAttribute 836 Includes bazel.StringListAttribute 837 SystemIncludes bazel.StringListAttribute 838} 839 840func bp2BuildParseExportedIncludes(ctx android.BazelConversionPathContext, module *Module, existingIncludes BazelIncludes) BazelIncludes { 841 libraryDecorator := module.linker.(*libraryDecorator) 842 return bp2BuildParseExportedIncludesHelper(ctx, module, libraryDecorator, &existingIncludes) 843} 844 845// Bp2buildParseExportedIncludesForPrebuiltLibrary returns a BazelIncludes with Bazel-ified values 846// to export includes from the underlying module's properties. 847func Bp2BuildParseExportedIncludesForPrebuiltLibrary(ctx android.BazelConversionPathContext, module *Module) BazelIncludes { 848 prebuiltLibraryLinker := module.linker.(*prebuiltLibraryLinker) 849 libraryDecorator := prebuiltLibraryLinker.libraryDecorator 850 return bp2BuildParseExportedIncludesHelper(ctx, module, libraryDecorator, nil) 851} 852 853// bp2BuildParseExportedIncludes creates a string list attribute contains the 854// exported included directories of a module. 855func bp2BuildParseExportedIncludesHelper(ctx android.BazelConversionPathContext, module *Module, libraryDecorator *libraryDecorator, includes *BazelIncludes) BazelIncludes { 856 var exported BazelIncludes 857 if includes != nil { 858 exported = *includes 859 } else { 860 exported = BazelIncludes{} 861 } 862 for axis, configToProps := range module.GetArchVariantProperties(ctx, &FlagExporterProperties{}) { 863 for config, props := range configToProps { 864 if flagExporterProperties, ok := props.(*FlagExporterProperties); ok { 865 if len(flagExporterProperties.Export_include_dirs) > 0 { 866 exported.Includes.SetSelectValue(axis, config, android.FirstUniqueStrings(append(exported.Includes.SelectValue(axis, config), flagExporterProperties.Export_include_dirs...))) 867 } 868 if len(flagExporterProperties.Export_system_include_dirs) > 0 { 869 exported.SystemIncludes.SetSelectValue(axis, config, android.FirstUniqueStrings(append(exported.SystemIncludes.SelectValue(axis, config), flagExporterProperties.Export_system_include_dirs...))) 870 } 871 } 872 } 873 } 874 exported.AbsoluteIncludes.DeduplicateAxesFromBase() 875 exported.Includes.DeduplicateAxesFromBase() 876 exported.SystemIncludes.DeduplicateAxesFromBase() 877 878 return exported 879} 880 881func bazelLabelForStaticModule(ctx android.BazelConversionPathContext, m blueprint.Module) string { 882 label := android.BazelModuleLabel(ctx, m) 883 if ccModule, ok := m.(*Module); ok && ccModule.typ() == fullLibrary && !android.GenerateCcLibraryStaticOnly(m.Name()) { 884 label += "_bp2build_cc_library_static" 885 } 886 return label 887} 888 889func bazelLabelForSharedModule(ctx android.BazelConversionPathContext, m blueprint.Module) string { 890 // cc_library, at it's root name, propagates the shared library, which depends on the static 891 // library. 892 return android.BazelModuleLabel(ctx, m) 893} 894 895func bazelLabelForStaticWholeModuleDeps(ctx android.BazelConversionPathContext, m blueprint.Module) string { 896 label := bazelLabelForStaticModule(ctx, m) 897 if aModule, ok := m.(android.Module); ok { 898 if android.IsModulePrebuilt(aModule) { 899 label += "_alwayslink" 900 } 901 } 902 return label 903} 904 905func bazelLabelForWholeDeps(ctx android.BazelConversionPathContext, modules []string) bazel.LabelList { 906 return android.BazelLabelForModuleDepsWithFn(ctx, modules, bazelLabelForStaticWholeModuleDeps) 907} 908 909func bazelLabelForWholeDepsExcludes(ctx android.BazelConversionPathContext, modules, excludes []string) bazel.LabelList { 910 return android.BazelLabelForModuleDepsExcludesWithFn(ctx, modules, excludes, bazelLabelForStaticWholeModuleDeps) 911} 912 913func bazelLabelForStaticDepsExcludes(ctx android.BazelConversionPathContext, modules, excludes []string) bazel.LabelList { 914 return android.BazelLabelForModuleDepsExcludesWithFn(ctx, modules, excludes, bazelLabelForStaticModule) 915} 916 917func bazelLabelForStaticDeps(ctx android.BazelConversionPathContext, modules []string) bazel.LabelList { 918 return android.BazelLabelForModuleDepsWithFn(ctx, modules, bazelLabelForStaticModule) 919} 920 921func bazelLabelForSharedDeps(ctx android.BazelConversionPathContext, modules []string) bazel.LabelList { 922 return android.BazelLabelForModuleDepsWithFn(ctx, modules, bazelLabelForSharedModule) 923} 924 925func bazelLabelForHeaderDeps(ctx android.BazelConversionPathContext, modules []string) bazel.LabelList { 926 // This is not elegant, but bp2build's shared library targets only propagate 927 // their header information as part of the normal C++ provider. 928 return bazelLabelForSharedDeps(ctx, modules) 929} 930 931func bazelLabelForSharedDepsExcludes(ctx android.BazelConversionPathContext, modules, excludes []string) bazel.LabelList { 932 return android.BazelLabelForModuleDepsExcludesWithFn(ctx, modules, excludes, bazelLabelForSharedModule) 933} 934 935type binaryLinkerAttrs struct { 936 Linkshared *bool 937} 938 939func bp2buildBinaryLinkerProps(ctx android.BazelConversionPathContext, m *Module) binaryLinkerAttrs { 940 attrs := binaryLinkerAttrs{} 941 archVariantProps := m.GetArchVariantProperties(ctx, &BinaryLinkerProperties{}) 942 for axis, configToProps := range archVariantProps { 943 for _, p := range configToProps { 944 props := p.(*BinaryLinkerProperties) 945 staticExecutable := props.Static_executable 946 if axis == bazel.NoConfigAxis { 947 if linkBinaryShared := !proptools.Bool(staticExecutable); !linkBinaryShared { 948 attrs.Linkshared = &linkBinaryShared 949 } 950 } else if staticExecutable != nil { 951 // TODO(b/202876379): Static_executable is arch-variant; however, linkshared is a 952 // nonconfigurable attribute. Only 4 AOSP modules use this feature, defer handling 953 ctx.ModuleErrorf("bp2build cannot migrate a module with arch/target-specific static_executable values") 954 } 955 } 956 } 957 958 return attrs 959} 960