日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

.so 依赖目录 cmake_CMAKE最全实战(2)

發布時間:2024/1/23 编程问答 31 豆豆
生活随笔 收集整理的這篇文章主要介紹了 .so 依赖目录 cmake_CMAKE最全实战(2) 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

閱讀本篇文章前,請閱讀CMAKE最全實戰(1),這2篇是有關聯。

1.靜態庫與動態庫構建

從本節開始,我們不再折騰Hello World 了,我們來折騰Hello World 的共享庫。

本節的任務:

1.建??個靜態庫和動態庫,提供HelloFunc 函數供其他程序編程使?,HelloFunc向終端輸出Hello World 字符串。

2.安裝頭?件與共享庫。

準備?

在cmake ?錄建? t3 ?錄,?于存放本節涉及到的?程

建?共享庫

cd make/t3

mkdir lib

在 t3 ?錄下建?CMakeLists.txt,內容如下:

PROJECT(HELLOLIB)

ADD_SUBDIRECTORY(lib)

在 lib ?錄下建?兩個源?件hello.c 與hello.h

hello.c 內容如下:

#include "hello.h"void hello_func(void) {printf("Hello World!");return;}

hello.h 內容如下:

#ifndef HELLO_H_#define HELLO_H_ (1)#include void hello_func(void);#endif

在 lib ?錄下建?CMakeLists.txt,內容如下:

SET(LIBHELLO_SRC hello.c)

ADD_LIBRARY(hello SHARED ${LIBHELLO_SRC})

編譯共享庫

仍然采?out-of-source 編譯的?式,按照習慣,我們建??個build ?錄,在build?錄中

cmake ..

make

這時,你就可以在lib ?錄得到?個libhello.so,這就是我們期望的共享庫。如果你要指定libhello.so ?成的位置,可以通過在主?程?件CMakeLists.txt 中修改 ADD_SUBDIRECTORY(lib)指令來指定?個編譯輸出位置或者在lib/CMakeLists.txt 中添加SET(LIBRARY_OUTPUT_PATH )來指定?個新的位置。

這兩者的區別CMAKE最全實戰(1) 已經提到了,所以,這?不再贅述,下?,我們解釋?下?個新的指令

ADD_LIBRARY

ADD_LIBRARY(libname [SHARED|STATIC|MODULE] [EXCLUDE_FROM_ALL]

source1 source2 ... sourceN)

不需要寫全libhello.so,只需要填寫hello 即可,cmake 系統會?動為你?成 libhello.X。

類型有三種:

SHARED,動態庫

STATIC,靜態庫

MODULE,在使? dyld 的系統有效,如果不?持dyld,則被當作SHARED 對待。

EXCLUDE_FROM_ALL 參數的意思是這個庫不會被默認構建,除?有其他的組件依賴或者??構建。

添加靜態庫

同樣使?上?的指令,我們在?持動態庫的基礎上再為?程添加?個靜態庫,按照?般的習慣,靜態庫名字跟動態庫名字應該是?致的,只不過后綴是.a 罷了。

下?我們?這個指令再來添加靜態庫:

ADD_LIBRARY(hello STATIC ${LIBHELLO_SRC})

然后再在build ?錄進?外部編譯,我們會發現,靜態庫根本沒有被構建,仍然只?成了?個動態庫。因為hello 作為?個target 是不能重名的,所以,靜態庫構建指令?效。

如果我們把上?的hello 修改為hello_static:

ADD_LIBRARY(hello_static STATIC ${LIBHELLO_SRC})

就可以構建?個libhello_static.a 的靜態庫了。

這種結果顯示不是我們想要的,我們需要的是名字相同的靜態庫和動態庫,因為 target 名稱是唯?的,所以,我們肯定不能通過 ADD_LIBRARY 指令來實現了。這時候我們需要?到另外?個指令:

SET_TARGET_PROPERTIES,其基本語法是:

SET_TARGET_PROPERTIES(target1 target2 ...

PROPERTIES prop1 value1

prop2 value2 ...)

這條指令可以?來設置輸出的名稱,對于動態庫,還可以?來指定動態庫版本和 API 版本。

在本例中,我們需要作的是向lib/CMakeLists.txt 中添加?條:

SET_TARGET_PROPERTIES(hello_static PROPERTIES OUTPUT_NAME "hello") 這樣,我們就可以同時得到libhello.so/libhello.a 兩個庫了

