CMAKE简明教程
@firestaradmin 2020年12月18日
客路青山外,行舟绿水前。
潮平两岸阔,风正一帆悬。
海日生残夜,江春入旧年。
乡书何处达?归雁洛阳边。
————《次北固山下》作者:王湾
CMAKE简明教程
一、CMake 构建
例程目录介绍
这是一个 CMake 的多目录,多子工程(应用),库模式链接和不使用库模式链接的例子。
工程目录如下图:
- app:该目录下有两个demo (应用程序or子工程)文件夹
- app/demo1:该目录为demo1 应用程序的目录,会调用外部的驱动文件,和LIB库文件
- app/demo2:同上
- bin:可执行程序输出目录。(可在CMakeLists文件中修改)
- build:CMake 输出文件夹
- driver:驱动文件(本例程,该驱动就是实现一个
myadd()
函数) - lib:lib库文件(实现了一个
mysub()
函数)
其实driver 文件夹和lib 文件夹都是给APP 提供函数功能的,区别在于driver中的文件我们不编译为lib库,所以driver 文件夹中不需要CMakeLists 文件。
顶层CMake 文件
该文件位于 ./CMakeLists.txt
内容如下:
# 设置最低需求版本
cmake_minimum_required(VERSION 3.19)
# 设置工程名称
project (CMAKE_DEMO)
# include dir
# 添加头文件搜索路径,会继承到子目标
include_directories(${CMAKE_CURRENT_SOURCE_DIR}/driver/include)
include_directories(${CMAKE_CURRENT_SOURCE_DIR}/lib)
# 添加子目录下的CMakeLists.txt
add_subdirectory(app/demo1)
add_subdirectory(app/demo2)
add_subdirectory(lib)
# 这里在子cmake中 链接,所以这里注释了
# 添加链接库
# target_link_libraries(demo1 myMathLib)
# 添加链接库
# target_link_libraries(demo2 myMathLib)
APP 下的子工程 CMake 文件
./app/demo1/CMakeLists.txt :
cmake_minimum_required(VERSION 3.19)
project (demo1)
# 添加头文件搜索路径
include_directories(.)
# aux_source_directory 会搜索目录下所有源文件
aux_source_directory(./ SOURCE_FILE)
# CMAKE_CURRENT_SOURCE_DIR 指向当前目录
aux_source_directory(${CMAKE_CURRENT_SOURCE_DIR}/../../driver/src/ SOURCE_FILE2)
# CMAKE_SOURCE_DIR 指向总工程的根目录,设置 EXECUTABLE_OUTPUT_PATH 变量,将可执行文件存放到该目录
set(EXECUTABLE_OUTPUT_PATH ${CMAKE_SOURCE_DIR}/bin)
# 输出可执行文件
add_executable(demo1 ${SOURCE_FILE} ${SOURCE_FILE2})
# 添加链接库
target_link_libraries(demo1 myMathLib)
./app/demo2/CMakeLists.txt :
cmake_minimum_required(VERSION 3.19)
project (demo2)
# 添加头文件搜索路径
include_directories(.)
# aux_source_directory 会搜索目录下所有源文件
# aux_source_directory(./ SOURCE_FILE)
# CMAKE_CURRENT_SOURCE_DIR 指向当前目录
# aux_source_directory(${CMAKE_CURRENT_SOURCE_DIR}/../../driver/src/ SOURCE_FILE2)
# 有时候可能不需要目录下的所有源文件,可以使用SET 来指定源文件. CMAKE_SOURCE_DIR 指向总工程的根目录
set(SRC_LIST
main.c
${CMAKE_SOURCE_DIR}/driver/src/mymath.c
)
# CMAKE_SOURCE_DIR 指向总工程的根目录,设置 EXECUTABLE_OUTPUT_PATH 变量,将可执行文件存放到该目录
set(EXECUTABLE_OUTPUT_PATH ${CMAKE_SOURCE_DIR}/bin)
# 输出可执行文件
add_executable(demo2 ${SRC_LIST})
# 添加链接库
target_link_libraries(demo2 myMathLib)
LIB 下的CMake 文件
./lib/CMakeLists.txt:
cmake_minimum_required(VERSION 3.19)
# 查找当前目录下的所有源文件
# 并将名称保存到 DIR_LIB_SRCS 变量
aux_source_directory(. DIR_LIB_SRCS)
# 生成链接库
# add_library(<name> [STATIC | SHARED | MODULE]
# [EXCLUDE_FROM_ALL]
# [<source>...])
# 默认 不填写是静态库 也就是 STATIC
# STATIC:静态创建库,此模式该库会集成到应用程序中。
# SHARED:动态创建库,会生成.dll .so .a 等lib文件,需要将文件和程序放在同一目录,才可运行程序。
# MODULE:在使用 dyld 的系统有效,如果不支持 dyld,则被当作 SHARED 对待。
# EXCLUDE_FROM_ALL:这个库不会被默认构建,除非有其他的组件依赖或者手工构建。
add_library (myMathLib ${DIR_LIB_SRCS})
# add_library (myMathLib STATIC ${DIR_LIB_SRCS})
二、编译输出
1、在根目录创建 build 目录,进入后输入如下命令:
cmake ..
或者
cmake .. -G "MingW Makefiles"
-G
指定编译器,控制台输入 cmake --help
即可查询编译器名称
2、cmake 后使用make 进行编译链接
win10 下:
在build/ 目录下 输入以下命令(以MinGW 为例):
mingw32-make
mingw32-make demo1
mingw32-make clean
- mingw32-make:默认编译全部 target
- mingw32-make demo1:只编译 demo1
- mingw32-make clean:删除所有编译
Linux 下:
mingw32-make
make demo1
make clean
- make:默认编译全部 target
- make demo1:只编译 demo1
- make clean:删除所有编译
三、文件内容
1、demo
./app/demo1/main.c
#include <stdio.h>
#include "main.h"
#include "mymath.h"
#include "mymath2.h"
void main()
{
int add_temp, sub_temp;
add_temp = myadd(NUM1, 10);
sub_temp = mysub(NUM1, 10);
printf("======= demo1: ========\r\n");
printf("add result= %d\r\n", add_temp);
printf("sub result= %d\r\n", sub_temp);
char c;
c = getchar();
}
./app/demo1/main.h
#ifndef __MAIN_H_
#define __MAIN_H_
#define NUM1 100
#endif // !__MAIN_H_
2、driver
./driver/include/mymath.h
#ifndef __MYMATH_H_
#define __MYMATH_H_
int myadd(int a, int b);
#endif // !__MYMATH_H_
./driver/include/mymath.c
#include "mymath.h"
int myadd(int a, int b)
{
return a+b;
}
3、lib
./lib/mymath2.h
#ifndef __MYMATH2_H_
#define __MYMATH2_H_
int mysub(int a, int b);
#endif // !__MYMATH2_H_
./lib/mymath2.c
#include "mymath2.h"
int mysub(int a, int b)
{
return a-b;
}
四、 配合SH 脚本
build.sh
#!/bin/bash
BUILD_PROJECT=c_test
NINJA_EXE=$(pwd)/tools/ninja.exe
# echo ${NINJA_EXE}
CMAKE_EXE="D:/Program Files/CMAKE/bin/cmake.exe"
# because path have space, so use ''
CMAKE_OPTIONS="-DCMAKE_MAKE_PROGRAM=${NINJA_EXE}"
# echo ${CMAKE_OPTIONS}
echo "clean first ..."
. clean.sh
echo "mkdir build"
if [ ! -d "./build/" ];then
mkdir build
else
echo "build folder already exist"
fi
cd build
"${CMAKE_EXE}" -S .. -G "Ninja" ${CMAKE_OPTIONS}
# ${NINJA_EXE} -j 64
# ${NINJA_EXE} -j 64 c_test
${NINJA_EXE} -j 64 ${BUILD_PROJECT} > ../build_log.txt 2>&1
clean.sh
#!/bin/bash
echo "clean build ..."
rm -rf ./build/
五、使用ninja 并且放入工程文件下
# 设置最低需求版本
cmake_minimum_required(VERSION 3.19)
# set(CMAKE_SYSTEM_NAME Generic)
# specify make program
set(CMAKE_MAKE_PROGRAM ${CMAKE_CURRENT_SOURCE_DIR}/tools/ninja.exe)
# specify the cross compiler
set(CMAKE_C_COMPILER "D:/Program Files/mingw64/bin/gcc.exe")
set(CMAKE_CXX_COMPILER "D:/Program Files/mingw64/bin/g++.exe")
# generate flags from user variables
set(COMPILE_FLAGS "-W")
set(CMAKE_C_FLAGS "${COMPILE_FLAGS} ")
set(CMAKE_CXX_FLAGS "${COMPILE_FLAGS} ")
# 设置工程名称
project (c_cpp_demo)
# include dir
# 添加头文件搜索路径,会继承到子目标
include_directories(${CMAKE_CURRENT_SOURCE_DIR}/driver/include)
# include_directories(${CMAKE_CURRENT_SOURCE_DIR}/lib)
include_directories(${CMAKE_CURRENT_SOURCE_DIR}/lib/c/ug_log)
# 添加子目录下的CMakeLists.txt
# add_subdirectory(app/demo1)
# add_subdirectory(app/demo2)
# add_subdirectory(lib)
add_subdirectory(app/c_test)
# 这里在子cmake中 链接,所以这里注释了
# 添加链接库
# target_link_libraries(demo1 myMathLib)
# 添加链接库
# target_link_libraries(demo2 myMathLib)
OTHER:
添加外部目录为子目录:
如果要添加的子目录是同级或者外部,直接用 add_subdirectory
就不行了。
原来add_subdirectory
还有一个 binary_dir
参数(一般这个参数用不到,所以从来没关注过)
这个参数用来指定source_dir
在输出文件夹中的位置,如果没有指定的时候,就用source_dir
的值。
如果要添加外部文件夹,binary_dir
就必须指定。
如 要添加上级的src目录:
# mySrc.out参数用于指定外部文件夹在输出文件夹中的位置
add_subdirectory(${CMAKE_SOURCE_DIR}/../mySrc mySrc.out)
本博客所有文章除特别声明外,均采用 CC BY-SA 4.0 协议 ,转载请注明出处!