All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.android.build.gradle.ndk.internal.NdkHandler Maven / Gradle / Ivy

/*
 * Copyright (C) 2014 The Android Open Source Project
 *
 * 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.android.build.gradle.ndk.internal;

import static com.android.SdkConstants.FN_LOCAL_PROPERTIES;

import com.android.SdkConstants;
import com.android.annotations.Nullable;
import com.android.build.gradle.ndk.NdkExtension;
import com.android.builder.model.AndroidProject;
import com.google.common.base.Charsets;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableMap;
import com.google.common.io.Closeables;

import org.gradle.api.InvalidUserDataException;
import org.gradle.api.Project;
import org.gradle.nativebinaries.BuildType;
import org.gradle.nativebinaries.platform.Platform;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.Locale;
import java.util.Collection;
import java.util.List;
import java.util.Map;
import java.util.Properties;

/**
 * Handles NDK related information.
 */
public class NdkHandler {

    // Map of ABI to toolchain platform string.
    private static final Map PLATFORM_STRING;

    // Map of ABI to target architecture
    private static final Map ARCHITECTURE_STRING;

    // Map of toolchain names to the subdirectory name containing the toolchain.
    private static final Map TOOLCHAIN_STRING;

    private static final List ABI32 = ImmutableList.of(
            SdkConstants.ABI_INTEL_ATOM,
            SdkConstants.ABI_ARMEABI_V7A,
            SdkConstants.ABI_ARMEABI,
            SdkConstants.ABI_MIPS);

    private static final List ALL_ABI = ImmutableList.of(
            SdkConstants.ABI_INTEL_ATOM,
            SdkConstants.ABI_INTEL_ATOM64,
            SdkConstants.ABI_ARMEABI_V7A,
            SdkConstants.ABI_ARMEABI,
            SdkConstants.ABI_ARM64_V8A,
            SdkConstants.ABI_MIPS,
            SdkConstants.ABI_MIPS64);

    private NdkExtension ndkExtension;

    private Project project;

    private File ndkDirectory;

    static {
        // Initialize static maps.
        PLATFORM_STRING = ImmutableMap.builder()
                .put(SdkConstants.ABI_INTEL_ATOM, "x86")
                .put(SdkConstants.ABI_INTEL_ATOM64, "x86_64")
                .put(SdkConstants.ABI_ARMEABI_V7A, "arm-linux-androideabi")
                .put(SdkConstants.ABI_ARMEABI, "arm-linux-androideabi")
                .put(SdkConstants.ABI_ARM64_V8A, "aarch64-linux-android")
                .put(SdkConstants.ABI_MIPS, "mipsel-linux-android")
                .put(SdkConstants.ABI_MIPS64, "mips64el-linux-android")
                .build();

        ARCHITECTURE_STRING = ImmutableMap.builder()
                .put(SdkConstants.ABI_INTEL_ATOM, SdkConstants.CPU_ARCH_INTEL_ATOM)
                .put(SdkConstants.ABI_INTEL_ATOM64, SdkConstants.CPU_ARCH_INTEL_ATOM64)
                .put(SdkConstants.ABI_ARMEABI_V7A, SdkConstants.CPU_ARCH_ARM)
                .put(SdkConstants.ABI_ARMEABI, SdkConstants.CPU_ARCH_ARM)
                .put(SdkConstants.ABI_ARM64_V8A, SdkConstants.CPU_ARCH_ARM64)
                .put(SdkConstants.ABI_MIPS, SdkConstants.CPU_ARCH_MIPS)
                .put(SdkConstants.ABI_MIPS64, SdkConstants.CPU_ARCH_MIPS64)
                .build();

        TOOLCHAIN_STRING = ImmutableMap.builder()
                .put("gcc", "")
                .put("clang", "clang")
                .build();
    }

    public NdkHandler(Project project, NdkExtension ndkExtension) {
        this.project = project;
        this.ndkExtension = ndkExtension;
        ndkDirectory = findNdkDirectory(project);
    }

    /**
     * Toolchain name used by the NDK.
     *
     * This is the name of the folder containing the toolchain under $ANDROID_NDK_HOME/toolchain.
     * e.g. for gcc targetting arm64_v8a, this method returns "aarch64-linux-android-4.9".
     */
    private static String getToolchainName(
            String toolchain,
            String toolchainVersion,
            String platform) {
        return PLATFORM_STRING.get(platform) + "-" + TOOLCHAIN_STRING.get(toolchain)
                + toolchainVersion;
    }

