当前位置: 首页 > article >正文

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

编辑


http://www.kler.cn/a/376223.html

相关文章:

  • 记一次OpenEuler Linux磁盘分区表损坏的数据恢复
  • nginx 配置ssl_dhparam好处及缺点
  • vscode 扩展Cline、Continue的差别?
  • gesp(C++五级)(4)洛谷:B3872:[GESP202309 五级] 巧夺大奖
  • 赤店商城系统点餐小程序多门店分销APP共享股东h5源码saas账号独立版全插件全开源
  • 【Spring Boot 应用开发】-04-01 自动配置-数据源-连接池
  • Docker | 常用的容器container命令
  • Linux开发讲课47--- 详解 Linux 中的虚拟文件系统
  • chatgpt需求与提示词
  • 算法实现 - 选择排序(Selection sort) - 理解版
  • STM32 HAL库 SPI驱动1.3寸 OLED屏幕
  • Django目录结构最佳实践
  • git常见用法【持续补充……】
  • 河南高校大数据实验室建设案例分享
  • Qt 实战(10)模型视图 | 10.6、自定义 QTableView
  • [MRCTF2020]PYWebsite1
  • jenkins 构建报错 Cannot run program “sh”
  • Uniapp的H5以及App不支持后端传FormData类型参数的解决方案
  • C#笔记——委托(2)
  • 浅谈人工智能之DB-GPT环境安装
  • SpringBoot3使用MyBatisPlus时遇到的问题 Invalid bean definition with name
  • python编程-类的特殊方法
  • Rust 力扣 - 2653. 滑动子数组的美丽值
  • 使用Docker Compose搭建多服务应用
  • Matlab车牌识别课程设计报告模板(附源代码)
  • Flutter鸿蒙next 封装 Dio 网络请求详解:登录身份验证与免登录缓存