1. 程式人生 > >用CMake代替makefile進行跨平臺交叉編譯

用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.並在vscodecmake管理專案

走了不少彎路。網上的資料很多都過時了,我今天(2018.11.11)搞了一天,終於成功的再vscode中只按下滑鼠就編譯出了一個llvm專案   第一步,下原始碼: 遵循https://clang.llvm.org/get_started.html的步驟下載原始碼,我只下了必須的llvm和cl

關於QTCMake編譯

    昨天剛到新公司,公司的程式碼都託管到伺服器上面,想在伺服器上面用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