虎妞
小铃铛的妈妈,经常带小铃铛干坏事。当然也教会了小铃铛很多生存技能
include_directories
是CMake中的一个命令,其作用是向项目中添加包含目录(即头文件搜索路径)。当编译器编译项目中的源代码文件时,它会在这些指定的目录中查找#include
指令引用的头文件。
使用 include_directories
命令可以使编译器搜索项目内外的附加目录,从而找到所需的头文件。这对于跨目录的项目结构或者使用第三方库非常有用。
下面是一个include_directories
的使用示例:
1 | include_directories(includes /path/to/external/includes) |
在这个例子中,includes
是项目内的一个目录,指的是相对于当前CMakeLists.txt
文件所在目录的相对路径。/path/to/external/includes
是系统中某个外部库头文件的绝对路径。这条命令将这两个目录添加到编译器的头文件搜索路径中。
一旦使用了include_directories
,它会影响所有随后定义的目标(例如使用add_executable
或者add_library
定义的可执行文件或库)。如果你希望对特定目标设置包含目录而不影响其他的,应使用target_include_directories
命令,它提供了更细粒度的控制。
例如:
1 | add_executable(MyExecutable main.cpp) |
在这个例子中,MyExecutable
仅会包含includes
目录作为私有依赖,这意味着这个包含目录仅对MyExecutable
可见,不会影响到其他目标。
通常建议使用target_include_directories
而非include_directories
,因为前者更符合现代CMake的目标属性设置方式,允许更好的封装性和可重用性
在 Java 中,”submodule” 这个术语并不是官方的编程概念,而是通常用于描述较大项目中的组织结构,尤其是在使用 Maven 或 Gradle 这样的构建工具时。这些构建工具允许你创建多模块(multi-module)项目,其中每个模块可以有自己的构建生命周期和依赖管理。
如果将 CMake 中的 add_subdirectory
命令与 Java 多模块项目的概念进行比较,那么可以说它们在概念上是相似的。add_subdirectory
允许你将一个目录(可以认为是一个模块或子项目)添加到主项目的构建过程中。这个目录通常包含它自己的 CMakeLists.txt
文件,定义了如何构建该目录中的代码。
在 Java 的多模块项目中,每个模块也会有自己的构建配置文件(例如 Maven 的 pom.xml
),定义了模块的构建过程和依赖。
例如,在 Maven 中,你的项目结构可能如下:
1 | project/ |
父项目的 pom.xml
文件会包含对所有子模块的引用:
1 | <modules> |
将 Maven 的多模块项目和 CMake 中的 add_subdirectory
命令进行类比,它们都有以下相似之处:
总之,尽管 CMake 和 Java 构建工具(如 Maven 或 Gradle)在技术细节上不同,add_subdirectory
与 Java 多模块项目的概念在组织和管理大型代码基础方面确实有一定的相似性。
在 CMake 中,并没有一个默认机制来自动查找源码文件。CMake 需要你在 CMakeLists.txt
配置文件中显式地指定源码文件。这意味着 CMake 不会去猜测或自动探测你的源码文件所在;你必须明确告诉 CMake 需要编译哪些文件。
通常,你会在 CMakeLists.txt
文件中使用 add_executable
或者 add_library
命令来定义编译目标,并显式地列出构成该目标的所有源码文件。例如:
1 | add_executable(MyExecutable main.cpp foo.cpp bar.cpp) |
在这个例子中,MyExecutable
是目标的名字,main.cpp
、foo.cpp
和 bar.cpp
是明确指定的源码文件。
如果你有一组相对固定的源码文件,你可以简单地将它们全部列出。然而,对于较大的项目或者源码文件经常变动的情况,逐一列出所有文件可能会变得繁琐。为了简化这个过程,CMake 提供了一些命令来帮助你查找和指定源码文件,这些命令包括 aux_source_directory
和 file(GLOB ...)
。虽然这些命令可以帮助收集源码文件,但它们通常不是最佳实践,因为它们无法跟踪文件系统中的变化(例如,当你添加或删除文件时,CMake 不会自动更新)。
例如,使用 file(GLOB ...)
可以根据模式匹配查找文件:
1 | file(GLOB MY_SOURCES "*.cpp") # 不推荐用于源文件 |
在这个例子中,MY_SOURCES
变量会包含当前目录下所有后缀为 .cpp
的源码文件。
总结来说,CMake 需要你在 CMakeLists.txt
中显式指定源码文件,它不会默认查找源码文件。你可以使用 file(GLOB ...)
或 aux_source_directory
这样的命令来收集源码文件,但最好的实践仍然是显式地列出所有源码文件,尤其是对于那些希望确保构建系统适应性和可维护性的项目来说。
在C++中,extern
关键字用于指定变量或函数的定义在其他的文件中。这样可以在多个文件之间共享变量或函数。主要用途是用于提供对全局变量和函数的访问,尤其是在大型项目中多文件共用的场景。
extern
用法主要有以下几种场景:
声明全局变量而不定义它: extern
用来在一个文件中声明一个全局变量,而不是定义它。真正的定义会在别的地方。这样做的目的是为了在多个文件中共享这个变量。
1 | // file1.cpp |
以上代码中,file1.cpp
定义了一个全局变量myGlobal
,而file2.cpp
使用extern
来声明这个全局变量,以便可以在file2.cpp
中访问file1.cpp
中定义的myGlobal
。
声明函数: 一般情况下,函数在C++中默认是extern
的,即使没有显式声明。但是你也可以显式地声明它,特别是在你想要强调函数可以在其他文件中被访问时。
1 | // file1.cpp |
与static
关键字的对比: extern
和static
在用于变量声明时有着对立的含义。static
用于限制变量或函数的链接作用域到定义它的文件,而extern
则表明变量或函数可以在多个文件间共享。
使用extern "C"
防止C++的名称修饰: 当你想要在C++代码中调用C语言编写的函数时,你需要防止C++编译器对这些函数名进行名称修饰(name mangling),因为C编译器不会这么做。extern "C"
可以用来告诉C++编译器不要修饰这些特定的函数名。
1 | extern "C" { |
或者用于单个函数声明:
1 | extern "C" void cFunction(); |
在实际开发过程中,使用extern
关键字可以帮助组织跨多个文件的代码,方便代码管理和模块化设计。但是,过度使用全局变量可能会引起程序设计上的问题,如数据封装不足、线程安全问题等,因此应当谨慎使用。