aboutsummaryrefslogtreecommitdiffhomepage
path: root/src/test/java/com/google/devtools/build/lib/rules/objc/ObjcLibraryTest.java
diff options
context:
space:
mode:
authorGravatar cpeyser <cpeyser@google.com>2017-07-05 18:03:47 -0400
committerGravatar John Cater <jcater@google.com>2017-07-06 07:14:09 -0400
commit478f763599828f88724ee8b3e59f38539cbdd73d (patch)
treecb3f07a7e5ac4b8590a5331e494ed4f4f0be85fb /src/test/java/com/google/devtools/build/lib/rules/objc/ObjcLibraryTest.java
parent6508e317b76ef2f26cff5d95a4a82c13a1913b78 (diff)
Open source unit tests for the objc rules.
PiperOrigin-RevId: 161010594
Diffstat (limited to 'src/test/java/com/google/devtools/build/lib/rules/objc/ObjcLibraryTest.java')
-rw-r--r--src/test/java/com/google/devtools/build/lib/rules/objc/ObjcLibraryTest.java1542
1 files changed, 1542 insertions, 0 deletions
diff --git a/src/test/java/com/google/devtools/build/lib/rules/objc/ObjcLibraryTest.java b/src/test/java/com/google/devtools/build/lib/rules/objc/ObjcLibraryTest.java
new file mode 100644
index 0000000000..40a2c83edc
--- /dev/null
+++ b/src/test/java/com/google/devtools/build/lib/rules/objc/ObjcLibraryTest.java
@@ -0,0 +1,1542 @@
+// 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.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.FILE_IN_SRCS_AND_HDRS_WARNING_FORMAT;
+import static com.google.devtools.build.lib.rules.objc.ObjcProvider.ASSET_CATALOG;
+import static com.google.devtools.build.lib.rules.objc.ObjcProvider.BUNDLE_FILE;
+import static com.google.devtools.build.lib.rules.objc.ObjcProvider.CC_LIBRARY;
+import static com.google.devtools.build.lib.rules.objc.ObjcProvider.HEADER;
+import static com.google.devtools.build.lib.rules.objc.ObjcProvider.LIBRARY;
+import static com.google.devtools.build.lib.rules.objc.ObjcProvider.SDK_DYLIB;
+import static com.google.devtools.build.lib.rules.objc.ObjcProvider.WEAK_SDK_FRAMEWORK;
+import static com.google.devtools.build.lib.rules.objc.ObjcProvider.XCASSETS_DIR;
+import static com.google.devtools.build.lib.rules.objc.ObjcRuleClasses.NON_ARC_SRCS_TYPE;
+import static com.google.devtools.build.lib.rules.objc.ObjcRuleClasses.SRCS_TYPE;
+import static org.junit.Assert.fail;
+
+import com.google.common.base.Joiner;
+import com.google.common.collect.ImmutableList;
+import com.google.common.collect.Iterables;
+import com.google.devtools.build.lib.actions.Action;
+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.util.ActionsTestUtil;
+import com.google.devtools.build.lib.analysis.ConfiguredTarget;
+import com.google.devtools.build.lib.analysis.RunfilesProvider;
+import com.google.devtools.build.lib.analysis.actions.ParameterFileWriteAction;
+import com.google.devtools.build.lib.analysis.config.CompilationMode;
+import com.google.devtools.build.lib.analysis.util.ScratchAttributeWriter;
+import com.google.devtools.build.lib.packages.NoSuchTargetException;
+import com.google.devtools.build.lib.packages.util.MockObjcSupport;
+import com.google.devtools.build.lib.rules.apple.AppleToolchain;
+import com.google.devtools.build.lib.rules.apple.Platform;
+import com.google.devtools.build.lib.rules.cpp.CppCompileAction;
+import com.google.devtools.build.lib.rules.cpp.CppModuleMapAction;
+import com.google.devtools.build.lib.vfs.PathFragment;
+import com.google.devtools.common.options.OptionsParsingException;
+import java.util.Collections;
+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 {
+
+ static final RuleType RULE_TYPE = new OnlyNeedsSourcesRuleType("objc_library");
+ private static final String WRAPPED_CLANG = "wrapped_clang";
+
+ /**
+ * Middleman artifact arising from //tools/osx/crosstool:link, containing tools that should be
+ * inputs to link actions.
+ */
+ private static final String CROSSTOOL_LINK_MIDDLEMAN = "tools_Sosx_Scrosstool_Clink";
+
+ /** Creates an {@code objc_library} target writer. */
+ @Override
+ protected ScratchAttributeWriter createLibraryTargetWriter(String labelString) {
+ return ScratchAttributeWriter.fromLabelString(this, "objc_library", labelString);
+ }
+
+ @Test
+ public void testFilesToBuild() throws Exception {
+ useConfiguration("--crosstool_top=" + MockObjcSupport.DEFAULT_OSX_CROSSTOOL);
+ ConfiguredTarget target =
+ createLibraryTargetWriter("//objc:One")
+ .setAndCreateFiles("srcs", "a.m", "b.m", "private.h")
+ .write();
+
+ Iterable<Artifact> files = getFilesToBuild(target);
+ assertThat(Artifact.toRootRelativePaths(files)).containsExactly("objc/libOne.a");
+ }
+
+ @Test
+ public void testCompilesSources() throws Exception {
+ useConfiguration("--crosstool_top=" + MockObjcSupport.DEFAULT_OSX_CROSSTOOL);
+ 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.getPossibleInputsForTesting()))
+ .containsAllOf("objc/a.m", "objc/hdr.h", "objc/private.h");
+ assertThat(Artifact.toRootRelativePaths(compileA.getOutputs()))
+ .containsExactly("objc/_objs/x/objc/a.o", "objc/_objs/x/objc/a.d");
+ }
+
+ @Test
+ public void testObjcPlusPlusCompile() throws Exception {
+ useConfiguration(
+ "--crosstool_top=" + MockObjcSupport.DEFAULT_OSX_CROSSTOOL,
+ "--experimental_disable_go",
+ "--cpu=ios_i386",
+ "--ios_cpu=i386",
+ "--ios_minimum_os=9.10.11");
+ createLibraryTargetWriter("//objc:lib")
+ .setList("srcs", "a.mm")
+ .write();
+ CommandAction compileAction = compileAction("//objc:lib", "a.o");
+ assertThat(compileAction.getArguments())
+ .containsAllOf("-stdlib=libc++", "-std=gnu++11", "-mios-simulator-version-min=9.10.11");
+ }
+
+ @Test
+ public void testObjcPlusPlusCompileDarwin() throws Exception {
+ useConfiguration(
+ "--crosstool_top=" + MockObjcSupport.DEFAULT_OSX_CROSSTOOL,
+ "--experimental_disable_go",
+ "--cpu=darwin_x86_64",
+ "--macos_minimum_os=9.10.11",
+ // TODO(b/36126423): Darwin should imply macos, so the
+ // following line should not be necessary.
+ "--apple_platform_type=macos",
+ "--experimental_objc_crosstool=all");
+ createLibraryTargetWriter("//objc:lib")
+ .setList("srcs", "a.mm")
+ .write();
+ CommandAction compileAction = compileAction("//objc:lib", "a.o");
+ assertThat(compileAction.getArguments())
+ .containsAllOf("-stdlib=libc++", "-std=gnu++11", "-mmacosx-version-min=9.10.11");
+ }
+
+ @Test
+ public void testCompilationModeDbg() throws Exception {
+ useConfiguration(
+ "--crosstool_top=" + MockObjcSupport.DEFAULT_OSX_CROSSTOOL,
+ "--experimental_disable_go",
+ "--cpu=ios_i386",
+ "--ios_cpu=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(
+ "--crosstool_top=" + MockObjcSupport.DEFAULT_OSX_CROSSTOOL,
+ "--experimental_disable_go",
+ "--cpu=ios_i386",
+ "--ios_cpu=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(
+ "--crosstool_top=" + MockObjcSupport.DEFAULT_OSX_CROSSTOOL,
+ "--experimental_disable_go",
+ "--cpu=ios_i386",
+ "--ios_cpu=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();
+ ObjcProvider provider = providerForTarget("//lib:lib");
+ assertThat(provider.get(LIBRARY))
+ .containsExactlyElementsIn(archiveAction("//baselib:baselib").getOutputs());
+ }
+
+ @Test
+ public void testCreate_errorForEmptyFilegroupSources() throws Exception {
+ checkError(
+ "x",
+ "x",
+ "does not produce any objc_library srcs files (expected " + SRCS_TYPE + ")",
+ "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_warningForOverlappingSrcsAndHdrs() throws Exception {
+ scratch.file("/x/a.h", "dummy header file");
+ checkWarning(
+ "x",
+ "x",
+ String.format(FILE_IN_SRCS_AND_HDRS_WARNING_FORMAT, "x/a.h"),
+ "objc_library(name = 'x', srcs = ['a.h'], hdrs = ['a.h'])");
+ }
+
+ @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",
+ "'//x:cc.cc' does not produce any objc_library non_arc_srcs files (expected "
+ + NON_ARC_SRCS_TYPE
+ + ")",
+ "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(Artifact.toRootRelativePaths(target.getProvider(ObjcProvider.class).get(HEADER)))
+ .containsExactly("objc/a.h", "objc/b.h", "objc/f.m");
+ assertThat(Artifact.toRootRelativePaths(depender.getProvider(ObjcProvider.class).get(HEADER)))
+ .containsExactly("objc/a.h", "objc/b.h", "objc/f.m", "objc2/d.h", "objc2/e.m");
+ }
+
+ @Test
+ public void testNonPropagatedDepsProvider() throws Exception {
+ ConfiguredTarget target =
+ createLibraryTargetWriter("//objc:lib")
+ .setAndCreateFiles("srcs", "a.m", "b.m", "private.h")
+ .setAndCreateFiles("hdrs", "a.h", "b.h")
+ .write();
+ createLibraryTargetWriter("//objc2:lib")
+ .setAndCreateFiles("srcs", "a.m", "b.m", "private.h")
+ .setAndCreateFiles("hdrs", "c.h", "d.h")
+ .setList("non_propagated_deps", "//objc:lib")
+ .write();
+ ConfiguredTarget transitiveDepender =
+ createLibraryTargetWriter("//objc3:lib")
+ .setAndCreateFiles("srcs", "a.m", "b.m", "private.h")
+ .setAndCreateFiles("hdrs", "e.h", "f.h")
+ .setList("non_propagated_deps", "//objc2:lib")
+ .write();
+
+ assertThat(Artifact.toRootRelativePaths(target.getProvider(ObjcProvider.class).get(HEADER)))
+ .containsExactly("objc/a.h", "objc/b.h");
+ assertThat(
+ Artifact.toRootRelativePaths(
+ transitiveDepender.getProvider(ObjcProvider.class).get(HEADER)))
+ .containsExactly("objc2/c.h", "objc2/d.h", "objc3/e.h", "objc3/f.h");
+ }
+
+ @Test
+ public void testMultiPlatformLibrary() throws Exception {
+ useConfiguration("--ios_multi_cpus=i386,x86_64,armv7,arm64", "--ios_cpu=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(
+ "--crosstool_top=" + MockObjcSupport.DEFAULT_OSX_CROSSTOOL,
+ "--experimental_disable_go",
+ "--cpu=ios_i386",
+ "--ios_cpu=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())
+ .containsAllOf("-isysroot", AppleToolchain.sdkDir()).inOrder();
+ assertThat(Collections.frequency(compileActionA.getArguments(),
+ "-F" + AppleToolchain.sdkDir() + "/Developer/Library/Frameworks")).isEqualTo(1);
+ assertThat(Collections.frequency(compileActionA.getArguments(),
+ "-F" + frameworkDir(Platform.IOS_SIMULATOR))).isEqualTo(1);
+ assertThat(compileActionA.getArguments())
+ .containsAllIn(AppleToolchain.DEFAULT_WARNINGS.values());
+ assertThat(compileActionA.getArguments())
+ .containsAllIn(CompilationSupport.DEFAULT_COMPILER_FLAGS);
+ assertThat(compileActionA.getArguments())
+ .containsAllIn(CompilationSupport.SIMULATOR_COMPILE_FLAGS);
+ assertThat(compileActionA.getArguments()).contains("-fobjc-arc");
+ assertThat(compileActionA.getArguments()).containsAllOf("-c", "objc/a.m");
+ assertThat(compileActionNonArc.getArguments()).contains("-fno-objc-arc");
+ assertThat(compileActionA.getArguments()).containsAllIn(FASTBUILD_COPTS);
+ assertThat(compileActionA.getArguments())
+ .contains("-mios-simulator-version-min=" + DEFAULT_IOS_SDK_VERSION);
+ assertThat(compileActionA.getArguments()).contains("-arch i386");
+ }
+
+ @Test
+ public void testCompilationActions_device() throws Exception {
+ useConfiguration(
+ "--crosstool_top=" + MockObjcSupport.DEFAULT_OSX_CROSSTOOL,
+ "--experimental_disable_go",
+ "--cpu=ios_armv7",
+ "--ios_cpu=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())
+ .containsAllOf("-isysroot", AppleToolchain.sdkDir()).inOrder();
+ assertThat(Collections.frequency(compileActionA.getArguments(),
+ "-F" + AppleToolchain.sdkDir() + "/Developer/Library/Frameworks")).isEqualTo(1);
+ assertThat(Collections.frequency(compileActionA.getArguments(),
+ "-F" + frameworkDir(Platform.IOS_DEVICE))).isEqualTo(1);
+ assertThat(compileActionA.getArguments())
+ .containsAllIn(AppleToolchain.DEFAULT_WARNINGS.values());
+ assertThat(compileActionA.getArguments())
+ .containsAllIn(CompilationSupport.DEFAULT_COMPILER_FLAGS);
+ assertThat(compileActionA.getArguments())
+ .containsNoneIn(CompilationSupport.SIMULATOR_COMPILE_FLAGS);
+
+ assertThat(compileActionA.getArguments()).contains("-fobjc-arc");
+ assertThat(compileActionA.getArguments()).containsAllOf("-c", "objc/a.m");
+
+ assertThat(compileActionNonArc.getArguments()).contains("-fno-objc-arc");
+ assertThat(compileActionA.getArguments()).containsAllIn(FASTBUILD_COPTS);
+ assertThat(compileActionA.getArguments())
+ .contains("-miphoneos-version-min=" + DEFAULT_IOS_SDK_VERSION);
+ assertThat(compileActionA.getArguments()).contains("-arch armv7");
+ }
+
+ @Test
+ public void testArchivesPrecompiledObjectFiles() throws Exception {
+ useConfiguration("--crosstool_top=" + MockObjcSupport.DEFAULT_OSX_CROSSTOOL);
+ 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 testCompileWithFrameworkImportsIncludesFlagsAndInputArtifacts() throws Exception {
+ useConfiguration("--crosstool_top=" + MockObjcSupport.DEFAULT_OSX_CROSSTOOL);
+ addBinWithTransitiveDepOnFrameworkImport();
+ CommandAction compileAction = compileAction("//lib:lib", "a.o");
+
+ assertThat(compileAction.getArguments()).doesNotContain("-framework");
+ assertThat(Joiner.on("").join(compileAction.getArguments())).contains("-Ffx");
+ assertThat(compileAction.getInputs())
+ .containsAllOf(
+ getSourceArtifact("fx/fx1.framework/a"),
+ getSourceArtifact("fx/fx1.framework/b"),
+ getSourceArtifact("fx/fx2.framework/c"),
+ getSourceArtifact("fx/fx2.framework/d"));
+ }
+
+ @Test
+ public void testPrecompiledHeaders() throws Exception {
+ useConfiguration("--crosstool_top=" + MockObjcSupport.DEFAULT_OSX_CROSSTOOL);
+ 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(
+ "--crosstool_top=" + MockObjcSupport.DEFAULT_OSX_CROSSTOOL,
+ "--cpu=ios_i386",
+ "--ios_cpu=i386",
+ "--experimental_disable_go");
+ createLibraryTargetWriter("//objc:lib")
+ .setAndCreateFiles("srcs", "a.m", "b.m", "private.h")
+ .setAndCreateFiles("hdrs", "c.h")
+ .setList("copts", "-Ifoo", "--monkeys=$(TARGET_CPU)")
+ .write();
+
+ CommandAction compileActionA = compileAction("//objc:lib", "a.o");
+ assertThat(compileActionA.getArguments()).containsAllOf("-Ifoo", "--monkeys=ios_i386");
+ }
+
+ @Test
+ public void testObjcCopts() throws Exception {
+ useConfiguration(
+ "--crosstool_top=" + MockObjcSupport.DEFAULT_OSX_CROSSTOOL,
+ "--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(
+ "--crosstool_top=" + MockObjcSupport.DEFAULT_OSX_CROSSTOOL,
+ "--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).containsAllOf("-fobjc-arc", "-foo", "-bar").inOrder();
+ }
+
+ @Test
+ public void testCompilationActionsWithModuleMapsEnabled() throws Exception {
+ useConfiguration(
+ "--crosstool_top=" + MockObjcSupport.DEFAULT_OSX_CROSSTOOL,
+ "--experimental_objc_enable_module_maps");
+ createLibraryTargetWriter("//objc:lib")
+ .setAndCreateFiles("srcs", "a.m", "b.m", "private.h")
+ .setAndCreateFiles("hdrs", "c.h")
+ .write();
+
+ CommandAction compileActionA = compileAction("//objc:lib", "a.o");
+ assertThat(compileActionA.getArguments())
+ .containsAllIn(moduleMapArtifactArguments("//objc", "lib"));
+ assertThat(compileActionA.getArguments()).contains("-fmodule-maps");
+ assertThat(Artifact.toRootRelativePaths(compileActionA.getInputs()))
+ .doesNotContain("objc/lib.modulemaps/module.modulemap");
+ }
+
+ @Test
+ public void testCompilationActionsWithEmbeddedBitcode() throws Exception {
+ useConfiguration(
+ "--xcode_version=7.1",
+ "--ios_multi_cpus=arm64",
+ "--apple_bitcode=embedded");
+ createLibraryTargetWriter("//objc:lib")
+ .setAndCreateFiles("srcs", "a.m", "b.m", "private.h")
+ .setAndCreateFiles("hdrs", "c.h")
+ .write();
+
+ CommandAction compileActionA = compileAction("//objc:lib", "a.o");
+
+ assertThat(compileActionA.getArguments()).contains("-fembed-bitcode");
+ }
+
+ @Test
+ public void testCompilationActionsWithEmbeddedBitcodeMarkers() throws Exception {
+ useConfiguration(
+ "--xcode_version=7.1",
+ "--ios_multi_cpus=arm64",
+ "--apple_bitcode=embedded_markers");
+
+ createLibraryTargetWriter("//objc:lib")
+ .setAndCreateFiles("srcs", "a.m", "b.m", "private.h")
+ .setAndCreateFiles("hdrs", "c.h")
+ .write();
+
+ CommandAction compileActionA = compileAction("//objc:lib", "a.o");
+
+ assertThat(compileActionA.getArguments()).contains("-fembed-bitcode-marker");
+ }
+
+ @Test
+ public void testCompilationActionsWithNoBitcode() throws Exception {
+ useConfiguration(
+ "--crosstool_top=" + MockObjcSupport.DEFAULT_OSX_CROSSTOOL,
+ "--xcode_version=7.1",
+ "--ios_multi_cpus=arm64",
+ "--apple_bitcode=none");
+
+ createLibraryTargetWriter("//objc:lib")
+ .setAndCreateFiles("srcs", "a.m", "b.m", "private.h")
+ .setAndCreateFiles("hdrs", "c.h")
+ .write();
+
+ CommandAction compileActionA = compileAction("//objc:lib", "a.o");
+
+ assertThat(compileActionA.getArguments()).doesNotContain("-fembed-bitcode");
+ assertThat(compileActionA.getArguments()).doesNotContain("-fembed-bitcode-marker");
+ }
+
+ /**
+ * Tests that bitcode is disabled for simulator builds even if enabled by flag.
+ */
+ @Test
+ public void testCompilationActionsWithBitcode_simulator() throws Exception {
+ useConfiguration(
+ "--crosstool_top=" + MockObjcSupport.DEFAULT_OSX_CROSSTOOL,
+ "--xcode_version=7.1",
+ "--ios_multi_cpus=x86_64",
+ "--apple_bitcode=embedded");
+
+ createLibraryTargetWriter("//objc:lib")
+ .setAndCreateFiles("srcs", "a.m", "b.m", "private.h")
+ .setAndCreateFiles("hdrs", "c.h")
+ .write();
+
+ CommandAction compileActionA = compileAction("//objc:lib", "a.o");
+
+ assertThat(compileActionA.getArguments()).doesNotContain("-fembed-bitcode");
+ assertThat(compileActionA.getArguments()).doesNotContain("-fembed-bitcode-marker");
+ }
+
+ @Test
+ public void testModuleMapActionFiltersHeaders() throws Exception {
+ RULE_TYPE.scratchTarget(
+ scratch,
+ "srcs",
+ "['a.m', 'b.m', 'private.h', 'private.inc']",
+ "hdrs",
+ "['a.h', 'x.inc', 'foo.m', 'bar.mm']");
+
+ ConfiguredTarget configuredTarget = getConfiguredTarget("//x:x");
+ Artifact moduleMap = getGenfilesArtifact("x.modulemaps/module.modulemap", configuredTarget);
+
+ CppModuleMapAction genMap = (CppModuleMapAction) getGeneratingAction(moduleMap);
+
+ assertThat(Artifact.toRootRelativePaths(genMap.getPrivateHeaders())).isEmpty();
+ assertThat(Artifact.toRootRelativePaths(genMap.getPublicHeaders())).containsExactly("x/a.h");
+ }
+
+ @Test
+ public void testArchiveAction_simulator() throws Exception {
+ useConfiguration(
+ "--crosstool_top=" + MockObjcSupport.DEFAULT_OSX_CROSSTOOL,
+ "--experimental_disable_go",
+ "--cpu=ios_i386",
+ "--ios_cpu=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/libtool",
+ "-static",
+ "-filelist",
+ getBinArtifact("lib-archive.objlist", "//objc:lib").getExecPathString(),
+ "-arch_only",
+ "i386",
+ "-syslibroot",
+ AppleToolchain.sdkDir(),
+ "-o",
+ Iterables.getOnlyElement(archiveAction.getOutputs()).getExecPathString()));
+ assertThat(baseArtifactNames(archiveAction.getInputs()))
+ .containsAllOf("a.o", "b.o", "lib-archive.objlist", CROSSTOOL_LINK_MIDDLEMAN);
+ assertThat(baseArtifactNames(archiveAction.getOutputs())).containsExactly("liblib.a");
+ assertRequiresDarwin(archiveAction);
+ }
+
+ @Test
+ public void testArchiveAction_device() throws Exception {
+ useConfiguration(
+ "--crosstool_top=" + MockObjcSupport.DEFAULT_OSX_CROSSTOOL,
+ "--experimental_disable_go",
+ "--cpu=ios_armv7",
+ "--ios_cpu=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/libtool",
+ "-static",
+ "-filelist",
+ getBinArtifact("lib-archive.objlist", "//objc:lib").getExecPathString(),
+ "-arch_only",
+ "armv7",
+ "-syslibroot",
+ AppleToolchain.sdkDir(),
+ "-o",
+ Iterables.getOnlyElement(archiveAction.getOutputs()).getExecPathString()));
+ assertThat(baseArtifactNames(archiveAction.getInputs()))
+ .containsAllOf("a.o", "b.o", "lib-archive.objlist");
+ assertThat(baseArtifactNames(archiveAction.getOutputs())).containsExactly("liblib.a");
+ assertRequiresDarwin(archiveAction);
+ }
+
+ @Test
+ public void testFullyLinkArchiveAction_simulator() throws Exception {
+ useConfiguration(
+ "--crosstool_top=" + MockObjcSupport.DEFAULT_OSX_CROSSTOOL,
+ "--experimental_disable_go",
+ "--cpu=ios_i386",
+ "--ios_cpu=i386");
+ createLibraryTargetWriter("//objc:lib_dep")
+ .setAndCreateFiles("srcs", "a.m", "b.m", "private.h")
+ .setAndCreateFiles("hdrs", "a.h", "b.h")
+ .write();
+ createLibraryTargetWriter("//objc2:lib")
+ .setAndCreateFiles("srcs", "a.m", "b.m", "private.h")
+ .setAndCreateFiles("hdrs", "c.h", "d.h")
+ .setList("deps", "//objc:lib_dep")
+ .write();
+ CommandAction linkAction =
+ (CommandAction) getGeneratingActionForLabel("//objc2:lib_fully_linked.a");
+ assertRequiresDarwin(linkAction);
+ assertThat(linkAction.getArguments())
+ .isEqualTo(
+ ImmutableList.of(
+ "tools/osx/crosstool/iossim/libtool",
+ "-static",
+ "-arch_only",
+ "i386",
+ "-syslibroot",
+ AppleToolchain.sdkDir(),
+ "-o",
+ Iterables.getOnlyElement(linkAction.getOutputs()).getExecPathString(),
+ getBinArtifact("liblib.a", "//objc2:lib").getExecPathString(),
+ getBinArtifact("liblib_dep.a", "//objc:lib_dep").getExecPathString()));
+ // TODO(hlopko): make containsExactly once crosstools are updated so
+ // link_dynamic_library.sh is not needed anymore
+ assertThat(baseArtifactNames(linkAction.getInputs())).containsAllOf(
+ "liblib_dep.a",
+ "liblib.a",
+ CROSSTOOL_LINK_MIDDLEMAN);
+ }
+
+ @Test
+ public void testFullyLinkArchiveAction_device() throws Exception {
+ useConfiguration(
+ "--crosstool_top=" + MockObjcSupport.DEFAULT_OSX_CROSSTOOL,
+ "--experimental_disable_go",
+ "--cpu=ios_armv7",
+ "--ios_cpu=armv7");
+ createLibraryTargetWriter("//objc:lib_dep")
+ .setAndCreateFiles("srcs", "a.m", "b.m", "private.h")
+ .setAndCreateFiles("hdrs", "a.h", "b.h")
+ .write();
+ createLibraryTargetWriter("//objc2:lib")
+ .setAndCreateFiles("srcs", "a.m", "b.m", "private.h")
+ .setAndCreateFiles("hdrs", "c.h", "d.h")
+ .setList("deps", "//objc:lib_dep")
+ .write();
+ CommandAction linkAction =
+ (CommandAction) getGeneratingActionForLabel("//objc2:lib_fully_linked.a");
+ assertRequiresDarwin(linkAction);
+ assertThat(linkAction.getArguments())
+ .isEqualTo(
+ ImmutableList.of(
+ "tools/osx/crosstool/ios/libtool",
+ "-static",
+ "-arch_only",
+ "armv7",
+ "-syslibroot",
+ AppleToolchain.sdkDir(),
+ "-o",
+ Iterables.getOnlyElement(linkAction.getOutputs()).getExecPathString(),
+ getBinArtifact("liblib.a", "//objc2:lib").getExecPathString(),
+ getBinArtifact("liblib_dep.a", "//objc:lib_dep").getExecPathString()));
+ // TODO(hlopko): make containsExactly once crosstools are updated so
+ // link_dynamic_library.sh is not needed anymore
+ assertThat(baseArtifactNames(linkAction.getInputs())).containsAllOf(
+ "liblib_dep.a",
+ "liblib.a",
+ CROSSTOOL_LINK_MIDDLEMAN);
+ }
+
+ @Test
+ public void checkDoesNotStoreObjcLibsAsCC() throws Exception {
+ createLibraryTargetWriter("//objc:lib_dep")
+ .setAndCreateFiles("srcs", "a.m", "b.m", "private.h")
+ .setAndCreateFiles("hdrs", "a.h", "b.h")
+ .write();
+ createLibraryTargetWriter("//objc2:lib")
+ .setAndCreateFiles("srcs", "a.m", "b.m", "private.h")
+ .setAndCreateFiles("hdrs", "c.h", "d.h")
+ .setList("deps", "//objc:lib_dep")
+ .write();
+ ObjcProvider objcProvider = providerForTarget("//objc2:lib");
+ assertThat(objcProvider.get(CC_LIBRARY)).isEmpty();
+ }
+
+ @Test
+ public void testIncludesDirsGetPassedToCompileAction() throws Exception {
+ useConfiguration("--crosstool_top=" + MockObjcSupport.DEFAULT_OSX_CROSSTOOL);
+ 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(
+ getAppleCrosstoolConfiguration(), "third_party/foo", "lib/opensource/bar")) {
+ assertThat(Joiner.on("").join(compileAction.getArguments())).contains("-I" + path);
+ }
+ }
+
+ @Test
+ public void testPropagatesDefinesToDependersTransitively() throws Exception {
+ useConfiguration(
+ "--crosstool_top=" + MockObjcSupport.DEFAULT_OSX_CROSSTOOL,
+ "--experimental_disable_go",
+ "--cpu=ios_x86_64",
+ "--ios_cpu=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();
+ createBinaryTargetWriter("//bin:bin")
+ .setAndCreateFiles("srcs", "c.m")
+ .setList("deps", "//lib2:lib2")
+ .write();
+
+ assertThat(compileAction("//lib1:lib1", "a.o").getArguments())
+ .containsAllOf("-DA=foo", "-DB", "-DMONKEYS=ios_x86_64")
+ .inOrder();
+ assertThat(compileAction("//lib1:lib1", "b.o").getArguments())
+ .containsAllOf("-DA=foo", "-DB", "-DMONKEYS=ios_x86_64")
+ .inOrder();
+ assertThat(compileAction("//lib2:lib2", "a.o").getArguments())
+ .containsAllOf("-DA=foo", "-DB", "-DMONKEYS=ios_x86_64", "-DC=bar", "-DD")
+ .inOrder();
+ assertThat(compileAction("//lib2:lib2", "b.o").getArguments())
+ .containsAllOf("-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 {
+ useConfiguration("--crosstool_top=" + MockObjcSupport.DEFAULT_OSX_CROSSTOOL);
+ 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 {
+ useConfiguration(
+ "--crosstool_top=" + MockObjcSupport.DEFAULT_OSX_CROSSTOOL);
+ 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 testAssetCatalogsAttributeErrorForNotInXcAssetsDir() throws Exception {
+ useConfiguration("--crosstool_top=" + MockObjcSupport.DEFAULT_OSX_CROSSTOOL);
+ scratch.file("lib/ac/notinxcassets1");
+ scratch.file("lib/ac/notinxcassets2");
+ scratch.file("lib/ac/foo.xcassets/isinxcassets");
+ checkError("lib", "lib",
+ String.format(ObjcCommon.NOT_IN_CONTAINER_ERROR_FORMAT,
+ "lib/ac/notinxcassets2", ImmutableList.of(ObjcCommon.ASSET_CATALOG_CONTAINER_TYPE)),
+ "objc_library(name = 'lib', srcs = ['src.m'], asset_catalogs = glob(['ac/**']))");
+ }
+
+ @Test
+ public void testXcdatamodelsAttributeErrorForNotInXcdatamodelDir() throws Exception {
+ useConfiguration("--crosstool_top=" + MockObjcSupport.DEFAULT_OSX_CROSSTOOL);
+ scratch.file("lib/xcd/notinxcdatamodel1");
+ scratch.file("lib/xcd/notinxcdatamodel2");
+ scratch.file("lib/xcd/foo.xcdatamodel/isinxcdatamodel");
+ scratch.file("lib/xcd/bar.xcdatamodeld/isinxcdatamodeld");
+ checkError("lib", "lib",
+ String.format(ObjcCommon.NOT_IN_CONTAINER_ERROR_FORMAT,
+ "lib/xcd/notinxcdatamodel1", Xcdatamodels.CONTAINER_TYPES),
+ "objc_library(name = 'lib', srcs = ['src.m'], datamodels = glob(['xcd/**']))");
+ }
+
+ @Test
+ public void testProvidesStoryboardOptions() throws Exception {
+ checkProvidesStoryboardObjects(RULE_TYPE);
+ }
+
+ @Test
+ public void testDoesNotUseCxxUnfilteredFlags() throws Exception {
+ useConfiguration("--crosstool_top=" + MockObjcSupport.DEFAULT_OSX_CROSSTOOL);
+ 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(
+ "--crosstool_top=" + MockObjcSupport.DEFAULT_OSX_CROSSTOOL,
+ "--objc_use_dotd_pruning=false");
+ createLibraryTargetWriter("//lib:lib")
+ .setList("srcs", "a.m")
+ .write();
+ CppCompileAction compileAction = (CppCompileAction) compileAction("//lib:lib", "a.o");
+ assertThat(compileAction.discoverInputsFromDotdFiles(null, null, null)).isEmpty();
+ }
+
+ @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 depender =
+ createLibraryTargetWriter("//objc2:lib")
+ .setAndCreateFiles("srcs", "a.m", "b.m", "private.h")
+ .setAndCreateFiles("hdrs", "c.h", "d.h")
+ .setList("deps", "//objc:lib")
+ .write();
+ assertThat(Artifact.toRootRelativePaths(target.getProvider(ObjcProvider.class).get(LIBRARY)))
+ .containsExactly("objc/liblib.a");
+ assertThat(Artifact.toRootRelativePaths(depender.getProvider(ObjcProvider.class).get(LIBRARY)))
+ .containsExactly("objc/liblib.a", "objc2/liblib.a");
+ assertThat(Artifact.toRootRelativePaths(target.getProvider(ObjcProvider.class).get(HEADER)))
+ .containsExactly("objc/a.h", "objc/b.h");
+ assertThat(Artifact.toRootRelativePaths(depender.getProvider(ObjcProvider.class).get(HEADER)))
+ .containsExactly("objc/a.h", "objc/b.h", "objc2/c.h", "objc2/d.h");
+ }
+
+ @Test
+ public void testWeakSdkFrameworks_objcProvider() 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();
+
+ ObjcProvider baseProvider = providerForTarget("//base_lib:lib");
+ ObjcProvider dependerProvider = providerForTarget("//depender_lib:lib");
+
+ assertThat(baseProvider.get(WEAK_SDK_FRAMEWORK)).containsExactly(new SdkFramework("foo"));
+ assertThat(dependerProvider.get(WEAK_SDK_FRAMEWORK))
+ .containsExactly(new SdkFramework("foo"), new SdkFramework("bar"));
+ }
+
+ @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();
+ try {
+ reporter.removeHandler(failFastHandler);
+ getTarget("//lib:liblib.a");
+ fail("should have thrown");
+ } catch (NoSuchTargetException expected) {
+ }
+ }
+
+ @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 testExportsBundleDependencies() throws Exception {
+ scratch.file("bundle/bar/x.bundle/1");
+ scratch.file(
+ "bundle/BUILD",
+ "objc_bundle(",
+ " name = 'bundle',",
+ " bundle_imports = glob(['bar/**']),",
+ ")");
+ createLibraryTargetWriter("//lib:lib")
+ .setAndCreateFiles("srcs", "a.m", "b.m", "private.h")
+ .setList("bundles", "//bundle:bundle")
+ .write();
+ ObjcProvider provider = providerForTarget("//lib:lib");
+ assertThat(provider.get(BUNDLE_FILE))
+ .contains(new BundleableFile(getSourceArtifact("bundle/bar/x.bundle/1"), "x.bundle/1"));
+ }
+
+ @Test
+ public void testDylibsProvided() throws Exception {
+ createLibraryTargetWriter("//lib:lib")
+ .setAndCreateFiles("srcs", "a.m", "b.m", "private.h")
+ .setList("sdk_dylibs", "libdy1", "libdy2")
+ .write();
+ ObjcProvider provider = providerForTarget("//lib:lib");
+ assertThat(provider.get(SDK_DYLIB)).containsExactly("libdy1", "libdy2").inOrder();
+ }
+
+ @Test
+ public void testPopulatesCompilationArtifacts() throws Exception {
+ checkPopulatesCompilationArtifacts(RULE_TYPE);
+ }
+
+ @Test
+ public void testProvidesXcassetCatalogsTransitively() throws Exception {
+ scratch.file("lib1/ac.xcassets/foo");
+ scratch.file("lib1/ac.xcassets/bar");
+ createLibraryTargetWriter("//lib1:lib1")
+ .setAndCreateFiles("srcs", "a.m", "b.m", "private.h")
+ .set("asset_catalogs", "glob(['ac.xcassets/**'])")
+ .write();
+ scratch.file("lib2/ac.xcassets/baz");
+ scratch.file("lib2/ac.xcassets/42");
+ createLibraryTargetWriter("//lib2:lib2")
+ .setAndCreateFiles("srcs", "a.m", "b.m", "private.h")
+ .set("asset_catalogs", "glob(['ac.xcassets/**'])")
+ .setList("deps", "//lib1:lib1")
+ .write();
+
+ ObjcProvider lib2Provider = providerForTarget("//lib2:lib2");
+ assertThat(Artifact.toExecPaths(lib2Provider.get(ASSET_CATALOG)))
+ .containsExactly(
+ "lib1/ac.xcassets/foo",
+ "lib1/ac.xcassets/bar",
+ "lib2/ac.xcassets/baz",
+ "lib2/ac.xcassets/42");
+ assertThat(lib2Provider.get(XCASSETS_DIR))
+ .containsExactly(
+ PathFragment.create("lib1/ac.xcassets"), PathFragment.create("lib2/ac.xcassets"));
+
+ ObjcProvider lib1Provider = providerForTarget("//lib1:lib1");
+ assertThat(Artifact.toExecPaths(lib1Provider.get(ASSET_CATALOG)))
+ .containsExactly("lib1/ac.xcassets/foo", "lib1/ac.xcassets/bar");
+ assertThat(lib1Provider.get(XCASSETS_DIR))
+ .containsExactly(PathFragment.create("lib1/ac.xcassets"))
+ .inOrder();
+ }
+
+ @Test
+ public void testObjcListFileInArchiveGeneration() throws Exception {
+ scratch.file("lib/a.m");
+ scratch.file("lib/b.m");
+ scratch.file("lib/BUILD", "objc_library(name = 'lib1', srcs = ['a.m', 'b.m'])");
+ ConfiguredTarget target = getConfiguredTarget("//lib:lib1");
+ Artifact objlist = getBinArtifact("lib1-archive.objlist", target);
+ ParameterFileWriteAction action = (ParameterFileWriteAction) getGeneratingAction(objlist);
+ assertThat(action.getContents())
+ .containsExactlyElementsIn(
+ Artifact.toExecPaths(inputsEndingWith(archiveAction("//lib:lib1"), ".o")));
+ }
+
+ @Test
+ public void testErrorsWrongFileTypeForSrcsWhenCompiling() throws Exception {
+ checkErrorsWrongFileTypeForSrcsWhenCompiling(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 testCompilationActionsForOptimized() throws Exception {
+ checkClangCoptsForCompilationMode(RULE_TYPE, CompilationMode.OPT, CodeCoverageMode.NONE);
+ }
+
+ @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 testWarningForBlacklistedTypesInHeaders() throws Exception {
+ checkWarningForBlacklistedTypesInHeaders(RULE_TYPE);
+ }
+
+ @Test
+ public void testBundleInformationPropagatedThroughLibraries() throws Exception {
+ checkNestedBundleInformationPropagatedToDependers(RULE_TYPE);
+ }
+
+ @Test
+ public void testAppleSdkVersionEnv() throws Exception {
+ createLibraryTargetWriter("//objc:lib")
+ .setAndCreateFiles("srcs", "a.m", "b.m", "private.h")
+ .setAndCreateFiles("hdrs", "c.h")
+ .write();
+ CommandAction action = compileAction("//objc:lib", "a.o");
+
+ assertAppleSdkVersionEnv(action);
+ }
+
+ @Test
+ public void testNonDefaultAppleSdkVersionEnv() throws Exception {
+ useConfiguration("--ios_sdk_version=8.1");
+
+ createLibraryTargetWriter("//objc:lib")
+ .setAndCreateFiles("srcs", "a.m", "b.m", "private.h")
+ .setAndCreateFiles("hdrs", "c.h")
+ .write();
+ CommandAction action = compileAction("//objc:lib", "a.o");
+
+ assertAppleSdkVersionEnv(action, "8.1");
+ }
+
+ @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() throws Exception {
+ try {
+ useConfiguration("--ios_sdk_version=");
+ fail("Should fail for empty ios_sdk_version");
+ } catch (OptionsParsingException e) {
+ 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 testUsesDotdPruning() throws Exception {
+ useConfiguration(
+ "--crosstool_top=" + MockObjcSupport.DEFAULT_OSX_CROSSTOOL, "--objc_use_dotd_pruning");
+ createLibraryTargetWriter("//lib:lib").setList("srcs", "a.m").write();
+ CppCompileAction compileAction = (CppCompileAction) compileAction("//lib:lib", "a.o");
+ try {
+ compileAction.discoverInputsFromDotdFiles(null, null, null);
+ fail("Expected ActionExecutionException");
+ } catch (ActionExecutionException expected) {
+ assertThat(expected).hasMessageThat().contains("error while parsing .d file");
+ }
+ }
+
+ @Test
+ public void testAppleSdkDefaultPlatformEnv() throws Exception {
+ 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("--cpu=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");
+ }
+
+ @Test
+ public void testApplePlatformEnvForCcLibraryDep() throws Exception {
+ useConfiguration(
+ "--experimental_disable_go", "--experimental_disable_jvm", "--cpu=ios_i386",
+ "--crosstool_top=//tools/osx/crosstool:crosstool");
+
+ scratch.file("package/BUILD",
+ "cc_library(",
+ " name = 'cc_lib',",
+ " srcs = ['a.cc'],",
+ ")",
+ "",
+ "objc_binary(",
+ " name = 'objc_bin',",
+ " srcs = ['b.m'],",
+ " deps = [':cc_lib'],",
+ ")");
+
+ Action binLinkAction = linkAction("//package:objc_bin");
+ Artifact artifact =
+ ActionsTestUtil.getFirstArtifactEndingWith(binLinkAction.getInputs(), "libcc_lib.a");
+ Action cppLibLinkAction = getGeneratingAction(artifact);
+ Artifact cppLibArtifact =
+ ActionsTestUtil.getFirstArtifactEndingWith(cppLibLinkAction.getInputs(), ".o");
+
+ CppCompileAction action = (CppCompileAction) getGeneratingAction(cppLibArtifact);
+ assertAppleSdkVersionEnv(action.getEnvironment());
+ }
+
+ @Test
+ public void testDoesNotPropagateProtoIncludes() throws Exception {
+ useConfiguration("--crosstool_top=" + MockObjcSupport.DEFAULT_OSX_CROSSTOOL);
+ scratch.file(
+ "x/BUILD",
+ "proto_library(",
+ " name = 'protos',",
+ " srcs = ['data.proto'],",
+ ")",
+ "objc_proto_library(",
+ " name = 'objc_proto_lib',",
+ " deps = [':protos'],",
+ " portable_proto_filters = ['data_filter.pbascii'],",
+ ")");
+ createLibraryTargetWriter("//a:lib")
+ .setList("srcs", "a.m")
+ .setList("deps", "//x:objc_proto_lib")
+ .write();
+ createLibraryTargetWriter("//b:lib").setList("srcs", "b.m").setList("deps", "//a:lib").write();
+
+ CommandAction compileAction1 = compileAction("//a:lib", "a.o");
+ CommandAction compileAction2 = compileAction("//b:lib", "b.o");
+
+ assertThat(Joiner.on(" ").join(compileAction1.getArguments())).contains("objc_proto_lib");
+ assertThat(Joiner.on(" ").join(compileAction2.getArguments())).doesNotContain("objc_proto_lib");
+ }
+
+ @Test
+ public void testExportsJ2ObjcProviders() throws Exception {
+ useConfiguration("--crosstool_top=" + MockObjcSupport.DEFAULT_OSX_CROSSTOOL);
+ ConfiguredTarget lib = createLibraryTargetWriter("//a:lib").write();
+ assertThat(lib.getProvider(J2ObjcEntryClassProvider.class)).isNotNull();
+ assertThat(lib.getProvider(J2ObjcMappingFileProvider.class)).isNotNull();
+ }
+
+ @Test
+ public void testObjcProtoLibraryDoesNotCrash() throws Exception {
+ useConfiguration(
+ "--crosstool_top=" + MockObjcSupport.DEFAULT_OSX_CROSSTOOL,
+ "--experimental_objc_crosstool=all");
+ scratch.file(
+ "x/BUILD",
+ "objc_library(",
+ " name = 'objc',",
+ " srcs = ['source.m'],",
+ " deps = [':objc_proto_lib'],",
+ ")",
+ "proto_library(",
+ " name = 'protos',",
+ " srcs = ['data.proto'],",
+ ")",
+ "objc_proto_library(",
+ " name = 'objc_proto_lib',",
+ " deps = [':protos'],",
+ " portable_proto_filters = ['data_filter.pbascii'],",
+ ")");
+ assertThat(getConfiguredTarget("//x:objc")).isNotNull();
+ }
+
+ @Test
+ public void testLegacyObjcProtoLibraryDoesNotCrash() throws Exception {
+ useConfiguration(
+ "--crosstool_top=" + MockObjcSupport.DEFAULT_OSX_CROSSTOOL,
+ "--experimental_objc_crosstool=all");
+ scratch.file(
+ "x/BUILD",
+ "objc_library(",
+ " name = 'objc',",
+ " srcs = ['source.m'],",
+ " deps = [':objc_proto_lib'],",
+ ")",
+ "proto_library(",
+ " name = 'protos',",
+ " srcs = ['data.proto'],",
+ ")",
+ "objc_proto_library(",
+ " name = 'objc_proto_lib',",
+ " deps = [':protos'],",
+ ")");
+ assertThat(getConfiguredTarget("//x:objc")).isNotNull();
+ }
+
+ @Test
+ public void testObjcImportDoesNotCrash() throws Exception {
+ useConfiguration(
+ "--crosstool_top=" + MockObjcSupport.DEFAULT_OSX_CROSSTOOL,
+ "--experimental_objc_crosstool=all");
+ 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(
+ "--crosstool_top=" + MockObjcSupport.DEFAULT_OSX_CROSSTOOL,
+ "--experimental_disable_go",
+ "--cpu=ios_i386",
+ "--ios_cpu=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(
+ "--crosstool_top=" + MockObjcSupport.DEFAULT_OSX_CROSSTOOL, "--collect_code_coverage");
+ createLibraryTargetWriter("//objc:x")
+ .setAndCreateFiles("srcs", "a.mm", "b.cc", "c.mm", "d.cxx", "e.c", "f.m", "g.C")
+ .write();
+ List<String> copts = ImmutableList.of("-fprofile-arcs", "-ftest-coverage");
+ assertThat(compileAction("//objc:x", "a.o").getArguments()).containsAllIn(copts);
+ assertThat(compileAction("//objc:x", "b.o").getArguments()).containsAllIn(copts);
+ assertThat(compileAction("//objc:x", "c.o").getArguments()).containsAllIn(copts);
+ assertThat(compileAction("//objc:x", "d.o").getArguments()).containsAllIn(copts);
+ assertThat(compileAction("//objc:x", "e.o").getArguments()).containsAllIn(copts);
+ assertThat(compileAction("//objc:x", "f.o").getArguments()).containsAllIn(copts);
+ assertThat(compileAction("//objc:x", "g.o").getArguments()).containsAllIn(copts);
+ }
+
+ @Test
+ public void testCollectCodeCoverageWithLLVMCOVFlags() throws Exception {
+ useConfiguration(
+ "--crosstool_top=" + MockObjcSupport.DEFAULT_OSX_CROSSTOOL,
+ "--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();
+ List<String> copts = ImmutableList.of("-fprofile-instr-generate", "-fcoverage-mapping");
+ assertThat(compileAction("//objc:x", "a.o").getArguments()).containsAllIn(copts);
+ assertThat(compileAction("//objc:x", "b.o").getArguments()).containsAllIn(copts);
+ assertThat(compileAction("//objc:x", "c.o").getArguments()).containsAllIn(copts);
+ assertThat(compileAction("//objc:x", "d.o").getArguments()).containsAllIn(copts);
+ assertThat(compileAction("//objc:x", "e.o").getArguments()).containsAllIn(copts);
+ assertThat(compileAction("//objc:x", "f.o").getArguments()).containsAllIn(copts);
+ assertThat(compileAction("//objc:x", "g.o").getArguments()).containsAllIn(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 testSysrootArgSpecifiedWithGrteTopFlag() throws Exception {
+ MockObjcSupport.setup(mockToolsConfig, "default_grte_top : '//x'");
+ useConfiguration(
+ "--crosstool_top=" + MockObjcSupport.DEFAULT_OSX_CROSSTOOL,
+ "--experimental_disable_go",
+ "--experimental_objc_crosstool=all",
+ "--cpu=ios_x86_64",
+ "--ios_cpu=x86_64");
+ scratch.file(
+ "x/BUILD",
+ "objc_library(",
+ " name = 'objc',",
+ " srcs = ['source.m'],",
+ ")",
+ "filegroup(",
+ " name = 'everything',",
+ " srcs = ['header.h'],",
+ ")");
+ CommandAction compileAction = compileAction("//x:objc", "source.o");
+ assertThat(compileAction.getArguments()).contains("--sysroot=x");
+ }
+
+ @Test
+ public void testDefaultEnabledFeatureIsUsed() throws Exception {
+ MockObjcSupport.setup(mockToolsConfig,
+ "feature {",
+ " name: 'default'",
+ " enabled : true",
+ " flag_set {",
+ " action: 'objc-compile'",
+ " flag_group {",
+ " flag: '-dummy'",
+ " }",
+ " }",
+ "}");
+ useConfiguration(
+ "--crosstool_top=" + MockObjcSupport.DEFAULT_OSX_CROSSTOOL,
+ "--experimental_disable_go",
+ "--experimental_objc_crosstool=all",
+ "--cpu=ios_x86_64",
+ "--ios_cpu=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");
+ }
+}