【Cmake】利用NDK進行Android的交叉編譯(附實例)

很多時候,對於C++軟件工程師來說,可能需要編譯能夠在Android版本上直接運行的可執行程序、或者是編譯so庫文件,這個時候就需要完成交叉編譯。在命令行下執行交叉編譯有兩種方式:

  • 一是用NDK自帶的工具鏈
  • 二是使用獨立工具鏈

一般來說,只要使用NDK自帶的工具鏈即可滿足日常的需求。本文就這種交叉編譯方式進行講解。

本文實例源碼github地址https://github.com/yngzMiao/yngzmiao-blogs/tree/master/2019Q4/20191219


前期準備

對於C++軟件工程師而言,如果需要進行交叉編譯,一般需要準備如下內容:

  • 下載好NDK、CMake
  • 已完成的C/C++文件
  • 已完成的CMakeList.txt文件

準備好這些就可以進行Android的交叉編譯了。

如果對CMakeList.txt不太熟悉,可以參考博文:【CMake】CMakeLists.txt的超傻瓜手把手教程(附實例源碼)

其實交叉編譯的步驟,和一般情況下CMake的編譯的步驟很類似:

mkdir build && cd build
cmake ..
make
make install

兩者之間的不同完全在於:編譯工具鏈的不同。而這個不同,體現在cmake ..的時候需要添加-D的編譯變量和參數。


編譯變量與參數

官方文檔地址:CMake | Android NDK | Android Developers

下表介紹在將CMake和NDK搭配使用時,可以配置的部分變量:

編譯參數 說明
ANDROID_PLATFORM 指定目標Android平臺的名稱,如android-18指定Android 4.3(API級別18)
ANDROID_STL 指定CMake應使用的STL,默認c++_static
ANDROID_PIE 指定是否使用位置獨立的可執行文件(PIE)。Android動態鏈接器在Android 4.1(API級別16)及更高級別上支持PIE,可設置爲On、OFF
ANDROID_CPP_FEATURES 指定CMake編譯原生庫時需使用的特定C++功能,可設置爲rtti(運行時類型信息)、exceptions(C++異常)
ANDROID_ALLOW_UNDEFINED_SYMBOLS 指定CMake在構建原生庫時,如果遇到未定義的引用,是否會引發未定義的符號錯誤。默認FALSE
ANDROID_ARM_NEON 指定CMake是否應構建支持NEON的原生庫。API級別爲23或更高級別時,默認值爲true,否則爲false
ANDROID_DISABLE_FORMAT_STRING_CHECKS 指定是否在編譯源代碼時保護格式字符串。啓用保護後,如果在printf樣式函數中使用非常量格式字符串,則編譯器會引發錯誤。默認false

下表介紹在Android進行交叉編譯時,可以使用的具體構建參數,將有助於調試CMake構建問題:

編譯參數 說明
ANDROID_ABI 目標ABI,可設置爲armeabi-v7a、arm64-v8a、x86、x86_64,默認armeabi
ANDROID_NDK 安裝的NDK根目錄的絕對路徑
CMAKE_TOOLCHAIN_FILE 進行交叉編譯的android.toolchain.cmake文件的路徑,默認在$NDK/build/cmake/目錄
ANDROID_TOOLCHAIN CMake使用的編譯器工具鏈,默認爲clang
CMAKE_BUILD_TYPE 配置構建類型,可設置爲Release、Debug
ANDROID_NATIVE_API_LEVEL CMake進行編譯的Android API級別
CMAKE_LIBRARY_OUTPUT_DIRECTORY 構建LIBRARY目標文件之後,CMake存放這些文件的位置

看着編譯的變量和參數都不少,那如何來抉擇呢?

其實,一般情況下,只需要配置ANDROID_ABIANDROID_NDKCMAKE_TOOLCHAIN_FILEANDROID_PLATFORM四個變量即可。

ANDROID_ABI是CPU架構,ANDROID_NDK是NDK的根目錄,CMAKE_TOOLCHAIN_FILE是工具鏈文件,ANDROID_PLATFORM是支持的最低Android平臺

爲什麼指定ANDROID_PLATFORM?如果不指定,Android平臺版本較低,此時ANDROID_PIE默認爲OFF,可執行程序無法執行。


實例

實例內容:編譯C++程序爲可執行文件,程序內容實現打印語句Hello World。

主程序內容特別簡單:

# include <iostream>

int main(int argc, char const *argv[])
{
  for(int i = 0; i < 5; ++i)
    std::cout << "Hello World" << std::endl;

  return 0;
}

編寫CMakeLists.txt:

cmake_minimum_required(VERSION 3.0)
project(main)

add_definitions("-Wall -g")

add_executable(${PROJECT_NAME} main.cpp )

install(TARGETS ${PROJECT_NAME}
  RUNTIME DESTINATION ${PROJECT_SOURCE_DIR})

編寫編譯腳本:

#/bin/bash

export ANDROID_NDK=/opt/env/android-ndk-r14b

rm -r build
mkdir build && cd build 

cmake -DCMAKE_TOOLCHAIN_FILE=$ANDROID_NDK/build/cmake/android.toolchain.cmake \
	-DANDROID_ABI="armeabi-v7a" \
	-DANDROID_NDK=$ANDROID_NDK \
	-DANDROID_PLATFORM=android-22 \
	..

make && make install

cd ..

此時會生成可執行文件main,push到Android設備上運行,可以看到Hello World的打印信息。


相關閱讀

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章