cmake编译特性 相关设置函数(细节)
target_include_directories():指定目标包含的头文件路径。官方文档
target_link_libraries():指定目标链接的库。官方文档
target_compile_options():指定目标的编译选项。官方文档
目标 由 add_library() 或 add_executable() 生成。
参考原文链接:深入理解 CMake 中的 INCLUDE_DIRECTORIES 与 target_include_directories_cmake include头文件-CSDN博客
一、target_include_directories
(一)、
命令格式
target_include_directories(<target> [SYSTEM] [AFTER|BEFORE]
<INTERFACE|PUBLIC|PRIVATE> [directory1]
[<INTERFACE|PUBLIC|PRIVATE> [directory2] ...])
作用:
该命令给指定的目标文件<target>,添加头文件搜索目录。所以,<target>必须用add_executable()或add_library()等命令先创建出来。
参数选项:
AFTER或BEFORE
指定添加的目录:是追加到头文件搜索目录列表之后,还是在头文件搜索目录列表的最前面插入。
SYSTEM
该选项表明被添加的目录是系统目录。系统目录的搜索顺序在普通的头文件搜索目录之后,并且会添加到目标的INTERFACE_SYSTEM_INCLUDE_DIRECTORIES属性中。
INTERFACE或PUBLIC或PRIVATE
指定添加到目标的范围属性,INTERFACE和PUBLIC会添加到<target>的INTERFACE_INCLUDE_DIRECTORIES属性,PUBLIC和PRIVATE会添加到<target>的INCLUDE_DIRECTORIES属性中。
target_include_directories该命令给指定的目标文件添加头文件搜索目录。所以,<target>必须用add_executable()或add_library()等命令先创建出来。
(二)、CMake 中的 INCLUDE_DIRECTORIES 与 target_include_directories区别
在使用 CMake 构建系统时,指定头文件的包含路径是非常常见的一步。对于这个任务,CMake 提供了两种主要的命令:INCLUDE_DIRECTORIES 和 target_include_directories。虽然它们看似类似,但它们的:作用范围、应用方式以及适用场景却有很大差别。
1. 什么是头文件包含目录?
在编译 C++ 项目时,头文件提供了声明和接口,是源代码文件间相互引用的关键部分。为了告诉编译器去哪里查找这些头文件,通常需要指定一个或多个包含目录(include directories)。如果没有正确设置头文件路径,编译器会报出类似 "file not found" 的错误。因此,如何有效管理和设置这些路径对于构建项目至关重要。
CMake 作为一个跨平台的构建系统,提供了多种方式来为项目设置包含目录,最常用的就是 INCLUDE_DIRECTORIES 和 target_include_directories。
2. INCLUDE_DIRECTORIES —— 全局包含目录
INCLUDE_DIRECTORIES 是 CMake 中最早的用于设置包含路径的命令,它的效果是全局性的。也就是说,当你在 CMake 文件中调用 INCLUDE_DIRECTORIES 时,它会将指定的包含路径应用到当前作用域下的所有目标(targets)。所有在该命令之后的目标都会继承这些包含路径。
语法:
INCLUDE_DIRECTORIES(<directories>)
使用示例:
INCLUDE_DIRECTORIES(${CMAKE_SOURCE_DIR}/include)
这条指令会将项目根目录下的 include 目录添加为全局的包含目录。这样,所有的目标(如库、可执行文件)都可以从这个目录中查找头文件。
适用场景:
小型项目:在简单项目中,只有少量的源文件和库,头文件目录也很集中。此时使用 INCLUDE_DIRECTORIES 是一个快速且方便的选择。
简单的全局依赖:如果项目中的所有目标都依赖于同一组头文件路径,这种全局设置方式非常有效。
优点:
简单易用:只需一次调用,即可为所有目标设置头文件搜索路径。
快速实现:适合快速搭建或验证简单项目。
缺点:
全局性:一旦设置,后续所有的目标都会使用这些包含目录,难以做到细粒度的控制。这会增加项目规模和复杂性时的管理难度。
可维护性差:如果项目变得复杂,全局的包含目录可能会导致不必要的依赖,或者由于头文件冲突而导致编译问题。
潜在污染:多个模块共用一组全局的头文件路径,可能会引发意想不到的问题,如头文件覆盖或模块间的耦合度过高。
3. target_include_directories —— 精确控制每个目标的包含目录(细粒度的控制)
为了克服 INCLUDE_DIRECTORIES 的全局性问题,CMake 引入了 target_include_directories 命令,它允许开发者为特定的目标设置包含目录。与 INCLUDE_DIRECTORIES 不同,这个命令具有更强的作用范围控制能力,并且支持三种不同的作用域:PRIVATE、PUBLIC 和 INTERFACE,帮助管理目标之间的依赖关系。
语法:
target_include_directories(<target> [PRIVATE|PUBLIC|INTERFACE] <directories>)
PRIVATE:仅对当前目标可见,依赖于这个目标的其他目标不会继承这些包含目录。
PUBLIC:对当前目标和依赖于该目标的其他目标都可见。
INTERFACE:当前目标不会使用这些包含目录,但依赖于它的其他目标可以使用。
使用示例:
add_library(MyLibrary mylibrary.cpp)
target_include_directories(MyLibrary PUBLIC ${CMAKE_SOURCE_DIR}/include PRIVATE ${CMAKE_SOURCE_DIR}/src )
在这个例子中,MyLibrary 会使用 项目根目录下include 和 src 目录中的头文件:
PUBLIC 的 include 目录:不仅会对 MyLibrary 可见,还会对依赖于 MyLibrary 的目标可见。
PRIVATE 的 src 目录:则仅对 MyLibrary 自己可见,外部目标不会继承这个路径。
适用场景:
大型项目:在复杂的项目中,每个库或模块可能都有自己的依赖和头文件路径。这时,target_include_directories 能提供更加精细的控制。
模块化开发:当项目采用模块化或库的方式进行构建时,每个模块的头文件路径通常是独立的。使用 target_include_directories 可以避免头文件路径之间的冲突,并且可以很好地管理库与库之间的依赖关系。
公共和私有头文件区分:当一个库需要向外部暴露部分头文件(比如库的 API),但不希望暴露其内部实现的头文件时,可以利用 PUBLIC 和 PRIVATE 来进行管理。
优点:
精确控制:每个目标可以独立管理自己的包含目录,减少不必要的全局污染。
作用域管理:通过 PRIVATE、PUBLIC 和 INTERFACE,可以更灵活地控制头文件路径的可见性,从而更好地管理模块间的依赖关系。
可维护性强:在大型项目中,能够清晰地定义每个模块的头文件依赖,提升代码的可维护性。
缺点:
语法复杂:相比 INCLUDE_DIRECTORIES,target_include_directories 的语法和概念相对复杂,特别是对于新手来说,可能需要更多的学习时间。
初期搭建繁琐:在项目早期搭建阶段,可能会觉得使用 target_include_directories 比较繁琐,因为需要为每个目标单独配置头文件路径。
4. INCLUDE_DIRECTORIES 和 target_include_directories 的对比
5. 最佳实践
优先使用 target_include_directories:在现代 CMake 项目中,尤其是模块化和大型项目,尽量使用 target_include_directories 来精确控制头文件的包含目录。它能提供更清晰的依赖关系管理,减少不必要的全局污染。
分清 PUBLIC、PRIVATE 和 INTERFACE:合理使用这三者来管理库的头文件依赖。PUBLIC 适合对外暴露的 API 头文件,PRIVATE 用于内部实现细节,INTERFACE 则适合不直接使用但会传递依赖的情况。
减少全局依赖:避免滥用 INCLUDE_DIRECTORIES,尤其是在大型项目中,全局的头文件路径可能会引发意想不到的依赖和冲突问题。
模块化设计:当项目逐渐复杂化,考虑将项目划分为多个独立模块,每个模块只依赖于自己需要的头文件,使用 target_include_directories 来管理这些模块的头文件路径。
结论
在 CMake 中,INCLUDE_DIRECTORIES 和 target_include_directories 都是管理头文件路径的重要工具,但它们适用于不同的场景。INCLUDE_DIRECTORIES 简单直观,但在大型项目中会变得难以维护。相反,target_include_directories 提供了更强大的控制能力,能够为每个目标精确地管理头文件路径。
在现代 CMake 项目中,推荐使用 target_include_directories,因为它能够更好地管理目标之间的依赖,并且有助于保持项目的清晰性和可维护性。
参考原文链接:https://blog.csdn.net/m0_74091159/article/details/143071566
二、cmake target_link_libraries
参考原文链接:cmake target_link_libraries 详解-CSDN博客
在 CMake 中,target_link_libraries 命令用于将一个或多个库链接到特定的目标上,如可执行文件或库。这个命令非常灵活,可以用来指定目标所需的所有依赖项,包括系统库、第三方库以及你自己的其他目标。
基本语法
target_link_libraries(target_name
item1
item2
...
)
target_name:目标名称,可以是通过 add_executable 或 add_library 定义的可执行文件或库的名称。
item1, item2, …:可以是以下类型之一,
库的名称(普通库):例如 pthread, dl, m 等;
变量:指向库路径或名称的变量,例如 ${ARMADILLO_LIBRARIES};
全路径:指定要链接的库的完整路径,例如 /usr/lib/libexample.so。
示例用法
假设你的项目结构如下:
project/
├── CMakeLists.txt
├── src/
│ ├── main.cpp
│ ├── file1.cpp
│ └── file2.cpp
└── lib/
├── libexample.a
└── libanother.so
以下是一个示例 CMakeLists.txt 文件,演示了如何使用 target_link_libraries 将不同类型的库链接到一个名为 MyExecutable 的可执行文件中:
cmake_minimum_required(VERSION 3.10)
project(MyProject)
# 设置 C++ 标准
set(CMAKE_CXX_STANDARD 11)
set(CMAKE_CXX_STANDARD_REQUIRED True)
# 添加可执行文件
add_executable(MyExecutable
src/main.cpp
src/file1.cpp
src/file2.cpp
)
# 查找并链接 Armadillo 库
find_package(Armadillo REQUIRED)
target_link_libraries(MyExecutable ${ARMADILLO_LIBRARIES})
# 链接系统库 pthread
target_link_libraries(MyExecutable pthread)
# 链接自定义的静态库 libexample.a 和动态库 libanother.so
target_link_libraries(MyExecutable
${CMAKE_SOURCE_DIR}/lib/libexample.a
${CMAKE_SOURCE_DIR}/lib/libanother.so
)
注意事项
库的查找和链接:
使用 find_package 命令来查找和配置依赖库,例如 find_package(Armadillo REQUIRED)。
使用变量 ${VARIABLE_NAME} 来引用查找到的库路径或名称,例如 ${ARMADILLO_LIBRARIES}。
系统库
可以直接使用库的名称,例如 pthread、dl、m 等,这些通常是系统自带的标准库。
自定义库:
如果库不是通过 find_package 找到的,你可以使用全路径来指定要链接的库,例如 ${CMAKE_SOURCE_DIR}/lib/libexample.a。
链接顺序:
在链接库时,通常静态库应该放在动态库之前,例如target_link_libraries(MyExecutable lib1 lib2 …)。
通过 target_link_libraries 命令,你可以方便地管理和链接你的项目所需的所有库,使得 CMake 构建系统能够正确地生成可执行文件或库,并确保它们能够正确地链接和运行。
原文链接:https://blog.csdn.net/qq_37805392/article/details/139721270
三、target_compile_definitions
target_compile_definitions指令用于为指定的目标设置预处理器定义(即编译时的宏定义)。这些定义会在编译时传递给编译器,影响编译器如何处理代码。
语法
target_compile_definitions(<target> [INTERFACE|PUBLIC|PRIVATE] <definition>...)
target:要应用这些定义的目标,通常是通过 add_executable 或 add_library 定义的目标。
INTERFACE:定义将仅应用于使用此目标的其他目标,不会应用于该目标本身。通常用于库的公共 API。
PUBLIC:定义将应用于该目标及所有链接到该目标的目标。适用于库的公共部分和使用该库的可执行文件或其他库。
PRIVATE:定义将仅应用于该目标,不会传播给其他依赖于该目标的目标。
示例
简单定义:
add_executable(my_executable main.cpp)
# Add a compile definition for this target
target_compile_definitions(my_executable PRIVATE MY_DEFINE)
在这个例子中,MY_DEFINE 宏将仅在 my_executable 目标中定义,编译 main.cpp 时,编译器会使用 -DMY_DEFINE 参数。
传递性定义:
add_library(my_library my_library.cpp)
target_compile_definitions(my_library PUBLIC MY_LIBRARY_DEFINE)
add_executable(my_executable main.cpp)
target_link_libraries(my_executable my_library)
在这个例子中,MY_LIBRARY_DEFINE 宏不仅在 my_library 中可用,还会传递到 my_executable 中,因为定义是 PUBLIC 的。
接口定义:
add_library(my_library INTERFACE)
target_compile_definitions(my_library INTERFACE MY_INTERFACE_DEFINE)
add_executable(my_executable main.cpp)
target_link_libraries(my_executable my_library)
这里,my_library 只是一个接口库,它本身不编译代码,但 MY_INTERFACE_DEFINE 宏将会在所有链接到 my_library 的目标中定义,即在 my_executable 中定义。
使用场景
条件编译: 根据不同的目标或构建配置启用或禁用代码块。
跨平台支持: 为不同的操作系统或编译器设置特定的预处理器定义。
库的API配置: 控制库的公共 API 暴露的功能。
原文链接:https://blog.csdn.net/qq_37805392/article/details/141337449
四、add_library、set_target_properties 详细配置
4.1)add_library
二进制对象库OBJECT的编译和依赖配置:
# 添加object对象 testa_obj =》 a.cpp.o b.cpp.o
add_library(testa_obj OBJECT a.cpp b.cpp)
带版本号的库符号链接:
project(test)
add_library(output SHARED output.cpp)
file(STRINGS "VERSION" LIB_VERSION)
set(LIB_OUTPUT_DIR "${PROJECT_SOURCE_DIR}/dist")
set_target_properties(output
PROPERTIES
VERSION ${LIB_VERSION} #设置带版本号的符号链接
SOVERSION ${LIB_VERSION} #设置带版本号的符号链接
LIBRARY_OUTPUT_DIRECTORY ${LIB_OUTPUT_DIR}
ARCHIVE_OUTPUT_DIRECTORY ${LIB_OUTPUT_DIR}
)
add_subdirectory(demo)
在 set_target_properties
中,加上了 SOVERSION 版本号,这样,在编译的时候,就会编译成带有版本号的动态库文件,然后创建一个不带有版本号的软链接,变成完成的库如下所示:
另,
1.NO_SONAME
ON 不产生动态库的符号链接
2.VERSION
1.0.1 动态库的版本号
3.SOVERSION
10 API的版本号
set_target_properties(A PROPERTIES VERSION "1.0.1"SOVERSION "10")
4.2)set_target_properties概述
原文链接:CMake4-指令10:set_target_properties【设置目标的一些属性来改变它们构建的方式】【用来设置输出的名称,对于动态库,还可以用来指定动态库版本和API版本】-CSDN博客
为一个目标设置属性。该命令的语法是列出所有你想要变更的文件,然后提供你想要设置的值。你能够使用任何你想要的属性/值对,并且在随后的代码中调用GET_TARGET_PROPERTY命令取出属性的值。
set_target_properties(target1 target2 ...
PROPERTIES
prop1 value1
prop2 value2 ...
)
这个命令是设置目标的属性,该命令的语法是列出想要更改的所有目标,然后提供接下来想要设置的值。
您可以使用该命令任何所需的键值对,然后使用get_property()或get_target_property()命令提取它。
【案例】
有如下例子:
1.建立一个静态库和动态库,提供HelloFunc函数供其他程序编程使用,HelloFunc,向终端输出Hello World字符串。
2.安装头文件与共享库。
3.编写一个程序,来使用创建的共享库(静态库和动态库)。
首先,新建一个目录 /home/code/test/build,创建MakeLists.txt
PROJECT(HELLOLIB)
# 通过在主工程文件CMakeLists.txt中修改ADD_SUBDIRECTORY (lib) 指令来指定一个编译输出位置;
# 指定本工程中静态库libhello.so生成的位置,即 build/lib;
ADD_SUBDIRECTORY(lib)
在lib目录下建立两个源文件hello.cpp与 hello.h
hello.cpp内容如下:
#include "hello.h"
using namespace std;
void HelloFunc(){
cout << "Hello World/n";
}
hello.h内容如下:
#ifndef HELLO_H
#define HELLO_H
#include <stdio.h>
void HelloFunc();
#endif
在lib目录下建立CMakeLists.txt,内容如下:
SET (LIBHELLO_SRC hello.cpp)
# SET (LIBRARY_OUTPUT_PATH ${PROJECT_BINARY_DIR}/lib)
# 添加动态库,关键词为shared,不需要写全称libhello.so,
# 只需要填写hello即可,cmake系统会自动为你生成 libhello.X
ADD_LIBRARY (hello SHARED ${LIBHELLO_SRC})
# 添加静态库,关键词为static,ADD_LIBRARY (hello STATIC ${LIBHELLO_SRC})
# 仍然用hello作为target名时,是不能成功创建所需的静态库的,
# 因为hello作为一个target是不能重名的, 故把上面的hello修改为hello_static
# 同理,你不需要写全libhello_static.a
# 只需要填写hello即可,cmake系统会自动为你生成 libhello_static.X
ADD_LIBRARY (hello_static STATIC ${LIBHELLO_SRC})
# 按照一般的习惯,静态库名字跟动态库名字应该是一致的,只是扩展名不同;
# 即:静态库名为 libhello.a; 动态库名为libhello.so ;
# 所以,希望 "hello_static" 在输出时,不是"hello_static",而是以"hello"的名字显示,故设置如下:
SET_TARGET_PROPERTIES (hello_static PROPERTIES OUTPUT_NAME "hello")
GET_TARGET_PROPERTY (OUTPUT_VALUE hello_static OUTPUT_NAME)
MESSAGE (STATUS "This is the hello_static OUTPUT_NAME: " ${OUTPUT_VALUE})
# cmake在构建一个新的target时,会尝试清理掉其他使用这个名字的库,
# 因此,在构建libhello.a时,就会清理掉libhello.so.
# 为了回避这个问题,比如再次使用SET_TARGET_PROPERTIES定义 CLEAN_DIRECT_OUTPUT属性。
SET_TARGET_PROPERTIES (hello_static PROPERTIES CLEAN_DIRECT_OUTPUT 1)
SET_TARGET_PROPERTIES (hello PROPERTIES CLEAN_DIRECT_OUTPUT 1)
# 按照规则,动态库是应该包含一个版本号的,
# VERSION指代:动态库版本,SOVERSION指代:API版本。
SET_TARGET_PROPERTIES (hello PROPERTIES VERSION 1.2 SOVERSION 1)
# 我们需要将libhello.a, libhello.so.x以及hello.h 安装 到系统目录,才能真正让其他人开发使用,
# 在本例中我们将hello的共享库安装到<prefix>/lib目录;
# 将hello.h安装<prefix>/include/hello目录。
INSTALL (TARGETS hello hello_static LIBRARY DESTINATION lib ARCHIVE DESTINATION lib)
INSTALL (FILES hello.h DESTINATION include/hello)
在build目录中
cmake ..
make
这时,你就可以在lib目录得到一个libhello.so,这就是我们期望的共享库。
如果你要指定libhello.so生成的位置,可以通过:
在主工程文件CMakeLists.txt中修改ADD_SUBDIRECTORY (lib) 指令来指定一个编译输出位置;
或者在 lib/CMakeLists.txt中添加SET (LIBRARY_OUTPUT_PATH <路径>) 来指定一个新的位置。
五、CMake生成Debug和Release目标程序时的一些配置
原文链接:https://blog.csdn.net/new9232/article/details/140567742
文章介绍
本文章将介绍在Windows和Linux平台,生成可执行程序时,如何设置Debug和Release的一些属性。
主要介绍如何设置目标程序的生成路径,以及运行时库的设置和目标程序版本号的设置。
Debug和Release模式
-O,-O1: 这两个命令的效果是一样的,目的都是在不影响编译速度的前提下,尽量采用一些优化算法降低代码大小和可执行代码的运行速度。
-O2:该优化选项会牺牲部分编译速度,除了执行-O1所执行的所有优化之外,还会采用几乎所有的目标配置支持的优化算法,用以提高目标代码的运行速度。
-O3: 该选项除了执行-O2所有的优化选项之外,一般都是采取很多向量化算法,提高代码的并行执行程度。
-Os: -O3的目标是宁愿增加目标代码的大小,也要拼命的提高运行速度,但是这个选项是在-O2的基础之上,尽量的降低目标代码的大小,这对于存储容量很小的设备来说非常重要。
config对应的优化
Debug: -g
Release: -O3
RelWithDebInfo: -O2 -g
MinSizeRel: -Os
Linux配置
在CMake中设置
set(CMAKE_BUILD_TYPE Debug)
构建时配置
cmake .. -D CMAKE_BUILD_TYPE=Release
Windows配置
Windows需要在编译时配置生成的类型,默认生成Debug
编译时配置命令。加-v可以看到调试信息。
cmake --build . --config Release -v
Debug和Release不同输出路径
执行程序和dll输出
RUNTIME_OUTPUT_DIRECTORY_<CONFIG>
lib和a库输出
ARCHIVE_OUTPUT_DIRECTORY_<CONFIG>
so动态库输出
LIBRARY_OUTPUT_DIRECTORY_<CONFIG>
pdb文件输出
PDB_OUTPUT_DIRECTORY_<CONFIG>
debug库名加后缀
set_target_properties(${target} PROPERTIES DEBUG_POSTFIX "d")
运行时库设置
MSVC_RUNTIME_LIBRARY
MultiThreaded(MT): 运行时库静态链接到目标文件。
MultiThreadedDLL(MD): 运行时库动态链接到目标文件。
MultiThreadedDebug(MTd): 运行时库静态链接到目标文件,加调试信息。
MultiThreadedDebugDLL(MDd): 运行时库动态链接到目标文件,加调试信息。
默认运行时库是MD
动态库设置版本号:
NO_SONAME: NO-不产生动态库的符号链接,OFF - 产生动态库的符号链接;
VERSION: 整体版本号;
SOVERSION: 某个库的版本,对可执行程序无效。
【示例】
示例一:设置编译目标的路径
目录结构
├── build_linux
├── build_win
├── CMakeLists.txt
├── include
│ ├── dlib.h
│ └── jlib.h
└── src
├── dlib.cpp
├── jlib.cpp
└── main.cpp
CMakeLists.txt 文件内容
# 指定CMake最低版本
cmake_minimum_required(VERSION 3.16)
# 构建项目的名称
project(cmake_demo)
# 包含头文件
include_directories(${PROJECT_SOURCE_DIR}/include)
# 打印编译类型
message("CMAKE_BUILD_TYPE: " ${CMAKE_BUILD_TYPE})
# 生成静态库
add_library(jlib STATIC ${PROJECT_SOURCE_DIR}/src/jlib.cpp)
set(OUT_LIB_PATH ${PROJECT_SOURCE_DIR}/lib)
set(OUT_EXE_PATH ${PROJECT_SOURCE_DIR}/exe)
# 设置静态库的输出
set_target_properties(jlib PROPERTIES
# 除了debug和release其他类型库的输出
ARCHIVE_OUTPUT_DIRECTORY ${OUT_LIB_PATH}/other
# debug库的输出
ARCHIVE_OUTPUT_DIRECTORY_DEBUG ${OUT_LIB_PATH}/debug
# release库的输出
ARCHIVE_OUTPUT_DIRECTORY_RELEASE ${OUT_LIB_PATH}/release
)
# 生成动态库
add_library(dlib SHARED ${PROJECT_SOURCE_DIR}/src/dlib.cpp)
# 设置动态库的输出
set_target_properties(dlib PROPERTIES
# windows lib文件输出
ARCHIVE_OUTPUT_DIRECTORY ${OUT_LIB_PATH}/other
ARCHIVE_OUTPUT_DIRECTORY_DEBUG ${OUT_LIB_PATH}/debug
ARCHIVE_OUTPUT_DIRECTORY_RELEASE ${OUT_LIB_PATH}/release
# windows dll文件输出
RUNTIME_OUTPUT_DIRECTORY ${OUT_EXE_PATH}/other
RUNTIME_OUTPUT_DIRECTORY_DEBUG ${OUT_EXE_PATH}/debug
RUNTIME_OUTPUT_DIRECTORY_RELEASE ${OUT_EXE_PATH}/release
# linux so 文件输出
LIBRARY_OUTPUT_DIRECTORY ${OUT_LIB_PATH}/other
LIBRARY_OUTPUT_DIRECTORY_DEBUG ${OUT_LIB_PATH}/debug
LIBRARY_OUTPUT_DIRECTORY_RELEASE ${OUT_LIB_PATH}/release
# windows pdb文件
PDB_OUTPUT_DIRECTORY ${OUT_LIB_PATH}/pdb
PDB_OUTPUT_DIRECTORY_DEBUG ${OUT_LIB_PATH}/pdb
# debug 版本加后缀
DEBUG_POSTFIX "d"
)
# 生成可执行程序
add_executable(res ${PROJECT_SOURCE_DIR}/src/main.cpp)
# 设置可执行程序的输出
set_target_properties(res PROPERTIES
RUNTIME_OUTPUT_DIRECTORY ${OUT_EXE_PATH}/other
RUNTIME_OUTPUT_DIRECTORY_DEBUG ${OUT_EXE_PATH}/debug
RUNTIME_OUTPUT_DIRECTORY_RELEASE ${OUT_EXE_PATH}/release
# 设置工作目录
# VS_DEBUGGER_WORKING_DIRECTORY ${OUT_EXE_PATH}
# 根据不同编译类型,设置不同工作目录
# $<IF:1,debug,release> 满足条件,返回debug
# $<IF:0,debug,release> 不满足条件,返回release
VS_DEBUGGER_WORKING_DIRECTORY $<IF:$<CONFIG:Debug>,debug,release>
# windows pdb文件
PDB_OUTPUT_DIRECTORY ${OUT_LIB_PATH}/pdb
PDB_OUTPUT_DIRECTORY_DEBUG ${OUT_LIB_PATH}/pdb
# debug 版本加后缀
DEBUG_POSTFIX "d"
)
生成Release版本
# Windows 平台在 build_win 下执行
cmake ..
cmake --build . --config Release
# Linux 平台在 build_linux 下执行
cmake .. -D CMAKE_BUILD_TYPE=Release
make
生成Debug版本
# Windows 平台在 build_win 下执行
cmake ..
cmake --build . --config Debug
# Linux 平台在 build_linux 下执行
cmake .. -D CMAKE_BUILD_TYPE=Debug
make
看下最终生成的库目录结构
├── exe
│ ├── debug
│ │ ├── dlibd.dll
│ │ ├── resd
│ │ ├── resd.exe
│ └── release
│ ├── dlib.dll
│ ├── res
│ └── res.exe
├── lib
├── debug
│ ├── dlibd.lib
│ ├── jlib.lib
│ ├── jlib.pdb
│ ├── libdlibd.so
│ └── libjlib.a
├── pdb
│ ├── dlibd.pdb
│ ├── Release
│ └── resd.pdb
└── release
├── dlib.lib
├── jlib.lib
├── libdlib.so
└── libjlib.a
示例二:运行时库设置
这里以Release为例。运行时库默认是动态链接,即 MD
cmake中可以设置为静态链接,即 MT
# 指定CMake最低版本
cmake_minimum_required(VERSION 3.16)
# 构建项目的名称
project(cmake_demo)
# 包含头文件
include_directories(${PROJECT_SOURCE_DIR}/include)
# 生成可执行程序
add_executable(res ${PROJECT_SOURCE_DIR}/src/main.cpp)
# 设置运行时库静态链接MT - 只设置Release
set_target_properties(res PROPERTIES
MSVC_RUNTIME_LIBRARY "MultiThreaded"
)
# 根据编译类型设置
# set_target_properties(res PROPERTIES
# MSVC_RUNTIME_LIBRARY "MultiThreaded$<$<CONFIG:Debug>:Debug>"
# )
编译命令
cmake ..
cmake --build . --config Release -v
先不设置,看下效果
输出信息是 MD
生成的可执行程序要依赖运行时库,且可执行比较小,为9kb
设置为MT,再看下效果
输出信息是MT
没有依赖运行时库,且大小变为 95kb
示例三:动态库设置版本号
cmake文件内容
# 指定CMake最低版本
cmake_minimum_required(VERSION 3.16)
# 构建项目的名称
project(cmake_demo)
# 包含头文件
include_directories(${PROJECT_SOURCE_DIR}/include)
# 生成动态库
add_library(dlib SHARED ${PROJECT_SOURCE_DIR}/src/dlib.cpp)
# 设置目标程序版本号
set_target_properties(dlib PROPERTIES
VERSION "1.0.0"
SOVERSION "6"
NO_SONAME OFF
)
编译结果
原文链接:https://blog.csdn.net/new9232/article/details/140567742
编辑