在 linux 下使用 CMake 构建应用程序

在 linux 下使用 CMake 构建应用程序

https://www.ibm.com/developerworks/cn/linux/l-cn-cmake/index.html

CMake 简介

CMake 是一个跨平台的自动化建构系统,它使用一个名为 CMakeLists.txt 的文件来描述构建过程,可以产生标准的构建文件,如 Unix 的 Makefile 或Windows Visual C++ 的 projects/workspaces 。文件 CMakeLists.txt 需要手工编写,也可以通过编写脚本进行半自动的生成。CMake 提供了比 autoconfig 更简洁的语法。在 linux 平台下使用 CMake 生成 Makefile 并编译的流程如下:

  1. `编写 CmakeLists.txt。```
  2. 执行命令“cmake PATH”或者“ccmake PATH”生成 Makefile ( PATH 是 CMakeLists.txt 所在的目录 )。
  3. 使用 make 命令进行编译。

第一个工程

现假设我们的项目中只有一个源文件`` main.cpp

清单 1 源文件 main.cpp
#include<iostream>

int main()
{
    std::cout<<"Hello word!"<<std::endl;
    return 0;
}

为了构建该项目,我们需要编写文件 CMakeLists.txt 并将其与 main.cpp 放在 同一个目录下:

清单 2 CMakeLists.txt
PROJECT(CMakeDemo)
CMAKE_MINIMUM_REQUIRED(VERSION 2.6)
#add_executable(CMakeDemo main.cpp)
AUX_SOURCE_DIRECTORY(. DIR_SRCS)
ADD_EXECUTABLE(main ${DIR_SRCS})

CMakeLists.txt 的语法比较简单,由命令、注释和空格组成,其中命令是不区分大小写的,符号"#"后面的内容被认为是注释。命令由命令名称、小括号和参数组成,参数之间使用空格进行间隔。例如对于清单2的 CMakeLists.txt 文件:第一行是一条命令,名称是 PROJECT ,参数是 CMakeDemo ,该命令表示项目的名称是 CMakeDemo。第二行的命令限定了 CMake 的版本。第四行使用命令 AUX_SOURCE_DIRECTORY 将当前目录中的源文件名称赋值给变量 DIR_SRCS。第四行使用命令 ADD_EXECUTABLE 指示变量 DIR_SRCS 中的源文件需要编译 成一个名称为 main 的可执行文件(第三行使用命令 ADD_EXECUTABLE将main.cpp编译 成一个名称CMakeDemo的可执行文件) 。

完成了文件 CMakeLists.txt 的编写后需要使用 cmake 或 ccmake 命令生成Makefile 。 ccmake 与命令 cmake 的不同之处在于 ccmake 提供了一个图形化的操作界面。cmake 命令的执行方式如下:

`cmake [options] <``path-to-source``>`

这里我们进入了 main.cpp 所在的目录后执行 “cmake .” 后就可以得到 Makefile 并使用 make 进行编译,如下图所示。

luni@ubuntu:~/Project/src/cmakedemo$ cmake .
-- The C compiler identification is GNU 5.4.0
-- The CXX compiler identification is GNU 5.4.0
-- Check for working C compiler: /usr/bin/cc
-- Check for working C compiler: /usr/bin/cc -- works
-- Detecting C compiler ABI info
-- Detecting C compiler ABI info - done
-- Detecting C compile features
-- Detecting C compile features - done
-- Check for working CXX compiler: /usr/bin/c++
-- Check for working CXX compiler: /usr/bin/c++ -- works
-- Detecting CXX compiler ABI info
-- Detecting CXX compiler ABI info - done
-- Detecting CXX compile features
-- Detecting CXX compile features - done
-- Configuring done
-- Generating done
-- Build files have been written to: /home/luni/Project/src/cmakedemo
luni@ubuntu:~/Project/src/cmakedemo$ ls
CMakeCache.txt  cmake_install.cmake  main.cpp
CMakeFiles      CMakeLists.txt       Makefile
luni@ubuntu:~/Project/src/cmakedemo$ make
Scanning dependencies of target main
[ 50%] Building CXX object CMakeFiles/main.dir/main.cpp.o
[100%] Linking CXX executable main
[100%] Built target main
luni@ubuntu:~/Project/src/cmakedemo$ ls
CMakeCache.txt  cmake_install.cmake  main      Makefile
CMakeFiles      CMakeLists.txt       main.cpp

