概念
cmake 是一个跨平台的自动构建工具(除了 cmake 之外,还有一些其它的自动构建工具,常用的譬如 automake、autoconf 等),cmake 的诞生主要是为了解决直接使用 make+Makefile 这种方式无法实现跨平台的问题,所以 cmake 是可以实现跨平台的编译工具,这是它最大的特点 。
-
开放源代码。我们可以直接从 cmake 官网
下载到它的源代码 - 跨平台。cmake 并不直接编译、构建出最终的可执行文件或库文件,它允许开发者编写一种与平台无关的 CMakeLists.txt 文件来制定整个工程的编译流程,cmake 工具会解析 CMakeLists.txt 文件语法规则,再根据当前的编译平台,生成本地化的 Makefile 和工程文件,最后通过 make 工具来编译整个工程
- 语法规则简单。
cmake与Makefile关系
cmake的使用方法
sudo apt-get install cmake
安装完成之后可以通过 cmake –version 命令查看 cmake的版本号。cmake 官方也给大家提供相应教程,链接地址如下所示:
文档总链接地址:
培训教程:
https://cmake.org/cmake/help/latest/guide/tutorial/index.html
-
单一源文件
源码代码:
main.c
#include <stdio.h>
int main()
{
printf("Hello World!\n");
return 0;
}
CMakeList.txt
project(HELLO) #project 是一个命令,命令的使用方式有点类似于 C 语言中的函数,因为命令后面需要提供一对括号,并且通常需要我们提供参数,多个参数使用空格分隔而不是逗号“,”。project 命令用于设置工程的名称,括号中的参数 HELLO 便是我们要设置的工程名称;设置工程名称并不是强制性的,但是最好加上。
add_executable(hello ./main.c) #add_executable 同样也是一个命令,用于生成一个可执行文件,在本例中传入了两个参数,第一个参数表示生成的可执行文件对应的文件名,第二个参数表示对应的源文件
执行命令:
cmake ./ #生成Makefile
make
./hello
out-of-source方式构建
cmake 生成的文件以及最终的可执行文件 hello 与工程的源码文件 main.c 混在了一起,这使得工程看起来非常乱,当我们需要清理 cmake 产生的文件时将变得非常麻烦,这不是我们想看到的;我们需要将构建过程生成的文件与源文件分离开来,不让它们混杂在一起,也就是使用 out-of-source 方式构建
mkdir build
cd build
cmake ../
make
./hello
cd ..
rm -rf build #删除编译的结果(很关键)
-
多个源文件
hello.h:
#ifndef __TEST_HELLO_
#define __TEST_HELLO_
void hello(const char *name);
#endif //__TEST_HELLO_
hello.c:
#include <stdio.h>
#include "hello.h"
void hello(const char *name)
{
printf("Hello %s!\n", name);
}
main.c:
#include "hello.h"
int main(void)
{
hello("World");
return 0;
}
CMakeList.txt:
project(HELLO)
set(SRC_LIST main.c hello.c)
add_executable(hello ${SRC_LIST}) #使用到了 set 命令,set 命令用于设置变量,如果变量不存在则创建该变量并设置它
-
生成库文件
CMakeList.txt:
project(HELLO)
add_library(libhello hello.c) #生成静态库.a文件
add_executable(hello main.c)
target_link_libraries(hello libhello) #target_link_libraries 命令为目标指定依赖库,在本例中,hello.c 被编译为库文件,并将其链接进 hello 程序。
如果要生成动态库文件,可以这样做:
add_library(libhello SHARED hello.c) #生成动态库文件
add_library(libhello STATIC hello.c) #生成静态库文件
修改生成的库文件名字
add_library(hello hello.c) #不能修改生成库的名称,因为不能直接修改 add_library 命令的参数
set_target_properties(libhello PROPERTIES OUTPUT_NAME "hello") #用于设置目标的属性,这里通过 set_target_properties 命令对 libhello 目标的OUTPUT_NAME 属性进行了设置,将其设置为 hello
CMakeList.txt:
cmake_minimum_required(VERSION 3.5) #要求的最低的版本
project(HELLO)
add_library(libhello SHARED hello.c) #动态库
set_target_properties(libhello PROPERTIES OUTPUT_NAME "hello") #"hello" 属性
add_executable(hello main.c)
target_link_libraries(hello libhello) #参考上文,应用程序名称
- 将源文件组织到不同的目录
# tree
.
├── build
│ ├── CMakeCache.txt
│ ├── CMakeFiles
│ │ ├── 3.16.3
│ │ │ ├── CMakeCCompiler.cmake
│ │ │ ├── CMakeCXXCompiler.cmake
│ │ │ ├── CMakeDetermineCompilerABI_C.bin
│ │ │ ├── CMakeDetermineCompilerABI_CXX.bin
│ │ │ ├── CMakeSystem.cmake
│ │ │ ├── CompilerIdC
│ │ │ │ ├── a.out
│ │ │ │ ├── CMakeCCompilerId.c
│ │ │ │ └── tmp
│ │ │ └── CompilerIdCXX
│ │ │ ├── a.out
│ │ │ ├── CMakeCXXCompilerId.cpp
│ │ │ └── tmp
│ │ ├── cmake.check_cache
│ │ ├── CMakeDirectoryInformation.cmake
│ │ ├── CMakeOutput.log
│ │ ├── CMakeTmp
│ │ ├── Makefile2
│ │ ├── Makefile.cmake
│ │ ├── progress.marks
│ │ └── TargetDirectories.txt
│ ├── cmake_install.cmake
│ ├── libhello
│ │ ├── CMakeFiles
│ │ │ ├── CMakeDirectoryInformation.cmake
│ │ │ ├── libhello.dir
│ │ │ │ ├── build.make
│ │ │ │ ├── C.includecache
│ │ │ │ ├── cmake_clean.cmake
│ │ │ │ ├── cmake_clean_target.cmake
│ │ │ │ ├── DependInfo.cmake
│ │ │ │ ├── depend.internal
│ │ │ │ ├── depend.make
│ │ │ │ ├── flags.make
│ │ │ │ ├── hello.c.o
│ │ │ │ ├── link.txt
│ │ │ │ └── progress.make
│ │ │ └── progress.marks
│ │ ├── cmake_install.cmake
│ │ ├── libhello.a
│ │ └── Makefile
│ ├── Makefile
│ └── src
│ ├── CMakeFiles
│ │ ├── CMakeDirectoryInformation.cmake
│ │ ├── hello.dir
│ │ │ ├── build.make
│ │ │ ├── C.includecache
│ │ │ ├── cmake_clean.cmake
│ │ │ ├── DependInfo.cmake
│ │ │ ├── depend.internal
│ │ │ ├── depend.make
│ │ │ ├── flags.make
│ │ │ ├── link.txt
│ │ │ ├── main.c.o
│ │ │ └── progress.make
│ │ └── progress.marks
│ ├── cmake_install.cmake
│ ├── hello
│ └── Makefile
├── CMakeLists.txt #顶层CMakeLists.txt
├── libhello
│ ├── CMakeLists.txt #CMakeLists.txt,在src文件夹中
│ ├── hello.c
│ └── hello.h
└── src
├── CMakeLists.txt #CMakeList.txt,在libhello文件夹中
└── main.c
16 directories, 56 files
顶层 CMakeLists.txt
cmake_minimum_required(VERSION 3.5)
project(HELLO)
add_subdirectory(libhello) #子目录
add_subdirectory(src) #子目录
src 目录下的 CMakeLists.txt
include_directories(${PROJECT_SOURCE_DIR}/libhello) #新增加了 include_directories 命令用来指明头文件所在的路径,并且使用到了 PROJECT_SOURCE_DIR 变量,该变量指向了一个路径,从命名上可知,该变量表示工程源码的目录。
add_executable(hello main.c)
target_link_libraries(hello libhello)
libhello 目录下的 CMakeLists.txt
add_library(libhello hello.c)
set_target_properties(libhello PROPERTIES OUTPUT_NAME "hello")
-
将生成的可执行文件和库文件放置到单独的目录下
在默认情况下,make 编译生成的可执行文件和库文件会与 cmake 命令产生的中间文件(CMakeCache.txt、CmakeFiles、cmake_install.cmake 以及 Makefile 等)混在一起,也就是它们在同一个目录下;如果我想让可执行文件单独放置在 bin 目录下,而库文件单独放置在 lib 目录下,就像下面这样:
(1)将 src 目录下的 CMakeList.txt 文件进行修改:
include_directories(${PROJECT_SOURCE_DIR}/libhello)
set(EXECUTABLE_OUTPUT_PATH ${PROJECT_BINARY_DIR}/bin) #设置bin文件夹
add_executable(hello main.c)
target_link_libraries(hello libhello)
(2)对 libhello 目录下的 CMakeList.txt 文件进行修改:
set(LIBRARY_OUTPUT_PATH ${PROJECT_BINARY_DIR}/lib)
add_library(libhello hello.c)
set_target_properties(libhello PROPERTIES OUTPUT_NAME "hello")
文件结构:
#tree
.
├── build
│ ├── bin
│ │ └── hello
│ ├── CMakeCache.txt
│ ├── CMakeFiles
│ │ ├── 3.16.3
│ │ │ ├── CMakeCCompiler.cmake
│ │ │ ├── CMakeCXXCompiler.cmake
│ │ │ ├── CMakeDetermineCompilerABI_C.bin
│ │ │ ├── CMakeDetermineCompilerABI_CXX.bin
│ │ │ ├── CMakeSystem.cmake
│ │ │ ├── CompilerIdC
│ │ │ │ ├── a.out
│ │ │ │ ├── CMakeCCompilerId.c
│ │ │ │ └── tmp
│ │ │ └── CompilerIdCXX
│ │ │ ├── a.out
│ │ │ ├── CMakeCXXCompilerId.cpp
│ │ │ └── tmp
│ │ ├── cmake.check_cache
│ │ ├── CMakeDirectoryInformation.cmake
│ │ ├── CMakeOutput.log
│ │ ├── CMakeTmp
│ │ ├── Makefile2
│ │ ├── Makefile.cmake
│ │ ├── progress.marks
│ │ └── TargetDirectories.txt
│ ├── cmake_install.cmake
│ ├── lib
│ │ └── libhello.a
│ ├── libhello
│ │ ├── CMakeFiles
│ │ │ ├── CMakeDirectoryInformation.cmake
│ │ │ ├── libhello.dir
│ │ │ │ ├── build.make
│ │ │ │ ├── C.includecache
│ │ │ │ ├── cmake_clean.cmake
│ │ │ │ ├── cmake_clean_target.cmake
│ │ │ │ ├── DependInfo.cmake
│ │ │ │ ├── depend.internal
│ │ │ │ ├── depend.make
│ │ │ │ ├── flags.make
│ │ │ │ ├── hello.c.o
│ │ │ │ ├── link.txt
│ │ │ │ └── progress.make
│ │ │ └── progress.marks
│ │ ├── cmake_install.cmake
│ │ └── Makefile
│ ├── Makefile
│ └── src
│ ├── CMakeFiles
│ │ ├── CMakeDirectoryInformation.cmake
│ │ ├── hello.dir
│ │ │ ├── build.make
│ │ │ ├── C.includecache
│ │ │ ├── cmake_clean.cmake
│ │ │ ├── DependInfo.cmake
│ │ │ ├── depend.internal
│ │ │ ├── depend.make
│ │ │ ├── flags.make
│ │ │ ├── link.txt
│ │ │ ├── main.c.o
│ │ │ └── progress.make
│ │ └── progress.marks
│ ├── cmake_install.cmake
│ └── Makefile
├── CMakeLists.txt
├── libhello
│ ├── CMakeLists.txt
│ ├── hello.c
│ └── hello.h
└── src
├── CMakeLists.txt
└── main.c
18 directories, 56 files