與他對應的指令是:

GET_TARGET_PROPERTY(VAR target property)

具體?法如下例,我們向lib/CMakeListst.txt 中添加:

GET_TARGET_PROPERTY(OUTPUT_VALUE hello_static OUTPUT_NAME)

MESSAGE(STATUS “This is the hello_static OUTPUT_NAME:”${OUTPUT_VALUE})

如果沒有這個屬性定義,則返回NOTFOUND。

讓我們來檢查?下最終的構建結果,我們發現,libhello.a 已經構建完成,位于 build/lib ?錄中,但是libhello.so 去消失了。這個問題的原因是:cmake 在構建?個新的target 時,會嘗試清理掉其他使?這個名字的庫,因為,在構建libhello.a 時,就會清理掉libhello.so.

為了回避這個問題,?如再次使?SET_TARGET_PROPERTIES 定CLEAN_DIRECT_OUTPUT 屬性。

向 lib/CMakeLists.txt 中添加:

SET_TARGET_PROPERTIES(hello PROPERTIES CLEAN_DIRECT_OUTPUT 1)

SET_TARGET_PROPERTIES(hello_static PROPERTIES CLEAN_DIRECT_OUTPUT 1)

這時候,我們再次進?構建,會發現build/lib ?錄中同時?成了libhello.so 和 libhello.a

動態庫版本號

按照規則,動態庫是應該包含?個版本號的,我們可以看?下系統的動態庫,?般情況是

libhello.so.1.2

libhello.so ->libhello.so.1

libhello.so.1->libhello.so.1.2

為了實現動態庫版本號,我們仍然需要使? SET_TARGET_PROPERTIES 指令

具體使??法如下:

SET_TARGET_PROPERTIES(hello PROPERTIES VERSION 1.2 SOVERSION 1) VERSION 指代動態庫版本,SOVERSION 指代 API 版本。

將上述指令加?lib/CMakeLists.txt 中,重新構建看看結果。

在 build/lib ?錄會?成: libhello.so.1.2 libhello.so.1->libhello.so.1.2 libhello.so ->libhello.so.1

安裝共享庫和頭?件

需要將libhello.a, libhello.so.x 以及 hello.h 安裝到系統?錄,才能真正讓其他?開發 使 ? , 在 本 例 中 我 們 將 hello 的 共 享 庫 安 裝 到 /lib ? 錄 , 將 hello.h 安 裝 到/include/hello ?錄。

利?CMAKE最全實戰(1) 了解到的INSTALL 指令,我們向lib/CMakeLists.txt 中添加如下指令:

INSTALL(TARGETS hello hello_static

LIBRARY DESTINATION lib

ARCHIVE DESTINATION lib)

INSTALL(FILES hello.h DESTINATION include/hello)

注意,靜態庫要使?ARCHIVE 關鍵字

通過:

cmake -DCMAKE_INSTALL_PREFIX=/usr ..

make

make install

可以將頭?件和共享庫安裝到系統?錄/usr/lib 和/usr/include/hello 中了

如果報錯

CMake Error: cmake_symlink_library: System Error: Operation not supported

CMake Error: cmake_symlink_library: System Error: Operation not supported

make[2]: *** [lib/CMakeFiles/hello_dynamic.dir/build.make:85: lib/libhello.so.1.2] Error 1

make[2]: *** Deleting file 'lib/libhello.so.1.2'

make[1]: *** [CMakeFiles/Makefile2:130: lib/CMakeFiles/hello_dynamic.dir/all] Error 2

make: *** [Makefile:130: all] Error 2

則說明你你可能是通過hgfs共享的Windows?錄下進?make,?成so時需要在純linux環境運?,?如把t3拷?到~/0/makefile/t3, 并且先把對應的build?錄??的內容清空,重新cmake .. 再make

本?節,我們談到了:如何通過ADD_LIBRARY 指令構建動態庫和靜態庫。如何通過SET_TARGET_PROPERTIES 同時構建同名的動態庫和靜態庫。如何通過SET_TARGET_PROPERTIES 控制動態庫版本最終使?上?節談到的INSTALL 指令來安裝頭?件和動態、靜態庫。在下?節,我們需要編寫另?個?級?點的 Hello World 來演示怎么使?我們已經構建的構建的共享庫libhello 和外部頭?件。

