最小的Android CMake构建

时间:2018-10-16 17:41:59

标签: android c++ cmake

我正在尝试将本机C ++ DLL移植为Android上的共享库。对于构建,我使用的是VSCode,而不是Visual Studio。下载了Android NDK r18b。我的项目基于CMake,当我尝试使用“ NMake Mmakefiles”生成器生成该项目时,总是会收到此错误:

CMAKE_SYSTEM_NAME is 'Android' but 'NVIDIA Nsight Tegra Visual Studio Edition' is not installed.

我创建了一个小项目来对此进行测试。

main.cpp

int foo( int a, int b ) { return a + b; }

CMakeLists.txt

cmake_minimum_required( VERSION 3.11.0 )
add_library( Engine SHARED main.cpp )

我使用以下命令行(CMake 3.11.4)运行它:

cmake -g "NMake Makefiles" .. -DCMAKE_TOOLCHAIN_FILE=%NDK_ROOT%\build\cmake\android.toolchain.cmake -DANDROID_NDK=%NDK_ROOT%

有了这个,我仍然得到错误:

CMake Error in CMakeLists.txt:
CMAKE_SYSTEM_NAME is 'Android' but 'NVIDIA Nsight Tegra Visual Studio Edition' is not installed.

有人可以帮我把这个小main.cpp制作成Android .so吗?我不想使用Android Studio或其他IDE。寻找创建make文件并将其添加到我的VSCode版本中。

谢谢。

2 个答案:

答案 0 :(得分:0)

如果您愿意使用Gradle来配置cmake ...

我使用Gradle Wrapper,在安装gradle之后,您可以在目录中调用gradle wrapper,它将安装本地副本。此副本可以设置为特定版本,也可以为upgraded

Android Gradle插件使用ninja构建系统来配置cmake和目标ABI。以下脚本将为所有受支持的平台类型生成ABI,但是很容易删除您不想创建的任何ABI。

VSCode有一个gradle plugin可以从IDE生成,或者您可以创建仅调用gradlew命令行的构建类型。


首先,我先使用gradle wrapper然后使用gradlew init来创建gradle项目。

然后,我添加了用于构建Android库的构建脚本。

build.gradle

/*
 * This file was generated by the Gradle 'init' task.
 *
 * This is a general purpose Gradle build.
 * Learn how to create Gradle builds at https://guides.gradle.org/creating-new-gradle-builds/
 */
 buildscript {
    repositories {
        jcenter()
        google()
    }
    dependencies {
        classpath 'com.android.tools.build:gradle:3.2.1'
        // NOTE: Do not place your application dependencies here; they belong
        // in the individual module build.gradle files
    }
}

allprojects {
    repositories {
        jcenter()
        google()
    }
}

apply plugin: 'com.android.library'

android {
    compileSdkVersion 28      // Change this to the SDK version you have installed
    buildToolsVersion '28.0.3' // Change this to the SDK build tools you have installed
    defaultConfig {
        minSdkVersion 16      // Cannot be less than 16
        targetSdkVersion 28   // Same as CompileSdkVersion
        versionCode 1
        versionName "1.0"

        sourceSets {
            main {
                manifest.srcFile 'AndroidManifest.xml'
            }
        }

        ndk {
            abiFilters = []
            abiFilters.addAll(ABI_FILTERS.split(';').collect { it as String })
        }

        externalNativeBuild {
            cmake {
                arguments '-DANDROID_PLATFORM=android-16',
                        '-DANDROID_TOOLCHAIN=clang', '-DANDROID_STL=c++_static',
                        '-DANDROID_CPP_FEATURES=rtti exceptions'
            }
        }

    }
    externalNativeBuild {
        cmake {
            path './CMakeLists.txt'
        }
    }
    buildTypes {
        release {
            minifyEnabled false
        }
        debug {
            debuggable true
            jniDebuggable true
            minifyEnabled false
        }
    }
}

