cmake_minimum_required(version 版本号)
例如:
cmake_minimum_required(version 2.8)
#定义工程名称
project(项目名称)
例如:
project(MyTest)
set(var [value])
例如:
# 第一种用法,生成代码文件列表
#先直接设置SRC_LIST的值
set(SRC_LIST add.h add.cpp)
#然后再在SRC_LIST中追加main.cpp
set(SRC_LIST ${SRC_LIST} main.cpp)
# 第二中用法,设置库生成目录或者可执行文件生成目录
set( LIBRARY_OUTPUT_PATH ${PROJECT_SOURCE_DIR}/lib/linux)
set( EXECUTABLE_OUTPUT_PATH ${PROJECT_SOURCE_DIR}/bin)
# 编译静态库
add_library(库名称 STATIC 代码文件名称)
# 编译动态库
add_library(库名称 SHARED 代码文件名称)
# 编译可执行程序
add_executable(可执行程序名 代码文件名称)
例如:
# 编译静态库
add_library(add STATIC add.h add.cpp)
add_library(add STATIC ${ADD_SRC} ${ADD_HDR})
# 编译动态库
add_library(add SHARED add.h add.cpp)
add_library(add SHARED ${ADD_SRC} ${ADD_HDR})
# 编译可执行程序
add_executable(main add.h add.cpp mai.cpp)
add_executable(main ${MAIN_SRC} ${MAIN_HDR})
例如将当前编译的静态库或者动态库输出到当前项目文件夹lib子目录下
set(LIBRARY_OUTPUT_PATH ${PROJECT_SOURCE_DIR}/lib)
例如将当前可执行程序输出到当前项目文件夹的bin子目录下
#设定可执行二进制文件的目录
set( EXECUTABLE_OUTPUT_PATH ${PROJECT_SOURCE_DIR}/bin)
例如将链接库搜索目录设置为当前项目文件夹下lib/linux文件夹
link_directories( ${PROJECT_SOURCE_DIR}/lib/linux)
例如将包含目录设置为当前项目文件夹下include文件夹
include_directories(${PROJECT_SOURCE_DIR}/include)
#预定义宏
add_definitions(-D宏名称)
例如:
add_definitions(-DWINDOWS)
add_definitions(-DLINUX)
link_libraries(
静态库1
静态库2
静态库3
...
)
注意,link_libraries中的静态库为全路径,常与1.7 link_directories 搭配使用,例如:
lib1.a lib2.a在目录${PROJECT_SOURCE_DIR}/lib/linux下,则先设置链接目录,再链接相应的库
#设置链接目录
link_directories( ${PROJECT_SOURCE_DIR}/lib/linux)
link_libraries(
lib1.a
lib2.a
)
target_link_libraries(所需生成的文件名称 所需链接的动态库名称)
例如
target_link_libraries(main dl)
在cmake语法中,link_libraries和target_link_libraries是很重要的两个链接库的方式,虽然写法上很相似,但是功能上有很大区别:
(1) link_libraries用在add_executable之前,target_link_libraries用在add_executable之后
(2) link_libraries用来链接静态库,target_link_libraries用来链接导入库,即按照header file + .lib + .dll方式隐式调用动态库的.lib库
例如将当前文件夹下所有.cpp文件的文件名加入到MAIN_SRC中,将当前文件夹下所有.h加入到MAIN_HDR中。
file(GLOB MAIN_SRC ${CMAKE_CURRENT_SOURCE_DIR}/*.cpp)
file(GLOB MAIN_HDR ${CMAKE_CURRENT_SOURCE_DIR}/*.h)
例如将当前文件夹子目录src文件夹下所有.cpp文件的文件名加入到MAIN_SRC中,将当前文件夹子目录src文件夹下所有.h加入到MAIN_HDR中。
file(GLOB MAIN_SRC ${CMAKE_CURRENT_SOURCE_DIR}/src/*.cpp)
file(GLOB MAIN_HDR ${CMAKE_CURRENT_SOURCE_DIR}/src/*.h)
例如将当前文件夹下(包括子目录下)所有.cpp文件的文件名加入到MAIN_SRC中,所有.h加入到MAIN_HDR中
file(GLOB_RECURSE MAIN_SRC ${CMAKE_CURRENT_SOURCE_DIR}/*.cpp)
file(GLOB_RECURSE MAIN_HDR ${CMAKE_CURRENT_SOURCE_DIR}/*.h)
常见的List操作包括:
list(LENGTH
例如从MAIN_SRC移除指定项
list(REMOVE_ITEM MAIN_SRC ${CMAKE_CURRENT_SOURCE_DIR}/add.cpp)
# 搜索当前目录
file(GLOB MAIN_SRC ${CMAKE_CURRENT_SOURCE_DIR}/*.cpp)
file(GLOB MAIN_HDR ${CMAKE_CURRENT_SOURCE_DIR}/*.h)
# 递归搜索当前目录下src子目录
file(GLOB_RECURSE MAIN_SRC_ELSE ${CMAKE_CURRENT_SOURCE_DIR}/src/*.cpp)
file(GLOB_RECURSE MAIN_HDR_ELSE ${CMAKE_CURRENT_SOURCE_DIR}/src/*.h)
# 将MAIN_SRC_ELSE中的值添加到MAIN_SRC
# 将MAIN_HDR_ELSE中的值添加到MAIN_HDR
list(APPEND MAIN_SRC ${MAIN_SRC_ELSE})
list(APPEND MAIN_HDR ${MAIN_HDR_ELSE})
例如
add_subdirectory(src)
该语句会在执行完当前文件夹CMakeLists.txt之后执行src子目录下的CMakeLists.txt
输出正常:
message(STATUS "Enter cmake ${CMAKE_CURRENT_LIST_DIR}")
输出警告
message(WARNING "Enter cmake ${CMAKE_CURRENT_LIST_DIR}")
输出错误:
message(FATAL_ERROR "Enter cmake ${CMAKE_CURRENT_LIST_DIR}")
install 指令用于定义安装规则,安装的内容包括二进制可执行文件、动态库、静态库以及文件、目录、脚本等。
例如:
install(TARGETS util
RUNTIME DESTINATION bin
LIBRARY DESTINATION lib
ARCHIVE DESTINATION lib)
ARCHIVE指静态库,LIBRARY指动态库,RUNTIME指可执行目标二进制,上述示例的意思是:
install(DIRECTORY include/ DESTINATION include/util)
这个语句的意思是将include/目录安装到include/util目录
设置编译选项可以通过add_compile_options命令,也可以通过set命令修改CMAKE_CXX_FLAGS或CMAKE_C_FLAGS。
方式1
set( CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11 -march=native -O3 -frtti -fpermissive -fexceptions -pthread")
方式2
add_compile_options(-march=native -O3 -fexceptions -pthread -fPIC)
这两种方式的区别在于:
add_compile_options命令添加的编译选项是针对所有编译器的(包括c和c++编译器),而set命令设置CMAKE_C_FLAGS或CMAKE_CXX_FLAGS变量则是分别只针对c和c++编译器的。
例如操作系统判断方式一:
if(WIN32)
message(STATUS “This operating system is Windows.”)
elseif(UNIX)
message(STATUS “This operating system is Linux.”)
elseif(APPLE)
message(STATUS “This operating system is APPLE.”)
endif(WIN32)
操作系统判断方式二:
if (CMAKE_SYSTEM_NAME MATCHES "Linux")
message(STATUS "current platform: Linux ")
elseif (CMAKE_SYSTEM_NAME MATCHES "Windows")
message(STATUS "current platform: Windows")
elseif (CMAKE_SYSTEM_NAME MATCHES "FreeBSD")
message(STATUS "current platform: FreeBSD")
else ()
message(STATUS "other platform: ${CMAKE_SYSTEM_NAME}")
endif (CMAKE_SYSTEM_NAME MATCHES "Linux")
设置环境变量:
set(env{name} value)
调用环境变量:
$env{name}
例如
message(STATUS "$env{name}")
自动添加CMAKE_CURRENT_BINARY_DIR和CMAKE_CURRENT_SOURCE_DIR到当前处理 的CMakeLists.txt。
相当于在每个CMakeLists.txt加入:
include_directories(${CMAKE_CURRENT_BINARY_DIR} ${CMAKE_CURRENT_SOURCE_DIR})
if (expression):expression 不为空时为真,false的值包括(0,N,NO,OFF,FALSE,NOTFOUND);
if (not exp):与上面相反;
if (var1 AND var2):如果两个变量都为真时为真;
if (var1 OR var2):如果两个变量有一个为真时为真;
if (COMMAND cmd):如果 cmd 确实是命令并可调用为真;
if (EXISTS dir) if (EXISTS file):如果目录或文件存在为真;
if (file1 IS_NEWER_THAN file2):当 file1 比 file2 新,或 file1/file2 中有一个不存在时为真,文件名需使用全路径;
if (IS_DIRECTORY dir):当 dir 是目录时为真;
if (DEFINED var):如果变量被定义为真;
if (var MATCHES regex):给定的变量或者字符串能够匹配正则表达式 regex 时为真,此处 var 可以用 var 名,也可以用 ${var};
if (string MATCHES regex):给定的字符串能够匹配正则表达式regex时为真。
if (variable LESS number):如果variable小于number时为真;
if (string LESS number):如果string小于number时为真;
if (variable GREATER number):如果variable大于number时为真;
if (string GREATER number):如果string大于number时为真;
if (variable EQUAL number):如果variable等于number时为真;
if (string EQUAL number):如果string等于number时为真。
if (variable STRLESS string)
if (string STRLESS string)
if (variable STRGREATER string)
if (string STRGREATER string)
if (variable STREQUAL string)
if (string STREQUAL string)
start 表示起始数,stop 表示终止数,step 表示步长
foreach(loop_var RANGE start stop [step])
...
endforeach(loop_var)
while(condition)
...
endwhile()
include(CheckCXXCompilerFlag)
CHECK_CXX_COMPILER_FLAG("-std=c++11" COMPILER_SUPPORTS_CXX11)
CHECK_CXX_COMPILER_FLAG("-std=c++0x" COMPILER_SUPPORTS_CXX0X)
if(COMPILER_SUPPORTS_CXX11)
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11")
elseif(COMPILER_SUPPORTS_CXX0X)
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++0x")
else()
message(STATUS "The compiler ${CMAKE_CXX_COMPILER} has no C++11 support. Please use a different C++ compiler.")
endif()
例如,我们在工程中引用了许多的第三方开源库,这些库的源码与自己所写的代码需要进行区分和隔离,通常情况下会单独开一个third筛选器存储这些第三方库的项目,怎么做?
第一步:在第三方库的CMakeLists.txt中cmake_minimum_required(VERSION 2.6)中加上set_property(GLOBAL PROPERTY USE_FOLDERS On)
第二步:在生成编译目标的语法之后,如:
add_executable(demo demo.cpp) # 生成可执行文件
add_library(common STATIC util.cpp) # 生成静态库
add_library(common SHARED util.cpp) # 生成动态库或共享库
加入一句
set_target_properties(${第三方库项目名称} PROPERTIES FOLDER “目标文件夹名称”)
这个问题要将生成执行文件、静态库、动态库的声明
add_executable(demo demo.cpp) # 生成可执行文件
add_library(common STATIC util.cpp) # 生成静态库
add_library(common SHARED util.cpp) # 生成动态库或共享库
放在
target_link_libraries()
之前。
在项目根目录下执行命令:
touch *
更新所有文件时间。
以一个简单可执行程序调用so库为例:
#include
#include
#include
typedef int (*ADD)(int,int);
int main(){
//这里调用刚才生成的so库里的add方法
void *handle=dlopen("../lib/libAddSo.so",RTLD_NOW);
if(handle != NULL)
{
dlerror();
char * error = NULL;
ADD add=NULL;
*(void **)(&add)=dlsym(handle,"add");
if ((error = dlerror()) == NULL && add != NULL)
{
int result=add(2,5);
printf("%d\n",result);
}
else
{
error = dlerror();
printf("%s\n",error == NULL ? "unknow error" : error);
}
}
return 0;
}
add.h
__attribute__((visibility ("default"))) int add(int a,int b)
add.cpp
extern "C"
{
int add(int a,int b)
{
return (a + b);
}
}
CmakeTest:
│
├─bin
├─exe
│ main.cpp
│
├─lib
└─so
add.cpp
add.h
其中,
bin目录设定为可执行文件生成目录;
lib目录设定为动态链接库so生成目录;
在CmakeTest文件夹下新建CMakeLists.txt,并写入以下内容:
#cmake 最低版本要求
cmake_minimum_required(VERSION 2.8)
#打印相关信息
message(STATUS "Enter cmake ${CMAKE_CURRENT_LIST_DIR}")
message(STATUS "Project:AnimationEngine")
message(STATUS "Project Directory: ${PROJECT_SOURCE_DIR}")
#定义工程名称
project(CmakeTest)
#设置编译器(可选的有gcc,g++)
SET(CMAKE_CXX_COMPILER "g++")
# 设置用debug还是release模式。debug允许断点,而release更快
set( CMAKE_BUILD_TYPE Debug )
#set( CMAKE_BUILD_TYPE Release )
# 设置编译选项
# 允许c++11标准、O3优化、多线程。match选项可避免一些cpu上的问题
set( CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11 -march=native -O3 -pthread")
#设定可执行二进制文件的目录
SET( EXECUTABLE_OUTPUT_PATH ${PROJECT_SOURCE_DIR}/bin)
#设定存放编译出来的库文件的目录
SET( LIBRARY_OUTPUT_PATH ${PROJECT_SOURCE_DIR}/lib/)
#并且把该目录设为连接目录
LINK_DIRECTORIES( ${PROJECT_SOURCE_DIR}/lib/)
# 递归执行src目录下的CMakeLists.txt
add_subdirectory(so)
add_subdirectory(exe)
cmake_minimum_required(VERSION 2.8)
message(STATUS "Enter cmake ${CMAKE_CURRENT_LIST_DIR}")
file(GLOB Main_SRC ${CMAKE_CURRENT_SOURCE_DIR}/*.cpp)
file(GLOB Main_HDR ${CMAKE_CURRENT_SOURCE_DIR}/*.h)
link_libraries(libAddSo.so)
add_executable(main ${Main_SRC} ${Main_HDR})
#预定义宏
add_definitions(-DLINUX -DAE_EXPORTS)
target_link_libraries(main ${CMAKE_DL_LIBS} libAddSo.so)
message(STATUS "current path:${CMAKE_CURRENT_SOURCE_DIR}/lib/linux")
cmake_minimum_required(VERSION 2.8)
message(STATUS "Enter cmake ${CMAKE_CURRENT_LIST_DIR}")
#搜索以下目录
file(GLOB AddSo_SRC ${CMAKE_CURRENT_SOURCE_DIR}/*.cpp)
file(GLOB AddSo_HDR ${CMAKE_CURRENT_SOURCE_DIR}/*.h)
add_library(AddSo SHARED ${AddSo_SRC} ${AddSo_HDR})
以Ubuntu系统为例,对上述示例项目进行编译,并运行。
进入CmakeTest文件夹,打开命令终端,输入命令:
cmake ./
cmake则会出现以下cmake成功界面:
然后再输入命令:
make
生成makefile文件,正确make则会出现以下界面:
可以忽略时钟错误警告(CLion打开后就变成这样了)。
CmakeTest:
│ CMakeCache.txt
│ CMakeLists.txt
│ cmake_install.cmake
│ Makefile
│ tree.txt
│
├─bin
│ main
│
├─CMakeFiles
│ │ cmake.check_cache
│ │ CMakeDirectoryInformation.cmake
│ │ CMakeOutput.log
│ │ feature_tests.bin
│ │ feature_tests.c
│ │ feature_tests.cxx
│ │ Makefile.cmake
│ │ Makefile2
│ │ progress.marks
│ │ TargetDirectories.txt
│ │
│ ├─3.12.1
│ │ │ CMakeCCompiler.cmake
│ │ │ CMakeCXXCompiler.cmake
│ │ │ CMakeDetermineCompilerABI_C.bin
│ │ │ CMakeDetermineCompilerABI_CXX.bin
│ │ │ CMakeSystem.cmake
│ │ │
│ │ ├─CompilerIdC
│ │ │ │ a.out
│ │ │ │ CMakeCCompilerId.c
│ │ │ │
│ │ │ └─tmp
│ │ └─CompilerIdCXX
│ │ │ a.out
│ │ │ CMakeCXXCompilerId.cpp
│ │ │
│ │ └─tmp
│ └─CMakeTmp
├─exe
│ │ CMakeLists.txt
│ │ cmake_install.cmake
│ │ main.cpp
│ │ Makefile
│ │
│ └─CMakeFiles
│ │ CMakeDirectoryInformation.cmake
│ │ progress.marks
│ │
│ └─main.dir
│ build.make
│ cmake_clean.cmake
│ CXX.includecache
│ depend.internal
│ depend.make
│ DependInfo.cmake
│ flags.make
│ link.txt
│ main.cpp.o
│ progress.make
│
├─lib
│ libAddSo.so
│
└─so
│ add.cpp
│ add.h
│ CMakeLists.txt
│ cmake_install.cmake
│ Makefile
│
└─CMakeFiles
│ CMakeDirectoryInformation.cmake
│ progress.marks
│
└─AddSo.dir
add.cpp.o
build.make
cmake_clean.cmake
CXX.includecache
depend.internal
depend.make
DependInfo.cmake
flags.make
link.txt
progress.make
进入exe目录,运行main程序:
./main
如果您觉得这篇博文有用,请访问我的个人站:http://www.stubbornhuang.com/,更多博文干货等着您。