CMake+MinGW+vcpkg项目引入三方库的两种方式(手动路径,vcpkg)
接到个新项目,用到很多三方库,从对接的同事那了解到vcpkg这个工具,周末试用了下,确实很方便,以前需要自己动手的源码下载,编译和打包安装,如今一个vcpkg install
就能一站解决,十分便利,vcpkg的构建系统包含CMake,自己在用vcpkg搭建项目的时候遇到了些问题,一时搜索无法解决,最后回去补了些CMake的基础,再回来用vcpkg,才终于走顺,这里把实验的过程特此记录。
用的项目例子为Helloworld程序引用fmt库,测试环境Windows10, 目录结构如下:
PS D:\CodeDraft\helloworld> tree /F
卷 开发 的文件夹 PATH 列表
卷序列号为 BE68-723D
D:.
│ CMakeLists.txt
│ main.cpp
│ run_cmake.ps1
│
├─3rdparty
│ └─fmt_x64-mingw-dynamic
│ │ BUILD_INFO
│ │ CONTROL
│ │
│ ├─bin
│ │ libfmt.dll
│ │
│ ├─debug
│ │ ├─bin
│ │ │ libfmtd.dll
│ │ │
│ │ └─lib
│ │ │ libfmtd.dll.a
│ │ │
│ │ └─pkgconfig
│ │ fmt.pc
│ │
│ ├─include
│ │ └─fmt
vcpkg的下载过程可参考:https://www.cnblogs.com/linuxAndMcu/p/14696542.html
建项目过程,首先新建个helloworld文件夹
mkdir helloworld
cd helloworld
然后main.cpp如下
#include <fmt/core.h>
int main()
{
fmt::print("Hello World!\n");
return 0;
}
手动路径
用vcpkg将fmt库下载好之后直接CV到helloworld项目的3rdparty中,vcpkg install
的包一般安装在vcpkg安装目录的packages
文件夹中。
vcpkg install fmt:x64-mingw-dynamic
注意triplet参数,Windows上默认用x64-windows, 我习惯用mingw,注意x64-windows是msvc编译器,跟mingw的程序不兼容。
vcpkg又分动态库和静态库版本,一般使用动态库,我选的是x64-mingw-dynamic,即mingw的动态版本。
有了库和main.cpp, 可以编写CMakeLists.txt了:
cmake_minimum_required(VERSION 3.10)
project(HelloWorld)
message("CMAKE_SOURCE_DIR: ${CMAKE_SOURCE_DIR}")
include_directories(${CMAKE_SOURCE_DIR}/3rdparty/fmt_x64-mingw-dynamic/include)
link_directories(${CMAKE_SOURCE_DIR}/3rdparty/fmt_x64-mingw-dynamic/bin) # -Lpath
link_libraries(fmt) #-lfmt
add_executable(HelloWorld main.cpp)
add_custom_command(TARGET HelloWorld POST_BUILD #-for copy libs in windows
COMMAND ${CMAKE_COMMAND} -E copy_if_different
${CMAKE_SOURCE_DIR}/3rdparty/fmt_x64-mingw-dynamic/bin/libfmt.dll
${CMAKE_SOURCE_DIR}/build)
build然后run, 这里我用的ps脚本,后面发现CMakePresets.json也有类似的功能,后面vcpkg方式用的就是CMakePresets.json。
cmake -G "MinGW Makefiles" -B build
cd build
make
.\HelloWorld.exe
cd ..
windows上执行项目相比Ubuntu上有一个坑点,exe文件运行必须依赖同一目录下的dll,在powershell上表现为执行.\HelloWorld.exe
无响应,在资源管理器双击运行才会报错说明缺少了什么库。这里我用add_custom_command命令自动把对应的dll文件给拷贝进去。
自此项目编译运行就完成了,优点简单易懂,缺点就是不适合三方库多,结构复杂的项目。
Vcpkg自动方式
照着微软官方的教程做就行,不过官方用的msvc, MinGW需要对CMakePreset.json做点修改,这里放出来:
{
"version": 2,
"configurePresets": [
{
"name": "default",
"generator": "MinGW Makefiles",
"binaryDir": "${sourceDir}/build",
"cacheVariables": {
"CMAKE_TOOLCHAIN_FILE": "$env{VCPKG_ROOT}/scripts/buildsystems/vcpkg.cmake",
"VCPKG_TARGET_TRIPLET" : "x64-mingw-dynamic",
"CMAKE_BUILD_TYPE": "Debug"
}
}
]
}
可以看到需要指明generator
,VCPKG_TARGET_TRIPLET
,CMAKE_BUILD_TYPE
, 告诉CMake,根据MinGW的生成方式,下载vcpkg.json依赖库的x64-mingw-dynamic版本,以Debug的构建类型调用。
vcpkg的方式也可以自动将dll库引入。
小踩坑
手动引入方式,在网上搜索如何拷贝dll库时,用过这么一个引入三方库的写法:
cmake_minimum_required(VERSION 3.10)
project(HelloWorld)
message("CMAKE_SOURCE_DIR: ${CMAKE_SOURCE_DIR}")
message("VCPKG_ROOT: $ENV{VCPKG_ROOT}")
add_executable(HelloWorld main.cpp)
add_library(fmt SHARED IMPORTED)
set_property(TARGET fmt PROPERTY IMPORTED_LOCATION ${CMAKE_SOURCE_DIR}/3rdparty/fmt_x64-mingw-dynamic/bin/libfmt.dll)
target_include_directories(fmt INTERFACE ${CMAKE_SOURCE_DIR}/3rdparty/fmt_x64-mingw-dynamic/include)
target_link_libraries(HelloWorld fmt)
结果不知为何,CMake居然找不到dll库了!几个小时搜索仍旧未见效果,最后只好stackoverflow上问,才知道原来又是windows基础的锅,编译用lib运行用dll,要补全set_property, 不知道为什么用link_directories
和link_libraries
就过了。
add_library(fmt SHARED IMPORTED)
set_property(TARGET fmt PROPERTY IMPORTED_LOCATION ${CMAKE_SOURCE_DIR}/3rdparty/fmt_x64-mingw-dynamic/bin/libfmt.dll)
set_property(TARGET fmt PROPERTY IMPORTED_IMPLIB ${CMAKE_SOURCE_DIR}/3rdparty/fmt_x64-mingw-dynamic/lib/libfmt.lib) #应补上
fmt的x64-mingw-dynamic版本只提供了dll,没有提供lib,好在MinGW提供了生成的工具:
gendef.exe libfmt.dll
dlltool.exe -d libfmt.def -l libfmt.lib
把libfmt.lib拷贝到指定目录,重新编译,通过。