cmake是⾼级编译配置⼯具,是处理⼤型C/C++/JAVA项⽬的一个编译工具。
cmake的所有操作都是通过编译CMakeLists.txt来完成的,这里需要注意的是,CMakeLists.txt文件名不能有错,特别是大小写。
关键字
在介绍之前,先说明一下。指令是⼤⼩写⽆关的,参数和变量是⼤⼩写相关的,但仍然推荐全部使⽤⼤写指令。
1.PROJECT
可以⽤来指定⼯程的名字和⽀持的语⾔,默认⽀持所有语⾔,如PROJECT (HELLO)
PROJECT (HELLO CXX)
指定了⼯程的名字,并且⽀持语⾔是C++,如果需要支持多种语言,用空格分隔。
2.SET
显式指定变量命名,多个变量用空格分隔。
3.MESSAGE
向终端输出用户自定义信息,类似"cout"等。
cmake输出的信息有三种:
SEND_ERROR,产⽣错误,⽣成过程被跳过。
STATUS,输出前缀为—的信息。
FATAL_ERROR,⽴即终⽌所有 cmake 过程。
4.ADD_EXECUTABLE
生成可执行文件。用法如ADD_EXECUTABLE(hello main.cpp)
这样就会生成hello的可执行文件。
5.ADD_SUBDIRECTORY
ADD_SUBDIRECTORY(source_dir [binary_dir] [EXCLUDE_FROM_ALL])
这个指令⽤于向当前⼯程添加存放源⽂件的⼦⽬录,并可以指定中间⼆进制和⽬标⼆进制存放的位置。一句话说,就是告诉cmake还有别的目录。
binary_dir指定编译结果存放的目录。如果不指定,自动放到./src目录(没有则创建)下。
EXCLUDE_FROM_ALL函数是将写的⽬录从编译中排除。
6. INSTALL
使用cmake安装文件,这些文件可以是⼆进制、动态库、静态库以及⽂件、⽬录、脚本等
INSTALL(FILES COPYRIGHT README DESTINATION share/doc/cmake/)
FILES是类型名,指头文件,如果是不同的文件会有不同:TARGETS指二进制文件(.so和.a),ARCHIVE 特指静态库,LIBRARY 特指动态库,PROGRAMS是非目标可执行程序,目录也用这个。FILES后是文件名。要注意目录的话加不加"/“会有区别,加”/"只是代表目录下的所有文件,不加则表示这个目录。
DESTINATION后是安装路径,有两种写法:一是写绝对路径;二是写相对路径,相对路径实际路径是:${CMAKE_INSTALL_PREFIX}/<DESTINATION 定义的路径>。这里注意CMAKE_INSTALL_PREFIX默认是在/usr/local/,可以通过cmake -DCMAKE_INSTALL_PREFIX=/usr 在cmake的时候指定CMAKE_INSTALL_PREFIX变量的路径。这里-D后面可以用空格隔开,也可以不用,建议隔开。
后期需要使用make install。
7.ADD_LIBRARY
ADD_LIBRARY(hello SHARED ${LIBHELLO_SRC})
建立一个动态库,建立静态库的话,把SHARED换成STATIC,不写的话,默认是静态库。
这里还需要注意,一是cmake会给库名自动加上前后缀,如上例中为libhello.so。另外还有一点,实际开发过程中,希望静态库与动态名字相同。这里玩要注意,如果要同时建立多个库,库名不能相同,即使一个动态一个静态,也会实际只生成一个。
8.SET_PROPERTIES
这条指令可以⽤来设置输出的名称,对于动态库,还可以⽤来指定动态库版本和 API 版本,同时构建静态和动态库。具体用法如下:
ADD_LIBRARY(hello_static STATIC ${LIBHELLO_SRC})
#对hello_static的重名为hello
SET_TARGET_PROPERTIES(hello_static PROPERTIES OUTPUT_NAME "hello")
#cmake 在构建⼀个新的target 时,会尝试清理掉其他使⽤这个名字的库,因为,在构建libhello.so 时, 就会清理掉 libhello.a
SET_TARGET_PROPERTIES(hello_static PROPERTIES CLEAN_DIRECT_OUTPUT 1)
ADD_LIBRARY(hello SHARED ${LIBHELLO_SRC})
SET_TARGET_PROPERTIES(hello PROPERTIES OUTPUT_NAME "hello")
SET_TARGET_PROPERTIES(hello PROPERTIES CLEAN_DIRECT_OUTPUT 1)
9.INCLUDE_DIRECTORIES
这条指令可以⽤来向⼯程添加多个特定的头⽂件搜索路径,路径之间⽤空格分隔。在编译时找不到头文件时使用,括号里直接写路径名即可。
10.TARGET_LINK_LIBRARIES
这条指令用来添加需要链接的共享库。
TARGET_LINK_LIBRARIES(main libhello.so)
注意这句话要在ADD_EXECUTABLE指令之前,还要注意考虑32位和64位的问题,因为有lib和lib64两个目录。另外,如果动态库和静态库名字相同,优先调用动态库,这一点要注意。
11.AUX_SOURCE_DIRECTORY
找在某个路径下的所有源⽂件
aux_source_directory(<dir> <variable>)
12.FOREACH
cmake中的遍历功能,与ENDFOREACH()配合使用
用法如下
FOREACH(SUB_DIR ${SUB_DIR_LIST})
#遍历源⽂件
AUX_SOURCE_DIRECTORY(${SUB_DIR} SRC_LIST)
ENDFOREACH()
13.ADD_COMPILE_OPTIONS
cmake中的编译选项。
编译动态库AUX_SOURCE_DIRECTORY(-fPIC)
变量
cmake里有很多变量,可通过MESSAGE指令打印出来的方法来查看这些变量到底是什么。这里只介绍部分常用地的变量。
1.x_BINARY_DIR和x_SOURCE_DIR
分别代表build路径和源路径。x是项目名,如果项目名改变,上面两个变量名也会发生变化。解决这个问题,可以用PROJECT_BINARY_DIR和PROJECT_SOURCE_DIR,它们和刚才两个变量一样,只是名字不会变化。
2.CMAKE_INSTALL_PREFIX
cmake生成文件是默认加的路径前缀,默认是/usr/local/。
3.CMAKE_INCLUDE_PATH 和 CMAKE_LIBRARY_PATH
这两个是linux的环境变量,可以在linux的bash中进⾏设置,也可以使⽤export CMAKE_INCLUDE_PATH=/usr/include/hello
4.CMAKE_CURRENT_SOURCE_DIR
当前源码所在目录。
5.LIBRARY_OUTPUT_PATH和EXECUTABLE_OUTPUT_PATH
库文件生成目录和执行文件生成目录。
语法
1.变量使⽤${}⽅式取值,但是在 IF 控制语句中是直接使⽤变量名。
2.指令(参数 1 参数 2…) 参数使⽤括弧括起,参数之间使⽤空格或分号分开。
内部构建和外部构建
内部构建就是在源码所在目录构建cmake项目,由于产生的文件较多,不方便清理。
外部构建就是再另起一个目录进行构建,不会对源⽂件有任何影响,强烈使⽤外部构建⽅式。
工程化构建cmake
1.为⼯程添加⼀个⼦⽬录src,⽤来放置⼯程源代码。
2.添加⼀个⼦⽬录doc,⽤来放置这个⼯程的⽂档hello.txt。
3.在⼯程⽬录添加⽂本⽂件COPYRIGHT,README。
4.在⼯程⽬录添加⼀个runhello.sh脚本,⽤来调⽤hello⼆进制。
5.将构建后的⽬标⽂件放⼊构建⽬录的bin⼦⽬录。
6.将doc⽬录的内容以及COPYRIGHT/README安装到/usr/share/doc/cmake/。
构建debug版本
上面所构建的项目默认是release版本,有时为了调试,会构建debug版本,可以使用gdb等调试工具。
cmake -DCMAKE_BUILD_TYPE=debug
还是注意一下-D可以分开。
跨平台
cmake还可以在WIN32、APPLE等平台上使用,主要是标志上的区别。但是对于服务器开发而言,一般很少用。