aboutsummaryrefslogtreecommitdiffhomepage
path: root/src/main/java/com/google/devtools/build/lib/rules/cpp/CcLinkParams.java
diff options
context:
space:
mode:
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.java357
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));
+}