diff options
author | 2015-11-06 17:49:58 +0000 | |
---|---|---|
committer | 2015-11-06 22:53:20 +0000 | |
commit | 0c4e3bf1bfb77198a1ac03715fabb253844a4f8d (patch) | |
tree | 6be2f10fd3c4dc7895aa15a76d61dfd3c2ef7e1f /src | |
parent | f1ed27d220281a066ecdea0334b079dc72a41e36 (diff) |
bazel: support linking accumulated libraries into C++ binaries
This CL permits a cc_binary to have a set of dependencies that are all
gathered together when the cc_binary is linked, producing a set of
LibraryToLink objects to link into the cc_binary. Each such
dependency will an instance of a class that extends BuildLibraryToLink
to a CcLinkParams. All instances of the same class will be gathered
together. At link time the BuildLibraryToLink method buildLibraries
will be called to build the LibraryToLink objects.
--
MOS_MIGRATED_REVID=107242331
Diffstat (limited to 'src')
4 files changed, 216 insertions, 5 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 index 1657c1debc..189d7e58e4 100644 --- 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 @@ -34,8 +34,8 @@ 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>The parameters concerned are the link options (strings) passed to the linker, linkstamps, a + * list of libraries to be linked in, and a list of libraries to build at link time. * * <p>Items in the collections are stored in nested sets. Link options and libraries are stored in * link order (preorder) and linkstamps are sorted. @@ -44,13 +44,16 @@ public final class CcLinkParams { private final NestedSet<ImmutableList<String>> linkOpts; private final NestedSet<Linkstamp> linkstamps; private final NestedSet<LibraryToLink> libraries; + private final ExtraLinkTimeLibraries extraLinkTimeLibraries; private CcLinkParams(NestedSet<ImmutableList<String>> linkOpts, NestedSet<Linkstamp> linkstamps, - NestedSet<LibraryToLink> libraries) { + NestedSet<LibraryToLink> libraries, + ExtraLinkTimeLibraries extraLinkTimeLibraries) { this.linkOpts = linkOpts; this.linkstamps = linkstamps; this.libraries = libraries; + this.extraLinkTimeLibraries = extraLinkTimeLibraries; } /** @@ -78,6 +81,13 @@ public final class CcLinkParams { return libraries; } + /** + * The extra link time libraries; will be null if there are no such libraries. + */ + public ExtraLinkTimeLibraries getExtraLinkTimeLibraries() { + return extraLinkTimeLibraries; + } + public static final Builder builder(boolean linkingStatically, boolean linkShared) { return new Builder(linkingStatically, linkShared); } @@ -112,6 +122,13 @@ public final class CcLinkParams { private final NestedSetBuilder<LibraryToLink> librariesBuilder = NestedSetBuilder.linkOrder(); + /** + * A builder for the list of link time libraries. Most builds + * won't have any such libraries, so save space by leaving the + * default as null. + */ + private ExtraLinkTimeLibraries.Builder extraLinkTimeLibrariesBuilder = null; + private boolean built = false; private Builder(boolean linkingStatically, boolean linkShared) { @@ -130,8 +147,12 @@ public final class CcLinkParams { if (!localLinkopts.isEmpty()) { linkOptsBuilder.add(localLinkopts); } + ExtraLinkTimeLibraries extraLinkTimeLibraries = null; + if (extraLinkTimeLibrariesBuilder != null) { + extraLinkTimeLibraries = extraLinkTimeLibrariesBuilder.build(); + } return new CcLinkParams(linkOptsBuilder.build(), linkstampsBuilder.build(), - librariesBuilder.build()); + librariesBuilder.build(), extraLinkTimeLibraries); } private boolean add(CcLinkParamsStore store) { @@ -217,6 +238,12 @@ public final class CcLinkParams { linkOptsBuilder.addTransitive(args.getLinkopts()); linkstampsBuilder.addTransitive(args.getLinkstamps()); librariesBuilder.addTransitive(args.getLibraries()); + if (args.getExtraLinkTimeLibraries() != null) { + if (extraLinkTimeLibrariesBuilder == null) { + extraLinkTimeLibrariesBuilder = ExtraLinkTimeLibraries.builder(); + } + extraLinkTimeLibrariesBuilder.addTransitive(args.getExtraLinkTimeLibraries()); + } return this; } @@ -257,6 +284,18 @@ public final class CcLinkParams { } /** + * Adds an extra link time library, a library that is actually + * built at link time. + */ + public Builder addExtraLinkTimeLibrary(ExtraLinkTimeLibrary e) { + if (extraLinkTimeLibrariesBuilder == null) { + extraLinkTimeLibrariesBuilder = ExtraLinkTimeLibraries.builder(); + } + extraLinkTimeLibrariesBuilder.add(e); + return this; + } + + /** * Processes typical dependencies a C/C++ library. * * <p>A helper method that processes getValues() and merges contents of @@ -332,5 +371,6 @@ public final class 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)); + NestedSetBuilder.<LibraryToLink>emptySet(Order.LINK_ORDER), + null); } 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 ccfb2e1ad5..49a5a02cee 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 @@ -1159,6 +1159,12 @@ public final class CppLinkAction extends AbstractAction { public Builder addLinkParams(CcLinkParams linkParams, RuleErrorConsumer errorListener) { addLinkopts(linkParams.flattenedLinkopts()); addLibraries(linkParams.getLibraries()); + ExtraLinkTimeLibraries extraLinkTimeLibraries = linkParams.getExtraLinkTimeLibraries(); + if (extraLinkTimeLibraries != null) { + for (ExtraLinkTimeLibrary extraLibrary : extraLinkTimeLibraries.getExtraLibraries()) { + addLibraries(extraLibrary.buildLibraries(ruleContext)); + } + } addLinkstamps(CppHelper.resolveLinkstamps(errorListener, linkParams)); return this; } diff --git a/src/main/java/com/google/devtools/build/lib/rules/cpp/ExtraLinkTimeLibraries.java b/src/main/java/com/google/devtools/build/lib/rules/cpp/ExtraLinkTimeLibraries.java new file mode 100644 index 0000000000..d596ce0156 --- /dev/null +++ b/src/main/java/com/google/devtools/build/lib/rules/cpp/ExtraLinkTimeLibraries.java @@ -0,0 +1,102 @@ +// Copyright 2015 The Bazel Authors. 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.collect.Lists; + +import java.util.Collection; +import java.util.LinkedHashMap; +import java.util.List; +import java.util.Map; + +/** + * A list of extra libraries to include in a link. These are non-C++ + * libraries that are built from inputs gathered from all the dependencies. + * The dependencies have no way to coordinate, so each one will add an + * ExtraLinkTimeLibrary to its CcLinkParams. ExtraLinkTimeLibrary is an + * interface, and all ExtraLinkTimeLibrary objects of the same class will + * be gathered together. + */ +public final class ExtraLinkTimeLibraries { + /** + * We can have multiple different kinds of lists of libraries to include + * at link time. We map from the class type to an actual instance. + */ + private final Collection<ExtraLinkTimeLibrary> extraLibraries; + + private ExtraLinkTimeLibraries(Collection<ExtraLinkTimeLibrary> extraLibraries) { + this.extraLibraries = extraLibraries; + } + + /** + * Return the set of extra libraries. + */ + public Collection<ExtraLinkTimeLibrary> getExtraLibraries() { + return extraLibraries; + } + + public static final Builder builder() { + return new Builder(); + } + + /** + * Builder for {@link ExtraLinkTimeLibraries}. + */ + public static final class Builder { + private Map<Class<? extends ExtraLinkTimeLibrary>, ExtraLinkTimeLibrary.Builder> libraries = + new LinkedHashMap<>(); + + private Builder() { + // Nothing to do. + } + + /** + * Build a {@link ExtraLinkTimeLibraries} object. + */ + public ExtraLinkTimeLibraries build() { + List<ExtraLinkTimeLibrary> extraLibraries = Lists.newArrayList(); + for (ExtraLinkTimeLibrary.Builder builder : libraries.values()) { + extraLibraries.add(builder.build()); + } + return new ExtraLinkTimeLibraries(extraLibraries); + } + + /** + * Add a transitive dependency. + */ + public final Builder addTransitive(ExtraLinkTimeLibraries dep) { + for (ExtraLinkTimeLibrary depLibrary : dep.getExtraLibraries()) { + Class<? extends ExtraLinkTimeLibrary> c = depLibrary.getClass(); + if (!libraries.containsKey(c)) { + libraries.put(c, depLibrary.getBuilder()); + } + libraries.get(c).addTransitive(depLibrary); + } + return this; + } + + /** + * Add a single library to build. + */ + public final Builder add(ExtraLinkTimeLibrary b) { + Class<? extends ExtraLinkTimeLibrary> c = b.getClass(); + if (!libraries.containsKey(c)) { + libraries.put(c, b.getBuilder()); + } + libraries.get(c).addTransitive(b); + return this; + } + } +} diff --git a/src/main/java/com/google/devtools/build/lib/rules/cpp/ExtraLinkTimeLibrary.java b/src/main/java/com/google/devtools/build/lib/rules/cpp/ExtraLinkTimeLibrary.java new file mode 100644 index 0000000000..52b2a0822a --- /dev/null +++ b/src/main/java/com/google/devtools/build/lib/rules/cpp/ExtraLinkTimeLibrary.java @@ -0,0 +1,63 @@ +// Copyright 2015 The Bazel Authors. 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.devtools.build.lib.analysis.RuleContext; +import com.google.devtools.build.lib.collect.nestedset.NestedSet; +import com.google.devtools.build.lib.rules.cpp.LinkerInputs.LibraryToLink; + +/** + * An extra library to include in a link. The actual library is built + * at link time. + * + * <p>This can be used for non-C++ inputs to a C++ link. A class that + * implements this interface will support transitively gathering all + * inputs from link dependencies, and then combine them all together + * into a set of C++ libraries. + * + * <p>Any implementations must be immutable (and therefore thread-safe), + * because this is passed between rules and accessed in a multi-threaded + * context. + */ +public interface ExtraLinkTimeLibrary { + /** + * Build the LibraryToLink inputs to pass to the C++ linker. + */ + NestedSet<LibraryToLink> buildLibraries(RuleContext context); + + /** + * Get a new Builder for this ExtraLinkTimeLibrary class. This acts + * like a static method, in that the result does not depend on the + * current state of the object, and the new Builder starts out + * empty. + */ + Builder getBuilder(); + + /** + * The Builder interface builds an ExtraLinkTimeLibrary. + */ + public interface Builder { + /** + * Add the inputs associated with another instance of the same + * underlying ExtraLinkTimeLibrary type. + */ + void addTransitive(ExtraLinkTimeLibrary dep); + + /** + * Build the ExtraLinkTimeLibrary based on the inputs. + */ + ExtraLinkTimeLibrary build(); + } +} |