Android NDK 12 交叉编译

前言

简单地说,交叉编译就是程序的编译的环境和它的运行的环境不一样,即在一个平台上生成另一个平台上的可执行代码。需要使用交叉编译的主要原因是由于目标环境中各种资源都相对有限,所以很难直接进行本地编译。

一、交叉编译工具链

1.1、什么是交叉编译工具链

交叉工具链是指可以生成目标环境可运行代码的工具集。在 Linux 系统中的编译工具链包括以下一些工具,编译器 gcc,链接器 ld,归档工具 ar 等,如果在 Linux 环境中交叉编译 Android 系统环境可运行的代码,是不能直接使用 Linux 下的编译工具的,而应该使用 Android NDK 里的工具链,它们对应的名子为 arm-linux-android-gcc,arm-linux-android-ld 等。

1.2、交叉编译工具的命名规则

交叉编译工具的命名形式如下所示:

arch-[vendor]-kernel-system-toolname

它由五部分组成,下面分别解释一下每部分的含义:

  1. arch,指的是 CPU 架构,一般包括如下几种架构:
  • arm
  • mips
  • powerpc
  • x86
  • x86_64
  1. verdor,一般指的是生产厂商,如果没有生产厂商可以为空。
  2. kernel,指的目标环境使用的 kernel,以 android 为例,它使用的是 linux 内核,所以在这部分会填写为 linux。
  3. system,指的是哪个系统,如:
  • androideabi
  • android
  1. toolname: 指的是 gcc,ld,ar 等。

所以可以看到 android 的编译工具的名子会写成 arm-linux-andirod-gcc。

1.3、交叉编译常用变量说明

在做交叉编译时,常会在脚本中定义一些环境变量以方便我们命名用,常用的环境变量如下:

  • PREFIX: 指明交叉编译后输出的目录;
  • ARCH: 指明交叉编译后输出的 CPU 架构;
  • CROSS-PREFIX:指明交叉编译前辍 arch-vender-kernel-system;
  • SYSROOT: 指明交叉编译目标机器的头文件和库文件目录
  • TOOLCHAIN: 指明交叉编译工具链的位置;
  • PLATFROM:指明交叉编译时使用的是哪个版本的的头文件和库文件,它是 SYSROOT 的一部分;
  • ANDROID_NDK: 指明 Android NDK 所在目录。

二、如何进行交叉编译

通过设置 configure 参数来生成交叉编译的 Makefile 文件:

  • arch 指定架构;
  • cross-prefix 交叉编译工具链前辍;
  • sys root 交叉编译树的根。

例子:

以 ffmpeg 的交叉编译为例,来看一下如何生成交叉编译的 Makefile:

./configure --target-os=linux --arch=arm --enable-cross-compile --cross-prefix=arm-linux-androideabi-
--sysroot=~Library/Android/sdk/ndk-bundle/platforms/android-9/arch-arm

执行后的结果如下:

install prefix            /usr/local
source path               .
C compiler                arm-linux-androideabi-gcc
C library                 bionic
host C compiler           gcc
host C library
ARCH                      arm (armv5te)

三、使用 ndk-build 编译 NDK 程序

Google 提供了一系列脚本工具,以方便大家做 Android NDK 方面的开发,其中最重要的是 ndk-build 脚本。有了这些脚本,开发者就不必再定义各种环境变量,只需要提供两个 Makefile 片段指明要编译哪些 C/C++文件,生成哪个目标环境的程序就好了。ndk-build 脚本工具会自动检测各种环境变量、目标环境编译器等,最终完成交叉编译。

3.1 NDK-BUILD 的工作

先来看一下 ndk-build,通过查看 ndk-build 源码可以看到,它执行的是类似于

$GNUMAKE -f <ndk>/build/core/build-local.mk <parameters> 

这样的命令,实际就是自动检测并设置环境变量。执行 ndk-build NDK_LOG=1 命令,会看到下面的信息:

Android NDK: NDK installation path auto-detected:
Android NDK: GNU Make version 3.81 detected
Android NDK: Host OS was auto-detected: darwin
Android NDK: Host operating system detected: darwin
Android NDK: Host CPU was auto-detected: x86
Android NDK: HOST_TAG set to darwin-x86
Android NDK: Host tools prebuilt directory:
#这里检测到编译器地址
~/Library/Android/sdk/ndk-bundle/prebuilt/darwin-x86_64/bin
Android NDK: Found platform root directory:
#这里检测到 platforms 目录地址
~/Library/Android/sdk/ndk-bundle/platforms
#下面列出了所有支持的 platform
Android NDK: Found supported platforms: android-12 android-13 android-14 android-15 android-16 android-17
android-18 android-19 android-21 android-22 android-23 android-24 android-26 android-9
#列出支持的目标环境
Android NDK: PLATFORM android-12 supports: arm mips x86
......
#下面是每个目标环境的的环境树
Android NDK:   ABI arm sysroot is: /Users/lichao/Library/Android/sdk/ndk-bundle/platforms/android-12/arch-arm
Android NDK:   ABI mips sysroot is: /Users/lichao/Library/Android/sdk/ndk-bundle/platforms/android-12/arch-mips
Android NDK:   ABI x86 sysroot is: /Users/lichao/Library/Android/sdk/ndk-bundle/platforms/android-12/arch-x86

