blob: 9f27fd9a919d6dd48ef36ab7f9763407299de3cc [file] [log] [blame]
// 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.devtools.build.lib.actions.util.ActionsTestUtil.baseArtifactNames;
import static com.google.devtools.build.lib.actions.util.ActionsTestUtil.getFirstArtifactEndingWith;
import static com.google.devtools.build.lib.rules.python.PythonTestUtils.getPyLoad;
import com.google.common.base.Joiner;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.ImmutableSet;
import com.google.common.collect.Iterables;
import com.google.devtools.build.lib.actions.Action;
import com.google.devtools.build.lib.actions.ActionAnalysisMetadata;
import com.google.devtools.build.lib.actions.ActionExecutionContext;
import com.google.devtools.build.lib.actions.ActionExecutionContext.LostInputsCheck;
import com.google.devtools.build.lib.actions.ActionExecutionException;
import com.google.devtools.build.lib.actions.ActionInputPrefetcher;
import com.google.devtools.build.lib.actions.Artifact;
import com.google.devtools.build.lib.actions.Artifact.SpecialArtifact;
import com.google.devtools.build.lib.actions.Artifact.TreeFileArtifact;
import com.google.devtools.build.lib.actions.CommandAction;
import com.google.devtools.build.lib.actions.CommandLineLimits;
import com.google.devtools.build.lib.actions.CommandLines.ExpandedCommandLines;
import com.google.devtools.build.lib.actions.DiscoveredModulesPruner;
import com.google.devtools.build.lib.actions.PathMapper;
import com.google.devtools.build.lib.actions.ThreadStateReceiver;
import com.google.devtools.build.lib.actions.util.ActionsTestUtil;
import com.google.devtools.build.lib.analysis.ConfiguredTarget;
import com.google.devtools.build.lib.analysis.actions.ParameterFileWriteAction;
import com.google.devtools.build.lib.analysis.actions.SpawnAction;
import com.google.devtools.build.lib.analysis.configuredtargets.RuleConfiguredTarget;
import com.google.devtools.build.lib.cmdline.Label;
import com.google.devtools.build.lib.cmdline.RepositoryName;
import com.google.devtools.build.lib.collect.nestedset.Depset;
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.CppCompileAction;
import com.google.devtools.build.lib.rules.cpp.CppCompileActionTemplate;
import com.google.devtools.build.lib.rules.cpp.CppModuleMapAction;
import com.google.devtools.build.lib.rules.cpp.CppRuleClasses;
import com.google.devtools.build.lib.rules.cpp.UmbrellaHeaderAction;
import com.google.devtools.build.lib.testutil.TestConstants;
import com.google.devtools.build.lib.vfs.FileSystemUtils;
import com.google.devtools.build.lib.vfs.PathFragment;
import com.google.devtools.build.lib.vfs.SyscallCache;
import java.io.ByteArrayOutputStream;
import java.util.Optional;
import java.util.regex.Pattern;
import javax.annotation.Nullable;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.JUnit4;
/**
* Unit test for Java source file translation into ObjC in <code>java_library</code> and translated
* file compilation and linking in {@link ObjcBinary} and {@link J2ObjcLibrary}.
*/
@RunWith(JUnit4.class)
public class BazelJ2ObjcLibraryTest extends J2ObjcLibraryTest {
private static final Provider.Key starlarkJ2objcMappingFileProviderKey =
new StarlarkProvider.Key(
Label.parseCanonicalUnchecked("@_builtins//:common/objc/providers.bzl"),
"J2ObjcMappingFileInfo");
private StructImpl getJ2ObjcMappingFileInfoFromTarget(ConfiguredTarget configuredTarget)
throws Exception {
return (StructImpl) configuredTarget.get(starlarkJ2objcMappingFileProviderKey);
}
private ImmutableList<Artifact> getArtifacts(StructImpl j2ObjcMappingFileInfo, String attribute)
throws Exception {
Depset filesDepset = (Depset) j2ObjcMappingFileInfo.getValue(attribute);
return filesDepset.toList(Artifact.class);
}
@Test
public void testJ2ObjCInformationExportedFromJ2ObjcLibrary() throws Exception {
ConfiguredTarget j2objcLibraryTarget = getConfiguredTarget(
"//java/com/google/dummy/test:transpile");
CcLinkingContext ccLinkingContext =
j2objcLibraryTarget.get(CcInfo.PROVIDER).getCcLinkingContext();
assertThat(baseArtifactNames(ccLinkingContext.getStaticModeParamsForDynamicLibraryLibraries()))
.containsExactly("libjre_core_lib.a", "libtest_j2objc.lo");
CcCompilationContext ccCompilationContext =
j2objcLibraryTarget.get(CcInfo.PROVIDER).getCcCompilationContext();
assertThat(baseArtifactNames(ccCompilationContext.getDeclaredIncludeSrcs()))
.containsExactly("jre_core.h", "test.h");
String execPath = getRuleContext(j2objcLibraryTarget).getBinFragment() + "/";
assertThat(
Iterables.transform(
ccCompilationContext.getIncludeDirs(), PathFragment::getSafePathString))
.containsExactly(execPath + "java/com/google/dummy/test/_j2objc/test");
}
@Test
public void testJ2ObjCAspectDisablesParseHeaders() throws Exception {
MockObjcSupport.setupCcToolchainConfig(
mockToolsConfig, MockObjcSupport.darwinX86_64().withFeatures(CppRuleClasses.PARSE_HEADERS));
useConfiguration("--features=parse_headers", "--process_headers_in_dependencies");
ConfiguredTarget j2objcAspectTarget =
getJ2ObjCAspectConfiguredTarget("//java/com/google/dummy/test:test");
CcCompilationContext ccCompilationContext =
j2objcAspectTarget.get(CcInfo.PROVIDER).getCcCompilationContext();
assertThat(baseArtifactNames(ccCompilationContext.getHeaderTokens().toList()))
.doesNotContain("test.h.processed");
}
@Test
public void testJ2ObjCInformationExportedWithGeneratedJavaSources() throws Exception {
scratch.file("java/com/google/test/in.txt");
scratch.file(
"java/com/google/test/BUILD",
"""
package(default_visibility = ["//visibility:public"])
genrule(
name = "dummy_gen",
srcs = ["in.txt"],
outs = ["test.java"],
cmd = "dummy",
)
java_library(
name = "test",
srcs = [":test.java"],
)
j2objc_library(
name = "transpile",
tags = ["__J2OBJC_LIBRARY_MIGRATION_DO_NOT_USE_WILL_BREAK__"],
deps = ["test"],
)
""");
ConfiguredTarget target = getConfiguredTarget("//java/com/google/test:transpile");
CcLinkingContext ccLinkingContext = target.get(CcInfo.PROVIDER).getCcLinkingContext();
assertThat(baseArtifactNames(ccLinkingContext.getStaticModeParamsForDynamicLibraryLibraries()))
.containsExactly("libjre_core_lib.a", "libtest_j2objc.lo");
CcCompilationContext ccCompilationContext =
target.get(CcInfo.PROVIDER).getCcCompilationContext();
assertThat(baseArtifactNames(ccCompilationContext.getDeclaredIncludeSrcs()))
.containsExactly("jre_core.h", "test.h");
String execPath = getRuleContext(target).getBinFragment() + "/";
String genfilesFragment = getRuleContext(target).getGenfilesFragment().toString();
assertThat(
Iterables.transform(
ccCompilationContext.getIncludeDirs(), PathFragment::getSafePathString))
.containsExactly(
execPath + "java/com/google/test/_j2objc/test/" + genfilesFragment,
execPath + "java/com/google/test/_j2objc/test");
}
@Test
public void testJ2ObjcProtoRuntimeLibraryAndHeadersExported() throws Exception {
scratch.file("java/com/google/dummy/test/proto/test.java");
scratch.file("java/com/google/dummy/test/proto/test.proto");
scratch.file(
"java/com/google/dummy/test/proto/BUILD",
TestConstants.LOAD_PROTO_LIBRARY,
"package(default_visibility=['//visibility:public'])",
"proto_library(",
" name = 'test_proto',",
" srcs = ['test.proto'],",
")",
"java_proto_library(",
" name = 'test_java_proto',",
" deps = [':test_proto'],",
")",
"java_library(",
" name = 'test',",
" srcs = ['test.java'],",
" deps = [':test_java_proto']",
")",
"j2objc_library(",
" name = 'transpile',",
" deps = ['test'],",
" tags = ['__J2OBJC_LIBRARY_MIGRATION_DO_NOT_USE_WILL_BREAK__'],",
")");
ConfiguredTarget j2objcLibraryTarget = getConfiguredTarget(
"//java/com/google/dummy/test/proto:transpile");
CcLinkingContext ccLinkingContext =
j2objcLibraryTarget.get(CcInfo.PROVIDER).getCcLinkingContext();
assertThat(baseArtifactNames(ccLinkingContext.getStaticModeParamsForDynamicLibraryLibraries()))
.containsExactly(
"libjre_core_lib.a",
"libproto_runtime.a",
"libtest_j2objc.lo",
"libtest_proto_j2objc.lo");
CcCompilationContext ccCompilationContext =
j2objcLibraryTarget.get(CcInfo.PROVIDER).getCcCompilationContext();
assertThat(baseArtifactNames(ccCompilationContext.getDeclaredIncludeSrcs()))
.containsExactly("jre_core.h", "runtime.h", "test.j2objc.pb.h", "test.h");
}
@Test
public void testJ2ObjcHeaderMapExportedInJavaLibrary() throws Exception {
scratch.file(
"java/com/google/transpile/BUILD",
"""
java_library(
name = "dummy",
srcs = ["dummy.java"],
)
""");
ConfiguredTarget target = getJ2ObjCAspectConfiguredTarget("//java/com/google/transpile:dummy");
StructImpl j2ObjcMappingFileInfo = getJ2ObjcMappingFileInfoFromTarget(target);
ImmutableList<Artifact> headerMappingFilesList =
getArtifacts(j2ObjcMappingFileInfo, "header_mapping_files");
assertThat(headerMappingFilesList.get(0).getRootRelativePath().toString())
.isEqualTo("java/com/google/transpile/dummy.mapping.j2objc");
}
@Test
public void testDepsJ2ObjcHeaderMapExportedInJavaLibraryWithNoSourceFile() throws Exception {
scratch.file(
"java/com/google/transpile/BUILD",
"""
java_library(
name = "dummy",
exports = ["//java/com/google/dep"],
)
""");
scratch.file(
"java/com/google/dep/BUILD",
"""
java_library(
name = "dep",
srcs = ["dummy.java"],
)
""");
ConfiguredTarget target = getJ2ObjCAspectConfiguredTarget("//java/com/google/transpile:dummy");
StructImpl j2ObjcMappingFileInfo = getJ2ObjcMappingFileInfoFromTarget(target);
ImmutableList<Artifact> headerMappingFilesList =
getArtifacts(j2ObjcMappingFileInfo, "header_mapping_files");
assertThat(headerMappingFilesList.get(0).getRootRelativePath().toString())
.isEqualTo("java/com/google/dep/dep.mapping.j2objc");
}
@Test
public void testJ2ObjcProtoClassMappingFilesExportedInJavaLibrary() throws Exception {
scratch.file("java/com/google/dummy/test/proto/test.java");
scratch.file("java/com/google/dummy/test/proto/test.proto");
scratch.file(
"java/com/google/dummy/test/proto/BUILD",
TestConstants.LOAD_PROTO_LIBRARY,
"package(default_visibility=['//visibility:public'])",
"proto_library(",
" name = 'test_proto',",
" srcs = ['test.proto'],",
")",
"java_proto_library(",
" name = 'test_java_proto',",
" deps = [':test_proto'],",
")",
"java_library(",
" name = 'test',",
" srcs = ['test.java'],",
" deps = [':test_java_proto']",
")");
ConfiguredTarget target = getJ2ObjCAspectConfiguredTarget(
"//java/com/google/dummy/test/proto:test");
StructImpl j2ObjcMappingFileInfo = getJ2ObjcMappingFileInfoFromTarget(target);
ImmutableList<Artifact> classMappingFilesList =
getArtifacts(j2ObjcMappingFileInfo, "class_mapping_files");
assertThat(classMappingFilesList.get(0).getExecPathString())
.containsMatch(
"/darwin_x86_64-fastbuild-applebin_macos-ST-[^/]*/bin/java/com/google/dummy/test/proto/test.clsmap.properties");
}
@Test
public void testJavaProtoLibraryWithProtoLibrary() throws Exception {
scratch.file(
"x/BUILD",
TestConstants.LOAD_PROTO_LIBRARY,
"proto_library(",
" name = 'test_proto',",
" srcs = ['test.proto'],",
")",
"java_proto_library(",
" name = 'test_java_proto',",
" deps = [':test_proto'],",
")",
"java_library(",
" name = 'test',",
" srcs = ['test.java'],",
" deps = [':test_java_proto']",
")");
ConfiguredTarget target = getJ2ObjCAspectConfiguredTarget("//x:test");
StructImpl j2ObjcMappingFileInfo = getJ2ObjcMappingFileInfoFromTarget(target);
ImmutableList<Artifact> classMappingFilesList =
getArtifacts(j2ObjcMappingFileInfo, "class_mapping_files");
assertThat(classMappingFilesList.get(0).getExecPathString())
.containsMatch(
"/darwin_x86_64-fastbuild-applebin_macos-ST-[^/]*/bin/x/test.clsmap.properties");
ObjcProvider objcProvider = target.get(ObjcProvider.STARLARK_CONSTRUCTOR);
CcCompilationContext ccCompilationContext =
target.get(CcInfo.PROVIDER).getCcCompilationContext();
assertThat(ccCompilationContext.getDeclaredIncludeSrcs().toList().toString())
.containsMatch("/darwin_x86_64-fastbuild-applebin_macos-ST-[^/]*/bin]x/test.j2objc.pb.h");
assertThat(objcProvider.get(ObjcProvider.SOURCE).toList().toString())
.containsMatch("/darwin_x86_64-fastbuild-applebin_macos-ST-[^/]*/bin]x/test.j2objc.pb.m,");
}
@Test
public void testJavaProtoLibraryWithProtoLibrary_external() throws Exception {
scratch.file("/bla/WORKSPACE");
// Create the rule '@bla//foo:test_proto'.
scratch.file(
"/bla/foo/BUILD",
TestConstants.LOAD_PROTO_LIBRARY,
"package(default_visibility=['//visibility:public'])",
"proto_library(",
" name = 'test_proto',",
" srcs = ['test.proto'],",
")",
"java_proto_library(",
" name = 'test_java_proto',",
" deps = [':test_proto'])",
"");
String existingWorkspace =
new String(FileSystemUtils.readContentAsLatin1(rootDirectory.getRelative("WORKSPACE")));
scratch.overwriteFile(
"WORKSPACE", "local_repository(name = 'bla', path = '/bla/')", existingWorkspace);
invalidatePackages(); // A dash of magic to re-evaluate the WORKSPACE file.
scratch.file(
"x/BUILD",
"""
java_library(
name = "test",
srcs = ["test.java"],
deps = ["@bla//foo:test_java_proto"],
)
""");
ConfiguredTarget target = getJ2ObjCAspectConfiguredTarget("//x:test");
StructImpl j2ObjcMappingFileInfo = getJ2ObjcMappingFileInfoFromTarget(target);
ImmutableList<Artifact> classMappingFilesList =
getArtifacts(j2ObjcMappingFileInfo, "class_mapping_files");
assertThat(classMappingFilesList.get(0).getExecPathString())
.containsMatch(
"/darwin_x86_64-fastbuild-applebin_macos-ST-[^/]*/bin/external/bla/foo/test.clsmap.properties");
ObjcProvider objcProvider = target.get(ObjcProvider.STARLARK_CONSTRUCTOR);
CcCompilationContext ccCompilationContext =
target.get(CcInfo.PROVIDER).getCcCompilationContext();
assertThat(ccCompilationContext.getDeclaredIncludeSrcs().toList().toString())
.containsMatch(
"/darwin_x86_64-fastbuild-applebin_macos-ST-[^/]*/bin]external/bla/foo/test.j2objc.pb.h");
assertThat(objcProvider.get(ObjcProvider.SOURCE).toList().toString())
.containsMatch(
"/darwin_x86_64-fastbuild-applebin_macos-ST-[^/]*/bin]external/bla/foo/test.j2objc.pb.m");
assertThat(ccCompilationContext.getIncludeDirs())
.contains(
getConfiguration(target)
.getGenfilesFragment(RepositoryName.create("bla"))
.getRelative("external/bla"));
}
@Test
public void testJ2ObjcInfoExportedInJavaImport() throws Exception {
scratch.file(
"java/com/google/transpile/BUILD",
"""
java_import(
name = "dummy",
jars = ["dummy.jar"],
srcjar = "dummy.srcjar",
)
""");
ConfiguredTarget target = getJ2ObjCAspectConfiguredTarget("//java/com/google/transpile:dummy");
StructImpl j2ObjcMappingFileInfo = getJ2ObjcMappingFileInfoFromTarget(target);
ImmutableList<Artifact> headerMappingFilesList =
getArtifacts(j2ObjcMappingFileInfo, "header_mapping_files");
ImmutableList<Artifact> classMappingFilesList =
getArtifacts(j2ObjcMappingFileInfo, "class_mapping_files");
assertThat(headerMappingFilesList.get(0).getRootRelativePath().toString())
.isEqualTo("java/com/google/transpile/dummy.mapping.j2objc");
assertThat(classMappingFilesList).isEmpty();
}
protected Artifact getBinArtifact(String outputName, RuleConfiguredTarget target) {
for (ActionAnalysisMetadata action : target.getActions()) {
Optional<Artifact> artifact =
action.getOutputs().stream().filter(artifactNamed(outputName)).findFirst();
if (artifact.isPresent()) {
return artifact.get();
}
}
return null;
}
protected void checkObjcArchiveAndLinkActions(
String archiveFileName, String objFileName, Iterable<String> compilationInputExecPaths)
throws Exception {
CommandAction linkAction =
(CommandAction)
getGeneratingAction(
getBinArtifact(
"app/app_bin", (RuleConfiguredTarget) getConfiguredTarget("//app:app")));
checkObjcCompileActions(
getFirstArtifactEndingWith(linkAction.getInputs(), archiveFileName),
objFileName, compilationInputExecPaths);
}
@Test
public void testMissingEntryClassesError() throws Exception {
useConfiguration("--j2objc_dead_code_removal");
checkError(
"java/com/google/dummy",
"transpile",
"Entry classes must be specified when flag --compilation_mode=opt is on in order to perform"
+ " J2ObjC dead code stripping.",
"j2objc_library(",
" name = 'transpile',",
" deps = ['//java/com/google/dummy/test:test'],",
" tags = ['__J2OBJC_LIBRARY_MIGRATION_DO_NOT_USE_WILL_BREAK__'],",
")");
}
@Test
public void testNoJ2ObjcDeadCodeRemovalActionWithoutOptFlag() throws Exception {
useConfiguration("--noj2objc_dead_code_removal");
addSimpleJ2ObjcLibraryWithEntryClasses();
addAppleBinaryStarlarkRule(scratch);
addSimpleBinaryTarget("//java/com/google/app/test:transpile");
Artifact expectedPrunedSource = getBinArtifact(
"_j2objc_pruned/app/java/com/google/app/test/_j2objc/test/"
+ "java/com/google/app/test/test_pruned.m", getConfiguredTarget("//app:app"));
assertThat(getGeneratingAction(expectedPrunedSource)).isNull();
}
@Test
public void testExplicitJreDeps() throws Exception {
ConfiguredTarget j2objcLibraryTarget = getConfiguredTarget(
"//java/com/google/dummy/test:transpile");
CcLinkingContext ccLinkingContext =
j2objcLibraryTarget.get(CcInfo.PROVIDER).getCcLinkingContext();
assertThat(baseArtifactNames(ccLinkingContext.getStaticModeParamsForDynamicLibraryLibraries()))
.containsExactly("libjre_core_lib.a", "libtest_j2objc.lo");
CcCompilationContext ccCompilationContext =
j2objcLibraryTarget.get(CcInfo.PROVIDER).getCcCompilationContext();
assertThat(baseArtifactNames(ccCompilationContext.getDeclaredIncludeSrcs()))
.containsExactly("jre_core.h", "test.h");
}
@Test
public void testTagInJreDeps() throws Exception {
scratch.file(
"app/BUILD",
"""
package(default_visibility = ["//visibility:public"])
objc_library(
name = "no_tag_dep",
)
j2objc_library(
name = "test",
jre_deps = ["no_tag_dep"],
tags = ["__J2OBJC_LIBRARY_MIGRATION_DO_NOT_USE_WILL_BREAK__"],
)
""");
reporter.removeHandler(failFastHandler);
getConfiguredTarget("//app:test");
assertContainsEvent(
Pattern.compile(
".* objc_library rule \\'@//app:no_tag_dep\\' is misplaced here \\(Only J2ObjC JRE"
+ " libraries are allowed\\)"));
}
@Test
public void testTranspilationActionTreeArtifactOutputsFromSourceJar() throws Exception {
useConfiguration("--ios_minimum_os=1.0");
scratch.file("java/com/google/transpile/dummy.java");
scratch.file("java/com/google/transpile/dummyjar.srcjar");
scratch.file(
"java/com/google/transpile/BUILD",
"""
java_library(
name = "dummy",
srcs = [
"dummy.java",
"dummyjar.srcjar",
],
)
""");
ConfiguredTarget target = getJ2ObjCAspectConfiguredTarget("//java/com/google/transpile:dummy");
ObjcProvider provider = target.get(ObjcProvider.STARLARK_CONSTRUCTOR);
CcCompilationContext ccCompilationContext =
target.get(CcInfo.PROVIDER).getCcCompilationContext();
Artifact srcJarSources = getFirstArtifactEndingWith(
provider.get(ObjcProvider.SOURCE), "source_files");
Artifact srcJarHeaders =
getFirstArtifactEndingWith(ccCompilationContext.getDeclaredIncludeSrcs(), "header_files");
assertThat(srcJarSources.getRootRelativePathString())
.isEqualTo("java/com/google/transpile/_j2objc/src_jar_files/dummy/source_files");
assertThat(srcJarHeaders.getRootRelativePathString())
.isEqualTo("java/com/google/transpile/_j2objc/src_jar_files/dummy/header_files");
assertThat(srcJarSources.isTreeArtifact()).isTrue();
assertThat(srcJarHeaders.isTreeArtifact()).isTrue();
}
@Test
public void testGeneratedTreeArtifactFromGenJar() throws Exception {
useConfiguration("--ios_minimum_os=1.0");
addSimpleJ2ObjcLibraryWithJavaPlugin();
ConfiguredTarget j2objcLibraryTarget =
getConfiguredTarget("//java/com/google/app/test:transpile");
ObjcProvider provider = j2objcLibraryTarget.get(ObjcProvider.STARLARK_CONSTRUCTOR);
CcCompilationContext ccCompilationContext =
j2objcLibraryTarget.get(CcInfo.PROVIDER).getCcCompilationContext();
Artifact headers =
getFirstArtifactEndingWith(ccCompilationContext.getDeclaredIncludeSrcs(), "header_files");
Artifact sources =
getFirstArtifactEndingWith(provider.get(ObjcProvider.SOURCE), "source_files");
assertThat(headers.isTreeArtifact()).isTrue();
assertThat(sources.isTreeArtifact()).isTrue();
SpawnAction j2objcAction = (SpawnAction) getGeneratingAction(headers);
assertThat(j2objcAction.getOutputs()).containsAtLeast(headers, sources);
assertContainsSublist(
ImmutableList.copyOf(paramFileArgsForAction(j2objcAction)),
ImmutableList.of(
"--output_gen_source_dir",
sources.getExecPathString(),
"--output_gen_header_dir",
headers.getExecPathString()));
}
@Test
public void testJ2ObjcHeaderMappingAction() throws Exception {
scratch.file(
"java/com/google/transpile/BUILD",
"""
java_library(
name = "lib1",
srcs = [
"jar.srcjar",
"libOne.java",
],
deps = [":lib2"],
)
java_library(
name = "lib2",
srcs = ["libTwo.java"],
)
""");
ConfiguredTarget target = getJ2ObjCAspectConfiguredTarget(
"//java/com/google/transpile:lib1");
StructImpl j2ObjcMappingFileInfo = getJ2ObjcMappingFileInfoFromTarget(target);
ImmutableList<Artifact> headerMappingFilesList =
getArtifacts(j2ObjcMappingFileInfo, "header_mapping_files");
assertThat(baseArtifactNames(headerMappingFilesList))
.containsExactly("lib1.mapping.j2objc", "lib2.mapping.j2objc");
Artifact mappingFile =
getFirstArtifactEndingWith(headerMappingFilesList, "lib1.mapping.j2objc");
SpawnAction headerMappingAction = (SpawnAction) getGeneratingAction(mappingFile);
String execPath = getRuleContext(target).getBinFragment() + "/";
assertThat(baseArtifactNames(headerMappingAction.getInputs()))
.containsAtLeast("libOne.java", "jar.srcjar");
assertThat(headerMappingAction.getArguments().get(0))
.contains("tools/j2objc/j2objc_header_map_binary");
assertThat(headerMappingAction.getArguments().get(1)).isEqualTo("--source_files");
assertThat(headerMappingAction.getArguments().get(2))
.isEqualTo("java/com/google/transpile/libOne.java");
assertThat(headerMappingAction.getArguments().get(3)).isEqualTo("--source_jars");
assertThat(headerMappingAction.getArguments().get(4))
.isEqualTo("java/com/google/transpile/jar.srcjar");
assertThat(headerMappingAction.getArguments().get(5)).isEqualTo("--output_mapping_file");
assertThat(headerMappingAction.getArguments().get(6))
.isEqualTo(execPath + "java/com/google/transpile/lib1.mapping.j2objc");
}
protected void checkObjcCompileActions(
Artifact archiveFile, String objFileName, Iterable<String> compilationInputExecPaths)
throws Exception {
CommandAction compileAction = getObjcCompileAction(archiveFile, objFileName);
assertThat(baseArtifactNames(compileAction.getPossibleInputsForTesting()))
.containsAtLeastElementsIn(compilationInputExecPaths);
}
protected CommandAction getObjcCompileAction(Artifact archiveFile, String objFileName)
throws Exception {
CommandAction archiveAction = (CommandAction) getGeneratingAction(archiveFile);
CommandAction compileAction =
(CommandAction)
getGeneratingAction(getFirstArtifactEndingWith(archiveAction.getInputs(), objFileName));
return compileAction;
}
protected void addSimpleBinaryTarget(String j2objcLibraryTargetDep) throws Exception {
scratch.file("app/app.m");
scratch.file("app/Info.plist");
scratch.file(
"app/BUILD",
"load('//test_starlark:apple_binary_starlark.bzl', 'apple_binary_starlark')",
"package(default_visibility=['//visibility:public'])",
"objc_library(",
" name = 'lib',",
" deps = ['" + j2objcLibraryTargetDep + "'])",
"",
"apple_binary_starlark(",
" name = 'app',",
" platform_type = 'ios',",
" deps = [':main_lib'],",
")",
"objc_library(",
" name = 'main_lib',",
" srcs = ['app.m'],",
" deps = [':lib'],",
")");
}
protected void addSimpleJ2ObjcLibraryWithEntryClasses() throws Exception {
scratch.file("java/com/google/app/test/test.java");
scratch.file(
"java/com/google/app/test/BUILD",
"""
package(default_visibility = ["//visibility:public"])
java_library(
name = "test",
srcs = ["test.java"],
)
j2objc_library(
name = "transpile",
entry_classes = ["com.google.app.test.test"],
tags = ["__J2OBJC_LIBRARY_MIGRATION_DO_NOT_USE_WILL_BREAK__"],
deps = ["test"],
)
""");
}
protected void addSimpleJ2ObjcLibraryWithJavaPlugin() throws Exception {
scratch.file("java/com/google/app/test/test.java");
scratch.file("java/com/google/app/test/plugin.java");
scratch.file(
"java/com/google/app/test/BUILD",
"""
package(default_visibility = ["//visibility:public"])
java_library(
name = "test",
srcs = ["test.java"],
plugins = [":plugin"],
)
java_plugin(
name = "plugin",
srcs = ["plugin.java"],
processor_class = "com.google.process.stuff",
)
j2objc_library(
name = "transpile",
tags = ["__J2OBJC_LIBRARY_MIGRATION_DO_NOT_USE_WILL_BREAK__"],
deps = [":test"],
)
""");
}
protected Artifact j2objcArchive(String j2objcLibraryTarget, String javaTargetName)
throws Exception {
ConfiguredTarget target = getConfiguredTarget(j2objcLibraryTarget);
CcLinkingContext ccLinkingContext = target.get(CcInfo.PROVIDER).getCcLinkingContext();
String archiveName = String.format("lib%s_j2objc.lo", javaTargetName);
return getFirstArtifactEndingWith(
ccLinkingContext.getStaticModeParamsForDynamicLibraryLibraries(), archiveName);
}
@Test
public void testJ2ObjcInformationExportedFromObjcLibrary() throws Exception {
scratch.file("app/lib.m");
scratch.file(
"app/BUILD",
"""
package(default_visibility = ["//visibility:public"])
objc_library(
name = "lib",
srcs = ["lib.m"],
deps = ["//java/com/google/dummy/test:transpile"],
)
""");
ConfiguredTarget objcTarget = getConfiguredTarget("//app:lib");
CcLinkingContext ccLinkingContext = objcTarget.get(CcInfo.PROVIDER).getCcLinkingContext();
assertThat(baseArtifactNames(ccLinkingContext.getStaticModeParamsForDynamicLibraryLibraries()))
.containsExactly("libjre_core_lib.a", "libtest_j2objc.lo", "liblib.a");
CcCompilationContext ccCompilationContext =
objcTarget.get(CcInfo.PROVIDER).getCcCompilationContext();
assertThat(baseArtifactNames(ccCompilationContext.getDeclaredIncludeSrcs()))
.containsExactly("jre_core.h", "test.h");
String execPath = getRuleContext(objcTarget).getBinFragment() + "/";
assertThat(
Iterables.transform(
ccCompilationContext.getIncludeDirs(), PathFragment::getSafePathString))
.containsExactly(execPath + "java/com/google/dummy/test/_j2objc/test");
}
@Test
public void testJ2ObjcInfoExportedInObjcLibraryFromRuntimeDeps() throws Exception {
scratch.file("app/lib.m");
scratch.file(
"app/BUILD",
"""
package(default_visibility = ["//visibility:public"])
java_library(
name = "dummyOne",
srcs = ["dummyOne.java"],
)
java_library(
name = "dummyTwo",
srcs = ["dummyTwo.java"],
runtime_deps = [":dummyOne"],
)
j2objc_library(
name = "transpile",
tags = ["__J2OBJC_LIBRARY_MIGRATION_DO_NOT_USE_WILL_BREAK__"],
deps = [":dummyTwo"],
)
objc_library(
name = "lib",
srcs = ["lib.m"],
deps = ["//app:transpile"],
)
""");
ConfiguredTarget objcTarget = getConfiguredTarget("//app:lib");
CcLinkingContext ccLinkingContext = objcTarget.get(CcInfo.PROVIDER).getCcLinkingContext();
assertThat(baseArtifactNames(ccLinkingContext.getStaticModeParamsForDynamicLibraryLibraries()))
.containsExactly(
"libjre_core_lib.a", "libdummyOne_j2objc.lo", "libdummyTwo_j2objc.lo", "liblib.a");
CcCompilationContext ccCompilationContext =
objcTarget.get(CcInfo.PROVIDER).getCcCompilationContext();
assertThat(baseArtifactNames(ccCompilationContext.getDeclaredIncludeSrcs()))
.containsExactly("jre_core.h", "dummyOne.h", "dummyTwo.h");
String execPath = getRuleContext(objcTarget).getBinFragment() + "/";
assertThat(
Iterables.transform(
ccCompilationContext.getIncludeDirs(), PathFragment::getSafePathString))
.containsExactly(execPath + "app/_j2objc/dummyOne", execPath + "app/_j2objc/dummyTwo");
}
@Nullable
private ParameterFileWriteAction paramFileWriteActionForLinkAction(Action action) {
for (Artifact input : action.getInputs().toList()) {
if (!(input instanceof SpecialArtifact)) {
if (input.getFilename().endsWith("linker.objlist")) {
Action generatingAction = getGeneratingAction(input);
if (generatingAction instanceof ParameterFileWriteAction) {
return (ParameterFileWriteAction) generatingAction;
}
}
}
}
return null;
}
@Test
public void testJ2ObjcAppearsInLinkArgs() throws Exception {
scratch.file(
"java/c/y/BUILD",
"""
java_library(
name = "ylib",
srcs = ["lib.java"],
)
""");
addAppleBinaryStarlarkRule(scratch);
scratch.file(
"x/BUILD",
"load('//test_starlark:apple_binary_starlark.bzl', 'apple_binary_starlark')",
"j2objc_library(",
" name = 'j2',",
" deps = [ '//java/c/y:ylib' ],",
" tags = ['__J2OBJC_LIBRARY_MIGRATION_DO_NOT_USE_WILL_BREAK__'],",
" jre_deps = [ '"
+ TestConstants.TOOLS_REPOSITORY
+ "//third_party/java/j2objc:jre_io_lib' ],",
")",
"apple_binary_starlark(",
" name = 'test',",
" platform_type = 'ios',",
" deps = [':main_lib'],",
")",
"objc_library(",
" name = 'main_lib',",
" srcs = ['test.m'],",
" deps = [':j2'],",
")");
CommandAction linkAction = linkAction("//x:test");
ConfiguredTarget target = getConfiguredTarget("//x:test");
String binDir = removeConfigFragment(getRuleContext(target).getBinFragment().toString());
ParameterFileWriteAction paramAction = paramFileWriteActionForLinkAction(linkAction);
Iterable<String> paramFileArgs = paramAction.getCommandLine().arguments();
assertThat(removeConfigFragment(ImmutableList.copyOf(linkAction.getArguments())))
.contains("-force_load " + binDir + "/java/c/y/libylib_j2objc.lo");
assertThat(removeConfigFragment(ImmutableList.copyOf(paramFileArgs)))
.containsAtLeast(
// All jre libraries mus appear after java libraries in the link order.
binDir
+ "/"
+ TestConstants.TOOLS_REPOSITORY_PATH_PREFIX
+ "third_party/java/j2objc/libjre_io_lib.a",
binDir
+ "/"
+ TestConstants.TOOLS_REPOSITORY_PATH_PREFIX
+ "third_party/java/j2objc/libjre_core_lib.a")
.inOrder();
}
@Test
public void testArchiveLinkActionWithTreeArtifactFromGenJar() throws Exception {
useConfiguration("--ios_minimum_os=1.0");
addSimpleJ2ObjcLibraryWithJavaPlugin();
Artifact archive = j2objcArchive("//java/com/google/app/test:transpile", "test");
SpawnAction archiveAction = (SpawnAction) getGeneratingAction(archive);
Artifact objectFilesFromGenJar =
getFirstArtifactEndingWith(archiveAction.getInputs(), "source_files");
Artifact normalObjectFile = getFirstArtifactEndingWith(archiveAction.getInputs(), "test.o");
// Test that the archive commandline contains the individual object files inside
// the object file tree artifact.
ExpandedCommandLines expandedCommandLines =
archiveAction
.getCommandLines()
.expand(
DUMMY_ARTIFACT_EXPANDER,
archiveAction.getPrimaryOutput().getExecPath(),
PathMapper.NOOP,
CommandLineLimits.UNLIMITED);
assertThat(expandedCommandLines.arguments())
.containsAtLeast(
objectFilesFromGenJar.getExecPathString() + "/children1",
objectFilesFromGenJar.getExecPathString() + "/children2",
normalObjectFile.getExecPathString());
}
@Test
public void testJ2ObjCCustomModuleMap() throws Exception {
scratch.file("java/com/google/transpile/dummy.java");
scratch.file(
"java/com/google/transpile/BUILD",
"""
package(default_visibility = ["//visibility:public"])
java_library(
name = "dummy",
srcs = ["dummy.java"],
)
""");
ConfiguredTarget target = getJ2ObjCAspectConfiguredTarget("//java/com/google/transpile:dummy");
ObjcProvider provider = target.get(ObjcProvider.STARLARK_CONSTRUCTOR);
Artifact moduleMap =
getFirstArtifactEndingWith(
provider.get(ObjcProvider.MODULE_MAP), "dummy.modulemaps/module.modulemap");
Artifact umbrellaHeader =
getFirstArtifactEndingWith(
provider.get(ObjcProvider.UMBRELLA_HEADER), "dummy.modulemaps/umbrella.h");
CppModuleMapAction moduleMapAction = (CppModuleMapAction) getGeneratingAction(moduleMap);
UmbrellaHeaderAction umbrellaHeaderAction =
(UmbrellaHeaderAction) getGeneratingAction(umbrellaHeader);
ActionExecutionContext dummyActionExecutionContext =
new ActionExecutionContext(
/* executor= */ null,
/* inputMetadataProvider= */ null,
ActionInputPrefetcher.NONE,
actionKeyContext,
/* outputMetadataStore= */ null,
/* rewindingEnabled= */ false,
LostInputsCheck.NONE,
/* fileOutErr= */ null,
/* eventHandler= */ null,
/* clientEnv= */ ImmutableMap.of(),
/* topLevelFilesets= */ ImmutableMap.of(),
DUMMY_ARTIFACT_EXPANDER,
/* actionFileSystem= */ null,
/* skyframeDepsResult= */ null,
DiscoveredModulesPruner.DEFAULT,
SyscallCache.NO_CACHE,
ThreadStateReceiver.NULL_INSTANCE);
ByteArrayOutputStream moduleMapStream = new ByteArrayOutputStream();
ByteArrayOutputStream umbrellaHeaderStream = new ByteArrayOutputStream();
moduleMapAction.newDeterministicWriter(dummyActionExecutionContext)
.writeOutputFile(moduleMapStream);
umbrellaHeaderAction.newDeterministicWriter(dummyActionExecutionContext)
.writeOutputFile(umbrellaHeaderStream);
String moduleMapContent = moduleMapStream.toString();
String umbrellaHeaderContent = umbrellaHeaderStream.toString();
assertThat(moduleMapContent).contains("umbrella header \"umbrella.h\"");
assertThat(umbrellaHeaderContent).contains("/dummy.h");
assertThat(umbrellaHeaderContent).contains("#include");
}
@Test
public void testModuleMapFromGenJarTreeArtifact() throws Exception {
useConfiguration("--ios_minimum_os=1.0");
addSimpleJ2ObjcLibraryWithJavaPlugin();
ConfiguredTarget j2objcLibraryTarget =
getConfiguredTarget("//java/com/google/app/test:transpile");
ObjcProvider provider = j2objcLibraryTarget.get(ObjcProvider.STARLARK_CONSTRUCTOR);
CcCompilationContext ccCompilationContext =
j2objcLibraryTarget.get(CcInfo.PROVIDER).getCcCompilationContext();
Artifact moduleMap =
getFirstArtifactEndingWith(
provider.get(ObjcProvider.MODULE_MAP), "test.modulemaps/module.modulemap");
Artifact umbrellaHeader =
getFirstArtifactEndingWith(
provider.get(ObjcProvider.UMBRELLA_HEADER), "test.modulemaps/umbrella.h");
CppModuleMapAction moduleMapAction = (CppModuleMapAction) getGeneratingAction(moduleMap);
UmbrellaHeaderAction umbrellaHeaderAction =
(UmbrellaHeaderAction) getGeneratingAction(umbrellaHeader);
Artifact headers =
getFirstArtifactEndingWith(ccCompilationContext.getDeclaredIncludeSrcs(), "header_files");
// Test that the module map action contains the header tree artifact as both the public header
// and part of the action inputs.
assertThat(moduleMapAction.getPublicHeaders()).contains(headers);
assertThat(moduleMapAction.getInputs().toList()).contains(headers);
ActionExecutionContext dummyActionExecutionContext =
new ActionExecutionContext(
/* executor= */ null,
/* inputMetadataProvider= */ null,
ActionInputPrefetcher.NONE,
actionKeyContext,
/* outputMetadataStore= */ null,
/* rewindingEnabled= */ false,
LostInputsCheck.NONE,
/* fileOutErr= */ null,
/* eventHandler= */ null,
/* clientEnv= */ ImmutableMap.of(),
/* topLevelFilesets= */ ImmutableMap.of(),
DUMMY_ARTIFACT_EXPANDER,
/* actionFileSystem= */ null,
/* skyframeDepsResult= */ null,
DiscoveredModulesPruner.DEFAULT,
SyscallCache.NO_CACHE,
ThreadStateReceiver.NULL_INSTANCE);
ByteArrayOutputStream moduleMapStream = new ByteArrayOutputStream();
ByteArrayOutputStream umbrellaHeaderStream = new ByteArrayOutputStream();
moduleMapAction
.newDeterministicWriter(dummyActionExecutionContext)
.writeOutputFile(moduleMapStream);
umbrellaHeaderAction
.newDeterministicWriter(dummyActionExecutionContext)
.writeOutputFile(umbrellaHeaderStream);
String moduleMapContent = moduleMapStream.toString();
String umbrellaHeaderContent = umbrellaHeaderStream.toString();
// Test that the module map content contains the individual headers inside the header tree
// artifact.
assertThat(moduleMapContent).contains("umbrella header \"umbrella.h\"");
assertThat(umbrellaHeaderContent).contains(headers.getExecPathString() + "/children1");
assertThat(umbrellaHeaderContent).contains(headers.getExecPathString() + "/children2");
}
@Test
public void testObjcCompileAction() throws Exception {
Artifact archive = j2objcArchive("//java/com/google/dummy/test:transpile", "test");
CommandAction compileAction = getObjcCompileAction(archive, "test.o");
assertThat(baseArtifactNames(compileAction.getPossibleInputsForTesting()))
.containsAtLeast("jre_core.h", "test.h", "test.m");
assertThat(compileAction.getArguments())
.containsAtLeast("-fno-objc-arc", "-fno-strict-overflow", "-fobjc-weak");
}
@Test
public void testObjcCompileArcAction() throws Exception {
useConfiguration("--j2objc_translation_flags=-use-arc");
Artifact archive = j2objcArchive("//java/com/google/dummy/test:transpile", "test");
CommandAction compileAction = getObjcCompileAction(archive, "test.o");
assertThat(baseArtifactNames(compileAction.getPossibleInputsForTesting()))
.containsAtLeast("jre_core.h", "test.h", "test.m");
assertThat(compileAction.getArguments())
.containsAtLeast("-fobjc-arc", "-fobjc-arc-exceptions", "-fno-strict-overflow");
}
@Test
public void testJ2ObjcSourcesCompilationAndLinking() throws Exception {
addAppleBinaryStarlarkRule(scratch);
addSimpleBinaryTarget("//java/com/google/dummy/test:transpile");
checkObjcArchiveAndLinkActions(
"libtest_j2objc.lo",
"test.o",
ImmutableList.of("jre_core.h", "test.h", "test.m"));
}
@Test
public void testNestedJ2ObjcLibraryDeps() throws Exception {
scratch.file("java/com/google/dummy/dummy.java");
scratch.file(
"java/com/google/dummy/BUILD",
"""
package(default_visibility = ["//visibility:public"])
java_library(
name = "dummy",
srcs = ["dummy.java"],
)
j2objc_library(
name = "transpile",
tags = ["__J2OBJC_LIBRARY_MIGRATION_DO_NOT_USE_WILL_BREAK__"],
deps = [
":dummy",
"//java/com/google/dummy/test:transpile",
],
)
""");
addAppleBinaryStarlarkRule(scratch);
addSimpleBinaryTarget("//java/com/google/dummy:transpile");
checkObjcArchiveAndLinkActions(
"libtest_j2objc.lo",
"test.o",
ImmutableList.of("jre_core.h", "test.h", "test.m"));
checkObjcArchiveAndLinkActions(
"libdummy_j2objc.lo",
"dummy.o",
ImmutableList.of("jre_core.h", "dummy.h", "dummy.m"));
}
// Tests that a j2objc library can acquire java library information from a Starlark rule target.
@Test
public void testJ2ObjcLibraryDepThroughStarlarkRule() throws Exception {
scratch.file("examples/inner.java");
scratch.file("examples/outer.java");
scratch.file(
"examples/fake_rule.bzl",
"""
def _fake_rule_impl(ctx):
myProvider = ctx.attr.deps[0][JavaInfo]
return myProvider
fake_rule = rule(
implementation = _fake_rule_impl,
attrs = {"deps": attr.label_list()},
provides = [JavaInfo],
)
""");
scratch.file(
"examples/BUILD",
"""
load("//examples:fake_rule.bzl", "fake_rule")
package(default_visibility = ["//visibility:public"])
java_library(
name = "inner",
srcs = ["inner.java"],
)
fake_rule(
name = "propagator",
deps = [":inner"],
)
java_library(
name = "outer",
srcs = ["outer.java"],
deps = [":propagator"],
)
j2objc_library(
name = "transpile",
tags = ["__J2OBJC_LIBRARY_MIGRATION_DO_NOT_USE_WILL_BREAK__"],
deps = [
":outer",
],
)
objc_library(
name = "lib",
srcs = ["lib.m"],
deps = [":transpile"],
)
""");
ConfiguredTarget objcTarget = getConfiguredTarget("//examples:lib");
// The only way that //examples:lib can see inner's archive is through the Starlark rule.
CcLinkingContext ccLinkingContext = objcTarget.get(CcInfo.PROVIDER).getCcLinkingContext();
assertThat(baseArtifactNames(ccLinkingContext.getStaticModeParamsForDynamicLibraryLibraries()))
.contains("libinner_j2objc.lo");
}
@Test
public void testJ2ObjcTranspiledHeaderInCompilationAction() throws Exception {
scratch.file("app/lib.m");
scratch.file(
"app/BUILD",
"""
package(default_visibility = ["//visibility:public"])
objc_library(
name = "lib",
srcs = ["lib.m"],
deps = ["//java/com/google/dummy/test:transpile"],
)
""");
checkObjcCompileActions(
getBinArtifact("liblib.a", getConfiguredTarget("//app:lib")),
"lib.o",
ImmutableList.of("test.h"));
}
@Test
public void testProtoToolchainForJ2ObjcFlag() throws Exception {
useConfiguration(
"--proto_toolchain_for_java=//tools/proto/toolchains:java",
"--proto_toolchain_for_j2objc=//tools/j2objc:alt_j2objc_proto_toolchain");
scratch.file("tools/j2objc/proto_plugin_binary");
scratch.file("tools/j2objc/alt_proto_runtime.h");
scratch.file("tools/j2objc/alt_proto_runtime.m");
scratch.file("tools/j2objc/proto_to_exclude.proto");
scratch.overwriteFile(
"tools/j2objc/BUILD",
TestConstants.LOAD_PROTO_LIBRARY,
TestConstants.LOAD_PROTO_LANG_TOOLCHAIN,
"package(default_visibility=['//visibility:public'])",
"exports_files(['j2objc_deploy.jar'])",
getPyLoad("py_binary"),
"py_binary(",
" name = 'j2objc_wrapper_binary',",
" srcs = ['j2objc_wrapper_binary.py'],",
")",
"proto_library(",
" name = 'excluded_protos',",
" srcs = ['proto_to_exclude.proto'],",
")",
"py_binary(",
" name = 'j2objc_header_map_binary',",
" srcs = ['j2objc_header_map_binary.py'],",
")",
"proto_lang_toolchain(",
" name = 'alt_j2objc_proto_toolchain',",
" command_line = '--PLUGIN_j2objc_out=file_dir_mapping,generate_class_mappings:$(OUT)',",
" plugin_format_flag = '--plugin=protoc-gen-PLUGIN_j2objc=%s', ",
" plugin = ':alt_proto_plugin',",
" runtime = ':alt_proto_runtime',",
" blacklisted_protos = [':excluded_protos'],",
")",
"proto_library(",
" name = 'excluded_proto_library',",
" srcs = ['proto_to_exclude.proto'],",
")",
"objc_library(",
" name = 'alt_proto_runtime',",
" hdrs = ['alt_proto_runtime.h'],",
" srcs = ['alt_proto_runtime.m'],",
")",
"filegroup(",
" name = 'alt_proto_plugin',",
" srcs = ['proto_plugin_binary']",
")");
scratch.file("java/com/google/dummy/test/proto/test.java");
scratch.file("java/com/google/dummy/test/proto/test.proto");
scratch.file(
"java/com/google/dummy/test/proto/BUILD",
TestConstants.LOAD_PROTO_LIBRARY,
"package(default_visibility=['//visibility:public'])",
"proto_library(",
" name = 'test_proto',",
" srcs = ['test.proto'],",
" deps = ['//tools/j2objc:excluded_proto_library'],",
")",
"java_proto_library(",
" name = 'test_java_proto',",
" deps = [':test_proto'],",
")",
"java_library(",
" name = 'test',",
" srcs = ['test.java'],",
" deps = [':test_java_proto'])",
"",
"j2objc_library(",
" name = 'transpile',",
" tags = ['__J2OBJC_LIBRARY_MIGRATION_DO_NOT_USE_WILL_BREAK__'],",
" deps = ['test'])");
ConfiguredTarget j2objcLibraryTarget =
getConfiguredTarget("//java/com/google/dummy/test/proto:transpile");
CcLinkingContext ccLinkingContext =
j2objcLibraryTarget.get(CcInfo.PROVIDER).getCcLinkingContext();
assertThat(baseArtifactNames(ccLinkingContext.getStaticModeParamsForDynamicLibraryLibraries()))
.containsExactly(
"libjre_core_lib.a",
"libalt_proto_runtime.a",
"libtest_j2objc.lo",
"libtest_proto_j2objc.lo");
CcCompilationContext ccCompilationContext =
j2objcLibraryTarget.get(CcInfo.PROVIDER).getCcCompilationContext();
assertThat(baseArtifactNames(ccCompilationContext.getDeclaredIncludeSrcs()))
.containsExactly("jre_core.h", "alt_proto_runtime.h", "test.j2objc.pb.h", "test.h");
}
@Test
public void testJ2ObjcDeadCodeRemovalActionWithOptFlag() throws Exception {
useConfiguration("--j2objc_dead_code_removal");
addSimpleJ2ObjcLibraryWithEntryClasses();
addAppleBinaryStarlarkRule(scratch);
addSimpleBinaryTarget("//java/com/google/app/test:transpile");
RuleConfiguredTarget appTarget = (RuleConfiguredTarget) getConfiguredTarget("//app:app");
Artifact prunedArchive =
getBinArtifact(
"app/_j2objc_pruned/app/java/com/google/app/test/libtest_j2objc_pruned.lo", appTarget);
Action action = getGeneratingAction(prunedArchive);
ConfiguredTarget javaTarget = getConfiguredTarget("//java/com/google/app/test:test");
Artifact inputArchive = getBinArtifact("libtest_j2objc.lo", javaTarget);
Artifact headerMappingFile = getBinArtifact("test.mapping.j2objc", javaTarget);
Artifact dependencyMappingFile = getBinArtifact("test.dependency_mapping.j2objc", javaTarget);
Artifact archiveSourceMappingFile =
getBinArtifact("test.archive_source_mapping.j2objc", javaTarget);
String execPath = removeConfigFragment(getRuleContext(javaTarget).getBinFragment() + "/");
assertContainsSublist(
removeConfigFragment(ImmutableList.copyOf(paramFileArgsForAction(action))),
ImmutableList.of(
"--input_archive",
removeConfigFragment(inputArchive.getExecPathString()),
"--output_archive",
removeConfigFragment(prunedArchive.getExecPathString()),
"--dummy_archive",
execPath
+ TestConstants.TOOLS_REPOSITORY_PATH_PREFIX
+ "tools/objc/dummy/libdummy_lib.a",
"--dependency_mapping_files",
removeConfigFragment(dependencyMappingFile.getExecPathString()),
"--header_mapping_files",
removeConfigFragment(headerMappingFile.getExecPathString()),
"--archive_source_mapping_files",
removeConfigFragment(archiveSourceMappingFile.getExecPathString()),
"--entry_classes",
"com.google.app.test.test"));
SpawnAction deadCodeRemovalAction = (SpawnAction) getGeneratingAction(prunedArchive);
assertThat(deadCodeRemovalAction.getArguments().get(0))
.contains("tools/objc/j2objc_dead_code_pruner_binary");
assertThat(deadCodeRemovalAction.getOutputs()).containsExactly(prunedArchive);
}
/** Returns the actions created by the action template corresponding to given artifact. */
protected ImmutableList<CppCompileAction> getActionsForInputsOfGeneratingActionTemplate(
Artifact artifact, TreeFileArtifact treeFileArtifact) throws ActionExecutionException {
CppCompileActionTemplate template =
(CppCompileActionTemplate) getActionGraph().getGeneratingAction(artifact);
return template.generateActionsForInputArtifacts(
ImmutableSet.of(treeFileArtifact), ActionsTestUtil.NULL_TEMPLATE_EXPANSION_ARTIFACT_OWNER);
}
@Test
public void testCompileActionTemplateFromGenJar() throws Exception {
useConfiguration(
"--apple_platform_type=ios",
"--cpu=ios_i386",
"--ios_minimum_os=1.0",
"--platforms=" + MockObjcSupport.IOS_I386);
addSimpleJ2ObjcLibraryWithJavaPlugin();
Artifact archive = j2objcArchive("//java/com/google/app/test:transpile", "test");
CommandAction archiveAction = (CommandAction) getGeneratingAction(archive);
Artifact objectFilesFromGenJar =
getFirstArtifactEndingWith(archiveAction.getInputs(), "source_files");
assertThat(objectFilesFromGenJar.isTreeArtifact()).isTrue();
assertThat(objectFilesFromGenJar.getRootRelativePathString())
.isEqualTo("java/com/google/app/test/_objs/test/non_arc/source_files");
ActionAnalysisMetadata actionTemplate =
getActionGraph().getGeneratingAction(objectFilesFromGenJar);
Artifact sourceFilesFromGenJar =
getFirstArtifactEndingWith(actionTemplate.getInputs(), "source_files");
assertThat(sourceFilesFromGenJar.getRootRelativePathString())
.isEqualTo("java/com/google/app/test/_j2objc/src_jar_files/test/source_files");
// We can't easily access the header artifact through the middleman artifact, so use its
// expected path directly.
String headerFilesFromGenJar =
"java/com/google/app/test/_j2objc/src_jar_files/test/header_files";
// The files contained inside the tree artifacts are not known until execution time.
// Therefore we need to fake some files inside them to test the action template in this
// analysis-time test.
TreeFileArtifact oneSourceFileFromGenJar =
TreeFileArtifact.createTreeOutput((SpecialArtifact) sourceFilesFromGenJar, "children1.m");
TreeFileArtifact oneObjFileFromGenJar =
TreeFileArtifact.createTreeOutput((SpecialArtifact) objectFilesFromGenJar, "children1.o");
Iterable<CppCompileAction> compileActions =
getActionsForInputsOfGeneratingActionTemplate(
objectFilesFromGenJar, oneSourceFileFromGenJar);
CommandAction compileAction = Iterables.getOnlyElement(compileActions);
ConfiguredTarget j2objcLibraryTarget =
getConfiguredTarget("//java/com/google/dummy/test:transpile");
String genfilesFragment = getRuleContext(j2objcLibraryTarget).getGenfilesFragment().toString();
String binFragment = getRuleContext(j2objcLibraryTarget).getBinFragment().toString();
String commandLine = Joiner.on(" ").join(compileAction.getArguments());
ImmutableList<String> expectedArgs =
new ImmutableList.Builder<String>()
.add("-fexceptions")
.add("-fasm-blocks")
.add("-fobjc-abi-version=2")
.add("-fobjc-legacy-dispatch")
.add("-DOS_IOS")
.add("-arch", "i386")
.add("-isysroot")
.add("__BAZEL_XCODE_SDKROOT__")
.add("-O0")
.add("-DDEBUG=1")
.add("-iquote")
.add(".")
.add("-iquote")
.add(genfilesFragment)
.add("-I")
.add(binFragment + "/java/com/google/app/test/_j2objc/test")
.add("-I")
.add(headerFilesFromGenJar)
.add("-fno-strict-overflow")
.add("-fno-objc-arc")
.add("-c")
.add(oneSourceFileFromGenJar.getExecPathString())
.add("-o")
.add(oneObjFileFromGenJar.getExecPathString())
.build();
for (String expectedArg : expectedArgs) {
assertThat(commandLine).contains(expectedArg);
}
}
@Test
public void j2objcLibrary_noPropperTag_lockdownError() throws Exception {
useConfiguration("--incompatible_j2objc_library_migration");
scratch.file("test/BUILD", "j2objc_library(name = 'test')");
reporter.removeHandler(failFastHandler);
getConfiguredTarget("//test");
assertContainsEvent(
"j2objc_library is locked. Please do not use this rule since it will be deleted in the"
+ " future.");
}
@Test
public void j2objcLibrary_withPropperTag_noError() throws Exception {
useConfiguration("--incompatible_j2objc_library_migration");
scratch.file(
"test/BUILD",
"""
j2objc_library(
name = "test",
tags = ["__J2OBJC_LIBRARY_MIGRATION_DO_NOT_USE_WILL_BREAK__"],
)
""");
getConfiguredTarget("//test");
assertNoEvents();
}
}