最近经常要编译github上clone下来的工程,大部分是基于cmake构建。要是自己想改一改,加一加就需要自己写CMakelist.txt。其中有几个问题始终云里雾里,花了很多时间才搞定。现在主要对找包的问题总结一下。
GNU编译器套件gcc可以编译C,C++,Fortran,Java等等编程语言。当程序只有一个源文件时,直接用gcc就可以编译。
刚进入 Apple,Chris Lattner 就大展身手:首先在 OpenGL 小组做代码优化,把 LLVM 运行时的编译架在 OpenGL 栈上,这样 OpenGL 栈能够产出更高效率的图形代码。如果显卡足够高级,这些代码会直接扔入 GPU 执行
同时,LLVM 的链接优化被直接加入到 Apple 的代码链接器上,而 LLVM-GCC 也被同步到使用 GCC4.0 代码。
Clang是LLVM 的前端,可以用来编译 C,C++,ObjectiveC 等语言。Clang 则是以 LLVM 为后端的一款高效易用,并且与IDE 结合很好的编译前端
makefile,即自动化编译脚本,提供了编译和链接的指令,由make工具实现这些指令。makefile中包括了调用gcc或其他编译器编译源代码的命令。
CMake是一个构建生成器,提供了强大的领域特定语言(DSL)来描述构建系统应该实现的功能。这是CMake的主要优势之一,它允许使用相同的CMake脚本集生成平台原生构建系统。CMake软件工具集,使开发人员可以完全控制给定项目的生命周期:
• CMake是描述如何在所有主要硬件和操作系统上配置、构建和安装项目,无论是构建可执行文件、库,还是两者都要构建。
• CTest定义测试、测试套件,并设置应该如何执行。
• CPack为打包需求提供了DSL。
• CDash将项目的测试结果在面板中展示。
CMakeList.txt(组态档)为cmake提供了生成makefile的指令。类似makefile与make工具的关系。其中组态档是由人工完成的。
当有Message.cpp 和Message.h文件后, 先把它们编译成一个库,而不是直接编译成可执行文件
1.创建目标-静态库。库的名称和源码文件名相同,如下:
add_library(message
STATIC
Message.hpp
Message.cpp
)
2.创建hello-world可执行文件的目标部分不需要修改:
add_executable(hello-world hello-world.cpp)
3.最后,将目标库链接到可执行目标:
target_link_libraries(hello-world message)
:顺序不要错
add_library(message STATIC Message.hpp Message.cpp) 生成必要的构建指令,将指定的源码编译到库 中。add_library的第一个参数是目标名。整个CMakeLists.txt中,可使用相同的名称来引用库。生成的库的实际名称将由CMake通过在前面添加前缀lib和适当的扩展名作为后缀来形成 。生成库是根据第二个参数(STATIC或SHARED)和操作系统确定的。
- STATIC: 用于创建静态库,即编译文件的打包存档,以便在链接其他目标时使用,例如:可执行文件。
- SHARED: 用于创建动态库,即可以动态链接,并在运行时加载的库。可以在CMakeLists.txt中使用add_library(message SHARED Message.hpp Message.cpp)从静态库切换到动态共享对象(DSO)。
target_link_libraries(hello-world message): 将库链接到可执行文件。此命令还确保hello-world可执行文件可以正确地依赖于消息库。因此,在消息库链接到hello-world可执行文件之前,需要完成消息库的构建。
1.使用CMake附带的find-module,查找pkg-config。这里在find_package中传递了QUIET参数。只有在没有找到pkg-config时,CMake才会报错:
find_package(PkgConfig REQUIRED QUIET)
2.找到pkg-config时,我们将使用pkg_search_module函数,以搜索任何附带包配置.pc文件的库或程序。该示例中,我们查找ZeroMQ库:
pkg_search_module(
ZeroMQ
REQUIRED
libzeromq libzmq lib0mq
IMPORTED_TARGET
)
1.将当前源目录CMAKE_CURRENT_SOURCE_DIR,添加到CMake将查找模块的路径列表CMAKE_MODULE_PATH中。这样CMake就可以找到,我们自定义的FindZeroMQ.cmake模块:
list(APPEND CMAKE_MODULE_PATH ${CMAKE_CURRENT_SOURCE_DIR})
2.现在FindZeroMQ.cmake模块是可用的,可以通过这个模块来搜索项目所需的依赖项。由于我们没有使用QUIET选项来查找find_package,所以当找到库时,状态消息将自动打印:
find_package(ZeroMQ REQUIRED)
3.我们继续添加hwserver可执行目标。头文件包含目录和链接库是使用find_package命令成功后,使用ZeroMQ_INCLUDE_DIRS和ZeroMQ_LIBRARIES变量进行指定的:
add_executable(hwserver hwserver.c)
target_include_directories(hwserver
PRIVATE
${ZeroMQ_INCLUDE_DIRS}
)
target_link_libraries(hwserver
PRIVATE
${ZeroMQ_LIBRARIES}
)
检查用户是否为所需的包提供了自定义位置。
使用find_家族中的命令搜索所需包的必需组件,即头文件、库、可执行程序等等。我们使用find_path查找头文件的完整路径,并使用find_library查找库。CMake还提供find_file、find_program和find_package。这些命令的签名如下:
find_path(<VAR> NAMES name PATHS paths)
如果搜索成功,将保存搜索结果;如果搜索失败,则会设置为-NOTFOUND。NAMES和PATHS分别是CMake应该查找的文件的名称和搜索应该指向的路径。
初步搜索的结果中,可以提取版本号。示例中,ZeroMQ头文件包含库版本,可以使用字符串操作和正则表达式提取库版本信息。
最后,调用find_package_handle_standard_args命令。处理find_package命令的REQUIRED、QUIET和版本参数,并设置ZeroMQ_FOUND变量。
写一个库,在cmake文件夹下新建一个FindAdd.cmake的文件。我们的目标是找到库的头文件所在目录和共享库文件的所在位置。
# 在指定目录下寻找头文件和动态库文件的位置,可以指定多个目标路径
find_path(ADD_INCLUDE_DIR libadd.h /usr/include/ /usr/local/include ${CMAKE_SOURCE_DIR}/ModuleMode)
find_library(ADD_LIBRARY NAMES add PATHS /usr/lib/add /usr/local/lib/add ${CMAKE_SOURCE_DIR}/ModuleMode)
if (ADD_INCLUDE_DIR AND ADD_LIBRARY)
set(ADD_FOUND TRUE)
endif (ADD_INCLUDE_DIR AND ADD_LIBRARY)
这时我们便可以像引用标准库一样引入我们自定义的库了。
在CMakeList.txt中添加
# 将项目目录下的cmake文件夹加入到CMAKE_MODULE_PATH中,让find_pakcage能够找到我们自定义的函数库
set(CMAKE_MODULE_PATH "${CMAKE_SOURCE_DIR}/cmake;${CMAKE_MODULE_PATH}")
add_executable(addtest addtest.cc)
find_package(ADD)
if(ADD_FOUND)
target_include_directories(addtest PRIVATE ${ADD_INCLUDE_DIR})
target_link_libraries(addtest ${ADD_LIBRARY})
else(ADD_FOUND)
message(FATAL_ERROR "ADD library not found")
endif(ADD_FOUND)
https://zhuanlan.zhihu.com/p/97369704
https://www.bookstack.cn/books/CMake-Cookbook
https://zhuanlan.zhihu.com/p/64373941
https://zhuanlan.zhihu.com/p/357803433