cmake笔记 &编译与链接

常用cmake代码

if(USE_CUDA)
    add_definitions(-DUSE_CUDA=1)
    enable_language(CUDA)
    find_package(CUDA 11.4 REQUIRED)

    set(src
        main.cpp
       cuda.cu
    )
endif()

概述

Cmake从开始到结束是:

  1. project File Generation(Configure,Generate); 重点阶段
  2. Build(可以使用cmake,也可以使用visual studio 等IDE工具);
  3. Test(可以使用cmake自带的单元测试工具 CTest);
  4. Package(可以使用 cmake自带的打包工具 CPack);

本文为《cmake practice》的个人笔记。
注意,如果仅仅使用qt编程的话,没必要使用cmake,因为qmake已经足够专业。

cmake的正常使用顺序:

  1. 找一个合适的位置,mkdir build & cd build (也就是 out-of-source build)
  2. cmake … (…代表的是父目录,也就是cmakelists所在的路径)
  3. make

注意,清理工程的命令为: make clean

CMake变量

CMake基本变量

使用set来定义一个基本变量:set (foo ab) # foo = "ab"
通过变量名来获得变量: set(bar $(foo)cd)

CMake环境变量

设置环境变量:
set(ENV {PATH} "$ENV{PATH}:/opt/mydir")
获取环境变量:
$ENV{varName}

CMake缓存变量

cmake -D myVar:type=somevalue ...
-U 选项从缓存中删除变量。

编译最简单的hello world

工程结构:
在这里插入图片描述

CMakeLists.txt中的内容:

PROJECT(HELLO) 
SET(SRC_LIST main.c)
MESSAGE(STATUS "This is BINARY dir" ${HELLO_BINARY_DIR})
MESSAGE(STATUS "This is SOURCE dir" ${HELLO_SOURCE_DIR})
ADD_EXECUTABLE(hello ${SRC_LIST})
  • 注意SRC_LIST 外面需要加上${}。这是cmake的语法,变量会需要这样去取值。但是后续需要注意的是,在IF语句中会直接使用变量名。

在进行常规cmake和make操作后,在build文件夹中就会出现目标文件 hello.o,可以直接用于运行。

如果想要看到具体的make信息,可以输入 make VERBOSE=1


1. PROJECT(projectname [CXX] [C] [Java])
用于定义工程名称,默认情况下支持所有语言。该指令运行的同时,隐式地定义了两个cmake变量,即<projectname>_BINARY_DIR以及<projectname>_SOURCE_DIR。注意,通过外部编译进行工程构建,HELLO_SOURCE_DIR 仍然指代工程路径,即
/backup/cmake/t1而 HELLO_BINARY_DIR 则指代编译路径,即/backup/cmake/t1/build。

2. SET(VAR [VALUE] [CACHE TYPE DOCSTRING [FORCE]])
显式定义变量

3. MESSAGE([SEND_ERROR | STATUS | FATAL_ERROR] "message to display" ...)
向终端输出用户定义的信息:

  • SEND_ERROR,产生错误,生成过程被跳过;
  • SATUS,输出前缀为—的信息;
  • FATAL_ERROR,立即终止所有 cmake 过程

4. ADD_EXECUTABLE(hello ${SRC_LIST})"
生成一个文件名为 hello 的可执行文件
相关的源文件是 SRC_LIST 中定义的源文件列表。

编译工程化的helloWorld

在这里插入图片描述

新建src文件夹,在src文件夹中放入main.c文件,且新建一个cmakelists,内容是:ADD_EXECUTABLE(hello main.c)
而后,跳出src文件夹,再新建一个cmakelists,内容是:
PROJECT(HELLO) ADD_SUBDIRECTORY(src bin)
我们就可以惊奇的发现,编译后的hello文件竟然在build/bin文件夹下。
而能够实现这种惊奇的命令就是: ADD_SUBDIRECTORY


ADD_SUBDIRECTORY(source_dir [binary_dir] [EXCLUDE_FROM_ALL])

  1. ADD_SUBDIRECTORY(source_dir [binary_dir] [EXCLUDE_FROM_ALL])
    这个命令用于向当前工程添加存放源代码的子目录,且可以指定中间二进制以及目标二进制存放的位置。注意,这个添加的目录,不一定非得是源工程的子目录,不过通常会是。
    注意,这个命令会为子目录中的CMakeLists.txt创建一个新的子作用域,而父作用域中所定义的所有变量对于子作用域来说都是可见的,子作用域可以像调用自己变量一样调用父作用域里面的变量。
    所谓 EXECLUDE_FROM_ALL参数的含义是将该目录从编译过程中排除掉,举个例子,工程里的example,往往需要工程构建完后,再进到example目录里面单独编译。
    ADD_SUBDIRECTORY(src bin)做的事情就是,在编译时将src重命名为bin,并将中间结果与目标二进制放到bin里面。

此时的目录结构为:在这里插入图片描述

通过set来定义可执行文件或者库输出的位置


实际上,我们还可以通过SET指令重新定义 EXECUTABLE_OUTPUT_PATHLIBRARY_OUTPUT_PATH 来仅仅指定目标二进制输出的位置,注意,此时不包含编译生成的中间文件。
具体为:

SET(EXECUTABLE_OUTPUT_PATH ${PROJECT_BINARY_DIR}/bin)
SET(LIBRARY_OUTPUT_PATH ${PROJECT_BINARY_DIR}/lib)

创建一个静态库、一个可执行文件,并在可执行文件中调用这个库

  • 创建静态库
    add_library(MyStaticLib STATIC MyStaticLib.hpp MyStaticLib.cpp)

  • 创建可执行文件
    add_executable(hello-world hello-world.cpp)

  • 链接库到可执行文件
    target_link_libraries(hello-world MystaicLib)


