Windows下CMake链接库

如何在VScode中使用CMake链接库,主要是静态库,动态库在Windows中直接放在exe同目录。

说明

  • Cmake工具包使用VS Studio Community 2022 - amd64
  • 这篇博客会以两个库作为例子,一个是自己写的add.h及add.cpp另一个则链接openCV4.8.0
  • 这篇博客不记录CMake、C++等工具相关配置。

关于add.h

编译链接静态库

  • 以下是文件结构,未标识后缀的应视为文件夹,除.vscode属一个文件夹(主要是 C++相关配置文件)。
  • 此项目名称为cmake-study
D:/cmake-study/
├─.vscode
├─build
├─lesson2-1
│  ├─add
│     ├─add.cpp
│     └─CMakelists.txt
│  ├─lib
│     ├─add_static.lib
│     └─add.h
│  ├─CMakelists.txt
│  └─main.cpp
├─CMakeLists.txt

C++中我们自己写的库可以与main一起放在同一目录下,#include"add.h"然后进行调试或运行。对于我们自己写的库,为避免过多的代码复写,直接编译成动态库或静态库要更加省力。所以我们的目标是将add.cpp编译成静态库,然后通过CMake指定需要链接的库,然后直接在main.cpp中调用即可。

编写lesson2-1/add中的CMakelists

我们的目标是通过该CMakelists.txt指定将add.cpp编译为一个静态库,Windows系统一般以.lib作后缀。所以该CMakelists.txt应编写如下。

add_library(add_static add.cpp)

add_library指定我们需要编译一个‘库’,而内部的add_static指定编译后库的名字,也即编译后,我们的静态库应该叫add_static.lib,而add.cpp则是需要编译的文件,需要注意的是,这里使用的是相对路径,也可以写成./add.cpp

编写lesson2-1中的CMakelists

CMakelists的目标是将./add中的CMakelists加入进来,同时指定需要包括的静态库文件的位置、需要链接的静态库文件以及需要编译的文件。在本文件结构下,把所有静态库以及相关头文件全部放在同目录的lib文件夹下。则可以编写CMakelists.txt如下。

add_subdirectory(add)
include_directories(./lib)
add_executable(lesson2-1 main.cpp)
target_link_libraries(lesson2-1 D:/cmake-study/lesson2-1/lib/add_static.lib)

add_subdirectory将同目录下add文件夹加入进来,同时include_directories指定包括头文件位置,add_executable指定需要一同编译的文件,同时指定生成一个lesson2-1的项目文件,该文件可以在./cmake-study/build中找到。最后target_link_libraries指定需要链接的文件以及被链接的项目文件。但此处仿佛必须写绝对路径,否则依然会出现 LNK ERROR,故也可以参考下列编写方法。

add_subdirectory(add)
include_directories(./lib)
link_directories(./lib) # 指定链接库的路径
add_executable(lesson2-1 main.cpp)
target_link_libraries(lesson2-1 add_static.lib) # 在指定的 link_directories 中选择链接的库

编写cmake-study中的CMakelists

CMakelists.txt主要作为所有项目的管理,所以主要是设定一些基本设置。比如我们还有lesson2-2文件夹,该文件中还可以有其他C++项目,或是即将要讲到的lesson2-opencv文件夹。我们指定C++ 14以及最低CMake版本为 3.15。同时指定整个项目文件名为cmake-study

cmake_minimum_required(VERSION 3.15)
project(camke_study)

set(CMAKE_CXX_STANDARD 14)
add_subdirectory(lesson2-1)
add_subdirectory(lesson2-2)
add_subdirectory(lesson2-opencv)

关于链接openCV

我们首先给出一个示例程序,main.cpp,注意cv::imread中的图像路径需要自己指定,如果不指定的话也可以看终端是否成功输出"无法读取输入图像"。

#include <opencv2/opencv.hpp>
#include <iostream>
int main(int argc, char **argv)
{
    cv::Mat inputImage = cv::imread("path/to/image.jpg", cv::IMREAD_COLOR);
    if (inputImage.empty())
    {
        std::cout << "无法读取输入图像" << std::endl;
        return -1;
    }
    cv::Mat outputImage;
    inputImage.copyTo(outputImage);
    cv::imshow("原始图像", inputImage);
    cv::imshow("复制后的图像", outputImage);
    cv::waitKey(0);
    return 0;
}

链接opencv2/opencv.hpp

注意此处cmake-study/CMakelists.txt文件与示例add.h一致,主要是用于所有项目的管理。所以重要的是cmake-study/lesson2-opencv文件夹下的CMakelists.txt

D:/cmake-study/
├─.vscode
├─build
├─lesson2-opencv
│  ├─CMakelists.txt
│  └─main.cpp
├─CMakeLists.txt

编写lesson2-opencv中的CMakelists

通过第一个例子我们已经知道,要链接opencv2/opencv.hpp文件,我们需要该文件的位置,以及相关静态库/动态库的位置。官网下载openCV4.8.0并指定路径进行安装后,打开该opencv文件,我们主要需要/opencv/build/include(该文件夹内包括了opencv2以及各种头文件)和/opencv/build/x64/vc16中的bin(动态库)以及lib(静态库)。注意以上opencv文件路径省略了前面的部分,需要使用绝对路径。所以我们可以编写CMakelists.txt如下

include_directories(D:/opencv/build/include)
add_executable(lesson2-opencv main.cpp)
target_link_libraries(lesson2-opencv D:/opencv/build/x64/vc16/lib/opencv_world480d.lib) # debug版本选择opencv_world480d.lib

当然,我们也可以将opencv/build/include中的include文件夹直接复制到main.cpp相同目录中,同时新建一个文件夹lib将静态库复制在里面,此时CMakelists编写如下。

include_directories(include)
link_directories(./lib)
add_executable(lesson2-opencv main.cpp)
target_link_libraries(lesson2-opencv opencv_world480d.lib) # debug版本选择opencv_world480d.lib