| // Copyright 2017 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.objc; |
| |
| import static com.google.common.collect.ImmutableList.toImmutableList; |
| import static com.google.common.collect.MoreCollectors.onlyElement; |
| import static com.google.common.truth.Truth.assertThat; |
| import static com.google.common.truth.Truth.assertWithMessage; |
| import static com.google.devtools.build.lib.actions.util.ActionsTestUtil.baseArtifactNames; |
| import static com.google.devtools.build.lib.rules.objc.CompilationSupport.ABSOLUTE_INCLUDES_PATH_FORMAT; |
| import static com.google.devtools.build.lib.rules.objc.CompilationSupport.BOTH_MODULE_NAME_AND_MODULE_MAP_SPECIFIED; |
| import static org.junit.Assert.assertThrows; |
| |
| import com.google.common.base.Joiner; |
| import com.google.common.base.Optional; |
| import com.google.common.collect.ImmutableList; |
| import com.google.common.collect.Iterables; |
| import com.google.devtools.build.lib.actions.ActionAnalysisMetadata; |
| import com.google.devtools.build.lib.actions.ActionExecutionException; |
| import com.google.devtools.build.lib.actions.Artifact; |
| import com.google.devtools.build.lib.actions.CommandAction; |
| import com.google.devtools.build.lib.actions.ExecutionRequirements; |
| import com.google.devtools.build.lib.actions.util.ActionsTestUtil; |
| import com.google.devtools.build.lib.analysis.ConfiguredTarget; |
| import com.google.devtools.build.lib.analysis.FilesToRunProvider; |
| import com.google.devtools.build.lib.analysis.OutputGroupInfo; |
| import com.google.devtools.build.lib.analysis.RunfilesProvider; |
| import com.google.devtools.build.lib.analysis.config.CompilationMode; |
| import com.google.devtools.build.lib.analysis.configuredtargets.RuleConfiguredTarget; |
| import com.google.devtools.build.lib.analysis.test.InstrumentedFilesInfo; |
| import com.google.devtools.build.lib.analysis.util.AnalysisMock; |
| import com.google.devtools.build.lib.analysis.util.ScratchAttributeWriter; |
| import com.google.devtools.build.lib.cmdline.Label; |
| import com.google.devtools.build.lib.cmdline.LabelSyntaxException; |
| import com.google.devtools.build.lib.collect.nestedset.NestedSet; |
| import com.google.devtools.build.lib.packages.NoSuchTargetException; |
| import com.google.devtools.build.lib.packages.Provider; |
| import com.google.devtools.build.lib.packages.StarlarkProvider; |
| import com.google.devtools.build.lib.packages.StructImpl; |
| import com.google.devtools.build.lib.packages.util.MockObjcSupport; |
| import com.google.devtools.build.lib.rules.cpp.CcCompilationContext; |
| import com.google.devtools.build.lib.rules.cpp.CcInfo; |
| import com.google.devtools.build.lib.rules.cpp.CcLinkingContext; |
| import com.google.devtools.build.lib.rules.cpp.CcLinkingContext.LinkerInput; |
| import com.google.devtools.build.lib.rules.cpp.CcToolchainProvider; |
| import com.google.devtools.build.lib.rules.cpp.CppCompileAction; |
| import com.google.devtools.build.lib.rules.cpp.CppLinkAction; |
| import com.google.devtools.build.lib.rules.cpp.CppRuleClasses; |
| import com.google.devtools.build.lib.rules.cpp.LibraryToLink; |
| import com.google.devtools.build.lib.vfs.FileSystemUtils; |
| import com.google.devtools.common.options.OptionsParsingException; |
| import java.util.Collection; |
| import java.util.List; |
| import org.junit.Test; |
| import org.junit.runner.RunWith; |
| import org.junit.runners.JUnit4; |
| |
| /** Test case for objc_library. */ |
| @RunWith(JUnit4.class) |
| public class ObjcLibraryTest extends ObjcRuleTestCase { |
| |
| private static final RuleType RULE_TYPE = new OnlyNeedsSourcesRuleType("objc_library"); |
| private static final String WRAPPED_CLANG = "wrapped_clang"; |
| |
| @Test |
| public void testConfigTransitionWithTopLevelAppleConfiguration() throws Exception { |
| scratch.file( |
| "bin/BUILD", |
| """ |
| objc_library( |
| name = "objc", |
| srcs = ["objc.m"], |
| ) |
| |
| cc_binary( |
| name = "cc", |
| srcs = ["cc.cc"], |
| deps = [":objc"], |
| ) |
| """); |
| |
| useConfiguration( |
| "--apple_platform_type=ios", |
| "--cpu=ios_x86_64", |
| "--platforms=" + MockObjcSupport.IOS_X86_64); |
| |
| ConfiguredTarget cc = getConfiguredTarget("//bin:cc"); |
| Artifact objcObject = |
| ActionsTestUtil.getFirstArtifactEndingWith( |
| actionsTestUtil().artifactClosureOf(getFilesToBuild(cc)), "objc.o"); |
| assertThat(objcObject.getExecPathString()).contains("ios_x86_64"); |
| } |
| |
| @Test |
| public void testNoTransition() throws Exception { |
| scratch.file( |
| "bin/BUILD", |
| """ |
| objc_library( |
| name = "objc", |
| srcs = ["objc.m"], |
| ) |
| |
| cc_binary( |
| name = "cc", |
| srcs = ["cc.cc"], |
| deps = [":objc"], |
| ) |
| """); |
| |
| setBuildLanguageOptions("--incompatible_disable_objc_library_transition"); |
| useConfiguration("--macos_cpus=arm64,x86_64"); |
| |
| ConfiguredTarget cc = getConfiguredTarget("//bin:cc"); |
| Artifact objcObject = |
| ActionsTestUtil.getFirstArtifactEndingWith( |
| actionsTestUtil().artifactClosureOf(getFilesToBuild(cc)), "objc.o"); |
| assertThat(objcObject.getExecPathString()).contains("k8-fastbuild"); |
| } |
| |
| @Test |
| public void testFilesToBuild() throws Exception { |
| ConfiguredTarget target = |
| createLibraryTargetWriter("//objc:One") |
| .setAndCreateFiles("srcs", "a.m", "b.m", "private.h") |
| .write(); |
| |
| NestedSet<Artifact> files = getFilesToBuild(target); |
| assertThat(Artifact.toRootRelativePaths(files)).containsExactly("objc/libOne.a"); |
| } |
| |
| @Test |
| public void testCompilesSources() throws Exception { |
| createLibraryTargetWriter("//objc/lib1") |
| .setAndCreateFiles("srcs", "a.m") |
| .setAndCreateFiles("hdrs", "hdr.h") |
| .write(); |
| |
| createLibraryTargetWriter("//objc/lib2") |
| .setAndCreateFiles("srcs", "b.m") |
| .setAndCreateFiles("hdrs", "private.h") |
| .write(); |
| |
| createLibraryTargetWriter("//objc/lib3") |
| .setAndCreateFiles("srcs", "a.m") |
| .setAndCreateFiles("hdrs", "hdr.h") |
| .setList("deps", "//objc/lib1") |
| .setList("implementation_deps", "//objc/lib2") |
| .write(); |
| |
| createLibraryTargetWriter("//objc:x") |
| .setAndCreateFiles("srcs", "a.m", "private.h") |
| .setAndCreateFiles("hdrs", "hdr.h") |
| .setList("deps", "//objc/lib3:lib3") |
| .write(); |
| |
| CppCompileAction compileA = (CppCompileAction) compileAction("//objc:x", "a.o"); |
| |
| assertThat(Artifact.toRootRelativePaths(compileA.getPossibleInputsForTesting())) |
| .containsAtLeast("objc/a.m", "objc/hdr.h", "objc/private.h"); |
| assertThat(Artifact.toRootRelativePaths(compileA.getOutputs())) |
| .containsExactly("objc/_objs/x/arc/a.o", "objc/_objs/x/arc/a.d"); |
| } |
| |
| @Test |
| public void testSerializedDiagnosticsFileFeature() throws Exception { |
| useConfiguration("--features=serialized_diagnostics_file"); |
| |
| createLibraryTargetWriter("//objc/lib1") |
| .setAndCreateFiles("srcs", "a.m") |
| .setAndCreateFiles("hdrs", "hdr.h") |
| .write(); |
| |
| createLibraryTargetWriter("//objc/lib2") |
| .setAndCreateFiles("srcs", "a.m") |
| .setAndCreateFiles("hdrs", "hdr.h") |
| .setList("deps", "//objc/lib1") |
| .write(); |
| |
| createLibraryTargetWriter("//objc:x") |
| .setAndCreateFiles("srcs", "a.m", "private.h") |
| .setAndCreateFiles("hdrs", "hdr.h") |
| .setList("deps", "//objc/lib2:lib2") |
| .write(); |
| |
| CppCompileAction compileA = (CppCompileAction) compileAction("//objc:x", "a.o"); |
| |
| assertThat(Artifact.toRootRelativePaths(compileA.getOutputs())) |
| .containsExactly("objc/_objs/x/arc/a.o", "objc/_objs/x/arc/a.d", "objc/_objs/x/arc/a.dia"); |
| } |
| |
| @Test |
| public void testCompilesSourcesWithSameBaseName() throws Exception { |
| createLibraryTargetWriter("//foo:lib") |
| .setAndCreateFiles("srcs", "a.m", "pkg1/a.m", "b.m") |
| .setAndCreateFiles("non_arc_srcs", "pkg2/a.m") |
| .write(); |
| |
| getConfiguredTarget("//foo:lib"); |
| |
| Artifact a0 = getBinArtifact("_objs/lib/arc/0/a.o", getConfiguredTarget("//foo:lib")); |
| Artifact a1 = getBinArtifact("_objs/lib/arc/1/a.o", getConfiguredTarget("//foo:lib")); |
| Artifact a2 = getBinArtifact("_objs/lib/non_arc/a.o", getConfiguredTarget("//foo:lib")); |
| Artifact b = getBinArtifact("_objs/lib/arc/b.o", getConfiguredTarget("//foo:lib")); |
| |
| assertThat(getGeneratingAction(a0)).isNotNull(); |
| assertThat(getGeneratingAction(a1)).isNotNull(); |
| assertThat(getGeneratingAction(a2)).isNotNull(); |
| assertThat(getGeneratingAction(b)).isNotNull(); |
| |
| assertThat(getGeneratingAction(a0).getInputs().toList()).contains(getSourceArtifact("foo/a.m")); |
| assertThat(getGeneratingAction(a1).getInputs().toList()) |
| .contains(getSourceArtifact("foo/pkg1/a.m")); |
| assertThat(getGeneratingAction(a2).getInputs().toList()) |
| .contains(getSourceArtifact("foo/pkg2/a.m")); |
| assertThat(getGeneratingAction(b).getInputs().toList()).contains(getSourceArtifact("foo/b.m")); |
| } |
| |
| @Test |
| public void testObjcPlusPlusCompile() throws Exception { |
| useConfiguration( |
| "--apple_platform_type=ios", |
| "--cpu=ios_i386", |
| "--platforms=" + MockObjcSupport.IOS_I386); |
| createLibraryTargetWriter("//objc:lib").setList("srcs", "a.mm").write(); |
| CommandAction compileAction = compileAction("//objc:lib", "a.o"); |
| assertThat(compileAction.getArguments()).containsAtLeast("-stdlib=libc++", "-std=gnu++11"); |
| } |
| |
| @Test |
| public void testObjcPlusPlusCompileDarwin() throws Exception { |
| useConfiguration( |
| "--cpu=darwin_x86_64", |
| // TODO(b/36126423): Darwin should imply macos, so the |
| // following line should not be necessary. |
| "--apple_platform_type=macos", |
| "--platforms=" + MockObjcSupport.DARWIN_X86_64); |
| createLibraryTargetWriter("//objc:lib").setList("srcs", "a.mm").write(); |
| CommandAction compileAction = compileAction("//objc:lib", "a.o"); |
| assertThat(compileAction.getArguments()).containsAtLeast("-stdlib=libc++", "-std=gnu++11"); |
| } |
| |
| @Test |
| public void testObjcSourceContainsObjccopt() throws Exception { |
| useConfiguration("--objccopt=--xyzzy"); |
| scratch.file("objc/a.m"); |
| scratch.file("objc/BUILD", RULE_TYPE.target(scratch, "objc", "lib", "srcs", "['a.m']")); |
| |
| CommandAction compileActionA = compileAction("//objc:lib", "a.o"); |
| assertThat(compileActionA.getArguments()).contains("--xyzzy"); |
| } |
| |
| @Test |
| public void testObjcppSourceContainsObjccopt() throws Exception { |
| useConfiguration("--objccopt=--xyzzy"); |
| scratch.file("objc/a.mm"); |
| scratch.file("objc/BUILD", RULE_TYPE.target(scratch, "objc", "lib", "srcs", "['a.mm']")); |
| |
| CommandAction compileActionA = compileAction("//objc:lib", "a.o"); |
| assertThat(compileActionA.getArguments()).contains("--xyzzy"); |
| } |
| |
| @Test |
| public void testCSourceDoesNotContainObjccopt() throws Exception { |
| useConfiguration("--objccopt=--xyzzy"); |
| scratch.file("objc/a.c"); |
| scratch.file("objc/BUILD", RULE_TYPE.target(scratch, "objc", "lib", "srcs", "['a.c']")); |
| |
| CommandAction compileActionA = compileAction("//objc:lib", "a.o"); |
| assertThat(compileActionA.getArguments()).doesNotContain("--xyzzy"); |
| } |
| |
| @Test |
| public void testCppSourceDoesNotContainObjccopt() throws Exception { |
| useConfiguration("--objccopt=--xyzzy"); |
| scratch.file("objc/a.cc"); |
| scratch.file("objc/BUILD", RULE_TYPE.target(scratch, "objc", "lib", "srcs", "['a.cc']")); |
| |
| CommandAction compileActionA = compileAction("//objc:lib", "a.o"); |
| assertThat(compileActionA.getArguments()).doesNotContain("--xyzzy"); |
| } |
| |
| @Test |
| public void testCppHeaderDoesNotContainsObjccopt() throws Exception { |
| MockObjcSupport.setupCcToolchainConfig( |
| mockToolsConfig, MockObjcSupport.darwinX86_64().withFeatures(CppRuleClasses.PARSE_HEADERS)); |
| useConfiguration( |
| "--features=parse_headers", "--process_headers_in_dependencies", "--objccopt=--xyzzy"); |
| |
| ConfiguredTarget x = |
| scratchConfiguredTarget("foo", "x", "cc_library(name = 'x', hdrs = ['x.h'])"); |
| |
| assertThat(getGeneratingCompileAction("_objs/x/x.h.processed", x).getArguments()) |
| .doesNotContain("--xyzzy"); |
| } |
| |
| @Test |
| public void testObjcHeaderContainsObjccopt() throws Exception { |
| MockObjcSupport.setupCcToolchainConfig( |
| mockToolsConfig, MockObjcSupport.darwinX86_64().withFeatures(CppRuleClasses.PARSE_HEADERS)); |
| useConfiguration( |
| "--features=parse_headers", "--process_headers_in_dependencies", "--objccopt=--xyzzy"); |
| |
| ConfiguredTarget x = |
| scratchConfiguredTarget("foo", "x", "objc_library(name = 'x', hdrs = ['x.h'])"); |
| |
| assertThat(getGeneratingCompileAction("_objs/x/arc/x.h.processed", x).getArguments()) |
| .contains("--xyzzy"); |
| } |
| |
| @Test |
| public void testCompilationModeDbg() throws Exception { |
| useConfiguration("--cpu=ios_i386", "--compilation_mode=dbg"); |
| scratch.file("objc/a.m"); |
| scratch.file("objc/BUILD", RULE_TYPE.target(scratch, "objc", "lib", "srcs", "['a.m']")); |
| |
| CommandAction compileActionA = compileAction("//objc:lib", "a.o"); |
| |
| assertThat(compileActionA.getArguments()).contains("--DBG_ONLY_FLAG"); |
| assertThat(compileActionA.getArguments()).doesNotContain("--FASTBUILD_ONLY_FLAG"); |
| assertThat(compileActionA.getArguments()).doesNotContain("--OPT_ONLY_FLAG"); |
| } |
| |
| @Test |
| public void testCompilationModeFastbuild() throws Exception { |
| useConfiguration("--cpu=ios_i386", "--compilation_mode=fastbuild"); |
| scratch.file("objc/a.m"); |
| scratch.file("objc/BUILD", RULE_TYPE.target(scratch, "objc", "lib", "srcs", "['a.m']")); |
| |
| CommandAction compileActionA = compileAction("//objc:lib", "a.o"); |
| |
| assertThat(compileActionA.getArguments()).doesNotContain("--DBG_ONLY_FLAG"); |
| assertThat(compileActionA.getArguments()).contains("--FASTBUILD_ONLY_FLAG"); |
| assertThat(compileActionA.getArguments()).doesNotContain("--OPT_ONLY_FLAG"); |
| } |
| |
| @Test |
| public void testCompilationModeOpt() throws Exception { |
| useConfiguration("--cpu=ios_i386", "--compilation_mode=opt"); |
| scratch.file("objc/a.m"); |
| scratch.file("objc/BUILD", RULE_TYPE.target(scratch, "objc", "lib", "srcs", "['a.m']")); |
| |
| CommandAction compileActionA = compileAction("//objc:lib", "a.o"); |
| |
| assertThat(compileActionA.getArguments()).doesNotContain("--DBG_ONLY_FLAG"); |
| assertThat(compileActionA.getArguments()).doesNotContain("--FASTBUILD_ONLY_FLAG"); |
| assertThat(compileActionA.getArguments()).contains("--OPT_ONLY_FLAG"); |
| } |
| |
| @Test |
| public void testCreate_runfilesWithSourcesOnly() throws Exception { |
| ConfiguredTarget target = |
| createLibraryTargetWriter("//objc:One") |
| .setAndCreateFiles("srcs", "a.m", "b.m", "private.h") |
| .write(); |
| RunfilesProvider provider = target.getProvider(RunfilesProvider.class); |
| assertThat(baseArtifactNames(provider.getDefaultRunfiles().getArtifacts())).isEmpty(); |
| assertThat(Artifact.toRootRelativePaths(provider.getDataRunfiles().getArtifacts())) |
| .containsExactly("objc/libOne.a"); |
| } |
| |
| @Test |
| public void testCreate_noErrorForEmptySourcesButHasDependency() throws Exception { |
| createLibraryTargetWriter("//baselib:baselib") |
| .setAndCreateFiles("srcs", "a.m", "b.m", "private.h") |
| .write(); |
| createLibraryTargetWriter("//lib:lib") |
| .setAndCreateFiles("hdrs", "a.h") |
| .setList("deps", "//baselib:baselib") |
| .write(); |
| |
| CcLinkingContext ccLinkingContext = |
| getConfiguredTarget("//lib:lib").get(CcInfo.PROVIDER).getCcLinkingContext(); |
| assertThat(ccLinkingContext.getStaticModeParamsForDynamicLibraryLibraries()) |
| .containsExactlyElementsIn(archiveAction("//baselib:baselib").getOutputs()); |
| } |
| |
| @Test |
| public void testCreate_errorForEmptyFilegroupSources() throws Exception { |
| checkError( |
| "x", |
| "x", |
| "does not produce any objc_library srcs files", |
| "filegroup(name = 'fg', srcs = [])", |
| "objc_library(name = 'x', srcs = ['fg'])"); |
| } |
| |
| @Test |
| public void testCreate_srcsContainingHeaders() throws Exception { |
| scratch.file("x/a.m", "dummy source file"); |
| scratch.file("x/a.h", "dummy header file"); |
| scratch.file("x/BUILD", "objc_library(name = 'Target', srcs = ['a.m', 'a.h'])"); |
| assertThat(view.hasErrors(getConfiguredTarget("//x:Target"))).isFalse(); |
| } |
| |
| @Test |
| public void testCreate_headerAndCompiledSourceWithSameName() throws Exception { |
| scratch.file("objc/BUILD", "objc_library(name = 'Target', srcs = ['a.m'], hdrs = ['a.h'])"); |
| assertThat(view.hasErrors(getConfiguredTarget("//objc:Target"))).isFalse(); |
| } |
| |
| @Test |
| public void testCreate_errorForCcInNonArcSources() throws Exception { |
| scratch.file("x/cc.cc"); |
| checkError( |
| "x", |
| "x", |
| "non_arc_srcs attribute of objc_library rule @@//x:x: source file '@@//x:cc.cc' is" |
| + " misplaced here", |
| "objc_library(name = 'x', non_arc_srcs = ['cc.cc'])"); |
| } |
| |
| @Test |
| public void testFileInSrcsAndNonArcSources() throws Exception { |
| checkError( |
| "x", |
| "x", |
| String.format(CompilationSupport.FILE_IN_SRCS_AND_NON_ARC_SRCS_ERROR_FORMAT, "x/foo.m"), |
| "objc_library(name = 'x', srcs = ['foo.m'], non_arc_srcs = ['foo.m'])"); |
| } |
| |
| @Test |
| public void testCreate_headerContainingDotMAndDotCFiles() throws Exception { |
| scratch.file("x/a.m", "dummy source file"); |
| scratch.file("x/a.h", "dummy header file"); |
| scratch.file("x/b.m", "dummy source file"); |
| scratch.file("x/a.c", "dummy source file"); |
| scratch.file( |
| "x/BUILD", "objc_library(name = 'Target', srcs = ['a.m'], hdrs = ['a.h', 'b.m', 'a.c'])"); |
| assertThat(view.hasErrors(getConfiguredTarget("//x:Target"))).isFalse(); |
| } |
| |
| @Test |
| public void testProvidesObjcHeadersWithDotMFiles() throws Exception { |
| ConfiguredTarget target = |
| createLibraryTargetWriter("//objc:lib") |
| .setAndCreateFiles("srcs", "a.m", "b.m", "private.h") |
| .setAndCreateFiles("hdrs", "a.h", "b.h", "f.m") |
| .write(); |
| ConfiguredTarget depender = |
| createLibraryTargetWriter("//objc2:lib") |
| .setAndCreateFiles("srcs", "a.m", "b.m", "private.h") |
| .setAndCreateFiles("hdrs", "d.h", "e.m") |
| .setList("deps", "//objc:lib") |
| .write(); |
| assertThat(getArifactPathsOfHeaders(target)) |
| .containsExactly("objc/a.h", "objc/b.h", "objc/f.m", "objc/private.h"); |
| assertThat(getArifactPathsOfHeaders(depender)) |
| .containsExactly( |
| "objc/a.h", |
| "objc/b.h", |
| "objc/f.m", |
| "objc/private.h", |
| "objc2/d.h", |
| "objc2/e.m", |
| "objc2/private.h"); |
| } |
| |
| @Test |
| public void testMultiPlatformLibrary() throws Exception { |
| useConfiguration("--ios_multi_cpus=i386,x86_64,armv7,arm64", "--cpu=ios_armv7"); |
| |
| createLibraryTargetWriter("//objc:lib") |
| .setAndCreateFiles("srcs", "a.m", "b.m", "private.h") |
| .setAndCreateFiles("hdrs", "a.h") |
| .write(); |
| |
| assertThat(view.hasErrors(getConfiguredTarget("//objc:lib"))).isFalse(); |
| } |
| |
| @Test |
| public void testCompilationActions_simulator() throws Exception { |
| useConfiguration( |
| "--apple_platform_type=ios", "--cpu=ios_i386", "--platforms=" + MockObjcSupport.IOS_I386); |
| |
| scratch.file("objc/a.m"); |
| scratch.file("objc/non_arc.m"); |
| scratch.file("objc/private.h"); |
| scratch.file("objc/c.h"); |
| scratch.file( |
| "objc/BUILD", |
| RULE_TYPE.target( |
| scratch, |
| "objc", |
| "lib", |
| "srcs", |
| "['a.m', 'private.h']", |
| "hdrs", |
| "['c.h']", |
| "non_arc_srcs", |
| "['non_arc.m']")); |
| |
| CommandAction compileActionA = compileAction("//objc:lib", "a.o"); |
| CommandAction compileActionNonArc = compileAction("//objc:lib", "non_arc.o"); |
| |
| assertRequiresDarwin(compileActionA); |
| assertThat(compileActionA.getArguments()) |
| .contains("tools/osx/crosstool/iossim/" + WRAPPED_CLANG); |
| assertThat(compileActionA.getArguments()) |
| .containsAtLeast("-isysroot", AppleToolchain.sdkDir()) |
| .inOrder(); |
| assertThat(compileActionA.getArguments()) |
| .containsAtLeastElementsIn(CompilationSupport.DEFAULT_COMPILER_FLAGS); |
| assertThat(compileActionA.getArguments()) |
| .containsAtLeastElementsIn(CompilationSupport.SIMULATOR_COMPILE_FLAGS); |
| assertThat(compileActionA.getArguments()).contains("-fobjc-arc"); |
| assertThat(compileActionA.getArguments()).containsAtLeast("-c", "objc/a.m"); |
| assertThat(compileActionNonArc.getArguments()).contains("-fno-objc-arc"); |
| assertThat(compileActionA.getArguments()).containsAtLeastElementsIn(FASTBUILD_COPTS); |
| assertThat(compileActionA.getArguments()).contains("-arch i386"); |
| } |
| |
| @Test |
| public void testCompilationActions_device() throws Exception { |
| useConfiguration( |
| "--apple_platform_type=ios", "--cpu=ios_armv7", "--platforms=" + MockObjcSupport.IOS_ARMV7); |
| |
| scratch.file("objc/a.m"); |
| scratch.file("objc/non_arc.m"); |
| scratch.file("objc/private.h"); |
| scratch.file("objc/c.h"); |
| scratch.file( |
| "objc/BUILD", |
| RULE_TYPE.target( |
| scratch, |
| "objc", |
| "lib", |
| "srcs", |
| "['a.m', 'private.h']", |
| "hdrs", |
| "['c.h']", |
| "non_arc_srcs", |
| "['non_arc.m']")); |
| |
| CommandAction compileActionA = compileAction("//objc:lib", "a.o"); |
| CommandAction compileActionNonArc = compileAction("//objc:lib", "non_arc.o"); |
| |
| assertRequiresDarwin(compileActionA); |
| assertThat(compileActionA.getArguments()).contains("tools/osx/crosstool/ios/" + WRAPPED_CLANG); |
| assertThat(compileActionA.getArguments()) |
| .containsAtLeast("-isysroot", AppleToolchain.sdkDir()) |
| .inOrder(); |
| assertThat(compileActionA.getArguments()) |
| .containsAtLeastElementsIn(CompilationSupport.DEFAULT_COMPILER_FLAGS); |
| assertThat(compileActionA.getArguments()) |
| .containsNoneIn(CompilationSupport.SIMULATOR_COMPILE_FLAGS); |
| |
| assertThat(compileActionA.getArguments()).contains("-fobjc-arc"); |
| assertThat(compileActionA.getArguments()).containsAtLeast("-c", "objc/a.m"); |
| |
| assertThat(compileActionNonArc.getArguments()).contains("-fno-objc-arc"); |
| assertThat(compileActionA.getArguments()).containsAtLeastElementsIn(FASTBUILD_COPTS); |
| assertThat(compileActionA.getArguments()).contains("-arch armv7"); |
| } |
| |
| @Test |
| public void testArchivesPrecompiledObjectFiles() throws Exception { |
| scratch.file("objc/a.m"); |
| scratch.file("objc/b.o"); |
| scratch.file("objc/BUILD", RULE_TYPE.target(scratch, "objc", "x", "srcs", "['a.m', 'b.o']")); |
| assertThat(Artifact.toRootRelativePaths(archiveAction("//objc:x").getInputs())) |
| .contains("objc/b.o"); |
| } |
| |
| @Test |
| public void testCompileWithFrameworkImportsIncludesFlags() throws Exception { |
| addAppleBinaryStarlarkRule(scratch); |
| addBinWithTransitiveDepOnFrameworkImport(); |
| CommandAction compileAction = compileAction("//lib:lib", "a.o"); |
| |
| assertThat(compileAction.getArguments()).doesNotContain("-framework"); |
| assertThat(Joiner.on("").join(compileAction.getArguments())).contains("-Ffx"); |
| } |
| |
| @Test |
| public void testPrecompiledHeaders() throws Exception { |
| scratch.file("objc/a.m"); |
| scratch.file("objc/c.pch"); |
| scratch.file( |
| "objc/BUILD", |
| RULE_TYPE.target( |
| scratch, "objc", "x", "srcs", "['a.m']", "non_arc_srcs", "['b.m']", "pch", "'c.pch'")); |
| CppCompileAction compileAction = (CppCompileAction) compileAction("//objc:x", "a.o"); |
| assertThat(Joiner.on(" ").join(compileAction.getArguments())).contains("-include objc/c.pch"); |
| assertThat(Artifact.toRootRelativePaths(compileAction.getPossibleInputsForTesting())) |
| .contains("objc/c.pch"); |
| } |
| |
| @Test |
| public void testCompilationActionsWithCopts() throws Exception { |
| useConfiguration( |
| "--apple_platform_type=ios", "--cpu=ios_i386", "--platforms=" + MockObjcSupport.IOS_I386); |
| |
| scratch.file( |
| "objc/defs.bzl", |
| """ |
| def _var_providing_rule_impl(ctx): |
| return [ |
| platform_common.TemplateVariableInfo({ |
| "FOO": "$(BAR)", |
| "BAR": ctx.attr.var_value, |
| "BAZ": "$(FOO)", |
| }), |
| ] |
| |
| var_providing_rule = rule( |
| implementation = _var_providing_rule_impl, |
| attrs = {"var_value": attr.string()}, |
| ) |
| """); |
| |
| scratch.file( |
| "objc/BUILD", |
| """ |
| load("//objc:defs.bzl", "var_providing_rule") |
| |
| var_providing_rule( |
| name = "set_foo_to_bar", |
| var_value = "bar", |
| ) |
| |
| objc_library( |
| name = "lib", |
| srcs = [ |
| "a.m", |
| "b.m", |
| "private.h", |
| ], |
| hdrs = ["c.h"], |
| copts = [ |
| "-Ifoo", |
| "--monkeys=$(TARGET_CPU)", |
| "--gorillas=$(FOO),$(BAR),$(BAZ)", |
| ], |
| toolchains = [":set_foo_to_bar"], |
| ) |
| """); |
| |
| CommandAction compileActionA = compileAction("//objc:lib", "a.o"); |
| assertThat(compileActionA.getArguments()) |
| .containsAtLeast("-Ifoo", "--monkeys=ios_i386", "--gorillas=bar,bar,bar"); |
| } |
| |
| @Test |
| public void testObjcCopts() throws Exception { |
| useConfiguration("--objccopt=-foo"); |
| createLibraryTargetWriter("//lib:lib") |
| .setAndCreateFiles("srcs", "a.m", "b.m", "private.h") |
| .write(); |
| List<String> args = compileAction("//lib:lib", "a.o").getArguments(); |
| assertThat(args).contains("-foo"); |
| } |
| |
| @Test |
| public void testObjcCopts_argumentOrdering() throws Exception { |
| useConfiguration("--objccopt=-foo"); |
| createLibraryTargetWriter("//lib:lib") |
| .setAndCreateFiles("srcs", "a.m", "b.m", "private.h") |
| .setList("copts", "-bar") |
| .write(); |
| List<String> args = compileAction("//lib:lib", "a.o").getArguments(); |
| assertThat(args).containsAtLeast("-fobjc-arc", "-foo", "-bar").inOrder(); |
| } |
| |
| @Test |
| public void testBothModuleNameAndModuleMapGivesError() throws Exception { |
| checkError( |
| "x", |
| "x", |
| BOTH_MODULE_NAME_AND_MODULE_MAP_SPECIFIED, |
| "objc_library( name = 'x', module_name = 'x', module_map = 'x.modulemap' )"); |
| } |
| |
| @Test |
| public void testCompilationActionsWithCoptFmodules() throws Exception { |
| createLibraryTargetWriter("//objc:lib") |
| .setAndCreateFiles("srcs", "a.m", "b.m", "private.h") |
| .setAndCreateFiles("hdrs", "c.h") |
| .setList("copts", "-fmodules") |
| .write(); |
| CommandAction compileActionA = compileAction("//objc:lib", "a.o"); |
| assertThat(removeConfigFragment(compileActionA.getArguments())) |
| .containsAtLeast( |
| "-fmodules", |
| "-fmodules-cache-path=" |
| + OUTPUTDIR |
| + "/" |
| + CompilationSupport.OBJC_MODULE_CACHE_DIR_NAME); |
| } |
| |
| @Test |
| public void testArchiveAction_simulator() throws Exception { |
| useConfiguration( |
| "--apple_platform_type=ios", "--cpu=ios_i386", "--platforms=" + MockObjcSupport.IOS_I386); |
| createLibraryTargetWriter("//objc:lib") |
| .setAndCreateFiles("srcs", "a.m", "b.m", "private.h") |
| .setAndCreateFiles("hdrs", "c.h") |
| .write(); |
| |
| CommandAction archiveAction = archiveAction("//objc:lib"); |
| assertThat(archiveAction.getArguments()) |
| .isEqualTo( |
| ImmutableList.of( |
| "tools/osx/crosstool/iossim/ar_wrapper", |
| "rcs", |
| Iterables.getOnlyElement(archiveAction.getOutputs()).getExecPathString(), |
| getBinArtifact("_objs/lib/arc/a.o", getConfiguredTarget("//objc:lib")) |
| .getExecPathString(), |
| getBinArtifact("_objs/lib/arc/b.o", getConfiguredTarget("//objc:lib")) |
| .getExecPathString())); |
| assertThat(baseArtifactNames(archiveAction.getInputs())) |
| .containsAtLeast("a.o", "b.o", "ar", "libempty.a", "libtool"); |
| assertThat(baseArtifactNames(archiveAction.getOutputs())).containsExactly("liblib.a"); |
| assertRequiresDarwin(archiveAction); |
| } |
| |
| @Test |
| public void testArchiveAction_device() throws Exception { |
| useConfiguration( |
| "--apple_platform_type=ios", "--cpu=ios_armv7", "--platforms=" + MockObjcSupport.IOS_ARMV7); |
| createLibraryTargetWriter("//objc:lib") |
| .setAndCreateFiles("srcs", "a.m", "b.m", "private.h") |
| .setAndCreateFiles("hdrs", "c.h") |
| .write(); |
| CommandAction archiveAction = archiveAction("//objc:lib"); |
| |
| assertThat(archiveAction.getArguments()) |
| .isEqualTo( |
| ImmutableList.of( |
| "tools/osx/crosstool/ios/ar_wrapper", |
| "rcs", |
| Iterables.getOnlyElement(archiveAction.getOutputs()).getExecPathString(), |
| getBinArtifact("_objs/lib/arc/a.o", getConfiguredTarget("//objc:lib")) |
| .getExecPathString(), |
| getBinArtifact("_objs/lib/arc/b.o", getConfiguredTarget("//objc:lib")) |
| .getExecPathString())); |
| assertThat(baseArtifactNames(archiveAction.getInputs())).containsAtLeast("a.o", "b.o"); |
| assertThat(baseArtifactNames(archiveAction.getOutputs())).containsExactly("liblib.a"); |
| assertRequiresDarwin(archiveAction); |
| } |
| |
| @Test |
| public void testIncludesDirsGetPassedToCompileAction() throws Exception { |
| createLibraryTargetWriter("//lib:lib") |
| .setAndCreateFiles("srcs", "a.m", "b.m", "private.h") |
| .setList("includes", "../third_party/foo", "opensource/bar") |
| .write(); |
| CommandAction compileAction = compileAction("//lib:lib", "a.o"); |
| |
| for (String path : rootedIncludePaths("third_party/foo", "lib/opensource/bar")) { |
| assertThat(Joiner.on("").join(removeConfigFragment(compileAction.getArguments()))) |
| .contains("-I" + path); |
| } |
| } |
| |
| @Test |
| public void testIncludesDirs_inExternalRepo_resolvesSiblingLayout() throws Exception { |
| FileSystemUtils.appendIsoLatin1( |
| scratch.resolve("WORKSPACE"), |
| "local_repository(name = 'lib_external', path = 'lib_external')"); |
| invalidatePackages(); |
| |
| scratch.file("lib_external/WORKSPACE"); |
| scratch.file( |
| "lib_external/BUILD", |
| """ |
| objc_library( |
| name = "lib", |
| srcs = [ |
| "a.m", |
| "bar/b.h", |
| ], |
| includes = ["bar"], |
| ) |
| """); |
| scratch.file("lib_external/a.m"); |
| scratch.file("lib_external/bar/b.h"); |
| |
| setBuildLanguageOptions("--experimental_sibling_repository_layout"); |
| |
| CommandAction compileAction = compileAction("@lib_external//:lib", "a.o"); |
| String actionArgs = Joiner.on("").join(removeConfigFragment(compileAction.getArguments())); |
| |
| assertThat(actionArgs).contains("-I../lib_external/bar"); |
| } |
| |
| @Test |
| public void testPropagatesDefinesToDependersTransitively() throws Exception { |
| useConfiguration( |
| "--apple_platform_type=ios", |
| "--cpu=ios_x86_64", |
| "--platforms=" + MockObjcSupport.IOS_X86_64); |
| createLibraryTargetWriter("//lib1:lib1") |
| .setAndCreateFiles("srcs", "a.m") |
| .setAndCreateFiles("non_arc_srcs", "b.m") |
| .setList("defines", "A=foo", "B", "MONKEYS=$(TARGET_CPU)") |
| .write(); |
| createLibraryTargetWriter("//lib2:lib2") |
| .setAndCreateFiles("srcs", "a.m") |
| .setAndCreateFiles("non_arc_srcs", "b.m") |
| .setList("deps", "//lib1:lib1") |
| .setList("defines", "C=bar", "D") |
| .write(); |
| addAppleBinaryStarlarkRule(scratch); |
| scratch.file( |
| "bin/BUILD", |
| """ |
| load("//test_starlark:apple_binary_starlark.bzl", "apple_binary_starlark") |
| |
| apple_binary_starlark( |
| name = "bin", |
| platform_type = "ios", |
| deps = ["//lib2"], |
| ) |
| """); |
| |
| assertThat(compileAction("//lib1:lib1", "a.o").getArguments()) |
| .containsAtLeast("-DA=foo", "-DB", "-DMONKEYS=ios_x86_64") |
| .inOrder(); |
| assertThat(compileAction("//lib1:lib1", "b.o").getArguments()) |
| .containsAtLeast("-DA=foo", "-DB", "-DMONKEYS=ios_x86_64") |
| .inOrder(); |
| assertThat(compileAction("//lib2:lib2", "a.o").getArguments()) |
| .containsAtLeast("-DA=foo", "-DB", "-DMONKEYS=ios_x86_64", "-DC=bar", "-DD") |
| .inOrder(); |
| assertThat(compileAction("//lib2:lib2", "b.o").getArguments()) |
| .containsAtLeast("-DA=foo", "-DB", "-DMONKEYS=ios_x86_64", "-DC=bar", "-DD") |
| .inOrder(); |
| // TODO: Add tests for //bin:bin once experimental_objc_binary is implemented |
| } |
| |
| @Test |
| public void testDuplicateDefines() throws Exception { |
| createLibraryTargetWriter("//lib:lib") |
| .setAndCreateFiles("srcs", "a.m") |
| .setList("defines", "foo=bar", "foo=bar") |
| .write(); |
| int timesDefinesAppear = 0; |
| for (String arg : compileAction("//lib:lib", "a.o").getArguments()) { |
| if (arg.equals("-Dfoo=bar")) { |
| timesDefinesAppear++; |
| } |
| } |
| assertWithMessage("Duplicate define \"foo=bar\" should occur only once in command line") |
| .that(timesDefinesAppear) |
| .isEqualTo(1); |
| } |
| |
| @Test |
| public void checkDefinesFromCcLibraryDep() throws Exception { |
| checkDefinesFromCcLibraryDep(RULE_TYPE); |
| } |
| |
| @Test |
| public void testCppSourceCompilesWithCppFlags() throws Exception { |
| createLibraryTargetWriter("//objc:x") |
| .setAndCreateFiles("srcs", "a.mm", "b.cc", "c.mm", "d.cxx", "e.c", "f.m", "g.C") |
| .write(); |
| assertThat(compileAction("//objc:x", "a.o").getArguments()).contains("-std=gnu++11"); |
| assertThat(compileAction("//objc:x", "b.o").getArguments()).contains("-std=gnu++11"); |
| assertThat(compileAction("//objc:x", "c.o").getArguments()).contains("-std=gnu++11"); |
| assertThat(compileAction("//objc:x", "d.o").getArguments()).contains("-std=gnu++11"); |
| assertThat(compileAction("//objc:x", "e.o").getArguments()).doesNotContain("-std=gnu++11"); |
| assertThat(compileAction("//objc:x", "f.o").getArguments()).doesNotContain("-std=gnu++11"); |
| assertThat(compileAction("//objc:x", "g.o").getArguments()).contains("-std=gnu++11"); |
| } |
| |
| @Test |
| public void testDoesNotUseCxxUnfilteredFlags() throws Exception { |
| createLibraryTargetWriter("//lib:lib").setList("srcs", "a.m").write(); |
| // -pthread is an unfiltered_cxx_flag in the osx crosstool. |
| assertThat(compileAction("//lib:lib", "a.o").getArguments()).doesNotContain("-pthread"); |
| } |
| |
| @Test |
| public void testDoesNotUseDotdPruning() throws Exception { |
| useConfiguration("--objc_use_dotd_pruning=false"); |
| createLibraryTargetWriter("//lib:lib").setList("srcs", "a.m").write(); |
| CppCompileAction compileAction = (CppCompileAction) compileAction("//lib:lib", "a.o"); |
| assertThat(compileAction.getDotdFile()).isNull(); |
| } |
| |
| @Test |
| public void testProvidesObjcLibraryAndHeaders() throws Exception { |
| ConfiguredTarget target = |
| createLibraryTargetWriter("//objc:lib") |
| .setAndCreateFiles("srcs", "a.m", "b.m", "private.h") |
| .setAndCreateFiles("hdrs", "a.h", "b.h") |
| .write(); |
| ConfiguredTarget impltarget = |
| createLibraryTargetWriter("//objc_impl:lib") |
| .setAndCreateFiles("srcs", "a.m", "b.m", "private.h") |
| .setAndCreateFiles("hdrs", "a.h", "b.h") |
| .write(); |
| ConfiguredTarget depender = |
| createLibraryTargetWriter("//objc_depender:lib") |
| .setAndCreateFiles("srcs", "a.m", "b.m", "private.h") |
| .setAndCreateFiles("hdrs", "c.h", "d.h") |
| .setList("deps", "//objc:lib") |
| .setList("implementation_deps", "//objc_impl:lib") |
| .write(); |
| |
| assertThat(getArifactPathsOfLibraries(target)).containsExactly("objc/liblib.a"); |
| assertThat(getArifactPathsOfLibraries(depender)) |
| .containsExactly("objc/liblib.a", "objc_impl/liblib.a", "objc_depender/liblib.a"); |
| assertThat(getArifactPathsOfHeaders(target)) |
| .containsExactly("objc/a.h", "objc/b.h", "objc/private.h"); |
| assertThat(getArifactPathsOfHeaders(impltarget)) |
| .containsExactly("objc_impl/a.h", "objc_impl/b.h", "objc_impl/private.h"); |
| assertThat(getArifactPathsOfHeaders(depender)) |
| .containsExactly( |
| "objc/a.h", |
| "objc/b.h", |
| "objc/private.h", |
| "objc_depender/c.h", |
| "objc_depender/d.h", |
| "objc_depender/private.h"); |
| } |
| |
| @Test |
| public void testCollectsWeakSdkFrameworksTransitively() throws Exception { |
| createLibraryTargetWriter("//base_lib:lib") |
| .setAndCreateFiles("srcs", "a.m", "b.m", "private.h") |
| .setList("weak_sdk_frameworks", "foo") |
| .write(); |
| createLibraryTargetWriter("//depender_lib:lib") |
| .setAndCreateFiles("srcs", "a.m", "b.m", "private.h") |
| .setList("weak_sdk_frameworks", "bar") |
| .setList("deps", "//base_lib:lib") |
| .write(); |
| |
| ImmutableList<String> baseLinkFlags = getCcInfoUserLinkFlagsFromTarget("//base_lib:lib"); |
| assertThat(baseLinkFlags).containsExactly("-weak_framework", "foo").inOrder(); |
| ImmutableList<String> dependerLinkFlags = |
| getCcInfoUserLinkFlagsFromTarget("//depender_lib:lib"); |
| assertThat(dependerLinkFlags) |
| .containsExactly("-weak_framework", "bar", "-weak_framework", "foo") |
| .inOrder(); |
| } |
| |
| @Test |
| public void testErrorIfDepDoesNotExist() throws Exception { |
| checkErrorIfNotExist("deps", "[':nonexistent']"); |
| } |
| |
| @Test |
| public void testArIsNotImplicitOutput() throws Exception { |
| createLibraryTargetWriter("//lib:lib") |
| .setAndCreateFiles("srcs", "a.m", "b.m", "private.h") |
| .write(); |
| reporter.removeHandler(failFastHandler); |
| assertThrows(NoSuchTargetException.class, () -> getTarget("//lib:liblib.a")); |
| } |
| |
| @Test |
| public void testErrorForAbsoluteIncludesPath() throws Exception { |
| scratch.file("x/a.m"); |
| checkError( |
| "x", |
| "x", |
| String.format(ABSOLUTE_INCLUDES_PATH_FORMAT, "/absolute/path"), |
| "objc_library(", |
| " name = 'x',", |
| " srcs = ['a.m'],", |
| " includes = ['/absolute/path'],", |
| ")"); |
| } |
| |
| @Test |
| public void testDylibsProvided() throws Exception { |
| createLibraryTargetWriter("//lib:lib") |
| .setAndCreateFiles("srcs", "a.m", "b.m", "private.h") |
| .setList("sdk_dylibs", "libdy1", "libdy2") |
| .write(); |
| |
| CcLinkingContext ccLinkingContext = ccInfoForTarget("//lib:lib").getCcLinkingContext(); |
| assertThat(ccLinkingContext.getFlattenedUserLinkFlags()).containsExactly("-ldy1", "-ldy2"); |
| } |
| |
| @Test |
| public void testPopulatesCompilationArtifacts() throws Exception { |
| checkPopulatesCompilationArtifacts(RULE_TYPE); |
| } |
| |
| @Test |
| public void testCompilationActionsForDebug() throws Exception { |
| checkClangCoptsForCompilationMode(RULE_TYPE, CompilationMode.DBG, CodeCoverageMode.NONE); |
| } |
| |
| @Test |
| public void testClangCoptsForDebugModeWithoutGlib() throws Exception { |
| checkClangCoptsForDebugModeWithoutGlib(RULE_TYPE); |
| } |
| |
| @Test |
| public void testClangCoptsForDebugModeWithoutHardcoding() throws Exception { |
| useConfiguration( |
| "--apple_platform_type=ios", |
| "--platforms=" + MockObjcSupport.IOS_X86_64, |
| "--compilation_mode=dbg", |
| "--incompatible_avoid_hardcoded_objc_compilation_flags"); |
| scratch.file("x/a.m"); |
| RULE_TYPE.scratchTarget(scratch, "srcs", "['a.m']"); |
| |
| assertThat(compileAction("//x:x", "a.o").getArguments()).doesNotContain("-DDEBUG=1"); |
| } |
| |
| @Test |
| public void testClangCoptsForDebugModeWithoutGlibOrHardcoding() throws Exception { |
| useConfiguration( |
| "--apple_platform_type=ios", |
| "--platforms=" + MockObjcSupport.IOS_X86_64, |
| "--compilation_mode=dbg", |
| "--objc_debug_with_GLIBCXX=false", |
| "--incompatible_avoid_hardcoded_objc_compilation_flags"); |
| scratch.file("x/a.m"); |
| RULE_TYPE.scratchTarget(scratch, "srcs", "['a.m']"); |
| |
| assertThat(compileAction("//x:x", "a.o").getArguments()) |
| .containsNoneOf("-D_GLIBCXX_DEBUG", "-DDEBUG=1"); |
| } |
| |
| @Test |
| public void testCompilationActionsForOptimized() throws Exception { |
| checkClangCoptsForCompilationMode(RULE_TYPE, CompilationMode.OPT, CodeCoverageMode.NONE); |
| } |
| |
| @Test |
| public void testClangCoptsForOptimizedWithoutHardcoding() throws Exception { |
| useConfiguration( |
| "--apple_platform_type=ios", |
| "--platforms=" + MockObjcSupport.IOS_X86_64, |
| "--compilation_mode=opt", |
| "--incompatible_avoid_hardcoded_objc_compilation_flags"); |
| scratch.file("x/a.m"); |
| RULE_TYPE.scratchTarget(scratch, "srcs", "['a.m']"); |
| |
| assertThat(compileAction("//x:x", "a.o").getArguments()).doesNotContain("-DNDEBUG=1"); |
| } |
| |
| @Test |
| public void testUsesDefinesFromTransitiveCcDeps() throws Exception { |
| scratch.file( |
| "package/BUILD", |
| """ |
| cc_library( |
| name = "cc_lib", |
| srcs = ["a.cc"], |
| defines = ["FOO"], |
| ) |
| |
| objc_library( |
| name = "objc_lib", |
| srcs = ["b.m"], |
| deps = [":cc_lib"], |
| ) |
| """); |
| |
| CommandAction compileAction = compileAction("//package:objc_lib", "b.o"); |
| assertThat(compileAction.getArguments()).contains("-DFOO"); |
| } |
| |
| @Test |
| public void testAllowVariousNonBlacklistedTypesInHeaders() throws Exception { |
| checkAllowVariousNonBlacklistedTypesInHeaders(RULE_TYPE); |
| } |
| |
| @Test |
| public void testXcodeVersionEnv() throws Exception { |
| useConfiguration("--xcode_version=5.8"); |
| |
| createLibraryTargetWriter("//objc:lib") |
| .setAndCreateFiles("srcs", "a.m", "b.m", "private.h") |
| .setAndCreateFiles("hdrs", "c.h") |
| .write(); |
| CommandAction action = compileAction("//objc:lib", "a.o"); |
| |
| assertXcodeVersionEnv(action, "5.8"); |
| } |
| |
| @Test |
| public void testIosSdkVersionCannotBeDefinedButEmpty() { |
| OptionsParsingException e = |
| assertThrows(OptionsParsingException.class, () -> useConfiguration("--ios_sdk_version=")); |
| assertThat(e).hasMessageThat().contains("--ios_sdk_version"); |
| } |
| |
| private void checkErrorIfNotExist(String attribute, String value) throws Exception { |
| scratch.file("x/a.m"); |
| checkError( |
| "x", |
| "x", |
| "in " |
| + attribute |
| + " attribute of objc_library rule //x:x: rule '//x:nonexistent' does not exist", |
| "objc_library(", |
| " name = 'x',", |
| " srcs = ['a.m'],", |
| attribute + " = " + value, |
| ")"); |
| } |
| |
| @Test |
| public void testCompilesWithHdrs() throws Exception { |
| checkCompilesWithHdrs(ObjcLibraryTest.RULE_TYPE); |
| } |
| |
| @Test |
| public void testCompilesAssemblyWithPreprocessing() throws Exception { |
| createLibraryTargetWriter("//objc:lib") |
| .setAndCreateFiles("srcs", "a.m", "b.S") |
| .setAndCreateFiles("hdrs", "c.h") |
| .write(); |
| |
| CommandAction compileAction = compileAction("//objc:lib", "b.o"); |
| |
| // Clang automatically preprocesses .S files, so the assembler-with-cpp flag is unnecessary. |
| // Regression test for b/22636858. |
| assertThat(compileAction.getArguments()).doesNotContain("-x"); |
| assertThat(compileAction.getArguments()).doesNotContain("assembler-with-cpp"); |
| assertThat(baseArtifactNames(compileAction.getOutputs())).containsExactly("b.o", "b.d"); |
| assertThat(baseArtifactNames(compileAction.getPossibleInputsForTesting())) |
| .containsAtLeast("c.h", "b.S"); |
| } |
| |
| @Test |
| public void testReceivesTransitivelyPropagatedDefines() throws Exception { |
| checkReceivesTransitivelyPropagatedDefines(RULE_TYPE); |
| } |
| |
| @Test |
| public void testSdkIncludesUsedInCompileAction() throws Exception { |
| checkSdkIncludesUsedInCompileAction(RULE_TYPE); |
| } |
| |
| @Test |
| public void testCompilationActionsWithPch() throws Exception { |
| useConfiguration("--apple_platform_type=ios", "--platforms=" + MockObjcSupport.IOS_X86_64); |
| scratch.file("objc/foo.pch"); |
| createLibraryTargetWriter("//objc:lib") |
| .setAndCreateFiles("srcs", "a.m", "b.m", "private.h") |
| .setAndCreateFiles("hdrs", "c.h") |
| .set("pch", "'some.pch'") |
| .write(); |
| |
| CommandAction compileActionA = compileAction("//objc:lib", "a.o"); |
| |
| assertThat(removeConfigFragment(compileActionA.getArguments())) |
| .containsAtLeastElementsIn( |
| new ImmutableList.Builder<String>() |
| .add("-fexceptions") |
| .add("-fasm-blocks") |
| .add("-fobjc-abi-version=2") |
| .add("-fobjc-legacy-dispatch") |
| .addAll(CompilationSupport.DEFAULT_COMPILER_FLAGS) |
| .add("-arch x86_64") |
| .add("-isysroot", AppleToolchain.sdkDir()) |
| .addAll(FASTBUILD_COPTS) |
| .add("-iquote", ".") |
| .add("-iquote", OUTPUTDIR) |
| .add("-include", "objc/some.pch") |
| .add("-fobjc-arc") |
| .add("-c", "objc/a.m") |
| .addAll(outputArgs(compileActionA.getOutputs())) |
| .build()); |
| |
| assertThat(compileActionA.getPossibleInputsForTesting().toList()) |
| .contains(getFileConfiguredTarget("//objc:some.pch").getArtifact()); |
| } |
| |
| // Converts output artifacts into expected command-line arguments. |
| private ImmutableList<String> outputArgs(Collection<Artifact> outputs) { |
| ImmutableList.Builder<String> result = new ImmutableList.Builder<>(); |
| for (String outputConfig : Artifact.toExecPaths(outputs)) { |
| String output = removeConfigFragment(outputConfig); |
| if (output.endsWith(".o")) { |
| result.add("-o", output); |
| } else if (output.endsWith(".d")) { |
| result.add("-MD", "-MF", output); |
| } else { |
| throw new IllegalArgumentException( |
| "output " + output + " has unknown ending (not in (.d, .o)"); |
| } |
| } |
| return result.build(); |
| } |
| |
| @Test |
| public void testCollectsSdkFrameworksTransitively() throws Exception { |
| createLibraryTargetWriter("//base_lib:lib") |
| .setAndCreateFiles("srcs", "a.m", "b.m", "private.h") |
| .setList("sdk_frameworks", "foo") |
| .write(); |
| createLibraryTargetWriter("//depender_lib:lib") |
| .setAndCreateFiles("srcs", "a.m", "b.m", "private.h") |
| .setList("sdk_frameworks", "bar") |
| .setList("deps", "//base_lib:lib") |
| .write(); |
| |
| ImmutableList<String> baseLinkFlags = getCcInfoUserLinkFlagsFromTarget("//base_lib:lib"); |
| assertThat(baseLinkFlags).containsExactly("-framework", "foo").inOrder(); |
| ImmutableList<String> dependerLinkFlags = |
| getCcInfoUserLinkFlagsFromTarget("//depender_lib:lib"); |
| assertThat(dependerLinkFlags) |
| .containsExactly("-framework", "bar", "-framework", "foo") |
| .inOrder(); |
| |
| // Make sure that the archive action does not actually include the frameworks. This is needed |
| // for creating binaries but is ignored for libraries. |
| CommandAction archiveAction = archiveAction("//depender_lib:lib"); |
| assertThat(archiveAction.getArguments()) |
| .isEqualTo( |
| ImmutableList.of( |
| "tools/osx/crosstool/mac/ar_wrapper", |
| "rcs", |
| Iterables.getOnlyElement(archiveAction.getOutputs()).getExecPathString(), |
| getBinArtifact("_objs/lib/arc/a.o", getConfiguredTarget("//depender_lib:lib")) |
| .getExecPathString(), |
| getBinArtifact("_objs/lib/arc/b.o", getConfiguredTarget("//depender_lib:lib")) |
| .getExecPathString())); |
| } |
| |
| @Test |
| public void testMultipleRulesCompilingOneSourceGenerateUniqueObjFiles() throws Exception { |
| scratch.file("lib/a.m"); |
| scratch.file( |
| "lib/BUILD", |
| """ |
| objc_library( |
| name = "lib1", |
| srcs = ["a.m"], |
| copts = ["-Ilib1flag"], |
| ) |
| |
| objc_library( |
| name = "lib2", |
| srcs = ["a.m"], |
| copts = ["-Ilib2flag"], |
| ) |
| """); |
| Artifact obj1 = Iterables.getOnlyElement(inputsEndingWith(archiveAction("//lib:lib1"), ".o")); |
| Artifact obj2 = Iterables.getOnlyElement(inputsEndingWith(archiveAction("//lib:lib2"), ".o")); |
| |
| // The exec paths of each obj file should be based on the objc_library target. |
| assertThat(obj1.getExecPathString()).contains("lib1"); |
| assertThat(obj1.getExecPathString()).doesNotContain("lib2"); |
| assertThat(obj2.getExecPathString()).doesNotContain("lib1"); |
| assertThat(obj2.getExecPathString()).contains("lib2"); |
| |
| CommandAction compile1 = (CommandAction) getGeneratingAction(obj1); |
| CommandAction compile2 = (CommandAction) getGeneratingAction(obj2); |
| assertThat(compile1.getArguments()).contains("-Ilib1flag"); |
| assertThat(compile2.getArguments()).contains("-Ilib2flag"); |
| } |
| |
| @Test |
| public void testIncludesDirsOfTransitiveDepsGetPassedToCompileAction() throws Exception { |
| createLibraryTargetWriter("//lib1:lib1") |
| .setAndCreateFiles("srcs", "a.m", "b.m", "private.h") |
| .setList("includes", "third_party/foo", "opensource/bar") |
| .write(); |
| |
| createLibraryTargetWriter("//lib2:lib2") |
| .setAndCreateFiles("srcs", "a.m", "b.m", "private.h") |
| .setList("includes", "more_includes") |
| .setList("deps", "//lib1:lib1") |
| .write(); |
| CommandAction compileAction = compileAction("//lib2:lib2", "a.o"); |
| // We remove spaces, since the crosstool rules do not use spaces in include paths |
| String compileActionArgs = |
| Joiner.on("").join(removeConfigFragment(compileAction.getArguments())).replace(" ", ""); |
| List<String> expectedIncludePaths = |
| rootedIncludePaths("lib2/more_includes", "lib1/third_party/foo", "lib1/opensource/bar"); |
| for (String expectedIncludePath : expectedIncludePaths) { |
| assertThat(compileActionArgs).contains("-I" + expectedIncludePath); |
| } |
| } |
| |
| @Test |
| public void testIncludesDirsOfTransitiveCcDepsGetPassedToCompileAction() throws Exception { |
| scratch.file( |
| "package/BUILD", |
| """ |
| cc_library( |
| name = "cc_lib", |
| srcs = ["a.cc"], |
| includes = ["foo/bar"], |
| ) |
| |
| objc_library( |
| name = "objc_lib", |
| srcs = ["b.m"], |
| deps = [":cc_lib"], |
| ) |
| """); |
| |
| CommandAction compileAction = compileAction("//package:objc_lib", "b.o"); |
| assertContainsSublist( |
| removeConfigFragment(removeConfigFragment(compileAction.getArguments())), |
| ImmutableList.copyOf( |
| Interspersing.beforeEach("-isystem", rootedIncludePaths("package/foo/bar")))); |
| } |
| |
| @Test |
| public void testIncludesDirsOfTransitiveCcIncDepsGetPassedToCompileAction() throws Exception { |
| scratch.file( |
| "third_party/cc_lib/BUILD", |
| """ |
| licenses(["unencumbered"]) |
| |
| cc_library( |
| name = "cc_lib_impl", |
| srcs = [ |
| "v1/a.c", |
| "v1/a.h", |
| ], |
| ) |
| |
| cc_library( |
| name = "cc_lib", |
| hdrs = ["v1/a.h"], |
| strip_include_prefix = "v1", |
| deps = [":cc_lib_impl"], |
| ) |
| """); |
| |
| scratch.file( |
| "package/BUILD", |
| """ |
| objc_library( |
| name = "objc_lib", |
| srcs = ["b.m"], |
| deps = ["//third_party/cc_lib"], |
| ) |
| """); |
| |
| CommandAction compileAction = compileAction("//package:objc_lib", "b.o"); |
| // We remove spaces, since the crosstool rules do not use spaces for include paths. |
| String compileActionArgs = Joiner.on("").join(compileAction.getArguments()).replace(" ", ""); |
| assertThat(compileActionArgs) |
| .matches(".*-iquote.*/third_party/cc_lib/_virtual_includes/cc_lib.*"); |
| } |
| |
| @Test |
| public void testIncludesIquoteFlagForGenFilesRoot() throws Exception { |
| createLibraryTargetWriter("//lib:lib") |
| .setAndCreateFiles("srcs", "a.m", "b.m", "private.h") |
| .write(); |
| CommandAction compileAction = compileAction("//lib:lib", "a.o"); |
| assertContainsSublist( |
| removeConfigFragment(compileAction.getArguments()), ImmutableList.of("-iquote", OUTPUTDIR)); |
| } |
| |
| @Test |
| public void testCompilesAssemblyAsm() throws Exception { |
| createLibraryTargetWriter("//objc:lib") |
| .setAndCreateFiles("srcs", "a.m", "b.asm") |
| .setAndCreateFiles("hdrs", "c.h") |
| .write(); |
| |
| CommandAction compileAction = compileAction("//objc:lib", "b.o"); |
| |
| assertThat(compileAction.getArguments()).doesNotContain("-x"); |
| assertThat(compileAction.getArguments()).doesNotContain("assembler-with-cpp"); |
| assertThat(baseArtifactNames(compileAction.getOutputs())).contains("b.o"); |
| assertThat(baseArtifactNames(compileAction.getPossibleInputsForTesting())) |
| .containsAtLeast("c.h", "b.asm"); |
| } |
| |
| @Test |
| public void testCompilesAssemblyS() throws Exception { |
| createLibraryTargetWriter("//objc:lib") |
| .setAndCreateFiles("srcs", "a.m", "b.s") |
| .setAndCreateFiles("hdrs", "c.h") |
| .write(); |
| |
| CommandAction compileAction = compileAction("//objc:lib", "b.o"); |
| |
| assertThat(compileAction.getArguments()).doesNotContain("-x"); |
| assertThat(compileAction.getArguments()).doesNotContain("assembler-with-cpp"); |
| assertThat(baseArtifactNames(compileAction.getOutputs())).contains("b.o"); |
| assertThat(baseArtifactNames(compileAction.getPossibleInputsForTesting())) |
| .containsAtLeast("c.h", "b.s"); |
| } |
| |
| @Test |
| public void testProvidesHdrsAndIncludes() throws Exception { |
| checkProvidesHdrsAndIncludes(RULE_TYPE, Optional.of("x/private.h")); |
| } |
| |
| @Test |
| public void testPruningActionsSetLocalityBasedOnXcode() throws Exception { |
| scratch.file( |
| "xcode/BUILD", |
| """ |
| xcode_version( |
| name = "version10_1_0", |
| aliases = [ |
| "10.1", |
| "10.1.0", |
| ], |
| default_ios_sdk_version = "12.1", |
| default_macos_sdk_version = "10.14", |
| default_tvos_sdk_version = "12.1", |
| default_watchos_sdk_version = "5.1", |
| version = "10.1.0", |
| ) |
| |
| xcode_version( |
| name = "version10_2_1", |
| aliases = [ |
| "10.2.1", |
| "10.2", |
| ], |
| default_ios_sdk_version = "12.2", |
| default_macos_sdk_version = "10.14", |
| default_tvos_sdk_version = "12.2", |
| default_watchos_sdk_version = "5.2", |
| version = "10.2.1", |
| ) |
| |
| available_xcodes( |
| name = "local", |
| default = ":version10_1_0", |
| versions = [":version10_1_0"], |
| ) |
| |
| available_xcodes( |
| name = "remote", |
| default = ":version10_2_1", |
| versions = [":version10_2_1"], |
| ) |
| |
| xcode_config( |
| name = "my_config", |
| local_versions = ":local", |
| remote_versions = ":remote", |
| ) |
| """); |
| |
| useConfigurationWithCustomXcode( |
| "--xcode_version=10.2.1", |
| "--xcode_version_config=//xcode:my_config", |
| "--objc_use_dotd_pruning"); |
| createLibraryTargetWriter("//lib:lib").setList("srcs", "a.m").write(); |
| CppCompileAction action = (CppCompileAction) compileAction("//lib:lib", "a.o"); |
| assertHasRequirement(action, ExecutionRequirements.REQUIREMENTS_SET); |
| assertHasRequirement(action, ExecutionRequirements.NO_LOCAL); |
| assertNotHasRequirement(action, ExecutionRequirements.NO_REMOTE); |
| } |
| |
| @Test |
| public void testUsesDotdPruning() throws Exception { |
| useConfiguration("--objc_use_dotd_pruning"); |
| createLibraryTargetWriter("//lib:lib").setList("srcs", "a.m").write(); |
| CppCompileAction compileAction = (CppCompileAction) compileAction("//lib:lib", "a.o"); |
| ActionExecutionException expected = |
| assertThrows( |
| ActionExecutionException.class, |
| () -> |
| compileAction.discoverInputsFromDotdFiles( |
| new ActionExecutionContextBuilder().build(), null, null, null, false)); |
| assertThat(expected).hasMessageThat().contains("error while parsing .d file"); |
| } |
| |
| @Test |
| public void testAppleSdkDefaultPlatformEnv() throws Exception { |
| useConfiguration("--apple_platform_type=ios", "--platforms=" + MockObjcSupport.IOS_X86_64); |
| createLibraryTargetWriter("//objc:lib") |
| .setAndCreateFiles("srcs", "a.m", "b.m", "private.h") |
| .setAndCreateFiles("hdrs", "c.h") |
| .write(); |
| CommandAction action = compileAction("//objc:lib", "a.o"); |
| |
| assertAppleSdkPlatformEnv(action, "iPhoneSimulator"); |
| } |
| |
| @Test |
| public void testAppleSdkDevicePlatformEnv() throws Exception { |
| useConfiguration( |
| "--apple_platform_type=ios", "--cpu=ios_arm64", "--platforms=" + MockObjcSupport.IOS_ARM64); |
| |
| createLibraryTargetWriter("//objc:lib") |
| .setAndCreateFiles("srcs", "a.m", "b.m", "private.h") |
| .setAndCreateFiles("hdrs", "c.h") |
| .write(); |
| CommandAction action = compileAction("//objc:lib", "a.o"); |
| |
| assertAppleSdkPlatformEnv(action, "iPhoneOS"); |
| } |
| |
| private StructImpl getJ2ObjcInfoFromTarget(ConfiguredTarget configuredTarget, String providerName) |
| throws Exception { |
| Provider.Key key = |
| new StarlarkProvider.Key( |
| Label.parseCanonical("@_builtins//:common/objc/providers.bzl"), providerName); |
| return (StructImpl) configuredTarget.get(key); |
| } |
| |
| @Test |
| public void testExportsJ2ObjcProviders() throws Exception { |
| ConfiguredTarget lib = createLibraryTargetWriter("//a:lib").write(); |
| StructImpl j2ObjcEntryClassInfo = getJ2ObjcInfoFromTarget(lib, "J2ObjcEntryClassInfo"); |
| StructImpl j2ObjcMappingFileInfo = getJ2ObjcInfoFromTarget(lib, "J2ObjcMappingFileInfo"); |
| assertThat(j2ObjcEntryClassInfo).isNotNull(); |
| assertThat(j2ObjcMappingFileInfo).isNotNull(); |
| } |
| |
| @Test |
| public void testObjcImportDoesNotCrash() throws Exception { |
| scratch.file( |
| "x/BUILD", |
| """ |
| objc_library( |
| name = "objc", |
| srcs = ["source.m"], |
| deps = [":import"], |
| ) |
| |
| objc_import( |
| name = "import", |
| archives = ["archive.a"], |
| ) |
| """); |
| assertThat(getConfiguredTarget("//x:objc")).isNotNull(); |
| } |
| |
| @Test |
| public void testCompilationActionsWithIQuotesInCopts() throws Exception { |
| useConfiguration("--cpu=ios_i386"); |
| createLibraryTargetWriter("//objc:lib") |
| .setAndCreateFiles("srcs", "a.m", "b.m", "private.h") |
| .setAndCreateFiles("hdrs", "c.h") |
| .setList("copts", "-iquote foo/bar", "-iquote bam/baz") |
| .write(); |
| |
| CommandAction compileActionA = compileAction("//objc:lib", "a.o"); |
| String action = String.join(" ", compileActionA.getArguments()); |
| assertThat(action).contains("-iquote foo/bar"); |
| assertThat(action).contains("-iquote bam/baz"); |
| } |
| |
| @Test |
| public void testCollectCodeCoverageWithGCOVFlags() throws Exception { |
| useConfiguration("--collect_code_coverage"); |
| createLibraryTargetWriter("//objc:x") |
| .setAndCreateFiles("srcs", "a.mm", "b.cc", "c.mm", "d.cxx", "e.c", "f.m", "g.C") |
| .write(); |
| ImmutableList<String> copts = ImmutableList.of("-fprofile-arcs", "-ftest-coverage"); |
| assertThat(compileAction("//objc:x", "a.o").getArguments()).containsAtLeastElementsIn(copts); |
| assertThat(compileAction("//objc:x", "b.o").getArguments()).containsAtLeastElementsIn(copts); |
| assertThat(compileAction("//objc:x", "c.o").getArguments()).containsAtLeastElementsIn(copts); |
| assertThat(compileAction("//objc:x", "d.o").getArguments()).containsAtLeastElementsIn(copts); |
| assertThat(compileAction("//objc:x", "e.o").getArguments()).containsAtLeastElementsIn(copts); |
| assertThat(compileAction("//objc:x", "f.o").getArguments()).containsAtLeastElementsIn(copts); |
| assertThat(compileAction("//objc:x", "g.o").getArguments()).containsAtLeastElementsIn(copts); |
| } |
| |
| @Test |
| public void testCollectCodeCoverageWithLLVMCOVFlags() throws Exception { |
| useConfiguration("--collect_code_coverage", "--experimental_use_llvm_covmap"); |
| createLibraryTargetWriter("//objc:x") |
| .setAndCreateFiles("srcs", "a.mm", "b.cc", "c.mm", "d.cxx", "e.c", "f.m", "g.C") |
| .write(); |
| ImmutableList<String> copts = |
| ImmutableList.of("-fprofile-instr-generate", "-fcoverage-mapping"); |
| assertThat(compileAction("//objc:x", "a.o").getArguments()).containsAtLeastElementsIn(copts); |
| assertThat(compileAction("//objc:x", "b.o").getArguments()).containsAtLeastElementsIn(copts); |
| assertThat(compileAction("//objc:x", "c.o").getArguments()).containsAtLeastElementsIn(copts); |
| assertThat(compileAction("//objc:x", "d.o").getArguments()).containsAtLeastElementsIn(copts); |
| assertThat(compileAction("//objc:x", "e.o").getArguments()).containsAtLeastElementsIn(copts); |
| assertThat(compileAction("//objc:x", "f.o").getArguments()).containsAtLeastElementsIn(copts); |
| assertThat(compileAction("//objc:x", "g.o").getArguments()).containsAtLeastElementsIn(copts); |
| } |
| |
| @Test |
| public void testNoG0IfGeneratesDsym() throws Exception { |
| useConfiguration("--apple_generate_dsym", "-c", "opt"); |
| createLibraryTargetWriter("//x:x").setList("srcs", "a.m").write(); |
| CommandAction compileAction = compileAction("//x:x", "a.o"); |
| assertThat(compileAction.getArguments()).doesNotContain("-g0"); |
| } |
| |
| @Test |
| public void testFilesToCompileOutputGroup() throws Exception { |
| checkFilesToCompileOutputGroup(RULE_TYPE); |
| } |
| |
| @Test |
| public void testDefaultEnabledFeatureIsUsed() throws Exception { |
| // Although using --cpu=ios_x86_64, it transitions to darwin_x86_64, so the actual |
| // cc_toolchain in use will be the darwin_x86_64 one. |
| MockObjcSupport.setupCcToolchainConfig( |
| mockToolsConfig, MockObjcSupport.darwinX86_64().withFeatures("default_feature")); |
| useConfiguration("--cpu=ios_x86_64"); |
| scratch.file( |
| "x/BUILD", |
| """ |
| objc_library( |
| name = "objc", |
| srcs = ["source.m"], |
| ) |
| """); |
| CommandAction compileAction = compileAction("//x:objc", "source.o"); |
| assertThat(compileAction.getArguments()).contains("-dummy"); |
| } |
| |
| @Test |
| public void testHeaderPassedToCcLib() throws Exception { |
| createLibraryTargetWriter("//objc:lib").setList("hdrs", "objc_hdr.h").write(); |
| ScratchAttributeWriter.fromLabelString(this, "cc_library", "//cc:lib") |
| .setList("srcs", "a.cc") |
| .setList("deps", "//objc:lib") |
| .write(); |
| CommandAction compileAction = compileAction("//cc:lib", "a.o"); |
| assertThat(Artifact.toRootRelativePaths(compileAction.getPossibleInputsForTesting())) |
| .contains("objc/objc_hdr.h"); |
| } |
| |
| @Test |
| public void testTextualHeaderPassedToCcLib() throws Exception { |
| ScratchAttributeWriter.fromLabelString(this, "cc_library", "//cc/txt_dep") |
| .setList("textual_hdrs", "hdr.h") |
| .write(); |
| createLibraryTargetWriter("//objc:lib").setList("deps", "//cc/txt_dep").write(); |
| ScratchAttributeWriter.fromLabelString(this, "cc_library", "//cc/lib") |
| .setList("srcs", "a.cc") |
| .setList("deps", "//objc:lib") |
| .write(); |
| CommandAction compileAction = compileAction("//cc/lib", "a.o"); |
| assertThat(Artifact.toRootRelativePaths(compileAction.getPossibleInputsForTesting())) |
| .contains("cc/txt_dep/hdr.h"); |
| } |
| |
| /** Regression test for https://github.com/bazelbuild/bazel/issues/7721. */ |
| @Test |
| public void testToolchainRuntimeLibrariesSolibDir() throws Exception { |
| MockObjcSupport.setupCcToolchainConfig( |
| mockToolsConfig, |
| MockObjcSupport.darwinX86_64() |
| .withFeatures( |
| CppRuleClasses.SUPPORTS_INTERFACE_SHARED_LIBRARIES, |
| CppRuleClasses.SUPPORTS_DYNAMIC_LINKER)); |
| scratch.file( |
| "foo/BUILD", |
| """ |
| cc_test( |
| name = "d", |
| deps = [":b"], |
| ) |
| |
| objc_library( |
| name = "b", |
| deps = [":a"], |
| ) |
| |
| cc_library( |
| name = "a", |
| srcs = ["a.c"], |
| ) |
| """); |
| ConfiguredTarget configuredTarget = getConfiguredTarget("//foo:d"); |
| assertThat(configuredTarget).isNotNull(); |
| } |
| |
| @Test |
| public void testDirectFields() throws Exception { |
| scratch.file( |
| "x/BUILD", |
| """ |
| objc_library( |
| name = "foo", |
| srcs = [ |
| "foo.m", |
| "foo_impl.h", |
| ], |
| hdrs = ["foo.h"], |
| textual_hdrs = ["foo.inc"], |
| ) |
| |
| objc_library( |
| name = "bar", |
| srcs = [ |
| "bar.m", |
| "bar_impl.h", |
| ], |
| hdrs = ["bar.h"], |
| textual_hdrs = ["bar.inc"], |
| deps = [":foo"], |
| ) |
| """); |
| |
| ObjcProvider dependerProvider = |
| getConfiguredTarget("//x:bar").get(ObjcProvider.STARLARK_CONSTRUCTOR); |
| assertThat(baseArtifactNames(dependerProvider.getDirect(ObjcProvider.SOURCE))) |
| .containsExactly("bar.m", "bar_impl.h"); |
| |
| ConfiguredTarget target = getConfiguredTarget("//x:bar"); |
| CcCompilationContext ccCompilationContext = |
| target.get(CcInfo.PROVIDER).getCcCompilationContext(); |
| assertThat(baseArtifactNames(ccCompilationContext.getDirectPublicHdrs())) |
| .containsExactly("bar.h"); |
| assertThat(baseArtifactNames(ccCompilationContext.getDirectPrivateHdrs())) |
| .containsExactly("bar_impl.h"); |
| assertThat(baseArtifactNames(ccCompilationContext.getTextualHdrs())).containsExactly("bar.inc"); |
| |
| // Verify that the CppModuleMap objects are not added twice when merging the ARC and non-ARC |
| // contexts. |
| assertThat(ccCompilationContext.getExportingModuleMaps()).hasSize(1); |
| } |
| |
| @Test |
| public void testNameHasSlash() throws Exception { |
| scratch.file("x/foo.m"); |
| checkError( |
| "x", |
| "foo/bar", |
| "this attribute has unsupported character '/'", |
| "objc_library(name = 'foo/bar', srcs = ['foo.m'])"); |
| } |
| |
| @Test |
| public void testObjcLibraryLoadedThroughMacro() throws Exception { |
| setupTestObjcLibraryLoadedThroughMacro(/* loadMacro= */ true); |
| assertThat(getConfiguredTarget("//a:a")).isNotNull(); |
| assertNoEvents(); |
| } |
| |
| private void setupTestObjcLibraryLoadedThroughMacro(boolean loadMacro) throws Exception { |
| scratch.file( |
| "a/BUILD", |
| getAnalysisMock().ccSupport().getMacroLoadStatement(loadMacro, "objc_library"), |
| "objc_library(name='a', srcs=['a.cc'])"); |
| } |
| |
| @Test |
| public void testGenerateDsymFlagPropagatesToObjcLibraryFeature() throws Exception { |
| useConfiguration("--apple_generate_dsym"); |
| createLibraryTargetWriter("//objc/lib").setList("srcs", "a.m").write(); |
| CommandAction compileAction = compileAction("//objc/lib", "a.o"); |
| assertThat(compileAction.getArguments()).contains("-DDUMMY_GENERATE_DSYM_FILE"); |
| } |
| |
| @Test |
| public void testArtifactsToAlwaysBuild() throws Exception { |
| ConfiguredTarget x = |
| scratchConfiguredTarget( |
| "foo", |
| "x", |
| "objc_library(name = 'x', srcs = ['x.m'], non_arc_srcs = ['x2.m'], deps = [':y'])", |
| "objc_library(name = 'y', srcs = ['y.m'], non_arc_srcs = ['y2.m'], )"); |
| assertThat( |
| ActionsTestUtil.sortedBaseNamesOf(getOutputGroup(x, OutputGroupInfo.HIDDEN_TOP_LEVEL))) |
| .isEqualTo("x.o x2.o y.o y2.o"); |
| } |
| |
| @Test |
| public void testLangObjcFeature() throws Exception { |
| MockObjcSupport.setupCcToolchainConfig( |
| mockToolsConfig, MockObjcSupport.darwinX86_64().withFeatures(CppRuleClasses.PARSE_HEADERS)); |
| useConfiguration("--features=parse_headers", "--process_headers_in_dependencies"); |
| |
| ConfiguredTarget x = |
| scratchConfiguredTarget("foo", "x", "objc_library(name = 'x', hdrs = ['x.h'])"); |
| |
| assertThat(getGeneratingCompileAction("_objs/x/arc/x.h.processed", x).getArguments()) |
| .contains("-DDUMMY_LANG_OBJC"); |
| } |
| |
| private CppCompileAction getGeneratingCompileAction( |
| String packageRelativePath, ConfiguredTarget owner) { |
| return (CppCompileAction) getGeneratingAction(getBinArtifact(packageRelativePath, owner)); |
| } |
| |
| @Test |
| public void testProcessHeadersInArcOnly() throws Exception { |
| MockObjcSupport.setupCcToolchainConfig( |
| mockToolsConfig, MockObjcSupport.darwinX86_64().withFeatures(CppRuleClasses.PARSE_HEADERS)); |
| useConfiguration("--features=parse_headers", "--process_headers_in_dependencies"); |
| ConfiguredTarget x = |
| scratchConfiguredTarget("foo", "x", "objc_library(name = 'x', hdrs = ['x.h'])"); |
| CcCompilationContext ccCompilationContext = x.get(CcInfo.PROVIDER).getCcCompilationContext(); |
| assertThat(Artifact.toRootRelativePaths(ccCompilationContext.getHeaderTokens())) |
| .containsExactly("foo/_objs/x/arc/x.h.processed"); |
| } |
| |
| @Test |
| public void testProcessHeadersInDependencies() throws Exception { |
| MockObjcSupport.setupCcToolchainConfig( |
| mockToolsConfig, MockObjcSupport.darwinX86_64().withFeatures(CppRuleClasses.PARSE_HEADERS)); |
| useConfiguration("--features=parse_headers", "--process_headers_in_dependencies"); |
| ConfiguredTarget x = |
| scratchConfiguredTarget( |
| "foo", |
| "x", |
| "objc_library(name = 'x', deps = [':y'])", |
| "objc_library(name = 'y', hdrs = ['y.h'])"); |
| CcCompilationContext ccCompilationContext = x.get(CcInfo.PROVIDER).getCcCompilationContext(); |
| assertThat(ActionsTestUtil.baseNamesOf(ccCompilationContext.getHeaderTokens())) |
| .isEqualTo("y.h.processed"); |
| assertThat(ActionsTestUtil.baseNamesOf(getOutputGroup(x, OutputGroupInfo.HIDDEN_TOP_LEVEL))) |
| .isEqualTo("y.h.processed"); |
| } |
| |
| @Test |
| public void testProcessHeadersInDependenciesOfCcBinary() throws Exception { |
| MockObjcSupport.setupCcToolchainConfig( |
| mockToolsConfig, MockObjcSupport.darwinX86_64().withFeatures(CppRuleClasses.PARSE_HEADERS)); |
| useConfiguration("--features=parse_headers", "--process_headers_in_dependencies"); |
| ConfiguredTarget x = |
| scratchConfiguredTarget( |
| "foo", |
| "x", |
| "cc_binary(name = 'x', deps = [':y', ':z'])", |
| "cc_library(name = 'y', hdrs = ['y.h'])", |
| "objc_library(name = 'z', srcs = ['z.h'])"); |
| String validation = ActionsTestUtil.baseNamesOf(getOutputGroup(x, OutputGroupInfo.VALIDATION)); |
| assertThat(validation).contains("y.h.processed"); |
| assertThat(validation).contains("z.h.processed"); |
| } |
| |
| @Test |
| public void testSrcCompileActionMnemonic() throws Exception { |
| MockObjcSupport.setupCcToolchainConfig( |
| mockToolsConfig, MockObjcSupport.darwinX86_64().withFeatures(CppRuleClasses.PARSE_HEADERS)); |
| useConfiguration("--features=parse_headers", "--process_headers_in_dependencies"); |
| |
| ConfiguredTarget x = |
| scratchConfiguredTarget("foo", "x", "objc_library(name = 'x', srcs = ['a.m'])"); |
| |
| assertThat(getGeneratingCompileAction("_objs/x/arc/a.o", x).getMnemonic()) |
| .isEqualTo("ObjcCompile"); |
| } |
| |
| @Test |
| public void testHeaderCompileActionMnemonic() throws Exception { |
| MockObjcSupport.setupCcToolchainConfig( |
| mockToolsConfig, MockObjcSupport.darwinX86_64().withFeatures(CppRuleClasses.PARSE_HEADERS)); |
| useConfiguration("--features=parse_headers", "--process_headers_in_dependencies"); |
| |
| ConfiguredTarget x = |
| scratchConfiguredTarget( |
| "foo", "x", "objc_library(name = 'x', srcs = ['y.h'], hdrs = ['z.h'])"); |
| |
| assertThat(getGeneratingCompileAction("_objs/x/arc/y.h.processed", x).getMnemonic()) |
| .isEqualTo("ObjcCompile"); |
| assertThat(getGeneratingCompileAction("_objs/x/arc/z.h.processed", x).getMnemonic()) |
| .isEqualTo("ObjcCompile"); |
| } |
| |
| @Test |
| public void testIncompatibleUseCppCompileHeaderMnemonic() throws Exception { |
| MockObjcSupport.setupCcToolchainConfig( |
| mockToolsConfig, MockObjcSupport.darwinX86_64().withFeatures(CppRuleClasses.PARSE_HEADERS)); |
| useConfiguration( |
| "--incompatible_use_cpp_compile_header_mnemonic", |
| "--features=parse_headers", |
| "--process_headers_in_dependencies"); |
| |
| ConfiguredTarget x = |
| scratchConfiguredTarget( |
| "foo", "x", "objc_library(name = 'x', srcs = ['a.m', 'y.h'], hdrs = ['z.h'])"); |
| |
| assertThat(getGeneratingCompileAction("_objs/x/arc/a.o", x).getMnemonic()) |
| .isEqualTo("ObjcCompile"); |
| assertThat(getGeneratingCompileAction("_objs/x/arc/y.h.processed", x).getMnemonic()) |
| .isEqualTo("ObjcCompileHeader"); |
| assertThat(getGeneratingCompileAction("_objs/x/arc/z.h.processed", x).getMnemonic()) |
| .isEqualTo("ObjcCompileHeader"); |
| } |
| |
| @Test |
| public void testAlwaysLinkDefaultFalse() throws Exception { |
| useConfiguration("--incompatible_objc_alwayslink_by_default=false"); |
| addAppleBinaryStarlarkRule(scratch); |
| |
| scratch.file( |
| "test/BUILD", |
| """ |
| load("//test_starlark:apple_binary_starlark.bzl", "apple_binary_starlark") |
| |
| apple_binary_starlark( |
| name = "objc_bin", |
| platform_type = "ios", |
| deps = [":main_lib"], |
| ) |
| |
| objc_library( |
| name = "main_lib", |
| srcs = ["b.m"], |
| ) |
| """); |
| |
| CommandAction testLinkAction = linkAction("//test:objc_bin"); |
| assertThat(Joiner.on(" ").join(testLinkAction.getArguments())).doesNotContain("-force_load"); |
| } |
| |
| @Test |
| public void testAlwaysLinkDefaultTrue() throws Exception { |
| useConfiguration("--incompatible_objc_alwayslink_by_default"); |
| addAppleBinaryStarlarkRule(scratch); |
| |
| scratch.file( |
| "test/BUILD", |
| """ |
| load("//test_starlark:apple_binary_starlark.bzl", "apple_binary_starlark") |
| |
| apple_binary_starlark( |
| name = "objc_bin", |
| platform_type = "ios", |
| deps = [":main_lib"], |
| ) |
| |
| objc_library( |
| name = "main_lib", |
| srcs = ["b.m"], |
| ) |
| """); |
| scratch.file("test/b.m", "// dummy file"); |
| |
| CommandAction testLinkAction = linkAction("//test:objc_bin"); |
| assertThat(Joiner.on(" ").join(testLinkAction.getArguments())) |
| .containsMatch("-force_load [^ ]+-out/[^ ]+/test/libmain_lib.lo"); |
| } |
| |
| @Test |
| public void testAlwaysLinkTrueDefaultFalse() throws Exception { |
| useConfiguration("--incompatible_objc_alwayslink_by_default=false"); |
| addAppleBinaryStarlarkRule(scratch); |
| |
| scratch.file( |
| "test/BUILD", |
| """ |
| load("//test_starlark:apple_binary_starlark.bzl", "apple_binary_starlark") |
| |
| apple_binary_starlark( |
| name = "objc_bin", |
| platform_type = "ios", |
| deps = [":main_lib"], |
| ) |
| |
| objc_library( |
| name = "main_lib", |
| srcs = ["b.m"], |
| alwayslink = True, |
| ) |
| """); |
| |
| CommandAction testLinkAction = linkAction("//test:objc_bin"); |
| assertThat(Joiner.on(" ").join(testLinkAction.getArguments())) |
| .containsMatch("-force_load [^ ]+-out/[^ ]+/test/libmain_lib.lo"); |
| } |
| |
| @Test |
| public void testAlwaysLinkFalseDefaultTrue() throws Exception { |
| useConfiguration("--incompatible_objc_alwayslink_by_default"); |
| addAppleBinaryStarlarkRule(scratch); |
| |
| scratch.file( |
| "test/BUILD", |
| """ |
| load("//test_starlark:apple_binary_starlark.bzl", "apple_binary_starlark") |
| |
| apple_binary_starlark( |
| name = "objc_bin", |
| platform_type = "ios", |
| deps = [":main_lib"], |
| ) |
| |
| objc_library( |
| name = "main_lib", |
| srcs = ["b.m"], |
| alwayslink = False, |
| ) |
| """); |
| |
| CommandAction testLinkAction = linkAction("//test:objc_bin"); |
| assertThat(Joiner.on(" ").join(testLinkAction.getArguments())).doesNotContain("-force_load"); |
| } |
| |
| @Test |
| public void testLinkActionMnemonic() throws Exception { |
| scratchConfiguredTarget("foo", "x", "objc_library(name = 'x', srcs = ['a.m'])"); |
| |
| CppLinkAction archiveAction = (CppLinkAction) archiveAction("//foo:x"); |
| assertThat(archiveAction.getMnemonic()).isEqualTo("CppArchive"); |
| } |
| |
| private static List<String> linkstampExecPaths(NestedSet<CcLinkingContext.Linkstamp> linkstamps) { |
| return ActionsTestUtil.execPaths( |
| ActionsTestUtil.transform(linkstamps.toList(), CcLinkingContext.Linkstamp::getArtifact)); |
| } |
| |
| @Test |
| public void testPassesThroughLinkstamps() throws Exception { |
| scratch.file( |
| "x/BUILD", |
| """ |
| objc_library( |
| name = "foo", |
| deps = [":bar"], |
| ) |
| |
| cc_library( |
| name = "bar", |
| linkstamp = "bar.cc", |
| ) |
| """); |
| |
| assertThat( |
| linkstampExecPaths( |
| getConfiguredTarget("//x:foo") |
| .get(CcInfo.PROVIDER) |
| .getCcLinkingContext() |
| .getLinkstamps())) |
| .containsExactly("x/bar.cc"); |
| } |
| |
| @Test |
| public void testCompileLanguageApi() throws Exception { |
| String fragments = " fragments = ['google_cpp', 'cpp'],"; |
| if (AnalysisMock.get().isThisBazel()) { |
| fragments = " fragments = ['cpp'],"; |
| } |
| scratch.file("myinfo/myinfo.bzl", "MyInfo = provider()"); |
| scratch.file("myinfo/BUILD"); |
| scratch.overwriteFile("tools/build_defs/foo/BUILD"); |
| scratch.file( |
| "tools/build_defs/foo/extension.bzl", |
| "load('//myinfo:myinfo.bzl', 'MyInfo')", |
| "def _objc_starlark_library_impl(ctx):", |
| " toolchain = ctx.attr._my_cc_toolchain[cc_common.CcToolchainInfo]", |
| " features = ['objc-compile']", |
| " features.extend(ctx.features)", |
| " feature_configuration = cc_common.configure_features(", |
| " ctx = ctx,", |
| " cc_toolchain=toolchain,", |
| " requested_features = features,", |
| " unsupported_features = ctx.disabled_features)", |
| " foo_dict = {'string_variable': 'foo',", |
| " 'string_sequence_variable' : ['foo'],", |
| " 'string_depset_variable': depset(['foo'])}", |
| " (compilation_context, compilation_outputs) = cc_common.compile(", |
| " actions=ctx.actions,", |
| " feature_configuration=feature_configuration,", |
| " cc_toolchain=toolchain,", |
| " srcs=ctx.files.srcs,", |
| " name=ctx.label.name + '_suffix',", |
| " language='objc'", |
| " )", |
| " (linking_context,", |
| " linking_outputs) = cc_common.create_linking_context_from_compilation_outputs(", |
| " actions=ctx.actions,", |
| " feature_configuration=feature_configuration,", |
| " compilation_outputs=compilation_outputs,", |
| " name = ctx.label.name,", |
| " cc_toolchain=toolchain,", |
| " language='c++'", |
| " )", |
| " files_to_build = []", |
| " files_to_build.extend(compilation_outputs.pic_objects)", |
| " files_to_build.extend(compilation_outputs.objects)", |
| " library_to_link = None", |
| " if len(ctx.files.srcs) > 0:", |
| " library_to_link = linking_outputs.library_to_link", |
| " if library_to_link.pic_static_library != None:", |
| " files_to_build.append(library_to_link.pic_static_library)", |
| " files_to_build.append(library_to_link.dynamic_library)", |
| " return [MyInfo(libraries=[library_to_link]),", |
| " DefaultInfo(files=depset(files_to_build)),", |
| " CcInfo(compilation_context=compilation_context,", |
| " linking_context=linking_context)]", |
| "objc_starlark_library = rule(", |
| " implementation = _objc_starlark_library_impl,", |
| " attrs = {", |
| " 'srcs': attr.label_list(allow_files=True),", |
| " '_my_cc_toolchain': attr.label(default =", |
| " '//a:alias')", |
| " },", |
| fragments, |
| ")"); |
| scratch.file( |
| "foo/BUILD", |
| """ |
| load("//tools/build_defs/foo:extension.bzl", "objc_starlark_library") |
| |
| objc_starlark_library( |
| name = "starlark_lib", |
| srcs = ["starlark_lib.m"], |
| ) |
| """); |
| scratch.file("a/BUILD", "cc_toolchain_alias(name='alias')"); |
| getConfiguredTarget("//foo:starlark_lib"); |
| assertNoEvents(); |
| } |
| |
| @Test |
| public void testCcTestUsesStaticLibraries() throws Exception { |
| scratch.file( |
| "x/BUILD", |
| """ |
| cc_test( |
| name = "test", |
| deps = [":foo"], |
| ) |
| |
| objc_library( |
| name = "foo", |
| deps = [":bar"], |
| ) |
| |
| cc_library( |
| name = "bar", |
| srcs = [ |
| "bar.a", |
| "bar.so", |
| ], |
| ) |
| """); |
| |
| assertThat( |
| artifactsToStrings( |
| getGeneratingAction( |
| getConfiguredTarget("//x:test") |
| .getProvider(FilesToRunProvider.class) |
| .getExecutable()) |
| .getInputs())) |
| .contains("src x/bar.a"); |
| } |
| |
| @Test |
| public void testPassesDependenciesStaticLibrariesInCcInfo() throws Exception { |
| scratch.file( |
| "x/BUILD", |
| """ |
| objc_library( |
| name = "baz", |
| srcs = ["baz.mm"], |
| ) |
| |
| objc_library( |
| name = "foo", |
| srcs = ["foo.mm"], |
| deps = [":baz"], |
| ) |
| |
| cc_library( |
| name = "bar", |
| srcs = ["bar.cc"], |
| deps = [":foo"], |
| ) |
| """); |
| |
| CcInfo ccInfo = getConfiguredTarget("//x:bar").get(CcInfo.PROVIDER); |
| |
| assertThat( |
| artifactsToStrings( |
| ccInfo.getCcLinkingContext().getLinkerInputs().toList().stream() |
| .map(LinkerInput::getLibraries) |
| .flatMap(List::stream) |
| .map(LibraryToLink::getStaticLibrary) |
| .collect(toImmutableList()))) |
| .contains("/ x/libbaz.a"); |
| } |
| |
| @Test |
| public void testGrepIncludesPassed() throws Exception { |
| if (analysisMock.isThisBazel()) { |
| return; |
| } |
| scratch.file( |
| "x/BUILD", |
| """ |
| objc_library( |
| name = "foo", |
| srcs = ["foo.mm"], |
| ) |
| """); |
| |
| CppCompileAction compileA = (CppCompileAction) compileAction("//x:foo", "foo.o"); |
| assertThat(compileA.getGrepIncludes()).isNotNull(); |
| } |
| |
| @Test |
| public void testModuleMapFileAccessed() throws Exception { |
| scratch.file( |
| "x/BUILD", |
| """ |
| objc_library( |
| name = "foo", |
| srcs = ["foo.mm"], |
| enable_modules = True, |
| module_map = "foo.modulemap", |
| ) |
| """); |
| |
| getConfiguredTarget("//x:foo"); |
| } |
| |
| @Test |
| public void correctToolFilesUsed() throws Exception { |
| scratch.file( |
| "a/BUILD", |
| """ |
| cc_toolchain_alias(name = "a") |
| |
| objc_library( |
| name = "l", |
| srcs = ["l.m"], |
| ) |
| |
| objc_library( |
| name = "asm", |
| srcs = ["a.s"], |
| ) |
| |
| objc_library( |
| name = "preprocessed-asm", |
| srcs = ["a.S"], |
| ) |
| """); |
| useConfiguration("--incompatible_use_specific_tool_files"); |
| |
| ConfiguredTarget target = getConfiguredTarget("//a:a"); |
| CcToolchainProvider toolchainProvider = target.get(CcToolchainProvider.PROVIDER); |
| |
| RuleConfiguredTarget libTarget = (RuleConfiguredTarget) getConfiguredTarget("//a:l"); |
| ActionAnalysisMetadata archiveAction = |
| libTarget.getActions().stream() |
| .filter((a) -> a.getMnemonic().equals("CppArchive")) |
| .collect(onlyElement()); |
| assertThat(archiveAction.getInputs().toList()) |
| .containsAtLeastElementsIn(toolchainProvider.getArFiles().toList()); |
| |
| ActionAnalysisMetadata objcCompileAction = |
| libTarget.getActions().stream() |
| .filter((a) -> a.getMnemonic().equals("ObjcCompile")) |
| .collect(onlyElement()); |
| assertThat(objcCompileAction.getInputs().toList()) |
| .containsAtLeastElementsIn(toolchainProvider.getCompilerFiles().toList()); |
| |
| ActionAnalysisMetadata asmAction = |
| ((RuleConfiguredTarget) getConfiguredTarget("//a:asm")) |
| .getActions().stream() |
| .filter((a) -> a.getMnemonic().equals("CppCompile")) |
| .collect(onlyElement()); |
| assertThat(asmAction.getInputs().toList()) |
| .containsAtLeastElementsIn(toolchainProvider.getAsFiles().toList()); |
| |
| ActionAnalysisMetadata preprocessedAsmAction = |
| ((RuleConfiguredTarget) getConfiguredTarget("//a:preprocessed-asm")) |
| .getActions().stream() |
| .filter((a) -> a.getMnemonic().equals("CppCompile")) |
| .collect(onlyElement()); |
| assertThat(preprocessedAsmAction.getInputs().toList()) |
| .containsAtLeastElementsIn(toolchainProvider.getCompilerFiles().toList()); |
| } |
| |
| /** b/197608223 */ |
| @Test |
| public void testCompilationPrerequisitesHasHeaders() throws Exception { |
| scratch.file( |
| "bin/BUILD", |
| """ |
| objc_library( |
| name = "objc", |
| srcs = ["objc.m"], |
| deps = [":cc"], |
| ) |
| |
| cc_library( |
| name = "cc", |
| srcs = ["cc.cc"], |
| hdrs = ["cc.h"], |
| ) |
| """); |
| |
| useConfiguration( |
| "--apple_platform_type=ios", |
| "--cpu=ios_x86_64", |
| "--platforms=" + MockObjcSupport.IOS_X86_64); |
| |
| ConfiguredTarget cc = getConfiguredTarget("//bin:objc"); |
| |
| assertThat( |
| artifactsToStrings( |
| cc.get(OutputGroupInfo.STARLARK_CONSTRUCTOR) |
| .getOutputGroup(OutputGroupInfo.COMPILATION_PREREQUISITES))) |
| .contains("src bin/cc.h"); |
| } |
| |
| @Test |
| public void testCoptsLocationIsExpanded() throws Exception { |
| scratch.file( |
| "bin/BUILD", |
| "objc_library(", |
| " name = 'lib',", |
| " copts = ['$(rootpath lib1.m) $(location lib2.m) $(location data.data) $(execpath" |
| + " header.h)'],", |
| " srcs = ['lib1.m'],", |
| " non_arc_srcs = ['lib2.m'],", |
| " data = ['data.data', 'lib2.m'],", |
| " hdrs = ['header.h'],", |
| ")"); |
| |
| useConfiguration( |
| "--apple_platform_type=ios", |
| "--cpu=ios_x86_64", |
| "--platforms=" + MockObjcSupport.IOS_X86_64); |
| |
| CppCompileAction compileA = (CppCompileAction) compileAction("//bin:lib", "lib1.o"); |
| assertThat(compileA.compileCommandLine.getCopts()) |
| .containsAtLeast("bin/lib1.m", "bin/lib2.m", "bin/data.data", "bin/header.h"); |
| } |
| |
| @Test |
| public void testCoptsLocationWhenNotExpanded_throwsAssertionError() throws Exception { |
| scratch.file( |
| "bin/BUILD", |
| """ |
| objc_library( |
| name = "lib", |
| srcs = ["lib1.m"], |
| hdrs = ["header.h"], |
| copts = ["$(execpath lib2.m)"], |
| ) |
| """); |
| |
| useConfiguration( |
| "--apple_platform_type=ios", |
| "--cpu=ios_x86_64", |
| "--platforms=" + MockObjcSupport.IOS_X86_64); |
| |
| assertThrows(AssertionError.class, () -> compileAction("//bin:lib", "lib1.o")); |
| } |
| |
| @Test |
| public void testEnableCoveragePropagatesSupportFiles() throws Exception { |
| scratch.file( |
| "a/BUILD", |
| """ |
| cc_toolchain_alias(name = "toolchain") |
| |
| objc_library( |
| name = "lib", |
| ) |
| """); |
| useConfiguration("--collect_code_coverage", "--instrumentation_filter=//a[:/]"); |
| |
| CcToolchainProvider ccToolchainProvider = |
| getConfiguredTarget("//a:toolchain").get(CcToolchainProvider.PROVIDER); |
| InstrumentedFilesInfo instrumentedFilesInfo = |
| getConfiguredTarget("//a:lib").get(InstrumentedFilesInfo.STARLARK_CONSTRUCTOR); |
| |
| assertThat(instrumentedFilesInfo.getCoverageSupportFiles().toList()).isNotEmpty(); |
| assertThat(instrumentedFilesInfo.getCoverageSupportFiles().toList()) |
| .containsExactlyElementsIn(ccToolchainProvider.getCoverageFiles().toList()); |
| } |
| |
| @Test |
| public void testDisableCoverageDoesNotPropagateSupportFiles() throws Exception { |
| scratch.file( |
| "a/BUILD", |
| """ |
| cc_toolchain_alias(name = "toolchain") |
| |
| objc_library( |
| name = "lib", |
| ) |
| """); |
| |
| InstrumentedFilesInfo instrumentedFilesInfo = |
| getConfiguredTarget("//a:lib").get(InstrumentedFilesInfo.STARLARK_CONSTRUCTOR); |
| |
| assertThat(instrumentedFilesInfo.getCoverageSupportFiles().toList()).isEmpty(); |
| } |
| |
| @Test |
| public void testCoverageMetadataFiles() throws Exception { |
| scratch.file( |
| "a/BUILD", |
| """ |
| cc_toolchain_alias(name = "toolchain") |
| |
| objc_library( |
| name = "foo", |
| srcs = ["foo.m"], |
| ) |
| |
| objc_library( |
| name = "bar", |
| srcs = ["bar.m"], |
| deps = [":foo"], |
| ) |
| """); |
| useConfiguration("--collect_code_coverage", "--instrumentation_filter=//a[:/]"); |
| |
| InstrumentedFilesInfo instrumentedFilesInfo = |
| getConfiguredTarget("//a:bar").get(InstrumentedFilesInfo.STARLARK_CONSTRUCTOR); |
| |
| assertThat( |
| Artifact.toRootRelativePaths(instrumentedFilesInfo.getInstrumentationMetadataFiles())) |
| .containsExactly("a/_objs/foo/arc/foo.gcno", "a/_objs/bar/arc/bar.gcno"); |
| } |
| |
| private ImmutableList<String> getCcInfoUserLinkFlagsFromTarget(String target) |
| throws LabelSyntaxException { |
| return getConfiguredTarget(target) |
| .get(CcInfo.PROVIDER) |
| .getCcLinkingContext() |
| .getUserLinkFlags() |
| .toList() |
| .stream() |
| .map(CcLinkingContext.LinkOptions::get) |
| .flatMap(List::stream) |
| .collect(toImmutableList()); |
| } |
| |
| @Test |
| public void testSdkUserLinkFlagsFromSdkFieldsAndLinkoptsArePropagatedOnCcInfo() throws Exception { |
| scratch.file( |
| "x/BUILD", |
| """ |
| objc_library( |
| name = "foo", |
| linkopts = [ |
| "-lxml2", |
| "-framework AVFoundation", |
| "-Wl,-framework,Framework", |
| ], |
| sdk_dylibs = ["libz"], |
| sdk_frameworks = ["CoreData"], |
| deps = [ |
| ":bar", |
| ":car", |
| ], |
| ) |
| |
| objc_library( |
| name = "bar", |
| linkopts = [ |
| "-lsqlite3", |
| "-Wl,-weak_framework,WeakFrameworkFromLinkOpt", |
| ], |
| sdk_frameworks = ["Foundation"], |
| ) |
| |
| objc_library( |
| name = "car", |
| linkopts = [ |
| "-framework UIKit", |
| ], |
| sdk_dylibs = ["libc++"], |
| weak_sdk_frameworks = ["WeakFramework"], |
| ) |
| """); |
| |
| ImmutableList<String> userLinkFlags = getCcInfoUserLinkFlagsFromTarget("//x:foo"); |
| assertThat(userLinkFlags).isNotEmpty(); |
| assertThat(userLinkFlags).containsAtLeast("-framework", "AVFoundation").inOrder(); |
| assertThat(userLinkFlags).containsAtLeast("-framework", "CoreData").inOrder(); |
| assertThat(userLinkFlags).containsAtLeast("-framework", "Foundation").inOrder(); |
| assertThat(userLinkFlags).containsAtLeast("-framework", "UIKit").inOrder(); |
| assertThat(userLinkFlags).containsAtLeast("-lz", "-lc++", "-lxml2", "-lsqlite3"); |
| assertThat(userLinkFlags).containsAtLeast("-framework", "Framework").inOrder(); |
| assertThat(userLinkFlags).containsAtLeast("-weak_framework", "WeakFramework").inOrder(); |
| assertThat(userLinkFlags) |
| .containsAtLeast("-weak_framework", "WeakFrameworkFromLinkOpt") |
| .inOrder(); |
| } |
| |
| @Test |
| public void testTreeArtifactSrcs() throws Exception { |
| doTestTreeAtrifactInAttributes("srcs"); |
| } |
| |
| @Test |
| public void testTreeArtifactNonArcSrcs() throws Exception { |
| doTestTreeAtrifactInAttributes("non_arc_srcs"); |
| } |
| |
| @Test |
| public void testTreeArtifactHdrs() throws Exception { |
| doTestTreeAtrifactInAttributes("hdrs"); |
| } |
| |
| private void doTestTreeAtrifactInAttributes(String attrName) throws Exception { |
| reporter.removeHandler(failFastHandler); |
| scratch.file( |
| "bar/create_tree_artifact.bzl", |
| """ |
| def _impl(ctx): |
| tree = ctx.actions.declare_directory("dir") |
| ctx.actions.run_shell( |
| outputs = [tree], |
| inputs = [], |
| arguments = [tree.path], |
| command = "mkdir $1", |
| ) |
| return [DefaultInfo(files = depset([tree]))] |
| |
| create_tree_artifact = rule(implementation = _impl) |
| """); |
| scratch.file( |
| "bar/BUILD", |
| "load(':create_tree_artifact.bzl', 'create_tree_artifact')", |
| "create_tree_artifact(name = 'tree_artifact')", |
| "objc_library(", |
| " name = 'lib',", |
| " " + attrName + " = [':tree_artifact'],", |
| ")"); |
| |
| getConfiguredTarget("//bar:lib"); |
| |
| assertNoEvents(); |
| } |
| } |