aboutsummaryrefslogtreecommitdiffhomepage
path: root/src/main/java/com
diff options
context:
space:
mode:
Diffstat (limited to 'src/main/java/com')
-rw-r--r--src/main/java/com/google/devtools/build/lib/bazel/rules/android/AndroidNdkRepositoryFunction.java191
-rw-r--r--src/main/java/com/google/devtools/build/lib/bazel/rules/android/android_ndk_cc_toolchain_suite_template.txt28
-rw-r--r--src/main/java/com/google/devtools/build/lib/bazel/rules/android/android_ndk_cc_toolchain_template.txt59
-rw-r--r--src/main/java/com/google/devtools/build/lib/bazel/rules/android/android_ndk_toolchain_template.txt123
-rw-r--r--src/main/java/com/google/devtools/build/lib/bazel/rules/android/ndkcrosstools/AndroidNdkCrosstools.java222
-rw-r--r--src/main/java/com/google/devtools/build/lib/bazel/rules/android/ndkcrosstools/ApiLevel.java154
-rw-r--r--src/main/java/com/google/devtools/build/lib/bazel/rules/android/ndkcrosstools/ArmCrosstools.java445
-rw-r--r--src/main/java/com/google/devtools/build/lib/bazel/rules/android/ndkcrosstools/MipsCrosstools.java221
-rw-r--r--src/main/java/com/google/devtools/build/lib/bazel/rules/android/ndkcrosstools/NdkPaths.java207
-rw-r--r--src/main/java/com/google/devtools/build/lib/bazel/rules/android/ndkcrosstools/NdkRelease.java86
-rw-r--r--src/main/java/com/google/devtools/build/lib/bazel/rules/android/ndkcrosstools/X86Crosstools.java213
-rw-r--r--src/main/java/com/google/devtools/build/lib/rules/cpp/CrosstoolConfigurationLoader.java5
-rw-r--r--src/main/java/com/google/devtools/build/lib/util/AutoProfiler.java141
-rw-r--r--src/main/java/com/google/devtools/build/lib/util/OS.java7
14 files changed, 1863 insertions, 239 deletions
diff --git a/src/main/java/com/google/devtools/build/lib/bazel/rules/android/AndroidNdkRepositoryFunction.java b/src/main/java/com/google/devtools/build/lib/bazel/rules/android/AndroidNdkRepositoryFunction.java
index a98fb177ce..f510538fc9 100644
--- a/src/main/java/com/google/devtools/build/lib/bazel/rules/android/AndroidNdkRepositoryFunction.java
+++ b/src/main/java/com/google/devtools/build/lib/bazel/rules/android/AndroidNdkRepositoryFunction.java
@@ -13,20 +13,28 @@
// limitations under the License.
package com.google.devtools.build.lib.bazel.rules.android;
-import com.google.common.collect.ImmutableList;
import com.google.devtools.build.lib.analysis.RuleDefinition;
import com.google.devtools.build.lib.bazel.repository.RepositoryFunction;
+import com.google.devtools.build.lib.bazel.rules.android.ndkcrosstools.AndroidNdkCrosstools;
+import com.google.devtools.build.lib.bazel.rules.android.ndkcrosstools.AndroidNdkCrosstools.NdkCrosstoolsException;
+import com.google.devtools.build.lib.bazel.rules.android.ndkcrosstools.NdkPaths;
+import com.google.devtools.build.lib.bazel.rules.android.ndkcrosstools.NdkRelease;
import com.google.devtools.build.lib.packages.AttributeMap;
import com.google.devtools.build.lib.packages.NonconfigurableAttributeMapper;
import com.google.devtools.build.lib.packages.PackageIdentifier.RepositoryName;
import com.google.devtools.build.lib.packages.Rule;
import com.google.devtools.build.lib.packages.Type;
+import com.google.devtools.build.lib.skyframe.FileSymlinkException;
import com.google.devtools.build.lib.skyframe.FileValue;
-import com.google.devtools.build.lib.util.CPU;
-import com.google.devtools.build.lib.util.OS;
+import com.google.devtools.build.lib.skyframe.InconsistentFilesystemException;
import com.google.devtools.build.lib.util.ResourceFileLoader;
+import com.google.devtools.build.lib.vfs.FileSystemUtils;
import com.google.devtools.build.lib.vfs.Path;
import com.google.devtools.build.lib.vfs.PathFragment;
+import com.google.devtools.build.lib.vfs.RootedPath;
+import com.google.devtools.build.lib.view.config.crosstool.CrosstoolConfig.CToolchain;
+import com.google.devtools.build.lib.view.config.crosstool.CrosstoolConfig.CrosstoolRelease;
+import com.google.devtools.build.lib.view.config.crosstool.CrosstoolConfig.DefaultCpuToolchain;
import com.google.devtools.build.skyframe.SkyFunctionException;
import com.google.devtools.build.skyframe.SkyFunctionException.Transience;
import com.google.devtools.build.skyframe.SkyFunctionName;
@@ -34,12 +42,14 @@ import com.google.devtools.build.skyframe.SkyKey;
import com.google.devtools.build.skyframe.SkyValue;
import java.io.IOException;
+import java.util.ArrayList;
import java.util.List;
/**
* Implementation of the {@code android_ndk_repository} rule.
*/
public class AndroidNdkRepositoryFunction extends RepositoryFunction {
+
@Override
public SkyValue compute(SkyKey skyKey, Environment env) throws SkyFunctionException {
RepositoryName repositoryName = (RepositoryName) skyKey.argument();
@@ -69,80 +79,16 @@ public class AndroidNdkRepositoryFunction extends RepositoryFunction {
AttributeMap attributes = NonconfigurableAttributeMapper.of(rule);
String ruleName = rule.getName();
String apiLevel = attributes.get("api_level", Type.INTEGER).toString();
- List<String> cpus = ImmutableList.of("arm"); // TODO(bazel-team): autodetect
- String abi = "armeabi-v7a"; // TODO(bazel-team): Should this be an attribute on the rule?
- String compiler = "4.9"; // TODO(bazel-team): Should this be an attribute on the rule?
-
- // TODO(bazel-team): move this, add other cases
- String hostPlatform, hostArch;
- switch (OS.getCurrent()) {
- case DARWIN:
- hostPlatform = "darwin";
- break;
- case LINUX:
- hostPlatform = "linux";
- break;
- default:
- hostPlatform = "unknown";
- }
- switch (CPU.getCurrent()) {
- case X86_32:
- hostArch = "x86";
- break;
- case X86_64:
- hostArch = "x86_64";
- break;
- default:
- hostArch = "unknown";
- }
-
- String hostCpu = hostPlatform + "-" + hostArch;
-
- String ccToolchainSuiteTemplate;
- String ccToolchainTemplate;
- String toolchainTemplate;
+ CrosstoolRelease androidCrosstoolRelease;
try {
- ccToolchainSuiteTemplate = ResourceFileLoader.loadResource(
- AndroidNdkRepositoryFunction.class, "android_ndk_cc_toolchain_suite_template.txt");
- ccToolchainTemplate = ResourceFileLoader.loadResource(
- AndroidNdkRepositoryFunction.class, "android_ndk_cc_toolchain_template.txt");
- toolchainTemplate = ResourceFileLoader.loadResource(
- AndroidNdkRepositoryFunction.class, "android_ndk_toolchain_template.txt");
- } catch (IOException e) {
- throw new IllegalStateException(e);
- }
-
- StringBuilder toolchainMap = new StringBuilder();
- StringBuilder toolchainProtos = new StringBuilder();
- StringBuilder toolchains = new StringBuilder();
-
- for (String cpu : cpus) {
- toolchainMap.append(String.format("\"%s\": \":cc-compiler-%s\", ", abi, abi));
- toolchainProtos.append(
- toolchainTemplate
- .replace("%repository%", ruleName)
- .replace("%host_cpu%", hostCpu)
- .replace("%cpu%", cpu)
- .replace("%abi%", abi)
- .replace("%api_level%", apiLevel)
- .replace("%compiler%", compiler));
- toolchains.append(
- ccToolchainTemplate
- .replace("%repository%", ruleName)
- .replace("%host_cpu%", hostCpu)
- .replace("%cpu%", cpu)
- .replace("%abi%", abi)
- .replace("%api_level%", apiLevel)
- .replace("%compiler%", compiler));
+ androidCrosstoolRelease = AndroidNdkCrosstools.createCrosstoolRelease(
+ env.getListener(), ruleName, apiLevel, getNdkRelease(directoryValue, env));
+ } catch (NdkCrosstoolsException e) {
+ throw new RepositoryFunctionException(new IOException(e), Transience.PERSISTENT);
}
- String buildFile = ccToolchainSuiteTemplate
- .replace("%toolchain_map%", toolchainMap)
- .replace("%toolchain_protos%", toolchainProtos)
- .replace("%toolchains%", toolchains)
- .replace("%default_cpu%", abi);
-
+ String buildFile = createBuildFile(androidCrosstoolRelease, ruleName);
return writeBuildFile(directoryValue, buildFile);
}
@@ -155,4 +101,103 @@ public class AndroidNdkRepositoryFunction extends RepositoryFunction {
public Class<? extends RuleDefinition> getRuleDefinition() {
return AndroidNdkRepositoryRule.class;
}
+
+ private static String createBuildFile(CrosstoolRelease androidCrosstoolRelease, String ruleName) {
+
+ String ccToolchainSuiteTemplate = getTemplate("android_ndk_cc_toolchain_suite_template.txt");
+ String ccToolchainTemplate = getTemplate("android_ndk_cc_toolchain_template.txt");
+
+ StringBuilder toolchainMap = new StringBuilder();
+ for (DefaultCpuToolchain defaultToolchain : androidCrosstoolRelease.getDefaultToolchainList()) {
+ toolchainMap.append(String.format(" \"%s\": \":%s\",\n",
+ defaultToolchain.getCpu(), defaultToolchain.getToolchainIdentifier()));
+ }
+
+ StringBuilder ccToolchainRules = new StringBuilder();
+ for (CToolchain toolchain : androidCrosstoolRelease.getToolchainList()) {
+ ccToolchainRules.append(createCcToolchainRule(ccToolchainTemplate, toolchain));
+ }
+
+ String crosstoolReleaseProto = androidCrosstoolRelease.toString();
+
+ return ccToolchainSuiteTemplate
+ .replace("%ruleName%", ruleName)
+ .replace("%toolchainMap%", toolchainMap.toString().trim())
+ .replace("%crosstoolReleaseProto%", crosstoolReleaseProto)
+ .replace("%ccToolchainRules%", ccToolchainRules);
+ }
+
+ private static String createCcToolchainRule(String ccToolchainTemplate, CToolchain toolchain) {
+
+ // TODO(bazel-team): It's unfortunate to have to extract data from a CToolchain proto like this.
+ // It would be better to have a higher-level construction (like an AndroidToolchain class)
+ // from which the CToolchain proto and rule information needed here can be created.
+ // Alternatively it would be nicer to just be able to glob the entire NDK and add that one glob
+ // to each cc_toolchain rule, and then the complexities in the method and the templates can
+ // go away, but globbing the entire NDK takes ~60 seconds, mostly because of MD5ing all the
+ // binary files in the NDK (eg the .so / .a / .o files).
+
+ // This also includes the files captured with cxx_builtin_include_directory
+ String toolchainDirectory = NdkPaths.getToolchainDirectoryFromToolPath(
+ toolchain.getToolPathList().get(0).getPath());
+
+ // Create file glob patterns for the various files that the toolchain references.
+
+ String androidPlatformIncludes = NdkPaths.stripRepositoryPrefix(toolchain.getBuiltinSysroot())
+ + "/**/*";
+
+ List<String> toolchainFileGlobPatterns = new ArrayList<String>();
+ toolchainFileGlobPatterns.add(androidPlatformIncludes);
+
+ for (String cxxFlag : toolchain.getUnfilteredCxxFlagList()) {
+ if (!cxxFlag.startsWith("-")) { // Skip flag names
+ toolchainFileGlobPatterns.add(NdkPaths.stripRepositoryPrefix(cxxFlag) + "/**/*");
+ }
+ }
+
+ StringBuilder toolchainFileGlobs = new StringBuilder();
+ for (String toolchainFileGlobPattern : toolchainFileGlobPatterns) {
+ toolchainFileGlobs.append(String.format(
+ " \"%s\",\n", toolchainFileGlobPattern));
+ }
+
+ return ccToolchainTemplate
+ .replace("%toolchainName%", toolchain.getToolchainIdentifier())
+ .replace("%cpu%", toolchain.getTargetCpu())
+ .replace("%toolchainDirectory%", toolchainDirectory)
+ .replace("%toolchainFileGlobs%", toolchainFileGlobs.toString().trim());
+ }
+
+ private static NdkRelease getNdkRelease(FileValue directoryValue, Environment env)
+ throws RepositoryFunctionException {
+
+ Path releaseFilePath = directoryValue.realRootedPath().asPath().getRelative("ndk/RELEASE.TXT");
+
+ SkyKey releaseFileKey = FileValue.key(RootedPath.toRootedPath(
+ releaseFilePath, PathFragment.EMPTY_FRAGMENT));
+
+ String releaseFileContent;
+ try {
+ env.getValueOrThrow(releaseFileKey,
+ IOException.class,
+ FileSymlinkException.class,
+ InconsistentFilesystemException.class);
+
+ releaseFileContent = new String(FileSystemUtils.readContent(releaseFilePath));
+ } catch (IOException | FileSymlinkException | InconsistentFilesystemException e) {
+ throw new RepositoryFunctionException(
+ new IOException("Could not read RELEASE.TXT in Android NDK: " + e.getMessage()),
+ Transience.PERSISTENT);
+ }
+
+ return NdkRelease.create(releaseFileContent.trim());
+ }
+
+ private static String getTemplate(String templateFile) {
+ try {
+ return ResourceFileLoader.loadResource(AndroidNdkRepositoryFunction.class, templateFile);
+ } catch (IOException e) {
+ throw new IllegalStateException(e);
+ }
+ }
}
diff --git a/src/main/java/com/google/devtools/build/lib/bazel/rules/android/android_ndk_cc_toolchain_suite_template.txt b/src/main/java/com/google/devtools/build/lib/bazel/rules/android/android_ndk_cc_toolchain_suite_template.txt
index 5f3b5a1d80..be9258be3a 100644
--- a/src/main/java/com/google/devtools/build/lib/bazel/rules/android/android_ndk_cc_toolchain_suite_template.txt
+++ b/src/main/java/com/google/devtools/build/lib/bazel/rules/android/android_ndk_cc_toolchain_suite_template.txt
@@ -1,13 +1,29 @@
+# Copyright 2015 Google Inc. 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.
+
+# This build file was automatically generated for the
+# android_ndk_repository rule "%ruleName%"
+
package(default_visibility = ["//visibility:public"])
cc_toolchain_suite(
name = "toolchain",
- toolchains = { %toolchain_map% },
+ toolchains = {
+ %toolchainMap%
+ },
proto = """
-major_version: "android"
-minor_version: ""
-default_target_cpu: "%default_cpu%"
-%toolchain_protos%
+%crosstoolReleaseProto%
""")
cc_library(
@@ -15,4 +31,4 @@ cc_library(
srcs = [],
)
-%toolchains%
+%ccToolchainRules%
diff --git a/src/main/java/com/google/devtools/build/lib/bazel/rules/android/android_ndk_cc_toolchain_template.txt b/src/main/java/com/google/devtools/build/lib/bazel/rules/android/android_ndk_cc_toolchain_template.txt
index c920236f00..6dbdd17bae 100644
--- a/src/main/java/com/google/devtools/build/lib/bazel/rules/android/android_ndk_cc_toolchain_template.txt
+++ b/src/main/java/com/google/devtools/build/lib/bazel/rules/android/android_ndk_cc_toolchain_template.txt
@@ -1,41 +1,32 @@
-filegroup(
- name = "%abi%-android-%compiler%-toolchain",
- srcs = glob([
- "toolchains/%cpu%-linux-androideabi-%compiler%/**",
- ]),
- output_licenses = ["unencumbered"],
-)
-
-filegroup(
- name = "%abi%-android-%api_level%-%compiler%-files",
- srcs = [
- ":everything-%api_level%-%abi%",
- ":%abi%-android-%compiler%-toolchain",
- ],
-)
+################################################################
+# %toolchainName%
+################################################################
cc_toolchain(
- name = "cc-compiler-%abi%",
- all_files = ":%abi%-android-%api_level%-%compiler%-files",
- compiler_files = ":%abi%-android-%compiler%-toolchain",
- cpu = "%abi%",
- dwp_files = ":%abi%-android-%compiler%-toolchain",
- dynamic_runtime_libs = [":%abi%-android-%compiler%-toolchain"],
- linker_files = ":%abi%-android-%compiler%-toolchain",
- objcopy_files = ":%abi%-android-%compiler%-toolchain",
- static_runtime_libs = [":%abi%-android-%compiler%-toolchain"],
- strip_files = ":%abi%-android-%compiler%-toolchain",
+ name = "%toolchainName%",
+ all_files = ":%toolchainName%-all_files",
+ compiler_files = ":%toolchainName%-toolchain_files",
+ cpu = "%cpu%",
+ dwp_files = ":%toolchainName%-toolchain_files",
+ dynamic_runtime_libs = [":%toolchainName%-toolchain_files"],
+ linker_files = ":%toolchainName%-toolchain_files",
+ objcopy_files = ":%toolchainName%-toolchain_files",
+ static_runtime_libs = [":%toolchainName%-toolchain_files"],
+ strip_files = ":%toolchainName%-toolchain_files",
supports_param_files = 0,
)
filegroup(
- name = "everything-%api_level%-%abi%",
- srcs = glob(
- [
- "ndk/platforms/android-%api_level%/arch-%cpu%/usr/include/**/*.h",
- "ndk/platforms/android-%api_level%/arch-%cpu%/usr/lib/**/*.a",
- "ndk/platforms/android-%api_level%/arch-%cpu%/usr/lib/**/*.o",
- "ndk/platforms/android-%api_level%/arch-%cpu%/usr/lib/**/*.so",
- ],
- ),
+ name = "%toolchainName%-toolchain_files",
+ srcs = glob(["toolchains/%toolchainDirectory%/**"]),
+ output_licenses = ["unencumbered"],
+)
+
+filegroup(
+ name = "%toolchainName%-all_files",
+ srcs = [
+ ":%toolchainName%-toolchain_files",
+ ] + glob([
+ %toolchainFileGlobs%
+ ]),
)
diff --git a/src/main/java/com/google/devtools/build/lib/bazel/rules/android/android_ndk_toolchain_template.txt b/src/main/java/com/google/devtools/build/lib/bazel/rules/android/android_ndk_toolchain_template.txt
deleted file mode 100644
index 836a807cb8..0000000000
--- a/src/main/java/com/google/devtools/build/lib/bazel/rules/android/android_ndk_toolchain_template.txt
+++ /dev/null
@@ -1,123 +0,0 @@
-default_toolchain {
- cpu: "%abi%"
- toolchain_identifier: "%abi%-linux-androideabi-%compiler%"
-}
-
-toolchain {
-
- # this should be more specific
- abi_version: "local"
- abi_libc_version: "local"
-
- compiler: "gcc"
- host_system_name: "local"
- needsPic: true
- supports_gold_linker: false
- supports_incremental_linker: false
- supports_fission: false
- supports_interface_shared_objects: false
- supports_normalizing_ar: false
- supports_start_end_lib: false
- supports_thin_archives: false
- target_libc: "local"
-
- target_cpu: "%abi%"
- target_system_name: "%abi%-linux-androideabi-%compiler%"
- toolchain_identifier: "%abi%-linux-androideabi-%compiler%"
-
- tool_path { name: "ar"
- path: "external/%repository%/ndk/toolchains/%cpu%-linux-androideabi-%compiler%/prebuilt/%host_cpu%/bin/%cpu%-linux-androideabi-ar"
- }
- tool_path { name: "compat-ld"
- path: "external/%repository%/ndk/toolchains/%cpu%-linux-androideabi-%compiler%/prebuilt/%host_cpu%/bin/%cpu%-linux-androideabi-ld"
- }
- tool_path { name: "cpp"
- path: "external/%repository%/ndk/toolchains/%cpu%-linux-androideabi-%compiler%/prebuilt/%host_cpu%/bin/%cpu%-linux-androideabi-cpp"
- }
- tool_path { name: "dwp"
- path: "external/%repository%/ndk/toolchains/%cpu%-linux-androideabi-%compiler%/prebuilt/%host_cpu%/bin/%cpu%-linux-androideabi-dwp"
- }
- tool_path { name: "gcc"
- path: "external/%repository%/ndk/toolchains/%cpu%-linux-androideabi-%compiler%/prebuilt/%host_cpu%/bin/%cpu%-linux-androideabi-gcc"
- }
- tool_path { name: "gcov"
- path: "external/%repository%/ndk/toolchains/%cpu%-linux-androideabi-%compiler%/prebuilt/%host_cpu%/bin/%cpu%-linux-androideabi-gcov"
- }
- tool_path { name: "ld"
- path: "external/%repository%/ndk/toolchains/%cpu%-linux-androideabi-%compiler%/prebuilt/%host_cpu%/bin/%cpu%-linux-androideabi-ld"
- }
- tool_path { name: "nm"
- path: "external/%repository%/ndk/toolchains/%cpu%-linux-androideabi-%compiler%/prebuilt/%host_cpu%/bin/%cpu%-linux-androideabi-nm"
- }
- tool_path { name: "objcopy"
- path: "external/%repository%/ndk/toolchains/%cpu%-linux-androideabi-%compiler%/prebuilt/%host_cpu%/bin/%cpu%-linux-androideabi-objcopy"
- }
- tool_path { name: "strip"
- path: "external/%repository%/ndk/toolchains/%cpu%-linux-androideabi-%compiler%/prebuilt/%host_cpu%/bin/%cpu%-linux-androideabi-strip"
- }
- tool_path { name: "objdump"
- path: "external/%repository%/ndk/toolchains/%cpu%-linux-androideabi-%compiler%/prebuilt/%host_cpu%/bin/%cpu%-linux-androideabi-objdump"
- }
- objcopy_embed_flag: "-I"
-
- cxx_flag: "-std=c++0x"
- compilation_mode_flags {
- mode: FASTBUILD
- }
- compilation_mode_flags {
- mode: DBG
- }
- compilation_mode_flags {
- mode: COVERAGE
- }
- compilation_mode_flags {
- mode: OPT
- }
-
- cxx_flag: "-std=gnu++11"
-
- cxx_builtin_include_directory: "external/%repository%/ndk/platforms/android-%api_level%/arch-%cpu%/usr/include"
- cxx_builtin_include_directory: "external/%repository%/ndk/sources"
- cxx_builtin_include_directory: "external/%repository%/ndk/toolchains/%cpu%-linux-androideabi-%compiler%/prebuilt/%host_cpu%/lib/gcc/%cpu%-linux-androideabi/%compiler%/include"
- cxx_builtin_include_directory: "external/%repository%/ndk/toolchains/%cpu%-linux-androideabi-%compiler%/prebuilt/%host_cpu%/lib/gcc/%cpu%-linux-androideabi/%compiler%/include-fixed"
-
- unfiltered_cxx_flag: "-isystemexternal/%repository%/ndk/platforms/android-%api_level%/arch-%cpu%/usr/include"
- unfiltered_cxx_flag: "-isystemexternal/%repository%/ndk/sources/cxx-stl/gnu-libstdc++/%compiler%/include"
- unfiltered_cxx_flag: "-isystemexternal/%repository%/ndk/sources/cxx-stl/gnu-libstdc++/%compiler%/libs/%abi%/include"
-
- unfiltered_cxx_flag: "-isystem"
- unfiltered_cxx_flag: "external/%repository%/ndk/sources/cxx-stl/stlport/stlport"
- unfiltered_cxx_flag: "-isystem"
- unfiltered_cxx_flag: "external/%repository%/ndk/sources/cxx-stl/gabi++/include"
-
- linking_mode_flags {
- mode: FULLY_STATIC
- }
- objcopy_embed_flag: "-I"
- objcopy_embed_flag: "binary"
- linking_mode_flags {
- mode: MOSTLY_STATIC
- }
- linking_mode_flags {
- mode: DYNAMIC
- }
-
- unfiltered_cxx_flag: "-fno-canonical-system-headers"
- unfiltered_cxx_flag: "-no-canonical-prefixes"
-
- linker_flag: "-no-canonical-prefixes"
-
- compiler_flag: "-fPIE"
- compiler_flag: "-DANDROID"
- compiler_flag: "-g"
-
- linker_flag: "--sysroot=external/%repository%/ndk/platforms/android-%api_level%/arch-%cpu%"
- linker_flag: "-fPIE"
- linker_flag: "-pie"
-
- linker_flag: "-Lexternal/%repository%/ndk/sources/cxx-stl/gnu-libstdc++/%compiler%/libs/%abi%/"
- linker_flag: "-lgnustl_static"
- linker_flag: "-lsupc++"
- linker_flag: "-lc"
- linker_flag: "-lm"
-}
diff --git a/src/main/java/com/google/devtools/build/lib/bazel/rules/android/ndkcrosstools/AndroidNdkCrosstools.java b/src/main/java/com/google/devtools/build/lib/bazel/rules/android/ndkcrosstools/AndroidNdkCrosstools.java
new file mode 100644
index 0000000000..4ba18b8874
--- /dev/null
+++ b/src/main/java/com/google/devtools/build/lib/bazel/rules/android/ndkcrosstools/AndroidNdkCrosstools.java
@@ -0,0 +1,222 @@
+// Copyright 2015 Google Inc. 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.bazel.rules.android.ndkcrosstools;
+
+import com.google.common.collect.ImmutableList;
+import com.google.common.collect.ImmutableMap;
+import com.google.devtools.build.lib.events.Event;
+import com.google.devtools.build.lib.events.EventHandler;
+import com.google.devtools.build.lib.util.OS;
+import com.google.devtools.build.lib.view.config.crosstool.CrosstoolConfig.CToolchain;
+import com.google.devtools.build.lib.view.config.crosstool.CrosstoolConfig.CrosstoolRelease;
+import com.google.devtools.build.lib.view.config.crosstool.CrosstoolConfig.DefaultCpuToolchain;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Map.Entry;
+
+/**
+ * Generates a CrosstoolRelease proto for the Android NDK.
+ */
+public class AndroidNdkCrosstools {
+
+ // TODO(bazel-team): Support future versions of the NDK.
+ private static final String KNOWN_NDK_REVISION = "r10e";
+
+ /**
+ * Exception thrown when there is an error creating the crosstools file.
+ */
+ public static class NdkCrosstoolsException extends Exception {
+ private NdkCrosstoolsException(String msg) {
+ super(msg);
+ }
+ }
+
+ /**
+ * Creates a CrosstoolRelease proto for the Android NDK, given the API level to use and the
+ * release revision. The crosstools are generated through code rather than checked in as a flat
+ * file to reduce the amount of templating needed (for parameters like the release name and
+ * certain paths), to reduce duplication, and to make it easier to support future versions of the
+ * NDK. TODO(bazel-team): Eventually we should move this into Skylark so the crosstools can be
+ * updated independently of Bazel itself.
+ *
+ * @param eventHandler The event handler for sending warning messages.
+ * @param repositoryName The name of the repository, which should correspond to the name of the
+ * android_ndk_repository rule.
+ * @param apiLevel The API level used for the NDK.
+ * @param ndkRelease The NDK release
+ * @return A CrosstoolRelease for the Android NDK.
+ * @throws NdkCrosstoolsException If the crosstool could not be created.
+ */
+ public static CrosstoolRelease createCrosstoolRelease(
+ EventHandler eventHandler, String repositoryName, String apiLevel, NdkRelease ndkRelease)
+ throws NdkCrosstoolsException {
+
+ // Check that the Android NDK revision is both valid and one we know about.
+ if (!ndkRelease.isValid) {
+
+ // Try using the NDK revision we know about.
+ ndkRelease = NdkRelease.guessBitness(KNOWN_NDK_REVISION);
+
+ eventHandler.handle(Event.warn(String.format(
+ "The revision of the Andorid NDK given in android_ndk_repository rule '%s' could not be "
+ + "determined (the revision string found is '%s'). "
+ + "Defaulting to Android NDK revision %s", repositoryName, ndkRelease.rawRelease,
+ ndkRelease)));
+
+ } else if (!KNOWN_NDK_REVISION.equals(ndkRelease.release)) {
+ eventHandler.handle(Event.warn(String.format(
+ "Bazel Android NDK crosstools are based on Android NDK revision %s. "
+ + "The revision of the Android NDK given in android_ndk_repository rule '%s' is '%s'",
+ KNOWN_NDK_REVISION, repositoryName, ndkRelease.release)));
+ }
+
+ return CrosstoolRelease.newBuilder()
+ .setMajorVersion("android")
+ .setMinorVersion("")
+ .setDefaultTargetCpu("armeabi")
+ .addAllDefaultToolchain(getDefaultCpuToolchains())
+ .addAllToolchain(createToolchains(eventHandler, repositoryName, apiLevel, ndkRelease))
+ .build();
+ }
+
+ private static ImmutableList<CToolchain> createToolchains(
+ EventHandler eventHandler, String repositoryName, String apiLevel, NdkRelease ndkRelease)
+ throws NdkCrosstoolsException {
+
+ String hostPlatform = getHostPlatform(ndkRelease);
+ NdkPaths ndkPaths = new NdkPaths(eventHandler, repositoryName, hostPlatform, apiLevel);
+
+ List<CToolchain.Builder> toolchainBuilders = new ArrayList<>();
+ toolchainBuilders.addAll(new ArmCrosstools(ndkPaths).createCrosstools());
+ toolchainBuilders.addAll(new MipsCrosstools(ndkPaths).createCrosstools());
+ toolchainBuilders.addAll(new X86Crosstools(ndkPaths).createCrosstools());
+
+ ImmutableList.Builder<CToolchain> toolchains = new ImmutableList.Builder<>();
+
+ // Set attributes common to all toolchains.
+ for (CToolchain.Builder toolchainBuilder : toolchainBuilders) {
+ toolchainBuilder
+ .setHostSystemName(hostPlatform)
+ .setTargetLibc("local")
+ .setAbiVersion(toolchainBuilder.getTargetCpu())
+ .setAbiLibcVersion("local");
+
+ // builtin_sysroot is set individually on each toolchain.
+ toolchainBuilder.addCxxBuiltinIncludeDirectory("%sysroot%/usr/include");
+
+ // Add a toolchain for each available STL implementation.
+ for (CToolchain.Builder builder : createStlImpls(toolchainBuilder, ndkPaths)) {
+ toolchains.add(builder.build());
+ }
+ }
+
+ return toolchains.build();
+ }
+
+ /**
+ * Creates a list of CToolchain builders for each STL implementation available in the NDK based
+ * on the given CToolchain builder.
+ */
+ private static ImmutableList<CToolchain.Builder> createStlImpls(
+ CToolchain.Builder builder, NdkPaths ndkPaths) {
+ ImmutableList.Builder<CToolchain.Builder> toolchains = ImmutableList.builder();
+
+ CToolchain baseToolchain = builder.build();
+
+ // Extract the gcc version from the compiler, which should look like "gcc-4.8" or "gcc-4.9".
+ String gccVersion = baseToolchain.getCompiler().split("-")[1];
+
+ toolchains.add(CToolchain.newBuilder(baseToolchain)
+ .setToolchainIdentifier(baseToolchain.getToolchainIdentifier() + "-gnu-libstdcpp")
+ .addAllUnfilteredCxxFlag(createIncludeFlags(ndkPaths.createGnuLibstdcIncludePaths(
+ gccVersion, baseToolchain.getTargetCpu()))));
+
+ toolchains.add(CToolchain.newBuilder(baseToolchain)
+ .setToolchainIdentifier(baseToolchain.getToolchainIdentifier() + "-libcpp")
+ .addAllUnfilteredCxxFlag(createIncludeFlags(ndkPaths.createLibcxxIncludePaths())));
+
+ toolchains.add(CToolchain.newBuilder(baseToolchain)
+ .setToolchainIdentifier(baseToolchain.getToolchainIdentifier() + "-stlport")
+ .addAllUnfilteredCxxFlag(createIncludeFlags(ndkPaths.createStlportIncludePaths())));
+
+ return toolchains.build();
+ }
+
+ private static Iterable<String> createIncludeFlags(Iterable<String> includePaths) {
+ ImmutableList.Builder<String> includeFlags = ImmutableList.builder();
+ for (String includePath : includePaths) {
+ includeFlags.add("-isystem");
+ includeFlags.add(includePath);
+ }
+ return includeFlags.build();
+ }
+
+ private static ImmutableList<DefaultCpuToolchain> getDefaultCpuToolchains() {
+ // TODO(bazel-team): It would be better to generate this somehow.
+ ImmutableMap<String, String> defaultCpus = ImmutableMap.<String, String>builder()
+ .put("armeabi", "arm-linux-androideabi-4.9-gnu-libstdcpp")
+ .put("armeabi-v7a", "arm-linux-androideabi-4.9-v7a-gnu-libstdcpp")
+ .put("armeabi-v7a-hard", "arm-linux-androideabi-4.9-v7a-hard-gnu-libstdcpp")
+ .put("armeabi-thumb", "arm-linux-androideabi-4.9-thumb-gnu-libstdcpp")
+ .put("armeabi-v7a-thumb", "arm-linux-androideabi-4.9-v7a-thumb-gnu-libstdcpp")
+ .put("armeabi-v7a-hard-thumb", "arm-linux-androideabi-4.9-v7a-hard-thumb-gnu-libstdcpp")
+ .put("arm64-v8a", "aarch64-linux-android-4.9-gnu-libstdcpp")
+ .put("mips", "mipsel-linux-android-4.9-gnu-libstdcpp")
+ .put("mips64", "mips64el-linux-android-4.9-gnu-libstdcpp")
+ .put("x86", "x86-4.9-gnu-libstdcpp")
+ .put("x86_64", "x86_64-4.9-gnu-libstdcpp")
+ .build();
+
+ ImmutableList.Builder<DefaultCpuToolchain> defaultCpuToolchains = ImmutableList.builder();
+ for (Entry<String, String> entry : defaultCpus.entrySet()) {
+ defaultCpuToolchains.add(DefaultCpuToolchain.newBuilder()
+ .setCpu(entry.getKey())
+ .setToolchainIdentifier(entry.getValue())
+ .build());
+ }
+ return defaultCpuToolchains.build();
+ }
+
+ private static String getHostPlatform(NdkRelease ndkRelease) throws NdkCrosstoolsException {
+ String hostOs;
+ switch (OS.getCurrent()) {
+ case DARWIN:
+ hostOs = "darwin";
+ break;
+ case LINUX:
+ hostOs = "linux";
+ break;
+ case WINDOWS:
+ hostOs = "windows";
+ if (!ndkRelease.is64Bit) {
+ // 32-bit windows paths don't have the "-x86" suffix in the NDK (added below), but
+ // 64-bit windows does have the "-x86_64" suffix.
+ return hostOs;
+ }
+ break;
+ case UNKNOWN:
+ default:
+ throw new NdkCrosstoolsException(
+ String.format("NDK does not support the host platform \"%s\"", OS.getCurrent()));
+ }
+
+ // Use the arch from the NDK rather than detecting the actual platform, since it's possible
+ // to use the 32-bit NDK on a 64-bit machine.
+ String hostArch = ndkRelease.is64Bit ? "x86_64" : "x86";
+
+ return hostOs + "-" + hostArch;
+ }
+}
diff --git a/src/main/java/com/google/devtools/build/lib/bazel/rules/android/ndkcrosstools/ApiLevel.java b/src/main/java/com/google/devtools/build/lib/bazel/rules/android/ndkcrosstools/ApiLevel.java
new file mode 100644
index 0000000000..34e6663a7b
--- /dev/null
+++ b/src/main/java/com/google/devtools/build/lib/bazel/rules/android/ndkcrosstools/ApiLevel.java
@@ -0,0 +1,154 @@
+// Copyright 2015 Google Inc. 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.bazel.rules.android.ndkcrosstools;
+
+import com.google.common.collect.ImmutableListMultimap;
+import com.google.common.collect.ImmutableMap;
+import com.google.common.collect.Iterables;
+import com.google.devtools.build.lib.events.Event;
+import com.google.devtools.build.lib.events.EventHandler;
+
+/**
+ * Class which encodes information from the Android NDK makefiles about API levels.
+ */
+class ApiLevel {
+
+ /**
+ * Maps an Android API level to the architectures that that level supports.
+ * Based on the directories in the "platforms" directory in the NDK.
+ */
+ private static final ImmutableListMultimap<String, String> API_LEVEL_TO_ARCHITECTURES =
+ ImmutableListMultimap.<String, String>builder()
+ .putAll("3", "arm")
+ .putAll("4", "arm")
+ .putAll("5", "arm")
+ .putAll("8", "arm")
+ .putAll("9", "arm", "mips", "x86")
+ .putAll("12", "arm", "mips", "x86")
+ .putAll("13", "arm", "mips", "x86")
+ .putAll("14", "arm", "mips", "x86")
+ .putAll("15", "arm", "mips", "x86")
+ .putAll("16", "arm", "mips", "x86")
+ .putAll("17", "arm", "mips", "x86")
+ .putAll("18", "arm", "mips", "x86")
+ .putAll("19", "arm", "mips", "x86")
+ .putAll("21", "arm", "mips", "x86", "arm64", "mips64", "x86_64")
+ .build();
+
+ /**
+ * Maps an API level to it's equivalent API level in the NDK.
+ *
+ * <p>Per the "special cases" listed in build/core/add-application.mk:
+ *
+ * <pre>
+ * SPECIAL CASES:
+ * 1) android-6 and android-7 are the same thing as android-5
+ * 2) android-10 and android-11 are the same thing as android-9
+ * 3) android-20 is the same thing as android-19
+ * 4) android-21 and up are the same thing as android-21
+ * ADDITIONAL CASES for remote server where total number of files is limited
+ * 5) android-13 is the same thing as android-12
+ * 6) android-15 is the same thing as android-14
+ * 7) android-17 is the same thing as android-16
+ * </pre>
+ */
+ private static final ImmutableMap<String, String> API_EQUIVALENCIES =
+ ImmutableMap.<String, String>builder()
+ .put("3", "3")
+ .put("4", "4")
+
+ // Case 1
+ .put("5", "5")
+ .put("6", "5")
+ .put("7", "5")
+
+ .put("8", "8")
+
+ // Case 2
+ .put("9", "9")
+ .put("10", "9")
+ .put("11", "9")
+
+ // Case 5
+ .put("12", "12")
+ .put("13", "12")
+
+ // Case 6
+ .put("14", "14")
+ .put("15", "14")
+
+ // Case 7
+ .put("16", "16")
+ .put("17", "16")
+
+ .put("18", "18")
+
+ // Case 3
+ .put("19", "19")
+ .put("20", "19")
+
+ // Case 4
+ .put("21", "21")
+ .put("22", "21")
+
+ .build();
+
+ private final String correctedApiLevel;
+
+ ApiLevel(EventHandler eventHandler, String repositoryName, String apiLevel) {
+ this.correctedApiLevel = getCorrectedApiLevel(eventHandler, repositoryName, apiLevel);
+ }
+
+ /**
+ * Translates the given API level to the equivalent API level in the NDK.
+ */
+ static String getCorrectedApiLevel(
+ EventHandler eventHandler, String repositoryName, String apiLevel) {
+
+ String correctedApiLevel = API_EQUIVALENCIES.get(apiLevel);
+ if (correctedApiLevel == null) {
+ // The user specified an API level we don't know about. Default to the most recent API level.
+ // This relies on the entries being added in sorted order.
+ String latestApiLevel = Iterables.getLast(API_EQUIVALENCIES.keySet());
+ correctedApiLevel = API_EQUIVALENCIES.get(latestApiLevel);
+
+ eventHandler.handle(Event.warn(String.format(
+ "API level %s specified by android_ndk_repository '%s' is not available. "
+ + "Using latest known API level %s",
+ apiLevel, repositoryName, latestApiLevel)));
+ }
+ return correctedApiLevel;
+ }
+
+ String getCpuCorrectedApiLevel(String targetCpu) {
+
+ // Check that this API level supports the given cpu architecture (eg 64 bit is supported on only
+ // 21+).
+ if (!API_LEVEL_TO_ARCHITECTURES.get(correctedApiLevel).contains(targetCpu)) {
+ // If the given API level does not support the given architecture, find an API level that
+ // does support this architecture. A warning isn't printed because the crosstools for
+ // architectures that aren't supported by this API level are generated anyway, even if the
+ // user doesn't intend to use them (eg, if they're building for only 32 bit archs, the
+ // crosstools for the 64 bit toolchains are generated regardless).
+ // API_LEVEL_TO_ARCHITECTURES.inverse() returns a map of architectures to the APIs that
+ // support that architecture.
+ return Iterables.getLast(API_LEVEL_TO_ARCHITECTURES.inverse().get(targetCpu));
+ }
+
+ return correctedApiLevel;
+ }
+
+}
+
diff --git a/src/main/java/com/google/devtools/build/lib/bazel/rules/android/ndkcrosstools/ArmCrosstools.java b/src/main/java/com/google/devtools/build/lib/bazel/rules/android/ndkcrosstools/ArmCrosstools.java
new file mode 100644
index 0000000000..dd046558c6
--- /dev/null
+++ b/src/main/java/com/google/devtools/build/lib/bazel/rules/android/ndkcrosstools/ArmCrosstools.java
@@ -0,0 +1,445 @@
+// Copyright 2015 Google Inc. 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.bazel.rules.android.ndkcrosstools;
+
+import com.google.common.collect.ImmutableList;
+import com.google.devtools.build.lib.rules.cpp.CppConfiguration;
+import com.google.devtools.build.lib.view.config.crosstool.CrosstoolConfig.CToolchain;
+import com.google.devtools.build.lib.view.config.crosstool.CrosstoolConfig.CompilationMode;
+import com.google.devtools.build.lib.view.config.crosstool.CrosstoolConfig.CompilationModeFlags;
+import com.google.devtools.build.lib.view.config.crosstool.CrosstoolConfig.ToolPath;
+
+/**
+ * Crosstool definitions for ARM. These values are based on the setup.mk files in the Android NDK
+ * toolchain directories.
+ */
+class ArmCrosstools {
+
+ private final NdkPaths ndkPaths;
+
+ ArmCrosstools(NdkPaths ndkPaths) {
+ this.ndkPaths = ndkPaths;
+ }
+
+ ImmutableList<CToolchain.Builder> createCrosstools() {
+
+ ImmutableList.Builder<CToolchain.Builder> builder = ImmutableList.builder();
+
+ builder.add(createAarch64Toolchain());
+
+ // The flags for aarch64 clang 3.5 and 3.6 are the same, they differ only in the LLVM version
+ // given in their tool paths.
+ builder.add(createAarch64ClangToolchain("3.5"));
+ builder.add(createAarch64ClangToolchain("3.6"));
+
+ // The Android NDK Make files create several sets of flags base on
+ // arm vs armeabi-v7a vs armeabi-v7a-hard, and arm vs thumb mode, each for gcc 4.8 and 4.9,
+ // resulting in:
+ // arm-linux-androideabi-4.8
+ // arm-linux-androideabi-4.8-v7a
+ // arm-linux-androideabi-4.8-v7a-hard
+ // arm-linux-androideabi-4.8-thumb
+ // arm-linux-androideabi-4.8-v7a-thumb
+ // arm-linux-androideabi-4.8-v7a-hard-thumb
+ // arm-linux-androideabi-4.9
+ // arm-linux-androideabi-4.9-v7a
+ // arm-linux-androideabi-4.9-v7a-hard
+ // arm-linux-androideabi-4.9-thumb
+ // arm-linux-androideabi-4.9-v7a-thumb
+ // arm-linux-androideabi-4.9-v7a-hard-thumb
+ //
+ // and similar for the Clang toolchains.
+
+ // gcc-4.8 for arm doesn't have the gcov-tool.
+ CppConfiguration.Tool[] excludedTools = { CppConfiguration.Tool.GCOVTOOL };
+ createArmeabiToolchain(builder, "4.8", "-fstack-protector", false, excludedTools);
+ createArmeabiToolchain(builder, "4.8", "-fstack-protector", true, excludedTools);
+ createArmeabiToolchain(builder, "4.9", "-fstack-protector-strong", false);
+ createArmeabiToolchain(builder, "4.9", "-fstack-protector-strong", true);
+
+ createArmeabiClangToolchain(builder, "3.5", false);
+ createArmeabiClangToolchain(builder, "3.5", true);
+ createArmeabiClangToolchain(builder, "3.6", false);
+ createArmeabiClangToolchain(builder, "3.6", true);
+
+ return builder.build();
+ }
+
+ private CToolchain.Builder createAarch64Toolchain() {
+
+ String toolchainName = "aarch64-linux-android-4.9";
+ String targetPlatform = "aarch64-linux-android";
+
+ return CToolchain.newBuilder()
+ .setToolchainIdentifier("aarch64-linux-android-4.9")
+ .setTargetSystemName("aarch64-linux-android")
+ .setTargetCpu("arm64-v8a")
+ .setCompiler("gcc-4.9")
+
+ .addAllToolPath(ndkPaths.createToolpaths(toolchainName, targetPlatform))
+
+ .addAllCxxBuiltinIncludeDirectory(ndkPaths.createToolchainIncludePaths(
+ toolchainName, targetPlatform, "4.9"))
+
+ .setBuiltinSysroot(ndkPaths.createBuiltinSysroot("arm64"))
+
+ // Compiler flags
+ .addCompilerFlag("-fpic")
+ .addCompilerFlag("-ffunction-sections")
+ .addCompilerFlag("-funwind-tables")
+ .addCompilerFlag("-fstack-protector-strong")
+ .addCompilerFlag("-no-canonical-prefixes")
+
+ // Linker flags
+ .addLinkerFlag("-no-canonical-prefixes")
+
+ // Additional release flags
+ .addCompilationModeFlags(CompilationModeFlags.newBuilder()
+ .setMode(CompilationMode.OPT)
+ .addCompilerFlag("-O2")
+ .addCompilerFlag("-g")
+ .addCompilerFlag("-DNDEBUG")
+ .addCompilerFlag("-fomit-frame-pointer")
+ .addCompilerFlag("-fstrict-aliasing")
+ .addCompilerFlag("-funswitch-loops")
+ .addCompilerFlag("-finline-limit=300"))
+
+ // Additional debug flags
+ .addCompilationModeFlags(CompilationModeFlags.newBuilder()
+ .setMode(CompilationMode.DBG)
+ .addCompilerFlag("-O0")
+ .addCompilerFlag("-UNDEBUG")
+ .addCompilerFlag("-fno-omit-frame-pointer")
+ .addCompilerFlag("-fno-strict-aliasing"));
+ }
+
+ private CToolchain.Builder createAarch64ClangToolchain(String clangVersion) {
+
+ String toolchainName = "aarch64-linux-android-4.9";
+ String targetPlatform = "aarch64-linux-android";
+ String gccToolchain = ndkPaths.createGccToolchainPath(toolchainName);
+ String llvmTriple = "aarch64-none-linux-android";
+
+ return CToolchain.newBuilder()
+ .setToolchainIdentifier("aarch64-linux-android-clang" + clangVersion)
+ .setTargetSystemName("aarch64-linux-android")
+ .setTargetCpu("arm64-v8a")
+ .setCompiler("gcc-4.9")
+
+ .addAllToolPath(ndkPaths.createClangToolpaths(toolchainName, targetPlatform, clangVersion))
+
+ .addAllCxxBuiltinIncludeDirectory(ndkPaths.createToolchainIncludePaths(
+ toolchainName, targetPlatform, "4.9"))
+
+ .setBuiltinSysroot(ndkPaths.createBuiltinSysroot("arm64"))
+
+ // Compiler flags
+ .addCompilerFlag("-gcc-toolchain")
+ .addCompilerFlag(gccToolchain)
+ .addCompilerFlag("-target")
+ .addCompilerFlag(llvmTriple)
+ .addCompilerFlag("-ffunction-sections")
+ .addCompilerFlag("-funwind-tables")
+ .addCompilerFlag("-fstack-protector-strong")
+ .addCompilerFlag("-fpic")
+ .addCompilerFlag("-Wno-invalid-command-line-argument")
+ .addCompilerFlag("-Wno-unused-command-line-argument")
+ .addCompilerFlag("-no-canonical-prefixes")
+
+ // Linker flags
+ .addLinkerFlag("-gcc-toolchain")
+ .addLinkerFlag(gccToolchain)
+ .addLinkerFlag("-target")
+ .addLinkerFlag(llvmTriple)
+ .addLinkerFlag("-no-canonical-prefixes")
+
+ // Additional release flags
+ .addCompilationModeFlags(CompilationModeFlags.newBuilder()
+ .setMode(CompilationMode.OPT)
+ .addCompilerFlag("-O2")
+ .addCompilerFlag("-g")
+ .addCompilerFlag("-DNDEBUG")
+ .addCompilerFlag("-fomit-frame-pointer")
+ .addCompilerFlag("-fstrict-aliasing"))
+
+ // Additional debug flags
+ .addCompilationModeFlags(CompilationModeFlags.newBuilder()
+ .setMode(CompilationMode.DBG)
+ .addCompilerFlag("-O0")
+ .addCompilerFlag("-UNDEBUG")
+ .addCompilerFlag("-fno-omit-frame-pointer")
+ .addCompilerFlag("-fno-strict-aliasing"));
+ }
+
+ private void createArmeabiToolchain(ImmutableList.Builder<CToolchain.Builder> builder,
+ String gccVersion, String stackProtectorFlag, boolean thumb,
+ CppConfiguration.Tool... excludedTools) {
+
+ builder.add(createBaseArmeabiToolchain(thumb, gccVersion, stackProtectorFlag, excludedTools)
+ .setToolchainIdentifier(
+ createArmeabiName("arm-linux-androideabi-%s", gccVersion, thumb))
+ .setTargetCpu("armeabi")
+
+ .addCompilerFlag("-march=armv5te")
+ .addCompilerFlag("-mtune=xscale")
+ .addCompilerFlag("-msoft-float"));
+
+ builder.add(createBaseArmeabiToolchain(thumb, gccVersion, stackProtectorFlag, excludedTools)
+ .setToolchainIdentifier(
+ createArmeabiName("arm-linux-androideabi-%s-v7a", gccVersion, thumb))
+ .setTargetCpu("armeabi-v7a")
+
+ .addCompilerFlag("-march=armv7-a")
+ .addCompilerFlag("-mfpu=vfpv3-d16")
+ .addCompilerFlag("-mfloat-abi=softfp")
+
+ .addLinkerFlag("-march=armv7-a")
+ .addLinkerFlag("-Wl,--fix-cortex-a8"));
+
+ builder.add(createBaseArmeabiToolchain(thumb, gccVersion, stackProtectorFlag, excludedTools)
+ .setToolchainIdentifier(
+ createArmeabiName("arm-linux-androideabi-%s-v7a-hard", gccVersion, thumb))
+ .setTargetCpu("armeabi-v7a-hard")
+
+ .addCompilerFlag("-march=armv7-a")
+ .addCompilerFlag("-mfpu=vfpv3-d16")
+ .addCompilerFlag("-mhard-float")
+ .addCompilerFlag("-D_NDK_MATH_NO_SOFTFP=1")
+
+ .addLinkerFlag("-march=armv7-a")
+ .addLinkerFlag("-Wl,--fix-cortex-a8")
+ .addLinkerFlag("-Wl,--no-warn-mismatch")
+ .addLinkerFlag("-lm_hard"));
+ }
+
+ private String createArmeabiName(String base, String gccVersion, boolean thumb) {
+ String thumbString = thumb ? "-thumb" : "";
+ return String.format(base, gccVersion) + thumbString;
+ }
+
+ /**
+ * Flags common to arm-linux-androideabi*
+ */
+ private CToolchain.Builder createBaseArmeabiToolchain(
+ boolean thumb, String gccVersion, String stackProtectorFlag,
+ CppConfiguration.Tool... excludedTools) {
+
+ String toolchainName = "arm-linux-androideabi-" + gccVersion;
+ String targetPlatform = "arm-linux-androideabi";
+
+ ImmutableList<ToolPath> toolPaths = ndkPaths.createToolpaths(
+ toolchainName,
+ targetPlatform,
+ excludedTools);
+
+ ImmutableList<String> toolchainIncludes = ndkPaths.createToolchainIncludePaths(
+ toolchainName,
+ targetPlatform,
+ gccVersion);
+
+ CToolchain.Builder builder = CToolchain.newBuilder()
+ .setTargetSystemName(targetPlatform)
+ .setCompiler("gcc-" + gccVersion)
+
+ .addAllToolPath(toolPaths)
+ .addAllCxxBuiltinIncludeDirectory(toolchainIncludes)
+ .setBuiltinSysroot(ndkPaths.createBuiltinSysroot("arm"))
+
+ .addCompilerFlag(stackProtectorFlag)
+
+ // Compiler flags
+ .addCompilerFlag("-fpic")
+ .addCompilerFlag("-ffunction-sections")
+ .addCompilerFlag("-funwind-tables")
+ .addCompilerFlag("-no-canonical-prefixes")
+
+ // Linker flags
+ .addLinkerFlag("-no-canonical-prefixes");
+
+ if (thumb) {
+ builder.addCompilationModeFlags(CompilationModeFlags.newBuilder()
+ .setMode(CompilationMode.OPT)
+ .addCompilerFlag("-mthumb")
+ .addCompilerFlag("-Os")
+ .addCompilerFlag("-g")
+ .addCompilerFlag("-DNDEBUG")
+ .addCompilerFlag("-fomit-frame-pointer")
+ .addCompilerFlag("-fno-strict-aliasing")
+ .addCompilerFlag("-finline-limit=64"));
+
+ builder.addCompilationModeFlags(CompilationModeFlags.newBuilder()
+ .setMode(CompilationMode.DBG)
+ .addCompilerFlag("-g")
+ .addCompilerFlag("-fno-strict-aliasing")
+ .addCompilerFlag("-finline-limit=64")
+ .addCompilerFlag("-O0")
+ .addCompilerFlag("-UNDEBUG")
+ .addCompilerFlag("-marm")
+ .addCompilerFlag("-fno-omit-frame-pointer"));
+ } else {
+ builder.addCompilationModeFlags(CompilationModeFlags.newBuilder()
+ .setMode(CompilationMode.OPT)
+ .addCompilerFlag("-O2")
+ .addCompilerFlag("-g")
+ .addCompilerFlag("-DNDEBUG")
+ .addCompilerFlag("-fomit-frame-pointer")
+ .addCompilerFlag("-fstrict-aliasing")
+ .addCompilerFlag("-funswitch-loops")
+ .addCompilerFlag("-finline-limit=300"));
+
+ builder.addCompilationModeFlags(CompilationModeFlags.newBuilder()
+ .setMode(CompilationMode.DBG)
+ .addCompilerFlag("-g")
+ .addCompilerFlag("-funswitch-loops")
+ .addCompilerFlag("-finline-limit=300")
+ .addCompilerFlag("-O0")
+ .addCompilerFlag("-UNDEBUG")
+ .addCompilerFlag("-fno-omit-frame-pointer")
+ .addCompilerFlag("-fno-strict-aliasing"));
+ }
+
+ return builder;
+ }
+
+ private void createArmeabiClangToolchain(ImmutableList.Builder<CToolchain.Builder> builder,
+ String clangVersion, boolean thumb) {
+
+ builder.add(createBaseArmeabiClangToolchain(clangVersion, thumb)
+ .setToolchainIdentifier(
+ createArmeabiName("arm-linux-androideabi-clang%s", clangVersion, thumb))
+ .setTargetCpu("armeabi")
+
+ .addCompilerFlag("-target")
+ .addCompilerFlag("armv5te-none-linux-androideabi") // LLVM_TRIPLE
+ .addCompilerFlag("-march=armv5te")
+ .addCompilerFlag("-mtune=xscale")
+ .addCompilerFlag("-msoft-float")
+
+ .addLinkerFlag("-target")
+ // LLVM_TRIPLE
+ .addLinkerFlag("armv5te-none-linux-androideabi"));
+
+ builder.add(createBaseArmeabiClangToolchain(clangVersion, thumb)
+ .setToolchainIdentifier(
+ createArmeabiName("arm-linux-androideabi-clang%s-v7a", clangVersion, thumb))
+ .setTargetCpu("armeabi-v7a")
+
+ .addCompilerFlag("-target")
+ .addCompilerFlag("armv7-none-linux-androideabi") // LLVM_TRIPLE
+ .addCompilerFlag("-march=armv7-a")
+ .addCompilerFlag("-mfloat-abi=softfp")
+ .addCompilerFlag("-mfpu=vfpv3-d16")
+
+ .addLinkerFlag("-target")
+ .addLinkerFlag("armv7-none-linux-androideabi") // LLVM_TRIPLE
+ .addLinkerFlag("-Wl,--fix-cortex-a8"));
+
+ builder.add(createBaseArmeabiClangToolchain(clangVersion, thumb)
+ .setToolchainIdentifier(
+ createArmeabiName("arm-linux-androideabi-clang%s-v7a-hard", clangVersion, thumb))
+ .setTargetCpu("armeabi-v7a-hard")
+
+ .addCompilerFlag("-target")
+ .addCompilerFlag("armv7-none-linux-androideabi") // LLVM_TRIPLE
+ .addCompilerFlag("-march=armv7-a")
+ .addCompilerFlag("-mfpu=vfpv3-d16")
+ .addCompilerFlag("-mhard-float")
+ .addCompilerFlag("-D_NDK_MATH_NO_SOFTFP=1")
+
+ .addLinkerFlag("-target")
+ .addLinkerFlag("armv7-none-linux-androideabi") // LLVM_TRIPLE
+ .addLinkerFlag("-Wl,--fix-cortex-a8")
+ .addLinkerFlag("-Wl,--no-warn-mismatch")
+ .addLinkerFlag("-lm_hard"));
+ }
+
+ private CToolchain.Builder createBaseArmeabiClangToolchain(String clangVersion, boolean thumb) {
+
+ String toolchainName = "arm-linux-androideabi-4.8";
+ String targetPlatform = "arm-linux-androideabi";
+ String gccToolchain = ndkPaths.createGccToolchainPath("arm-linux-androideabi-4.8");
+
+ CToolchain.Builder builder = CToolchain.newBuilder()
+ .setTargetSystemName("arm-linux-androideabi")
+ .setCompiler("gcc-4.8")
+
+ .addAllToolPath(ndkPaths.createClangToolpaths(
+ toolchainName,
+ targetPlatform,
+ clangVersion,
+ // gcc-4.8 arm doesn't have gcov-tool
+ CppConfiguration.Tool.GCOVTOOL))
+
+ .addAllCxxBuiltinIncludeDirectory(ndkPaths.createToolchainIncludePaths(
+ toolchainName, targetPlatform, "4.8"))
+
+ .setBuiltinSysroot(ndkPaths.createBuiltinSysroot("arm"))
+
+ // Compiler flags
+ .addCompilerFlag("-gcc-toolchain")
+ .addCompilerFlag(gccToolchain)
+ .addCompilerFlag("-fpic")
+ .addCompilerFlag("-ffunction-sections")
+ .addCompilerFlag("-funwind-tables")
+ .addCompilerFlag("-fstack-protector-strong")
+ .addCompilerFlag("-Wno-invalid-command-line-argument")
+ .addCompilerFlag("-Wno-unused-command-line-argument")
+ .addCompilerFlag("-no-canonical-prefixes")
+ .addCompilerFlag("-fno-integrated-as")
+
+ // Linker flags
+ .addLinkerFlag("-gcc-toolchain")
+ .addLinkerFlag(gccToolchain)
+ .addLinkerFlag("-no-canonical-prefixes");
+
+ if (thumb) {
+ builder.addCompilationModeFlags(CompilationModeFlags.newBuilder()
+ .setMode(CompilationMode.OPT)
+ .addCompilerFlag("-mthumb")
+ .addCompilerFlag("-Os")
+ .addCompilerFlag("-g")
+ .addCompilerFlag("-DNDEBUG")
+ .addCompilerFlag("-fomit-frame-pointer")
+ .addCompilerFlag("-fno-strict-aliasing"));
+
+ builder.addCompilationModeFlags(CompilationModeFlags.newBuilder()
+ .setMode(CompilationMode.DBG)
+ .addCompilerFlag("-g")
+ .addCompilerFlag("-fno-strict-aliasing")
+ .addCompilerFlag("-O0")
+ .addCompilerFlag("-UNDEBUG")
+ .addCompilerFlag("-marm")
+ .addCompilerFlag("-fno-omit-frame-pointer"));
+ } else {
+ builder.addCompilationModeFlags(CompilationModeFlags.newBuilder()
+ .setMode(CompilationMode.OPT)
+ .addCompilerFlag("-O2")
+ .addCompilerFlag("-g")
+ .addCompilerFlag("-DNDEBUG")
+ .addCompilerFlag("-fomit-frame-pointer")
+ .addCompilerFlag("-fstrict-aliasing"));
+
+ builder.addCompilationModeFlags(CompilationModeFlags.newBuilder()
+ .setMode(CompilationMode.DBG)
+ .addCompilerFlag("-g")
+ .addCompilerFlag("-O0")
+ .addCompilerFlag("-UNDEBUG")
+ .addCompilerFlag("-fno-omit-frame-pointer")
+ .addCompilerFlag("-fno-strict-aliasing"));
+ }
+
+ return builder;
+ }
+} \ No newline at end of file
diff --git a/src/main/java/com/google/devtools/build/lib/bazel/rules/android/ndkcrosstools/MipsCrosstools.java b/src/main/java/com/google/devtools/build/lib/bazel/rules/android/ndkcrosstools/MipsCrosstools.java
new file mode 100644
index 0000000000..afe5d9abd4
--- /dev/null
+++ b/src/main/java/com/google/devtools/build/lib/bazel/rules/android/ndkcrosstools/MipsCrosstools.java
@@ -0,0 +1,221 @@
+// Copyright 2015 Google Inc. 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.bazel.rules.android.ndkcrosstools;
+
+import com.google.common.collect.ImmutableList;
+import com.google.devtools.build.lib.rules.cpp.CppConfiguration;
+import com.google.devtools.build.lib.view.config.crosstool.CrosstoolConfig.CToolchain;
+import com.google.devtools.build.lib.view.config.crosstool.CrosstoolConfig.CompilationMode;
+import com.google.devtools.build.lib.view.config.crosstool.CrosstoolConfig.CompilationModeFlags;
+
+/**
+ * Crosstool definitions for MIPS. These values are based on the setup.mk files in the Android NDK
+ * toolchain directories.
+ */
+class MipsCrosstools {
+
+ private final NdkPaths ndkPaths;
+
+ MipsCrosstools(NdkPaths ndkPaths) {
+ this.ndkPaths = ndkPaths;
+ }
+
+ ImmutableList<CToolchain.Builder> createCrosstools() {
+
+ ImmutableList.Builder<CToolchain.Builder> builder = ImmutableList.builder();
+
+ /**
+ * mips64
+ */
+
+ builder.add(createMipsToolchain()
+ .setToolchainIdentifier("mips64el-linux-android-4.9")
+ .setTargetSystemName("mips64el-linux-android")
+ .setTargetCpu("mips64")
+ .setCompiler("gcc-4.9")
+
+ .addAllToolPath(ndkPaths.createToolpaths(
+ "mips64el-linux-android-4.9", "mips64el-linux-android",
+ // mips64 toolchain doesn't have the dwp tool.
+ CppConfiguration.Tool.DWP))
+
+ .addAllCxxBuiltinIncludeDirectory(ndkPaths.createToolchainIncludePaths(
+ "mips64el-linux-android-4.9", "mips64el-linux-android", "4.9"))
+
+ .setBuiltinSysroot(ndkPaths.createBuiltinSysroot("mips64")));
+
+ // The flags for mips64 clang 3.5 and 3.6 are the same, they differ only in the LLVM version
+ // given in their tool paths.
+ for (String clangVersion : new String[] { "3.5", "3.6" }) {
+ builder.add(createMipsClangToolchain("mips64", "4.9")
+ .setToolchainIdentifier("mips64el-linux-android-clang" + clangVersion)
+ .setTargetSystemName("mips64el-linux-android")
+ .setTargetCpu("mips64")
+ .setCompiler("gcc-4.9")
+
+ .addAllToolPath(ndkPaths.createClangToolpaths(
+ "mips64el-linux-android-4.9", "mips64el-linux-android", clangVersion,
+ CppConfiguration.Tool.DWP))
+
+ .addAllCxxBuiltinIncludeDirectory(ndkPaths.createToolchainIncludePaths(
+ "mips64el-linux-android-4.9", "mips64el-linux-android", "4.9"))
+
+ .setBuiltinSysroot(ndkPaths.createBuiltinSysroot("mips64")));
+ }
+
+ /**
+ * mips
+ */
+
+ builder.add(createMipsToolchain()
+ .setToolchainIdentifier("mipsel-linux-android-4.8")
+ .setTargetSystemName("mipsel-linux-android")
+ .setTargetCpu("mips")
+ .setCompiler("gcc-4.8")
+
+ .addAllToolPath(ndkPaths.createToolpaths(
+ "mipsel-linux-android-4.8", "mipsel-linux-android",
+ // gcc-4.8 mips toolchain doesn't have dwp or gcov-tool.
+ CppConfiguration.Tool.DWP,
+ CppConfiguration.Tool.GCOVTOOL))
+
+ .addAllCxxBuiltinIncludeDirectory(ndkPaths.createToolchainIncludePaths(
+ "mipsel-linux-android-4.8", "mipsel-linux-android", "4.8"))
+
+ .setBuiltinSysroot(ndkPaths.createBuiltinSysroot("mips")));
+
+ builder.add(createMipsToolchain()
+ .setToolchainIdentifier("mipsel-linux-android-4.9")
+ .setTargetSystemName("mipsel-linux-android")
+ .setTargetCpu("mips")
+ .setCompiler("gcc-4.9")
+
+ .addAllToolPath(ndkPaths.createToolpaths(
+ "mipsel-linux-android-4.9", "mipsel-linux-android",
+ // gcc-4.9 mips toolchain doesn't have the dwp tool.
+ CppConfiguration.Tool.DWP))
+
+ .addAllCxxBuiltinIncludeDirectory(ndkPaths.createToolchainIncludePaths(
+ "mipsel-linux-android-4.9", "mipsel-linux-android", "4.9"))
+
+ .setBuiltinSysroot(ndkPaths.createBuiltinSysroot("mips")));
+
+ // The flags for mips clang 3.5 and 3.6 are the same, they differ only in the LLVM version
+ // given in their tool paths.
+ for (String clangVersion : new String[] { "3.5", "3.6" }) {
+ builder.add(createMipsClangToolchain("mips", "4.8")
+ .setToolchainIdentifier("mipsel-linux-android-clang" + clangVersion)
+ .setTargetSystemName("mipsel-linux-android")
+ .setTargetCpu("mips")
+ .setCompiler("gcc-4.8")
+
+ .addAllToolPath(ndkPaths.createClangToolpaths(
+ "mipsel-linux-android-4.8", "mipsel-linux-android", clangVersion,
+ CppConfiguration.Tool.DWP, CppConfiguration.Tool.GCOVTOOL))
+
+ .addAllCxxBuiltinIncludeDirectory(ndkPaths.createToolchainIncludePaths(
+ "mipsel-linux-android-4.8", "mipsel-linux-android", "4.8"))
+
+ .setBuiltinSysroot(ndkPaths.createBuiltinSysroot("mips")));
+ }
+
+ return builder.build();
+ }
+
+ private CToolchain.Builder createMipsToolchain() {
+ return CToolchain.newBuilder()
+ // Compiler flags
+ .addCompilerFlag("-fpic")
+ .addCompilerFlag("-fno-strict-aliasing")
+ .addCompilerFlag("-finline-functions")
+ .addCompilerFlag("-ffunction-sections")
+ .addCompilerFlag("-funwind-tables")
+ .addCompilerFlag("-fmessage-length=0")
+ .addCompilerFlag("-fno-inline-functions-called-once")
+ .addCompilerFlag("-fgcse-after-reload")
+ .addCompilerFlag("-frerun-cse-after-loop")
+ .addCompilerFlag("-frename-registers")
+ .addCompilerFlag("-no-canonical-prefixes")
+
+ // Linker flags
+ .addLinkerFlag("-no-canonical-prefixes")
+
+ // Additional release flags
+ .addCompilationModeFlags(CompilationModeFlags.newBuilder()
+ .setMode(CompilationMode.OPT)
+ .addCompilerFlag("-O2")
+ .addCompilerFlag("-g")
+ .addCompilerFlag("-DNDEBUG")
+ .addCompilerFlag("-fomit-frame-pointer")
+ .addCompilerFlag("-funswitch-loops")
+ .addCompilerFlag("-finline-limit=300"))
+
+ // Additional debug flags
+ .addCompilationModeFlags(CompilationModeFlags.newBuilder()
+ .setMode(CompilationMode.DBG)
+ .addCompilerFlag("-O0")
+ .addCompilerFlag("-g")
+ .addCompilerFlag("-fno-omit-frame-pointer"));
+ }
+
+ private CToolchain.Builder createMipsClangToolchain(String mipsArch, String gccVersion) {
+
+ String gccToolchain = ndkPaths.createGccToolchainPath(
+ String.format("%s-linux-android-%s", mipsArch, gccVersion));
+
+ String llvmTriple = mipsArch + "-none-linux-android";
+
+ return CToolchain.newBuilder()
+ .setCompiler("gcc-" + gccVersion)
+
+ // Compiler flags
+ .addCompilerFlag("-gcc-toolchain")
+ .addCompilerFlag(gccToolchain)
+ .addCompilerFlag("-target")
+ .addCompilerFlag(llvmTriple)
+ .addCompilerFlag("-fpic")
+ .addCompilerFlag("-fno-strict-aliasing")
+ .addCompilerFlag("-finline-functions")
+ .addCompilerFlag("-ffunction-sections")
+ .addCompilerFlag("-funwind-tables")
+ .addCompilerFlag("-fmessage-length=0")
+ .addCompilerFlag("-Wno-invalid-command-line-argument")
+ .addCompilerFlag("-Wno-unused-command-line-argument")
+ .addCompilerFlag("-no-canonical-prefixes")
+
+ // Linker flags
+ .addLinkerFlag("-gcc-toolchain")
+ .addLinkerFlag(gccToolchain)
+ .addLinkerFlag("-target")
+ .addLinkerFlag(llvmTriple)
+ .addLinkerFlag("-no-canonical-prefixes")
+
+ // Additional release flags
+ .addCompilationModeFlags(CompilationModeFlags.newBuilder()
+ .setMode(CompilationMode.OPT)
+ .addCompilerFlag("-O2")
+ .addCompilerFlag("-g")
+ .addCompilerFlag("-DNDEBUG")
+ .addCompilerFlag("-fomit-frame-pointer"))
+
+ // Additional debug flags
+ .addCompilationModeFlags(CompilationModeFlags.newBuilder()
+ .setMode(CompilationMode.DBG)
+ .addCompilerFlag("-O0")
+ .addCompilerFlag("-g")
+ .addCompilerFlag("-fno-omit-frame-pointer"));
+ }
+}
+
diff --git a/src/main/java/com/google/devtools/build/lib/bazel/rules/android/ndkcrosstools/NdkPaths.java b/src/main/java/com/google/devtools/build/lib/bazel/rules/android/ndkcrosstools/NdkPaths.java
new file mode 100644
index 0000000000..564a34d739
--- /dev/null
+++ b/src/main/java/com/google/devtools/build/lib/bazel/rules/android/ndkcrosstools/NdkPaths.java
@@ -0,0 +1,207 @@
+// Copyright 2015 Google Inc. 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.bazel.rules.android.ndkcrosstools;
+
+import com.google.common.collect.ImmutableList;
+import com.google.devtools.build.lib.events.EventHandler;
+import com.google.devtools.build.lib.rules.cpp.CppConfiguration;
+import com.google.devtools.build.lib.rules.cpp.CppConfiguration.Tool;
+import com.google.devtools.build.lib.view.config.crosstool.CrosstoolConfig.ToolPath;
+
+import java.util.Arrays;
+import java.util.List;
+
+/**
+ * Class for creating paths that are specific to the structure of the Android NDK, but which are
+ * common to all crosstool toolchains.
+ */
+public class NdkPaths {
+
+ /**
+ * Removes the NDK repository prefix from the given path. Eg:
+ * "external/%repositoryName%/ndk/a/b/c" -> "ndk/a/b/c"
+ */
+ public static String stripRepositoryPrefix(String path) {
+ return path.split("/", 3)[2];
+ }
+
+ private final String repositoryName, hostPlatform;
+ private final ApiLevel apiLevel;
+
+ NdkPaths(EventHandler eventHandler, String repositoryName, String hostPlatform, String apiLevel) {
+ this.repositoryName = repositoryName;
+ this.hostPlatform = hostPlatform;
+ this.apiLevel = new ApiLevel(eventHandler, repositoryName, apiLevel);
+ }
+
+ ImmutableList<ToolPath> createToolpaths(String toolchainName, String targetPlatform,
+ CppConfiguration.Tool... excludedTools) {
+
+ ImmutableList.Builder<ToolPath> toolPaths = ImmutableList.builder();
+
+ for (Tool tool : CppConfiguration.Tool.values()) {
+
+ // Some toolchains don't have particular tools.
+ if (!Arrays.asList(excludedTools).contains(tool)) {
+
+ String toolPath = createToolPath(toolchainName, targetPlatform + "-" + tool.getNamePart());
+
+ toolPaths.add(ToolPath.newBuilder()
+ .setName(tool.getNamePart())
+ .setPath(toolPath)
+ .build());
+ }
+ }
+
+ return toolPaths.build();
+ }
+
+ ImmutableList<ToolPath> createClangToolpaths(String toolchainName, String targetPlatform,
+ String llvmVersion, CppConfiguration.Tool... excludedTools) {
+
+ // Add GCC to the list of excluded tools. It will be replaced by clang below.
+ excludedTools = ImmutableList.<CppConfiguration.Tool>builder()
+ .add(excludedTools)
+ .add(CppConfiguration.Tool.GCC)
+ .build()
+ .toArray(new CppConfiguration.Tool[excludedTools.length + 1]);
+
+ // Create the regular tool paths, then add clang.
+ return ImmutableList.<ToolPath>builder()
+ .addAll(createToolpaths(toolchainName, targetPlatform, excludedTools))
+
+ .add(ToolPath.newBuilder()
+ .setName("gcc")
+ .setPath(createToolPath("llvm-" + llvmVersion, "clang"))
+ .build())
+ .build();
+ }
+
+ private String createToolPath(String toolchainName, String toolName) {
+
+ String toolpathTemplate =
+ "external/%repositoryName%/ndk/toolchains/%toolchainName%/prebuilt/%hostPlatform%"
+ + "/bin/%toolName%";
+
+ return toolpathTemplate
+ .replace("%repositoryName%", repositoryName)
+ .replace("%toolchainName%", toolchainName)
+ .replace("%hostPlatform%", hostPlatform)
+ .replace("%toolName%", toolName);
+ }
+
+ public static String getToolchainDirectoryFromToolPath(String toolPath) {
+ return toolPath.split("/")[4];
+ }
+
+ String createGccToolchainPath(String toolchainName) {
+
+ String gccToolchainPathTemplate =
+ "external/%repositoryName%/ndk/toolchains/%toolchainName%/prebuilt/%hostPlatform%";
+
+ return gccToolchainPathTemplate
+ .replace("%repositoryName%", repositoryName)
+ .replace("%toolchainName%", toolchainName)
+ .replace("%hostPlatform%", hostPlatform);
+ }
+
+ ImmutableList<String> createToolchainIncludePaths(
+ String toolchainName, String targetPlatform, String gccVersion) {
+
+ ImmutableList.Builder<String> includePaths = ImmutableList.builder();
+
+ includePaths.add(createToolchainIncludePath(
+ toolchainName, targetPlatform, gccVersion, "include"));
+ includePaths.add(createToolchainIncludePath(
+ toolchainName, targetPlatform, gccVersion, "include-fixed"));
+
+ return includePaths.build();
+ }
+
+ private String createToolchainIncludePath(
+ String toolchainName, String targetPlatform, String gccVersion, String includeFolderName) {
+
+ String toolchainIncludePathTemplate =
+ "external/%repositoryName%/ndk/toolchains/%toolchainName%/prebuilt/%hostPlatform%"
+ + "/lib/gcc/%targetPlatform%/%gccVersion%/%includeFolderName%";
+
+ return toolchainIncludePathTemplate
+ .replace("%repositoryName%", repositoryName)
+ .replace("%toolchainName%", toolchainName)
+ .replace("%hostPlatform%", hostPlatform)
+ .replace("%targetPlatform%", targetPlatform)
+ .replace("%gccVersion%", gccVersion)
+ .replace("%includeFolderName%", includeFolderName);
+ }
+
+ String createBuiltinSysroot(String targetCpu) {
+
+ String correctedApiLevel = apiLevel.getCpuCorrectedApiLevel(targetCpu);
+
+ String androidPlatformIncludePathTemplate =
+ "external/%repositoryName%/ndk/platforms/android-%apiLevel%/arch-%arch%";
+
+ return androidPlatformIncludePathTemplate
+ .replace("%repositoryName%", repositoryName)
+ .replace("%apiLevel%", correctedApiLevel)
+ .replace("%arch%", targetCpu);
+ }
+
+ ImmutableList<String> createGnuLibstdcIncludePaths(String gccVersion, String targetCpu) {
+
+ if (targetCpu.equals("arm64")) {
+ targetCpu = "arm64-v8a";
+ }
+
+ String prefix = "external/%repositoryName%/ndk/sources/cxx-stl/gnu-libstdc++/%gccVersion%/";
+ List<String> includePathTemplates = Arrays.asList(
+ prefix + "include",
+ prefix + "libs/%targetCpu%/include",
+ prefix + "include/backward");
+
+ ImmutableList.Builder<String> includePaths = ImmutableList.builder();
+ for (String template : includePathTemplates) {
+ includePaths.add(
+ template
+ .replace("%repositoryName%", repositoryName)
+ .replace("%gccVersion%", gccVersion)
+ .replace("%targetCpu%", targetCpu));
+ }
+ return includePaths.build();
+ }
+
+ ImmutableList<String> createStlportIncludePaths() {
+
+ String prefix = "external/%repositoryName%/ndk/sources/cxx-stl/"
+ .replace("%repositoryName%", repositoryName);
+
+ return ImmutableList.<String>builder()
+ .add(prefix + "stlport/stlport")
+ .add(prefix + "gabi++/include")
+ .build();
+ }
+
+ ImmutableList<String> createLibcxxIncludePaths() {
+
+ String prefix = "external/%repositoryName%/ndk/sources/"
+ .replace("%repositoryName%", repositoryName);
+
+ return ImmutableList.<String>builder()
+ .add(prefix + "cxx-stl/llvm-libc++/libcxx/include")
+ .add(prefix + "cxx-stl/llvm-libc++abi/libcxxabi/include")
+ .add(prefix + "android/support/include")
+ .build();
+ }
+}
diff --git a/src/main/java/com/google/devtools/build/lib/bazel/rules/android/ndkcrosstools/NdkRelease.java b/src/main/java/com/google/devtools/build/lib/bazel/rules/android/ndkcrosstools/NdkRelease.java
new file mode 100644
index 0000000000..37095c775f
--- /dev/null
+++ b/src/main/java/com/google/devtools/build/lib/bazel/rules/android/ndkcrosstools/NdkRelease.java
@@ -0,0 +1,86 @@
+// Copyright 2015 Google Inc. 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.bazel.rules.android.ndkcrosstools;
+
+import com.google.devtools.build.lib.util.CPU;
+
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+/**
+ * Class for information about an NDK release.
+ */
+public class NdkRelease {
+
+ public static NdkRelease create(String releaseString) {
+ // NDK release should be of the format "r\d+\w?(-rc\d+)?( \(64-bit\))?", eg:
+ // r8
+ // r10
+ // r10 (64-bit)
+ // r10e
+ // r10e-rc4
+ // r10e-rc4 (64-bit)
+ Pattern releaseRegex = Pattern.compile(
+ "(?<rel>r\\d+\\w?)(-(?<rc>rc\\d+))?(?<s4> \\(64-bit\\))?");
+ Matcher matcher = releaseRegex.matcher(releaseString);
+ boolean isValid = matcher.matches();
+
+ if (isValid) {
+ return new NdkRelease(
+ releaseString,
+ isValid,
+ matcher.group("rel"), /* release */
+ matcher.group("rc"), /* releaseCandidate */
+ matcher.group("s4") != null /* is64Bit */);
+ } else {
+ return new NdkRelease(releaseString, false, null, null, false);
+ }
+ }
+
+ /**
+ * Guesses the bit-ness of the NDK based on the current platform.
+ */
+ static NdkRelease guessBitness(String baseReleaseString) {
+ NdkRelease baseRelease = create(baseReleaseString);
+ boolean is64Bit = (CPU.getCurrent() == CPU.X86_64);
+ return new NdkRelease(
+ baseRelease.rawRelease + (is64Bit ? " (64-bit)" : ""),
+ baseRelease.isValid,
+ baseRelease.release,
+ baseRelease.releaseCandidate,
+ is64Bit);
+ }
+
+ public final String rawRelease;
+ public final boolean isValid;
+
+ public final String release;
+ public final String releaseCandidate;
+ public final boolean is64Bit;
+
+ private NdkRelease(String rawRelease, boolean isValid, String release, String releaseCandidate,
+ boolean is64Bit) {
+ this.rawRelease = rawRelease;
+ this.isValid = isValid;
+ this.release = release;
+ this.releaseCandidate = releaseCandidate;
+ this.is64Bit = is64Bit;
+ }
+
+ @Override
+ public String toString() {
+ return rawRelease;
+ }
+}
diff --git a/src/main/java/com/google/devtools/build/lib/bazel/rules/android/ndkcrosstools/X86Crosstools.java b/src/main/java/com/google/devtools/build/lib/bazel/rules/android/ndkcrosstools/X86Crosstools.java
new file mode 100644
index 0000000000..f3c99bb8d9
--- /dev/null
+++ b/src/main/java/com/google/devtools/build/lib/bazel/rules/android/ndkcrosstools/X86Crosstools.java
@@ -0,0 +1,213 @@
+// Copyright 2015 Google Inc. 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.bazel.rules.android.ndkcrosstools;
+
+import com.google.common.collect.ImmutableList;
+import com.google.devtools.build.lib.rules.cpp.CppConfiguration;
+import com.google.devtools.build.lib.view.config.crosstool.CrosstoolConfig.CToolchain;
+import com.google.devtools.build.lib.view.config.crosstool.CrosstoolConfig.CompilationMode;
+import com.google.devtools.build.lib.view.config.crosstool.CrosstoolConfig.CompilationModeFlags;
+
+/**
+ * Crosstool definitions for x86. These values are based on the setup.mk files in the Android NDK
+ * toolchain directories.
+ */
+class X86Crosstools {
+
+ private final NdkPaths ndkPaths;
+
+ X86Crosstools(NdkPaths ndkPaths) {
+ this.ndkPaths = ndkPaths;
+ }
+
+ ImmutableList<CToolchain.Builder> createCrosstools() {
+
+ ImmutableList.Builder<CToolchain.Builder> builder = ImmutableList.builder();
+
+ /**
+ * x86
+ */
+
+ builder.add(createBaseX86Toolchain()
+ .setToolchainIdentifier("x86-4.8")
+ .setTargetCpu("x86")
+ .setCompiler("gcc-4.8")
+
+ .addAllToolPath(ndkPaths.createToolpaths(
+ "x86-4.8", "i686-linux-android",
+ // gcc-4.8 x86 toolchain doesn't have gcov-tool.
+ CppConfiguration.Tool.GCOVTOOL))
+
+ .addAllCxxBuiltinIncludeDirectory(ndkPaths.createToolchainIncludePaths(
+ "x86-4.8", "i686-linux-android", "4.8"))
+
+ .setBuiltinSysroot(ndkPaths.createBuiltinSysroot("x86"))
+
+ .addCompilerFlag("-fstack-protector"));
+
+ builder.add(createBaseX86Toolchain()
+ .setToolchainIdentifier("x86-4.9")
+ .setTargetCpu("x86")
+ .setCompiler("gcc-4.9")
+
+ .addAllToolPath(ndkPaths.createToolpaths(
+ "x86-4.9", "i686-linux-android"))
+
+ .addAllCxxBuiltinIncludeDirectory(ndkPaths.createToolchainIncludePaths(
+ "x86-4.9", "i686-linux-android", "4.9"))
+
+ .setBuiltinSysroot(ndkPaths.createBuiltinSysroot("x86"))
+
+ .addCompilerFlag("-fstack-protector-strong"));
+
+ // Add Clang toolchains. x86 uses gcc-4.8.
+ for (String clangVersion : new String[] { "3.5", "3.6" }) {
+ builder.add(createX86ClangToolchain("x86", "i686", "4.8")
+ .setToolchainIdentifier("x86-clang" + clangVersion)
+ .setTargetCpu("x86")
+
+ .addAllToolPath(ndkPaths.createClangToolpaths(
+ "x86-4.8", "i686-linux-android", clangVersion,
+ // gcc-4.8 x86 toolchain doesn't have gcov-tool.
+ CppConfiguration.Tool.GCOVTOOL))
+
+ .addAllCxxBuiltinIncludeDirectory(ndkPaths.createToolchainIncludePaths(
+ "x86-4.8", "i686-linux-android", "4.8"))
+
+ .setBuiltinSysroot(ndkPaths.createBuiltinSysroot("x86")));
+ }
+
+ /**
+ * x86_64
+ */
+
+ builder.add(createBaseX86Toolchain()
+ .setToolchainIdentifier("x86_64-4.9")
+ .setTargetCpu("x86_64")
+ .setCompiler("gcc-4.9")
+
+ .addAllToolPath(ndkPaths.createToolpaths(
+ "x86_64-4.9", "x86_64-linux-android"))
+
+ .addAllCxxBuiltinIncludeDirectory(ndkPaths.createToolchainIncludePaths(
+ "x86_64-4.9", "x86_64-linux-android", "4.9"))
+
+ .setBuiltinSysroot(ndkPaths.createBuiltinSysroot("x86_64"))
+
+ .addCompilerFlag("-fstack-protector-strong"));
+
+ // Add Clang toolchains. x86_64 uses gcc-4.9.
+ for (String clangVersion : new String[] { "3.5", "3.6" }) {
+ builder.add(createX86ClangToolchain("x86_64", "x86_64", "4.9")
+ .setToolchainIdentifier("x86_64-clang" + clangVersion)
+ .setTargetCpu("x86_64")
+
+ .addAllToolPath(ndkPaths.createClangToolpaths(
+ "x86_64-4.9", "x86_64-linux-android", clangVersion))
+
+ .addAllCxxBuiltinIncludeDirectory(ndkPaths.createToolchainIncludePaths(
+ "x86_64-4.9", "x86_64-linux-android", "4.9"))
+
+ .setBuiltinSysroot(ndkPaths.createBuiltinSysroot("x86_64")));
+ }
+
+ ImmutableList<CToolchain.Builder> toolchainBuilders = builder.build();
+
+ for (CToolchain.Builder toolchainBuilder : toolchainBuilders) {
+ toolchainBuilder.setTargetSystemName("x86-linux-android");
+ }
+
+ return toolchainBuilders;
+ }
+
+ private CToolchain.Builder createBaseX86Toolchain() {
+ return CToolchain.newBuilder()
+ // Compiler flags
+ .addCompilerFlag("-ffunction-sections")
+ .addCompilerFlag("-funwind-tables")
+ .addCompilerFlag("-no-canonical-prefixes")
+
+ // Linker flags
+ .addLinkerFlag("-no-canonical-prefixes")
+
+ // Additional release flags
+ .addCompilationModeFlags(CompilationModeFlags.newBuilder()
+ .setMode(CompilationMode.OPT)
+ .addCompilerFlag("-O2")
+ .addCompilerFlag("-g")
+ .addCompilerFlag("-DNDEBUG")
+ .addCompilerFlag("-fomit-frame-pointer")
+ .addCompilerFlag("-fstrict-aliasing")
+ .addCompilerFlag("-funswitch-loops")
+ .addCompilerFlag("finline-limit=300"))
+
+ // Additional debug flags
+ .addCompilationModeFlags(CompilationModeFlags.newBuilder()
+ .setMode(CompilationMode.DBG)
+ .addCompilerFlag("-O0")
+ .addCompilerFlag("-g")
+ .addCompilerFlag("-fno-omit-frame-pointer")
+ .addCompilerFlag("-fno-strict-aliasing"));
+ }
+
+ private CToolchain.Builder createX86ClangToolchain(
+ String x86Arch, String llvmArch, String gccVersion) {
+
+ String gccToolchain = ndkPaths.createGccToolchainPath(
+ String.format("%s-linux-android-%s", x86Arch, gccVersion));
+
+ String llvmTriple = llvmArch + "-none-linux-android";
+
+ return CToolchain.newBuilder()
+ .setCompiler("gcc-" + gccVersion)
+
+ // Compiler flags
+ .addCompilerFlag("-gcc-toolchain")
+ .addCompilerFlag(gccToolchain)
+ .addCompilerFlag("-target")
+ .addCompilerFlag(llvmTriple)
+ .addCompilerFlag("-ffunction-sections")
+ .addCompilerFlag("-funwind-tables")
+ .addCompilerFlag("-fstack-protector-strong")
+ .addCompilerFlag("-fPIC")
+ .addCompilerFlag("-Wno-invalid-command-line-argument")
+ .addCompilerFlag("-Wno-unused-command-line-argument")
+ .addCompilerFlag("-no-canonical-prefixes")
+
+ // Linker flags
+ .addLinkerFlag("-gcc-toolchain")
+ .addLinkerFlag(gccToolchain)
+ .addLinkerFlag("-target")
+ .addLinkerFlag(llvmTriple)
+ .addLinkerFlag("-no-canonical-prefixes")
+
+ // Additional release flags
+ .addCompilationModeFlags(CompilationModeFlags.newBuilder()
+ .setMode(CompilationMode.OPT)
+ .addCompilerFlag("-O2")
+ .addCompilerFlag("-g")
+ .addCompilerFlag("-DNDEBUG")
+ .addCompilerFlag("-fomit-frame-pointer")
+ .addCompilerFlag("-fstrict-aliasing"))
+
+ // Additional debug flags
+ .addCompilationModeFlags(CompilationModeFlags.newBuilder()
+ .setMode(CompilationMode.DBG)
+ .addCompilerFlag("-O0")
+ .addCompilerFlag("-g")
+ .addCompilerFlag("-fno-omit-frame-pointer")
+ .addCompilerFlag("-fnostrict-aliasing"));
+ }
+}
diff --git a/src/main/java/com/google/devtools/build/lib/rules/cpp/CrosstoolConfigurationLoader.java b/src/main/java/com/google/devtools/build/lib/rules/cpp/CrosstoolConfigurationLoader.java
index e5957581ae..15e91e2c67 100644
--- a/src/main/java/com/google/devtools/build/lib/rules/cpp/CrosstoolConfigurationLoader.java
+++ b/src/main/java/com/google/devtools/build/lib/rules/cpp/CrosstoolConfigurationLoader.java
@@ -383,8 +383,9 @@ public class CrosstoolConfigurationLoader {
// crosstool_config.proto file.
String rx = "[a-zA-Z_][\\.\\- \\w]*";
if (!selectedIdentifier.matches(rx)) {
- throw new InvalidConfigurationException("Toolchain identifier for cpu '" + cpu + "' " +
- "is illegal (does not match '" + rx + "')");
+ throw new InvalidConfigurationException(String.format(
+ "Toolchain identifier '%s' for cpu '%s' is illegal (does not match '%s')",
+ selectedIdentifier, cpu, rx));
}
}
diff --git a/src/main/java/com/google/devtools/build/lib/util/AutoProfiler.java b/src/main/java/com/google/devtools/build/lib/util/AutoProfiler.java
new file mode 100644
index 0000000000..46b00f9599
--- /dev/null
+++ b/src/main/java/com/google/devtools/build/lib/util/AutoProfiler.java
@@ -0,0 +1,141 @@
+// Copyright 2015 Google Inc. 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.util;
+
+import com.google.common.base.Preconditions;
+
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.atomic.AtomicBoolean;
+import java.util.logging.Logger;
+
+/**
+ * A convenient way to actively get access to timing information (e.g. for logging purposes) with
+ * minimal boilerplate. Contrast with {@link Profiler}, which records profiling data for offline
+ * consumption.
+ *
+ * <p>The intended usage is:
+ *
+ * <pre>
+ * {@code
+ * try (AutoProfiler profiler = AutoProfiler.createLoggingProfiler("Your stuff")) {
+ * // Your code here.
+ * }
+ * }
+ * </pre>
+ *
+ * <p>but if the try-with-resources pattern is too cumbersome, you can also do
+ *
+ * <pre>
+ * {@code
+ * AutoProfiler profiler = AutoProfiler.createLoggingProfiler("Your stuff");
+ * // Your code here.
+ * profiler.close();
+ * }
+ * </pre>
+ */
+public class AutoProfiler implements AutoCloseable {
+ private static final Logger LOG = Logger.getLogger(AutoProfiler.class.getName());
+
+ private final ElapsedTimeReceiver elapsedTimeReceiver;
+ private final long startTimeNanos;
+ private final AtomicBoolean closed = new AtomicBoolean(false);
+
+ private AutoProfiler(ElapsedTimeReceiver elapsedTimeReceiver, long startTimeNanos) {
+ this.elapsedTimeReceiver = elapsedTimeReceiver;
+ this.startTimeNanos = startTimeNanos;
+ }
+
+ /** A opaque receiver of elapsed time information. */
+ public interface ElapsedTimeReceiver {
+ /**
+ * Receives the elapsed time of the lifetime of an {@link AutoProfiler} instance.
+ *
+ * <p>Note that System#nanoTime isn't guaranteed to be non-decreasing, so implementations should
+ * check for non-positive {@code elapsedTimeNanos} if they care about this sort of thing.
+ */
+ void accept(long elapsedTimeNanos);
+ }
+
+ /**
+ * Returns an {@link AutoProfiler} that, when closed, logs the elapsed time in milliseconds to a
+ * default logger.
+ *
+ * <p>The returned {@link AutoProfiler} is thread-safe.
+ */
+ public static AutoProfiler create(String taskDescription) {
+ return create(taskDescription, LOG);
+ }
+
+ /**
+ * Returns an {@link AutoProfiler} that, when closed, logs the elapsed time in milliseconds to
+ * the given {@link Logger}.
+ *
+ * <p>The returned {@link AutoProfiler} is thread-safe.
+ */
+ public static AutoProfiler create(String taskDescription, Logger logger) {
+ return create(taskDescription, logger, TimeUnit.MILLISECONDS);
+ }
+
+ /**
+ * Returns an {@link AutoProfiler} that, when closed, logs the elapsed time the given
+ * {@link TimeUnit} to the given {@link Logger}.
+ *
+ * <p>The returned {@link AutoProfiler} is thread-safe.
+ */
+ public static AutoProfiler create(String taskDescription, Logger logger, TimeUnit timeUnit) {
+ return create(new LoggingElapsedTimeReceiver(taskDescription, logger, timeUnit));
+ }
+
+ /**
+ * Returns an {@link AutoProfiler} that, when closed, invokes the given
+ * {@link ElapsedTimeReceiver}.
+ *
+ * <p>The returned {@link AutoProfiler} is as thread-safe as the given
+ * {@link ElapsedTimeReceiver} is.
+ */
+ public static AutoProfiler create(ElapsedTimeReceiver elapsedTimeReceiver) {
+ return new AutoProfiler(elapsedTimeReceiver, BlazeClock.nanoTime());
+ }
+
+ /** Can be called at most once. */
+ @Override
+ public void close() {
+ long elapsedTimeNanos = BlazeClock.nanoTime() - startTimeNanos;
+ Preconditions.checkState(closed.compareAndSet(false, true));
+ elapsedTimeReceiver.accept(elapsedTimeNanos);
+ }
+
+ private static class LoggingElapsedTimeReceiver implements ElapsedTimeReceiver {
+ private final String taskDescription;
+ private final Logger logger;
+ private final TimeUnit timeUnit;
+
+ private LoggingElapsedTimeReceiver(String taskDescription, Logger logger, TimeUnit timeUnit) {
+ this.taskDescription = taskDescription;
+ this.logger = logger;
+ this.timeUnit = timeUnit;
+ }
+
+ @Override
+ public void accept(long elapsedTimeNanos) {
+ if (elapsedTimeNanos > 0) {
+ logger.info(String.format("Spent %d %s doing %s",
+ timeUnit.convert(elapsedTimeNanos, TimeUnit.NANOSECONDS),
+ timeUnit.toString(),
+ taskDescription));
+ }
+ }
+ }
+}
+
diff --git a/src/main/java/com/google/devtools/build/lib/util/OS.java b/src/main/java/com/google/devtools/build/lib/util/OS.java
index 04e437b8f2..97e6c3a13a 100644
--- a/src/main/java/com/google/devtools/build/lib/util/OS.java
+++ b/src/main/java/com/google/devtools/build/lib/util/OS.java
@@ -20,7 +20,7 @@ public enum OS {
DARWIN("osx", "Mac OS X"),
LINUX("linux", "Linux"),
WINDOWS("windows", "Windows"),
- UNKNOWN("", "");
+ UNKNOWN("unknown", "");
private final String canonicalName;
private final String detectionName;
@@ -41,6 +41,11 @@ public enum OS {
return canonicalName;
}
+ @Override
+ public String toString() {
+ return getCanonicalName();
+ }
+
// We inject a the OS name through blaze.os, so we can have
// some coverage for Windows specific code on Linux.
private static OS determineCurrentOs() {