通过上面的分析就应该清楚 ndk-build 主要作什么事情了。既然 Google 已经给我们提供了这么方便的交叉编译工具,那作为开发者还需要做下面两件事儿:

  1. 编写 C/C++ 代码

  2. 编写 Android.mk 和 Application.mk 两个 Makefile 片段

3.2、Android.mk 与 Application.mk

下面就来看一下两个 Makefile 片段 Android.mk 和 Application.mk 是做什么用的。

  • Android.mk:目的是用于向构建系统描述源文件和共享库,它位于 $PROJECT/jni/ 目录中
  • Application.mk:目的是描述在你的应用程序中所需要的模块(即静态库或动态库),它也位于 $PROJECT/jni/ 目录中

3.2.1、Android.mk

先来看一下 Android.mk 的例子:

LOCAL_PATH       :=  $(call my-dir)
include              $(CLEAR_VARS)
LOCAL_MODULE     :=  hello_jni
LOCAL_SRC_FILES  :=  hello_jni.c
include              $(BUILD_SHARED_LIBRARY)

每行语句的作用如下:

  • LOCAL_PATH

    在 Android.mk 中必须首先定义 LOCAL_PATH 变量,此变量表示源文件在开发树中的位置。构建系统提供的宏函数 my-dir 将返回当前目录(包含 Android.mk 文件本身的目录)的路径。

  • CLEAR_VARS

    CLEAR_VARS 变量指向特殊 GNU Makefile,可清除许多 LOCAL_XXX 变量,例如 LOCAL_MODULE、LOCAL_SRC_FILES 和 LOCAL_STATIC_LIBRARIES。

请注意,它不会清除 LOCAL_PATH。此变量必须保留其值,因为系统在单一 GNU Make 执行环境(其中所有变量都是全局的)中解析所有构建控制文件。在描述每个模块之前,必须声明(重新声明)此变量。

  • LOCAL_MODULE

    变量将存储要构建的模块的名称。

  • LOCAL_SRC_FILES

    LOCAL_SRC_FILES 枚举源文件,以空格分隔多个文件。LOCAL_SRC_FILES 变量必须包含要构建到模块中的 C 和/或 C++ 源文件列表。

  • BUILD_SHARED_LIBRARY

    这一行帮助系统将所有内容连接到一起。

3.2.2、Application.mk

再来看一下 Application.mk 的例子:

APP_PLATFORM := android-9
APP_STL := gnustl_static
APP_CFLAGS := -Wno-error=format-security
APP_ABI := armeabi armeabi-v7a arm64-v8a
APP_OPTION := release

每行的作用如下:

  • APP_PLATFORM

此变量包含目标 Android 平台的名称。NDK API 级别与 Android 版本对照表如下:

NDK 支持的 API 级别 Android 版本
9 2.3 到 3.0.x
12 3.1.x
13 3.2
14 4.0 到 4.0.2
15 4.0.3 和 4.0.4
16 4.1 和 4.1.1
17 4.2 和 4.2.2
18 4.3
19 4.4
21 4.4W 和 5.0
  • APP_STL

    默认情况下,NDK 构建系统为 Android 系统提供的最小 C++ 运行时库(system/lib/libstdc++.so) 。该指令可以让您在自己的应用中使用或链接的替代 C++ 实现。

  • APP_CFLAGS

    构建系统在仅构建 C++ 源文件时传递到编译器的一组 C++ 编译器标志。

  • APP_ABI

    您可以使用 APP_ABI 选择编译出不同的 ABI 目标环境代码。

  • APP_OPTION

    可定义变量为 release 或 debug。在构建应用的模块时可使用它来更改优化级别。

通过上面的分析,我们可以知道 Google 为了开发者更容易的开发 NDK 程序,给我们提供了一套交叉编译的工具,大大降低了开发 NDK 程序的难度。

原文连接:Linux/Mac 交叉编译 Android 程序 & 深入理解使用ndk-build编译NDK程序

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

推荐阅读更多精彩内容

  • Android游戏开发实践(1)之NDK与JNI开发02 承接上篇Android游戏开发实践(1)之NDK与JNI...
    AlphaGL阅读 3,740评论 0 24
  • 一、NDK产生的背景 Android平台从诞生起,就已经支持C、C++开发。众所周知,Android的SDK基于J...
    Ten_Minutes阅读 3,482评论 1 27
  • 翻译自docs/ANDROID-MK.html Indroduction 本篇文档描述Andrid.mk编译文件的...
    记得柒叁贰阅读 17,346评论 0 15
  • 在我们传统看来,孕期有很多忌讳,很多事情都不能做,一些场合更是不待见孕妇。近日,台湾一位准妈妈就遭遇了这么一件事:...
    瞧那一家子阅读 763评论 0 0
  • 默日,末日,这是每一个人都不希望出现的日子。 自从默日出生,家里就开始死人,他的名字也定了下来。默日,默字与末同...
    沐玥卿阅读 445评论 1 2