用CMake代替makefile進行跨平臺交叉編譯
出處:http://www.cnblogs.com/wengzilin/p/4466708.html
在開始介紹如何使用CMake編譯跨平臺的靜態庫之前,先講講我在沒有使用CMake之前所趟過的坑。因為很多開源的程式,比如png,都是自帶編譯指令碼的。我們可以使用下列指令碼來進行編譯:
1 2 3 |
./configure --prefix=/xxx/xx --enable- static = YES
make
make install
|
相信手動在類Unix系統上面編譯過開源程式的同學對上面的命令肯定非常熟悉。更悲慘的是,有些開源庫是不提供configure配置檔案的,只有一個Makefile或者Makefile.gcc。我的體會是,Makefile是一個很複雜的東西,沒有一定的積累我們是看不懂的,更別說去修改它了。而本文的CMake可以更傻瓜更簡單地達到我們的目的,你不需要理會複雜的makefile語法。Just follow me!
如果不配置編譯器和一些編譯、連結引數,這樣的操作,最後編譯出來的靜態庫只能在本系統上面被連結使用。比如你在mac上面執行上面的命令,編譯出來的靜態庫就只能給mac程式連結使用。如果在Linux上面執行上述命令,則也只能給Linux上面的程式所連結使用。如果我們想要在Mac上面編譯出ios和android的靜態庫,就必須要用到交叉編譯。
要進行交叉編譯,一般來說要指定目標編譯平臺的編譯器,通常是指定一個CC環境變數,根據編譯的是c庫還是c++庫,要分別指定C_flags和CXX_flag,當然還需要指定c/c++和系統sdk的標頭檔案包含路徑。總之,非常之繁瑣。
為什麼要使用CMake
為什麼我們不使用autoconf?為什麼我們不使用QMake,JAM,ANT呢?具體原因大家可以參考我在本文最後的參考連結裡面的《Mastering CMake》一書的第一章。我自己使用CMake的感受就是:我原來編寫bash,配置configure引數,讀各個開源庫的INSTALL檔案(因為不同庫的configure引數有差別),配置各種編譯flag,標頭檔案包含等。最後3天時間,折騰了png和jepg兩個庫的編譯。當然,中間我還寫了android和linux的編譯指令碼。而換用CMake以後,我2天時間編譯完了Box2D,spine和Chipmunk的編譯。並且配置指令碼相當簡單,新增新的庫,基本上只是拷貝指令碼,修改一兩個引數即可。有了CMake,編譯跨平臺靜態庫和生成跨平臺可執行程式So Easy!
編寫CMakeLists.txt
編寫一個靜態庫的CMake配置檔案過程如下:(這裡我以Box2D為例)
1、指定標頭檔案和原始檔
1 2 3 4 5 |
include_directories(
${CMAKE_CURRENT_SOURCE_DIR}
)
file(GLOB_RECURSE box2d_source_files
"${CMAKE_CURRENT_SOURCE_DIR}/Box2D/*.cpp" )
|
我的CMakeLists.txt和Box2D的檔案結構關係如下圖所示:
這裡的${CMAKE_CURRENT_SOURCE_DIR}
表示CMakeLists.txt所在的目錄。而GLOB_RECURSE可以遞迴地去搜索Box2D目錄下面所有的.cpp檔案來參與靜態庫的編譯。而include_directories和file指令,顯而易見,它們是用來指定靜態庫的標頭檔案和實現檔案。
注:指定標頭檔案的原則是:可以多引入,但不能缺。交叉編譯本質也是編譯,因此基本的要求是語法沒問題,如果必要的標頭檔案缺少了自然編譯會失敗!所以,原則上可以把整個根目錄的標頭檔案都引入進去,不過這樣雖然省事,但是會導致生成的庫檔案體積過大,但是會更保險一些,比如:
1 2 3 4 5 |
include_directories(
"../../../myWindows"
"../../../" #很殘暴地引入了整個根目錄
"../../../include_windows"
)
|
2、新增環境變數(可選, added by 程式設計小翁, 部落格園)
1 |
add_definitions( -D_FILE_OFFSET_BITS=64 -D_LARGEFILE_SOURCE -D_REENTRANT -DENV_UNIX -DBREAK_HANDLER -DUNICODE -D_UNICODE)
|
如果需要判斷平臺,可以這麼寫:
1 2 3 4 |
IF(APPLE)
add_definitions(-DENV_MACOSX)
FIND_LIBRARY(COREFOUNDATION_LIBRARY CoreFoundation )
ENDIF(APPLE)
|
其中-D_FILE_OFFSET_BITS=64表示定義一個環境變數_FILE_OFFSET_BITS且值為64。新增環境變數用在什麼時候呢?我們常常可以在一些開源的專案工程程式碼中看到這樣的形式:
1 2 3 4 5 |
#ifdef _UNICODE
AString name = nameWindowToUnix2(fileName);
#else
const
char * name = nameWindowToUnix(fileName);
#endif
|
以上程式碼中_UNICODE就是環境變數,那像這種變數該通過什麼時候定義呢?一種是像上面一樣通過add_definitions寫我們的編譯指令碼CMakeLists.txt,另一種是新建一個.h檔案,寫在裡面然後引用。兩種方式完全等效,我在我的交叉編譯工程中實踐過。例如,上面的add_definitions可以轉化為:
1 2 3 4 5 6 7 |
#define FILE_OFFSET_BITS 64
#define _LARGEFILE_SOURCE 1
#define _REENTRANT 1
#define ENV_UNIX 1
#define BREAK_HANDLER 1
#define UNICODE 1
#define _UNICODE 1
|
3、設定庫的名字跟型別
1 |
add_library(Box2D STATIC ${box2d_source_files})
|
這裡add_library表示最終編譯為一個庫,static表示是靜態庫,如果想編譯動態庫,可以修改為shared. 至此,一個靜態庫的配置就完成了。當然,因為這個庫沒有包括其它外部的標頭檔案,所以會比較簡單。但這也遠比自己寫一個Makefile要簡單N倍,請記住這句話。
以上就是編寫一個CMakeLists.txt配置檔案的全部必要過程,一些更復雜的配置檔案可能會增加一些其他東西,不過以上部分是基本逃不掉的。只要包含以上步驟就能成功交叉編譯出目標平臺的庫檔案。下面是一個完整的CMakeLists.txt檔案示例(檔名不能改):
CMakeLists.txt完整示例編譯iOS靜態庫
我們有了配置完畢的CMakeLists.txt檔案,但不要以為這樣就萬事大吉了!不知道你發現了沒,上述內容並不涉及目標平臺的相關資訊,因此編譯出來的庫只能在執行該配置檔案的當前系統上使用。現在需要配合接下來的操作才能最終達到目的。
編譯iOS庫,一般要先使用cmake指令生成xcode工程,再用xcode工程執行編譯出靜態庫(也就是工程的product是靜態庫,而不是**.app)。插播一段MAC系統下cmake安裝與使用方法介紹:
MAC預設是沒有cmake指令的。要測試你的MAC是否已經裝過cmake,可以這樣做:開啟Terminal,輸入cmake --version,如果已經安裝,則會顯示具體的版本號;否則就是沒安裝或者沒配置成功。 1、從這裡http://mac.softpedia.com/get/Development/Compilers/CMake.shtml下載cmake.app,然後安裝到預設位置; 2、將cmake.app與terminal相連結。開啟terminal,輸入以下命令:export PATH=/Applications/CMake.app/Contents/bin:$PATH 3、配置成功。這次再輸入cmake就有效了。不過,以上鍊接只對本terminal視窗有效,一旦關閉或者其他新建的terminal同樣要再做一遍!
回到iOS交叉編譯上來,使用cmake命令生成xcode工程可以這麼做:
1 |
cmake -GXcode .
|
通過該命令可以生成一個project.xcodeproject工程。但是,上述命令並不包含任何關於iOS的資訊,因此該xcode工程只能用於MAC庫的編譯。不過我們可以藉助ios-cmake開源專案。 下載iOS_64.cmake這個toolchain檔案,然後使用下列命令來生成ios工程:
1 |
cmake -DCMAKE_TOOLCHAIN_FILE=iOS_64.cmake -DCMAKE_IOS_DEVELOPER_ROOT=/Applications/Xcode.app/Contents/Developer/Platforms/iPhoneOS.platform/Developer/ -DCMAKE_IOS_SDK_ROOT=/Applications/Xcode.app/Contents/Developer/Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS.sdk/
-GXcode .
|
這個過程很容易出錯,出錯了不要慌,根據terminal的提示大膽地更改iOS_64.cmake(記得提前備份)。我也是一步步除錯過來的,以下的iOS_64.cmake是我自己更改後的,SDK是iOS8.3,Xcode6.3,如果環境跟我一樣的話理論上說可以直接使用我的.cmake:
我的iOS_64.cmake如果上面的操作都沒錯,就會順利生成一個project.xcodeproject檔案,開啟後記得做下面幾件事情:
1、設定Product->Scheme->Edit Scheme為release模式
2、其他設定如圖:
設定完畢後,點選執行,就能生成.a靜態庫了。這時候,你可以使用下面的命令測試一下生成的靜態庫是否真的是iOS下的庫。
開啟terminal,cd到.a所在目錄,假設靜態庫名字為libMyLib.a,輸入: lipo -info libMyLib.a ,如果顯示 Architectures in the fat file: lib7z_C++_938.a are: armv7 arm64 就說明操作無誤了。然後,盡情享用你的靜態庫吧!
編譯linux靜態庫(含64位和32位)
編譯linux的靜態庫是非常簡單的,只需要安裝好cmake以後,執行以下命令即可:
1 2 |
cmake .
make
|
注意,如果是64位的系統,那麼這樣只能生成64位的靜態庫。想要編譯出32位的靜態庫,則必須要先安裝32位系統的編譯工具鏈。
1 2 3 4 |
sudo apt-get install libx32gcc-4.8-dev
sudo apt-get install libc6-dev-i386
sudo apt-get install lib32stdc++6
sudo apt-get install g++-multilib
|
然後,只需要指定cxx_flags為-m32即可,對應的CMake的寫法為:
1 |
set(CMAKE_CXX_FLAGS
"${CMAKE_CXX_FLAGS} -m32" )
|
最後用cmake生成makefile並make即可生成32位的靜態庫。
編譯mac靜態庫
這個比較簡單,直接Xcode -GXcode
,然後用xcodebuild命令即可。
編譯Andoird靜態庫
編譯android庫我們同樣可以引入一個toolchain檔案,這裡我是從android-cmake裡面下載的。 在使用這個toolchain檔案之前,我們先要使用ndk自帶的make-standalone-toolchain.sh指令碼來生成對應平臺的toolchain.這個指令碼位於你的NDK的路徑下面的buil/tools目錄下。
比如要生成arm平臺的toolchain,我們可以使用下列命令:
1 |
sh $ANDROID_NDK/build/tools/make-standalone-toolchain.sh --platform=android-$ANDROID_API_LEVEL --install-dir=./android-toolchain --system=darwin-x86_64 --ndk-dir=/Users/guanghui/AndroidDev/android-ndk-r9d/
--toolchain=arm-linux-androideabi-4.8
|
這裡的$ANDROID_NDK
為你的NDK的安裝路徑。這段命令可以生成arm的toolchain,最終可以編譯出armeabi和armeabi-v7a靜態庫。 如果想生成x86的toolchain,指需要使用下列命令:
1 |
sh $ANDROID_NDK/build/tools/make-standalone-toolchain.sh --platform=android-$ANDROID_API_LEVEL --install-dir=./android-toolchain-x86 --system=darwin-x86_64 --ndk-dir=/Users/guanghui/AndroidDev/android-ndk-r9d/
--toolchain=x86-4.8
|
1 2 3 |
export PATH=$PATH:./android-toolchain/bin
export ANDROID_STANDALONE_TOOLCHAIN=./android-toolchain
cmake -DCMAKE_TOOLCHAIN_FILE=../android.toolchain.cmake -DANDROID_ABI= "armeabi"
..
|
編譯Win32,wp8和winrt靜態庫
這裡直接使用cmake-gui生成對應的VS工程,然後再手動編譯即可。
關於Box2D完整的跨平臺編譯指令碼可以參考子龍山人Github
Reference:
以上內容除iOS部分比較多原創外,其他內容大部分轉自子龍山人bolg。
##THAT IS ALL.
=======================================
原創文章,轉載請註明 程式設計小翁@部落格園,郵件[email protected],微信Jilon,歡迎各位與我在C/C++/Objective-C/機器視覺等領域展開交流!
=======================================
相關推薦
用CMake代替makefile進行跨平臺交叉編譯
出處:http://www.cnblogs.com/wengzilin/p/4466708.html 在開始介紹如何使用CMake編譯跨平臺的靜態庫之前,先講講我在沒有使用CMake之前所趟過的坑。因為很多開源的程式,比如png,都是自帶編譯指令碼的。我們可以使用下列指令
setTimeout和setInterval解析,妙用setTimeout代替setInterval進行間歇呼叫
"在開發環境下,很少使用間歇呼叫(setInterval),原因是後一個間歇呼叫很可能在前一個間歇呼叫結束前啟動" 妙用setTimeout代替setInterval進行間歇呼叫如下 function func(){ /****執行程式碼****/
用Eclipse和GDB構建ARM交叉編譯和線上除錯環境
再次強調一次,GDB遠端除錯套件包括Host端的gdb和Target端的gdbserver,對於gdb,宿主機上發行版本自帶的PC版gdb是不能用的,它沒有目標架構(ARM)相關的除錯支援。所以我們應該使用gdb的原始碼,針對ARM平臺編譯一個(toolchain還是Host上的)特別的版本。當然,如果晶
Linux下用CMAKE及exvim進行STM32開發
最近有閒時,買了一個Jlink,老的Puppy聖誕版不支援,在http://www.minilinux.net/node/2583上下載了一個lina-1.1.iso 分享地址:http://pan.baidu.com/s/1dDwxZep,不到300M,可以開啟PAE,我
跨平臺交叉編譯FFmpeg庫(Android、IOS、S2L)
一、Android平臺 2. 修改FFmpeg的configure。由於編譯出來的動態庫檔名的版本號在.so之後(例如“libavcodec.so.5.100.1”),而android平臺不能識別這樣檔名,所以需要修改這種檔名。在configure檔案中找到下面
cmake 配置arm-linux-gcc 交叉編譯環境
If cmake(1) is invoked with the command line parameter-DCMAKE_TOOLCHAIN_FILE=path/to/file, the fi
在Linux平臺上使用Cmake進行交叉編譯替代嵌入式平臺所使用的Makefile
jm11.0kta1.2.zip解壓後的資料夾名為JMKTA。 JMKTA的目錄結構如下 . ├── bin │ ├── decoder.cfg │ ├── encoder_baseline.cfg │ ├── encoder.cfg │ ├── encoder_extended.cfg│
Unbuntu16.04上用CMake圖形介面交叉編譯樹莓派的OpenCV3.0
引言 最近有個科研課題需要在樹莓派上做一系列驗證,但是實驗的程式是依賴OpenCV庫的(最重要我們修改了庫原始碼),而在樹莓派上編譯OpenCV原始碼很費時間,因此我只好使用交叉編譯的方法來編譯源程式。剛開始我們覺著網上材料大片,這部分的問題應該不大。可到操刀
交叉編譯環境在root用戶下找不到arm-linux-gcc問題:
root GC 路徑 bashrc 問題 編譯 用戶 環境變量 重新 原因是:環境變量(交叉編譯路徑)可能是在普通用戶下添加的,所以在root用戶下創建的文件使用arm-linux-gcc編譯的時候,找不到arm-linux-gcc。 解決辦法:找個終端:sudo -s
Linux下實現進度條程式. 通過makefile進行編譯. 建議自主完成一個彩色的進度條.
Linux下用C語言完成一個彩色進度條 1.建一個Makefile檔案 2.vim Makefile test:test.c
解決用cmake編譯與opencv相關的工程出現的錯誤
利用cmake編譯opencv相關工程時會彈出對話方塊,提示錯誤,紅色提示cmake找不到opencvconfig.cmake之類。 原因:cmake的OpenCV_DIR路徑為空,新增相應的路徑即可(就是下面紅色的目錄樹,點開找到右面那裡填入路徑)。 解決方案:在OenCV_DIR處新增 .
win10下,原始碼編譯Clang/llvm.並在vscode用cmake管理專案
走了不少彎路。網上的資料很多都過時了,我今天(2018.11.11)搞了一天,終於成功的再vscode中只按下滑鼠就編譯出了一個llvm專案 第一步,下原始碼: 遵循https://clang.llvm.org/get_started.html的步驟下載原始碼,我只下了必須的llvm和cl
關於QT用CMake編譯
昨天剛到新公司,公司的程式碼都託管到伺服器上面,想在伺服器上面用QTCreate開發,編譯是不可能了,於是換成了Cmake編譯檔案。拋棄掉了pro檔案。 寫一個CMakeList檔案 project(windowsflags) cmake_minimum_requir
go跨平臺編譯(交叉編譯)
go語言支援直接編譯不同系統的可執行程式,例如可以直接在mac上可以直接編譯linux的執行程式 支援的環境變數 GOOS:目標可執行程式執行作業系統,支援 darwin,freebsd,linux,windowsGOARCH:目標可執行程式作業系統構架,包括 386,amd64,arm CGO_ENA
為何windows下用cmake編譯找不到Boost庫
問題描述: CMake Error at D:/CMake/CMake 2.8/share/cmake-2.8/Modules/FindBoost.cmake:910 (message): Unable to find the requeste
GDB arm-linux交叉編譯移植和使用方法(特別是對於正在執行的程式或者段錯誤的程式進行分析)
測試程式碼中的test1是用來定位堆疊段錯誤,Delay函式是用來定位程式阻塞,都可以用gdb定位出來,如下: (1)測試程式執行時首先會有個段錯誤:./gdbtest & [[email protected] user0]$ [65334.020000] pgd = c3e14000 [
如何通過xmake進行交叉編譯
xmake 提供了方便靈活的交叉編譯支援,大部分情況下,都不需要配置很複雜的toolchains字首,例如:arm-linux- 什麼的 只要這個toolchains目錄滿足如下結構(大部分的交叉工具鏈都是這個結構): /home/toolchains_
Mac下進行golang的交叉編譯
由於golang的出身,對於linux的支援是最好的,相應來說,Mac的支援也很不錯,對windows的支援是最差的。 進行交叉編譯最好是從原始碼開始編譯,而且在交叉編譯中是不支援cgo的,這點請注意。 1. 獲得golang的原始碼
linux驅動部分:交叉編譯驅動模組&模組驅動的相關操作&Makefile講解
根據下面的提醒,在自己電腦是的情況是:b1、模組整個操作流程 (1)載入模組:insmod globalfifo_zs_fzs.ko (2)檢視模組是否被載入:lsmod (3)檢視裝置號:cat /proc/devices (4)建立裝置節點:mknod /dev/
用arm-linux-gcc交叉編譯 openssl zlib curl
參考了大牛文章: 準備工作: 1. ubuntu 系統 2. 下載 arm-linux-gcc-4.3.2.tgz 放到 /opt cd /opt wget http://www.arm123.com.cn/linux/arm-linux-gcc-4.3.2.tgz