com.google.devtools.build.lib.rules.cpp.CcLinkParams.java Source code

Java tutorial

Introduction

Here is the source code for com.google.devtools.build.lib.rules.cpp.CcLinkParams.java

Source

// Copyright 2014 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.base.Function;
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 com.google.devtools.build.lib.util.Preconditions;

import java.util.Collection;
import java.util.List;
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, 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.
 */
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, ExtraLinkTimeLibraries extraLinkTimeLibraries) {
        this.linkOpts = linkOpts;
        this.linkstamps = linkstamps;
        this.libraries = libraries;
        this.extraLinkTimeLibraries = extraLinkTimeLibraries;
    }

    /**
     * @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;
    }

    /**
     * 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);
    }

    /**
     * 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();

        /**
         * 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) {
            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);
            }
            ExtraLinkTimeLibraries extraLinkTimeLibraries = null;
            if (extraLinkTimeLibrariesBuilder != null) {
                extraLinkTimeLibraries = extraLinkTimeLibrariesBuilder.build();
            }
            return new CcLinkParams(linkOptsBuilder.build(), linkstampsBuilder.build(), librariesBuilder.build(),
                    extraLinkTimeLibraries);
        }

        public 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) {
                add(provider.getCcLinkParamsStore());
            }
            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;
        }

        /**
         * 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());
            if (args.getExtraLinkTimeLibraries() != null) {
                if (extraLinkTimeLibrariesBuilder == null) {
                    extraLinkTimeLibrariesBuilder = ExtraLinkTimeLibraries.builder();
                }
                extraLinkTimeLibrariesBuilder.addTransitive(args.getExtraLinkTimeLibraries());
            }
            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(NestedSet<Artifact> linkstamps, CppCompilationContext context) {
            for (Artifact linkstamp : linkstamps) {
                linkstampsBuilder.add(new Linkstamp(linkstamp, context.getDeclaredIncludeSrcs()));
            }
            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;
        }

        /**
         * 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
         * getPreferredLibraries() and getLinkOpts() into the current link params
         * object.
         */
        public Builder addCcLibrary(RuleContext context, boolean neverlink, List<String> linkopts,
                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(linkopts);
            }
            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 NestedSet<Artifact> declaredIncludeSrcs;

        private Linkstamp(Artifact artifact, NestedSet<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 NestedSet<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), null);
}