    /**
     * Determine the location of the NDK directory.
     *
     * The NDK directory can be set in the local.properties file or using the ANDROID_NDK_HOME
     * environment variable.
     */
    private static File findNdkDirectory(Project project) {
        File rootDir = project.getRootDir();
        File localProperties = new File(rootDir, FN_LOCAL_PROPERTIES);

        if (localProperties.isFile()) {

            Properties properties = new Properties();
            InputStreamReader reader = null;
            try {
                //noinspection IOResourceOpenedButNotSafelyClosed
                FileInputStream fis = new FileInputStream(localProperties);
                reader = new InputStreamReader(fis, Charsets.UTF_8);
                properties.load(reader);
            } catch (FileNotFoundException ignored) {
                // ignore since we check up front and we don't want to fail on it anyway
                // in case there's an env var.
            } catch (IOException e) {
                throw new RuntimeException("Unable to read ${localProperties}", e);
            } finally {
                try {
                    Closeables.close(reader, true /* swallowIOException */);
                } catch (IOException e) {
                    // ignore.
                }
            }

            String ndkDirProp = properties.getProperty("ndk.dir");
            if (ndkDirProp != null) {
                return new File(ndkDirProp);
            }

        } else {
            String envVar = System.getenv("ANDROID_NDK_HOME");
            if (envVar != null) {
                return new File(envVar);
            }
        }
        return null;
    }

    /**
     * Returns the directory of the NDK.
     */
    @Nullable
    public File getNdkDirectory() {
        return ndkDirectory;
    }

    NdkExtension getNdkExtension() {
        return ndkExtension;
    }

    /**
     * Return the path containing the prebuilt toolchain.
     *
     * @param toolchain        Name of the toolchain ["gcc", "clang"].
     * @param toolchainVersion Version of the toolchain.
     * @param platform         Target platform supported by the NDK.
     * @return Directory containing the prebuilt toolchain.
     */

    public File getToolchainPath(String toolchain, String toolchainVersion, String platform) {
        File prebuiltFolder;
        if (toolchain.equals("gcc")) {
            prebuiltFolder = new File(
                    getNdkDirectory(),
                    "toolchains/" + getToolchainName(toolchain, toolchainVersion, platform)
                            + "/prebuilt");

        } else if (toolchain.equals("clang")) {
            prebuiltFolder = new File(
                    getNdkDirectory(),
                    "toolchains/llvm-" + toolchainVersion + "/prebuilt");
        } else {
            throw new InvalidUserDataException("Unrecognized toolchain: " + toolchain);
        }

        String osName = System.getProperty("os.name").toLowerCase(Locale.ENGLISH);
        String hostOs;
        if (osName.contains("windows")) {
            hostOs = "windows";
        } else if (osName.contains("mac")) {
            hostOs = "darwin";
        } else {
            hostOs = "linux";
        }

        // Use 64-bit toolchain if available.
        File toolchainPath = new File(prebuiltFolder, hostOs + "-x86_64");
        if (toolchainPath.isDirectory()) {
            return toolchainPath;
        }

        // Fallback to 32-bit if we can't find the 64-bit toolchain.
        toolchainPath = new File(prebuiltFolder, hostOs);
        if (toolchainPath.isDirectory()) {
            return toolchainPath;
        } else {
            throw new InvalidUserDataException("Unable to find toolchain prebuilt folder in: "
                    + prebuiltFolder);
        }
    }

    /**
     * Returns the sysroot directory for the toolchain.
     */
    public String getSysroot(Platform platform) {
        return ndkDirectory + "/platforms/" + ndkExtension.getCompileSdkVersion()
                + "/arch-" + ARCHITECTURE_STRING.get(platform.getName());
    }

    /**
     * Return the output directory for a BuildType and Platform.
     */
    public File getOutputDirectory(BuildType buildType, Platform platform) {
        return new File(
                project.getBuildDir() + "/" + AndroidProject.FD_INTERMEDIATES + "/binaries/",
                ndkExtension.getModuleName() + "SharedLibrary/" + buildType.getName() + "/lib/" +
                        platform.getName());
    }

    /**
     * Return the directory containing prebuilt binaries such as gdbserver.
     */
    public File getPrebuiltDirectory(Platform platform) {
        return new File(
                ndkDirectory, "prebuilt/android-" + ARCHITECTURE_STRING.get(platform.getName()));
    }

    /**
     * Return true if compiledSdkVersion supports 64 bits ABI.
     */
    public boolean supports64Bits() {
        String targetString = getNdkExtension().getCompileSdkVersion().replace("android-", "");
        try {
            return Integer.parseInt(targetString) >= 20;
        } catch (NumberFormatException ignored) {
            // "android-L" supports 64-bits.
            return true;
        }
    }

    /**
     * Return the gcc version that will be used by the NDK.
     *
     * If the gcc toolchain is used, then it's simply the toolchain version requested by the user.
     * If clang is used, then it depends on the version of the NDK.
     */
    public String getGccToolchainVersion() {
        if (ndkExtension.getToolchain().equals("gcc")) {
            return ndkExtension.getToolchainVersion();
        } else {
            return supports64Bits() ? "4.9" : "4.8";
        }
    }

    /**
     * Returns a list of supported ABI.
     */
    public Collection getSupportedAbis() {
        return supports64Bits() ? ALL_ABI : ABI32;
    }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy