iwtbf: target_include_directories(&{PROJECT_BINARY_DIR})
是什么
GitHub Copilot: target_include_directories
是 CMake 中的一个命令,用于为目标添加包含目录。&{PROJECT_BINARY_DIR}
是一个变量,表示项目的二进制目录。
语法如下:
target_include_directories(<target> [SYSTEM] [AFTER|BEFORE] <INTERFACE|PUBLIC|PRIVATE> [items1...])
例如:
target_include_directories(my_target PRIVATE ${PROJECT_BINARY_DIR})
这行代码的意思是将 ${PROJECT_BINARY_DIR}
目录添加到 my_target
目标的私有包含路径中。
iwtbf: target_include_directories(Tutorial PUBLIC "${PROJECT_BINARY_DIR}")
GitHub Copilot: 这行代码的意思是将 ${PROJECT_BINARY_DIR}
目录添加到 Tutorial
目标的公共包含路径中。
具体解释如下:
target_include_directories
是 CMake 命令,用于为目标添加包含目录。Tutorial
是目标名称。PUBLIC
指定包含目录的可见性,表示该目录对目标及其依赖项都是可见的。"${PROJECT_BINARY_DIR}"
是包含目录的路径,表示项目的二进制目录。
完整示例:
target_include_directories(Tutorial PUBLIC "${PROJECT_BINARY_DIR}")
这行代码将 ${PROJECT_BINARY_DIR}
目录添加到 Tutorial
目标的公共包含路径中,使得该目录中的头文件可以被 Tutorial
及其依赖项访问。
iwtbf: 什么是项目的二进制目录
GitHub Copilot: 项目的二进制目录(PROJECT_BINARY_DIR
)是指 CMake 构建系统生成的所有构建文件(如编译后的目标文件、可执行文件、库文件等)所在的目录。这个目录通常是在运行 CMake 配置命令时指定的。
例如,在使用 CMake 构建项目时,通常会执行以下步骤:
-
创建一个构建目录:
mkdir build cd build
-
运行 CMake 配置命令,指定源代码目录和生成的二进制文件目录:
cmake ../path/to/source
在这个例子中,build
目录就是项目的二进制目录,CMake 会在这个目录中生成所有的构建文件。
在 CMakeLists.txt 文件中,可以使用 PROJECT_BINARY_DIR
变量来引用这个目录。例如:
message("Binary directory: ${PROJECT_BINARY_DIR}")
这行代码会输出项目的二进制目录路径。
iwtbf: 公共包含路径是什么
GitHub Copilot: 公共包含路径是指在构建系统中指定的包含目录,这些目录中的头文件可以被目标及其依赖项访问。在 CMake 中,通过 target_include_directories
命令可以为目标添加包含目录,并指定其可见性(INTERFACE
、PUBLIC
或 PRIVATE
)。
INTERFACE
:仅对依赖该目标的其他目标可见。PUBLIC
:对目标本身及其依赖项都可见。PRIVATE
:仅对目标本身可见。
例如:
target_include_directories(Tutorial PUBLIC "${PROJECT_SOURCE_DIR}/include")
这行代码将 ${PROJECT_SOURCE_DIR}/include
目录添加到 Tutorial
目标的公共包含路径中,使得该目录中的头文件可以被 Tutorial
及其依赖项访问。
总结:
- 公共包含路径是对目标及其依赖项都可见的包含目录。
- 在 CMake 中,通过
target_include_directories
命令并使用PUBLIC
关键字来指定公共包含路径。
iwtbf: 包含路径是什么
GitHub Copilot: 包含路径是编译器在编译源代码时查找头文件(.h
或 .hpp
文件)的位置。通过指定包含路径,编译器可以找到并包含这些头文件,从而使得源代码能够正确编译。
在 CMake 中,可以使用 target_include_directories
命令为目标添加包含路径。包含路径可以分为三种可见性:INTERFACE
、PUBLIC
和 PRIVATE
。
INTERFACE
:仅对依赖该目标的其他目标可见。PUBLIC
:对目标本身及其依赖项都可见。PRIVATE
:仅对目标本身可见。
例如:
target_include_directories(MyTarget PUBLIC "${CMAKE_SOURCE_DIR}/include")
这行代码将 ${CMAKE_SOURCE_DIR}/include
目录添加到 MyTarget
目标的公共包含路径中,使得该目录中的头文件可以被 MyTarget
及其依赖项访问。
总结:
- 包含路径是编译器查找头文件的位置。
- 在 CMake 中,可以使用
target_include_directories
命令为目标添加包含路径,并指定其可见性。
iwtbf: configure_file(TutorialConfig.h.in TutorialConfig.h)
GitHub Copilot: configure_file
是 CMake 中的一个命令,用于从模板文件生成配置文件。它会读取一个输入文件(通常带有 .in
后缀),替换其中的变量,然后将结果写入到输出文件中。
例如:
configure_file(TutorialConfig.h.in TutorialConfig.h)
这行代码的作用是:
- 读取
TutorialConfig.h.in
文件。 - 替换文件中的变量(例如
${PROJECT_NAME}
、${VERSION}
等)。 - 将替换后的内容写入到
TutorialConfig.h
文件中。
假设 TutorialConfig.h.in
文件内容如下:
#define PROJECT_NAME "@PROJECT_NAME@"
#define VERSION "@VERSION@"
在 CMakeLists.txt 中定义变量:
set(PROJECT_NAME "Tutorial")
set(VERSION "1.0")
执行 configure_file
后,生成的 TutorialConfig.h
文件内容如下:
#define PROJECT_NAME "Tutorial"
#define VERSION "1.0"
总结:
configure_file
命令用于从模板文件生成配置文件。- 它会替换模板文件中的变量,并将结果写入到指定的输出文件中。
iwtbf: 模板文件和配置文件的位置如何决定的
GitHub Copilot: 在使用 configure_file
命令时,模板文件和配置文件的位置是相对于当前的 CMake 构建目录和源目录来决定的。
-
模板文件的位置:
模板文件的位置通常是相对于 CMakeLists.txt 文件所在的源目录。你需要在configure_file
命令中指定模板文件的相对路径或绝对路径。例如,如果你的模板文件
TutorialConfig.h.in
位于项目的源目录中,你可以这样指定:configure_file(${CMAKE_SOURCE_DIR}/TutorialConfig.h.in ${CMAKE_BINARY_DIR}/TutorialConfig.h)
-
配置文件的位置:
配置文件的位置通常是相对于 CMake 的二进制目录(构建目录)。你需要在configure_file
命令中指定配置文件的相对路径或绝对路径。例如,如果你希望生成的配置文件
TutorialConfig.h
位于构建目录中,你可以这样指定:configure_file(${CMAKE_SOURCE_DIR}/TutorialConfig.h.in ${CMAKE_BINARY_DIR}/TutorialConfig.h)
完整示例:
# 设置项目名称和版本
set(PROJECT_NAME "Tutorial")
set(VERSION "1.0")
# 配置文件生成
configure_file(${CMAKE_SOURCE_DIR}/TutorialConfig.h.in ${CMAKE_BINARY_DIR}/TutorialConfig.h)
在这个示例中:
- 模板文件
TutorialConfig.h.in
位于源目录中。 - 生成的配置文件
TutorialConfig.h
位于构建目录中。
总结:
- 模板文件的位置通常是相对于源目录。
- 配置文件的位置通常是相对于构建目录。
- 可以使用
${CMAKE_SOURCE_DIR}
和${CMAKE_BINARY_DIR}
变量来指定源目录和构建目录的路径。
iwtbf: configure_file()需要两个文件已经存在,无法创建文件,对吗
GitHub Copilot: 不对。configure_file()
命令只需要模板文件已经存在,而不需要输出文件已经存在。configure_file()
会读取模板文件的内容,进行变量替换,然后生成输出文件。如果输出文件不存在,configure_file()
会自动创建它。
例如:
configure_file(TutorialConfig.h.in ${CMAKE_BINARY_DIR}/TutorialConfig.h)
在这个例子中:
TutorialConfig.h.in
是模板文件,必须已经存在。${CMAKE_BINARY_DIR}/TutorialConfig.h
是输出文件,如果不存在,configure_file()
会自动创建它。
总结:
configure_file()
需要模板文件已经存在。configure_file()
会自动创建输出文件,如果输出文件不存在。
iwtbf: Tutorial_VERSION_MAJOR和Tutorial_VERSION_MINOR是什么
GitHub Copilot: Tutorial_VERSION_MAJOR
和 Tutorial_VERSION_MINOR
通常是用于表示项目的主版本号和次版本号的变量。这些变量可以在 CMakeLists.txt 文件中定义,并在配置文件中使用。
例如,在 CMakeLists.txt 文件中,你可以这样定义版本号:
# 设置项目名称和版本号
set(Tutorial_VERSION_MAJOR 1)
set(Tutorial_VERSION_MINOR 0)
然后,你可以在模板文件(例如 TutorialConfig.h.in
)中使用这些变量:
// TutorialConfig.h.in
#define TUTORIAL_VERSION_MAJOR @Tutorial_VERSION_MAJOR@
#define TUTORIAL_VERSION_MINOR @Tutorial_VERSION_MINOR@
使用 configure_file
命令生成配置文件:
configure_file(TutorialConfig.h.in ${CMAKE_BINARY_DIR}/TutorialConfig.h)
生成的 TutorialConfig.h
文件将包含替换后的版本号:
// TutorialConfig.h
#define TUTORIAL_VERSION_MAJOR 1
#define TUTORIAL_VERSION_MINOR 0
总结:
Tutorial_VERSION_MAJOR
和Tutorial_VERSION_MINOR
是用于表示项目主版本号和次版本号的变量。- 这些变量可以在 CMakeLists.txt 文件中定义,并在模板文件中使用,通过
configure_file
命令生成配置文件。
iwtbf: cmake --build .
GitHub Copilot: cmake --build .
是一个命令,用于在当前目录中构建项目。它会调用生成的构建系统(例如 Makefile、Ninja、Visual Studio 解决方案等)来编译和链接项目。
使用步骤如下:
-
创建构建目录(如果还没有创建):
mkdir build cd build
-
运行 CMake 配置命令,生成构建系统文件:
cmake ..
-
构建项目:
cmake --build .
在这个例子中:
mkdir build
和cd build
创建并进入构建目录。cmake ..
命令在构建目录中运行 CMake 配置,生成构建系统文件。cmake --build .
命令在当前构建目录中构建项目。
总结:
cmake --build .
命令用于在当前目录中构建项目。- 它会调用生成的构建系统来编译和链接项目。
iwtbf: cmake ..\Step1\
GitHub Copilot: cmake ..\Step1\
命令用于在当前构建目录中运行 CMake 配置,并指定源代码目录为 ..\Step1\
。这会生成构建系统文件(例如 Makefile、Ninja 文件、Visual Studio 解决方案等),这些文件用于后续的构建过程。
具体步骤如下:
-
创建并进入构建目录:
mkdir build cd build
-
运行 CMake 配置命令,指定源代码目录为
..\Step1\
:cmake ..\Step1\
在这个例子中:
mkdir build
和cd build
创建并进入构建目录。cmake ..\Step1\
命令在构建目录中运行 CMake 配置,指定源代码目录为..\Step1\
。
总结:
cmake ..\Step1\
命令用于在当前构建目录中运行 CMake 配置,并指定源代码目录为..\Step1\
。- 这会生成构建系统文件,用于后续的构建过程。
iwtbf: library是什么
GitHub Copilot: 在软件开发中,库(library)是一组预编译的代码集合,可以被多个程序或模块共享和重用。库通常包含函数、类、数据结构和其他资源,开发者可以在自己的程序中调用这些库中的功能,而无需重新编写代码。
库可以分为两种主要类型:
-
静态库(Static Library):
- 静态库在编译时被链接到应用程序中,生成一个单一的可执行文件。
- 静态库的文件扩展名通常是
.lib
(Windows)或.a
(Unix/Linux)。
-
动态库(Dynamic Library):
- 动态库在运行时被加载到应用程序中,可以被多个程序共享。
- 动态库的文件扩展名通常是
.dll
(Windows)、.so
(Unix/Linux)或.dylib
(macOS)。
在 CMake 中,可以使用 add_library
命令来创建库。例如:
# 创建一个静态库
add_library(MyStaticLib STATIC mylib.cpp)
# 创建一个动态库
add_library(MySharedLib SHARED mylib.cpp)
然后,可以使用 target_link_libraries
命令将库链接到目标:
# 将库链接到可执行文件
add_executable(MyExecutable main.cpp)
target_link_libraries(MyExecutable MyStaticLib MySharedLib)
总结:
- 库是一组预编译的代码集合,可以被多个程序共享和重用。
- 库分为静态库和动态库。
- 在 CMake 中,可以使用
add_library
命令创建库,并使用target_link_libraries
命令将库链接到目标。
iwtbf: 库由什么组成
GitHub Copilot: 库(library)通常由以下几个部分组成:
-
头文件(Header Files):
- 头文件通常以
.h
或.hpp
作为扩展名。 - 头文件包含函数、类、宏和数据结构的声明。
- 头文件用于定义库的接口,供其他程序使用。
- 头文件通常以
-
源文件(Source Files):
- 源文件通常以
.c
、.cpp
、.cc
等作为扩展名。 - 源文件包含函数、类和其他代码的实现。
- 源文件在编译时生成目标文件(
.o
或.obj
),然后这些目标文件被打包成库文件。
- 源文件通常以
-
库文件(Library Files):
- 库文件是编译后的二进制文件,包含了源文件的实现。
- 静态库文件通常以
.lib
(Windows)或.a
(Unix/Linux)作为扩展名。 - 动态库文件通常以
.dll
(Windows)、.so
(Unix/Linux)或.dylib
(macOS)作为扩展名。
-
元数据和配置文件(Metadata and Configuration Files):
- 有些库可能包含元数据和配置文件,用于描述库的版本、依赖关系、编译选项等。
- 这些文件可以帮助构建系统(如 CMake)正确地使用和链接库。
示例:
假设我们有一个名为 MyLibrary
的库,它包含以下文件:
-
头文件:
MyLibrary.h
-
源文件:
MyLibrary.cpp
-
静态库文件:
MyLibrary.lib
(Windows)libMyLibrary.a
(Unix/Linux)
-
动态库文件:
MyLibrary.dll
(Windows)libMyLibrary.so
(Unix/Linux)libMyLibrary.dylib
(macOS)
在 CMake 中,可以这样定义和使用这个库:
# 定义库
add_library(MyLibrary STATIC MyLibrary.cpp)
# 或者
add_library(MyLibrary SHARED MyLibrary.cpp)
# 将库链接到可执行文件
add_executable(MyExecutable main.cpp)
target_link_libraries(MyExecutable MyLibrary)
总结:
- 库由头文件、源文件、库文件以及可能的元数据和配置文件组成。
- 头文件定义接口,源文件实现功能,库文件包含编译后的二进制代码。
- 在 CMake 中,可以使用
add_library
和target_link_libraries
命令来定义和使用库。
iwtbf: 将库链接到可执行文件是什么意思
GitHub Copilot: 将库链接到可执行文件是指在编译过程中,将库中的函数、类和其他符号与可执行文件中的引用进行匹配和绑定的过程。这个过程确保可执行文件在运行时能够正确调用库中的功能。
链接过程分为两种类型:
-
静态链接(Static Linking):
- 在编译时,将静态库的代码复制到可执行文件中。
- 生成的可执行文件包含所有依赖的库代码,因此不需要在运行时依赖外部库文件。
- 优点:可执行文件独立,不需要额外的库文件。
- 缺点:可执行文件体积较大,更新库时需要重新编译可执行文件。
-
动态链接(Dynamic Linking):
- 在运行时,将动态库加载到内存中,并将其符号与可执行文件中的引用进行匹配。
- 生成的可执行文件较小,但在运行时需要依赖外部的动态库文件。
- 优点:可执行文件体积较小,更新库时不需要重新编译可执行文件。
- 缺点:需要在运行时确保动态库文件存在。
在 CMake 中,可以使用 target_link_libraries
命令将库链接到可执行文件。例如:
假设我们有一个名为 MyLibrary
的库和一个名为 MyExecutable
的可执行文件:
# 定义库
add_library(MyLibrary STATIC MyLibrary.cpp)
# 或者
add_library(MyLibrary SHARED MyLibrary.cpp)
# 定义可执行文件
add_executable(MyExecutable main.cpp)
# 将库链接到可执行文件
target_link_libraries(MyExecutable MyLibrary)
在这个例子中:
add_library
命令定义了一个名为MyLibrary
的库。add_executable
命令定义了一个名为MyExecutable
的可执行文件。target_link_libraries
命令将MyLibrary
库链接到MyExecutable
可执行文件。
总结:
- 将库链接到可执行文件是指在编译过程中,将库中的符号与可执行文件中的引用进行匹配和绑定。
- 链接过程分为静态链接和动态链接。
- 在 CMake 中,可以使用
target_link_libraries
命令将库链接到可执行文件。
iwtbf: Once the library is created, it is connected to our executable target with target_include_directories() and target_link_libraries().
为什么要用到target_include_directories()
GitHub Copilot: target_include_directories()
命令用于指定目标的包含目录(include directories),这些目录包含头文件(header files),编译器在编译源文件时会在这些目录中查找头文件。
当你创建一个库并将其链接到可执行文件时,通常需要包含库的头文件,以便在可执行文件的源代码中使用库的功能。target_include_directories()
命令确保编译器能够找到这些头文件。
例如,假设你有一个库 MyLibrary
,它的头文件位于 include
目录中:
# 定义库
add_library(MyLibrary STATIC MyLibrary.cpp)
# 指定库的包含目录
target_include_directories(MyLibrary PUBLIC ${CMAKE_SOURCE_DIR}/include)
然后,你有一个可执行文件 MyExecutable
,需要使用 MyLibrary
库:
# 定义可执行文件
add_executable(MyExecutable main.cpp)
# 将库链接到可执行文件
target_link_libraries(MyExecutable MyLibrary)
在这个例子中:
target_include_directories(MyLibrary PUBLIC ${CMAKE_SOURCE_DIR}/include)
命令指定了MyLibrary
库的包含目录。PUBLIC
关键字表示包含目录对MyLibrary
及其依赖项(如MyExecutable
)都是可见的。- 当编译
MyExecutable
时,编译器会在include
目录中查找头文件。
总结:
target_include_directories()
命令用于指定目标的包含目录,确保编译器能够找到头文件。- 在将库链接到可执行文件时,使用
target_include_directories()
命令可以使可执行文件的源代码中正确引用库的头文件。
# iwtbf: target_include_directories()执行目标可以是什么
GitHub Copilot: target_include_directories()
命令的执行目标可以是任何由 add_library()
或 add_executable()
命令创建的目标。这些目标可以是静态库、动态库或可执行文件。
具体来说,target_include_directories()
命令用于为指定的目标添加包含目录,使得在编译该目标时,编译器能够找到并包含这些目录中的头文件。
以下是一些示例,展示了如何使用 target_include_directories()
命令:
示例 1:为库添加包含目录
# 定义一个静态库
add_library(MyLibrary STATIC MyLibrary.cpp)
# 为库添加包含目录
target_include_directories(MyLibrary PUBLIC ${CMAKE_SOURCE_DIR}/include)
示例 2:为可执行文件添加包含目录
# 定义一个可执行文件
add_executable(MyExecutable main.cpp)
# 为可执行文件添加包含目录
target_include_directories(MyExecutable PRIVATE ${CMAKE_SOURCE_DIR}/include)
示例 3:为可执行文件链接库并添加包含目录
# 定义一个静态库
add_library(MyLibrary STATIC MyLibrary.cpp)
# 为库添加包含目录
target_include_directories(MyLibrary PUBLIC ${CMAKE_SOURCE_DIR}/include)
# 定义一个可执行文件
add_executable(MyExecutable main.cpp)
# 将库链接到可执行文件
target_link_libraries(MyExecutable MyLibrary)
# 为可执行文件添加包含目录(如果需要额外的包含目录)
target_include_directories(MyExecutable PRIVATE ${CMAKE_SOURCE_DIR}/extra_include)
在这些示例中:
MyLibrary
是一个静态库目标。MyExecutable
是一个可执行文件目标。target_include_directories()
命令为这些目标添加了包含目录。
关键字 PUBLIC
、PRIVATE
和 INTERFACE
用于指定包含目录的可见性:
PUBLIC
:包含目录对目标本身及其依赖项都可见。PRIVATE
:包含目录仅对目标本身可见。INTERFACE
:包含目录仅对依赖该目标的其他目标可见。
总结:
target_include_directories()
命令的执行目标可以是由add_library()
或add_executable()
创建的任何目标。- 该命令用于为目标添加包含目录,使得编译器能够找到头文件。
add_subdirectory()的格式是什么
add_subdirectory()
的格式如下:
add_subdirectory(<source_dir> [<binary_dir>] [EXCLUDE_FROM_ALL])
参数说明
<source_dir>
:必需。包含CMakeLists.txt
文件的子目录路径。通常相对于当前 CMakeLists.txt 文件的位置。<binary_dir>
:可选。子目录的二进制输出目录。默认情况下,二进制目录与源目录同名。EXCLUDE_FROM_ALL
:可选。如果指定,子目录不会包含在默认构建目标中。
示例
基本用法
假设项目结构如下:
ProjectRoot/
├── CMakeLists.txt
└── src/
├── CMakeLists.txt
└── main.cpp
ProjectRoot/CMakeLists.txt
cmake_minimum_required(VERSION 3.10)
project(MyProject)
add_subdirectory(src)
ProjectRoot/src/CMakeLists.txt
add_executable(MyExecutable main.cpp)
指定二进制目录
add_subdirectory(src build/src)
src
:源目录。build/src
:二进制目录。
排除子目录
add_subdirectory(src EXCLUDE_FROM_ALL)
此命令添加 src
子目录,但不会将其包含在 all
目标中。
总结
add_subdirectory()
用于将子目录添加到构建过程中。- 可以指定源目录和可选的二进制目录。
- 通过
EXCLUDE_FROM_ALL
控制是否包含在默认构建目标中。
默认的src的二进制输出目录是ProjectRoot/src吗
默认情况下,add_subdirectory(src)
不会将生成的二进制文件直接输出到 ProjectRoot/src
目录。相反,CMake 使用二进制目录(build directory)来存放所有生成的构建文件,以保持源代码目录的整洁。
具体说明
-
构建目录与源代码目录分离:
通常,推荐使用外部构建(out-of-source build),即在源代码目录之外创建一个单独的构建目录。例如:ProjectRoot/ ├── CMakeLists.txt ├── src/ │ ├── CMakeLists.txt │ └── main.cpp └── build/
-
使用
add_subdirectory
:
在ProjectRoot/CMakeLists.txt
中添加子目录:cmake_minimum_required(VERSION 3.10) project(MyProject) add_subdirectory(src)
-
默认的二进制输出目录:
当你在build
目录中运行cmake ..
时,CMake 会在build
目录下为每个子目录创建相应的二进制输出目录。ProjectRoot/ ├── CMakeLists.txt ├── src/ │ ├── CMakeLists.txt │ └── main.cpp └── build/ ├── CMakeCache.txt ├── CMakeFiles/ └── src/ ├── CMakeFiles/ └── Makefile
在这种情况下,
src
子目录的二进制输出目录为build/src
,而不是ProjectRoot/src
。 -
指定自定义二进制目录(可选):
如果需要,可以在add_subdirectory
命令中指定自定义的二进制目录。例如:add_subdirectory(src build/src_bin)
这样,
src
子目录的二进制输出目录将是build/src_bin
。
总结
- 默认行为:
add_subdirectory(src)
会在二进制目录中创建一个与源目录同名的子目录(例如build/src
),而不是将二进制文件放在源代码目录ProjectRoot/src
中。 - 推荐实践:使用外部构建目录(例如
build/
)来分离源代码和构建文件,保持项目结构清晰。 - 自定义二进制目录:可以通过在
add_subdirectory
中指定第二个参数来自定义二进制目录的位置。
这样做有助于维护项目的整洁性,避免在源代码目录中混杂生成的构建文件。
add_subdirectory()的功能是什么
add_subdirectory()
是 CMake 中的一个命令,用于将子目录添加到当前的构建过程。通过使用 add_subdirectory()
,你可以组织项目结构,将不同的模块或组件分开管理,确保构建系统能够正确地识别和构建这些子项目。
格式
add_subdirectory(<source_dir> [<binary_dir>] [EXCLUDE_FROM_ALL])
参数说明
<source_dir>
:必需。包含CMakeLists.txt
文件的子目录路径。路径通常相对于当前CMakeLists.txt
文件的位置。<binary_dir>
:可选。指定子目录的二进制输出目录。如果不指定,默认会在构建目录中创建一个与源目录同名的子目录。EXCLUDE_FROM_ALL
:可选。如果指定,子目录不会包含在默认的all
目标中。这意味着该子目录只有在明确指定时才会被构建。
功能
-
组织项目结构:
- 将项目划分为多个模块或组件,每个模块有自己的源代码和
CMakeLists.txt
文件,便于维护和管理。
- 将项目划分为多个模块或组件,每个模块有自己的源代码和
-
继承和扩展设置:
- 子目录可以继承父目录中的设置,如编译选项、包含目录等,同时可以根据需要添加或覆盖这些设置。
-
控制构建流程:
- 通过
EXCLUDE_FROM_ALL
等选项,可以灵活控制哪些子目录在默认构建时被包含,哪些不被包含。
- 通过
示例
假设项目结构如下:
ProjectRoot/
├── CMakeLists.txt
├── src/
│ ├── CMakeLists.txt
│ └── main.cpp
└── lib/
├── CMakeLists.txt
└── library.cpp
ProjectRoot/CMakeLists.txt
cmake_minimum_required(VERSION 3.10)
project(MyProject)
# 添加 src 子目录
add_subdirectory(src)
# 添加 lib 子目录,并排除在默认构建之外
add_subdirectory(lib EXCLUDE_FROM_ALL)
ProjectRoot/src/CMakeLists.txt
add_executable(MyExecutable main.cpp)
# 链接库(假设库名为 MyLibrary)
target_link_libraries(MyExecutable PRIVATE MyLibrary)
ProjectRoot/lib/CMakeLists.txt
add_library(MyLibrary STATIC library.cpp)
# 指定包含目录
target_include_directories(MyLibrary PUBLIC ${CMAKE_SOURCE_DIR}/include)
使用场景
- 大型项目:将项目划分为多个子模块,每个子模块负责不同的功能,便于团队协作和代码管理。
- 复用代码:通过子目录管理独立的库或组件,实现代码复用。
- 第三方库集成:将第三方库的源码添加为子目录,便于统一管理和构建。
注意事项
- 路径正确性:确保
<source_dir>
路径正确,避免因路径错误导致找不到CMakeLists.txt
文件。 - 依赖管理:子目录之间的依赖关系需要通过
target_link_libraries()
等命令显式管理,确保构建顺序正确。 - 构建目录分离:推荐使用外部构建(out-of-source build)方式,即在源代码目录之外创建一个独立的构建目录,以保持源代码目录的整洁。
总结
add_subdirectory()
命令在 CMake 中起到了组织和管理项目结构的重要作用。通过合理使用 add_subdirectory()
,可以将复杂的项目划分为多个独立且可维护的子模块,提高项目的可扩展性和可维护性。
add_subdirectory()之后是否可以直接使用subdirectory中定义的内容
是的,在使用 add_subdirectory()
之后,可以直接使用子目录中定义的内容,如目标(库、可执行文件)和变量。add_subdirectory()
会将子目录的 CMakeLists.txt
包含到主项目中,使得子目录中定义的目标和设置在主项目中可见和可用。
示例
假设项目结构如下:
ProjectRoot/
├── CMakeLists.txt
├── src/
│ ├── CMakeLists.txt
│ └── main.cpp
└── lib/
├── CMakeLists.txt
└── MyLibrary.cpp
ProjectRoot/CMakeLists.txt
cmake_minimum_required(VERSION 3.10)
project(MyProject)
# 添加子目录 lib
add_subdirectory(lib)
# 添加子目录 src
add_subdirectory(src)
ProjectRoot/lib/CMakeLists.txt
# 定义静态库 MyLibrary
add_library(MyLibrary STATIC MyLibrary.cpp)
# 指定包含目录
target_include_directories(MyLibrary PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}/include)
ProjectRoot/src/CMakeLists.txt
# 定义可执行文件 MyExecutable
add_executable(MyExecutable main.cpp)
# 链接库 MyLibrary
target_link_libraries(MyExecutable PRIVATE MyLibrary)
ProjectRoot/src/main.cpp
#include "MyLibrary.h"
int main() {
myFunction();
return 0;
}
ProjectRoot/lib/MyLibrary.cpp
#include "MyLibrary.h"
#include <iostream>
void myFunction() {
std::cout << "Hello from MyLibrary!" << std::endl;
}
ProjectRoot/lib/include/MyLibrary.h
#pragma once
void myFunction();
解释
-
添加子目录:
- 主
CMakeLists.txt
使用add_subdirectory(lib)
和add_subdirectory(src)
将lib
和src
子目录添加到构建过程中。
- 主
-
定义库:
- 在
lib/CMakeLists.txt
中,使用add_library(MyLibrary STATIC MyLibrary.cpp)
定义了一个名为MyLibrary
的静态库。 - 使用
target_include_directories(MyLibrary PUBLIC ...)
指定了库的头文件目录,使得链接该库的目标可以找到相应的头文件。
- 在
-
定义可执行文件并链接库:
- 在
src/CMakeLists.txt
中,使用add_executable(MyExecutable main.cpp)
定义了一个可执行文件。 - 使用
target_link_libraries(MyExecutable PRIVATE MyLibrary)
将MyLibrary
库链接到MyExecutable
可执行文件。
- 在
-
使用库:
- 在
main.cpp
中包含了MyLibrary.h
并调用了myFunction()
,这是子目录lib
中定义的函数。
- 在
注意事项
-
目标可见性:
- 使用
PUBLIC
、PRIVATE
或INTERFACE
来设置包含目录和链接库的可见性。例如,上述示例中MyLibrary
使用PUBLIC
,意味着链接MyLibrary
的目标(如MyExecutable
)也可以访问其包含目录。
- 使用
-
构建顺序:
add_subdirectory()
确保子目录在主目录的构建过程中被正确处理,允许主目录使用子目录中定义的目标。
-
变量作用域:
- 子目录中的变量默认不会影响父目录,除非使用
set(... CACHE ...)
或其他方法显式传递变量。
- 子目录中的变量默认不会影响父目录,除非使用
总结
通过 add_subdirectory()
,可以将子目录中的目标和设置集成到主项目中,从而实现模块化和代码复用。这样,子目录中定义的库、可执行文件等内容可以在主项目及其他子目录中直接使用和链接。
链接库使用的是源文件(.cpp),包含目录使用的是头文件(.hpp)对吗
是的,基本上可以这样理解:
- 链接库 使用的是库文件(如
.lib
、.a
、.dll
、.so
等),这些库文件是由源文件(.cpp
)编译生成的。 - 包含目录 指定的是存放头文件(如
.h
、.hpp
)的路径,编译器在编译时会在这些目录中查找头文件。
详细说明
-
源文件 (.cpp):
- 包含库的实现代码。
- 在编译过程中,这些源文件会被编译成目标文件(
.o
或.obj
),然后打包成库文件(静态库.lib
或.a
,动态库.dll
、.so
等)。
-
头文件 (.h, .hpp):
- 包含库的接口声明,如函数声明、类定义等。
- 通过
target_include_directories()
指定包含目录,确保在使用库的代码中可以正确引用这些头文件。
-
库文件:
- 静态库(如
.lib
、.a
):在编译时链接到可执行文件中,生成的可执行文件包含所有需要的库代码。 - 动态库(如
.dll
、.so
):在运行时加载,生成的可执行文件依赖于外部的库文件。
- 静态库(如
示例
假设有一个库 MyLibrary
,结构如下:
MyLibrary/
├── include/
│ └── MyLibrary.hpp
└── src/
└── MyLibrary.cpp
CMakeLists.txt:
# 定义库
add_library(MyLibrary STATIC src/MyLibrary.cpp)
# 指定包含目录
target_include_directories(MyLibrary PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}/include)
使用库的可执行文件:
MyExecutable/
├── main.cpp
└── CMakeLists.txt
MyExecutable/CMakeLists.txt:
add_executable(MyExecutable main.cpp)
target_link_libraries(MyExecutable PRIVATE MyLibrary)
main.cpp:
#include "MyLibrary.hpp"
int main() {
myFunction();
return 0;
}
总结
- 源文件 (.cpp) 用于实现库的功能,编译后生成库文件。
- 头文件 (.h, .hpp) 用于声明库的接口,通过包含目录让使用者能够访问这些声明。
- 链接库 时,使用的是编译生成的库文件,而不是源文件。
这样,编译器在编译可执行文件时,会通过包含目录找到头文件,使用库文件中的实现代码进行链接,确保程序能够正确调用库中的功能。
既然add_subdirectory()是将子目录的CMakeLists.txt包含到主项目中,那理论上是否可以直接将子目录中的CMakeLists.txt中的内容进行路径方面的修正后直接替换顶层CMakeLists.txt中相应的add_subdirectory(),然后删除子目录中的CMakeLists.txt从而整个项目仅保留一个顶层CMakeLists.txt
是的,理论上,您可以将子目录中的 CMakeLists.txt
文件的内容整合到顶层的 CMakeLists.txt
中,调整相关的路径,然后删除子目录中的 CMakeLists.txt
,使整个项目仅保留一个顶层的 CMakeLists.txt
。然而,这种做法在实际项目中有一些优缺点需要考虑。
如何操作
-
整合内容:
- 打开子目录中的
CMakeLists.txt
文件。 - 复制其中定义的库、可执行文件、包含目录等命令。
- 将这些内容粘贴到顶层的
CMakeLists.txt
中,确保调整所有相对路径,使其相对于顶层目录正确。
- 打开子目录中的
-
调整路径:
- 更新所有源文件和头文件的路径。例如,将
src/main.cpp
调整为subdir/src/main.cpp
,如果子目录在顶层目录中的位置有所不同。
- 更新所有源文件和头文件的路径。例如,将
-
删除子目录的
CMakeLists.txt
:- 确保所有必要的配置都已迁移到顶层
CMakeLists.txt
后,可以删除子目录中的CMakeLists.txt
文件。
- 确保所有必要的配置都已迁移到顶层
-
移除
add_subdirectory()
:- 从顶层
CMakeLists.txt
中删除add_subdirectory(subdir)
命令,因为子目录的配置已被整合。
- 从顶层
示例
假设项目结构如下:
ProjectRoot/
├── CMakeLists.txt
├── src/
│ ├── CMakeLists.txt
│ └── main.cpp
└── lib/
├── CMakeLists.txt
└── MyLibrary.cpp
原顶层 CMakeLists.txt
:
cmake_minimum_required(VERSION 3.10)
project(MyProject)
add_subdirectory(src)
add_subdirectory(lib)
子目录 src/CMakeLists.txt
:
add_executable(MyExecutable main.cpp)
target_link_libraries(MyExecutable PRIVATE MyLibrary)
子目录 lib/CMakeLists.txt
:
add_library(MyLibrary STATIC MyLibrary.cpp)
target_include_directories(MyLibrary PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}/include)
整合后的顶层 CMakeLists.txt
:
cmake_minimum_required(VERSION 3.10)
project(MyProject)
# 定义库
add_library(MyLibrary STATIC lib/MyLibrary.cpp)
target_include_directories(MyLibrary PUBLIC ${CMAKE_SOURCE_DIR}/lib/include)
# 定义可执行文件并链接库
add_executable(MyExecutable src/main.cpp)
target_link_libraries(MyExecutable PRIVATE MyLibrary)
优缺点分析
优点
-
简单性:
- 对于小型项目,使用单一的
CMakeLists.txt
文件可能更为简洁,减少了文件数量。
- 对于小型项目,使用单一的
-
易于理解:
- 所有构建配置集中在一个文件中,便于新手或初学者理解项目的构建流程。
缺点
-
可维护性差:
- 随着项目规模的增大,单一的顶层
CMakeLists.txt
会变得臃肿,难以管理和维护。
- 随着项目规模的增大,单一的顶层
-
缺乏模块化:
- 分离的子目录和独立的
CMakeLists.txt
文件有助于模块化设计,每个模块或组件可以独立开发和测试。
- 分离的子目录和独立的
-
团队协作不便:
- 在多团队成员协作的情况下,分离的
CMakeLists.txt
文件有助于团队成员各自负责不同模块,减少冲突。
- 在多团队成员协作的情况下,分离的
-
复用性降低:
- 独立的子目录和
CMakeLists.txt
文件更容易被其他项目复用,通过add_subdirectory()
直接引入。
- 独立的子目录和
推荐做法
虽然将所有内容整合到顶层 CMakeLists.txt
中在技术上是可行的,但在实际开发中,推荐保持使用 add_subdirectory()
并保留子目录中的 CMakeLists.txt
文件。这种方式有助于:
- 模块化和分层设计:每个子模块或组件有独立的构建配置,便于管理和扩展。
- 提高可维护性:更清晰的项目结构,便于定位和修改特定模块的构建设置。
- 增强复用性:子模块可以更方便地被其他项目引用和复用。
总结
虽然可以通过调整路径和整合 CMakeLists.txt
内容,将子目录的配置合并到顶层文件中,但这种做法在项目规模增大或需要模块化管理时会带来诸多不便。保持子目录中的 CMakeLists.txt
文件,并使用 add_subdirectory()
来组织项目结构,是更为推荐和实践的构建方式,尤其适用于中大型项目和团队协作开发。
我注意到add_subdirectory(src) add_subdirectory(lib)中lib是在src后面添加的,但是src中的CMakeLIsts却使用了lib中的内容
您观察到的问题确实涉及到 add_subdirectory()
的调用顺序在 CMake 项目中的重要性。让我们详细解释一下这一点,以及如何正确组织项目结构以避免问题。
问题描述
假设您的顶层 CMakeLists.txt
如下:
cmake_minimum_required(VERSION 3.10)
project(MyProject)
add_subdirectory(src)
add_subdirectory(lib)
而在 src/CMakeLists.txt
中,您尝试链接 lib
中定义的库:
add_executable(MyExecutable main.cpp)
target_link_libraries(MyExecutable PRIVATE MyLibrary)
这种情况下,由于 lib
子目录在 src
之后添加,CMake 在处理 src/CMakeLists.txt
时,尚未定义 MyLibrary
库,导致链接失败或找不到目标错误。
原因分析
CMake 的解析顺序是自上而下的。当 CMake 处理 add_subdirectory()
时,会立即进入并解析指定子目录中的 CMakeLists.txt
。因此:
-
add_subdirectory(src)
被调用:- 进入
src/CMakeLists.txt
。 - 尝试链接
MyLibrary
,但lib
子目录尚未添加,MyLibrary
尚未定义。 - 导致错误。
- 进入
-
add_subdirectory(lib)
之后被调用:- 定义
MyLibrary
。 - 但是在
src
中已经尝试链接,出错已发生。
- 定义
解决方案
要确保 src
子目录能够正确链接 lib
中定义的库,您需要先添加 lib
子目录,再添加 src
子目录。这样,lib
中的库在 src
之前被定义,src
中的 CMakeLists.txt
能够正确引用 MyLibrary
。
修改后的顶层 CMakeLists.txt
:
cmake_minimum_required(VERSION 3.10)
project(MyProject)
# 先添加 lib 子目录,确保 MyLibrary 被定义
add_subdirectory(lib)
# 再添加 src 子目录,允许 src 链接到 MyLibrary
add_subdirectory(src)
目录结构示例
假设项目结构如下:
ProjectRoot/
├── CMakeLists.txt
├── src/
│ ├── CMakeLists.txt
│ └── main.cpp
└── lib/
├── CMakeLists.txt
└── MyLibrary.cpp
lib/CMakeLists.txt
:
# 定义库 MyLibrary
add_library(MyLibrary STATIC MyLibrary.cpp)
# 指定包含目录
target_include_directories(MyLibrary PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}/include)
src/CMakeLists.txt
:
# 定义可执行文件 MyExecutable
add_executable(MyExecutable main.cpp)
# 链接库 MyLibrary
target_link_libraries(MyExecutable PRIVATE MyLibrary)
总结
-
调用顺序重要:在顶层
CMakeLists.txt
中,先添加被依赖的子目录(如lib
),再添加依赖它的子目录(如src
)。 -
目标可见性:使用
PUBLIC
、PRIVATE
或INTERFACE
关键字在target_include_directories()
和target_link_libraries()
中正确设置目标的可见性,确保依赖关系正确传递。 -
模块化管理:保持子目录中的
CMakeLists.txt
文件独立有助于模块化管理,便于维护和扩展项目。
进一步优化建议
-
使用相对路径:确保在不同子目录中引用路径时使用相对于顶层或当前子目录的相对路径,避免路径混乱。
-
保持清晰的依赖关系:明确各模块之间的依赖关系,避免循环依赖。例如,
lib
不应该依赖于src
,以确保编译顺利进行。 -
分离构建目录:推荐使用 外部构建目录(out-of-source build),保持源代码目录的整洁。例如:
mkdir build cd build cmake .. cmake --build .
通过遵循上述原则,您可以确保 CMake 项目结构清晰、依赖关系明确,避免因 add_subdirectory()
顺序问题导致的构建错误。
源文件与头文件在同一个目录的情况下,使用这些源文件构成的library和链接了该library的可执行文件是否需要进行target_include_directirues()以包含这些头文件
在源文件和头文件位于同一个目录的情况下,是否需要使用 target_include_directories()
来包含这些头文件,取决于头文件的使用场景和编译器的查找路径。
情况分析
-
库的头文件在同一目录:
- 如果头文件和源文件在同一个目录,并且头文件仅在库的源文件中使用,那么在定义库时不需要额外的
target_include_directories()
。
- 如果头文件和源文件在同一个目录,并且头文件仅在库的源文件中使用,那么在定义库时不需要额外的
-
可执行文件需要访问库的头文件:
- 如果可执行文件需要访问库的头文件(例如,在可执行文件的源代码中包含库的头文件),则需要使用
target_include_directories()
将库的头文件目录添加到可执行文件的包含路径中。
- 如果可执行文件需要访问库的头文件(例如,在可执行文件的源代码中包含库的头文件),则需要使用
示例
假设项目结构如下:
ProjectRoot/
├── CMakeLists.txt
├── src/
│ ├── MyLibrary.cpp
│ ├── MyLibrary.hpp
│ └── main.cpp
顶层 CMakeLists.txt
:
cmake_minimum_required(VERSION 3.10)
project(MyProject)
add_subdirectory(src)
src/CMakeLists.txt
:
# 定义库 MyLibrary
add_library(MyLibrary MyLibrary.cpp)
# 定义可执行文件 MyExecutable
add_executable(MyExecutable main.cpp)
# 链接库 MyLibrary 到 MyExecutable
target_link_libraries(MyExecutable PRIVATE MyLibrary)
# 如果 MyExecutable 需要访问 MyLibrary.hpp,则需要添加包含目录
target_include_directories(MyExecutable PRIVATE ${CMAKE_CURRENT_SOURCE_DIR})
src/MyLibrary.hpp
:
#pragma once
void myFunction();
src/MyLibrary.cpp
:
#include "MyLibrary.hpp"
#include <iostream>
void myFunction() {
std::cout << "Hello from MyLibrary!" << std::endl;
}
src/main.cpp
:
#include "MyLibrary.hpp"
int main() {
myFunction();
return 0;
}
解释
-
定义库:
add_library(MyLibrary MyLibrary.cpp)
定义了一个名为MyLibrary
的库,包含MyLibrary.cpp
源文件。
-
定义可执行文件:
add_executable(MyExecutable main.cpp)
定义了一个名为MyExecutable
的可执行文件,包含main.cpp
源文件。
-
链接库:
target_link_libraries(MyExecutable PRIVATE MyLibrary)
将MyLibrary
库链接到MyExecutable
可执行文件。
-
包含目录:
target_include_directories(MyExecutable PRIVATE ${CMAKE_CURRENT_SOURCE_DIR})
将src
目录添加到MyExecutable
的包含路径中,使得main.cpp
能够找到并包含MyLibrary.hpp
头文件。
总结
- 库的头文件在同一目录:如果头文件仅在库的源文件中使用,不需要额外的
target_include_directories()
。 - 可执行文件需要访问库的头文件:如果可执行文件需要包含库的头文件,则需要使用
target_include_directories()
将头文件目录添加到可执行文件的包含路径中。
通过这种方式,可以确保编译器在编译可执行文件时能够正确找到并包含库的头文件,从而避免编译错误。
target_link_libraries()的格式是很忙
target_link_libraries()
是 CMake 中用于将库链接到目标(如可执行文件或另一个库)的命令。它的格式和用法如下:
格式
target_link_libraries(<target> [<PRIVATE|PUBLIC|INTERFACE>] <library>...)
参数说明
<target>
:必需。要链接库的目标名称(如可执行文件或库)。<PRIVATE|PUBLIC|INTERFACE>
:可选。指定链接库的可见性和传播方式。PRIVATE
:仅对当前目标可见,不传播到依赖该目标的其他目标。PUBLIC
:对当前目标和依赖该目标的其他目标都可见。INTERFACE
:仅对依赖该目标的其他目标可见,当前目标不可见。
<library>
:必需。要链接的库或目标,可以是多个。
示例
假设项目结构如下:
ProjectRoot/
├── CMakeLists.txt
├── src/
│ ├── CMakeLists.txt
│ ├── MyLibrary.cpp
│ ├── MyLibrary.hpp
│ └── main.cpp
顶层 CMakeLists.txt
:
cmake_minimum_required(VERSION 3.10)
project(MyProject)
add_subdirectory(src)
src/CMakeLists.txt
:
# 定义库 MyLibrary
add_library(MyLibrary MyLibrary.cpp)
# 定义可执行文件 MyExecutable
add_executable(MyExecutable main.cpp)
# 链接库 MyLibrary 到 MyExecutable
target_link_libraries(MyExecutable PRIVATE MyLibrary)
# 如果 MyExecutable 需要访问 MyLibrary.hpp,则需要添加包含目录
target_include_directories(MyExecutable PRIVATE ${CMAKE_CURRENT_SOURCE_DIR})
解释
-
定义库:
add_library(MyLibrary MyLibrary.cpp)
定义了一个名为MyLibrary
的库,包含MyLibrary.cpp
源文件。
-
定义可执行文件:
add_executable(MyExecutable main.cpp)
定义了一个名为MyExecutable
的可执行文件,包含main.cpp
源文件。
-
链接库:
target_link_libraries(MyExecutable PRIVATE MyLibrary)
将MyLibrary
库链接到MyExecutable
可执行文件。PRIVATE
关键字表示MyLibrary
仅对MyExecutable
可见,不传播到依赖MyExecutable
的其他目标。
可见性关键字
-
PRIVATE:
- 仅对当前目标可见,不传播到依赖该目标的其他目标。
- 适用于库仅在当前目标内部使用的情况。
-
PUBLIC:
- 对当前目标和依赖该目标的其他目标都可见。
- 适用于库在当前目标和依赖该目标的其他目标中都需要使用的情况。
-
INTERFACE:
- 仅对依赖该目标的其他目标可见,当前目标不可见。
- 适用于库仅在依赖该目标的其他目标中使用的情况。
示例:使用 PUBLIC
如果 MyLibrary
的头文件需要在 MyExecutable
和依赖 MyExecutable
的其他目标中都可见,可以使用 PUBLIC
:
target_link_libraries(MyExecutable PUBLIC MyLibrary)
总结
target_link_libraries()
用于将库链接到目标。- 格式为
target_link_libraries(<target> [<PRIVATE|PUBLIC|INTERFACE>] <library>...)
。 - 可见性关键字
PRIVATE
、PUBLIC
和INTERFACE
控制库的可见性和传播方式。 - 根据具体需求选择合适的可见性关键字,确保库的正确链接和使用。
一个源文件被包含为一个库之后,这个源文件#include的头文件也在这个库里吗
当一个源文件被包含为一个库之后,这个源文件 #include
的头文件是否也在这个库里,取决于头文件的具体位置和库的组织方式。通常情况下,头文件和源文件是分开管理的,头文件用于声明接口,源文件用于实现功能。
头文件和库的关系
-
头文件的作用:
- 头文件(
.h
或.hpp
)包含函数、类、宏和数据结构的声明。 - 头文件用于定义库的接口,供其他代码使用。
- 头文件(
-
源文件的作用:
- 源文件(
.c
或.cpp
)包含函数和类的实现。 - 源文件被编译成目标文件(
.o
或.obj
),然后打包成库文件(静态库.lib
或.a
,动态库.dll
、.so
等)。
- 源文件(
库的组织方式
通常,库的头文件和源文件是分开管理的。头文件提供接口,源文件实现功能。头文件通常放在一个 include
目录中,而源文件放在一个 src
目录中。
示例
假设项目结构如下:
ProjectRoot/
├── CMakeLists.txt
├── include/
│ └── MyLibrary.hpp
└── src/
├── CMakeLists.txt
└── MyLibrary.cpp
include/MyLibrary.hpp
:
#pragma once
void myFunction();
src/MyLibrary.cpp
:
#include "MyLibrary.hpp"
#include <iostream>
void myFunction() {
std::cout << "Hello from MyLibrary!" << std::endl;
}
src/CMakeLists.txt
:
# 定义库 MyLibrary
add_library(MyLibrary MyLibrary.cpp)
# 指定包含目录
target_include_directories(MyLibrary PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}/../include)
顶层 CMakeLists.txt
:
cmake_minimum_required(VERSION 3.10)
project(MyProject)
add_subdirectory(src)
解释
-
头文件和源文件分开管理:
- 头文件
MyLibrary.hpp
放在include
目录中。 - 源文件
MyLibrary.cpp
放在src
目录中。
- 头文件
-
定义库:
add_library(MyLibrary MyLibrary.cpp)
定义了一个名为MyLibrary
的库,包含MyLibrary.cpp
源文件。
-
指定包含目录:
target_include_directories(MyLibrary PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}/../include)
将include
目录添加到MyLibrary
的包含路径中,使得编译器能够找到MyLibrary.hpp
头文件。
总结
- 当一个源文件被包含为一个库之后,这个源文件
#include
的头文件通常不在库文件中,而是单独管理的。 - 头文件用于声明接口,源文件用于实现功能。
- 通过
target_include_directories()
命令,可以将头文件所在的目录添加到库的包含路径中,使得编译器能够找到并包含这些头文件。 - 这种组织方式有助于模块化管理和代码复用,确保头文件和源文件的清晰分离。