如何使?外部共享庫和頭?件

上?節我們已經完成了libhello 動態庫的構建以及安裝,本節我們的任務很簡單。編寫?個程序使?我們上?節構建的共享庫。

請在cmake ?錄建? t4 ?錄,本節所有資源將存儲在t4 ?錄。

構建?程

重復以前的步驟,建?src ?錄,編寫源?件main.c,內容如下:

#include "hello.h"

int main(void) {

hello_func();

return 0;

}

編寫?程主?件CMakeLists.txt

PROJECT(NEWHELLO)

ADD_SUBDIRECTORY(src)

編寫src/CMakeLists.txt

ADD_EXECUTABLE(main main.c)

外部構建

按照習慣,仍然建?build ?錄,使? cmake ..?式構建。

cmake ..

make

構建失敗,如果需要查看細節,可以使?第?節提到的?法

make VERBOSE=1 來構建

錯誤輸出為是:

cmake/t4/src/main.c:1:19: error: hello.h: 沒有那個?件或?錄

引?頭?件搜索路徑

假如hello.h 位于/usr/include/hello ?錄中,并沒有位于系統標準的頭?件路徑。

為了讓我們的?程能夠找到hello.h 頭?件,我們需要引??個新的指令。

INCLUDE_DIRECTORIES,其完整語法為:

INCLUDE_DIRECTORIES([AFTER|BEFORE] [SYSTEM] dir1 dir2 ...)

這條指令可以?來向?程添加多個特定的頭?件搜索路徑,路徑之間?空格分割,如果路徑中包含了空格,可以使?雙引號將它括起來,默認的?為是追加到當前的頭?件搜索路徑的后?,你可以通過兩種?式來進?控制搜索路徑添加的?式:

(1)CMAKE_INCLUDE_DIRECTORIES_BEFORE,通過SET 這個cmake 變量為on,可以將添加的頭?件搜索路徑放在已有路徑的前?

(2)通過AFTER 或者BEFORE 參數,也可以控制是追加還是置前

現在我們在src/CMakeLists.txt 中添加?個頭?件搜索路徑,?式很簡單,加?:

INCLUDE_DIRECTORIES(/usr/include/hello)

進?build ?錄,重新進?構建,這是找不到 hello.h 的錯誤已經消失,但是出現了?個新的錯誤:

