diff options
Diffstat (limited to 'src/main/java/com/google/devtools/build/lib')
10 files changed, 610 insertions, 253 deletions
diff --git a/src/main/java/com/google/devtools/build/lib/rules/cpp/CcToolchainFeatures.java b/src/main/java/com/google/devtools/build/lib/rules/cpp/CcToolchainFeatures.java index ca464d2a1b..bf9e7c5367 100644 --- a/src/main/java/com/google/devtools/build/lib/rules/cpp/CcToolchainFeatures.java +++ b/src/main/java/com/google/devtools/build/lib/rules/cpp/CcToolchainFeatures.java @@ -1150,7 +1150,7 @@ public class CcToolchainFeatures implements Serializable { * Add a variable that expands a flag group containing a reference to {@code name} for each * entry in {@code values}. */ - public Builder addSequenceVariable(String name, Collection<String> values) { + public Builder addSequenceVariable(String name, Iterable<String> values) { StringSequence.Builder sequenceBuilder = new StringSequence.Builder(); for (String value : values) { sequenceBuilder.addValue(value); diff --git a/src/main/java/com/google/devtools/build/lib/rules/cpp/CppLinkAction.java b/src/main/java/com/google/devtools/build/lib/rules/cpp/CppLinkAction.java index 44004745a0..04dc86895e 100644 --- a/src/main/java/com/google/devtools/build/lib/rules/cpp/CppLinkAction.java +++ b/src/main/java/com/google/devtools/build/lib/rules/cpp/CppLinkAction.java @@ -95,6 +95,7 @@ public final class CppLinkAction extends AbstractAction private static final String LINK_GUID = "58ec78bd-1176-4e36-8143-439f656b181d"; private static final String FAKE_LINK_GUID = "da36f819-5a15-43a9-8a45-e01b60e10c8b"; + @Nullable private final String mnemonic; private final CppConfiguration cppConfiguration; private final LibraryToLink outputLibrary; private final Artifact linkOutput; @@ -138,6 +139,7 @@ public final class CppLinkAction extends AbstractAction */ CppLinkAction( ActionOwner owner, + String mnemonic, Iterable<Artifact> inputs, ImmutableList<Artifact> outputs, CppConfiguration cppConfiguration, @@ -151,6 +153,11 @@ public final class CppLinkAction extends AbstractAction Map<String, String> toolchainEnv, ImmutableSet<String> executionRequirements) { super(owner, inputs, outputs); + if (mnemonic == null) { + this.mnemonic = (isLTOIndexing) ? "CppLTOIndexing" : "CppLink"; + } else { + this.mnemonic = mnemonic; + } this.mandatoryInputs = inputs; this.cppConfiguration = cppConfiguration; this.outputLibrary = outputLibrary; @@ -457,7 +464,7 @@ public final class CppLinkAction extends AbstractAction @Override public String getMnemonic() { - return (isLTOIndexing) ? "CppLTOIndexing" : "CppLink"; + return mnemonic; } @Override diff --git a/src/main/java/com/google/devtools/build/lib/rules/cpp/CppLinkActionBuilder.java b/src/main/java/com/google/devtools/build/lib/rules/cpp/CppLinkActionBuilder.java index f2690c6062..9fe8673389 100644 --- a/src/main/java/com/google/devtools/build/lib/rules/cpp/CppLinkActionBuilder.java +++ b/src/main/java/com/google/devtools/build/lib/rules/cpp/CppLinkActionBuilder.java @@ -124,6 +124,7 @@ public class CppLinkActionBuilder { @Nullable private final RuleContext ruleContext; private final AnalysisEnvironment analysisEnvironment; private final Artifact output; + @Nullable private String mnemonic; // can be null for CppLinkAction.createTestBuilder() @Nullable private final CcToolchainProvider toolchain; @@ -162,7 +163,7 @@ public class CppLinkActionBuilder { private Iterable<LTOBackendArtifacts> allLTOArtifacts = null; private final List<VariablesExtension> variablesExtensions = new ArrayList<>(); - private final List<Artifact> linkActionInputs = new ArrayList<>(); + private final NestedSetBuilder<Artifact> linkActionInputs = NestedSetBuilder.stableOrder(); /** * Creates a builder that builds {@link CppLinkAction} instances. @@ -442,8 +443,11 @@ public class CppLinkActionBuilder { /** Builds the Action as configured and returns it. */ public CppLinkAction build() throws InterruptedException { - Preconditions.checkState( - (libraryIdentifier == null) == (linkType == LinkTargetType.EXECUTABLE)); + // Executable links do not have library identifiers. + boolean hasIdentifier = (libraryIdentifier != null); + boolean isExecutable = linkType.isExecutable(); + Preconditions.checkState(hasIdentifier != isExecutable); + if (interfaceOutput != null && (fake || linkType != LinkTargetType.DYNAMIC_LIBRARY)) { throw new RuntimeException( "Interface output can only be used " + "with non-fake DYNAMIC_LIBRARY targets"); @@ -485,7 +489,7 @@ public class CppLinkActionBuilder { } } - final LibraryToLink outputLibrary = linkType == LinkTargetType.EXECUTABLE + final LibraryToLink outputLibrary = linkType.isExecutable() ? null : LinkerInputs.newInputLibrary(output, linkType.getLinkerOutput(), @@ -651,7 +655,7 @@ public class CppLinkActionBuilder { NestedSetBuilder<Artifact> dependencyInputsBuilder = NestedSetBuilder.stableOrder(); dependencyInputsBuilder.addTransitive(crosstoolInputs); dependencyInputsBuilder.add(toolchain.getLinkDynamicLibraryTool()); - dependencyInputsBuilder.addAll(linkActionInputs); + dependencyInputsBuilder.addTransitive(linkActionInputs.build()); if (runtimeMiddleman != null) { dependencyInputsBuilder.add(runtimeMiddleman); } @@ -737,6 +741,7 @@ public class CppLinkActionBuilder { return new CppLinkAction( getOwner(), + mnemonic, inputsBuilder.deduplicate().build(), actionOutputs, cppConfiguration, @@ -840,6 +845,12 @@ public class CppLinkActionBuilder { protected ActionOwner getOwner() { return ruleContext.getActionOwner(); } + + /** Sets the mnemonic for the link action. */ + public CppLinkActionBuilder setMnemonic(String mnemonic) { + this.mnemonic = mnemonic; + return this; + } /** Set the crosstool inputs required for the action. */ public CppLinkActionBuilder setCrosstoolInputs(NestedSet<Artifact> inputs) { @@ -1143,12 +1154,28 @@ public class CppLinkActionBuilder { } /** - * Sets extra input artifacts to the link action. + * Adds an extra input artifact to the link action. + */ + public CppLinkActionBuilder addActionInput(Artifact input) { + this.linkActionInputs.add(input); + return this; + } + + /** + * Adds extra input artifacts to the link action. */ - public CppLinkActionBuilder addActionInputs(Collection<Artifact> inputs) { + public CppLinkActionBuilder addActionInputs(Iterable<Artifact> inputs) { this.linkActionInputs.addAll(inputs); return this; } + + /** + * Adds extra input artifacts to the link actions. + */ + public CppLinkActionBuilder addTransitiveActionInputs(NestedSet<Artifact> inputs) { + this.linkActionInputs.addTransitive(inputs); + return this; + } private static class LinkArgCollector { String rpathRoot; diff --git a/src/main/java/com/google/devtools/build/lib/rules/cpp/Link.java b/src/main/java/com/google/devtools/build/lib/rules/cpp/Link.java index ec51c8413f..74f33ab913 100644 --- a/src/main/java/com/google/devtools/build/lib/rules/cpp/Link.java +++ b/src/main/java/com/google/devtools/build/lib/rules/cpp/Link.java @@ -103,6 +103,14 @@ public abstract class Link { STATIC, DYNAMIC } + + /** + * Whether a particular link target is executable. + */ + public enum Executable { + EXECUTABLE, + NOT_EXECUTABLE + } /** * Types of ELF files that can be created by the linker (.a, .so, .lo, @@ -115,7 +123,8 @@ public abstract class Link { Staticness.STATIC, "c++-link-static-library", Picness.NOPIC, - ArtifactCategory.STATIC_LIBRARY), + ArtifactCategory.STATIC_LIBRARY, + Executable.NOT_EXECUTABLE), /** An objc static archive. */ OBJC_ARCHIVE( @@ -123,19 +132,35 @@ public abstract class Link { Staticness.STATIC, "objc-archive", Picness.NOPIC, - ArtifactCategory.STATIC_LIBRARY), + ArtifactCategory.STATIC_LIBRARY, + Executable.NOT_EXECUTABLE), /** An objc fully linked static archive. */ OBJC_FULLY_LINKED_ARCHIVE( - ".a", Staticness.STATIC, "objc-fully-link", Picness.NOPIC, ArtifactCategory.STATIC_LIBRARY), + ".a", + Staticness.STATIC, + "objc-fully-link", + Picness.NOPIC, + ArtifactCategory.STATIC_LIBRARY, + Executable.NOT_EXECUTABLE), + /** An objc executable. */ + OBJC_EXECUTABLE( + "", + Staticness.STATIC, + "objc-executable", + Picness.NOPIC, + ArtifactCategory.EXECUTABLE, + Executable.EXECUTABLE), + /** A static archive with .pic.o object files (compiled with -fPIC). */ PIC_STATIC_LIBRARY( ".pic.a", Staticness.STATIC, "c++-link-pic-static-library", Picness.PIC, - ArtifactCategory.STATIC_LIBRARY), + ArtifactCategory.STATIC_LIBRARY, + Executable.NOT_EXECUTABLE), /** An interface dynamic library. */ INTERFACE_DYNAMIC_LIBRARY( @@ -143,7 +168,8 @@ public abstract class Link { Staticness.DYNAMIC, "c++-link-interface-dynamic-library", Picness.NOPIC, // Actually PIC but it's not indicated in the file name - ArtifactCategory.INTERFACE_LIBRARY), + ArtifactCategory.INTERFACE_LIBRARY, + Executable.NOT_EXECUTABLE), /** A dynamic library. */ DYNAMIC_LIBRARY( @@ -151,7 +177,8 @@ public abstract class Link { Staticness.DYNAMIC, "c++-link-dynamic-library", Picness.NOPIC, // Actually PIC but it's not indicated in the file name - ArtifactCategory.DYNAMIC_LIBRARY), + ArtifactCategory.DYNAMIC_LIBRARY, + Executable.NOT_EXECUTABLE), /** A static archive without removal of unused object files. */ ALWAYS_LINK_STATIC_LIBRARY( @@ -159,7 +186,8 @@ public abstract class Link { Staticness.STATIC, "c++-link-alwayslink-static-library", Picness.NOPIC, - ArtifactCategory.ALWAYSLINK_STATIC_LIBRARY), + ArtifactCategory.ALWAYSLINK_STATIC_LIBRARY, + Executable.NOT_EXECUTABLE), /** A PIC static archive without removal of unused object files. */ ALWAYS_LINK_PIC_STATIC_LIBRARY( @@ -167,7 +195,8 @@ public abstract class Link { Staticness.STATIC, "c++-link-alwayslink-pic-static-library", Picness.PIC, - ArtifactCategory.ALWAYSLINK_STATIC_LIBRARY), + ArtifactCategory.ALWAYSLINK_STATIC_LIBRARY, + Executable.NOT_EXECUTABLE), /** An executable binary. */ EXECUTABLE( @@ -175,25 +204,29 @@ public abstract class Link { Staticness.DYNAMIC, "c++-link-executable", Picness.NOPIC, // Picness is not indicate in the file name - ArtifactCategory.EXECUTABLE); + ArtifactCategory.EXECUTABLE, + Executable.EXECUTABLE); private final String extension; private final Staticness staticness; private final String actionName; private final ArtifactCategory linkerOutput; private final Picness picness; + private final Executable executable; LinkTargetType( String extension, Staticness staticness, String actionName, Picness picness, - ArtifactCategory linkerOutput) { + ArtifactCategory linkerOutput, + Executable executable) { this.extension = extension; this.staticness = staticness; this.actionName = actionName; this.linkerOutput = linkerOutput; this.picness = picness; + this.executable = executable; } /** @@ -223,6 +256,11 @@ public abstract class Link { public String getActionName() { return actionName; } + + /** Returns true iff this link type is executable */ + public boolean isExecutable() { + return (executable == Executable.EXECUTABLE); + } } /** diff --git a/src/main/java/com/google/devtools/build/lib/rules/cpp/LinkCommandLine.java b/src/main/java/com/google/devtools/build/lib/rules/cpp/LinkCommandLine.java index 27e3e4db99..6a95202423 100644 --- a/src/main/java/com/google/devtools/build/lib/rules/cpp/LinkCommandLine.java +++ b/src/main/java/com/google/devtools/build/lib/rules/cpp/LinkCommandLine.java @@ -408,6 +408,7 @@ public final class LinkCommandLine extends CommandLine { // TODO(b/30109612): make this pattern the case for all link variants. case OBJC_ARCHIVE: case OBJC_FULLY_LINKED_ARCHIVE: + case OBJC_EXECUTABLE: argv.add(toolPath); argv.addAll(featureConfiguration.getCommandLine(actionName, variables)); break; diff --git a/src/main/java/com/google/devtools/build/lib/rules/objc/BinaryLinkingTargetFactory.java b/src/main/java/com/google/devtools/build/lib/rules/objc/BinaryLinkingTargetFactory.java index 59eddc2d90..ea26384486 100644 --- a/src/main/java/com/google/devtools/build/lib/rules/objc/BinaryLinkingTargetFactory.java +++ b/src/main/java/com/google/devtools/build/lib/rules/objc/BinaryLinkingTargetFactory.java @@ -115,34 +115,26 @@ abstract class BinaryLinkingTargetFactory implements RuleConfiguredTargetFactory ruleContext.getPrerequisites("deps", Mode.TARGET, J2ObjcEntryClassProvider.class)) .build(); - CompilationSupport compilationSupport; - LegacyCompilationSupport legacyCompilationSupport = new LegacyCompilationSupport(ruleContext); + CompilationSupport compilationSupport = (usesCrosstool != UsesCrosstool.EXPERIMENTAL + || !ruleContext.getFragment(ObjcConfiguration.class).useCrosstoolForBinary()) + ? new LegacyCompilationSupport(ruleContext) + : new CrosstoolCompilationSupport(ruleContext); - if (usesCrosstool != UsesCrosstool.EXPERIMENTAL - || !ruleContext.getFragment(ObjcConfiguration.class).useCrosstoolForBinary()) { - compilationSupport = legacyCompilationSupport; - } else { - compilationSupport = new CrosstoolCompilationSupport(ruleContext); - } - compilationSupport + .validateAttributes() .addXcodeSettings(xcodeProviderBuilder, common) .registerCompileAndArchiveActions(common) .registerFullyLinkAction( common.getObjcProvider(), ruleContext.getImplicitOutputArtifact(CompilationSupport.FULLY_LINKED_LIB)) - .validateAttributes(); + .registerLinkActions( + objcProvider, + j2ObjcMappingFileProvider, + j2ObjcEntryClassProvider, + getExtraLinkArgs(ruleContext), + ImmutableList.<Artifact>of(), + DsymOutputType.APP); - // TODO(b/29582284): Factor into the above if/else once CrosstoolCompilationSupport supports - // executable linking. - legacyCompilationSupport.registerLinkActions( - objcProvider, - j2ObjcMappingFileProvider, - j2ObjcEntryClassProvider, - getExtraLinkArgs(ruleContext), - ImmutableList.<Artifact>of(), - DsymOutputType.APP); - Optional<XcTestAppProvider> xcTestAppProvider; Optional<RunfilesSupport> maybeRunfilesSupport = Optional.absent(); switch (hasReleaseBundlingSupport) { diff --git a/src/main/java/com/google/devtools/build/lib/rules/objc/CompilationSupport.java b/src/main/java/com/google/devtools/build/lib/rules/objc/CompilationSupport.java index 8bf9121f19..aaa5d80f60 100644 --- a/src/main/java/com/google/devtools/build/lib/rules/objc/CompilationSupport.java +++ b/src/main/java/com/google/devtools/build/lib/rules/objc/CompilationSupport.java @@ -15,10 +15,15 @@ package com.google.devtools.build.lib.rules.objc; import static com.google.devtools.build.lib.packages.ImplicitOutputsFunction.fromTemplates; +import static com.google.devtools.build.lib.rules.cpp.Link.LINK_LIBRARY_FILETYPES; +import static com.google.devtools.build.lib.rules.objc.ObjcProvider.FORCE_LOAD_LIBRARY; import static com.google.devtools.build.lib.rules.objc.ObjcProvider.FRAMEWORK_DIR; import static com.google.devtools.build.lib.rules.objc.ObjcProvider.FRAMEWORK_SEARCH_PATH_ONLY; import static com.google.devtools.build.lib.rules.objc.ObjcProvider.IMPORTED_LIBRARY; import static com.google.devtools.build.lib.rules.objc.ObjcProvider.INCLUDE_SYSTEM; +import static com.google.devtools.build.lib.rules.objc.ObjcProvider.LIBRARY; +import static com.google.devtools.build.lib.rules.objc.ObjcProvider.SDK_DYLIB; +import static com.google.devtools.build.lib.rules.objc.ObjcProvider.SDK_FRAMEWORK; import static com.google.devtools.build.lib.rules.objc.ObjcRuleClasses.COMPILABLE_SRCS_TYPE; import static com.google.devtools.build.lib.rules.objc.ObjcRuleClasses.HEADERS; import static com.google.devtools.build.lib.rules.objc.ObjcRuleClasses.NON_ARC_SRCS_TYPE; @@ -28,7 +33,9 @@ import static com.google.devtools.build.lib.rules.objc.ObjcRuleClasses.SWIFT_SOU import static java.nio.charset.StandardCharsets.ISO_8859_1; import com.google.common.annotations.VisibleForTesting; +import com.google.common.base.Joiner; import com.google.common.base.Optional; +import com.google.common.base.Preconditions; import com.google.common.base.Predicate; import com.google.common.base.Predicates; import com.google.common.collect.ImmutableList; @@ -67,8 +74,11 @@ import com.google.devtools.build.lib.rules.test.InstrumentedFilesCollector.Local import com.google.devtools.build.lib.rules.test.InstrumentedFilesProvider; import com.google.devtools.build.lib.util.FileTypeSet; import com.google.devtools.build.lib.util.Pair; +import com.google.devtools.build.lib.vfs.FileSystemUtils; import com.google.devtools.build.lib.vfs.PathFragment; +import java.util.LinkedHashSet; import java.util.List; +import java.util.Set; /** * Support for rules that compile sources. Provides ways to determine files that should be output, @@ -119,6 +129,17 @@ public abstract class CompilationSupport { ImmutableList.of( "-fexceptions", "-fasm-blocks", "-fobjc-abi-version=2", "-fobjc-legacy-dispatch"); + private static final String FRAMEWORK_SUFFIX = ".framework"; + + /** Selects cc libraries that have alwayslink=1. */ + protected static final Predicate<Artifact> ALWAYS_LINKED_CC_LIBRARY = + new Predicate<Artifact>() { + @Override + public boolean apply(Artifact input) { + return LINK_LIBRARY_FILETYPES.matches(input.getFilename()); + } + }; + /** * Returns the location of the xcrunwrapper tool. */ @@ -427,7 +448,7 @@ public abstract class CompilationSupport { // The COVERAGE_GCOV_PATH environment variable is added in TestSupport#getExtraProviders() NestedSetBuilder.<Pair<String, String>>emptySet(Order.COMPILE_ORDER), !TargetUtils.isTestRule(ruleContext.getTarget())); - } + } /** * Registers an action that will generate a clang module map for this target, using the hdrs @@ -450,7 +471,7 @@ public abstract class CompilationSupport { return this; } - /** + /** * Validates compilation-related attributes on this rule. * * @return this compilation support @@ -578,7 +599,7 @@ public abstract class CompilationSupport { J2ObjcEntryClassProvider j2ObjcEntryClassProvider, ExtraLinkArgs extraLinkArgs, Iterable<Artifact> extraLinkInputs, - DsymOutputType dsymOutputType); + DsymOutputType dsymOutputType) throws InterruptedException; /** * Returns the copts for the compile action in the current rule context (using a combination of @@ -611,7 +632,7 @@ public abstract class CompilationSupport { } return copts; } - + /** * Registers an action that writes given set of object files to the given objList. This objList is * suitable to signal symbols to archive in a libtool archiving invocation. @@ -645,8 +666,8 @@ public abstract class CompilationSupport { } /** - * Registers an action to create an archive artifact by fully (statically) linking all - * transitive dependencies of this rule. + * Registers an action to create an archive artifact by fully (statically) linking all transitive + * dependencies of this rule. * * @param objcProvider provides all compiling and linking information to create this artifact * @param inputArtifacts inputs for this action @@ -657,7 +678,200 @@ public abstract class CompilationSupport { ObjcProvider objcProvider, Iterable<Artifact> inputArtifacts, Artifact outputArchive) throws InterruptedException; - + /** + * Returns all framework names to pass to the linker using {@code -framework} flags. For a + * framework in the directory foo/bar.framework, the name is "bar". Each framework is found + * without using the full path by means of the framework search paths. Search paths are added by + * {@link#commonLinkAndCompileFlagsForClang(ObjcProvider, ObjcConfiguration, AppleConfiguration)}) + * + * <p>It's awful that we can't pass the full path to the framework and avoid framework search + * paths, but this is imposed on us by clang. clang does not support passing the full path to the + * framework, so Bazel cannot do it either. + */ + protected Set<String> frameworkNames(ObjcProvider provider) { + Set<String> names = new LinkedHashSet<>(); + Iterables.addAll(names, SdkFramework.names(provider.get(SDK_FRAMEWORK))); + for (PathFragment frameworkDir : provider.get(FRAMEWORK_DIR)) { + String segment = frameworkDir.getBaseName(); + Preconditions.checkState( + segment.endsWith(FRAMEWORK_SUFFIX), + "expect %s to end with %s, but it does not", + segment, + FRAMEWORK_SUFFIX); + names.add(segment.substring(0, segment.length() - FRAMEWORK_SUFFIX.length())); + } + return names; + } + + /** + * Returns libraries that should be passed to the linker. + */ + protected ImmutableList<String> libraryNames(ObjcProvider objcProvider) { + ImmutableList.Builder<String> args = new ImmutableList.Builder<>(); + for (String dylib : objcProvider.get(SDK_DYLIB)) { + if (dylib.startsWith("lib")) { + // remove lib prefix if it exists which is standard + // for libraries (libxml.dylib -> -lxml). + dylib = dylib.substring(3); + } + args.add(dylib); + } + return args.build(); + } + + /** + * Returns libraries that should be passed into the linker with {@code -force_load}. + */ + protected ImmutableSet<Artifact> getForceLoadArtifacts(ObjcProvider objcProvider) { + ImmutableList<Artifact> ccLibraries = objcProvider.getCcLibraries(); + Iterable<Artifact> ccLibrariesToForceLoad = + Iterables.filter(ccLibraries, ALWAYS_LINKED_CC_LIBRARY); + + return ImmutableSet.<Artifact>builder() + .addAll(objcProvider.get(FORCE_LOAD_LIBRARY)) + .addAll(ccLibrariesToForceLoad) + .build(); + } + + /** Returns pruned J2Objc archives for this target. */ + protected ImmutableList<Artifact> j2objcPrunedLibraries(ObjcProvider objcProvider) { + ImmutableList.Builder<Artifact> j2objcPrunedLibraryBuilder = ImmutableList.builder(); + for (Artifact j2objcLibrary : objcProvider.get(ObjcProvider.J2OBJC_LIBRARY)) { + j2objcPrunedLibraryBuilder.add(intermediateArtifacts.j2objcPrunedArchive(j2objcLibrary)); + } + return j2objcPrunedLibraryBuilder.build(); + } + + /** + * Returns true if this build should strip J2Objc dead code. + */ + protected boolean stripJ2ObjcDeadCode(J2ObjcEntryClassProvider j2ObjcEntryClassProvider) { + J2ObjcConfiguration j2objcConfiguration = + buildConfiguration.getFragment(J2ObjcConfiguration.class); + // Only perform J2ObjC dead code stripping if flag --j2objc_dead_code_removal is specified and + // users have specified entry classes. + return j2objcConfiguration.removeDeadCode() + && !j2ObjcEntryClassProvider.getEntryClasses().isEmpty(); + } + + /** + * Registers actions to perform J2Objc dead code removal. + */ + protected void registerJ2ObjcDeadCodeRemovalActions( + ObjcProvider objcProvider, + J2ObjcMappingFileProvider j2ObjcMappingFileProvider, + J2ObjcEntryClassProvider j2ObjcEntryClassProvider) { + NestedSet<String> entryClasses = j2ObjcEntryClassProvider.getEntryClasses(); + Artifact pruner = ruleContext.getPrerequisiteArtifact("$j2objc_dead_code_pruner", Mode.HOST); + NestedSet<Artifact> j2ObjcDependencyMappingFiles = + j2ObjcMappingFileProvider.getDependencyMappingFiles(); + NestedSet<Artifact> j2ObjcHeaderMappingFiles = + j2ObjcMappingFileProvider.getHeaderMappingFiles(); + NestedSet<Artifact> j2ObjcArchiveSourceMappingFiles = + j2ObjcMappingFileProvider.getArchiveSourceMappingFiles(); + + for (Artifact j2objcArchive : objcProvider.get(ObjcProvider.J2OBJC_LIBRARY)) { + PathFragment paramFilePath = + FileSystemUtils.replaceExtension( + j2objcArchive.getOwner().toPathFragment(), ".param.j2objc"); + Artifact paramFile = + ruleContext.getUniqueDirectoryArtifact( + "_j2objc_pruned", paramFilePath, ruleContext.getBinOrGenfilesDirectory()); + Artifact prunedJ2ObjcArchive = intermediateArtifacts.j2objcPrunedArchive(j2objcArchive); + Artifact dummyArchive = + Iterables.getOnlyElement( + ruleContext + .getPrerequisite("$dummy_lib", Mode.TARGET, ObjcProvider.class) + .get(LIBRARY)); + + CustomCommandLine commandLine = + CustomCommandLine.builder() + .addExecPath("--input_archive", j2objcArchive) + .addExecPath("--output_archive", prunedJ2ObjcArchive) + .addExecPath("--dummy_archive", dummyArchive) + .addExecPath("--xcrunwrapper", xcrunwrapper(ruleContext).getExecutable()) + .addJoinExecPaths("--dependency_mapping_files", ",", j2ObjcDependencyMappingFiles) + .addJoinExecPaths("--header_mapping_files", ",", j2ObjcHeaderMappingFiles) + .addJoinExecPaths( + "--archive_source_mapping_files", ",", j2ObjcArchiveSourceMappingFiles) + .add("--entry_classes") + .add(Joiner.on(",").join(entryClasses)) + .build(); + + ruleContext.registerAction( + new ParameterFileWriteAction( + ruleContext.getActionOwner(), + paramFile, + commandLine, + ParameterFile.ParameterFileType.UNQUOTED, + ISO_8859_1)); + ruleContext.registerAction( + ObjcRuleClasses.spawnAppleEnvActionBuilder( + appleConfiguration, appleConfiguration.getSingleArchPlatform()) + .setMnemonic("DummyPruner") + .setExecutable(pruner) + .addInput(dummyArchive) + .addInput(pruner) + .addInput(paramFile) + .addInput(j2objcArchive) + .addInput(xcrunwrapper(ruleContext).getExecutable()) + .addTransitiveInputs(j2ObjcDependencyMappingFiles) + .addTransitiveInputs(j2ObjcHeaderMappingFiles) + .addTransitiveInputs(j2ObjcArchiveSourceMappingFiles) + .setCommandLine( + CustomCommandLine.builder().addPaths("@%s", paramFile.getExecPath()).build()) + .addOutput(prunedJ2ObjcArchive) + .build(ruleContext)); + } + } + + /** Returns archives arising from j2objc transpilation after dead code removal. */ + protected Iterable<Artifact> computeAndStripPrunedJ2ObjcArchives( + J2ObjcEntryClassProvider j2ObjcEntryClassProvider, + J2ObjcMappingFileProvider j2ObjcMappingFileProvider, + ObjcProvider objcProvider) { + Iterable<Artifact> prunedJ2ObjcArchives = ImmutableList.<Artifact>of(); + if (stripJ2ObjcDeadCode(j2ObjcEntryClassProvider)) { + registerJ2ObjcDeadCodeRemovalActions( + objcProvider, j2ObjcMappingFileProvider, j2ObjcEntryClassProvider); + prunedJ2ObjcArchives = j2objcPrunedLibraries(objcProvider); + } + return prunedJ2ObjcArchives; + } + + /** + * Returns a nested set of Bazel-built ObjC libraries with all unpruned J2ObjC libraries + * substituted with pruned ones. + */ + protected ImmutableList<Artifact> substituteJ2ObjcPrunedLibraries(ObjcProvider objcProvider) { + ImmutableList.Builder<Artifact> libraries = new ImmutableList.Builder<>(); + + Set<Artifact> unprunedJ2ObjcLibs = objcProvider.get(ObjcProvider.J2OBJC_LIBRARY).toSet(); + for (Artifact library : objcProvider.getObjcLibraries()) { + // If we match an unpruned J2ObjC library, add the pruned version of the J2ObjC static library + // instead. + if (unprunedJ2ObjcLibs.contains(library)) { + libraries.add(intermediateArtifacts.j2objcPrunedArchive(library)); + } else { + libraries.add(library); + } + } + return libraries.build(); + } + + /** Returns the artifact that should be the outcome of this build's link action */ + protected Artifact getBinaryToLink() { + + // When compilation_mode=opt and objc_enable_binary_stripping are specified, the unstripped + // binary containing debug symbols is generated by the linker, which also needs the debug + // symbols for dead-code removal. The binary is also used to generate dSYM bundle if + // --apple_generate_dsym is specified. A symbol strip action is later registered to strip + // the symbol table from the unstripped binary. + return objcConfiguration.shouldStripBinary() + ? intermediateArtifacts.unstrippedSingleArchitectureBinary() + : intermediateArtifacts.strippedSingleArchitectureBinary(); + } + private NestedSet<Artifact> getGcovForObjectiveCIfNeeded() { if (ruleContext.getConfiguration().isCodeCoverageEnabled() && ruleContext.attributes().has(IosTest.OBJC_GCOV_ATTR, BuildType.LABEL)) { @@ -719,4 +933,4 @@ public abstract class CompilationSupport { } return parents.build(); } -}
\ No newline at end of file +} diff --git a/src/main/java/com/google/devtools/build/lib/rules/objc/CrosstoolCompilationSupport.java b/src/main/java/com/google/devtools/build/lib/rules/objc/CrosstoolCompilationSupport.java index bf50ddff16..cd6789d3d1 100644 --- a/src/main/java/com/google/devtools/build/lib/rules/objc/CrosstoolCompilationSupport.java +++ b/src/main/java/com/google/devtools/build/lib/rules/objc/CrosstoolCompilationSupport.java @@ -15,12 +15,17 @@ package com.google.devtools.build.lib.rules.objc; import static com.google.devtools.build.lib.rules.objc.ObjcProvider.DEFINE; +import static com.google.devtools.build.lib.rules.objc.ObjcProvider.DYNAMIC_FRAMEWORK_FILE; import static com.google.devtools.build.lib.rules.objc.ObjcProvider.IMPORTED_LIBRARY; import static com.google.devtools.build.lib.rules.objc.ObjcProvider.INCLUDE; import static com.google.devtools.build.lib.rules.objc.ObjcProvider.INCLUDE_SYSTEM; +import static com.google.devtools.build.lib.rules.objc.ObjcProvider.STATIC_FRAMEWORK_FILE; +import com.google.common.base.Predicates; import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableMap; +import com.google.common.collect.ImmutableSet; +import com.google.common.collect.Iterables; import com.google.common.collect.Sets; import com.google.devtools.build.lib.actions.Artifact; import com.google.devtools.build.lib.analysis.RuleConfiguredTarget.Mode; @@ -38,15 +43,16 @@ import com.google.devtools.build.lib.rules.cpp.CppRuleClasses; import com.google.devtools.build.lib.rules.cpp.Link.LinkStaticness; import com.google.devtools.build.lib.rules.cpp.Link.LinkTargetType; import com.google.devtools.build.lib.rules.cpp.PrecompiledFiles; +import com.google.devtools.build.lib.rules.objc.ObjcVariablesExtension.VariableCategory; import com.google.devtools.build.lib.vfs.PathFragment; import java.util.Collection; /** - * Constructs command lines for objc compilation, archiving, and linking. Uses the crosstool - * infrastructure to register {@link CppCompileAction} and {@link CppLinkAction} instances, - * making use of a provided toolchain. - * - * TODO(b/28403953): Deprecate LegacyCompilationSupport in favor of this implementation for all + * Constructs command lines for objc compilation, archiving, and linking. Uses the crosstool + * infrastructure to register {@link CppCompileAction} and {@link CppLinkAction} instances, making + * use of a provided toolchain. + * + * <p>TODO(b/28403953): Deprecate LegacyCompilationSupport in favor of this implementation for all * objc rules. */ public class CrosstoolCompilationSupport extends CompilationSupport { @@ -59,6 +65,7 @@ public class CrosstoolCompilationSupport extends CompilationSupport { "objc++-compile", "objc-archive", "objc-fully-link", + "objc-executable", "assemble", "preprocess-assemble", "c-compile", @@ -79,25 +86,37 @@ public class CrosstoolCompilationSupport extends CompilationSupport { CompilationAttributes.Builder.fromRuleContext(ruleContext).build()); this.compilationArtifacts = compilationArtifacts(ruleContext); } - + @Override CompilationSupport registerCompileAndArchiveActions( ObjcCommon common, ExtraCompileArgs extraCompileArgs, Iterable<PathFragment> priorityHeaders) throws RuleErrorException, InterruptedException { - CcLibraryHelper helper = createCcLibraryHelper(common); - + ObjcVariablesExtension.Builder extension = new ObjcVariablesExtension.Builder() + .setRuleContext(ruleContext) + .setObjcProvider(common.getObjcProvider()) + .setCompilationArtifacts(compilationArtifacts) + .setIntermediateArtifacts(intermediateArtifacts) + .setConfiguration(ruleContext.getConfiguration()); + CcLibraryHelper helper; + if (compilationArtifacts.getArchive().isPresent()) { Artifact objList = intermediateArtifacts.archiveObjList(); // TODO(b/30783125): Signal the need for this action in the CROSSTOOL. registerObjFilelistAction(getObjFiles(compilationArtifacts, intermediateArtifacts), objList); - helper.setLinkType(LinkTargetType.OBJC_ARCHIVE).addLinkActionInput(objList); + extension.addVariableCategory(VariableCategory.ARCHIVE_VARIABLES); + + helper = createCcLibraryHelper(common, extension.build()) + .setLinkType(LinkTargetType.OBJC_ARCHIVE) + .addLinkActionInput(objList); + } else { + helper = createCcLibraryHelper(common, extension.build()); } - - helper.build(); + helper.build(); + return this; } @@ -113,6 +132,16 @@ public class CrosstoolCompilationSupport extends CompilationSupport { .getPackageDirectory() .getRelative(labelName.replaceName("lib" + labelName.getBaseName())) .getPathString(); + ObjcVariablesExtension extension = new ObjcVariablesExtension.Builder() + .setRuleContext(ruleContext) + .setObjcProvider(objcProvider) + .setConfiguration(ruleContext.getConfiguration()) + .setIntermediateArtifacts(intermediateArtifacts) + .setFullyLinkArchive( + ruleContext.getImplicitOutputArtifact(CompilationSupport.FULLY_LINKED_LIB)) + .addVariableCategory(VariableCategory.FULLY_LINK_VARIABLES) + .build(); + CppLinkAction fullyLinkAction = new CppLinkActionBuilder(ruleContext, fullyLinkedArchive) .addActionInputs(objcProvider.getObjcLibraries()) @@ -121,7 +150,7 @@ public class CrosstoolCompilationSupport extends CompilationSupport { .setLinkType(LinkTargetType.OBJC_FULLY_LINKED_ARCHIVE) .setLinkStaticness(LinkStaticness.FULLY_STATIC) .setLibraryIdentifier(libraryIdentifier) - .addVariablesExtension(getVariablesExtension(objcProvider)) + .addVariablesExtension(extension) .setFeatureConfiguration(getFeatureConfiguration(ruleContext)) .build(); ruleContext.registerAction(fullyLinkAction); @@ -136,12 +165,61 @@ public class CrosstoolCompilationSupport extends CompilationSupport { J2ObjcEntryClassProvider j2ObjcEntryClassProvider, ExtraLinkArgs extraLinkArgs, Iterable<Artifact> extraLinkInputs, - DsymOutputType dsymOutputType) { - // TODO(b/29582284): Implement the link action in the objc crosstool. - throw new UnsupportedOperationException(); + DsymOutputType dsymOutputType) throws InterruptedException { + Iterable<Artifact> prunedJ2ObjcArchives = + computeAndStripPrunedJ2ObjcArchives( + j2ObjcEntryClassProvider, j2ObjcMappingFileProvider, objcProvider); + ImmutableList<Artifact> bazelBuiltLibraries = + Iterables.isEmpty(prunedJ2ObjcArchives) + ? objcProvider.getObjcLibraries() + : substituteJ2ObjcPrunedLibraries(objcProvider); + + Artifact inputFileList = intermediateArtifacts.linkerObjList(); + ImmutableSet<Artifact> forceLinkArtifacts = getForceLoadArtifacts(objcProvider); + + Iterable<Artifact> objFiles = + Iterables.concat( + bazelBuiltLibraries, objcProvider.get(IMPORTED_LIBRARY), objcProvider.getCcLibraries()); + // Clang loads archives specified in filelists and also specified as -force_load twice, + // resulting in duplicate symbol errors unless they are deduped. + objFiles = Iterables.filter(objFiles, Predicates.not(Predicates.in(forceLinkArtifacts))); + + registerObjFilelistAction(objFiles, inputFileList); + + ObjcVariablesExtension extension = new ObjcVariablesExtension.Builder() + .setRuleContext(ruleContext) + .setObjcProvider(objcProvider) + .setConfiguration(ruleContext.getConfiguration()) + .setIntermediateArtifacts(intermediateArtifacts) + .setFrameworkNames(frameworkNames(objcProvider)) + .setLibraryNames(libraryNames(objcProvider)) + .setForceLoadArtifacts(getForceLoadArtifacts(objcProvider)) + .setAttributeLinkopts(attributes.linkopts()) + .addVariableCategory(VariableCategory.EXECUTABLE_LINKING_VARIABLES) + .build(); + + Artifact binaryToLink = getBinaryToLink(); + CppLinkAction executableLinkAction = + new CppLinkActionBuilder(ruleContext, binaryToLink) + .setMnemonic("ObjcLink") + .addActionInputs(bazelBuiltLibraries) + .addActionInputs(objcProvider.getCcLibraries()) + .addTransitiveActionInputs(objcProvider.get(IMPORTED_LIBRARY)) + .addTransitiveActionInputs(objcProvider.get(STATIC_FRAMEWORK_FILE)) + .addTransitiveActionInputs(objcProvider.get(DYNAMIC_FRAMEWORK_FILE)) + .addActionInputs(prunedJ2ObjcArchives) + .addActionInput(inputFileList) + .setLinkType(LinkTargetType.OBJC_EXECUTABLE) + .setLinkStaticness(LinkStaticness.FULLY_STATIC) + .addVariablesExtension(extension) + .setFeatureConfiguration(getFeatureConfiguration(ruleContext)) + .build(); + ruleContext.registerAction(executableLinkAction); + + return this; } - private CcLibraryHelper createCcLibraryHelper(ObjcCommon common) throws InterruptedException { + private CcLibraryHelper createCcLibraryHelper(ObjcCommon common, VariablesExtension extension) { PrecompiledFiles precompiledFiles = new PrecompiledFiles(ruleContext); Collection<Artifact> arcSources = Sets.newHashSet(compilationArtifacts.getSrcs()); Collection<Artifact> nonArcSources = Sets.newHashSet(compilationArtifacts.getNonArcSrcs()); @@ -170,7 +248,7 @@ public class CrosstoolCompilationSupport extends CompilationSupport { .addCopts(ruleContext.getFragment(ObjcConfiguration.class).getCoptsForCompilationMode()) .addSystemIncludeDirs(common.getObjcProvider().get(INCLUDE_SYSTEM)) .setCppModuleMap(intermediateArtifacts.moduleMap()) - .addVariableExtension(getVariablesExtension(common.getObjcProvider())); + .addVariableExtension(extension); } private static FeatureConfiguration getFeatureConfiguration(RuleContext ruleContext) { @@ -192,7 +270,7 @@ public class CrosstoolCompilationSupport extends CompilationSupport { .add(CppRuleClasses.COMPILE_ACTION_FLAGS_IN_FLAG_SET) .add(CppRuleClasses.DEPENDENCY_FILE) .add(CppRuleClasses.INCLUDE_PATHS); - + if (ruleContext.getConfiguration().getFragment(ObjcConfiguration.class).moduleMapsEnabled()) { activatedCrosstoolSelectables.add(OBJC_MODULE_FEATURE_NAME); } @@ -207,17 +285,6 @@ public class CrosstoolCompilationSupport extends CompilationSupport { return toolchain.getFeatures().getFeatureConfiguration(activatedCrosstoolSelectables.build()); } - private VariablesExtension getVariablesExtension(ObjcProvider objcProvider) - throws InterruptedException { - return new ObjcVariablesExtension( - ruleContext, - objcProvider, - compilationArtifacts, - ruleContext.getImplicitOutputArtifact(CompilationSupport.FULLY_LINKED_LIB), - intermediateArtifacts, - ruleContext.getConfiguration()); - } - private static ImmutableList<Artifact> getObjFiles( CompilationArtifacts compilationArtifacts, IntermediateArtifacts intermediateArtifacts) { ImmutableList.Builder<Artifact> result = new ImmutableList.Builder<>(); diff --git a/src/main/java/com/google/devtools/build/lib/rules/objc/LegacyCompilationSupport.java b/src/main/java/com/google/devtools/build/lib/rules/objc/LegacyCompilationSupport.java index f7fdcdfb62..4658c5bd15 100644 --- a/src/main/java/com/google/devtools/build/lib/rules/objc/LegacyCompilationSupport.java +++ b/src/main/java/com/google/devtools/build/lib/rules/objc/LegacyCompilationSupport.java @@ -14,22 +14,17 @@ package com.google.devtools.build.lib.rules.objc; -import static com.google.devtools.build.lib.rules.cpp.Link.LINK_LIBRARY_FILETYPES; import static com.google.devtools.build.lib.rules.objc.ObjcProvider.DEFINE; import static com.google.devtools.build.lib.rules.objc.ObjcProvider.DYNAMIC_FRAMEWORK_FILE; import static com.google.devtools.build.lib.rules.objc.ObjcProvider.FORCE_LOAD_LIBRARY; -import static com.google.devtools.build.lib.rules.objc.ObjcProvider.FRAMEWORK_DIR; import static com.google.devtools.build.lib.rules.objc.ObjcProvider.Flag.USES_CPP; import static com.google.devtools.build.lib.rules.objc.ObjcProvider.Flag.USES_SWIFT; import static com.google.devtools.build.lib.rules.objc.ObjcProvider.HEADER; import static com.google.devtools.build.lib.rules.objc.ObjcProvider.IMPORTED_LIBRARY; import static com.google.devtools.build.lib.rules.objc.ObjcProvider.INCLUDE; import static com.google.devtools.build.lib.rules.objc.ObjcProvider.INCLUDE_SYSTEM; -import static com.google.devtools.build.lib.rules.objc.ObjcProvider.LIBRARY; import static com.google.devtools.build.lib.rules.objc.ObjcProvider.LINK_INPUTS; import static com.google.devtools.build.lib.rules.objc.ObjcProvider.MODULE_MAP; -import static com.google.devtools.build.lib.rules.objc.ObjcProvider.SDK_DYLIB; -import static com.google.devtools.build.lib.rules.objc.ObjcProvider.SDK_FRAMEWORK; import static com.google.devtools.build.lib.rules.objc.ObjcProvider.STATIC_FRAMEWORK_FILE; import static com.google.devtools.build.lib.rules.objc.ObjcProvider.WEAK_SDK_FRAMEWORK; import static com.google.devtools.build.lib.rules.objc.ObjcRuleClasses.CLANG; @@ -42,24 +37,20 @@ import static com.google.devtools.build.lib.rules.objc.ObjcRuleClasses.PRECOMPIL import static com.google.devtools.build.lib.rules.objc.ObjcRuleClasses.SRCS_TYPE; import static com.google.devtools.build.lib.rules.objc.ObjcRuleClasses.STRIP; import static com.google.devtools.build.lib.rules.objc.ObjcRuleClasses.SWIFT; -import static java.nio.charset.StandardCharsets.ISO_8859_1; import com.google.common.base.Joiner; import com.google.common.base.Optional; -import com.google.common.base.Predicate; import com.google.common.base.Predicates; import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableSet; import com.google.common.collect.Iterables; import com.google.devtools.build.lib.actions.Artifact; import com.google.devtools.build.lib.actions.Artifact.TreeFileArtifact; -import com.google.devtools.build.lib.actions.ParameterFile; import com.google.devtools.build.lib.analysis.PrerequisiteArtifacts; import com.google.devtools.build.lib.analysis.RuleConfiguredTarget.Mode; import com.google.devtools.build.lib.analysis.RuleContext; import com.google.devtools.build.lib.analysis.actions.CommandLine; import com.google.devtools.build.lib.analysis.actions.CustomCommandLine; -import com.google.devtools.build.lib.analysis.actions.ParameterFileWriteAction; import com.google.devtools.build.lib.analysis.actions.SpawnAction; import com.google.devtools.build.lib.analysis.actions.SpawnActionTemplate; import com.google.devtools.build.lib.analysis.actions.SpawnActionTemplate.OutputPathMapper; @@ -77,9 +68,7 @@ import com.google.devtools.build.lib.rules.cpp.CppModuleMap; import com.google.devtools.build.lib.util.Preconditions; import com.google.devtools.build.lib.vfs.FileSystemUtils; import com.google.devtools.build.lib.vfs.PathFragment; -import java.util.ArrayList; import java.util.List; -import java.util.Set; /** * Constructs command lines for objc compilation, archiving, and linking. Uses hard-coded @@ -89,17 +78,6 @@ import java.util.Set; */ public class LegacyCompilationSupport extends CompilationSupport { - private static final String FRAMEWORK_SUFFIX = ".framework"; - - /** Selects cc libraries that have alwayslink=1. */ - private static final Predicate<Artifact> ALWAYS_LINKED_CC_LIBRARY = - new Predicate<Artifact>() { - @Override - public boolean apply(Artifact input) { - return LINK_LIBRARY_FILETYPES.matches(input.getFilename()); - } - }; - /** * A mapper that maps input ObjC source {@link Artifact.TreeFileArtifact}s to output object file * {@link Artifact.TreeFileArtifact}s. @@ -798,12 +776,9 @@ public class LegacyCompilationSupport extends CompilationSupport { dsymBundleZip = Optional.absent(); } - Iterable<Artifact> prunedJ2ObjcArchives = ImmutableList.<Artifact>of(); - if (stripJ2ObjcDeadCode(j2ObjcEntryClassProvider)) { - registerJ2ObjcDeadCodeRemovalActions(objcProvider, j2ObjcMappingFileProvider, - j2ObjcEntryClassProvider); - prunedJ2ObjcArchives = j2objcPrunedLibraries(objcProvider); - } + Iterable<Artifact> prunedJ2ObjcArchives = + computeAndStripPrunedJ2ObjcArchives( + j2ObjcEntryClassProvider, j2ObjcMappingFileProvider, objcProvider); if (objcConfiguration.generateLinkmap()) { linkmap = Optional.of(intermediateArtifacts.linkmap()); @@ -821,15 +796,6 @@ public class LegacyCompilationSupport extends CompilationSupport { return this; } - private boolean stripJ2ObjcDeadCode(J2ObjcEntryClassProvider j2ObjcEntryClassProvider) { - J2ObjcConfiguration j2objcConfiguration = - buildConfiguration.getFragment(J2ObjcConfiguration.class); - // Only perform J2ObjC dead code stripping if flag --j2objc_dead_code_removal is specified and - // users have specified entry classes. - return j2objcConfiguration.removeDeadCode() - && !j2ObjcEntryClassProvider.getEntryClasses().isEmpty(); - } - private boolean isDynamicLib(CommandLine commandLine) { return Iterables.contains(commandLine.arguments(), "-dynamiclib"); } @@ -841,15 +807,7 @@ public class LegacyCompilationSupport extends CompilationSupport { Optional<Artifact> dsymBundleZip, Iterable<Artifact> prunedJ2ObjcArchives, Optional<Artifact> linkmap) { - // When compilation_mode=opt and objc_enable_binary_stripping are specified, the unstripped - // binary containing debug symbols is generated by the linker, which also needs the debug - // symbols for dead-code removal. The binary is also used to generate dSYM bundle if - // --apple_generate_dsym is specified. A symbol strip action is later registered to strip - // the symbol table from the unstripped binary. - Artifact binaryToLink = - objcConfiguration.shouldStripBinary() - ? intermediateArtifacts.unstrippedSingleArchitectureBinary() - : intermediateArtifacts.strippedSingleArchitectureBinary(); + Artifact binaryToLink = getBinaryToLink(); ImmutableList<Artifact> objcLibraries = objcProvider.getObjcLibraries(); ImmutableList<Artifact> ccLibraries = objcProvider.getCcLibraries(); @@ -912,14 +870,6 @@ public class LegacyCompilationSupport extends CompilationSupport { } } - private ImmutableList<Artifact> j2objcPrunedLibraries(ObjcProvider objcProvider) { - ImmutableList.Builder<Artifact> j2objcPrunedLibraryBuilder = ImmutableList.builder(); - for (Artifact j2objcLibrary : objcProvider.get(ObjcProvider.J2OBJC_LIBRARY)) { - j2objcPrunedLibraryBuilder.add(intermediateArtifacts.j2objcPrunedArchive(j2objcLibrary)); - } - return j2objcPrunedLibraryBuilder.build(); - } - private static CommandLine symbolStripCommandLine( Iterable<String> extraFlags, Artifact unstrippedArtifact, Artifact strippedArtifact) { return CustomCommandLine.builder() @@ -930,26 +880,6 @@ public class LegacyCompilationSupport extends CompilationSupport { .build(); } - /** - * Returns a nested set of Bazel-built ObjC libraries with all unpruned J2ObjC libraries - * substituted with pruned ones. - */ - private ImmutableList<Artifact> substituteJ2ObjcPrunedLibraries(ObjcProvider objcProvider) { - ImmutableList.Builder<Artifact> libraries = new ImmutableList.Builder<>(); - - Set<Artifact> unprunedJ2ObjcLibs = objcProvider.get(ObjcProvider.J2OBJC_LIBRARY).toSet(); - for (Artifact library : objcProvider.getObjcLibraries()) { - // If we match an unpruned J2ObjC library, add the pruned version of the J2ObjC static library - // instead. - if (unprunedJ2ObjcLibs.contains(library)) { - libraries.add(intermediateArtifacts.j2objcPrunedArchive(library)); - } else { - libraries.add(library); - } - } - return libraries.build(); - } - private CommandLine linkCommandLine( ExtraLinkArgs extraLinkArgs, ObjcProvider objcProvider, @@ -1103,104 +1033,6 @@ public class LegacyCompilationSupport extends CompilationSupport { } } - private Iterable<String> libraryNames(ObjcProvider objcProvider) { - ImmutableList.Builder<String> args = new ImmutableList.Builder<>(); - for (String dylib : objcProvider.get(SDK_DYLIB)) { - if (dylib.startsWith("lib")) { - // remove lib prefix if it exists which is standard - // for libraries (libxml.dylib -> -lxml). - dylib = dylib.substring(3); - } - args.add(dylib); - } - return args.build(); - } - - /** - * All framework names to pass to the linker using {@code -framework} flags. For a framework in - * the directory foo/bar.framework, the name is "bar". Each framework is found without using the - * full path by means of the framework search paths. The search paths are added by - * {@link #commonLinkAndCompileFlagsForClang(ObjcProvider, ObjcConfiguration, - * AppleConfiguration)}). - * - * <p>It's awful that we can't pass the full path to the framework and avoid framework search - * paths, but this is imposed on us by clang. clang does not support passing the full path to the - * framework, so Bazel cannot do it either. - */ - private Iterable<String> frameworkNames(ObjcProvider provider) { - List<String> names = new ArrayList<>(); - Iterables.addAll(names, SdkFramework.names(provider.get(SDK_FRAMEWORK))); - for (PathFragment frameworkDir : provider.get(FRAMEWORK_DIR)) { - String segment = frameworkDir.getBaseName(); - Preconditions.checkState(segment.endsWith(FRAMEWORK_SUFFIX), - "expect %s to end with %s, but it does not", segment, FRAMEWORK_SUFFIX); - names.add(segment.substring(0, segment.length() - FRAMEWORK_SUFFIX.length())); - } - return names; - } - - private void registerJ2ObjcDeadCodeRemovalActions(ObjcProvider objcProvider, - J2ObjcMappingFileProvider j2ObjcMappingFileProvider, - J2ObjcEntryClassProvider j2ObjcEntryClassProvider) { - NestedSet<String> entryClasses = j2ObjcEntryClassProvider.getEntryClasses(); - Artifact pruner = ruleContext.getPrerequisiteArtifact("$j2objc_dead_code_pruner", Mode.HOST); - NestedSet<Artifact> j2ObjcDependencyMappingFiles = - j2ObjcMappingFileProvider.getDependencyMappingFiles(); - NestedSet<Artifact> j2ObjcHeaderMappingFiles = - j2ObjcMappingFileProvider.getHeaderMappingFiles(); - NestedSet<Artifact> j2ObjcArchiveSourceMappingFiles = - j2ObjcMappingFileProvider.getArchiveSourceMappingFiles(); - - for (Artifact j2objcArchive : objcProvider.get(ObjcProvider.J2OBJC_LIBRARY)) { - PathFragment paramFilePath = FileSystemUtils.replaceExtension( - j2objcArchive.getOwner().toPathFragment(), ".param.j2objc"); - Artifact paramFile = ruleContext.getUniqueDirectoryArtifact( - "_j2objc_pruned", - paramFilePath, - ruleContext.getBinOrGenfilesDirectory()); - Artifact prunedJ2ObjcArchive = intermediateArtifacts.j2objcPrunedArchive(j2objcArchive); - Artifact dummyArchive = Iterables.getOnlyElement( - ruleContext.getPrerequisite("$dummy_lib", Mode.TARGET, ObjcProvider.class) - .get(LIBRARY)); - - CustomCommandLine commandLine = CustomCommandLine.builder() - .addExecPath("--input_archive", j2objcArchive) - .addExecPath("--output_archive", prunedJ2ObjcArchive) - .addExecPath("--dummy_archive", dummyArchive) - .addExecPath("--xcrunwrapper", xcrunwrapper(ruleContext).getExecutable()) - .addJoinExecPaths("--dependency_mapping_files", ",", j2ObjcDependencyMappingFiles) - .addJoinExecPaths("--header_mapping_files", ",", j2ObjcHeaderMappingFiles) - .addJoinExecPaths( - "--archive_source_mapping_files", ",", j2ObjcArchiveSourceMappingFiles) - .add("--entry_classes").add(Joiner.on(",").join(entryClasses)) - .build(); - - ruleContext.registerAction( - new ParameterFileWriteAction( - ruleContext.getActionOwner(), - paramFile, - commandLine, - ParameterFile.ParameterFileType.UNQUOTED, ISO_8859_1)); - ruleContext.registerAction(ObjcRuleClasses.spawnAppleEnvActionBuilder( - appleConfiguration, appleConfiguration.getSingleArchPlatform()) - .setMnemonic("DummyPruner") - .setExecutable(pruner) - .addInput(dummyArchive) - .addInput(pruner) - .addInput(paramFile) - .addInput(j2objcArchive) - .addInput(xcrunwrapper(ruleContext).getExecutable()) - .addTransitiveInputs(j2ObjcDependencyMappingFiles) - .addTransitiveInputs(j2ObjcHeaderMappingFiles) - .addTransitiveInputs(j2ObjcArchiveSourceMappingFiles) - .setCommandLine(CustomCommandLine.builder() - .addPaths("@%s", paramFile.getExecPath()) - .build()) - .addOutput(prunedJ2ObjcArchive) - .build(ruleContext)); - } - } - private CompilationSupport registerDsymActions(DsymOutputType dsymOutputType) { Artifact tempDsymBundleZip = intermediateArtifacts.tempDsymBundleZip(dsymOutputType); Artifact linkedBinary = diff --git a/src/main/java/com/google/devtools/build/lib/rules/objc/ObjcVariablesExtension.java b/src/main/java/com/google/devtools/build/lib/rules/objc/ObjcVariablesExtension.java index e14be86eba..851af8d32e 100644 --- a/src/main/java/com/google/devtools/build/lib/rules/objc/ObjcVariablesExtension.java +++ b/src/main/java/com/google/devtools/build/lib/rules/objc/ObjcVariablesExtension.java @@ -15,17 +15,22 @@ package com.google.devtools.build.lib.rules.objc; import static com.google.devtools.build.lib.rules.objc.ObjcProvider.IMPORTED_LIBRARY; +import static com.google.devtools.build.lib.rules.objc.ObjcProvider.LINKOPT; +import com.google.common.base.Preconditions; import com.google.common.collect.ImmutableList; +import com.google.common.collect.ImmutableSet; import com.google.devtools.build.lib.actions.Artifact; import com.google.devtools.build.lib.analysis.RuleConfiguredTarget.Mode; import com.google.devtools.build.lib.analysis.RuleContext; import com.google.devtools.build.lib.analysis.config.BuildConfiguration; +import com.google.devtools.build.lib.collect.nestedset.NestedSet; import com.google.devtools.build.lib.rules.apple.AppleConfiguration; import com.google.devtools.build.lib.rules.apple.Platform; import com.google.devtools.build.lib.rules.cpp.CcToolchainFeatures; import com.google.devtools.build.lib.rules.cpp.CcToolchainFeatures.Variables.StringSequence; import com.google.devtools.build.lib.rules.cpp.CcToolchainFeatures.Variables.VariablesExtension; +import java.util.Set; /** Build variable extensions for templating a toolchain for objc builds. */ class ObjcVariablesExtension implements VariablesExtension { @@ -43,22 +48,41 @@ class ObjcVariablesExtension implements VariablesExtension { static final String CC_LIBRARY_EXEC_PATHS_VARIABLE_NAME = "cc_library_exec_paths"; static final String IMPORTED_LIBRARY_EXEC_PATHS_VARIABLE_NAME = "imported_library_exec_paths"; + // executable linking variables + static final String FRAMEWORK_NAMES_VARIABLE_NAME = "framework_names"; + static final String WEAK_FRAMEWORK_NAMES_VARIABLE_NAME = "weak_framework_names"; + static final String LIBRARY_NAMES_VARIABLE_NAME = "library_names"; + static final String FILELIST_VARIABLE_NAME = "filelist"; + static final String LINKED_BINARY_VARIABLE_NAME = "linked_binary"; + static final String FORCE_LOAD_EXEC_PATHS_VARIABLE_NAME = "force_load_exec_paths"; + static final String DEP_LINKOPTS_VARIABLE_NAME = "dep_linkopts"; + static final String ATTR_LINKOPTS_VARIABLE_NAME = "attr_linkopts"; + private final RuleContext ruleContext; private final ObjcProvider objcProvider; private final CompilationArtifacts compilationArtifacts; private final Artifact fullyLinkArchive; private final IntermediateArtifacts intermediateArtifacts; - private final BuildConfiguration buildConfiguration; private final AppleConfiguration appleConfiguration; + private final Set<String> frameworkNames; + private final ImmutableList<String> libraryNames; + private final ImmutableSet<Artifact> forceLoadArtifacts; + private final NestedSet<String> attributeLinkopts; + private final ImmutableSet<VariableCategory> activeVariableCategories; - public ObjcVariablesExtension( + private ObjcVariablesExtension( RuleContext ruleContext, ObjcProvider objcProvider, CompilationArtifacts compilationArtifacts, Artifact fullyLinkArchive, IntermediateArtifacts intermediateArtifacts, - BuildConfiguration buildConfiguration) { + BuildConfiguration buildConfiguration, + Set<String> frameworkNames, + ImmutableList<String> libraryNames, + ImmutableSet<Artifact> forceLoadArtifacts, + NestedSet<String> attributeLinkopts, + ImmutableSet<VariableCategory> activeVariableCategories) { this.ruleContext = ruleContext; this.objcProvider = objcProvider; this.compilationArtifacts = compilationArtifacts; @@ -66,6 +90,16 @@ class ObjcVariablesExtension implements VariablesExtension { this.intermediateArtifacts = intermediateArtifacts; this.buildConfiguration = buildConfiguration; this.appleConfiguration = buildConfiguration.getFragment(AppleConfiguration.class); + this.frameworkNames = frameworkNames; + this.libraryNames = libraryNames; + this.forceLoadArtifacts = forceLoadArtifacts; + this.attributeLinkopts = attributeLinkopts; + this.activeVariableCategories = activeVariableCategories; + } + + /** Type of build variable that can optionally exported by this extension. */ + public enum VariableCategory { + ARCHIVE_VARIABLES, FULLY_LINK_VARIABLES, EXECUTABLE_LINKING_VARIABLES; } @Override @@ -74,10 +108,15 @@ class ObjcVariablesExtension implements VariablesExtension { addFrameworkVariables(builder); addArchVariables(builder); addModuleMapVariables(builder); - if (compilationArtifacts.getArchive().isPresent()) { + if (activeVariableCategories.contains(VariableCategory.ARCHIVE_VARIABLES)) { addArchiveVariables(builder); } - addFullyLinkArchiveVariables(builder); + if (activeVariableCategories.contains(VariableCategory.FULLY_LINK_VARIABLES)) { + addFullyLinkArchiveVariables(builder); + } + if (activeVariableCategories.contains(VariableCategory.EXECUTABLE_LINKING_VARIABLES)) { + addExecutableLinkVariables(builder); + } } private void addPchVariables(CcToolchainFeatures.Variables.Builder builder) { @@ -138,4 +177,144 @@ class ObjcVariablesExtension implements VariablesExtension { IMPORTED_LIBRARY_EXEC_PATHS_VARIABLE_NAME, ImmutableList.copyOf(Artifact.toExecPaths(objcProvider.get(IMPORTED_LIBRARY)))); } + + private void addExecutableLinkVariables(CcToolchainFeatures.Variables.Builder builder) { + builder.addSequenceVariable(FRAMEWORK_NAMES_VARIABLE_NAME, frameworkNames); + builder.addSequenceVariable( + WEAK_FRAMEWORK_NAMES_VARIABLE_NAME, + SdkFramework.names(objcProvider.get(ObjcProvider.WEAK_SDK_FRAMEWORK))); + builder.addSequenceVariable(LIBRARY_NAMES_VARIABLE_NAME, libraryNames); + builder.addVariable( + FILELIST_VARIABLE_NAME, intermediateArtifacts.linkerObjList().getExecPathString()); + builder.addVariable( + LINKED_BINARY_VARIABLE_NAME, + ruleContext.getFragment(ObjcConfiguration.class).shouldStripBinary() + ? intermediateArtifacts.unstrippedSingleArchitectureBinary().getExecPathString() + : intermediateArtifacts.strippedSingleArchitectureBinary().getExecPathString()); + + builder.addSequenceVariable( + FORCE_LOAD_EXEC_PATHS_VARIABLE_NAME, + Artifact.toExecPaths(forceLoadArtifacts)); + builder.addSequenceVariable(DEP_LINKOPTS_VARIABLE_NAME, objcProvider.get(LINKOPT)); + builder.addSequenceVariable(ATTR_LINKOPTS_VARIABLE_NAME, attributeLinkopts); + } + + /** A Builder for {@link ObjcVariablesExtension}. */ + static class Builder { + private RuleContext ruleContext; + private ObjcProvider objcProvider; + private CompilationArtifacts compilationArtifacts; + private Artifact fullyLinkArchive; + private IntermediateArtifacts intermediateArtifacts; + private BuildConfiguration buildConfiguration; + private Set<String> frameworkNames; + private ImmutableSet<Artifact> forceLoadArtifacts; + private ImmutableList<String> libraryNames; + private NestedSet<String> attributeLinkopts; + + private final ImmutableSet.Builder<VariableCategory> activeVariableCategoriesBuilder = + ImmutableSet.builder(); + + /** Sets the {@link RuleContext} for this extension. */ + public Builder setRuleContext(RuleContext ruleContext) { + this.ruleContext = Preconditions.checkNotNull(ruleContext); + return this; + } + + /** Sets the {@link ObjcProvider} for this extension. */ + public Builder setObjcProvider(ObjcProvider objcProvider) { + this.objcProvider = Preconditions.checkNotNull(objcProvider); + return this; + } + + /** Sets the {@link CompilationArtifacts} for this extension. */ + public Builder setCompilationArtifacts(CompilationArtifacts compilationArtifacts) { + this.compilationArtifacts = Preconditions.checkNotNull(compilationArtifacts); + return this; + } + + /** Sets the output of the fully link action. */ + public Builder setFullyLinkArchive(Artifact fullyLinkArchive) { + this.fullyLinkArchive = Preconditions.checkNotNull(fullyLinkArchive); + return this; + } + + /** Sets the {@link IntermediateArtifacts} for this extension. */ + public Builder setIntermediateArtifacts(IntermediateArtifacts intermediateArtifacts) { + this.intermediateArtifacts = Preconditions.checkNotNull(intermediateArtifacts); + return this; + } + + /** Sets the configuration for this extension. */ + public Builder setConfiguration(BuildConfiguration buildConfiguration) { + this.buildConfiguration = Preconditions.checkNotNull(buildConfiguration); + return this; + } + + /** Sets the framework names to be passed to the linker using {@code -framework}. */ + public Builder setFrameworkNames(Set<String> frameworkNames) { + this.frameworkNames = Preconditions.checkNotNull(frameworkNames); + return this; + } + + /** Sets binary input files to be passed to the linker with "-l" flags. */ + public Builder setLibraryNames(ImmutableList<String> libraryNames) { + this.libraryNames = Preconditions.checkNotNull(libraryNames); + return this; + } + + /** Sets artifacts to be passed to the linker with {@code -force_load}. */ + public Builder setForceLoadArtifacts(ImmutableSet<Artifact> forceLoadArtifacts) { + this.forceLoadArtifacts = Preconditions.checkNotNull(forceLoadArtifacts); + return this; + } + + /** Sets linkopts arising from rule attributes. */ + public Builder setAttributeLinkopts(NestedSet<String> attributeLinkopts) { + this.attributeLinkopts = Preconditions.checkNotNull(attributeLinkopts); + return this; + } + + /** Sets the given {@link VariableCategory} as active for this extension. */ + public Builder addVariableCategory(VariableCategory variableCategory) { + this.activeVariableCategoriesBuilder.add(Preconditions.checkNotNull(variableCategory)); + return this; + } + + public ObjcVariablesExtension build() { + + ImmutableSet<VariableCategory> activeVariableCategories = + activeVariableCategoriesBuilder.build(); + + Preconditions.checkNotNull(ruleContext, "missing RuleContext"); + Preconditions.checkNotNull(objcProvider, "missing ObjcProvider"); + Preconditions.checkNotNull(buildConfiguration, "missing BuildConfiguration"); + Preconditions.checkNotNull(intermediateArtifacts, "missing IntermediateArtifacts"); + if (activeVariableCategories.contains(VariableCategory.ARCHIVE_VARIABLES)) { + Preconditions.checkNotNull(compilationArtifacts, "missing CompilationArtifacts"); + } + if (activeVariableCategories.contains(VariableCategory.FULLY_LINK_VARIABLES)) { + Preconditions.checkNotNull(fullyLinkArchive, "missing fully-link archive"); + } + if (activeVariableCategories.contains(VariableCategory.EXECUTABLE_LINKING_VARIABLES)) { + Preconditions.checkNotNull(frameworkNames, "missing framework names"); + Preconditions.checkNotNull(libraryNames, "missing library names"); + Preconditions.checkNotNull(forceLoadArtifacts, "missing force-load artifacts"); + Preconditions.checkNotNull(attributeLinkopts, "missing attribute linkopts"); + } + + return new ObjcVariablesExtension( + ruleContext, + objcProvider, + compilationArtifacts, + fullyLinkArchive, + intermediateArtifacts, + buildConfiguration, + frameworkNames, + libraryNames, + forceLoadArtifacts, + attributeLinkopts, + activeVariableCategories); + } + } } |