使用Android Studio和CMake进行NDK开发 - 基础

1. 概述


在Android Studio 2.2之后,可以使用CMake来进行NDK开发,C/C++开发的便利性又提升了不少。这个是个好事,比较CMake使用起来还是比make要简单,并且抽象、跨平台。例如在linux可以生产linux下的makefile,在windows下可以生产Visual Studio的工程文件。

这里需要解析几个名词:

  • NDK

Android Native Development Kit,里面包含各个平台上的C/C++编译器、相关头文件和库(相当于Java的库)。

  • CMake

一套构建系统,类似Gradle,但是CMake不直接参与编译,而是产生其他构建系统的工程文件,再进行编译,在Android Studio当中,Gradle插件会驱动CMake产生各个平台(armeabi、armeabi-v7a、x86等)的ninja的构建文件,再驱动编译器进行编译。

  • LLDB

调试器,可以用来调试原生代码,之前版本使用的是GDB。

2. 准备


本文是基于Android Studio 2.3来讲解的,因此需要升级到2.3。安装好2.3之后,打开【SDK Manager】

image.png

勾选:【CMake】和【NDK】两个选项,然后点击【Apply】进行安装

因为google在国内假设了镜像站点,现在不需要使用[可不描述]来更新SDK了

3. 实践

3.1 创建项目


创建项目的流程,官方文档也有: https://developer.android.com/studio/projects/add-native-code.html
因此,我这里会在流程上补充一些说明。

新建项目,在第一页中勾选:

image.png

【include c++ support】来支持C++开发,如果已有项目没有勾选也没关系,可以在菜单中【link 】

一路next来到最后一页,定制你的C++项目支持

image.png

主要有三个参数组成:

  • C++标准

现在基本都是C++ 11开发了,如果不是要维护非常老的代码,建议选择C++11。
C++11相对于之前的版本(C++03)增加的功能非常丰富,具体可以参考这篇文章: http://blog.csdn.net/zhuxianjianqi/article/details/8658169

  • Exception Support

异常支持,如果取消掉的话,那么就不能使用 try-catch 进行异常处理了,建议选择。

  • Runtime Type Information Support

运行时类型信息支持,在C++运行的时候,不像Java、C#等一样,可以动态获取对象的类信息,开启这个选项来支持这个功能,建议选择。

到这里,项目就创建完毕了,点击 run 按钮,APP就可以在模拟器或者android设备上运行。

3.2 工程结构


打开代码所在的目录,进入APP子模块,可以看到相比传统的APP项目,会多出以下文件或者目录:

  • CMakeList.txt

CMake的工程文件,相当于 build.gradle 用于说明编译那些C/C++源码,以及相关的编译参数

  • src/main/cpp

C/C++源码目录

  • .externalNativeBuild

该文件夹是临时文件夹,gradle插件会调用cmake产生各个平台的临时构建文件,都存放在该目录

3.3 编译流程


需要注意的是,cmake并不能直接编译 c/c++ 源码,需要产生 ninja 的项目文件,才会编译,其流程大体是这样的。

生成ninja工程 ---> 编译/链接 ---> APP打包

对于 产生ninja工程,可以通过下述三种方式:

  • 修改CMakeLists.txt,然后执行 Build菜单的 Make Project 或者 Make module 或者直接 Run
  • 执行 Gradle Sync
  • 执行 Build菜单的 Refresh Linked C++ Projects

在实际使用中,有时候修改CMakeLists.txt不会重新产生ninja工程文件,导致编译会出现问题,所以官方可能也留了 Refresh Linked C++ Projects 给到大家手动刷新。另外,手动添加 C/C++源码的时候,也可以通过这种方式刷新工程。

4. 编译参数解析

4.1 build.gradle


该文件可以指定工具链的大部分核心参数,里面的源码大致如下:

apply plugin: 'com.android.application'

android {
    compileSdkVersion 24
    buildToolsVersion "25.0.3"
    defaultConfig {
        applicationId "com.test.ndkhelloworld"

        ...

        // 该代码块用于配置相关的参数
        externalNativeBuild {
            cmake {
                cppFlags "-std=c++11 -frtti -fexceptions"
            }
        }
    }
    buildTypes {
        release {
            minifyEnabled false
            proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
        }
    }

    // 该代码块用于链接到指定的CMakeLists.txt,路径是相对路径
    externalNativeBuild {
        cmake {
            path "CMakeLists.txt"
        }
    }
}

