diff options
Diffstat (limited to 'src/main/java/com/google/devtools/build/lib/rules/cpp/CcLinkParams.java')
-rw-r--r-- | src/main/java/com/google/devtools/build/lib/rules/cpp/CcLinkParams.java | 357 |
1 files changed, 357 insertions, 0 deletions
diff --git a/src/main/java/com/google/devtools/build/lib/rules/cpp/CcLinkParams.java b/src/main/java/com/google/devtools/build/lib/rules/cpp/CcLinkParams.java new file mode 100644 index 0000000000..4e4804b177 --- /dev/null +++ b/src/main/java/com/google/devtools/build/lib/rules/cpp/CcLinkParams.java @@ -0,0 +1,357 @@ +// Copyright 2014 Google Inc. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package com.google.devtools.build.lib.rules.cpp; + +import com.google.common.base.Function; +import com.google.common.base.Preconditions; +import com.google.common.collect.ImmutableList; +import com.google.common.collect.Iterables; +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.TransitiveInfoCollection; +import com.google.devtools.build.lib.collect.nestedset.NestedSet; +import com.google.devtools.build.lib.collect.nestedset.NestedSetBuilder; +import com.google.devtools.build.lib.collect.nestedset.Order; +import com.google.devtools.build.lib.rules.cpp.LinkerInputs.LibraryToLink; + +import java.util.Collection; +import java.util.Objects; + +/** + * Parameters to be passed to the linker. + * + * <p>The parameters concerned are the link options (strings) passed to the linker, linkstamps and a + * list of libraries to be linked in. + * + * <p>Items in the collections are stored in nested sets. Link options and libraries are stored in + * link order (preorder) and linkstamps are sorted. + */ +public final class CcLinkParams { + private final NestedSet<ImmutableList<String>> linkOpts; + private final NestedSet<Linkstamp> linkstamps; + private final NestedSet<LibraryToLink> libraries; + + private CcLinkParams(NestedSet<ImmutableList<String>> linkOpts, + NestedSet<Linkstamp> linkstamps, + NestedSet<LibraryToLink> libraries) { + this.linkOpts = linkOpts; + this.linkstamps = linkstamps; + this.libraries = libraries; + } + + /** + * @return the linkopts + */ + public NestedSet<ImmutableList<String>> getLinkopts() { + return linkOpts; + } + + public ImmutableList<String> flattenedLinkopts() { + return ImmutableList.copyOf(Iterables.concat(linkOpts)); + } + + /** + * @return the linkstamps + */ + public NestedSet<Linkstamp> getLinkstamps() { + return linkstamps; + } + + /** + * @return the libraries + */ + public NestedSet<LibraryToLink> getLibraries() { + return libraries; + } + + public static final Builder builder(boolean linkingStatically, boolean linkShared) { + return new Builder(linkingStatically, linkShared); + } + + /** + * Builder for {@link CcLinkParams}. + * + * + */ + public static final class Builder { + + /** + * linkingStatically is true when we're linking this target in either FULLY STATIC mode + * (linkopts=["-static"]) or MOSTLY STATIC mode (linkstatic=1). When this is true, we want to + * use static versions of any libraries that this target depends on (except possibly system + * libraries, which are not handled by CcLinkParams). When this is false, we want to use dynamic + * versions of any libraries that this target depends on. + */ + private final boolean linkingStatically; + + /** + * linkShared is true when we're linking with "-shared" (linkshared=1). + */ + private final boolean linkShared; + + private ImmutableList.Builder<String> localLinkoptsBuilder = ImmutableList.builder(); + + private final NestedSetBuilder<ImmutableList<String>> linkOptsBuilder = + NestedSetBuilder.linkOrder(); + private final NestedSetBuilder<Linkstamp> linkstampsBuilder = + NestedSetBuilder.compileOrder(); + private final NestedSetBuilder<LibraryToLink> librariesBuilder = + NestedSetBuilder.linkOrder(); + + private boolean built = false; + + private Builder(boolean linkingStatically, boolean linkShared) { + this.linkingStatically = linkingStatically; + this.linkShared = linkShared; + } + + /** + * Build a {@link CcLinkParams} object. + */ + public CcLinkParams build() { + Preconditions.checkState(!built); + // Not thread-safe, but builders should not be shared across threads. + built = true; + ImmutableList<String> localLinkopts = localLinkoptsBuilder.build(); + if (!localLinkopts.isEmpty()) { + linkOptsBuilder.add(localLinkopts); + } + return new CcLinkParams(linkOptsBuilder.build(), linkstampsBuilder.build(), + librariesBuilder.build()); + } + + private boolean add(CcLinkParamsStore store) { + if (store != null) { + CcLinkParams args = store.get(linkingStatically, linkShared); + addTransitiveArgs(args); + } + return store != null; + } + + /** + * Includes link parameters from a collection of dependency targets. + */ + public Builder addTransitiveTargets(Iterable<? extends TransitiveInfoCollection> targets) { + for (TransitiveInfoCollection target : targets) { + addTransitiveTarget(target); + } + return this; + } + + /** + * Includes link parameters from a dependency target. + * + * <p>The target should implement {@link CcLinkParamsProvider}. If it does not, + * the method does not do anything. + */ + public Builder addTransitiveTarget(TransitiveInfoCollection target) { + return addTransitiveProvider(target.getProvider(CcLinkParamsProvider.class)); + } + + /** + * Includes link parameters from a dependency target. The target is checked for the given + * mappings in the order specified, and the first mapping that returns a non-null result is + * added. + */ + @SafeVarargs + public final Builder addTransitiveTarget(TransitiveInfoCollection target, + Function<TransitiveInfoCollection, CcLinkParamsStore> firstMapping, + @SuppressWarnings("unchecked") // Java arrays don't preserve generic arguments. + Function<TransitiveInfoCollection, CcLinkParamsStore>... remainingMappings) { + if (add(firstMapping.apply(target))) { + return this; + } + for (Function<TransitiveInfoCollection, CcLinkParamsStore> mapping : remainingMappings) { + if (add(mapping.apply(target))) { + return this; + } + } + return this; + } + + /** + * Includes link parameters from a CcLinkParamsProvider provider. + */ + public Builder addTransitiveProvider(CcLinkParamsProvider provider) { + if (provider == null) { + return this; + } + + CcLinkParams args = provider.getCcLinkParams(linkingStatically, linkShared); + addTransitiveArgs(args); + return this; + } + + /** + * Includes link parameters from the given targets. Each target is checked for the given + * mappings in the order specified, and the first mapping that returns a non-null result is + * added. + */ + @SafeVarargs + public final Builder addTransitiveTargets( + Iterable<? extends TransitiveInfoCollection> targets, + Function<TransitiveInfoCollection, CcLinkParamsStore> firstMapping, + @SuppressWarnings("unchecked") // Java arrays don't preserve generic arguments. + Function<TransitiveInfoCollection, CcLinkParamsStore>... remainingMappings) { + for (TransitiveInfoCollection target : targets) { + addTransitiveTarget(target, firstMapping, remainingMappings); + } + return this; + } + + /** + * Includes link parameters from the given targets. Each target is checked for the given + * mappings in the order specified, and the first mapping that returns a non-null result is + * added. + * + * @deprecated don't add any new uses; all existing uses need to be audited and possibly merged + * into a single call - some of them may introduce semantic changes which need to be + * carefully vetted + */ + @Deprecated + @SafeVarargs + public final Builder addTransitiveLangTargets( + Iterable<? extends TransitiveInfoCollection> targets, + Function<TransitiveInfoCollection, CcLinkParamsStore> firstMapping, + @SuppressWarnings("unchecked") // Java arrays don't preserve generic arguments. + Function<TransitiveInfoCollection, CcLinkParamsStore>... remainingMappings) { + return addTransitiveTargets(targets, firstMapping, remainingMappings); + } + + /** + * Merges the other {@link CcLinkParams} object into this one. + */ + public Builder addTransitiveArgs(CcLinkParams args) { + linkOptsBuilder.addTransitive(args.getLinkopts()); + linkstampsBuilder.addTransitive(args.getLinkstamps()); + librariesBuilder.addTransitive(args.getLibraries()); + return this; + } + + /** + * Adds a collection of link options. + */ + public Builder addLinkOpts(Collection<String> linkOpts) { + localLinkoptsBuilder.addAll(linkOpts); + return this; + } + + /** + * Adds a collection of linkstamps. + */ + public Builder addLinkstamps(Iterable<Artifact> linkstamps, CppCompilationContext context) { + ImmutableList<Artifact> declaredIncludeSrcs = + ImmutableList.copyOf(context.getDeclaredIncludeSrcs()); + for (Artifact linkstamp : linkstamps) { + linkstampsBuilder.add(new Linkstamp(linkstamp, declaredIncludeSrcs)); + } + return this; + } + + /** + * Adds a library artifact. + */ + public Builder addLibrary(LibraryToLink library) { + librariesBuilder.add(library); + return this; + } + + /** + * Adds a collection of library artifacts. + */ + public Builder addLibraries(Iterable<LibraryToLink> libraries) { + librariesBuilder.addAll(libraries); + return this; + } + + /** + * Processes typical dependencies a C/C++ library. + * + * <p>A helper method that processes getValues() and merges contents of + * getPreferredLibraries() and getLinkOpts() into the current link params + * object. + */ + public Builder addCcLibrary(RuleContext context, CcCommon common, boolean neverlink, + CcLinkingOutputs linkingOutputs) { + addTransitiveTargets( + context.getPrerequisites("deps", Mode.TARGET), + CcLinkParamsProvider.TO_LINK_PARAMS, CcSpecificLinkParamsProvider.TO_LINK_PARAMS); + + if (!neverlink) { + addLibraries(linkingOutputs.getPreferredLibraries(linkingStatically, + linkShared || context.getFragment(CppConfiguration.class).forcePic())); + addLinkOpts(common.getLinkopts()); + } + return this; + } + } + + /** + * A linkstamp that also knows about its declared includes. + * + * <p>This object is required because linkstamp files may include other headers which + * will have to be provided during compilation. + */ + public static final class Linkstamp { + private final Artifact artifact; + private final ImmutableList<Artifact> declaredIncludeSrcs; + + private Linkstamp(Artifact artifact, ImmutableList<Artifact> declaredIncludeSrcs) { + this.artifact = Preconditions.checkNotNull(artifact); + this.declaredIncludeSrcs = Preconditions.checkNotNull(declaredIncludeSrcs); + } + + /** + * Returns the linkstamp artifact. + */ + public Artifact getArtifact() { + return artifact; + } + + /** + * Returns the declared includes. + */ + public ImmutableList<Artifact> getDeclaredIncludeSrcs() { + return declaredIncludeSrcs; + } + + @Override + public int hashCode() { + return Objects.hash(artifact, declaredIncludeSrcs); + } + + @Override + public boolean equals(Object obj) { + if (this == obj) { + return true; + } + if (!(obj instanceof Linkstamp)) { + return false; + } + Linkstamp other = (Linkstamp) obj; + return artifact.equals(other.artifact) + && declaredIncludeSrcs.equals(other.declaredIncludeSrcs); + } + } + + /** + * Empty CcLinkParams. + */ + public static final CcLinkParams EMPTY = new CcLinkParams( + NestedSetBuilder.<ImmutableList<String>>emptySet(Order.LINK_ORDER), + NestedSetBuilder.<Linkstamp>emptySet(Order.COMPILE_ORDER), + NestedSetBuilder.<LibraryToLink>emptySet(Order.LINK_ORDER)); +} |