diff options
Diffstat (limited to 'src/main/java/com')
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() { |