| // Copyright 2015 The Bazel Authors. All rights reserved. |
| // |
| // Licensed under the Apache License, Version 2.0 (the "License"); |
| // you may not use this file except in compliance with the License. |
| // You may obtain a copy of the License at |
| // |
| // http://www.apache.org/licenses/LICENSE-2.0 |
| // |
| // Unless required by applicable law or agreed to in writing, software |
| // distributed under the License is distributed on an "AS IS" BASIS, |
| // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| // See the License for the specific language governing permissions and |
| // limitations under the License. |
| |
| package com.google.devtools.build.lib.bazel.rules.android.ndkcrosstools; |
| |
| import com.google.common.base.Preconditions; |
| import com.google.common.collect.ImmutableList; |
| import com.google.common.collect.Lists; |
| 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; |
| private final String hostPlatform; |
| private final ApiLevel apiLevel; |
| private final Integer majorRevision; |
| |
| public NdkPaths( |
| String repositoryName, String hostPlatform, ApiLevel apiLevel, Integer majorRevision) { |
| this.repositoryName = repositoryName; |
| this.hostPlatform = hostPlatform; |
| this.apiLevel = apiLevel; |
| this.majorRevision = majorRevision; |
| } |
| |
| public 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(); |
| } |
| |
| public 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(llvmVersion == null ? "llvm" : "llvm-" + llvmVersion, "clang")) |
| .build()) |
| .build(); |
| } |
| |
| private String createToolPath(String toolchainName, String toolName) { |
| |
| String toolpathTemplate = "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("/")[2]; |
| } |
| |
| public String createGccToolchainPath(String toolchainName) { |
| |
| String gccToolchainPathTemplate = |
| "external/%repositoryName%/ndk/toolchains/%toolchainName%/prebuilt/%hostPlatform%"; |
| |
| return gccToolchainPathTemplate |
| .replace("%repositoryName%", repositoryName) |
| .replace("%toolchainName%", toolchainName) |
| .replace("%hostPlatform%", hostPlatform); |
| } |
| |
| /** |
| * Gets the clang NDK builtin includes directories that exist in the NDK. These directories are |
| * always searched for header files by clang and should be added to the CROSSTOOL in the |
| * cxx_builtin_include_directories list. |
| * |
| * <p>You can see the list of directories and the order that they are searched in by running |
| * {@code clang -E -x c++ - -v < /dev/null}. |
| */ |
| public String createClangToolchainBuiltinIncludeDirectory(String clangVersion) { |
| String clangBuiltinIncludeDirectoryPathTemplate = |
| "external/%repositoryName%/ndk/toolchains/llvm/prebuilt/%hostPlatform%/lib64/clang/" |
| + "%clangVersion%/include"; |
| return clangBuiltinIncludeDirectoryPathTemplate |
| .replace("%repositoryName%", repositoryName) |
| .replace("%hostPlatform%", hostPlatform) |
| .replace("%clangVersion%", clangVersion); |
| } |
| |
| /** |
| * Gets the gcc NDK builtin includes directories that exist in the NDK. These directories are |
| * always searched for header files by clang and should be added to the CROSSTOOL in the |
| * cxx_builtin_include_directories list. |
| * |
| * <p>You can see the list of directories and the order that they are searched in by running |
| * {@code gcc -E -x c++ - -v < /dev/null}. |
| */ |
| public List<String> createGccToolchainBuiltinIncludeDirectories( |
| final String toolchainName, final String targetPlatform, final String gccVersion) { |
| final String toolchainIncludePathTemplate = |
| "external/%repositoryName%/ndk/toolchains/%toolchainName%/prebuilt/%hostPlatform%" |
| + "/lib/gcc/%targetPlatform%/%gccVersion%/%includeFolderName%"; |
| return Lists.transform( |
| ImmutableList.of("include", "include-fixed"), |
| includeFolderName -> |
| toolchainIncludePathTemplate |
| .replace("%repositoryName%", repositoryName) |
| .replace("%toolchainName%", toolchainName) |
| .replace("%hostPlatform%", hostPlatform) |
| .replace("%targetPlatform%", targetPlatform) |
| .replace("%gccVersion%", gccVersion) |
| .replace("%includeFolderName%", includeFolderName)); |
| } |
| |
| /** |
| * NDK 14 and below. Each API level has its own headers. See |
| * https://android.googlesource.com/platform/ndk/+/ndk-r15-release/docs/UnifiedHeaders.md#supporting-unified-headers-in-your-build-system |
| * |
| * @param targetCpu the target CPU architecture |
| * @return the path to the compile time sysroot |
| */ |
| public 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); |
| } |
| |
| /** |
| * NDK 15 and above. The headers have been unified into ndk/sysroot. |
| * |
| * @return the sysroot location for NDK 15 and above. |
| */ |
| public String createBuiltinSysroot() { |
| // This location does not exist prior to NDK 15 |
| Preconditions.checkState(majorRevision >= 15); |
| |
| return "external/%repositoryName%/ndk/sysroot".replace("%repositoryName%", repositoryName); |
| } |
| |
| public String getCorrectedApiLevel(String targetCpu) { |
| return apiLevel.getCpuCorrectedApiLevel(targetCpu); |
| } |
| |
| ImmutableList<String> createGnuLibstdcIncludePaths(String gccVersion, String targetCpu) { |
| |
| String cpuNoThumb = targetCpu.replaceAll("-thumb$", ""); |
| |
| 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%", cpuNoThumb)); |
| } |
| return includePaths.build(); |
| } |
| |
| ImmutableList<String> createStlportIncludePaths() { |
| |
| String prefix = |
| "external/%repositoryName%/ndk/sources/cxx-stl/" |
| .replace("%repositoryName%", repositoryName); |
| |
| return ImmutableList.of(prefix + "stlport/stlport", prefix + "gabi++/include"); |
| } |
| |
| ImmutableList<String> createLibcxxIncludePaths() { |
| |
| String prefix = |
| "external/%repositoryName%/ndk/sources/".replace("%repositoryName%", repositoryName); |
| |
| ImmutableList.Builder<String> includePaths = ImmutableList.builder(); |
| |
| if (majorRevision <= 12) { |
| includePaths.add(prefix + "cxx-stl/llvm-libc++/libcxx/include"); |
| includePaths.add(prefix + "cxx-stl/llvm-libc++abi/libcxxabi/include"); |
| } else { |
| // libcxx/include was moved one level up from r13 onwards. |
| // See https://github.com/bazelbuild/bazel/issues/3641 |
| includePaths.add(prefix + "cxx-stl/llvm-libc++/include"); |
| includePaths.add(prefix + "cxx-stl/llvm-libc++abi/include"); |
| } |
| |
| includePaths.add(prefix + "android/support/include"); |
| |
| return includePaths.build(); |
| } |
| |
| /** |
| * @param stl The STL name as it appears in the NDK path |
| * @param gccVersion The GCC version "4.8" or "4.9", applicable only to gnu-libstdc++, or null |
| * @param targetCpu Target CPU |
| * @param fileExtension "a" or "so" |
| * @return A glob pattern for the STL runtime libs in the NDK. |
| */ |
| static String createStlRuntimeLibsGlob( |
| String stl, String gccVersion, String targetCpu, String fileExtension) { |
| |
| if (gccVersion != null) { |
| stl += "/" + gccVersion; |
| } |
| |
| targetCpu = targetCpu.replaceAll("-thumb$", "/thumb"); |
| |
| String template = |
| "ndk/sources/cxx-stl/%stl%/libs/%targetCpu%/*.%fileExtension%"; |
| return template |
| .replace("%stl%", stl) |
| .replace("%targetCpu%", targetCpu) |
| .replace("%fileExtension%", fileExtension); |
| } |
| |
| /** |
| * @param targetCpu Target CPU |
| * @return the directory of the target CPU's runtime .a files for linking |
| */ |
| public String createLibcppLinkerPath(String targetCpu) { |
| return "external/%repositoryName%/ndk/sources/cxx-stl/llvm-libc++/libs/%targetCpu%" |
| .replace("%repositoryName%", repositoryName) |
| .replace("%targetCpu%", targetCpu); |
| } |
| } |
| |