主要内容整理自《Cmake实践》一书
最简单的CMakeLists.txt:
PROJECT (HELLO)
ADD_EXECUTABLE(hello main.cpp)
PROJECT 指令
定义工程名称HELLO,并可指定工程支持的语言(支持语言可忽略,默认支持所有语言)
指令隐式的定义了两个 cmake 变量:
<projectname>_BINARY_DIR 和 <projectname>_SOURCE_DIR,如上面的HELLO_BINARY_DIR 和 HELLO_SOURCE_DIR。但是,cmake 系统也帮助我们预定义了 PROJECT_BINARY_DIR 和 PROJECT_SOURCE_DIR 变量,建议直接使用,不用根据工程名称修改。例如:
ADD_EXECUTABLE指令
生成一个文件名为 hello 的可执行文件
复杂一点:
PROJECT (HELLO)
SET(SRC_LIST main.c)
MESSAGE(STATUS "This is BINARY dir " ${HELLO_BINARY_DIR})
MESSAGE(STATUS "This is SOURCE dir "${HELLO_SOURCE_DIR})
ADD_EXECUTABLE(hello ${SRC_LIST})
SET、MESSAGE、ADD_EXECUTABLE等属于“指令”,指令不区分大小写
指令后的括号里可以有参数和变量,参数和变量区分大小写
SET(set)指令
SET 指令可以用来显式的定义变量
SET(SRC_LIST main.c t1.c t2.c)
MESSAGE 指令
用于向终端输出用户定义的信息,包含了三种类型:
SEND_ERROR、SATUS、FATAL_ERROR,常用SATUS
MESSAGE(STATUS "This is SOURCE dir is" ${HELLO_SOURCE_DIR})
变量
变量使用 ${ } 方式取值,但是在 IF 控制语句中是直接使用变量名
将源代码添加到子目录src
TEST下的CMakeLists.txt:
project(HELLO)
add_subdirectory(src bin)
src内的CMakeLists.txt:
add_executable(hello main.cpp)
ADD_SUBDIRECTORY 指令
ADD_SUBDIRECTORY(source_dir [binary_dir] [EXCLUDE_FROM_ALL])
可以指定编译输出(包含编译中间结果)的路径,如:上面的add_subdirectory(src bin),则编译后有:
还可以通过SET 指令重新定义最终的目标二进制的位置(指最终生成的 hello 或者最终的共享库,不包含编译生成的中间文件)
SET(EXECUTABLE_OUTPUT_PATH ${PROJECT_BINARY_DIR}/bin)
SET(LIBRARY_OUTPUT_PATH ${PROJECT_BINARY_DIR}/lib)
该语句和 ADD_EXECUTABLE 或 ADD_LIBRARY放在同一CMakeLists下。
静态库与动态库构建
TEST下的CMakeLists.txt:
PROJECT(HELLOLIB)
ADD_SUBDIRECTORY(lib)
lib下CMakeLists.txt:
SET(LIBHELLO_SRC hello.cpp)
ADD_LIBRARY(hello SHARED ${LIBHELLO_SRC})
lib下hello.cpp:
#include "hello.h"
void HelloFunc()
{
std::cout << "helloworld!" << std::endl;
}
lib下hello.h:
#ifndef HELLO_H
#define HELLO_H
#include <iostream>
void HelloFunc();
#endif
ADD_LIBRARY指令
ADD_LIBRARY (libname [SHARED|STATIC|MODULE] [EXCLUDE_FROM_ALL] source1
source2 ... sourceN)
SHARED:动态库 STATIC:静态库
动态库文件拓展名是.so,静态库文件拓展名是.a
如构建静态库:
ADD_LIBRARY(hello_static STATIC ${LIBHELLO_SRC})
如果想要名字相同的静态库和动态库,则需要SET_TARGET_PROPERTIES指令:
SET(LIBHELLO_SRC hello.cpp)
# 生成动态库
ADD_LIBRARY(hello SHARED ${LIBHELLO_SRC})
# 生成静态库
ADD_LIBRARY(hello_static STATIC ${LIBHELLO_SRC})
# 将生成的静态库hello_static.a重命名为hello.a
SET_TARGET_PROPERTIES(hello_static PROPERTIES OUTPUT_NAME "hello")
结果:
用外部共享库和头文件
即使有了include_directories(../lib),不会报:“error: hello.h: 没有那个文件或目录”,但是还会报错:main.cpp:(.text+0x9): undefined reference to `HelloFunc()'
这是因为并没有 link 到共享库 libhello 上。
LINK_DIRECTORIES指令
TARGET_LINK_LIBRARIES指令
为了解决上述问题,需要将目标文件链接到 libhello 。
LINK_DIRECTORIES(directory1 directory2 ...),可以添加非标准的共享库搜索路径
TARGET_LINK_LIBRARIES(target library1 <debug | optimized> library2 ...),用来为 target 添加需要链接的共享库,即将共享库链接到target上
为了解决前面遇到的 HelloFunc 未定义错误,需要做的是向 src/CMakeLists.txt 中添加如下指令: TARGET_LINK_LIBRARIES(main hello) 或者 TARGET_LINK_LIBRARIES(main libhello.so)
相同,链接到静态库上:TARGET_LINK_LIBRARIES(main libhello.a)