美文网首页c++-qtCMake实践
在cmake中使用pkg-config

在cmake中使用pkg-config

作者: BetterCV | 来源:发表于2020-05-24 12:56 被阅读0次
    package-153360_960_720.png

    什么是pkg-config

    简单理解,pkg-config根据.pc结尾的文件做依赖配置。
    找到.pc文件周,解析其内容,然后对底层构建工具(C/C++编译器、链接器)或高层构建工具(automake?, cmake)提供具体配置项目。

    通常是在POSIX系统(Linux,MacOS等)使用pkg-config,解决第三方依赖项配置问题。

    近些年来随着CMake的越发流行,原本用pkg-config的很多软件包提供了cmake的配置作为替代;少部分仍然提供.pc文件作为兼容考虑;还有另外一小部分的软件包,即使基于cmake构建了,对外提供依赖配置时仍然只有.pc文件。

    这就导致一个问题:虽然我学会了cmake在大部分时候都能解决依赖问题,但个别格楞子软件包还是要用pkg-config来搞。

    pkg-config的基本使用

    官方说明

    最直接的说明,来自于Ubuntu下pkg-config的man页面:

    DESCRIPTION
           The  pkg-config program is used to retrieve information about installed libraries in the system.  It
           is typically used to compile and link against one or more libraries.  Here is a typical  usage  sce‐
           nario in a Makefile:
    
           program: program.c
                cc program.c $(pkg-config --cflags --libs gnomeui)
    
           pkg-config  retrieves  information about packages from special metadata files. These files are named
           after the package, and has a .pc extension.  On most systems, pkg-config looks  in  /usr/lib/pkgcon‐
           fig,  /usr/share/pkgconfig, /usr/local/lib/pkgconfig and /usr/local/share/pkgconfig for these files.
           It will additionally look in the colon-separated (on Windows, semicolon-separated) list of  directo‐
           ries specified by the PKG_CONFIG_PATH environment variable.
    
           The  package name specified on the pkg-config command line is defined to be the name of the metadata
           file, minus the .pc extension. If a library can install multiple versions  simultaneously,  it  must
           give  each  version  its own name (for example, GTK 1.2 might have the package name "gtk+" while GTK
           2.0 has "gtk+-2.0").
    
           In addition to specifying a package name on the command line, the full path to a given .pc file  may
           be given instead. This allows a user to directly query a particular .pc file.
    

    也就是说,pkg-config默认会在以下路径中查找指定的包(库)对应的.pc文件:

    • /usr/lib/pkgconfig目录
    • /usr/share/pkgconfig目录
    • /usr/local/lib/pkgconfig目录
    • /usr/local/share/pkgconfig目录
    • PKG_CONFIG_PATH环境变量里的目录(可通过export PKG_CONFIG_PATH=XXX来修改)
    • 给pkg-config传入的.pc文件绝对路径

    而比较常用的选项是:

    --cflags  表示C/C++编译选项,例如指定头文件搜索目录
    --libs    表示链接选项,例如库的绝对目录,链接库按顺序列出等
    

    例如Linux下apt安装的opencv的结果分别为:

    (base) 1080Ti% pkg-config opencv --cflags
    -I/usr/include/opencv
    
    (base) 1080Ti% pkg-config opencv --libs  
    /usr/lib/x86_64-linux-gnu/libopencv_calib3d.so -lopencv_calib3d /usr/lib/x86_64-linux-gnu/libopencv_contrib.so -lopencv_contrib /usr/lib/x86_64-linux-gnu/libopencv_core.so -lopencv_core /usr/lib/x86_64-linux-gnu/libopencv_features2d.so -lopencv_features2d /usr/lib/x86_64-linux-gnu/libopencv_flann.so -lopencv_flann /usr/lib/x86_64-linux-gnu/libopencv_gpu.so -lopencv_gpu /usr/lib/x86_64-linux-gnu/libopencv_highgui.so -lopencv_highgui /usr/lib/x86_64-linux-gnu/libopencv_imgproc.so -lopencv_imgproc /usr/lib/x86_64-linux-gnu/libopencv_legacy.so -lopencv_legacy /usr/lib/x86_64-linux-gnu/libopencv_ml.so -lopencv_ml /usr/lib/x86_64-linux-gnu/libopencv_objdetect.so -lopencv_objdetect /usr/lib/x86_64-linux-gnu/libopencv_ocl.so -lopencv_ocl /usr/lib/x86_64-linux-gnu/libopencv_photo.so -lopencv_photo /usr/lib/x86_64-linux-gnu/libopencv_stitching.so -lopencv_stitching /usr/lib/x86_64-linux-gnu/libopencv_superres.so -lopencv_superres /usr/lib/x86_64-linux-gnu/libopencv_ts.so -lopencv_ts /usr/lib/x86_64-linux-gnu/libopencv_video.so -lopencv_video /usr/lib/x86_64-linux-gnu/libopencv_videostab.so -lopencv_videostab
    

    pkg-config到底用的是哪个.pc文件?

    比如我系统装了好多个版本的opencv,那么pkg-config到底找到并使用的是哪个opencv.pc呢?

    pkg-config opencv --debug > log.txt 2>&1
    ag 'opencv.pc' log.txt
    

    (不知为何,我用不了管道操作符,用了xargs也不行)
    输出:

    ⚡ ag 'opencv.pc' log.txt 
    167:File 'opencv.pc' appears to be a .pc file
    168:Will find package 'opencv' in file '/usr/lib/x86_64-linux-gnu/pkgconfig/opencv.pc'
    521:Reading 'opencv' from file '/usr/lib/x86_64-linux-gnu/pkgconfig/opencv.pc'
    522:Parsing package file '/usr/lib/x86_64-linux-gnu/pkgconfig/opencv.pc'
    

    于是打开/usr/lib/x86_64-linux-gnu/pkgconfig/opencv.pc文件,可以发现是2.4.9.1版本。

    给编译器和链接器传入pkg-config的结果

    例如单个文件使用opencv:

    g++ -o a.out hello_opencv.cpp `pkg-config --libs opencv`
    

    也可以在Makefile中进行设定。例如著名的Darknet,它早期某个版本的makefile内容如下:

    CC=gcc
    CFLAGS=-Wall `pkg-config --cflags opencv` -O3 -flto -ffast-math
    CFLAGS=-Wall `pkg-config --cflags opencv` -O0 -g
    LDFLAGS=`pkg-config --libs opencv` -lm
    VPATH=./src/
    
    OBJ=network.o image.o tests.o convolutional_layer.o connected_layer.o maxpool_layer.o activations.o
    
    all: cnn
    
    cnn: $(OBJ)
        $(CC) $(CFLAGS) $(LDFLAGS) $^ -o $@
    
    %.o: %.c 
        $(CC) $(CFLAGS) -c $< -o $@
    
    .PHONY: clean
    
    clean:
        rm -rf $(OBJ) cnn
    

    CMake中使用pkg-config

    1. 安装pkg-config

    安装pkg-config,并确保在CMake中能找到它的可执行文件。

    Ubuntu: sudo apt install pkg-config

    Windows: 下载 pkg-config-lite 。注意Anaconda/Miniconda中也带了pkg-config,但实测cmake中无法使用。为避免冲突,这里不把pkg-config-lite版的可执行文件路径放PATH系统环境变量,而是在cmake中单独配置:

    set(PKG_CONFIG_EXECUTABLE "D:/soft/pkg-config/bin/pkg-config.exe")
    

    2. CMakeLists.txt中使用pkg-config

    包括3个具体的步骤:

    • 确定.pc文件绝对路径(例如只提供.pc方式配置),记作$prefix/xxx.pc

    • 在CMakeLists.txt中,分别把$prefix和xxx填写入座:

    set(ENV{PKG_CONFIG_PATH} $prefix)
    find_package(PkgConfig)
    pkg_search_module(MyDepName REQUIRED xxx)
    

    其中MyDepName是自行起的名字,可以和原始包的名字不一样

    • 后续使用${MyDepName_LIBRARIES}${MyDepName_INCLUDE_DIRS}即可

    3. 举例

    Ubuntu 16.04下用apt安装openblas并在CMake中用pkg-config方式配置:

    #安装
    sudo apt install libopenblas-dev
    
    #查找.pc文件。
    #若查不到,执行sudo apt install --reinstall libopenblas-dev再执行
    dpkg -L libopenblas-dev | grep '.pc'
    
    #找到,在/usr/lib/pkgconfig/blas-openblas.pc
    

    编写CMakeLists.txt,把/usr/lib/pkgconfig/blas-openblas.pc拆分为/usr/lib/pkgconfigblas-openblas:

    cmake_minimum_required(VERSION 3.15)
    
    project(cmake_pkg_config_example)
    
    set(ENV{PKG_CONFIG_PATH} /usr/lib/pkgconfig)
    find_package(PkgConfig)
    pkg_search_module(OBS REQUIRED blas-openblas)
    
    message(STATUS "=== OBS_LIBRARIES: ${OBS_LIBRARIES}")
    message(STATUS "=== OBS_INCLUDE_DIRS: ${OBS_INCLUDE_DIRS}")
    

    其中OBS是我随便起的前缀,你也可以换成别的。后续使用这个库的时候,使用OBS_LIBRARIESOBS_INCLUDE_DIRS即可。

    Windows 10下用CMake配置Pangolin安装中配置的zlib
    Pangolin怎么配置这里就不贴了,正常使用cmake调用Visual Studio编译的流程即可。它会自动源码编译安装zlib。这里假设另一个项目要用到这个版本的zlib,则CMakeLists.txt写法如下:

    cmake_minimum_required(VERSION 3.15)
    
    project(cmake_pkg_config_example)
    
    #指定pkg-config.exe绝对路径
    set(PKG_CONFIG_EXECUTABLE "D:/soft/pkg-config/bin/pkg-config.exe")
    
    #指定zlib.pc所在目录
    set(ENV{PKG_CONFIG_PATH} "D:/lib/pangolin/share/pkgconfig")
    
    find_package(PkgConfig)
    message(STATUS "--- PKG_CONFIG_FOUND: ${PKG_CONFIG_FOUND}")
    message(STATUS "--- PKG_CONFIG_VERSION_STRING: ${PKG_CONFIG_VERSION_STRING}")
    
    pkg_search_module(ZLIB REQUIRED zlib)
    
    message(STATUS "=== ZLIB_LIBRARIES: ${ZLIB_LIBRARIES}")
    message(STATUS "=== ZLIB_INCLUDE_DIRS: ${ZLIB_INCLUDE_DIRS}")
    

    参考

    FindPkgConfig----CMake的pkg-config模块

    CMake的pkg-config模块使用

    How to install pkg config in windows?

    pkg-config-lite SourceForge

    相关文章

      网友评论

        本文标题:在cmake中使用pkg-config

        本文链接:https://www.haomeiwen.com/subject/cxodahtx.html