add_library() 可以选择编译成静态库(STATIC)、动态库(SHARED)或者模块(MODULE),模块在Windows平台上就表现为没有lib的dll文件(也就是说,没有那些原本存储于lib中的链接信息,也不能通过引入头文件来进行操作,只能进行动态加载)


如何使用外部共享库和头文件

其他有用的cmake命令

include_directories

添加头文件目录

include_directories("3rdparty\\opencv-3.4.1\\__build1\\install\\include" 
"3rdparty\\opencv-3.4.1\\__build1\\install\\include\\opencv" 
"3rdparty\\opencv-3.4.1\\__build1\\install\\include\\opencv2" )

find_package

我们可以通过find_package引入其他cmake编译安装的库,往往会是第三方库。
find_package本质上是一个查找依赖包的命令。

理想情况下,一句命令就可以把头文件包含的路径、库路径、库名字还有版本号都获取到。

但是在不理想的情况下,就会需要指定搜索路径,比如说:

find_package(fmt CONFIG REQUIRED
			     	   PATHS C:\\vcpkg\\vcpkg\\installed\\x64-windows\\share\\fmt
			  		   NO_DEFAULT_PATH))

此外,还需要注意 find_packagefind_library 指令得到的都是库文件的绝对路径。

file(GLOB variable [RELATIVE path] [globbing expressions]...)

file(GLOB variable [RELATIVE path] [globbing expressions]...)
file(GLOB_RECURSE variable [RELATIVE path] [FOLLOW_SYMLINKS] [globbing expressions]...)

GLOB选项将会为所有匹配查询表达式的文件生成一个文件list,并将该list存储进变量variable里。
文件名查询表达式与正则表达式类似,只不过更加简单。
如果为一个表达式指定了RELATIVE标志,返回的结果将会是相对于给定路径的相对路径

文件名查询表达式的例子有:

*.cxx - 匹配所有扩展名为cxx的文件。
*.vt? - 匹配所有扩展名是vta,…,vtz的文件。
f[3-5].txt - 匹配文件f3.txt, f4.txt, f5.txt。

GLOB_RECURSE选项将会生成一个类似于通常的GLOB选项的list,只是它会寻访所有那些匹配目录的子路径并同时匹配查询表达式的文件。

参考文献:https://www.cnblogs.com/coderfenghc/archive/2012/07/08/2581734.html

target_link_libraries

顾名思义,该指令的作用是将目标文件和库文件进行链接,这里的目标文件,既可以是可执行文件,也可以是其他库文件。

完整的指令语法是:

target_link_libraries(<target> [item1] [item2] [...]
                      [[debug|optimized|general] <item>] ...)

链接库顺序和gcc是一致的,即被链接的库放到后面,例如:
liba.a依赖libb.a
target_link_libraries(target a b)

windows 下 C++开发中的cmake

通常来说,在windows开发的时候,cmakelist写完了生成sln。
往往还是会选择用visual studio 而不是 visual studio code 来进行开发。
调用第三方库的时候,一定要问清楚自己以下几点:

  1. 是不是正确include了?
  2. 是不是正确链接 lib库了?
  3. dll有没有放到跟exe同级的目录下,或者直接编到系统库上?
  4. 到底是x86还是x64,有没有搞错这里。

注意事项

  • Cmake可以为一套源目录,创建多个构建目录,如Debug、Release、x86以及x64;
  • cmake -G "Unix Makefiles" ../source
    • -G 参数表示生成器
  • cmake --build . --config Release --target MyApp
    • –build 选项指向CMake项目生成的构建目录; 默认会生成最高版本。
    • –config 指定构建哪个配置;
    • –target 告诉构建工具要构建的目标。
  1. cmakelists如何同时链接debug库和release库?
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
Linux系统下,使用CMake进行编译的指令如下: 1. 首先,你需要安装CMake。你可以从官方网站下载CMake的源代码,并进行编译安装,或者使用包管理器进行安装。 2. 下载CMake的源代码,并解压缩: ```shell wget https://github.com/Kitware/CMake/releases/download/v3.16.8/cmake-3.16.8.tar.gz tar -xzf cmake-3.16.8.tar.gz ``` 3. 进入解压缩后的目录,并创建一个build文件夹: ```shell cd cmake-3.16.8 mkdir build ``` 4. 进入build文件夹,并执行cmake命令,生成Makefile和其他构建文件: ```shell cd build cmake .. ``` 5. 执行make命令,进行编译: ```shell make ``` 通过以上步骤,你可以使用CMakeLinux系统下进行编译。这些指令会帮助你在当前目录下创建一个build文件夹,并在其中生成Makefile和其他构建文件,然后使用make命令进行编译。<span class="em">1</span><span class="em">2</span><span class="em">3</span> #### 引用[.reference_title] - *1* [paddlepaddle-2.5.0rc1-cp37-cp37m-linux-aarch64.whl](https://download.csdn.net/download/musicsxf/87917049)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_2"}}] [.reference_item style="max-width: 33.333333333333336%"] - *2* [Linux学习笔记:使用Cmake编译](https://blog.csdn.net/dingxiaoxv/article/details/126921859)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_2"}}] [.reference_item style="max-width: 33.333333333333336%"] - *3* [linux-cmake常用指令](https://blog.csdn.net/m0_37792813/article/details/126403669)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_2"}}] [.reference_item style="max-width: 33.333333333333336%"] [ .reference_list ]

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

FLOWVERSE

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值