// 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.nativedeps; import com.google.common.base.Preconditions; import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableMap; import com.google.devtools.build.lib.actions.Artifact; import com.google.devtools.build.lib.actions.Root; import com.google.devtools.build.lib.analysis.RuleContext; import com.google.devtools.build.lib.analysis.actions.SymlinkAction; 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.cpp.ArtifactCategory; import com.google.devtools.build.lib.rules.cpp.CcCommon; import com.google.devtools.build.lib.rules.cpp.CcLinkParams; import com.google.devtools.build.lib.rules.cpp.CcToolchainFeatures.FeatureConfiguration; import com.google.devtools.build.lib.rules.cpp.CcToolchainProvider; import com.google.devtools.build.lib.rules.cpp.CppBuildInfo; import com.google.devtools.build.lib.rules.cpp.CppConfiguration; import com.google.devtools.build.lib.rules.cpp.CppHelper; import com.google.devtools.build.lib.rules.cpp.CppLinkAction; import com.google.devtools.build.lib.rules.cpp.CppLinkActionBuilder; import com.google.devtools.build.lib.rules.cpp.CppRuleClasses; import com.google.devtools.build.lib.rules.cpp.CppSemantics; import com.google.devtools.build.lib.rules.cpp.FdoSupportProvider; import com.google.devtools.build.lib.rules.cpp.Link; 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.LinkerInputs; import com.google.devtools.build.lib.rules.cpp.LinkerInputs.LibraryToLink; import com.google.devtools.build.lib.util.Fingerprint; import com.google.devtools.build.lib.vfs.PathFragment; import java.util.ArrayList; import java.util.Collection; import java.util.LinkedList; import java.util.List; import java.util.Map; /** * Helper class to create a dynamic library for rules which support integration with native code. * *
This library gets created by the build system by linking all C++ libraries in the transitive * closure of the dependencies into a standalone dynamic library, with some exceptions. It usually * does not include neverlink libraries or C++ binaries (or their transitive dependencies). Note * that some rules are implicitly neverlink. */ public abstract class NativeDepsHelper { /** * An implementation of {@link * com.google.devtools.build.lib.rules.cpp.CppLinkAction.LinkArtifactFactory} that can create * artifacts anywhere. * *
Necessary because the actions of nativedeps libraries should be shareable, and thus cannot * be under the package directory. */ private static final CppLinkAction.LinkArtifactFactory SHAREABLE_LINK_ARTIFACT_FACTORY = new CppLinkAction.LinkArtifactFactory() { @Override public Artifact create(RuleContext ruleContext, BuildConfiguration configuration, PathFragment rootRelativePath) { return ruleContext.getShareableArtifact(rootRelativePath, configuration.getBinDirectory(ruleContext.getRule().getRepository())); } }; private NativeDepsHelper() {} private static final String ANDROID_UNIQUE_DIR = "nativedeps"; /** * Creates an Action to create a dynamic library for Android by linking all native code (C/C++) * libraries in the transitive dependency closure of a rule. * *
We link the native deps in the equivalent of linkstatic=1, linkshared=1 mode. * *
linkstatic=1 means mostly-static mode, i.e. we select the ".a" (or ".pic.a") files, but we * don't include "-static" in linkopts. * *
linkshared=1 means we prefer the ".pic.a" files to the ".a" files, and the LinkTargetType is * set to DYNAMIC_LIBRARY which causes Link.java to include "-shared" in the linker options. * *
It is possible that this function may have no work to do if there are no native libraries in
* the transitive closure, or if the only native libraries in the transitive closure are already
* shared libraries. In this case, this function returns {@code null}.
*
* @param ruleContext the rule context to determine the native deps library
* @param linkParams the {@link CcLinkParams} for the rule, collected with linkstatic = 1 and
* linkshared = 1
* @param cppSemantics to use for linkstamp compiles
* @return the native deps library, or null if there was no code which needed to be linked in the
* transitive closure.
*/
public static Artifact linkAndroidNativeDepsIfPresent(
final RuleContext ruleContext,
CcLinkParams linkParams,
final BuildConfiguration configuration,
CcToolchainProvider toolchain,
CppSemantics cppSemantics)
throws InterruptedException {
if (!containsCodeToLink(linkParams.getLibraries())) {
return null;
}
PathFragment labelName = PathFragment.create(ruleContext.getLabel().getName());
String libraryIdentifier = ruleContext.getUniqueDirectory(ANDROID_UNIQUE_DIR)
.getRelative(labelName.replaceName("lib" + labelName.getBaseName()))
.getPathString();
Artifact nativeDeps = ruleContext.getUniqueDirectoryArtifact(ANDROID_UNIQUE_DIR,
labelName.replaceName("lib" + labelName.getBaseName() + ".so"),
configuration.getBinDirectory(ruleContext.getRule().getRepository()));
return createNativeDepsAction(
ruleContext,
linkParams,
/* extraLinkOpts= */ ImmutableList.of(),
configuration,
toolchain,
nativeDeps,
libraryIdentifier,
configuration.getBinDirectory(ruleContext.getRule().getRepository()),
/* useDynamicRuntime= */ false,
cppSemantics)
.getLibrary();
}
/** Determines if there is any code to be linked in the input iterable. */
private static boolean containsCodeToLink(Iterable TODO(bazel-team): (2010) Currently process of identifying parameters that can
* affect native library name is manual and should be kept in sync with the
* code in the CppLinkAction.Builder/CppLinkAction/Link classes which are
* responsible for generating linker command line. Ideally we should reuse
* generated command line for both purposes - selecting a name of the
* native library and using it as link action payload. For now, correctness
* of the method below is only ensured by validations in the
* CppLinkAction.Builder.build() method.
*/
private static PathFragment getSharedNativeDepsPath(Iterable