此构建文件包括一个虚拟 AndroidManifest.xml 文件:

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.example"
    android:versionCode="1"
    android:versionName="1.0" >

    <uses-sdk android:minSdkVersion="16" />

    <application/>

</manifest>

我需要旧版本的CMake,我使用3.4而不是3.11

CMakeLists.txt

cmake_minimum_required( VERSION 3.4.0 )
add_library( Engine SHARED main.cpp )

local.properties

# This file must *NOT* be checked into Version Control Systems,
# as it contains information specific to your local configuration.
#
# Location of the SDK. This is only used by Gradle.
# For customization when using a Version Control System, please read the
# header note.
ndk.dir=d\:\\android\\ndk
sdk.dir=d\:\\android\\sdk

gradle.properties

# Project-wide Gradle settings.

# IDE (e.g. Android Studio) users:
# Gradle settings configured through the IDE *will override*
# any settings specified in this file.

# For more details on how to configure your build environment visit
# http://www.gradle.org/docs/current/userguide/build_environment.html

# Specifies the JVM arguments used for the daemon process.
# The setting is particularly useful for tweaking memory settings.
org.gradle.jvmargs=-Xmx1536m

# When configured, Gradle will run in incubating parallel mode.
# This option should only be used with decoupled projects. More details, visit
# http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects
# org.gradle.parallel=true

# EDIT THIS LINE to change the Target ABIs
ABI_FILTERS=x86;x86_64;armeabi-v7a;arm64-v8a

org.gradle.java.home=D:\\Program Files\\Java\\jdk8

distributionUrl=\
  https\://services.gradle.org/distributions/gradle-4.1-all.zip

# When set to true the Gradle daemon is used to run the build. For local developer builds this is our favorite property.
# The developer environment is optimized for speed and feedback so we nearly always run Gradle jobs with the daemon.
org.gradle.daemon=true

最后,要构建,我只需运行:

.\gradlew :externalNativeBuildDebug

.\gradlew :externalNativeBuildRelease

它会在build\intermediates\cmake目录中生成库。

答案 1 :(得分:0)

我将其留在这里,是因为很难找到并完成有关Android Gradle实际操作方式的詹姆斯回答。

Gradle Task execution

CMake arguments created the Gradle

    ProcessInfoBuilder builder = new ProcessInfoBuilder();
    // CMake requires a folder. Trim the filename off.
    File cmakeListsFolder = getMakefile().getParentFile();

    builder.setExecutable(getCmakeExecutable());
    builder.addArgs(String.format("-H%s", cmakeListsFolder));
    builder.addArgs(String.format("-B%s", outputJson.getParentFile()));
    builder.addArgs("-GAndroid Gradle - Ninja");
    builder.addArgs(String.format("-DANDROID_ABI=%s", abi));
    builder.addArgs(String.format("-DANDROID_NDK=%s", getNdkFolder()));
    builder.addArgs(
            String.format("-DCMAKE_LIBRARY_OUTPUT_DIRECTORY=%s",
                    new File(getObjFolder(), abi)));
    builder.addArgs(
            String.format("-DCMAKE_BUILD_TYPE=%s", isDebuggable() ? "Debug" : "Release"));
    builder.addArgs(String.format("-DCMAKE_MAKE_PROGRAM=%s",
            getNinjaExecutable().getAbsolutePath()));
    builder.addArgs(String.format("-DCMAKE_TOOLCHAIN_FILE=%s",
            getToolChainFile().getAbsolutePath()));

    builder.addArgs(String.format("-DANDROID_NATIVE_API_LEVEL=%s", abiPlatformVersion));

    if (!getcFlags().isEmpty()) {
        builder.addArgs(String.format("-DCMAKE_C_FLAGS=%s", Joiner.on(" ").join(getcFlags())));
    }

    if (!getCppFlags().isEmpty()) {
        builder.addArgs(String.format("-DCMAKE_CXX_FLAGS=%s",
                Joiner.on(" ").join(getCppFlags())));
    }

    for (String argument : getBuildArguments()) {
        builder.addArgs(argument);
    }