以前不習慣用pkg-config,喜歡在Makefile中指定程序的依賴項。但是這樣做存在一個問題,即當你的機器上安裝了同一名稱但不同版本的依賴庫時,就有可能導致鏈接失敗。這時,pkg-config就顯示了它的優勢:使編譯選項簡潔明瞭。
那麼pkg-config是幹啥的呢?按照官方說法,它用來返回已安裝庫的基本信息。
pkg-config的參數有如下一堆,想獲得更全的參數及用法,可以通過執行“pkg-config --help”來查看全部參數及意義。
pkg-config [--modversion] [--help] [--print-errors] [--silence-errors] [--cflags] [--libs] [--libs-only-L] [--libs-only-l] [--cflags-only-I] [--variable=VARIABLENAME] [--define-variable=VARIABLENAME=VARIABLEVALUE] [--uninstalled] [--exists] [--atleast-version=VERSION] [--exact-version=VERSION] [--max-version=VERSION] [LIBRARIES...]
以上參數中,我們常用的基本就是[--cflags] [--libs],用來指出程序依賴的頭文件和庫文件路徑。典型用法如下:
program: program.c
cc program.c ‘pkg-config --cflags --libs gnomeui‘
其中,gnomeui就是程序要鏈接的庫的名稱。
例如,我們常用的opencv庫,若執行“pkg-config --cflags --libs opencv”,得到如下結果:
以上內容,不就是我們在Makefile裏寫的一堆依賴庫信息嗎?現在好了,一句pkg-config語句搞定。
那麼問題來了,pkg-config是如何獲得這些信息的呢?原來,pkg-config程序是去讀取庫名稱對應的.pc文件,如果用opencv的庫,就會去讀opencv.pc。
首先,.pc文件在哪裏?
默認情況下,會去prefix/lib/pkgconfig/路徑下查找,具體到Linux系統,就是/usr/lib/pkgconfig/目錄,若找不到,則會去PKG_CONFIG_PATH環境變量指定的路徑下查找。因此,如果我們安裝的庫文件不在系統環境變量中,需要將其添加到PKG_CONFIG_PATH中,具體來說,執行如下操作:
export PKG_CONFIG_PATH=/home/mylibs/lib/pkgconfig:$PKG_CONFIG_PATH
其中,/home/mylibs/lib/pkgconfig就是我們所安裝的庫文件對應的.pc文件的存放路徑。以我們安裝OpenCV的路徑爲例,看一下pkgconfig下面都有哪些文件:
可以看到,有我們安裝的libavcodec.pc、opencv.pc、x264.pc等等。
其次,.pc文件裏面都有哪些內容?
我們打開opencv.pc,可以看到如下內容:
.pc中明確列出了庫的prefix、執行文件地址、庫地址、頭文件地址,以及庫的名稱、描述、版本號、具體子模塊庫列表等等,可以說有了這個文件,我們程序依賴的內容就都有了。當然,如果你的系統裝了兩份不同版本的某個庫,那麼在使用pkg-config時就需要指定版本號了。
有了pkg-config,我們的Makefile編寫起來就簡潔多了,以下是依賴opencv的某工程的Makefile,貼上來做參考。
CFLAGS := -O3 $(EXTRA_INC) -std=c++11 `pkg-config --cflags --libs opencv`
LDFLAGS := $(EXTRA_LIBS)
SOURCE := $(wildcard *.cpp)
OBJ := $(patsubst %.cpp, %.o, $(wildcard *.cpp))
EXE := SmartDetect
$(EXE):$(OBJ)
g++ -o $(EXE) $^ -I. $(CFLAGS) $(LDFLAGS)
%.o:%.cpp
g++ -o $@ -c $^ $(CFLAGS) -I.
.PHONY:clean
clean:
rm $(OBJ) $(EXE)