cmake 基本入门(编译可执行文件和动态库)
编译可执行文件
单文件
cmake_minimum_required(VERSION 3.4.2) project(single) # 定义项目名称 add_executable(single main.cc) # 添加可执行文件
main.cc 如下
#include <stdio.h> #include <stdlib.h> double power(double base, int exponent) { int result = base; int i; if (exponent == 0) { return 1; } for(i = 1; i < exponent; ++i){ result = result * base; } return result; } int main(int argc, char *argv[]) { if (argc < 3){ printf("Usage: %s base exponent \n", argv[0]); return 1; } double base = atof(argv[1]); int exponent = atoi(argv[2]); double result = power(base, exponent); printf("%g ^ %d is %g\n", base, exponent, result); return 0; }
执行以下命令
mkdir build && cd build && cmake .. && make
结果如下,就是这么简单,不过对于单文件,没有直接gcc或者g++来的直接
├── CMakeLists.txt ├── build │ ├── CMakeCache.txt │ ├── CMakeFiles │ ├── Makefile │ ├── cmake_install.cmake │ └── single └── main.cc
单目录多文件
我们把main.cc里面的power函数的拆分到头文件和cc文件,修改CMakeLists.txt如下
cmake_minimum_required(VERSION 3.4.2) project(single) aux_source_directory(. DIR_SRCS) # 遍历目录的所有文件,赋值给Dir_SRCS add_executable(single ${DIR_SRCS})
还是一样执行以下命令
mkdir build && cd build && cmake .. && make
这个时候cmake比传统的gcc和g++要好一点了
├── CMakeLists.txt ├── MathFunction.cc ├── MathFunctions.h ├── build │ ├── CMakeCache.txt │ ├── CMakeFiles │ ├── Makefile │ ├── cmake_install.cmake │ └── single └── main.cc
多目录多文件
我们再折腾一下,把power函数相关的放入一个math文件夹,目录结构如下
├── CMakeLists.txt ├── main.cc └── math ├── MathFunction.cc └── MathFunctions.h
同时修改CMakeLists.txt加入math目录
cmake_minimum_required (VERSION 2.8) project (many) set(CMAKE_MACOSX_RPATH 1) aux_source_directory(. DIR_SRCS) aux_source_directory(./math MATH) list(APPEND DIR_SRCS ${MATH}) add_executable(many ${DIR_SRCS})
最后执行以下命令即可
mkdir build && cd build && cmake .. && make
多目录+子目录.a文件
我们稍作修改一下,我们想让math先编译成.a文件,这样math的用途可以更广
注意目录结构中,math文件夹里多了一个CMakeLists.txt文件,这意味着math文件夹可以独立编译
├── CMakeLists.txt ├── main.cc └── math ├── CMakeLists.txt ├── MathFunction.cc └── MathFunctions.h
我们看下math的CMakeLists文件,很简单,不同的是生成了一个静态库
aux_source_directory(. DIR_LIB_SRCS)
# 生成链接库
add_library (math STATIC ${DIR_LIB_SRCS})
主目录的CMakeLists文件也有小小的变动
cmake_minimum_required (VERSION 2.8) project (many) set(CMAKE_MACOSX_RPATH 1) aux_source_directory(. DIR_SRCS) # 添加 math 子目录 add_subdirectory(./math math) add_executable(many ${DIR_SRCS}) target_link_libraries(many math)
最后的目录结构如下(省略了一些重复的目录文件),可以看到math目录下面生成了一个.a文件
├── CMakeLists.txt ├── build │ ├── many │ └── math │ └── libmath.a ├── main.cc └── math ├── CMakeLists.txt ├── MathFunction.cc └── MathFunctions.h
最后看下这四种方式生成的可执行文件是否都能正常工作
$ cd ../../single_file/build/ $ ./single 2 3 2 ^ 3 is 8 $ cd ../../single_dir_many_file/build/ $ ./single 2 3 2 ^ 3 is 8 $ cd ../../many_dir_many_file/build/ $ ./many 2 3 2 ^ 3 is 8 $ cd ../../many_dir_many_file_a/build/ $ ./many 2 3 2 ^ 3 is 8
生成动态库
也是很简单的,改动CMakeLists文件的一行即可
cmake_minimum_required (VERSION 2.8) project (many) set(CMAKE_MACOSX_RPATH 1) aux_source_directory(. DIR_SRCS) # 添加 math 子目录 add_subdirectory(./math math) # 就是下面这一行 add_library(many SHARED ${DIR_SRCS}) target_link_libraries(many math)
在mac上面生成的动态库不是.so后缀,而是.dylib后缀(相同的代码在Linux上生成的应该是so)
├── CMakeLists.txt ├── build │ ├── libmany.dylib │ └── math ├── main.cc └── math ├── CMakeLists.txt ├── MathFunction.cc └── MathFunctions.h
mac上生成so动态库
如果是mac开发给Android或者Linux系统用,自然就有生成so动态库的需求,以Android为例,修改CMakeLists如下(碰到的大坑:set 命令要放在project命令前面,否则可能不生效,因为命令行可以但CmakeLists不行所以发现了这个大坑)
cmake_minimum_required (VERSION 2.8) set(CMAKE_SYSTEM_NAME Android) # 如果没有配置相关环境变量,可以参考下面的设置 # set(CMAKE_ANDROID_NDK "/Users/qiweijie/Tools/android-ndk-r15c") # set(CMAKE_TOOLCHAIN_FILE "/Users/qiweijie/Tools/android-ndk-r15c/build/cmake/android.toolchain.cmake") # set(ANDROID_TOOLCHAIN clang) # set(ANDROID_NATIVE_API_LEVEL 14) # set(ANDROID_ABI "armeabi-v7a") # set(CMAKE_BUILD_TYPE Release) # set(CMAKE_CROSSCOMPILING "TRUE") # set(CMAKE_CXX_STANDARD 11) #c++标准 project (many) aux_source_directory(. DIR_SRCS) # 添加 math 子目录 add_subdirectory(./math math) add_library(many SHARED ${DIR_SRCS}) target_link_libraries(many math)
done