成人免费xxxxx在线视频软件_久久精品久久久_亚洲国产精品久久久_天天色天天色_亚洲人成一区_欧美一级欧美三级在线观看

Cmake基礎示例:如何編譯【跨平臺】的動態庫和應用程序

系統 Linux
這篇文章,主要是把視頻中的示例代碼進行簡化,只使用一個動態庫和一個可執行文件,使用cmake構建工具,演示在 Windows 和 Linux 這兩個平臺下的構建過程。

[[441811]]

大家好,我是道哥,今天我為大伙兒解說的技術知識點是:【使用 cmake 來構建跨平臺的動態庫和應用程序】。

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

視頻中的示例代碼是提前寫好的,因此重點就放在構建(Build)環節了。主要是介紹了動態庫與動態庫之間、應用程序與動態庫之間的引用等等。

對動態庫、靜態庫比較熟悉的小伙伴,應該很容易就能理解其中的內容。但是對 C 語言不熟悉的朋友,看起來還是有一點點障礙。

這篇文章,主要是把視頻中的示例代碼進行簡化,只使用一個動態庫和一個可執行文件,使用cmake構建工具,演示在 Windows 和 Linux 這兩個平臺下的構建過程。

本文的內容很基礎,算是使用 cmake 來構建跨平臺程序的入門教程吧!

示例代碼

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

  1. mylib:只有一個源文件,編譯輸出一個動態庫;
  2. myapp:也只有一個源文件,鏈接 mylib 動態庫,編譯輸出一個可執行程序;

mylib

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

  1. // mylib/mylib.h w文件 
  2.  
  3. #ifndef _MY_LIB_ 
  4. #define _MY_LIB_ 
  5.  
  6. #ifdef MY_LINUX 
  7.     #define MYLIB_API       extern 
  8. #else 
  9.     #ifdef MYLIB_EXPORT 
  10.         #define MYLIB_API   __declspec(dllexport) 
  11.     #else 
  12.         #define MYLIB_API   __declspec(dllimport) 
  13.     #endif 
  14. #endif 
  15.  
  16. MYLIB_API int my_add(int num1, int num2); 
  17. MYLIB_API int my_sub(int num1, int num2); 
  18.  
  19. #endif  // _MY_LIB_ 

以上這個代碼,主要是用在Windows系統的動態導出庫,在 Linux 系統中,不是必要的。

補充:在 windows 系統中,編譯動態庫時會生成 xxx.dll 和 xxx.lib。xxx.dll 中是真正的庫文件指令,xxx.lib 中僅僅是符號表。

具體來說:在 Windows 系統中,當編譯動態庫的時候,打開(定義)宏 MYLIB_EXPORT,下面這個宏生效:

  1. #define MYLIB_API   __declspec(dllexport) 

這樣的話,兩個函數 my_add 和 my_sub 的符號才可能被導出到 mylib.lib 文件中。

當這個動態庫被應用程序(myapp)使用的時候,myapp.c在 include mylib.h 的時,關閉宏 MYLIB_EXPORT,此時下面這個宏就生效:

  1. #define MYLIB_API   __declspec(dllimport) 