cmake编译项目需要C++11特性的支持,只需要在CMakeLists.txt中加入:

add_definitions(-std=c++11)

执行可执行文件(muduo_server)需要依赖的库

target_link_libraries(muduo_server muduo_net muduo_base pthread)

指定可执行文件输出目录

set(EXECUTABLE_OUTPUT_PATH ${PROJECT_SOURCE_DIR}/bin)

添加需要链接的库文件目录,相当于g++命令的-L选项的作用,也相当于环境变量中增加LD_LIBRARY_PATH的路径的作用。

LINK_DIRECTORIES(../third/lib/log4cpp)

CMake中的set用于给一般变量,缓存变量,环境变量赋值。

set(SOURCE_SERVICE_FILES DispatchMsgService.cpp)
ADD_LIBRARY(service ${SOURCE_SERVICE_FILES})

CMake常用的预定义变量
PROJECT_NAME : 通过 project() 指定项目名称
PROJECT_SOURCE_DIR : 工程的根目录
PROJECT_BINARY_DIR : 执行 cmake 命令的目录
CMAKE_CURRENT_SOURCE_DIR : 当前 CMakeList.txt 文件所在的目录
CMAKE_CURRENT_BINARY_DIR : 编译目录,可使用 add subdirectory 来修改
EXECUTABLE_OUTPUT_PATH : 二进制可执行文件输出位置
LIBRARY_OUTPUT_PATH : 库文件输出位置
BUILD_SHARED_LIBS : 默认的库编译方式 ( shared 或 static ) ,默认为 static
CMAKE_C_FLAGS : 设置 C 编译选项
CMAKE_CXX_FLAGS : 设置 C++ 编译选项
CMAKE_CXX_FLAGS_DEBUG : 设置编译类型 Debug 时的编译选项
CMAKE_CXX_FLAGS_RELEASE : 设置编译类型 Release 时的编译选项
CMAKE_GENERATOR : 编译器名称
CMAKE_COMMAND : CMake 可执行文件本身的全路径
CMAKE_BUILD_TYPE : 工程编译生成的版本, Debug / Release

add_dependencies 为顶层目标引入一个依赖关系。

add_dependencies(target-name depend-target1 depend-target2 ...)
让一个顶层目标依赖于其他的顶层目标。一个顶层目标是由命令ADD_EXECUTABLE,ADD_LIBRARY,或者ADD_CUSTOM_TARGET产生的目标。

该命令用于查找库(动态库或者静态库),当构建依赖于第三方库/系统库,可以使用该命令来查找并使用库(Cmake中有另外一个命令find_package,能获取库的更多信息)
```cmake
find_library (<VAR> name [path1 path2 ...])

find_library(YAMLCPP libyaml-cpp.a)

用于存储该命令执行的结果,也就是找到的库的全路径(包含库名)
name用于指定待查找的库名称,库名称可以使用全称,例如libmymath.a(优先会当成全名搜索);也可以不带前缀(例如前缀lib)和后缀(例如Linux中的.so、.a,Mac中的.dylib等),直接使用mymath;

find_package用于查找包(通常是使用三方库),并返回关于包的细节(使用包所依赖的头文件、库文件、编译选项、链接选项等)
  与find_libaray直接在指定搜索目录下搜索库不同,find_package命令可以获取更多的信息,那么它的搜索方式也是与find_libaray不一样,它有两种不同的搜索方式,find_package命令的两种搜索模式:模块模式(Module mode)和配置模式(Config mode)这里暂不详说(因为太复杂了,我暂时也懒得看)。
基本命令

find_package(<PackageName> [version] [EXACT] [QUIET] [MODULE]
  [REQUIRED] [[COMPONENTS] [components...]]
  [OPTIONAL_COMPONENTS components...]
  [NO_POLICY_SCOPE])

find_package(Boost REQUIRED)
if(Boost_FOUND)
    include_directories(${Boost_INCLUDE_DIRS})
endif()
posted @ 2021-01-29 15:30  不知云深处  阅读(513)  评论(0编辑  收藏  举报