sudo apt-get install cmake2. 编写HelloWorld
main.cpp #inlcude3. 编写Cmake文件CMakeLists.txtint main() { std::cout << "Hello, World!" << std::endl; return 0; }
注意,Cmake文件的名字只能是CMakeLists.txt
PROJECT (HELLO)
SET(SRC_LIST main.cpp)
MESSAGE(STATUS "This is BINARY dir " ${HELLO_BINARY_DIR})
MESSAGE(STATUS "This is SOURCE dir " ${HELLO_SOURCE_DIR})
ADD_EXECUTABLE(hello ${SRC_LIST})
4. 使用cmake命令编译当前目录
cmake .5. 使用make命令进A行编译
make
查看当前目录
./hello
执行结果
以上述例子中的CMakeLists.txt为例
PROJECT (HELLO)
SET(SRC_LIST main.cpp)
MESSAGE(STATUS "This is BINARY dir " ${HELLO_BINARY_DIR})
MESSAGE(STATUS "This is SOURCE dir " ${HELLO_SOURCE_DIR})
ADD_EXECUTABLE(hello ${SRC_LIST})
PROJECT关键字
可以用来指定工程的名字和支持的语言,默认支持所有语言
PROJECT(HELLO) 指定了工程的名字,并且支持所有语言
PROJECT(HELLO CXX) 指定了工程的名字,并且支持语言是C++
PROJECT(HELLO C CXX) 指定了工程的名字,并且支持所有语言是C和C++
该指定隐式定义了两个CMake的变量
MESSAGE关键字可以直接使用这两个变量,都指向当前的工作目录
问题:如果改变了工程名,则这两个变量名也会改变
解决:又定义两个预定义变量:PROJECT_BINARY_DIR,PROJECT_SOURCE_DIR,而这两个变量和HELLO_BINARY_DIR,HELLO_SOURCE_DIR是一致的。
用来显式地指定变量
SET(SRC_LIST main.cpp) SRC_LIST变量就包含了main.cpp
也可以SET(SRC_LIST main.cpp t1.cpp t2.cpp)
多个cpp之间用空格分隔
向终端输出用户自定义信息
主要包含三种:
-
SEND_ERROR, 产生错误,生成过程被跳过
-
STATUS, 输出前缀为--的信息
-
FATAL_ERORR, 立刻终止所有CMake的过程
生成可执行文件
ADD_EXECUTABLE(hello ${SRC_LIST})
其中hello为生成的可执行文件的文件名,源文件读取变量SRC_LIST中的内容
也可以直接写成ADD_EXECUTABLE(hello main.cpp)
快速上手中的CMakeLists.txt例子可以简化为
PROJECT(HELLO) ADD_EXECUTABLE(hello main.cpp)
注意这里的工程名HELLO和最后生成的可执行文件文件名hello没有关系
语法基本原则- 变量使用${}方式取值,但是在IF控制语句中是直接使用变量名
- 指令(参数1, 参数2…),参数使用括弧括起,参数之间使用空格或分号隔开,以上述的ADD_EXECUTABLE指令为例,如果存在另外一个func.cpp源文件,写法为
- ADD_EXECUTABLE(hello main.cpp func.cpp)
- ADD_EXECUTABLE(hello main.cpp;func.cpp)
- 指令是大小写无关的,参数是大小写相关的,但是推荐指令全部大写
- SET(SRC_LIST main.cpp)可以写成SET(SRC_LIST “main.cpp”),如果源文件名中有空格,则必须要加双引号
- ADD_EXECUTABLE(hello main)后缀可以不加,但是推荐添加
- 内部构建:上述例子就是内部构建,产生较多的临时文件,不方便清理
- 外部构建:把生成的临时文件放在build目录下,不会对源文件有任何影响,推荐使用外部构建
清除之前的所有临时文件 rm -rf CMakeCache.txt CMakeFiles cmake_install.cmake Makefile 创建build目录用来存放这些临时文件 mkdir build cd build 使用cmake进行编译 cmake .. 编译的是build目录的上一级目录 使用make进行编译 make让HelloWorld看起来更像一个工程
- 添加一个子目录src,用来存放工程源代码
- 添加一个子目录doc,用来存放工程文档
- 在工程目录中添加文本文件COPYRIGHt(版权),READEME(阅读信息)
- 在工程目录中添加一个runhello.sh脚本,用来调用hello二进制文件
- 将构建后的目标文件放入构建目录的bin子目录
- 将doc目录的内容以及COPYRIGHT/READEME安装到/usr/share/doc/cmake/
每个目录下都要有一个CMakeLists.txt
-
创建src目录,并将main.cpp移动到src下
mkdir src mv main.cpp src
-
重写项目根目录下的CMakeLists.txt
echo "" > CMakeLists.txt
PROJECT(HELLO) ADD_SUBDIRECTORY(src bin) //关联到src,生成的中间二进制或目标二进制文件都存放到bin目录
-
重写src目录下的CMakeLists.txt
ADD_EXECUTABLE(hello main.cpp)
-
跳转到build目录下进行cmake编译和make编译
cmake .. make
-
可以发现build目录下多出了bin目录,bin目录结构
ADD_SUBDIRECTORY(source_dir [binary_dir] [EXCLUDE_FROM_ALL])
- 这个指令用于向当前工程项目添加存放源文件的子目录,并且可以指定中间二进制和目标二进制的存放位置
- EXCLUDE_FROM_ALL函数是将写的目录从编译中排除,如程序中的example
- ADD_SUBDIRECTORY(bin src)
将src子目录加入工程项目并指定编译输出(包含编译中间结果)路径为bin目录
如果不进行bin目录的指定,则编译结果(包含编译中间结果)都将存放到build/src目录中
SET指令重新定义EXECUTABLE_OUTPUT_PATH和LIBRARY_OUTPUT_PATH变量来指定最终的目标二进制的位置
SET(EXECUTABLE_OUTPUT_PATH ${PROJECT_BINARY_DIR}/bin)
SET(LIBRARY_OUTPUT_PATH ${PROJECT_BINARY_DIR}/lib)
哪里要改变目标存放路径,就在哪里加入上述的定义,所以应该在src/CMakeLists.txt中写
如何安装HelloWorld使用CMAKE一个新的指令:INSTALL
INSTALL的安装可以包括:二进制、动态库、静态库以及文件、目录、脚本等
使用CMAKE一个新的变量:CMAKE_INSTALL_PREFIX
touch COPYRIGHT mkdir doc cd doc touch hello.txt cd .. touch README touch runhello.sh安装COPYRIGHT和README
INSTALL(FILES COPYRIGHT README DESTINATION share/doc/cmake/)
FILES:文件
DESTINATION:
1、写绝对路径
2、写相对路径,相对路径的实际路径是:${CMAKE_INSTALL_PREFIX}/
CMAKE_INSTALL_PREFIX默认是在/usr/local/
cmake -DCMAKE_INSTALL_PREFIX=/usr ,在cmake的时候指定CMAKE_INSTALL_PREFIX变量的值
PROGRAMS:非目标文件的可执行程序安装(比如脚本)
INSTALL(PROGRAMS runhello.sh DESTINATION bin)
说明:实际安装到的是/usr/local/bin
- 通过在doc目录中建立CMakeLists.txt,通过install下的file
- 直接在工程目录通过 INSTALL (DIRECTORY doc/ DESTINATION share/doc/cmake)
DIRECTORY 后面连接的是所在SOURCE目录的相对路径
注意:abc和abc/有很大区别
目录名不以/结尾:这个目录将被安装为目标路径下的/
目录名以/结尾:将这个目录中的内容安装到目标路径
cd build cmake .. make make install //如果出现Maybe need administrative privileges. 使用sudo make install静态库和动态库的构建
1、建立一个静态库和动态库,提供HelloFunc函数供其他程序编程使用,HelloFunc向终端输出Hello World字符串
2、安装头文件与共享库
静态库和动态库的区别:
- 静态库的扩展名一般为".a"或".lib";动态库的扩展名一般为".so"或".dll"
- 静态库在编译时会直接整合到目标程序中,编译成功的可执行文件可独立运行
- 动态库在编译时不会被放到连接的目标程序中,可执行程序无法单独运行
mkdir cmake02 cd cmake02 mkdir build touch CMakeLists.txt mkdir lib cd lib touch CMakeLists.txt touch hello.cpp touch hello.h
hello.h #ifndef HELLO_H #define HELLO_H void HelloFunc(); #endif hello.cpp #include"hello.h" #includevoid HelloFunc() { std::cout << "Hello World!" << std::endl; } cmake02/CMakeLists.txt PROJECT(HELLO) ADD_SUBDIRECTORY(lib bin) cmake02/lib/CMakeLists.txt SET(LIBHELLO_SRC hello.cpp) ADD_LIBRARY(hello SHARED ${LIBHELLO_SRC})
进行编译
cd build cmake .. makeADD_LIBRARY
ADD_LIBRARY(hello SHARED ${LIBHELLO_SRC})
- hello:就是正常的库名,生成的名字前面会加上lib,最终产生的文件是libhello.so
- SHARED:动态库;STATIC:静态库
- ${LIBHELLO_SRC}:源文件
// 使用如下方式,只会构建出一个动态库,不会构建出静态库
ADD_LIBRARY(hello SHARED ${LIBHELLO_SRC})
ADD_LIBRARY(hello STATIC ${LIBHELLO_SRC})
// 修改静态库的名字,这样是可以同时构建出静态库和动态库,但是我们希望动态库和静态仅仅是后缀名不同
ADD_LIBRARY(hello SHARED ${LIBHELLO_SRC})
ADD_LIBRARY(hello_static STATIC ${LIBHELLO_SRC})
SET_TARGET_PROPERTIES
这条指令可以用来设置输出的名字,对于动态库,还可以用来指定动态库版本和API版本
修改版本号
SET_TARGET_PROPERTIES(hello PROPERTIES VERSION 1.2 SOVERSION 1)
VERSION指动态库版本,SOVERSION指API版本
同时构建静态和动态库
SET(LIBHELLO_SRC hello.cpp)
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)
在build目录下执行
rm -rf * cmake .. make安装共享库和头文件
在lib/CMakeLists.txt下添加
//将hello.放到相对路径的include/hello下,实际默认是/usr/local/include/hello INSTALL(FILES hello.h DESTINATION include/hello) // 其中hello动态库由LIBRARY指定到lib下,而hello_static由ARCHIVE指定到lib下 // 二进制,静态库和动态库安装都用TARGETS // ARCHIVE特指静态库,LIBRARY特指动态库,RUNTIME特指可执行二进制目标文件 // lib是相对路径,实际默认是/usr/local/lib INSTALL(TARGETS hello hello_static LIBRARY DESTINATION lib ARCHIVE DESTINATION lib)
安装时,指定一下路径,放到系统下
cmake -D CMAKE_INSTALL_PREFIX=/usr .. make make install
.
mkdir cmake03 mkdir build touch CMakeLists.txt mkdir src cd src touch CMakeLists.txt touch main.cpp cd ..
cmake03/CMakeLists.txt PROJECT(HELLO) ADD_SUBDIRECTORY(src bin) cmake03/src/CMakeLists.txt ADD_EXECUTABLE(hello main.cpp) INCLUDE_DIRECTORIES(/usr/include/hello) main.cpp #includeint main() { HelloFunc(); return 0; }
如果出现问题,将cmake03/src/CMakeLists.txt修改如此
INCLUDE_DIRECTORIES(/usr/include/hello) link_DIRECTORIES(/usr/include/hello) ADD_EXECUTABLE(hello main.cpp) TARGET_link_LIBRARIES(hello libhello.so)link_DIRECTORIES
用来指定非标准库的共享库的路径
TARGET_link_LIBRABRIES用于将两个可执行文件进行链接,这里是hello和libhello.so
至此,就完成了使用外部共享库和头文件



