如何編譯【跨平臺(tái)】的動(dòng)態(tài)庫(kù)和應(yīng)用程序
目錄
· 示例代碼
mylib
myapp
· Linux 下構(gòu)建過(guò)程
cmake 配置
make 編譯
編譯、執(zhí)行
· Windows 下構(gòu)建過(guò)程
cmake cofigure
build
調(diào)試
別人的經(jīng)驗(yàn),我們的階梯!
大家好,我是道哥,今天我為大伙兒解說(shuō)的技術(shù)知識(shí)點(diǎn)是:【使用 cmake 來(lái)構(gòu)建跨平臺(tái)的動(dòng)態(tài)庫(kù)和應(yīng)用程序】。
在很久之前,曾經(jīng)在B站上傳過(guò)幾個(gè)小視頻,介紹了在Windows和Linux這兩個(gè)平臺(tái)下,如何通過(guò)cmake和make這兩個(gè)構(gòu)建工具,來(lái)編譯、鏈接動(dòng)態(tài)庫(kù)、靜態(tài)庫(kù)以及可執(zhí)行程序。
視頻中的示例代碼是提前寫好的,因此重點(diǎn)就放在構(gòu)建(Build)環(huán)節(jié)了。主要是介紹了動(dòng)態(tài)庫(kù)與動(dòng)態(tài)庫(kù)之間、應(yīng)用程序與動(dòng)態(tài)庫(kù)之間的引用等等。
對(duì)動(dòng)態(tài)庫(kù)、靜態(tài)庫(kù)比較熟悉的小伙伴,應(yīng)該很容易就能理解其中的內(nèi)容。但是對(duì) C 語(yǔ)言不熟悉的朋友,看起來(lái)還是有一點(diǎn)點(diǎn)障礙。
這篇文章,主要是把視頻中的示例代碼進(jìn)行簡(jiǎn)化,只使用一個(gè)動(dòng)態(tài)庫(kù)和一個(gè)可執(zhí)行文件,使用cmake構(gòu)建工具,演示在 Windows 和 Linux 這兩個(gè)平臺(tái)下的構(gòu)建過(guò)程。
本文的內(nèi)容很基礎(chǔ),算是使用 cmake 來(lái)構(gòu)建跨平臺(tái)程序的入門教程吧!
示例代碼
首先看一下測(cè)試代碼的全貌:
mylib:只有一個(gè)源文件,編譯輸出一個(gè)動(dòng)態(tài)庫(kù);
myapp:也只有一個(gè)源文件,鏈接 mylib 動(dòng)態(tài)庫(kù),編譯輸出一個(gè)可執(zhí)行程序;
mylib
在mylib目錄中,一共有3個(gè)文件:mylib.h, mylib.c 以及 CMakeLists.txt,內(nèi)容分別如下:
以上這個(gè)代碼,主要是用在Windows系統(tǒng)的動(dòng)態(tài)導(dǎo)出庫(kù),在 Linux 系統(tǒng)中,不是必要的。
補(bǔ)充:在 windows 系統(tǒng)中,編譯動(dòng)態(tài)庫(kù)時(shí)會(huì)生成 xxx.dll 和 xxx.lib。xxx.dll 中是真正的庫(kù)文件指令,xxx.lib 中僅僅是符號(hào)表。
具體來(lái)說(shuō):在 Windows 系統(tǒng)中,當(dāng)編譯動(dòng)態(tài)庫(kù)的時(shí)候,打開(定義)宏 MYLIB_EXPORT,下面這個(gè)宏生效:
#define MYLIB_API __declspec(dllexport)
這樣的話,兩個(gè)函數(shù) my_add 和 my_sub 的符號(hào)才可能被導(dǎo)出到 mylib.lib 文件中。
當(dāng)這個(gè)動(dòng)態(tài)庫(kù)被應(yīng)用程序(myapp)使用的時(shí)候,myapp.c在 include mylib.h 的時(shí),關(guān)閉宏 MYLIB_EXPORT,此時(shí)下面這個(gè)宏就生效:
#define MYLIB_API __declspec(dllimport)
為了簡(jiǎn)化宏定義的復(fù)雜度,這里就不考慮靜態(tài)庫(kù)了。
看完了頭文件,再來(lái)看看源文件mylib.c:
最后再來(lái)看一下mylib/CMakeLists.txt文件:
關(guān)于cmake的語(yǔ)法就不多說(shuō)了,這里只用到了其中很少的一部分。
注意其中的一點(diǎn):ADD_DEFINITIONS(-DMYLIB_EXPORT),因?yàn)檫@個(gè)CMakeLists.txt是用來(lái)編譯動(dòng)態(tài)庫(kù)的,因此在Windows平臺(tái)下,每一個(gè)導(dǎo)出符號(hào)的前面需要加上 __declspec(dllexport),因此需要打開宏定義:MYLIB_EXPORT。
myapp
應(yīng)用程序的代碼就更簡(jiǎn)單了,只有兩個(gè)文件:myapp.c 和 CMakeLists.txt,內(nèi)容如下:
HelloWorld級(jí)別的代碼,不需要多解釋!CMakeLists.txt內(nèi)容如下:
最后一行 TARGET_LINK_LIBRARIES(${PROJECT_NAME} mylib) 說(shuō)明要鏈接mylib這個(gè)動(dòng)態(tài)庫(kù)。
那么到哪個(gè)目錄下去查找相應(yīng)的頭文件和庫(kù)文件呢?
通過(guò)這兩行來(lái)指定查找目錄:
這個(gè)兩個(gè)目錄暫時(shí)還不存在,待會(huì)編譯的時(shí)候我們?cè)偈謩?dòng)創(chuàng)建。
可以讓 mylib 在編譯時(shí)的輸出文件,自動(dòng)拷貝到指定的目錄。但是為了不把問(wèn)題復(fù)雜化,某些操作步驟通過(guò)手動(dòng)操作來(lái)完成,這樣也能更清楚的理解其中的鏈接過(guò)程。
最后就剩下最外層的CMakeLists.txt文件了:
它所做的主要工作就是:根據(jù)不同的平臺(tái),定義相應(yīng)的宏,并且添加了mylib和myapp這兩個(gè)子文件夾。
Linux 下構(gòu)建過(guò)程
cmake 配置
為了不污染源文件目錄,在最外層目錄下新建build目錄,然后執(zhí)行cmake指令:
此時(shí),在build目錄下,產(chǎn)生如下文件:
CMakeCache.txt CMakeFiles cmake_install.cmake Makefile myapp mylib
make 編譯
我們可以分別進(jìn)入mylib和myapp目錄,執(zhí)行make指令來(lái)單獨(dú)編譯,也可以直接在build目錄下編譯所有的目標(biāo)。
現(xiàn)在就直接在build目錄下編譯所有目標(biāo):
$ cd ~/tmp/cmake_demo/build
$ make
Scanning dependencies of target mylib
[ 25%] Building C object mylib/CMakeFiles/mylib.dir/mylib.c.o
[ 50%] Linking C shared library libmylib.so
[ 50%] Built target mylib
Scanning dependencies of target myapp
[ 75%] Building C object myapp/CMakeFiles/myapp.dir/myapp.c.o
~/tmp/cmake_demo/myapp/myapp.c:4:19: fatal error: mylib.h: 沒(méi)有那個(gè)文件或目錄
#include "mylib.h"
^
compilation terminated.
myapp/CMakeFiles/myapp.dir/build.make:62: recipe for target 'myapp/CMakeFiles/myapp.dir/myapp.c.o' failed
make[2]: *** [myapp/CMakeFiles/myapp.dir/myapp.c.o] Error 1
CMakeFiles/Makefile2:140: recipe for target 'myapp/CMakeFiles/myapp.dir/all' failed
make[1]: *** [myapp/CMakeFiles/myapp.dir/all] Error 2
Makefile:83: recipe for target 'all' failed
make: *** [all] Error 2
從提示信息中看出:已經(jīng)編譯生成了 ./mylib/libmylib.so 文件,但是在編譯可執(zhí)行程序 myapp 時(shí)遇到了錯(cuò)誤:找不到 mylib.h 文件!
在剛才介紹myapp/CMakeLists.txt文件時(shí)說(shuō)到:應(yīng)用程序查找頭文件的目錄是 myapp/include, 查找?guī)煳募哪夸浭?myapp/lib。
但是這2個(gè)目錄以及相應(yīng)的頭文件、庫(kù)文件都不存在!
因此我們需要手動(dòng)創(chuàng)建,并且把頭文件mylib.h和庫(kù)文件libmylib.so拷貝進(jìn)去,操作過(guò)程如下:
$ cd ~/tmp/cmake_demo/myapp/
$ mkdir include lib
$ cp ~/tmp/cmake_demo/mylib/mylib.h ./include/
$ cp ~/tmp/cmake_demo/build/mylib/libmylib.so ./lib/
注意:剛才編譯生成的庫(kù)文件libmylib.so是在build目錄下。
準(zhǔn)備好頭文件和庫(kù)文件之后,再次編譯一下:
$ cd ~/tmp/cmake_demo/build/
$ make
[ 50%] Built target mylib
[ 75%] Building C object myapp/CMakeFiles/myapp.dir/myapp.c.o
[100%] Linking C executable myapp
[100%] Built target myapp
此時(shí),就在 build/myapp 目錄下生成可執(zhí)行文件myapp了。
測(cè)試、執(zhí)行
$ cd ~/tmp/cmake_demo/build/myapp
$ ./myapp
ret1 = 7
ret2 = 3
完美!
由于我們是在build目錄下編譯的,編譯過(guò)程中所有的輸出和中間文件,都放在build目錄下,一點(diǎn)都沒(méi)有污染源文件。
Windows 下構(gòu)建過(guò)程
把Linux系統(tǒng)中的build文件夾刪除,然后把測(cè)試代碼壓縮,復(fù)制到Windows系統(tǒng)中繼續(xù)測(cè)試。
在Windows下編譯,一般就很少使用命令行了,大部分都使用VS或者VSCode來(lái)編譯。
打開 VSCode,然后打開測(cè)試代碼文件夾 cmake_demo:
因?yàn)樾枰褂胏make工具來(lái)構(gòu)建,所以需要在VSCode安裝 cmake 插件。(如何安裝 VSCode 插件就不贅述了)
第一步: cmake 配置
按下鍵盤 ctrl + shift + p,在命令窗口中選擇 Cmake: Configure,如果沒(méi)看到這個(gè)選項(xiàng),就手動(dòng)輸入前面的幾個(gè)字符,然后就可以智能匹配到:
在第一次 Configure 的時(shí)候,會(huì)彈出下面的選項(xiàng),來(lái)選擇編譯器:
我們這里選擇 64 位的 amd64。
配置的結(jié)果輸出在最下面窗口中的output標(biāo)簽中,如下所示:
這就表明cmake配置成功,正確的執(zhí)行了每一個(gè)文件夾下的 CMakeLists.txt 文件。
這個(gè)時(shí)候,來(lái)看一下資源管理器中有啥變化:自動(dòng)生成了 build 目錄,其中的文件如下:
看來(lái),流程與Linux系統(tǒng)中都是一樣的,只不過(guò)這里是VSCode主動(dòng)幫我們做了一些事情。
第二步: 編譯
配置之后,下一步就是編譯了。
按下 shift + F7,或者單擊VSCode底部的 Build 圖標(biāo):
彈出編譯目標(biāo)列表:
這里選擇 ALL_BUILD,也就是編譯所有的目標(biāo):mylib 和 myapp,輸出如下:
來(lái)看一下編譯的輸出文件:
mylib.dll 就是編譯得到的動(dòng)態(tài)鏈接庫(kù),mylib.lib是導(dǎo)入符號(hào)。
myapp.exe 是編譯得到的可執(zhí)行程序。
第三步: 執(zhí)行
我們先在命令行窗口中執(zhí)行一下myapp.exe:
提示錯(cuò)誤:找不到動(dòng)態(tài)鏈接庫(kù)!
手動(dòng)把mylib.dll拷貝到myuapp.exe同一個(gè)目錄下,然后再執(zhí)行一次 myapp.exe:
完美!
但是,既然已經(jīng)用VSCode來(lái)編譯了,那就繼續(xù)在VSCode中進(jìn)行代碼調(diào)試吧。
按下調(diào)試快捷鍵 F5,第一次會(huì)彈出調(diào)試器選擇項(xiàng):
選擇 LLDB,然后彈出錯(cuò)誤對(duì)話框:
因?yàn)槲覀儧](méi)有提供相應(yīng)的配置文件來(lái)告訴VSCode調(diào)試哪一個(gè)可執(zhí)行程序。
單擊[OK]之后,VSCode 會(huì)自動(dòng)為我們生成 .vscode/launcher.json 文件,內(nèi)容如下:
把其中的program項(xiàng)目,改成可執(zhí)行程序的全路徑:
"program": "F:/tmp/cmake_demo/build/myapp/Debug/myapp.exe"
然后再次按下F5鍵,這回終于可以正確執(zhí)行了:
此時(shí),就可以在mylib.c或者myapp.c中設(shè)置斷點(diǎn),然后進(jìn)行單步調(diào)試程序了:
發(fā)表評(píng)論
請(qǐng)輸入評(píng)論內(nèi)容...
請(qǐng)輸入評(píng)論/評(píng)論長(zhǎng)度6~500個(gè)字
最新活動(dòng)更多
-
即日-11.13立即報(bào)名>>> 【在線會(huì)議】多物理場(chǎng)仿真助跑新能源汽車
-
11月28日立即報(bào)名>>> 2024工程師系列—工業(yè)電子技術(shù)在線會(huì)議
-
12月19日立即報(bào)名>> 【線下會(huì)議】OFweek 2024(第九屆)物聯(lián)網(wǎng)產(chǎn)業(yè)大會(huì)
-
即日-12.26火熱報(bào)名中>> OFweek2024中國(guó)智造CIO在線峰會(huì)
-
即日-2025.8.1立即下載>> 《2024智能制造產(chǎn)業(yè)高端化、智能化、綠色化發(fā)展藍(lán)皮書》
-
精彩回顧立即查看>> 【限時(shí)免費(fèi)下載】TE暖通空調(diào)系統(tǒng)高效可靠的組件解決方案
推薦專題
- 1 【一周車話】沒(méi)有方向盤和踏板的車,你敢坐嗎?
- 2 特斯拉發(fā)布無(wú)人駕駛車,還未迎來(lái)“Chatgpt時(shí)刻”
- 3 特斯拉股價(jià)大跌15%:Robotaxi離落地還差一個(gè)蘿卜快跑
- 4 馬斯克給的“驚喜”夠嗎?
- 5 打完“價(jià)格戰(zhàn)”,大模型還要比什么?
- 6 馬斯克致敬“國(guó)產(chǎn)蘿卜”?
- 7 神經(jīng)網(wǎng)絡(luò),誰(shuí)是盈利最強(qiáng)企業(yè)?
- 8 比蘋果偉大100倍!真正改寫人類歷史的智能產(chǎn)品降臨
- 9 諾獎(jiǎng)進(jìn)入“AI時(shí)代”,人類何去何從?
- 10 Open AI融資后成萬(wàn)億獨(dú)角獸,AI人才之爭(zhēng)開啟
- 高級(jí)軟件工程師 廣東省/深圳市
- 自動(dòng)化高級(jí)工程師 廣東省/深圳市
- 光器件研發(fā)工程師 福建省/福州市
- 銷售總監(jiān)(光器件) 北京市/海淀區(qū)
- 激光器高級(jí)銷售經(jīng)理 上海市/虹口區(qū)
- 光器件物理工程師 北京市/海淀區(qū)
- 激光研發(fā)工程師 北京市/昌平區(qū)
- 技術(shù)專家 廣東省/江門市
- 封裝工程師 北京市/海淀區(qū)
- 結(jié)構(gòu)工程師 廣東省/深圳市