CMake:是一个比make更高级的编译配置工具,它可以根据不同平台、不同的编译器,生成相应的Makefile或者vcproj项目。
近期使用Visual Studio 2015 建立了Qt工程,不使用工程管理工具导致在代码组织和协作者不好处理,在Git上提交vs工程文件也有问题,一是工程文件比较大,二是提交代码会出现冲突,频繁解决冲突很麻烦。
迫于需要,自己捣鼓了一下CMake来管理工程,好处:让源码和构建文件分离,保持源码目录的干净,代码提交时只需要提交源码。
当CMake处理一个项目时,入口点是一个名为CMakeLists.txt的源文件,这个一定是根目录下的CMakeLists.txt。这个文件包含整个工程的构建规范,当我们有多个子文件夹需要编译时,使用add_subdirectory(<dir_name>)
命令来为构建添加子目录。添加的每个子目录也必须包含一个CMakeLists.txt文件作为该子目录的入口点。
先介绍cmake里面的一些函数:
project(<poject_name>)
:设置项目名称并将该名称存储在PROJECT_NAME变量中cmake_minimum_required(VERSION 3.4.1)
:指定需要的最小的CMake版本aux_source_directory(. SRC_LIST)
: 查找当前目录下所有源文件并保存至SRC_LIST变量中target_link_libraries(name lib1 lib2 lib3)
:将若干库链接到目标库文件CMAKE_CURRENT_SOURCE_DIR
:指的是当前处理的 CMakeLists.txt 所在的路径source_group
: 文件分组get_filename_component:(path files PATH)
:PATH参数:获取$(source)的路径到变量source_path中include_directories(./include ${MY_INCLUDE})
:指定的目录被追加到当前的include目录列表中。通过将CMAKE_INCLUDE_DIRECTORIES_BEFORE设置为ON,可以更改此默认行为add_subdirecroty(sub_dir [binary_dir])
:sub_dir指定包含CMakeLists.txt和源码文件的子目录位置,binary_dir是输出路径, 一般可以不指定add_executable(<name> ${SRC_LIST})
:添加可执行文件add_library(<name> ${SRC_LIST})
:添加库(可以指定静态、动态)link_directories(path)
:添加库的路径add_definitions(name)
:添加定义
自定义函数: 文件分组函数定义
#源文件分组
function(assign_source_group)
foreach(source IN ITEMS ${ARGN})
get_filename_component(source_path "${source}" PATH)
string(REPLACE "/" "\\" SOURCE_PATH_MSVC "${source_path}")
source_group("${SOURCE_PATH_MSVC}" FILES "${source}")
endforeach()
endfunction(assign_source_group)
#获取所有源文件
function(get_srcfile_list)
set(CURRENT_PATH ${CMAKE_CURRENT_SOURCE_DIR})
foreach(source IN ITEMS ${ARGN})
string(REPLACE ${CURRENT_PATH}/ "" CURRENT_SRC_PATH "${source}")
list(APPEND SOURCE_TREE "${CURRENT_SRC_PATH}")
endforeach()
set(CURRENT_SRC_TREE ${SOURCE_TREE} PARENT_SCOPE)
endfunction(get_srcfile_list)
#构建文件目录
function(build_file_tree)
FILE(GLOB_RECURSE ALL_SOURCE_LIST . "*.h" "*.hpp" "*.cpp" "*.c" "*.ui" "*.qrc")
get_srcfile_list(${ALL_SOURCE_LIST})
assign_source_group(${CURRENT_SRC_TREE})
set(SOURCE_TREE ${CURRENT_SRC_TREE} PARENT_SCOPE)
endfunction(build_file_tree)
#头文件设置
function(init_include_path)
#sometime have other dll need to be dynamic use
FILE(GLOB_RECURSE ALL_SOURCE_LIST . "*.h" "*.hpp" "*.dll")
# FILE(GLOB_RECURSE ALL_SOURCE_LIST . "*.h" "*.hpp")
assign_include_path(${ALL_SOURCE_LIST})
endfunction(init_include_path)
#添加头文件路径
function(assign_include_path)
foreach(source IN ITEMS ${ARGN})
get_filename_component(head_path "${source}" PATH)
string(REPLACE "/" "\\" HEAD_PATH_MSVC "${head_path}")
INCLUDE_DIRECTORIES(${HEAD_PATH_MSVC})
endforeach()
endfunction()
测试目录结构
vs工程:
apps、libs分别为可执行文件和库文件生成的路径;
builds为构建目录,CMake执行后,编译工程会自动创建目录;
project1 为静态库工程;Project2 普通的VS工程, Project3 为VS下添加的Qt项目;
Project3的目录:
CMakeLists.txt 文件
app.cmake 设置可执行文件的头文件路径、依赖库的路径和依赖的库名,指定生成路径
lib.cmake 设置库的生成路径、工程的头文件包含路径
INCLUDE(../func.cmake)
build_file_tree()
init_include_path() #调用func.cmake文件的自定义函数进行文件分组
顶层目录的CMakeList.txt 添加子目录
Project3子目录下CMake因为有Qt库,需要多几个设置
set (PROJECT_NAME Project3) #设置工程3的变量
project(${PROJECT_NAME}) #设置工程 包含了Qt的设置,放在文件最后在构建工程时会报CXX Compiler 错误
set(CMAKE_PREFIX_PATH "D:/Qt/Qt5.8.0/5.8/msvc2015_64") #设置Qt安装路径
set(CMAKE_INCLUDE_CURRENT_DIR ON) #设置工程包含当前目录
set(CMAKE_AUTOMOC ON) #打开全局moc,设置自动生成moc文件,一定要设置
set(CMAKE_AUTOUIC ON)#打开全局uic,非必须
set(CMAKE_AUTORCC ON)#打开全局rcc,非必须
find_package(qt5widgets) #查找需要的qt库文件,最好每一个库都要写,qt也会根据依赖关系自动添加
target_link_libraries(${PROJECT_NAME} ${Qt5Widgets_LIBRARIES}) #添加Qt的链接库
设置非控制台程序:
add_executable(${PROJECT_NAME} WIN32 ${SOURCE_TREE} ${HEAD} ${SOURCE} ${QRC} ${RES})
#设置工程为win32程序,默认是控制台
set_target_properties(${PROJECT_NAME} PROPERTIES LINK_FLAGS /SUBSYSTEM:WINDOWS) #windows应用
#set_target_properties(${PROJECT_NAME} PROPERTIES LINK_FLAGS /SUBSYSTEM:CONSOLE) #控制台
贴出完整的CMakeLists.txt
地址:
链接:https://pan.baidu.com/s/1nkGWKZ3I_OLeEoudYe_W2A
提取码:kwup