main.c:(.text+0x12): undefined reference to `HelloFunc'

因為我們并沒有link 到共享庫libhello 上。

為 target 添加共享庫

現在需要完成的任務是將?標?件鏈接到 libhello,這?我們需要引?兩個新的指令:

LINK_DIRECTORIES 和TARGET_LINK_LIBRARIES

LINK_DIRECTORIES 的全部語法是:

LINK_DIRECTORIES(directory1 directory2 ...)

這個指令?常簡單,添加?標準的共享庫搜索路徑,?如,在?程內部同時存在共享庫和可執??進制,在編譯時就需要指定?下這些共享庫的路徑。這個例?中我們沒有?到這個指令。

TARGETLINKLIBRARIES 的全部語法:

TARGET_LINK_LIBRARIES(target library1

library2

...)

這個指令可以?來為target 添加需要鏈接的共享庫,本例中是?個可執??件,但是同樣可以?于為??編寫的共享庫添加共享庫鏈接。為了解決我們前?遇到的HelloFunc 未定義錯誤,我們需要作的是向 src/CMakeLists.txt 中添加如下指令:

TARGET_LINK_LIBRARIES(main hello)

也可以寫成

TARGET_LINK_LIBRARIES(main libhello.so)

hello 指的是我們上?節構建的共享庫 libhello,進?build ?錄重新進?構建。

cmake ..

make

得到了?個連接到libhello 的可執?程序main,位于build/bin?錄,運? main 的結果是輸出:

Hello World

檢查?下main 的鏈接情況:

ldd bin/main

可以清楚的看到main 確實鏈接了共享庫libhello,?且鏈接的是動態庫 libhello.so.1。

如何鏈接到靜態庫呢?

?法很簡單:

將 TARGET_LINK_LIBRRARIES 指令修改為: TARGET_LINK_LIBRARIES(main libhello.a)

重新構建后再來看?下main 的鏈接情況。說明,main 確實鏈接到了靜態庫libhello.a。

ldd src/main

特殊的環境變量CMAKE_INCLUDE_PATH 和CMAKE_LIBRARY_PATH。

注意,這兩個是環境變量?不是cmake 變量。

CMAKE_INCLUDE_PATH=/home/include cmake ..等?式。這兩個變量主要是?來解決以前autotools ?程中--extra-include-dir 等參數的?持的。

也就是,如果頭?件沒有存放在常規路徑(/usr/include, /usr/local/include 等),則可以通過這些變量就?彌補。以本例中的hello.h 為例,它存放在/usr/include/hello ?錄,所以直接查找肯定是找不到的。使?了絕對路徑INCLUDE_DIRECTORIES(/usr/include/hello)告訴?程這個頭?件?錄。

為了將程序更智能?點,我們可以使? CMAKE_INCLUDE_PATH 來進?,使?bash 的?法如下:

export CMAKE_INCLUDE_PATH=/usr/include/hello

在頭?件中將INCLUDE_DIRECTORIES(/usr/include/hello)替換為:

上述的?些指令我們在后?會介紹。

這?簡單說明?下,FIND_PATH ?來在指定路徑中搜索?件名,?如:

FIND_PATH(myHeader NAMES hello.h PATHS /usr/include /usr/include/hello)

這?我們沒有指定路徑,但是,cmake 仍然可以幫我們找到hello.h 存放的路徑,就是因為我們設置了環境變量CMAKE_INCLUDE_PATH。如果你不使?FIND_PATH,CMAKE_INCLUDE_PATH 變量的設置是沒有作?的,你不能指望它會直接為編譯器命令添加參數-I。

以此為例,CMAKE_LIBRARY_PATH 可以?在 FIND_LIBRARY 中。同樣,因為這些變量直接為FIND_指令所使?,所以所有使?FIND_指令的cmake 模塊都會受益。

如何通過INCLUDE_DIRECTORIES 指令加??標準的頭?件搜索路徑。

如何通過LINK_DIRECTORIES 指令加??標準的庫?件搜索路徑。

如果通過TARGET_LINK_LIBRARIES 為庫或可執??進制加?庫鏈接。

并解釋了如果鏈接到靜態庫。到這?為?,您應該基本可以使?cmake ?作了,但是還有很多?級的話題沒有探討,?如編譯條件檢查、編譯器定義、平臺判斷、如何跟 pkgconfig 配合使?等等。到這?,或許你可以理解前?講到的“cmake 的使?過程其實就是學習cmake 語?并編寫 cmake 程序的過程”,既然是“cmake 語?”,?然涉及到變量、語法等.

下?節,我們將拋開程序的話題,看看常?的 CMAKE 變量以及?些基本的控制語法規則。

cmake 常?變量和常?環境變量

cmake 變量引?的?式

使?${}進?變量的引?。在IF 等語句中,是直接使?變量名?不通過${}取值。主要有隱式定義和顯式定義兩種,前?舉了?個隱式定義的例?,就是 PROJECT 指令,他會隱式的定義_BINARY_DIR 和_SOURCE_DIR 兩個變量。顯式定義的例?我們前?也提到了,使? SET 指令,就可以構建?個?定義變量了。

?如:

SET(HELLO_SRC main.c),就PROJECT_BINARY_DIR 可以通過${HELLO_SRC}來引?這個?定義變量了。

cmake 常?變量

(1)CMAKE_BINARY_DIR

PROJECT_BINARY_DIR

_BINARY_DIR

這三個變量指代的內容是?致的,如果是 in source 編譯,指得就是?程頂層?錄,如果是 out-ofsource 編譯,指的是?程編譯發?的?錄。PROJECT_BINARY_DIR 跟其他指令稍有區別,現在,你可以理解為他們是?致的。

(2)CMAKE_SOURCE_DIR

PROJECT_SOURCE_DIR

_SOURCE_DIR

這三個變量指代的內容是?致的,不論采?何種編譯?式,都是?程頂層?錄。也就是在in source 編譯時,他跟 CMAKE_BINARY_DIR 等變量?致。PROJECT_SOURCE_DIR 跟其他指令稍有區別,現在,你可以理解為他們是?致的。

(3)CMAKE_CURRENT_SOURCE_DIR

指的是當前處理的CMakeLists.txt 所在的路徑,?如上?我們提到的 src ??錄。

(4)CMAKE_CURRRENT_BINARY_DIR

如果是in-source 編譯,它跟 CMAKE_CURRENT_SOURCE_DIR ?致,如果是out-of-source 編譯,它指的是target 編譯?錄。

使?上?提到的ADD_SUBDIRECTORY(src bin)可以更改這個變量的值。使?SET(EXECUTABLE_OUTPUT_PATH )并不會對這個變量造成影響,它僅僅修改了最終?標?件存放的路徑。

(5)CMAKE_CURRENT_LIST_FILE

輸出調?這個變量的CMakeLists.txt 的完整路徑

(6)CMAKE_CURRENT_LIST_LINE

輸出這個變量所在的?

(7)CMAKE_MODULE_PATH

這個變量?來定義??的cmake 模塊所在的路徑。如果你的?程?較復雜,有可能會??編寫?些cmake模塊,這些cmake 模塊是隨你的?程發布的,為了讓cmake 在處理 CMakeLists.txt 時找到這些模塊,你需要通過SET 指令,將??的cmake 模塊路徑設置?下。?如

SET(CMAKE_MODULE_PATH ${PROJECT_SOURCE_DIR}/cmake)

這時候你就可以通過INCLUDE 指令來調???的模塊了。

(8)EXECUTABLE_OUTPUT_PATH 和 LIBRARY_OUTPUT_PATH

分別?來重新定義最終結果的存放?錄,前?我們已經提到了這兩個變量。

(9)PROJECT_NAME

返回通過PROJECT 指令定義的項?名稱。

cmake 調?環境變量的?式

使?$ENV{NAME}指令就可以調?系統的環境變量了。

?如

MESSAGE(STATUS “HOME dir: $ENV{HOME}”)

設置環境變量的?式是:

SET(ENV{變量名} 值)

(1)CMAKE_INCLUDE_CURRENT_DIR

?動添加CMAKE_CURRENT_BINARY_DIR 和CMAKE_CURRENT_SOURCE_DIR 到當前處理的 CMakeLists.txt。相當于在每個CMakeLists.txt 加?:

(2)CMAKE_INCLUDE_DIRECTORIES_PROJECT_BEFORE

將?程提供的頭?件?錄始終?于系統頭?件?錄的前?,當你定義的頭?件確實跟系統發?沖突時可以提供?些幫助。

(3)CMAKE_INCLUDE_PATH 和 CMAKE_LIBRARY_PATH 我們在上?節已經提及。

系統信息

(1)CMAKE_MAJOR_VERSION,CMAKE 主版本號,?如2.4.6 中的2

(2)CMAKE_MINOR_VERSION,CMAKE 次版本號,?如2.4.6 中的4

(3)CMAKE_PATCH_VERSION,CMAKE 補丁等級,?如2.4.6 中的6

(4)CMAKE_SYSTEM,系統名稱,?如Linux-2.6.22

(5)CMAKE_SYSTEM_NAME,不包含版本的系統名,?如Linux

(6)CMAKE_SYSTEM_VERSION,系統版本,?如 2.6.22

(7)CMAKE_SYSTEM_PROCESSOR,處理器名稱,?如i686。

(8)UNIX,在所有的類 UNIX 平臺為 TRUE,包括OS X 和cygwin

(9)WIN32,在所有的 win32 平臺為 TRUE,包括cygwin

主要的開關選項

(1)CMAKE_ALLOW_LOOSE_LOOP_CONSTRUCTS,?來控制IF ELSE 語句的書寫?式,在下?節語法部分會講到。

(2)BUILD_SHARED_LIBS。這個開關?來控制默認的庫編譯?式,如果不進?設置,使? ADD_LIBRARY 并沒有指定庫類型的情況下,默認編譯?成的庫都是靜態庫。如果SET(BUILD_SHARED_LIBS ON)后,默認?成的為動態庫。

(3)CMAKE_C_FLAGS

設置C 編譯選項,也可以通過指令 ADD_DEFINITIONS()添加。

(4)CMAKE_CXX_FLAGS

設置C++編譯選項,也可以通過指令 ADD_DEFINITIONS()添加。

本篇就介紹到這里,歡迎關注、點贊、分享、收藏

總結

以上是生活随笔為你收集整理的.so 依赖目录 cmake_CMAKE最全实战(2)的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。