訂閱
糾錯(cuò)
加入自媒體

如何編譯【跨平臺】的動態(tài)庫和應(yīng)用程序

目錄

· 示例代碼

mylib

myapp

· Linux 下構(gòu)建過程

cmake 配置

make 編譯

編譯、執(zhí)行

· Windows 下構(gòu)建過程

cmake cofigure

build

調(diào)試

別人的經(jīng)驗(yàn),我們的階梯!

大家好,我是道哥,今天我為大伙兒解說的技術(shù)知識點(diǎn)是:【使用 cmake 來構(gòu)建跨平臺的動態(tài)庫和應(yīng)用程序】。

在很久之前,曾經(jīng)在B站上傳過幾個(gè)小視頻,介紹了在Windows和Linux這兩個(gè)平臺下,如何通過cmake和make這兩個(gè)構(gòu)建工具,來編譯、鏈接動態(tài)庫、靜態(tài)庫以及可執(zhí)行程序。

視頻中的示例代碼是提前寫好的,因此重點(diǎn)就放在構(gòu)建(Build)環(huán)節(jié)了。主要是介紹了動態(tài)庫與動態(tài)庫之間、應(yīng)用程序與動態(tài)庫之間的引用等等。

對動態(tài)庫、靜態(tài)庫比較熟悉的小伙伴,應(yīng)該很容易就能理解其中的內(nèi)容。但是對 C 語言不熟悉的朋友,看起來還是有一點(diǎn)點(diǎn)障礙。

這篇文章,主要是把視頻中的示例代碼進(jìn)行簡化,只使用一個(gè)動態(tài)庫和一個(gè)可執(zhí)行文件,使用cmake構(gòu)建工具,演示在 Windows 和 Linux 這兩個(gè)平臺下的構(gòu)建過程。

本文的內(nèi)容很基礎(chǔ),算是使用 cmake 來構(gòu)建跨平臺程序的入門教程吧!

示例代碼

首先看一下測試代碼的全貌:

mylib:只有一個(gè)源文件,編譯輸出一個(gè)動態(tài)庫;

myapp:也只有一個(gè)源文件,鏈接 mylib 動態(tài)庫,編譯輸出一個(gè)可執(zhí)行程序;

mylib

在mylib目錄中,一共有3個(gè)文件:mylib.h, mylib.c 以及 CMakeLists.txt,內(nèi)容分別如下:

image.png

以上這個(gè)代碼,主要是用在Windows系統(tǒng)的動態(tài)導(dǎo)出庫,在 Linux 系統(tǒng)中,不是必要的。

補(bǔ)充:在 windows 系統(tǒng)中,編譯動態(tài)庫時(shí)會生成 xxx.dll 和 xxx.lib。xxx.dll 中是真正的庫文件指令,xxx.lib 中僅僅是符號表。

具體來說:在 Windows 系統(tǒng)中,當(dāng)編譯動態(tài)庫的時(shí)候,打開(定義)宏 MYLIB_EXPORT,下面這個(gè)宏生效:

#define MYLIB_API __declspec(dllexport)

這樣的話,兩個(gè)函數(shù) my_add 和 my_sub 的符號才可能被導(dǎo)出到 mylib.lib 文件中。

當(dāng)這個(gè)動態(tài)庫被應(yīng)用程序(myapp)使用的時(shí)候,myapp.c在 include  mylib.h 的時(shí),關(guān)閉宏 MYLIB_EXPORT,此時(shí)下面這個(gè)宏就生效:

#define MYLIB_API __declspec(dllimport)

為了簡化宏定義的復(fù)雜度,這里就不考慮靜態(tài)庫了。

看完了頭文件,再來看看源文件mylib.c:

image.png

最后再來看一下mylib/CMakeLists.txt文件:

image.png

關(guān)于cmake的語法就不多說了,這里只用到了其中很少的一部分。

注意其中的一點(diǎn):ADD_DEFINITIONS(-DMYLIB_EXPORT),因?yàn)檫@個(gè)CMakeLists.txt是用來編譯動態(tài)庫的,因此在Windows平臺下,每一個(gè)導(dǎo)出符號的前面需要加上 __declspec(dllexport),因此需要打開宏定義:MYLIB_EXPORT。

myapp

應(yīng)用程序的代碼就更簡單了,只有兩個(gè)文件:myapp.c 和 CMakeLists.txt,內(nèi)容如下:

image.png

HelloWorld級別的代碼,不需要多解釋!CMakeLists.txt內(nèi)容如下:

image.png

最后一行 TARGET_LINK_LIBRARIES(${PROJECT_NAME} mylib) 說明要鏈接mylib這個(gè)動態(tài)庫。

那么到哪個(gè)目錄下去查找相應(yīng)的頭文件和庫文件呢?

通過這兩行來指定查找目錄:

image.png

這個(gè)兩個(gè)目錄暫時(shí)還不存在,待會編譯的時(shí)候我們再手動創(chuàng)建。

可以讓 mylib 在編譯時(shí)的輸出文件,自動拷貝到指定的目錄。但是為了不把問題復(fù)雜化,某些操作步驟通過手動操作來完成,這樣也能更清楚的理解其中的鏈接過程。

最后就剩下最外層的CMakeLists.txt文件了:

image.png

