術語對照表:
參數 - option
選項 - flag算法
在編譯和連接時,提供必要的庫文件細節。元數據存儲在 pkg-config 文件裏面,文件後綴 .pc
,文件須要存放在 pkg-config 工具可以找到的特定位置。工具
文件內容包括預約義的元數據關鍵詞和形式自由的變量。
示例內容以下:ui
prefix=/usr/local exec_prefix=${prefix} includedir=${prefix}/include libdir=${exec_prefix}/lib Name: foo Description: The foo library Version: 1.0.0 Cflags: -I${includedir}/foo Libs: -L${libdir} -lfoo
關鍵字定義好比 Name:XXX
,後面跟着一個冒號 :
和值。關鍵字由 pkg-config 工具定義。
變量好比 prifix=XXX
,後面跟着一個等號 =
和值。變量一方面能夠簡化 .pc
文件的書寫,一方面能夠存儲一些 pkg-config 工具沒法覆蓋的數據。code
下面是對關鍵字字段的一個簡要介紹,更深刻的部分見 編寫 部分(也就是下一節):遞歸
Name:庫或者包的一個別名,方面人類閱讀。pkg-config 工具使用的名字是 .pc
文件的文件名,不會用到這個名字。ip
Description:對包的一個簡要描述。get
URL:人們能夠從這個地址下載包,並得到更多有關包的信息。io
Version:包的版本號編譯
Requires:這個包依賴的包的列表。依賴的包的版本號能夠經過比較操做符指定(例如 = 、<=)變量
Requires.private:這個包依賴的包的列表。可是目標應用沒法使用這些包。
Conflicts:可選字段,描述哪些包與此包衝突。
Cflags:不支持 pkg-config 的一些編譯選項和庫依賴。若是依賴的庫支持 pkg-config ,那麼這個庫就應該放到前面的 Requires 或者 Requires.private 字段中去。
Libs:不支持 pkg-config 的一些連接選項和庫依賴。
Libs.private:不支持 pkg-config 的一些用於私有庫依賴的連接選項。
在給一個包建立 pkg-config 文件(後面簡稱爲 pc 文件)的時候首先要決定這些文件的發佈方式,最好是每一個庫都有一個對應的 pc 文件,這樣每一個包至少有跟庫的數量一致的 pc 文件。
包的名字由 pc 元數據文件的文件名決定。也就是文件名中除去 .pc 後綴的那部分。一個常見的選擇是讓庫名字和 .pc 文件的名字一致。例如,下載了 libfoo.so 的包應該有一個對應的 libfoo.pc 文件包含相關的 pkg-config 元數據。可是不必定要這要,把pc文件命名爲 foo.pc 或者 foolib.pc 也是可行的。
Name、Description、URL字段都是純信息,很容易填。 Version 字段有一點點麻煩,須要確保該數據能被用戶所使用。pkg-config 使用 RPM 的算法來進行版本比較。建議使用經過句點 .
分開的十進制數,若是使用字母的話會出現不可預知的錯誤。版本號必須單調遞增,而且足以制定這個庫文件。一般使用包的版本號就足夠了,並且這樣方面用戶進行追蹤。
在介紹更有用的字段以前,先介紹一下變量的定義。變量最多見的用途是指定安裝路徑,使用變量可使元數據字段保持簡潔。變量是遞歸地進行展開的,所以跟自動生成的路徑一塊兒使用十分有用(這句話沒看懂)。
prefix=/usr/local includedir=${prefix}/include Cflags: -I${includedir}/foo
pkg-config 裏面最重要的元數據字段是 Requires、 Requires.private 、 Cflags 、 Libs 和 Libs.private 。它們定義了外部項目編譯連接這個庫時所須要元數據。
Requires 和 Requires.private 定義了這個庫所需的其餘模塊。一般建議使用 Require 的 private 變體,以免把沒必要要的庫暴露給用戶程序。若是用戶程序不會用到依賴庫的符號,那麼這個庫經不該該被直接連接到用戶程序上。更詳盡的討論參見 overlinking 。
由於 pkg-config 老是暴露 Requires 庫的連接選項,因此這些模塊會成爲程序的直接依賴。另外一方面,Require.private 中的庫在靜態連接的時候只會被包含。所以,一般比較合適的作法是僅在 Requires 字段添加同一個包裏面的模塊。 (老外的寫做水平也是堪憂啊,各類 包、模塊、庫詞彙混雜在一塊兒使用。)
Libs 包含使用庫所必需的連接選項。此外,Libs 和 Libs.private 還包含 pkg-config 不支持的其餘庫的連接選項。一樣的,推薦把外部庫的連接選項放到 Libs.private 字段裏面去。
Cflags 包含這個庫所必需的編譯選項。與 Libs 不一樣的是這個字段沒有 private 變體。由於不論是怎麼樣的連接場景,數據類型和宏定義都是須要的。
假設系統安裝了 .pc 文件,那麼 pkg-config 工具就是用來抽取元數據的。執行 pkg-config --help
能夠查看其各個參數的簡要描述。更詳細的描述能夠在 pkg-config(1) 手冊頁中找到。本節會簡要介紹一些經常使用的狀況。
假設一個系統有個兩個模塊,foo 和 bar 。他們的 pc 文件能夠是這樣:
foo.pc:
prefix=/usr exec_prefix=${prefix} includedir=${prefix}/include libdir=${exec_prefix}/lib Name: foo Description: The foo library Version: 1.0.0 Cflags: -I${includedir}/foo Libs: -L${libdir} -lfoo
bar.pc:
prefix=/usr exec_prefix=${prefix} includedir=${prefix}/include libdir=${exec_prefix}/lib Name: bar Description: The bar library Version: 2.1.2 Requires.private: foo >= 0.7 Cflags: -I${includedir} Libs: -L${libdir} -lbar
模塊的版本號能夠經過 --modversion
參數查看
$ pkg-config --modversion foo 1.0.0 $ pkg-config --modversion bar 2.1.2
每一個模塊所須要的連接選項能夠經過 --libs
參數查看
$ pkg-config --libs foo -lfoo $ pkg-config --libs bar -lbar
注意 pkg-config 隱去了部分 Libs 中的字段。這是由於當它看到 -L 選項時,知道 ${libdir} 路徑 /usr/lib 是系統連接器的查找路徑。使用 -L 能夠避免 pkg-config 干涉連接操做。
並且,儘管 foo 被 bar 所依賴,foo 的連接選項卻沒有輸出。這是由於 foo 並非用戶應用直接須要的模塊。而若是要靜態連接一個 bar 應用,須要同時設置兩個連接選項。
$ pkg-config --libs --static bar -lbar -lfoo
pkg-config 須要把兩個連接選項都輸出來,確保靜態連接的應用可以找到全部須要的符號。另外一方面,它會把全部 Cflags
輸出。
$ pkg-config --cflags bar -I/usr/include/foo $ pkg-config --cflags --static bar -I/usr/include/foo
另外一個經常使用的參數 --exists
,能夠用來檢測一個模塊的可用性。
$ pkg-config --exists foo $ echo $? 0
pkg-config 的一個最優秀的特性是提供了版本檢測。它能夠檢測是否存在知足條件的版本。
$ pkg-config --libs "bar >= 2.7" Requested 'bar >= 2.7' but version of bar is 2.1.2
有些命令在使用 --print-errors
參數後會進行更詳盡的輸出。
$ pkg-config --exists --print-errors xoxo Package xoxo was not found in the pkg-config search path. Perhaps you should add the directory containing `xoxo.pc' to the PKG_CONFIG_PATH environment variable No package 'xoxo' found
上面的輸出信息提到了 PKG_CONFIG_PATH
環境變量。這個變量用來增長 pkg-config 的搜索路徑。在一個典型的 Unix 系統中,它會搜索 /usr/lib/pkgconfig
和 /usr/share/pkgconfig
。這兩個路徑能夠覆蓋系統安裝的模塊。可是,有些本地模塊可能下載到了其餘路徑中,例如 /usr/local
。
這種狀況下,有必要把這個搜索路徑添加進去以便 pkg-config 能夠定位 pc 文件。
$ pkg-config --modversion hello Package hello was not found in the pkg-config search path. Perhaps you should add the directory containing `hello.pc' to the PKG_CONFIG_PATH environment variable No package 'hello' found $ export PKG_CONFIG_PATH=/usr/local/lib/pkgconfig $ pkg-config --modversion hello 1.0.0
把 pkg-config 模塊集成到用戶項目中的時候,使用自動配置(autoconf)的宏能夠簡化這個過程。
PKG_PREREQ(MIN-VERSION)
:確保所使用的自動配置宏高於或等於 MIN-VERSION 。
PKG_PROG_PKG_CONFIG([MIN-VERSION])
:定位 pkg-config 工具在系統中的位置,並檢測其版本的兼容性。
PKG_CHECK_EXISTS(MODULES,[ACTION-IF-FOUND],[ACTION-IF-NOT-FOUND])
:檢測某些模塊是否存在。
PKG_CHECK_MODULES(VARIABLE-PREFIX,MODULES,[ACTION-IF-FOUND],[ACTION-IF-NOT-FOUND])
:檢測某些模塊是否存在,若是存在,根據 pkg-config --cflags 和 pkg-config --libs 的輸出設置 <VARIABLE-PREFIX>_CFLAGS 和 <VARIABLE-PREFIX>_LIBS 。
略