...

这里有两个 externalNativeBuild 代码块

  • android.externalNativeBuild

ExternalNativeBuild 对象:http://google.github.io/android-gradle-dsl/current/com.android.build.gradle.internal.dsl.ExternalNativeBuild.html
主要配置 cmake 或者 ndk-build 的工程文件路径

  • `android.defaultConfig.externalNativeBuild

ExternalNativeBuildOptions 对象: http://google.github.io/android-gradle-dsl/current/com.android.build.gradle.internal.dsl.ExternalNativeBuild.html
具体的参数配置。后面都是以这个配置参数来讲解。

4.2 CMake变量解析


可以通过 arguments 命令来传递CMake构建参数(这些参数,实际会传递到NDK的构建工具链),形式为: -D参数名=参数值1 参数值2,需要注意的是,如果有多个参数,那么必须换行来传递,例如:

externalNativeBuild {
            cmake {
                arguments "-DANDROID_TOOLCHAIN=gcc"
                            "-DANDROID_STL=stlport_static"
            }
        }

以下是常用的变量:

  • ANDROID_TOOLCHAIN

编译工具链,可选:clang(默认)和gcc(已经过期)。

  • ANDROID_PLATFORM

android平台,例如:android-18 注意,该取值会影响到原生API的时候,有些原生API在低版本的android是没有的,详见: https://developer.android.com/ndk/guides/stable_apis.html

  • ANDROID_STL

STL(标准模板库)的选择,NDK自带了很多个版本的STL,功能大体上是一样的,但是授权会不一样。详细请阅读: https://developer.android.com/ndk/guides/cpp-support.html#hr
(stlport已经实现异常处理了,在低版本的NDK是不支持的)

  • ANDROID_PIE

启用PIE(position-independent executables),如果是 ANDROID_PLATFORM = android-16,该选项默认开启(取值为 ON),否则为 OFF

  • ANDROID_CPP_FEATURES

C++的功能,取值为: rttiexceptions,也可以使用 cppFlags 指定

  • ANDROID_ALLOW_UNDEFINED_SYMBOLS

允许未定义的符号,默认为 FALSE,可以取值为:TRUE

  • ANDROID_ARM_MODE

指令集模式,默认为: thumb ,可以取值为: arm

  • ANDROID_ARM_NEON

是否启用NEON,默认为FALSE,启用为:TRUE

  • ANDROID_DISABLE_FORMAT_STRING_CHECKS

是否禁用字符串格式化检查,默认为:FALSE,可以取值为:TRUE,建议默认值,不要禁用,因为很多漏洞或者BUG都出现在字符串格式化上面。

4.3 abi过滤器


通过 abiFilters 可以编译出指定ABI的二进制文件,可选值为:armeabiarmeabi-v7aarm64-v8amipsmips64x86以及x86_64

默认情况下,编译出来的都包含上述的ABI的二进制文件,如下图:

APK信息,build菜单->Analyze APK->选择产生的APK

可以清楚的看到,编译出来的二进制文件(库)可以在ARM、X86和MIPS所有平台上运行。实际上,我们想给APK瘦身的,不需要在那么多平台上运行,可以取消掉一些平台的支持,例如我们只支持armeabi和armeabi-v7a,X86和MIPS都不需要

externalNativeBuild {
            cmake {
                abiFilters "armeabi", "armeabi-v7a"
                cppFlags "-std=c++11 -frtti -fexceptions"
                arguments "-DANDROID_TOOLCHAIN=gcc",
                            "-DANDROID_STL=stlport_static"
            }
        }

执行clean之后再产生APK,可以看到,只有两个ABI的二进制产生

APK信息,build菜单->Analyze APK->选择产生的APK

我发现一个问题,即使sync、clean等一系列的操作后,不会删除原有产生的ninja工程文件,可以先手动删除掉 .externalNativeBuild 目录再重试一下。

4.4 传递C/C++参数


cFlags和cppFlags可以传递C/C++编译参数,这里不详细讨论。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 203,098评论 5 476
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,213评论 2 380
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 149,960评论 0 336
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,519评论 1 273
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,512评论 5 364
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,533评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,914评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,574评论 0 256
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,804评论 1 296
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,563评论 2 319
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,644评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,350评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,933评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,908评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,146评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,847评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,361评论 2 342

推荐阅读更多精彩内容