文章目录
学习经典的教程 cmake_examples
A_hello_cmake
A-hello-cmake$ tree
.
├── CMakeLists.txt
├── main.cpp
CMakeLists.txt
:
cmake_minimum_required(VERSION 2.6)
project (hello_cmake) //会创建PROJIECT_NAME
add_executable(${PROJECT_NAME} main.cpp) //习惯上把程序名和项目名字一样
概念
- binary directory
运行cmake命令的文件夹是CMAKE_BINARY_DIR
。支持In-place Build&out-of-source。
B_hello_headers
B-hello-headers$ tree
.
├── CMakeLists.txt
├── include
│ └── Hello.h
└── src
├── Hello.cpp
└── main.cpp
概念
- directory path
如CMAKE_SOURCE_DIR
,CMAKE_CURRENT_SOURCE_DIR
,PROJECT_SOURCE_DIR
,CMAKE_BINARY_DIR
,CMAKE_CURRENT_BINARY_DIR
,PROJECT_BINARY_DIR
.具体什么意思见Google。 - source files variable
# Create a sources variable with a link to all cpp files to compile
set(SOURCES
src/Hello.cpp
src/main.cpp
)
#上面的等价为
#file(GLOB SOURCES "src/*.cpp")
add_executable(${PROJECT_NAME} ${SOURCES})
现代的c++不推荐使用变量来标识源文件,一般是在
add_xxx
函数中直接声明
- including directories
target_include_directories(target
PRIVATE
${PROJECT_SOURCE_DIR}/include
)
相当于在编译这个target的时候加入的指令-I/directory/path
。PRIVATE
是的作用见下一节。
C_static_library
$ tree
.
├── CMakeLists.txt
├── include
│ └── static
│ └── Hello.h
└── src
├── Hello.cpp
└── main.cpp
概念
- adding a static library
add_library(hello_library STATIC
src/Hello.cpp
)
会产生一个libhello_library.a
名字的静态库。
如现代cmake,直接写出源文件,不使用变量
- Populating Including Directories
target_include_directories(hello_library
PUBLIC
${PROJECT_SOURCE_DIR}/include
)
PUBLIC
:编译这个目标和链接这个库的时候都要使用included directory。PRIVATE
:INTERFACE
:
推荐直接使用头文件的根目录,在包含头文件写如下的就好
#include "static/Hello.h"
- linking a library
add_executable(hello_binary
src/main.cpp
)
target_link_libraries( hello_binary
PRIVATE
hello_library
)
上面等价于(会自动的包含链接库的PUBLIC
和INTERFACE
对应的头文件目录)
/usr/bin/c++ CMakeFiles/hello_binary.dir/src/main.cpp.o -o hello_binary -rdynamic libhello_library.a
D_shared_library
$ tree
.
├── CMakeLists.txt
├── include
│ └── shared
│ └── Hello.h
└── src
├── Hello.cpp
└── main.cpp
概念
- adding a shared library
add_library(hello_library SHARED
src/Hello.cpp
)
产生libhello_library.so
的动态库。
- alias target
add_library(hello::library ALIAS hello_library)
- Linking a Shared Library
add_executable(hello_binary
src/main.cpp
)
target_link_libraries(hello_binary
PRIVATE
hello::library
)
等价于:
/usr/bin/c++ CMakeFiles/hello_binary.dir/src/main.cpp.o -o hello_binary -rdynamic libhello_library.so -Wl,-rpath,/home/matrim/workspace/cmake-examples/01-basic/D-shared-library/build
注意这里动态库和静态库的不同!
E_installing
$ tree
.
├── cmake-examples.conf
├── CMakeLists.txt
├── include
│ └── installing
│ └── Hello.h
├── README.adoc
└── src
├── Hello.cpp
└── main.cpp
概念
- installing
cmake可以设置make install
目标去安装二进制文件,库和其他文件。CAMKE_INSTALL_PREFIX
可以通过ccmake或cmake .. -DCMAKE_INSTALL_PREFIX=/install/location
设置。
# 二进制
install (TARGETS cmake_examples_inst_bin
DESTINATION bin)
# 动态库
install (TARGETS cmake_examples_inst
LIBRARY DESTINATION lib)
# 上面不能再window下工作
# 头文件
install(DIRECTORY ${PROJECT_SOURCE_DIR}/include/
DESTINATION include)
# 其他文件
install (FILES cmake-examples.conf
DESTINATION etc)
make install
运行后会产生install_manifest.txt
文件。
特别注记
- Overriding the default install location
CMAKE_INSTALL_PREFIX
默认为/usr/local/
。
要改变默认地址,在顶层CMakeLists.txt在加入任何二进制文件和库之前添加:
if( CMAKE_INSTALL_PREFIX_INITIALIZED_TO_DEFAULT )
message(STATUS "Setting default CMAKE_INSTALL_PREFIX path to ${CMAKE_BINARY_DIR}/install")
set(CMAKE_INSTALL_PREFIX "${CMAKE_BINARY_DIR}/install" CACHE STRING "The path to use for make install" FORCE)
endif()
这里修改到build/install
。
- DESTDIR
make install DESTDIR=/tmp/stage
install path会修改为${DESTDIR}/${CMAKE_INSTALL_PREFIX}
- unistall
sudo xargs rm < install_manifest.txt
F_build_type
$ tree
.
├── CMakeLists.txt
├── main.cpp
概念
- set build type
编译项目的时候的默认配置,有Release
,Debug
,MinSizeRel
,RelWithDebInfo
四种选项。
有两种方法
- gui工具
cmake .. -DCMAKE_BUILD_TYPE=Release
- set default build type
在顶层的CMakeLists.txt中加入
if(NOT CMAKE_BUILD_TYPE AND NOT CMAKE_CONFIGURATION_TYPES)
message("Setting build type to 'RelWithDebInfo' as none was specified.")
set(CMAKE_BUILD_TYPE RelWithDebInfo CACHE STRING "Choose the type of build." FORCE)
# Set the possible values of build type for cmake-gui
set_property(CACHE CMAKE_BUILD_TYPE PROPERTY STRINGS "Debug" "Release"
"MinSizeRel" "RelWithDebInfo")
endif()
G_compile_flags
$ tree
.
├── CMakeLists.txt
├── main.cpp
set per-Target c++ Flags
target_compile_definitions(cmake_examples_compile_flags
PRIVATE EX3
)
如果是library可以用PUBLIC
/INTERFACE
。
- Set Default C++ Flags
设置默认的编译flags需要在顶层的CMakeLists.txt中加入:
set (CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -DEX2" CACHE STRING "Set C++ Compiler Flags" FORCE)
CACHE STRING "Set C++ Compiler Flags" FORCE
的意思是强制在CMakeCache.txt
文件中设置这个变量。
如果是c编译flags:CMAKE_C_FLAGS
链接器flags:CMAKE_LINKER_FLAGS
如果设置了
CMAKE_CXX_FLAGS
等就全部默认是这个了,推荐还是使用target_compile_definitions
- Set CMake Flags
像上面一样有两种办法
- gui
- cmake … -DCMAKE_CXX_FLAGS=“-DEX3”
H_third_party_library
$ tree
.
├── CMakeLists.txt
├── main.cpp
概念
- finding a package
find_package(Boost 1.46.1 REQUIRED COMPONENTS filesystem system)
find_package
会寻找CMAKE_MODULE_PATH
(Linux默认是/usr/share/cmake/Modules
)中的FindXXX.cmake
- Checking if the package is found
被包含的package会设置变量XXX_FOUND
if(Boost_FOUND)
message ("boost found")
include_directories(${Boost_INCLUDE_DIRS})
else()
message (FATAL_ERROR "Cannot find Boost")
endif()
- Exported Variables
一个package被找到会export一些变量去告诉用户如何找到库,头文件,可执行文件。就像XXX_FOUND
一样,会被记录在FindXXX.cmake
的顶部。
Boost_INCLUDE_DIRS
-boost的头文件路径 .
- Alias / Imported targets
target_link_libraries( third_party_include
PRIVATE
Boost::filesystem
)
上面的Boost::filesystem
会自动添加 Boost::boost
和Boost::system
依赖。
- Non-alias targets
如果没有上面的imported target,那么怎么办呢?
xxx_INCLUDE_DIRS
:include目录的路径xxx_LIBRARY
:库的路径
如下使用:
# Include the boost headers
target_include_directories( third_party_include
PRIVATE ${Boost_INCLUDE_DIRS}
)
# link against the boost libraries
target_link_libraries( third_party_include
PRIVATE
${Boost_SYSTEM_LIBRARY}
${Boost_FILESYSTEM_LIBRARY}
)
I_compling_with_clang
$ tree
.
├── CMakeLists.txt
├── main.cpp
概念
- Compiler Option
Cmake提供了一些选项:
CMAKE_C_COMPILER
CMAKE_CXX_COMPILER
CMAKE_LINKER
- Setting Flags
你可以通过命令行和gui来设置。
下面是通过命令行:cmake .. -DCMAKE_C_COMPILER=clang-3.6 -DCMAKE_CXX_COMPILER=clang++-3.6
J_building_with_ninja
$ tree
.
├── CMakeLists.txt
├── main.cpp
概念
- generators
cmake包含了不同的generator,如Command-Line,IDE and Extra generators.
Command-Line Build Tool Generators:
- Ninja
- MMake Makefiles
- Unix Makefiles
- and so on…
IDE Build Tool Generators:
- vs
- Xcode
Extra Generators:
- CodeBlocks
- Sunlime Text 2
- Calling a Generator
$ cmake .. -G Ninja
$ ninja -v
$ ls
build.ninja CMakeCache.txt CMakeFiles cmake_install.cmake rules.ninja
K_import_targets
详细见H-third-party-library
L_cpp_standard
概念
有三种方式就不一一说明,下面是最普通的方法。
- Checking Compile flags
# 包含对应的函数
include(CheckCXXCompilerFlag)
# 检测是否支持,并把结果保存
CHECK_CXX_COMPILER_FLAG("-std=c++11" COMPILER_SUPPORTS_CXX11)
- Adding the flag
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()