CMake是一个开放源代码,跨平台的工具系列,旨在构建,测试和打包软件。CMake用于使用简单平台和独立于编译器的配置文件控制软件编译过程,并生成可在您选择的编译器环境中使用的本机makefile和工作区。CMake工具套件是由Kitware创建的,旨在满足ITK和VTK等开源项目对功能强大的跨平台构建环境的需求。
简单来说,CMake是一款非常强大的编译工具,配合buildroot可以做到自动从下GitHub下载源码、自动选择架构并编译到指定目录。听起来是不是很强大?当然,部分编译工具也能做到这一点,但没有这么智能,可能需要手动修改配置文件架构。
首先,提供一个buildroot配合Cmake自动编译的示例文章:
正文
在linux相关平台编程时,一般需要在不同架构、不同系统,甚至不同系统版本中编译工程。如果工程属于完全源码编译,倒也不算太麻烦。但,如果工程中携带指定版本外部库(比如静态方式加载),每一次编译都要修改编译配置或者指定编译选项,则太过繁杂。
接下来,我们从几个方面了解CMake的实战技巧。
1. CMake获取CPU架构信息
2. CMake获取系统信息
3. CMake获取linux发行版本
4. CMake添加头文件
5. CMake添加源文件
在CMakeList.txt中,通过“CMAKE_HOST_SYSTEM_PROCESSOR”变量可以获取到当前机器正在运行的cpu架构信息。
首先,我们通过这个变量输出当前机器的信息:message("-- CMAKE_HOST_SYSTEM_PROCESSOR: ${CMAKE_HOST_SYSTEM_PROCESSOR}"),参考图1:
接下来,把这个变量放入判断条件语句中,参考图2:
if(CMAKE_HOST_SYSTEM_PROCESSOR MATCHES "x86_64" )
message("-- 当前cpu架构: ${CMAKE_HOST_SYSTEM_PROCESSOR}")
endif()
在ubuntu相关系统中,通过uname系列指令可以显示系统信息,比如uname -a显示系统所有信息、uname -s显示系统名称等。接下来,通过CMake变量获取这些信息(部分信息与uname指令稍微不同)。首先输出部分系统信息,参考图3:
message("-- CMAKE_SYSTEM_INFO_FILE: ${CMAKE_SYSTEM_INFO_FILE}")
message("-- CMAKE_SYSTEM_NAME: ${CMAKE_SYSTEM_NAME}")
message("-- CMAKE_SYSTEM_PROCESSOR: ${CMAKE_SYSTEM_PROCESSOR}")
message("-- CMAKE_SYSTEM: ${CMAKE_SYSTEM}")
这部分变量可以获取到系统平台和系统版本,但不能确定属于哪一个发行版。
接下来,通过管道获取系统发行版信息,参考图4:
find_program(LINUX_RELEASE lsb_release)
execute_process(COMMAND ${LINUX_RELEASE} -is
OUTPUT_VARIABLE LINUX_RELEASE
OUTPUT_STRIP_TRAILING_WHITESPACE
)
message("-- LINUX_RELEASE: ${LINUX_RELEASE}")
接下来,把这个变量放入判断条件语句中,参考图5:
if (LINUX_RELEASE STREQUAL "Ubuntu")
message("-- linux: ${LINUX_RELEASE}")
endif()
现在我们了解了cpu架构获取方式、系统信息和linux发行版信息,之后可以通过if复合语句判断出目标linux系统了。
在CMakeList.txt中添加的头文件,直接使用#define "头文件名称"即可使用:
INCLUDE_DIRECTORIES(
lib/ubuntu_x86_64/machine/include # 添加文件内的所有头文件
lib/ubuntu_x86_64/machine/include/test.h # 添加指定头文件
)
使用“INCLUDE_DIRECTORIES”方式添加头文件不能以/作为结尾,应以文件夹名称或头文件名称作为结尾。
在CMakeList.txt中添加的源文件的方式比较,可以通过ADD_SUBDIRECTORY指定文件夹然后打包成二进制文件,也可以通过FILE方式可以把源文件与外部库打包。
add_subdirectory(source_dir [binary_dir]
[EXCLUDE_FROM_ALL]):
ADD_SUBDIRECTORY(src) # src中可以包含.h、.c和.cpp文件,这种方式可以直接添加头文件和源文件,不需要通过INCLUDE_DIRECTORIES指定头文件。
FILE:
cmake中的file用法比较全面,与c语言的文件io相似,这里主要讲述源文件与动态库链接的方式。
Reading
file(READ < filename> < out-var> […])
file(STRINGS < filename> < out-var> […])
file(< HASH> < filename> < out-var>)
file(TIMESTAMP < filename> < out-var> […])
file(GET_RUNTIME_DEPENDENCIES […])
Writing
file({WRITE | APPEND} < filename> < content>…)
file({TOUCH | TOUCH_NOCREATE} [< file>…])
file(GENERATE OUTPUT < output-file> […])
file(CONFIGURE OUTPUT < output-file> CONTENT < content> […])
Filesystem
file({GLOB | GLOB_RECURSE} < out-var> […] [< globbing-expr>…])
file(RENAME < oldname> < newname>)
file({REMOVE | REMOVE_RECURSE } [< files>…])
file(MAKE_DIRECTORY [< dir>…])
file({COPY | INSTALL} < file>… DESTINATION < dir> […])
file(SIZE < filename> < out-var>)
file(READ_SYMLINK < linkname> < out-var>)
file(CREATE_LINK < original> < linkname> […])
Path Conversion
file(RELATIVE_PATH < out-var> < directory> < file>)
file({TO_CMAKE_PATH | TO_NATIVE_PATH} < path> < out-var>)
Transfer
file(DOWNLOAD < url> < file> […])
file(UPLOAD < file> < url> […])
Locking
file(LOCK < path> […])
Archiving
file(ARCHIVE_CREATE OUTPUT < archive> FILES < files> […])
file(ARCHIVE_EXTRACT INPUT < archive> DESTINATION < dir> […])
源文件与动态库链接,然后链接到程序,这种方式主要用于外部库的封装调用
find_library(MOSQUITTOLIB mosquitto PATHS ${PROJECT_SOURCE_DIR}/usr/local/lib /usr/lib /usr/local/lib/ /usr/lib/x86_64-linux-gnu DOC "modbus library") # 首先从指定路径下找到modbus库
if(NOT MOSQUITTOLIB)
message(FATAL_ERROR "libmosquitto not found")
endif()
FILE(GLOB src
common/mqtt/mosquittopp.cpp) # src增加文件
ADD_LIBRARY(mqtt SHARED ${src}) # mqtt共享方式链接
TARGET_LINK_LIBRARIES(mqtt ${MOSQUITTOLIB}) # 链接动态库
TARGET_LINK_LIBRARIES(demo rt
mqtt ) #链接到工程中