它所做的主要工作就是:根據(jù)不同的平臺,定義相應(yīng)的宏,并且添加了mylib和myapp這兩個(gè)子文件夾。

Linux 下構(gòu)建過程

cmake 配置

為了不污染源文件目錄,在最外層目錄下新建build目錄,然后執(zhí)行cmake指令:

image.png

此時(shí),在build目錄下,產(chǎn)生如下文件:

CMakeCache.txt  CMakeFiles  cmake_install.cmake  Makefile  myapp  mylib

make 編譯

我們可以分別進(jìn)入mylib和myapp目錄,執(zhí)行make指令來單獨(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: 沒有那個(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í)說到:應(yīng)用程序查找頭文件的目錄是 myapp/include, 查找?guī)煳募哪夸浭?myapp/lib。

但是這2個(gè)目錄以及相應(yīng)的頭文件、庫文件都不存在!

因此我們需要手動創(chuàng)建,并且把頭文件mylib.h和庫文件libmylib.so拷貝進(jìn)去,操作過程如下:

$ 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/

注意:剛才編譯生成的庫文件libmylib.so是在build目錄下。

準(zhǔn)備好頭文件和庫文件之后,再次編譯一下:

$ 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了。

測試、執(zhí)行

$ cd ~/tmp/cmake_demo/build/myapp

$ ./myapp

ret1 = 7

ret2 = 3

完美!

由于我們是在build目錄下編譯的,編譯過程中所有的輸出和中間文件,都放在build目錄下,一點(diǎn)都沒有污染源文件。

Windows 下構(gòu)建過程

把Linux系統(tǒng)中的build文件夾刪除,然后把測試代碼壓縮,復(fù)制到Windows系統(tǒng)中繼續(xù)測試。

在Windows下編譯,一般就很少使用命令行了,大部分都使用VS或者VSCode來編譯。

打開 VSCode,然后打開測試代碼文件夾 cmake_demo:

因?yàn)樾枰褂胏make工具來構(gòu)建,所以需要在VSCode安裝 cmake 插件。(如何安裝 VSCode 插件就不贅述了)

第一步: cmake 配置

按下鍵盤 ctrl + shift + p,在命令窗口中選擇 Cmake: Configure,如果沒看到這個(gè)選項(xiàng),就手動輸入前面的幾個(gè)字符,然后就可以智能匹配到:

在第一次 Configure 的時(shí)候,會彈出下面的選項(xiàng),來選擇編譯器:

我們這里選擇 64 位的 amd64。

配置的結(jié)果輸出在最下面窗口中的output標(biāo)簽中,如下所示:

這就表明cmake配置成功,正確的執(zhí)行了每一個(gè)文件夾下的 CMakeLists.txt 文件。

這個(gè)時(shí)候,來看一下資源管理器中有啥變化:自動生成了 build 目錄,其中的文件如下:

看來,流程與Linux系統(tǒng)中都是一樣的,只不過這里是VSCode主動幫我們做了一些事情。

第二步: 編譯

配置之后,下一步就是編譯了。

按下 shift + F7,或者單擊VSCode底部的 Build 圖標(biāo):

彈出編譯目標(biāo)列表:

這里選擇 ALL_BUILD,也就是編譯所有的目標(biāo):mylib 和 myapp,輸出如下:

來看一下編譯的輸出文件:

mylib.dll 就是編譯得到的動態(tài)鏈接庫,mylib.lib是導(dǎo)入符號。

myapp.exe 是編譯得到的可執(zhí)行程序。

第三步: 執(zhí)行

我們先在命令行窗口中執(zhí)行一下myapp.exe:

提示錯(cuò)誤:找不到動態(tài)鏈接庫!

手動把mylib.dll拷貝到myuapp.exe同一個(gè)目錄下,然后再執(zhí)行一次 myapp.exe:

完美!

但是,既然已經(jīng)用VSCode來編譯了,那就繼續(xù)在VSCode中進(jìn)行代碼調(diào)試吧。

按下調(diào)試快捷鍵 F5,第一次會彈出調(diào)試器選擇項(xiàng):

選擇 LLDB,然后彈出錯(cuò)誤對話框:

因?yàn)槲覀儧]有提供相應(yīng)的配置文件來告訴VSCode調(diào)試哪一個(gè)可執(zhí)行程序。

單擊[OK]之后,VSCode 會自動為我們生成 .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)試程序了:


聲明: 本文由入駐維科號的作者撰寫,觀點(diǎn)僅代表作者本人,不代表OFweek立場。如有侵權(quán)或其他問題,請聯(lián)系舉報(bào)。

發(fā)表評論

0條評論,0人參與

請輸入評論內(nèi)容...

請輸入評論/評論長度6~500個(gè)字

您提交的評論過于頻繁,請輸入驗(yàn)證碼繼續(xù)

  • 看不清,點(diǎn)擊換一張  刷新

暫無評論

暫無評論

    掃碼關(guān)注公眾號
    OFweek人工智能網(wǎng)
    獲取更多精彩內(nèi)容
    文章糾錯(cuò)
    x
    *文字標(biāo)題:
    *糾錯(cuò)內(nèi)容:
    聯(lián)系郵箱:
    *驗(yàn) 證 碼:

    粵公網(wǎng)安備 44030502002758號