// 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 static com.google.common.truth.Truth.assertThat; import com.google.common.base.Predicate; import com.google.common.collect.Iterables; import com.google.devtools.build.lib.actions.Artifact; import com.google.devtools.build.lib.analysis.ConfiguredTarget; import com.google.devtools.build.lib.analysis.FileProvider; import com.google.devtools.build.lib.analysis.util.BuildViewTestCase; import java.util.List; import org.junit.Test; import org.junit.runner.RunWith; import org.junit.runners.JUnit4; /** * Test for shared library linking {@link CppLinkAction}. */ @RunWith(JUnit4.class) public final class LibraryLinkingTest extends BuildViewTestCase { private List<String> getLinkOpts(CppLinkAction linkAction, String... optionPatterns) throws Exception { // Strip the first parameters from the argv, which are the dynamic library script // (usually tools/cpp/link_dynamic_library.sh), and its arguments. return linkAction.getRawLinkArgv().subList(6, optionPatterns.length + 6); } private void assertLinkopts(CppLinkAction linkAction, String... optionPatterns) throws Exception { List<String> linkopts = getLinkOpts(linkAction, optionPatterns); for (int i = 0; i < optionPatterns.length; i++) { assertThat(linkopts.get(i)).matches(optionPatterns[i]); } } @Test public void testGeneratedLib() throws Exception { useConfiguration("--cpu=k8"); ConfiguredTarget genlib = scratchConfiguredTarget( "genrule", "thebinary.so", "genrule(name = 'genlib',", " outs = ['genlib.a'],", " cmd = '')", "cc_library(name = 'thelib',", " srcs = [':genlib'],", " linkstatic = 1)", "cc_binary(name = 'thebinary.so',", " deps = [':thelib'],", " linkstatic = 1,", " linkshared = 1)"); Artifact executable = getExecutable(genlib); CppLinkAction linkAction = (CppLinkAction) getGeneratingAction(executable); assertLinkopts( linkAction, "-shared", "-o", analysisMock.getProductName() + "-out/.+/genrule/thebinary.so", "-Wl,-whole-archive", analysisMock.getProductName() + "-out/.+/genrule/genlib.a", "-Wl,-no-whole-archive"); } /** * Tests that the shared library version of a cc_library includes linkopts settings * in its link command line, but the archive library version doesn't. */ @Test public void testCcLibraryLinkopts() throws Exception { scratch.overwriteFile( "custom_malloc/BUILD", "cc_library(name = 'custom_malloc',", " srcs = ['custom_malloc.cc'],", " linkopts = ['-Lmalloc_dir -lmalloc_opt']);"); ConfiguredTarget ccLib = getConfiguredTarget("//custom_malloc:custom_malloc"); final String linkOpt1 = "-Lmalloc_dir"; final String linkOpt2 = "-lmalloc_opt"; // Archive library version: Artifact archiveLib = Iterables.getOnlyElement( Iterables.filter( ccLib.getProvider(FileProvider.class).getFilesToBuild(), new Predicate<Artifact>() { @Override public boolean apply(Artifact artifact) { return artifact.getFilename().equals("libcustom_malloc.a"); } })); CppLinkAction archiveLink = (CppLinkAction) getGeneratingAction(archiveLib); List<String> args = archiveLink.getArgv(); assertThat(args).doesNotContain(linkOpt1); assertThat(args).doesNotContain(linkOpt2); // Shared library version: Artifact soLib = Iterables.getOnlyElement( ccLib .getProvider(CcExecutionDynamicLibrariesProvider.class) .getExecutionDynamicLibraryArtifacts()); // This artifact is generated by a SolibSymlinkAction, so we need to go back two levels. CppLinkAction solibLink = (CppLinkAction) getGeneratingAction(getGeneratingAction(soLib).getPrimaryInput()); args = solibLink.getArgv(); assertThat(args).contains(linkOpt1); assertThat(args).contains(linkOpt2); } }