為了簡化宏定義的復雜度,這里就不考慮靜態庫了。

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

  1. // mylib/mylib.c 文件 
  2.  
  3. #include "mylib.h" 
  4.  
  5. int my_add(int num1, int num2) 
  6.     return (num1 + num2); 
  7.  
  8. int my_sub(int num1, int num2) 
  9.     return (num1 - num2); 

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

  1. // mylib/CMakeLists.txt 文件 
  2.  
  3. CMAKE_MINIMUM_REQUIRED(VERSION 3.5) 
  4. PROJECT(mylib VERSION 1.0.0) 
  5.  
  6. # 自定義宏,代碼中可以使用  
  7. ADD_DEFINITIONS(-DMYLIB_EXPORT) 
  8.  
  9. # 頭文件 
  10. INCLUDE_DIRECTORIES(./) 
  11.  
  12. # 源文件 
  13. FILE(GLOB MYLIB_SRCS "*.c"
  14.  
  15. # 編譯目標 
  16. ADD_LIBRARY(${PROJECT_NAME} SHARED ${MYLIB_SRCS}) 

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

注意其中的一點:ADD_DEFINITIONS(-DMYLIB_EXPORT),因為這個CMakeLists.txt是用來編譯動態庫的,因此在Windows平臺下,每一個導出符號的前面需要加上 __declspec(dllexport),因此需要打開宏定義:MYLIB_EXPORT。

myapp

應用程序的代碼就更簡單了,只有兩個文件:myapp.c 和 CMakeLists.txt,內容如下:

  1. // myapp/myapp.c 文件 
  2.  
  3. #include <stdio.h> 
  4. #include <stdlib.h> 
  5.  
  6. #include "mylib.h" 
  7.  
  8. int main(int argc, char *argv[]) 
  9.     int ret1, ret2; 
  10.     int a = 5; 
  11.     int b = 2; 
  12.      
  13.     ret1 = my_add(a, b); 
  14.     ret2 = my_sub(a, b); 
  15.     printf("ret1 = %d \n", ret1); 
  16.     printf("ret2 = %d \n", ret2); 
  17.     getchar(); 
  18.     return 0; 

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

  1. // myapp/CMakeLists.txt 文件 
  2.  
  3. CMAKE_MINIMUM_REQUIRED(VERSION 3.5) 
  4. PROJECT(myapp VERSION 1.0.0) 
  5.  
  6. # 頭文件路徑 
  7. INCLUDE_DIRECTORIES(./include) 
  8.  
  9. # 庫文件路徑 
  10. LINK_DIRECTORIES(./lib) 
  11.  
  12. # 源文件 
  13. FILE(GLOB MYAPP_SRCS "*.c"
  14.  
  15. # 編譯目標 
  16. ADD_EXECUTABLE(${PROJECT_NAME} ${MYAPP_SRCS}) 
  17.  
  18. # 依賴的動態庫 
  19. TARGET_LINK_LIBRARIES(${PROJECT_NAME} mylib) 

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

那么到哪個目錄下去查找相應的頭文件和庫文件呢?

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

  1. # 頭文件路徑 
  2. INCLUDE_DIRECTORIES(./include) 
  3.  
  4. # 庫文件路徑 
  5. LINK_DIRECTORIES(./lib) 

這個兩個目錄暫時還不存在,待會編譯的時候我們再手動創建。

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

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

  1. CMAKE_MINIMUM_REQUIRED(VERSION 3.5) 
  2. PROJECT(cmake_demo VERSION 1.0.0) 
  3.  
  4. SET(CMAKE_C_STANDARD 99) 
  5.  
  6. # 自定義宏,代碼中可以使用  
  7. if (CMAKE_HOST_UNIX) 
  8.     ADD_DEFINITIONS(-DMY_LINUX) 
  9. else () 
  10.     ADD_DEFINITIONS(-DMY_WINDOWS) 
  11. endif() 
  12.       
  13. ADD_SUBDIRECTORY(mylib) 
  14. ADD_SUBDIRECTORY(myapp) 

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

Linux 下構建過程

cmake 配置

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

  1. $ cd ~/tmp/cmake_demo/ 
  2. $ mkdir build 
  3. $ cd build/ 
  4. $ ls 
  5. $ cmake .. 

此時,在build目錄下,產生如下文件:

  1. CMakeCache.txt  CMakeFiles  cmake_install.cmake  Makefile  myapp  mylib 

make 編譯

我們可以分別進入mylib和myapp目錄,執行make指令來單獨編譯,也可以直接在build目錄下編譯所有的目標。

現在就直接在build目錄下編譯所有目標:

  1. $ cd ~/tmp/cmake_demo/build 
  2. $ make 
  3. Scanning dependencies of target mylib 
  4. [ 25%] Building C object mylib/CMakeFiles/mylib.dir/mylib.c.o 
  5. [ 50%] Linking C shared library libmylib.so 
  6. [ 50%] Built target mylib 
  7. Scanning dependencies of target myapp 
  8. [ 75%] Building C object myapp/CMakeFiles/myapp.dir/myapp.c.o 
  9. ~/tmp/cmake_demo/myapp/myapp.c:4:19: fatal error: mylib.h: 沒有那個文件或目錄 
  10.  #include "mylib.h" 
  11.                    ^ 
  12. compilation terminated. 
  13. myapp/CMakeFiles/myapp.dir/build.make:62: recipe for target 'myapp/CMakeFiles/myapp.dir/myapp.c.o' failed 
  14. make[2]: *** [myapp/CMakeFiles/myapp.dir/myapp.c.o] Error 1 
  15. CMakeFiles/Makefile2:140: recipe for target 'myapp/CMakeFiles/myapp.dir/all' failed 
  16. make[1]: *** [myapp/CMakeFiles/myapp.dir/all] Error 2 
  17. Makefile:83: recipe for target 'all' failed 
  18. make: *** [all] Error 2 

從提示信息中看出:已經編譯生成了 ./mylib/libmylib.so 文件,但是在編譯可執行程序 myapp 時遇到了錯誤:找不到 mylib.h 文件!

在剛才介紹myapp/CMakeLists.txt文件時說到:應用程序查找頭文件的目錄是 myapp/include, 查找庫文件的目錄是 myapp/lib。

但是這2個目錄以及相應的頭文件、庫文件都不存在!

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

  1. $ cd ~/tmp/cmake_demo/myapp/ 
  2. $ mkdir  include lib 
  3. $ cp ~/tmp/cmake_demo/mylib/mylib.h ./include/ 
  4. $ cp ~/tmp/cmake_demo/build/mylib/libmylib.so ./lib/ 

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

準備好頭文件和庫文件之后,再次編譯一下:

  1. $ cd ~/tmp/cmake_demo/build/ 
  2. $ make 
  3. [ 50%] Built target mylib 
  4. [ 75%] Building C object myapp/CMakeFiles/myapp.dir/myapp.c.o 
  5. [100%] Linking C executable myapp 
  6. [100%] Built target myapp 

此時,就在 build/myapp 目錄下生成可執行文件myapp了。

測試、執行

  1. $ cd ~/tmp/cmake_demo/build/myapp 
  2. $ ./myapp 
  3. ret1 = 7  
  4. ret2 = 3 

完美!

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

Windows 下構建過程

把Linux系統中的build文件夾刪除,然后把測試代碼壓縮,復制到Windows系統中繼續測試。

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

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

因為需要使用cmake工具來構建,所以需要在VSCode安裝 cmake 插件。(如何安裝 VSCode 插件就不贅述了)

第一步: cmake 配置

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

在第一次 Configure 的時候,會彈出下面的選項,來選擇編譯器:

我們這里選擇 64 位的 amd64。

配置的結果輸出在最下面窗口中的output標簽中,如下所示:

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

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

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

第二步: 編譯

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

按下 shift + F7,或者單擊VSCode底部的 Build 圖標:

彈出編譯目標列表:

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

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

mylib.dll 就是編譯得到的動態鏈接庫,mylib.lib是導入符號。

myapp.exe 是編譯得到的可執行程序。

第三步: 執行

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

提示錯誤:找不到動態鏈接庫!

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

完美!

但是,既然已經用VSCode來編譯了,那就繼續在VSCode中進行代碼調試吧。

按下調試快捷鍵 F5,第一次會彈出調試器選擇項:

選擇 LLDB,然后彈出錯誤對話框:

因為我們沒有提供相應的配置文件來告訴VSCode調試哪一個可執行程序。

單擊[OK]之后,VSCode 會自動為我們生成 .vscode/launcher.json 文件,內容如下:

把其中的program項目,改成可執行程序的全路徑:

  1. "program""F:/tmp/cmake_demo/build/myapp/Debug/myapp.exe" 

然后再次按下F5鍵,這回終于可以正確執行了:

此時,就可以在mylib.c或者myapp.c中設置斷點,然后進行單步調試程序了:

本文轉載自微信公眾號「IOT物聯網小鎮」

 

責任編輯:姜華 來源: IOT物聯網小鎮
相關推薦

2021-05-07 08:00:19

應用程序框架

2021-04-08 11:10:07

C語言版本Cmake

2023-10-29 09:13:56

GolangGo

2015-01-14 09:41:28

跨平臺移動應用Linux開發

2010-08-12 15:52:34

Flex應用程序

2023-02-10 14:54:20

編譯工具cmake

2013-10-31 10:44:54

IDE工具

2015-01-06 13:42:45

跨平臺開發APP工具

2020-09-23 14:33:01

Golang桌面開發GUI

2011-03-22 14:12:17

LAMP

2016-05-27 15:44:12

H5LeanCloudWex5

2021-05-21 07:59:40

應用程序設計動態庫函數

2009-07-21 15:14:32

預編譯應用程序ASP.NET

2022-12-22 08:01:09

Vue測試庫測試

2009-07-01 13:54:41

Servlet和JSP

2011-05-31 13:34:22

應用開發iPad

2010-02-01 10:43:10

C++跨平臺應用

2021-02-23 23:06:31

數據庫Redis技術

2023-10-30 10:34:20

Golang數據庫

2022-09-08 11:45:18

云計算多云IT
點贊
收藏

51CTO技術棧公眾號

主站蜘蛛池模板: 欧美综合视频在线 | 久草www | 午夜视频一区二区三区 | 精品国产欧美一区二区三区成人 | 久久久久久久久久久91 | 黑人精品欧美一区二区蜜桃 | 成人在线观看亚洲 | 亚洲欧美日韩电影 | 国产日韩久久久久69影院 | 国产精品一区二区不卡 | 国产精品久久久久久中文字 | 不卡一区 | 国产激情视频网址 | 欧美在线一区二区三区 | 午夜免费福利片 | 国产午夜精品一区二区三区四区 | 伊人久久麻豆 | 中文字幕一二三区 | 特黄色一级毛片 | 日本三级电影在线看 | 日韩在线观看中文字幕 | 国产成年人视频 | 日本不卡免费新一二三区 | 亚洲午夜av久久乱码 | 日本精品一区二区三区四区 | 成年人在线播放 | 一区二区蜜桃 | www.黄色在线观看 | 久久人人国产 | 91精品久久久久久久久中文字幕 | 狠狠插天天干 | 91欧美| 久久久综合网 | 蜜臀久久| 91丨九色丨国产在线 | 免费一级欧美在线观看视频 | 草久久久| 男人av在线| 岛国精品 | 精品国产精品一区二区夜夜嗨 | 青草青草久热精品视频在线观看 |