/** * Returns a raw link command for the given link invocation, including both command and arguments * (argv). After any further usage-specific processing, this can be passed to {@link * #finalizeWithLinkstampCommands} to give the final command line. * * @return raw link command line. */ public List<String> getRawLinkArgv() { List<String> argv = new ArrayList<>(); switch (linkTargetType) { case EXECUTABLE: argv.add(cppConfiguration.getCppExecutable().getPathString()); argv.addAll(featureConfiguration.getCommandLine(actionName, variables)); argv.addAll(noWholeArchiveFlags); addToolchainFlags(argv); break; case DYNAMIC_LIBRARY: if (interfaceOutput != null) { argv.add(configuration.getShExecutable().getPathString()); argv.add("-c"); argv.add( "build_iface_so=\"$0\"; impl=\"$1\"; iface=\"$2\"; cmd=\"$3\"; shift 3; " + "\"$cmd\" \"$@\" && \"$build_iface_so\" \"$impl\" \"$iface\""); argv.add(interfaceSoBuilder.getExecPathString()); argv.add(output.getExecPathString()); argv.add(interfaceOutput.getExecPathString()); } argv.add(cppConfiguration.getCppExecutable().getPathString()); argv.addAll(featureConfiguration.getCommandLine(actionName, variables)); argv.addAll(noWholeArchiveFlags); addToolchainFlags(argv); break; case STATIC_LIBRARY: case PIC_STATIC_LIBRARY: case ALWAYS_LINK_STATIC_LIBRARY: case ALWAYS_LINK_PIC_STATIC_LIBRARY: // The static library link command follows this template: // ar <cmd> <output_archive> <input_files...> argv.add(cppConfiguration.getArExecutable().getPathString()); argv.addAll( cppConfiguration.getArFlags(cppConfiguration.archiveType() == Link.ArchiveType.THIN)); argv.add(output.getExecPathString()); argv.addAll(featureConfiguration.getCommandLine(actionName, variables)); argv.addAll(noWholeArchiveFlags); break; default: throw new IllegalArgumentException(); } return argv; }
/** * Select .pcm inputs to pass on the command line depending on whether we are in pic or non-pic * mode. */ private Collection<String> getHeaderModulePaths(CppCompileActionBuilder builder, boolean usePic) { Collection<String> result = new LinkedHashSet<>(); NestedSet<Artifact> artifacts = featureConfiguration.isEnabled(CppRuleClasses.HEADER_MODULE_INCLUDES_DEPENDENCIES) ? builder.getContext().getTopLevelHeaderModules(usePic) : builder.getContext().getAdditionalInputs(usePic); for (Artifact artifact : artifacts) { String filename = artifact.getFilename(); if (!filename.endsWith(".pcm")) { continue; } // Depending on whether this specific compile action is pic or non-pic, select the // corresponding header modules. Note that the compilation context might give us both // from targets that are built in both modes. if (usePic == filename.endsWith(".pic.pcm")) { result.add(artifact.getExecPathString()); } } return result; }
/** * Constructs the C++ linker actions. It generally generates two actions, one for a static library * and one for a dynamic library. If PIC is required for shared libraries, but not for binaries, * it additionally creates a third action to generate a PIC static library. * * <p>For dynamic libraries, this method can additionally create an interface shared library that * can be used for linking, but doesn't contain any executable code. This increases the number of * cache hits for link actions. Call {@link #setAllowInterfaceSharedObjects(boolean)} to enable * this behavior. * * @throws RuleErrorException */ public CcLinkingOutputs createCcLinkActions(CcCompilationOutputs ccOutputs) throws RuleErrorException { // For now only handle static links. Note that the dynamic library link below ignores linkType. // TODO(bazel-team): Either support non-static links or move this check to setLinkType(). Preconditions.checkState(linkType.isStaticLibraryLink(), "can only handle static links"); CcLinkingOutputs.Builder result = new CcLinkingOutputs.Builder(); if (cppConfiguration.isLipoContextCollector()) { // Don't try to create LIPO link actions in collector mode, // because it needs some data that's not available at this point. return result.build(); } AnalysisEnvironment env = ruleContext.getAnalysisEnvironment(); boolean usePicForBinaries = CppHelper.usePic(ruleContext, true); boolean usePicForSharedLibs = CppHelper.usePic(ruleContext, false); // Create static library (.a). The linkType only reflects whether the library is alwayslink or // not. The PIC-ness is determined by whether we need to use PIC or not. There are three cases // for (usePicForSharedLibs usePicForBinaries): // // (1) (false false) -> no pic code // (2) (true false) -> shared libraries as pic, but not binaries // (3) (true true) -> both shared libraries and binaries as pic // // In case (3), we always need PIC, so only create one static library containing the PIC object // files. The name therefore does not match the content. // // Presumably, it is done this way because the .a file is an implicit output of every cc_library // rule, so we can't use ".pic.a" that in the always-PIC case. // If the crosstool is configured to select an output artifact, we use that selection. // Otherwise, we use linux defaults. Artifact linkedArtifact = getLinkedArtifact(linkType); CppLinkAction maybePicAction = newLinkActionBuilder(linkedArtifact) .addNonLibraryInputs(ccOutputs.getObjectFiles(usePicForBinaries)) .addNonLibraryInputs(ccOutputs.getHeaderTokenFiles()) .addLTOBitcodeFiles(ccOutputs.getLtoBitcodeFiles()) .setLinkType(linkType) .setLinkStaticness(LinkStaticness.FULLY_STATIC) .setFeatureConfiguration(featureConfiguration) .build(); env.registerAction(maybePicAction); result.addStaticLibrary(maybePicAction.getOutputLibrary()); // Create a second static library (.pic.a). Only in case (2) do we need both PIC and non-PIC // static libraries. In that case, the first static library contains the non-PIC code, and this // one contains the PIC code, so the names match the content. if (!usePicForBinaries && usePicForSharedLibs) { LinkTargetType picLinkType = (linkType == LinkTargetType.ALWAYS_LINK_STATIC_LIBRARY) ? LinkTargetType.ALWAYS_LINK_PIC_STATIC_LIBRARY : LinkTargetType.PIC_STATIC_LIBRARY; // If the crosstool is configured to select an output artifact, we use that selection. // Otherwise, we use linux defaults. Artifact picArtifact = getLinkedArtifact(picLinkType); CppLinkAction picAction = newLinkActionBuilder(picArtifact) .addNonLibraryInputs(ccOutputs.getObjectFiles(true)) .addNonLibraryInputs(ccOutputs.getHeaderTokenFiles()) .addLTOBitcodeFiles(ccOutputs.getLtoBitcodeFiles()) .setLinkType(picLinkType) .setLinkStaticness(LinkStaticness.FULLY_STATIC) .setFeatureConfiguration(featureConfiguration) .build(); env.registerAction(picAction); result.addPicStaticLibrary(picAction.getOutputLibrary()); } if (!createDynamicLibrary) { return result.build(); } // Create dynamic library. Artifact soImpl; if (soImplArtifact == null) { // If the crosstool is configured to select an output artifact, we use that selection. // Otherwise, we use linux defaults. soImpl = getLinkedArtifact(LinkTargetType.DYNAMIC_LIBRARY); } else { soImpl = soImplArtifact; } List<String> sonameLinkopts = ImmutableList.of(); Artifact soInterface = null; if (cppConfiguration.useInterfaceSharedObjects() && allowInterfaceSharedObjects) { soInterface = CppHelper.getLinuxLinkedArtifact(ruleContext, LinkTargetType.INTERFACE_DYNAMIC_LIBRARY); sonameLinkopts = ImmutableList.of( "-Wl,-soname=" + SolibSymlinkAction.getDynamicLibrarySoname( soImpl.getRootRelativePath(), false)); } // Should we also link in any libraries that this library depends on? // That is required on some systems... CppLinkActionBuilder linkActionBuilder = newLinkActionBuilder(soImpl) .setInterfaceOutput(soInterface) .addNonLibraryInputs(ccOutputs.getObjectFiles(usePicForSharedLibs)) .addNonLibraryInputs(ccOutputs.getHeaderTokenFiles()) .addLTOBitcodeFiles(ccOutputs.getLtoBitcodeFiles()) .setLinkType(LinkTargetType.DYNAMIC_LIBRARY) .setLinkStaticness(LinkStaticness.DYNAMIC) .addLinkopts(linkopts) .addLinkopts(sonameLinkopts) .setRuntimeInputs( CppHelper.getToolchain(ruleContext).getDynamicRuntimeLinkMiddleman(), CppHelper.getToolchain(ruleContext).getDynamicRuntimeLinkInputs()) .setFeatureConfiguration(featureConfiguration); if (!ccOutputs.getLtoBitcodeFiles().isEmpty() && featureConfiguration.isEnabled(CppRuleClasses.THIN_LTO)) { linkActionBuilder.setLTOIndexing(true); CppLinkAction indexAction = linkActionBuilder.build(); env.registerAction(indexAction); for (LTOBackendArtifacts ltoArtifacts : indexAction.getAllLTOBackendArtifacts()) { ltoArtifacts.scheduleLTOBackendAction(ruleContext, usePicForSharedLibs); } linkActionBuilder.setLTOIndexing(false); } CppLinkAction action = linkActionBuilder.build(); env.registerAction(action); LibraryToLink dynamicLibrary = action.getOutputLibrary(); LibraryToLink interfaceLibrary = action.getInterfaceOutputLibrary(); if (interfaceLibrary == null) { interfaceLibrary = dynamicLibrary; } // If shared library has neverlink=1, then leave it untouched. Otherwise, // create a mangled symlink for it and from now on reference it through // mangled name only. if (neverLink) { result.addDynamicLibrary(interfaceLibrary); result.addExecutionDynamicLibrary(dynamicLibrary); } else { LibraryToLink libraryLink = SolibSymlinkAction.getDynamicLibrarySymlink( ruleContext, interfaceLibrary.getArtifact(), false, false, ruleContext.getConfiguration()); result.addDynamicLibrary(libraryLink); LibraryToLink implLibraryLink = SolibSymlinkAction.getDynamicLibrarySymlink( ruleContext, dynamicLibrary.getArtifact(), false, false, ruleContext.getConfiguration()); result.addExecutionDynamicLibrary(implLibraryLink); } return result.build(); }
private void createSourceAction( String outputName, CcCompilationOutputs.Builder result, AnalysisEnvironment env, Artifact sourceArtifact, CppCompileActionBuilder builder, ArtifactCategory outputCategory, boolean addObject, boolean enableCoverage, boolean generateDwo, boolean generateDotd, Map<String, String> sourceSpecificBuildVariables) { PathFragment ccRelativeName = semantics.getEffectiveSourcePath(sourceArtifact); if (cppConfiguration.isLipoOptimization()) { // TODO(bazel-team): we shouldn't be needing this, merging context with the binary // is a superset of necessary information. LipoContextProvider lipoProvider = Preconditions.checkNotNull(CppHelper.getLipoContextProvider(ruleContext), outputName); builder.setContext( CppCompilationContext.mergeForLipo(lipoProvider.getLipoContext(), context)); } boolean generatePicAction = getGeneratePicActions(); // If we always need pic for everything, then don't bother to create a no-pic action. boolean generateNoPicAction = getGenerateNoPicActions(); Preconditions.checkState(generatePicAction || generateNoPicAction); if (fake) { boolean usePic = !generateNoPicAction; createFakeSourceAction( outputName, result, env, builder, outputCategory, addObject, ccRelativeName, sourceArtifact.getExecPath(), usePic, generateDotd); } else { // Create PIC compile actions (same as non-PIC, but use -fPIC and // generate .pic.o, .pic.d, .pic.gcno instead of .o, .d, .gcno.) if (generatePicAction) { String picOutputBase = CppHelper.getCompileArtifactName(ruleContext, ArtifactCategory.PIC_FILE, outputName); CppCompileActionBuilder picBuilder = copyAsPicBuilder(builder, picOutputBase, outputCategory, generateDotd); String gcnoFileName = CppHelper.getCompileArtifactName( ruleContext, ArtifactCategory.COVERAGE_DATA_FILE, picOutputBase); Artifact gcnoFile = enableCoverage ? CppHelper.getCompileOutputArtifact(ruleContext, gcnoFileName) : null; Artifact dwoFile = generateDwo ? getDwoFile(picBuilder.getOutputFile()) : null; setupCompileBuildVariables( picBuilder, /*usePic=*/ true, ccRelativeName, sourceArtifact.getExecPath(), gcnoFile, dwoFile, sourceSpecificBuildVariables); if (maySaveTemps) { result.addTemps( createTempsActions( sourceArtifact, outputName, picBuilder, /*usePic=*/ true, /*generateDotd=*/ generateDotd, ccRelativeName)); } picBuilder.setGcnoFile(gcnoFile); picBuilder.setDwoFile(dwoFile); semantics.finalizeCompileActionBuilder(ruleContext, picBuilder); CppCompileAction picAction = picBuilder.build(); env.registerAction(picAction); if (addObject) { result.addPicObjectFile(picAction.getOutputFile()); if (featureConfiguration.isEnabled(CppRuleClasses.THIN_LTO) && CppFileTypes.LTO_SOURCE.matches(sourceArtifact.getFilename())) { result.addLTOBitcodeFile(picAction.getOutputFile()); } } if (dwoFile != null) { // Host targets don't produce .dwo files. result.addPicDwoFile(dwoFile); } if (cppConfiguration.isLipoContextCollector() && !generateNoPicAction) { result.addLipoScannable(picAction); } } if (generateNoPicAction) { Artifact noPicOutputFile = CppHelper.getCompileOutputArtifact( ruleContext, CppHelper.getCompileArtifactName(ruleContext, outputCategory, outputName)); builder.setOutputs(outputCategory, outputName, generateDotd); String gcnoFileName = CppHelper.getCompileArtifactName( ruleContext, ArtifactCategory.COVERAGE_DATA_FILE, outputName); // Create non-PIC compile actions Artifact gcnoFile = !cppConfiguration.isLipoOptimization() && enableCoverage ? CppHelper.getCompileOutputArtifact(ruleContext, gcnoFileName) : null; Artifact noPicDwoFile = generateDwo ? getDwoFile(noPicOutputFile) : null; setupCompileBuildVariables( builder, /*usePic=*/ false, ccRelativeName, sourceArtifact.getExecPath(), gcnoFile, noPicDwoFile, sourceSpecificBuildVariables); if (maySaveTemps) { result.addTemps( createTempsActions( sourceArtifact, outputName, builder, /*usePic=*/ false, /*generateDotd*/ generateDotd, ccRelativeName)); } builder.setGcnoFile(gcnoFile); builder.setDwoFile(noPicDwoFile); semantics.finalizeCompileActionBuilder(ruleContext, builder); CppCompileAction compileAction = builder.build(); env.registerAction(compileAction); Artifact objectFile = compileAction.getOutputFile(); if (addObject) { result.addObjectFile(objectFile); if (featureConfiguration.isEnabled(CppRuleClasses.THIN_LTO) && CppFileTypes.LTO_SOURCE.matches(sourceArtifact.getFilename())) { result.addLTOBitcodeFile(objectFile); } } if (noPicDwoFile != null) { // Host targets don't produce .dwo files. result.addDwoFile(noPicDwoFile); } if (cppConfiguration.isLipoContextCollector()) { result.addLipoScannable(compileAction); } } } }
private void setupCompileBuildVariables( CppCompileActionBuilder builder, boolean usePic, PathFragment ccRelativeName, PathFragment autoFdoImportPath, Artifact gcnoFile, Artifact dwoFile, Map<String, String> sourceSpecificBuildVariables) { CcToolchainFeatures.Variables.Builder buildVariables = new CcToolchainFeatures.Variables.Builder(); // TODO(bazel-team): Pull out string constants for all build variables. CppCompilationContext builderContext = builder.getContext(); CppModuleMap cppModuleMap = builderContext.getCppModuleMap(); Artifact sourceFile = builder.getSourceFile(); Artifact outputFile = builder.getOutputFile(); String realOutputFilePath; buildVariables.addVariable("source_file", sourceFile.getExecPathString()); buildVariables.addVariable("output_file", outputFile.getExecPathString()); if (builder.getTempOutputFile() != null) { realOutputFilePath = builder.getTempOutputFile().getPathString(); } else { realOutputFilePath = builder.getOutputFile().getExecPathString(); } if (FileType.contains(outputFile, CppFileTypes.ASSEMBLER, CppFileTypes.PIC_ASSEMBLER)) { buildVariables.addVariable("output_assembly_file", realOutputFilePath); } else if (FileType.contains( outputFile, CppFileTypes.PREPROCESSED_C, CppFileTypes.PREPROCESSED_CPP, CppFileTypes.PIC_PREPROCESSED_C, CppFileTypes.PIC_PREPROCESSED_CPP)) { buildVariables.addVariable("output_preprocess_file", realOutputFilePath); } else { buildVariables.addVariable("output_object_file", realOutputFilePath); } DotdFile dotdFile = CppFileTypes.mustProduceDotdFile(sourceFile.getPath().toString()) ? Preconditions.checkNotNull(builder.getDotdFile()) : null; // Set dependency_file to enable <object>.d file generation. if (dotdFile != null) { buildVariables.addVariable("dependency_file", dotdFile.getSafeExecPath().getPathString()); } if (featureConfiguration.isEnabled(CppRuleClasses.MODULE_MAPS) && cppModuleMap != null) { // If the feature is enabled and cppModuleMap is null, we are about to fail during analysis // in any case, but don't crash. buildVariables.addVariable("module_name", cppModuleMap.getName()); buildVariables.addVariable("module_map_file", cppModuleMap.getArtifact().getExecPathString()); CcToolchainFeatures.Variables.ValueSequence.Builder sequence = new CcToolchainFeatures.Variables.ValueSequence.Builder(); for (Artifact artifact : builderContext.getDirectModuleMaps()) { sequence.addValue(artifact.getExecPathString()); } buildVariables.addSequence("dependent_module_map_files", sequence.build()); } if (featureConfiguration.isEnabled(CppRuleClasses.USE_HEADER_MODULES)) { buildVariables.addSequenceVariable("module_files", getHeaderModulePaths(builder, usePic)); } if (featureConfiguration.isEnabled(CppRuleClasses.INCLUDE_PATHS)) { buildVariables.addSequenceVariable( "include_paths", getSafePathStrings(builderContext.getIncludeDirs())); buildVariables.addSequenceVariable( "quote_include_paths", getSafePathStrings(builderContext.getQuoteIncludeDirs())); buildVariables.addSequenceVariable( "system_include_paths", getSafePathStrings(builderContext.getSystemIncludeDirs())); } if (featureConfiguration.isEnabled(CppRuleClasses.PREPROCESSOR_DEFINES)) { String fdoBuildStamp = CppHelper.getFdoBuildStamp(ruleContext); ImmutableList<String> defines; if (fdoBuildStamp != null) { // Stamp FDO builds with FDO subtype string defines = ImmutableList.<String>builder() .addAll(builderContext.getDefines()) .add( CppConfiguration.FDO_STAMP_MACRO + "=\"" + CppHelper.getFdoBuildStamp(ruleContext) + "\"") .build(); } else { defines = builderContext.getDefines(); } buildVariables.addSequenceVariable("preprocessor_defines", defines); } if (usePic) { if (!featureConfiguration.isEnabled(CppRuleClasses.PIC)) { ruleContext.ruleError("PIC compilation is requested but the toolchain does not support it"); } buildVariables.addVariable("pic", ""); } if (ccRelativeName != null) { CppHelper.getFdoSupport(ruleContext) .configureCompilation( builder, buildVariables, ruleContext, ccRelativeName, autoFdoImportPath, usePic, featureConfiguration); } if (gcnoFile != null) { buildVariables.addVariable("gcov_gcno_file", gcnoFile.getExecPathString()); } if (dwoFile != null) { buildVariables.addVariable("per_object_debug_info_file", dwoFile.getExecPathString()); } buildVariables.addAllVariables(CppHelper.getToolchain(ruleContext).getBuildVariables()); buildVariables.addAllVariables(sourceSpecificBuildVariables); for (VariablesExtension extension : variablesExtensions) { extension.addVariables(buildVariables); } CcToolchainFeatures.Variables variables = buildVariables.build(); builder.setVariables(variables); }
/** @returns whether we want to provide header modules for the current target. */ private boolean shouldProvideHeaderModules() { return featureConfiguration.isEnabled(CppRuleClasses.HEADER_MODULES) && !cppConfiguration.isLipoContextCollector(); }
/** Create context for cc compile action from generated inputs. */ private CppCompilationContext initializeCppCompilationContext(CppModel model) { CppCompilationContext.Builder contextBuilder = new CppCompilationContext.Builder(ruleContext); // Setup the include path; local include directories come before those inherited from deps or // from the toolchain; in case of aliasing (same include file found on different entries), // prefer the local include rather than the inherited one. // Add in the roots for well-formed include names for source files and // generated files. It is important that the execRoot (EMPTY_FRAGMENT) comes // before the genfilesFragment to preferably pick up source files. Otherwise // we might pick up stale generated files. PathFragment repositoryPath = ruleContext.getLabel().getPackageIdentifier().getRepository().getPathFragment(); contextBuilder.addQuoteIncludeDir(repositoryPath); contextBuilder.addQuoteIncludeDir( ruleContext.getConfiguration().getGenfilesFragment().getRelative(repositoryPath)); for (PathFragment systemIncludeDir : systemIncludeDirs) { contextBuilder.addSystemIncludeDir(systemIncludeDir); } for (PathFragment includeDir : includeDirs) { contextBuilder.addIncludeDir(includeDir); } contextBuilder.mergeDependentContexts( AnalysisUtils.getProviders(deps, CppCompilationContext.class)); CppHelper.mergeToolchainDependentContext(ruleContext, contextBuilder); // But defines come after those inherited from deps. contextBuilder.addDefines(defines); // There are no ordering constraints for declared include dirs/srcs, or the pregrepped headers. contextBuilder.addDeclaredIncludeSrcs(publicHeaders); contextBuilder.addDeclaredIncludeSrcs(publicTextualHeaders); contextBuilder.addDeclaredIncludeSrcs(privateHeaders); contextBuilder.addPregreppedHeaderMap( CppHelper.createExtractInclusions(ruleContext, semantics, publicHeaders)); contextBuilder.addPregreppedHeaderMap( CppHelper.createExtractInclusions(ruleContext, semantics, publicTextualHeaders)); contextBuilder.addPregreppedHeaderMap( CppHelper.createExtractInclusions(ruleContext, semantics, privateHeaders)); contextBuilder.addCompilationPrerequisites(prerequisites); // Add this package's dir to declaredIncludeDirs, & this rule's headers to declaredIncludeSrcs // Note: no include dir for STRICT mode. if (headersCheckingMode == HeadersCheckingMode.WARN) { contextBuilder.addDeclaredIncludeWarnDir(ruleContext.getLabel().getPackageFragment()); for (PathFragment looseIncludeDir : looseIncludeDirs) { contextBuilder.addDeclaredIncludeWarnDir(looseIncludeDir); } } else if (headersCheckingMode == HeadersCheckingMode.LOOSE) { contextBuilder.addDeclaredIncludeDir(ruleContext.getLabel().getPackageFragment()); for (PathFragment looseIncludeDir : looseIncludeDirs) { contextBuilder.addDeclaredIncludeDir(looseIncludeDir); } } if (featureConfiguration.isEnabled(CppRuleClasses.MODULE_MAPS)) { CppModuleMap cppModuleMap = CppHelper.addCppModuleMapToContext(ruleContext, contextBuilder); // TODO(bazel-team): addCppModuleMapToContext second-guesses whether module maps should // actually be enabled, so we need to double-check here. Who would write code like this? if (cppModuleMap != null) { CppModuleMapAction action = new CppModuleMapAction( ruleContext.getActionOwner(), cppModuleMap, privateHeaders, publicHeaders, collectModuleMaps(), additionalExportedHeaders, featureConfiguration.isEnabled(CppRuleClasses.HEADER_MODULES), featureConfiguration.isEnabled(CppRuleClasses.MODULE_MAP_HOME_CWD), featureConfiguration.isEnabled(CppRuleClasses.GENERATE_SUBMODULES), !featureConfiguration.isEnabled(CppRuleClasses.MODULE_MAP_WITHOUT_EXTERN_MODULE)); ruleContext.registerAction(action); } if (model.getGeneratesPicHeaderModule()) { contextBuilder.setPicHeaderModule(model.getPicHeaderModule(cppModuleMap.getArtifact())); } if (model.getGeneratesNoPicHeaderModule()) { contextBuilder.setHeaderModule(model.getHeaderModule(cppModuleMap.getArtifact())); } if (featureConfiguration.isEnabled(CppRuleClasses.USE_HEADER_MODULES) && featureConfiguration.isEnabled(CppRuleClasses.TRANSITIVE_MODULE_MAPS)) { contextBuilder.setProvideTransitiveModuleMaps(true); } } semantics.setupCompilationContext(ruleContext, contextBuilder); return contextBuilder.build(); }
/** Create the C++ compile and link actions, and the corresponding C++-related providers. */ public Info build() { // Fail early if there is no lipo context collector on the rule - otherwise we end up failing // in lipo optimization. Preconditions.checkState( // 'cc_inc_library' rules do not compile, and thus are not affected by LIPO. ruleContext.getRule().getRuleClass().equals("cc_inc_library") || ruleContext.getRule().isAttrDefined(":lipo_context_collector", BuildType.LABEL)); if (checkDepsGenerateCpp) { for (LanguageDependentFragment dep : AnalysisUtils.getProviders(deps, LanguageDependentFragment.class)) { LanguageDependentFragment.Checker.depSupportsLanguage( ruleContext, dep, CppRuleClasses.LANGUAGE); } } CppModel model = initializeCppModel(); CppCompilationContext cppCompilationContext = initializeCppCompilationContext(model); model.setContext(cppCompilationContext); boolean compileHeaderModules = featureConfiguration.isEnabled(CppRuleClasses.HEADER_MODULES); Preconditions.checkState( !compileHeaderModules || cppCompilationContext.getCppModuleMap() != null, "All cc rules must support module maps."); // Create compile actions (both PIC and non-PIC). CcCompilationOutputs ccOutputs = model.createCcCompileActions(); if (!objectFiles.isEmpty() || !picObjectFiles.isEmpty()) { // Merge the pre-compiled object files into the compiler outputs. ccOutputs = new CcCompilationOutputs.Builder() .merge(ccOutputs) .addLTOBitcodeFile(ccOutputs.getLtoBitcodeFiles()) .addObjectFiles(objectFiles) .addPicObjectFiles(picObjectFiles) .build(); } // Create link actions (only if there are object files or if explicitly requested). CcLinkingOutputs ccLinkingOutputs = CcLinkingOutputs.EMPTY; if (emitLinkActionsIfEmpty || !ccOutputs.isEmpty()) { // On some systems, the linker gives an error message if there are no input files. Even with // the check above, this can still happen if there is a .nopic.o or .o files in srcs, but no // other files. To fix that, we'd have to check for each link action individually. // // An additional pre-existing issue is that the header check tokens are dropped if we don't // generate any link actions, effectively disabling header checking in some cases. if (linkType.isStaticLibraryLink()) { // TODO(bazel-team): This can't create the link action for a cc_binary yet. ccLinkingOutputs = model.createCcLinkActions(ccOutputs); } } CcLinkingOutputs originalLinkingOutputs = ccLinkingOutputs; if (!(staticLibraries.isEmpty() && picStaticLibraries.isEmpty() && dynamicLibraries.isEmpty())) { // Merge the pre-compiled libraries (static & dynamic) into the linker outputs. ccLinkingOutputs = new CcLinkingOutputs.Builder() .merge(ccLinkingOutputs) .addStaticLibraries(staticLibraries) .addPicStaticLibraries(picStaticLibraries) .addDynamicLibraries(dynamicLibraries) .addExecutionDynamicLibraries(dynamicLibraries) .build(); } DwoArtifactsCollector dwoArtifacts = DwoArtifactsCollector.transitiveCollector(ccOutputs, deps); Runfiles cppStaticRunfiles = collectCppRunfiles(ccLinkingOutputs, true); Runfiles cppSharedRunfiles = collectCppRunfiles(ccLinkingOutputs, false); // By very careful when adding new providers here - it can potentially affect a lot of rules. // We should consider merging most of these providers into a single provider. Map<Class<? extends TransitiveInfoProvider>, TransitiveInfoProvider> providers = new LinkedHashMap<>(); providers.put( CppRunfilesProvider.class, new CppRunfilesProvider(cppStaticRunfiles, cppSharedRunfiles)); providers.put(CppCompilationContext.class, cppCompilationContext); providers.put( CppDebugFileProvider.class, new CppDebugFileProvider( dwoArtifacts.getDwoArtifacts(), dwoArtifacts.getPicDwoArtifacts())); providers.put(TransitiveLipoInfoProvider.class, collectTransitiveLipoInfo(ccOutputs)); Map<String, NestedSet<Artifact>> outputGroups = new TreeMap<>(); outputGroups.put(OutputGroupProvider.TEMP_FILES, getTemps(ccOutputs)); if (emitCompileProviders) { boolean isLipoCollector = ruleContext.getFragment(CppConfiguration.class).isLipoContextCollector(); boolean processHeadersInDependencies = ruleContext.getFragment(CppConfiguration.class).processHeadersInDependencies(); boolean usePic = CppHelper.usePic(ruleContext, false); outputGroups.put( OutputGroupProvider.FILES_TO_COMPILE, ccOutputs.getFilesToCompile(isLipoCollector, processHeadersInDependencies, usePic)); outputGroups.put( OutputGroupProvider.COMPILATION_PREREQUISITES, CcCommon.collectCompilationPrerequisites(ruleContext, cppCompilationContext)); } // TODO(bazel-team): Maybe we can infer these from other data at the places where they are // used. if (emitCcNativeLibrariesProvider) { providers.put( CcNativeLibraryProvider.class, new CcNativeLibraryProvider(collectNativeCcLibraries(ccLinkingOutputs))); } providers.put( CcExecutionDynamicLibrariesProvider.class, collectExecutionDynamicLibraryArtifacts(ccLinkingOutputs.getExecutionDynamicLibraries())); boolean forcePic = ruleContext.getFragment(CppConfiguration.class).forcePic(); if (emitCcSpecificLinkParamsProvider) { providers.put( CcSpecificLinkParamsProvider.class, new CcSpecificLinkParamsProvider( createCcLinkParamsStore(ccLinkingOutputs, cppCompilationContext, forcePic))); } else { providers.put( CcLinkParamsProvider.class, new CcLinkParamsProvider( createCcLinkParamsStore(ccLinkingOutputs, cppCompilationContext, forcePic))); } return new Info( providers, outputGroups, ccOutputs, ccLinkingOutputs, originalLinkingOutputs, cppCompilationContext); }
private boolean shouldProcessHeaders() { return featureConfiguration.isEnabled(CppRuleClasses.PREPROCESS_HEADERS) || featureConfiguration.isEnabled(CppRuleClasses.PARSE_HEADERS); }