方式一: add_executable
例如, 在 Qt Creator 中,使用 CMake 构建项目时,默认情况下头文件不会显示在项目浏览器中。要让头文件显示出来,你可以在 CMakeLists.txt 文件中添加相应的头文件。
以下是一个简单的示例,展示了如何将头文件添加到 CMakeLists.txt 中:
cmake_minimum_required(VERSION 3.5) project(MyQtProject LANGUAGES CXX) set(CMAKE_CXX_STANDARD 11) set(CMAKE_CXX_STANDARD_REQUIRED ON) find_package(Qt5 COMPONENTS Core Widgets REQUIRED) # 添加源文件和头文件 set(SOURCE_FILES main.cpp mainwindow.cpp ) set(HEADER_FILES mainwindow.h ) # 如果有 UI 文件或资源文件,也可以在此处添加 set(UI_FILES mainwindow.ui ) set(QRC_FILES resources.qrc ) qt5_wrap_ui(UI_HEADERS ${UI_FILES}) qt5_add_resources(QRC_RESOURCES ${QRC_FILES}) add_executable(MyQtProject ${SOURCE_FILES} ${HEADER_FILES} ${UI_HEADERS} ${QRC_RESOURCES}) target_link_libraries(MyQtProject Qt5::Core Qt5::Widgets)
在这个示例中,我们首先定义了一个变量 HEADER_FILES
,其中包含了我们想要在项目中显示的头文件。然后,在 add_executable()
函数中添加这些头文件,以便它们能够显示在 Qt Creator 的项目浏览器中。
同样,我们还可以添加 UI 文件和资源文件,这样它们也会出现在项目浏览器中。这是通过 qt5_wrap_ui()
和 qt5_add_resources()
函数完成的。
遍历头文件
为了遍历 ${CMAKE_SOURCE_DIR}/include
目录下的所有头文件,你可以使用 file(GLOB_RECURSE ...)
命令将它们添加到一个变量中,而不是使用 set()
。这里是一个例子:
file(GLOB_RECURSE HEADER_FILES "${CMAKE_SOURCE_DIR}/include/*.h")
这个命令会递归地遍历 ${CMAKE_SOURCE_DIR}/include
目录,并将所有找到的 .h
文件添加到 HEADER_FILES
变量中。之后,你可以像之前的回答中展示的那样,将 HEADER_FILES
添加到 add_executable()
函数中。
但是,需要注意的是,使用 GLOB_RECURSE
可能会导致一些问题,因为当你添加或删除头文件时,CMake 可能不会自动重新运行。在这种情况下,你需要手动重新运行 CMake 以更新项目。因此,在某些情况下,显式地列出所有的头文件可能是更好的做法。
构建原理
将头文件添加到可执行文件(add_executable()
)实际上并不会影响编译过程。头文件主要是为了在编译期间提供类型声明、函数原型和其他信息。编译器在处理源文件时,会通过源文件中的 #include
指令找到并处理这些头文件。
将头文件添加到 add_executable()
的主要目的是让这些头文件在某些集成开发环境(IDE)中(如 Qt Creator)显示出来。这样可以方便地在 IDE 中浏览和编辑头文件。但是,这并不会改变编译过程。
实际上,当你编译一个项目时,编译器只处理源文件(如 .cpp
文件)。这些源文件中的 #include
指令会让编译器去查找并处理相应的头文件。因此,即使你没有将头文件添加到 add_executable()
中,只要源文件正确地包含了这些头文件,它们仍然会在编译期间被处理。
注意
如果你已经使用 file()
和 add_executable()
将头文件添加到了可执行文件,通常情况下,编译器仍然需要知道头文件的位置。这时你需要使用 include_directories()
或者 target_include_directories()
来指定头文件的路径。
这两个命令的区别在于:
include_directories()
: 这个命令会将给定目录添加到所有目标的头文件搜索路径中。这意味着在项目中定义的所有目标都将使用这个路径来查找头文件。target_include_directories()
: 这个命令允许你为特定目标指定头文件搜索路径。这样,只有指定的目标会使用这个路径来查找头文件。
以下是一个使用 target_include_directories()
的例子:
cmake_minimum_required(VERSION 3.5) project(MyProject LANGUAGES CXX) set(CMAKE_CXX_STANDARD 11) set(CMAKE_CXX_STANDARD_REQUIRED ON) file(GLOB_RECURSE HEADER_FILES "${CMAKE_SOURCE_DIR}/include/*.h") file(GLOB_RECURSE SOURCE_FILES "${CMAKE_SOURCE_DIR}/src/*.cpp") add_executable(MyProject ${HEADER_FILES} ${SOURCE_FILES}) # 指定头文件搜索路径 target_include_directories(MyProject PRIVATE ${CMAKE_SOURCE_DIR}/include)
在这个例子中,我们使用 file()
和 add_executable()
将头文件和源文件添加到了可执行文件。然后,我们使用 target_include_directories()
为 MyProject
目标指定了头文件搜索路径,这样编译器就能找到这些头文件。这里使用了 PRIVATE
关键字,表示这个头文件路径仅对 MyProject
目标有效。
所以,即使你已经将头文件添加到了可执行文件,你仍然需要使用 include_directories()
或 target_include_directories()
来指定头文件的位置。
方式二: source_group
将头文件添加到 add_executable()
是解决 IDE 环境中 CMake 项目不显示头文件的一种常用方法。但是,也有其他方法可以实现类似的效果,例如使用源文件组(source groups)。
源文件组允许你在 IDE 中对文件进行分组和分类。在 CMake 中,你可以使用 source_group()
命令来创建源文件组。以下是一个示例:
cmake_minimum_required(VERSION 3.5) project(MyQtProject LANGUAGES CXX) set(CMAKE_CXX_STANDARD 11) set(CMAKE_CXX_STANDARD_REQUIRED ON) find_package(Qt5 COMPONENTS Core Widgets REQUIRED) # 添加源文件和头文件 set(SOURCE_FILES main.cpp mainwindow.cpp ) set(HEADER_FILES mainwindow.h ) # 创建源文件组 source_group(TREE "${CMAKE_CURRENT_SOURCE_DIR}" FILES ${SOURCE_FILES} ${HEADER_FILES}) # 如果有 UI 文件或资源文件,也可以在此处添加 set(UI_FILES mainwindow.ui ) set(QRC_FILES resources.qrc ) qt5_wrap_ui(UI_HEADERS ${UI_FILES}) qt5_add_resources(QRC_RESOURCES ${QRC_FILES}) add_executable(MyQtProject ${SOURCE_FILES} ${HEADER_FILES} ${UI_HEADERS} ${QRC_RESOURCES}) target_link_libraries(MyQtProject Qt5::Core Qt5::Widgets)
在这个示例中,我们使用 source_group()
命令创建了一个源文件组,将源文件和头文件分组到一起。TREE
参数表示我们希望从当前源文件目录开始组织文件。这将使得在 IDE(如 Qt Creator)中显示头文件成为可能。
然而,不同 IDE 对 CMake 的支持程度不同,因此这些方法在不同的 IDE 中可能会有所差异。总的来说,将头文件添加到 add_executable()
是一种更通用的方法。
结语
不管采用哪种方式,都不会影响编译过程。头文件主要是在编译时为源文件提供类型声明、函数原型和其他信息。头文件会在源文件中通过 #include
指令被包含,这些方法主要是为了在 IDE 中方便地显示和管理头文件。