【Linux】CMake编译C/C++工程文件
文章目录
前言
CMake 是一个开源、跨平台的管理源代码构建的工具。CMake 广泛用于 C 和 C++ 语言,但它也可以用于构建其他语言的源代码。makefile通常依赖于你当前的编译平台,使用CMake 可以产生自动化生成makefile,达到可以移植跨平台的目的。
一、CMake编译工程
项目主目录存在一个CMakeLists.txt文件
1.1 两种方式设置编译规则
- 包含源文件的子文件夹包含CMakeLists.txt文件,主目录的CMakeLists.txt通过add_subdirectory添加子目录即可
- 包含源文件的子文件夹未包含CMakeLists.txt文件,子目录编译规则体现在主目录的CMakeLists.txt中
1.2 两种构建方式
- 内部构建(in-source build):内部构建会在同级目录下产生一大堆中间文件,与源文件放在一起显得杂乱无章
- 外部构建(out-of-source build):将编译输出文件与源文件放在不同目录中,常创建一个build目录,将编译输出文件放在build目录下
1.3 CMake构建C/C++工程流程
- 手动编写
CMakeLists.txt
- 执行
cmake PATH
生成Makefile(PATH是顶层CMakeLists.txt所在的目录) - 执行命令
make
进行编译
二、CMake重要指令及常用变量
2.1 CMake语法特性
- 基本语法格式:指令(参数1 参数二…)
- 参数使用括号括起来
- 指令名不区分大小写,参数或变量区分大小写
- 指令名不区分大小写无关,参数和变量区分大小写
2.2 CMake重要指令
-
cmake_minimum_required
:指定CMake最小版本要求
语法:cmake_minimum_required(VERSION versionnumber [FATAL_ERROR])#设置CMake最低版本为2.5 cmake_minimum_required(VERSION 2.5)
-
project
:定义工程名称,并且可指定工程支持的语言
语法:project(projectname [CXX] [C] [Java])#设置工程名为HELLO project(HELLO)
-
set
:显示定义变量
语法:set(VAR [VALUE] [CACHE TYPE DOCSTRING [FORCE]]))#定义变量MYFRIEND_SRC,其值为include/myfriend.h src/myfriend.cpp set(MYFRIEND_SRC include/myfriend.h src/myfriend.cpp)
-
include_directories
:向工程添加多个特定的头文件搜索路径
语法:include_directories([AFTER|BEFORE] [SYSTEM] dir1 dir2 …)#将目录/usr/include/myincludefolder ./include添加进头文件搜索路径 include_directories(/usr/include/myincludefolder ./include)
-
link_directories
:向工程添加多个特定库文件的搜索路径
语法:link_directories(dir1 dir2 …)#将目录/usr/lib/mylibfolder ./lib添加进库文件搜索路径 link_directories(/usr/lib/mylibfolder ./lib)
-
add_library
:生成库文件
语法:add_library(libname [SHARED|STATIC|MODULE] [EXCLUDE_FROM_ALL] source1 source2 … sourceN)#通过变量SRC生成libhello.so共享库 add_library(hello SHARED ${SRC})
-
add_compile_options
:添加编译参数
语法:add_compile_options(option1 option2 …)#添加编译参数-g -o2 -std=c++11(相当于g++ -g -o2 -std=c++11) add_compile_options(-g -o2 -std=c++11)
-
add_executable
:生成可执行文件
语法:add_executable(exename souce1 source2 …)#生成可执行文件main_cmake,源文件为main.cpp、src/myfriend.cpp #相当于 g++ main.cpp src/myfriend.cpp -Iinclude -o main add_executable(main_cmake main.cpp src/myfriend.cpp)
-
target_link_libraries
:为target添加需要链接的共享库(相当于g++编译时的-I参数)
语法:target_link_libraries(target library<debug| optimized> library2…)#将MYFRINED_SHARED动态库文件链接到可执行文件main_cmake target_link_libraries(main_cmake MYFRINED_SHARED)
-
add_subdirectories
:向当前工程添加存放源文件的子目录,并且可以指定中间二进制和目标二进制文件的存放位置
语法:add_subdirectories(source_dir [binary_dir] [EXCLUDE_FROM_ALL])#添加src子目录,src需要有一个CMakeLists.txt文件 add_subdirectories(src)
-
aux_source_directory
:发现一个目录下所有的源代码文件并将列表存储在一个变量中,这个指令临时被用来构建源文件列表
语法:aux_source_directory(dir VARIABLE)#定义SRC变量,其值为当前目录(.)下所有的源代码文件 aux_source_directory(. SRC) #编译SRC变量所代表的所有源代码文件,生成main可执行文件 add_executable(main ${SRC})
2.3 CMake常用变量
CMAKE_C_FLAGS
:gcc编译选项CMAKE_CXX_FLAGS
:g++编译选项CMAKE_BUILD_TYPE
:编译类型(Debug、Release)CMAKE_BINARY_DIR
、PROJECT_BINARY_DIR
、_BINARY_DIR
:如果为in source build,指工程顶层目录;如果是out of source,指工程编译发生的目录CMAKE_SOURCE_DIR
、PROJECT_SOURCE_DIR
、_SOURCE_DIR
:无论采用何种编译方式都指工程顶层目录CMAKE_C_COMPILER
:指定C编译器CMAKE_CXX_COMPILER
:指定C++编译器EXECUTABLE_OUTPUT_PATH
:可执行文件输出的存放路径LIBRARY_OUTPUT_PATH
:库文件输出的存放路径
2.4 生成静态库/共享库
库分为静态库(Static Library)和共享库(Shared library)两类。静态库文件的扩展名是.a,共享库文件的扩展名是.so(在CYGWIN环境下,分别叫做.o和.dll)。
2.4.1生成静态库
静态库:可重定位目标文件以一种特定的方式打包成一个单独的文件,并且在链接生成可执行文件时,从这个单独的文件中“拷贝”它自己需要的内容到最终的可执行文件中。这个单独的文件,称为静态库。linux中通常以.a(archive)为后缀
CMakeLists.txt:
#设置CMake最低版本为2.5
cmake_minimum_required(VERSION 2.5)
#设置工程名为HELLO
project(HELLO)
#通过hello.cpp生成静态库文件libhello.a
add_library(hello hello.cpp)
[vvvcxjvvv@localhost hello]$ cd build
[vvvcxjvvv@localhost build]$ cmake ../
-- The C compiler identification is GNU 4.8.5
-- The CXX compiler identification is GNU 4.8.5
-- 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
-- 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
-- Configuring done
-- Generating done
-- Build files have been written to: /home/vvvcxjvvv/Desktop/cxj_data/mycode/hello/build
[vvvcxjvvv@localhost build]$ make
Scanning dependencies of target hello
[100%] Building CXX object CMakeFiles/hello.dir/hello.o
Linking CXX static library libhello.a
[100%] Built target hello
[vvvcxjvvv@localhost build]$
2.4.2 生成共享库
动态库:动态库和静态库类似,但是它并不在链接时将需要的二进制代码都“拷贝”到可执行文件中,而是仅仅“拷贝”一些重定位和符号表信息,这些信息可以在程序运行时完成真正的链接过程。linux中通常以.so(shared object)作为后缀。
CMakeLists.txt编写:
#设置最低cmake版本
cmake_minimum_required(VERSION 2.5)
#设置项目名称为MYFRIEND
project(MYFRIEND)
#定义变量MYFRIEND_SRC为include/myfriend.h src/myfriend.cpp
set(MYFRIEND_SRC include/myfriend.h src/myfriend.cpp)
#将include目录添加进头文件搜索路径(重要!!!否则找不到include/myfriend.h)
include_directories(include)
#通过变量MYFRIEND_SRC生成libMYFRINED_SHARED.so共享库
add_library(MYFRINED_SHARED SHARED ${MYFRIEND_SRC})
[vvvcxjvvv@localhost temp3]$ cd build
[vvvcxjvvv@localhost build]$ cmake ../
-- The C compiler identification is GNU 4.8.5
-- The CXX compiler identification is GNU 4.8.5
-- 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
-- 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
[vvvcxjvvv@localhost build]$ cmake ../
-- The C compiler identification is GNU 4.8.5
-- The CXX compiler identification is GNU 4.8.5
-- 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
-- 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
-- Configuring done
-- Generating done
-- Build files have been written to: /home/vvvcxjvvv/Desktop/cxj_data/mycode/temp3/build
[vvvcxjvvv@localhost build]$ make
Scanning dependencies of target MYFRINED_SHARED
[100%] Building CXX object CMakeFiles/MYFRINED_SHARED.dir/src/myfriend.o
Linking CXX shared library libMYFRINED_SHARED.so
[100%] Built target MYFRINED_SHARED
[vvvcxjvvv@localhost build]$
三、使用案例
3.1 单文件直接编译(内部构建)
CMakeLists.txt编写:
#设置CMake最低版本为2.5
cmake_minimum_required(VERSION 2.5)
#设置工程名为HELLO
project(HELLO)
#生成可执行文件hello_cmake(源文件为hello.cpp)
add_executable(hello_cmake hello.cpp)
初始文件目录:
[vvvcxjvvv@localhost hello]$ tree .
.
├── CMakeLists.txt
└── hello.cpp
0 directories, 2 files
执行cmake .
——进行内部构建
[vvvcxjvvv@localhost hello]$ cmake .
-- The C compiler identification is GNU 4.8.5
-- The CXX compiler identification is GNU 4.8.5
-- 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
-- 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
-- Configuring done
-- Generating done
-- Build files have been written to: /home/vvvcxjvvv/Desktop/cxj_data/mycode/hello
[vvvcxjvvv@localhost hello]$ tree .
.
├── CMakeCache.txt
├── CMakeFiles
│ ├── 2.8.12.2
│ │ ├── CMakeCCompiler.cmake
│ │ ├── CMakeCXXCompiler.cmake
│ │ ├── CMakeDetermineCompilerABI_C.bin
│ │ ├── CMakeDetermineCompilerABI_CXX.bin
│ │ ├── CMakeSystem.cmake
│ │ ├── CompilerIdC
│ │ │ ├── a.out
│ │ │ └── CMakeCCompilerId.c
│ │ └── CompilerIdCXX
│ │ ├── a.out
│ │ └── CMakeCXXCompilerId.cpp
│ ├── cmake.check_cache
│ ├── CMakeDirectoryInformation.cmake
│ ├── CMakeOutput.log
│ ├── CMakeTmp
│ ├── hello_cmake.dir
│ │ ├── build.make
│ │ ├── cmake_clean.cmake
│ │ ├── DependInfo.cmake
│ │ ├── depend.make
│ │ ├── flags.make
│ │ ├── link.txt
│ │ └── progress.make
│ ├── Makefile2
│ ├── Makefile.cmake
│ ├── progress.marks
│ └── TargetDirectories.txt
├── cmake_install.cmake
├── CMakeLists.txt
├── hello.cpp
└── Makefile
6 directories, 28 files
执行make
进行编译:
[vvvcxjvvv@localhost hello]$ make
Scanning dependencies of target hello_cmake
[100%] Building CXX object CMakeFiles/hello_cmake.dir/hello.o
Linking CXX executable hello_cmake
[100%] Built target hello_cmake
[vvvcxjvvv@localhost hello]$ tree .
.
├── CMakeCache.txt
├── CMakeFiles
│ ├── 2.8.12.2
│ │ ├── CMakeCCompiler.cmake
│ │ ├── CMakeCXXCompiler.cmake
│ │ ├── CMakeDetermineCompilerABI_C.bin
│ │ ├── CMakeDetermineCompilerABI_CXX.bin
│ │ ├── CMakeSystem.cmake
│ │ ├── CompilerIdC
│ │ │ ├── a.out
│ │ │ └── CMakeCCompilerId.c
│ │ └── CompilerIdCXX
│ │ ├── a.out
│ │ └── CMakeCXXCompilerId.cpp
│ ├── cmake.check_cache
│ ├── CMakeDirectoryInformation.cmake
│ ├── CMakeOutput.log
│ ├── CMakeTmp
│ ├── hello_cmake.dir
│ │ ├── build.make
│ │ ├── cmake_clean.cmake
│ │ ├── CXX.includecache
│ │ ├── DependInfo.cmake
│ │ ├── depend.internal
│ │ ├── depend.make
│ │ ├── flags.make
│ │ ├── hello.o
│ │ ├── link.txt
│ │ └── progress.make
│ ├── Makefile2
│ ├── Makefile.cmake
│ ├── progress.marks
│ └── TargetDirectories.txt
├── cmake_install.cmake
├── CMakeLists.txt
├── hello_cmake
├── hello.cpp
└── Makefile
6 directories, 32 files
[vvvcxjvvv@localhost hello]$ ./hello_cmake
Hello World!
[vvvcxjvvv@localhost hello]$
3.2 多目录工程直接编译(外部构建)
CMakeLists.txt编写:
#设置最低的cmake版本为2.5
cmake_minimum_required(VERSION 2.5)
#设置项目名称为MYFRIEND
Project(MYFRIEND)
#把源文件目录include添加到工程的头文件搜索路径
include_directories(include)
#生成可执行文件main_cmake,源文件为main.cpp、src/myfriend.cpp
#相当于 g++ main.cpp src/myfriend.cpp -Iinclude -o main
add_executable(main_cmake main.cpp src/myfriend.cpp)
初始目录结构:
[vvvcxjvvv@localhost temp1]$ tree .
.
├── CMakeLists.txt
├── include
│ └── myfriend.h
├── main.cpp
└── src
└── myfriend.cpp
2 directories, 4 files
创建build文件夹存放输出文件——外部构建
[vvvcxjvvv@localhost temp1]$ mkdir build
[vvvcxjvvv@localhost temp1]$ cd build
使用cmake ../
找到顶层目录下的CMakeLists.txt
[vvvcxjvvv@localhost build]$ cmake ../
-- The C compiler identification is GNU 4.8.5
-- The CXX compiler identification is GNU 4.8.5
-- 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
-- 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
-- Configuring done
-- Generating done
-- Build files have been written to: /home/vvvcxjvvv/Desktop/cxj_data/mycode/temp1/build
使用make
进行编译,产生的可执行文件在build目录下
[vvvcxjvvv@localhost build]$ make
Scanning dependencies of target main_cmake
[ 50%] Building CXX object CMakeFiles/main_cmake.dir/main.o
[100%] Building CXX object CMakeFiles/main_cmake.dir/src/myfriend.o
Linking CXX executable main_cmake
[100%] Built target main_cmake
[vvvcxjvvv@localhost build]$ cd ../
[vvvcxjvvv@localhost temp1]$ tree .
.
├── build
│ ├── CMakeCache.txt
│ ├── CMakeFiles
│ │ ├── 2.8.12.2
│ │ │ ├── CMakeCCompiler.cmake
│ │ │ ├── CMakeCXXCompiler.cmake
│ │ │ ├── CMakeDetermineCompilerABI_C.bin
│ │ │ ├── CMakeDetermineCompilerABI_CXX.bin
│ │ │ ├── CMakeSystem.cmake
│ │ │ ├── CompilerIdC
│ │ │ │ ├── a.out
│ │ │ │ └── CMakeCCompilerId.c
│ │ │ └── CompilerIdCXX
│ │ │ ├── a.out
│ │ │ └── CMakeCXXCompilerId.cpp
│ │ ├── cmake.check_cache
│ │ ├── CMakeDirectoryInformation.cmake
│ │ ├── CMakeOutput.log
│ │ ├── CMakeTmp
│ │ ├── main_cmake.dir
│ │ │ ├── build.make
│ │ │ ├── cmake_clean.cmake
│ │ │ ├── CXX.includecache
│ │ │ ├── DependInfo.cmake
│ │ │ ├── depend.internal
│ │ │ ├── depend.make
│ │ │ ├── flags.make
│ │ │ ├── link.txt
│ │ │ ├── main.o
│ │ │ ├── progress.make
│ │ │ └── src
│ │ │ └── myfriend.o
│ │ ├── Makefile2
│ │ ├── Makefile.cmake
│ │ ├── progress.marks
│ │ └── TargetDirectories.txt
│ ├── cmake_install.cmake
│ ├── main_cmake
│ └── Makefile
├── CMakeLists.txt
├── include
│ └── myfriend.h
├── main.cpp
└── src
└── myfriend.cpp
10 directories, 35 files
[vvvcxjvvv@localhost temp1]$ cd build
[vvvcxjvvv@localhost build]$ ./main_cmake
Hello Chandler
3.3 多目录工程生成库编译(外部构建)
CMakelists.txt编写:
#设置最低cmake版本
cmake_minimum_required(VERSION 2.5)
#设置项目名称为MYFRIEND
project(MYFRIEND)
#添加编译参数-g -o2 -std=c++11
add_compile_options(-g -o2 -std=c++11)
#定义变量MYFRIEND_SRC为include/myfriend.h src/myfriend.cpp
set(MYFRIEND_SRC include/myfriend.h src/myfriend.cpp)
#将include目录添加进头文件搜索路径(重要!!!否则找不到include/myfriend.h)
include_directories(include)
#通过变量MYFRIEND_SRC生成libMYFRINED_SHARED.so共享库
add_library(MYFRINED_SHARED SHARED ${MYFRIEND_SRC})
#生成可执行文件main_cmake,源文件为main.cpp
add_executable(main_cmake main.cpp)
#将MYFRINED_SHARED动态库文件链接到可执行文件main_cmake
target_link_libraries(main_cmake MYFRINED_SHARED)
创建build文件夹以把输出文件放入build中
进入build文件夹后执行cmake ../
——外部构建
[vvvcxjvvv@localhost temp2]$ mkdir build
[vvvcxjvvv@localhost temp2]$ cd build
[vvvcxjvvv@localhost build]$ cmake ../
-- The C compiler identification is GNU 4.8.5
-- The CXX compiler identification is GNU 4.8.5
-- 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
-- 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
-- Configuring done
-- Generating done
-- Build files have been written to: /home/vvvcxjvvv/Desktop/cxj_data/mycode/temp2/build
执行make
进行编译(libMYFRINED_SHARED.so、main_cmake都在build目录下)
[vvvcxjvvv@localhost build]$ make
Scanning dependencies of target MYFRINED_SHARED
[ 50%] Building CXX object CMakeFiles/MYFRINED_SHARED.dir/src/myfriend.o
Linking CXX shared library libMYFRINED_SHARED.so
[ 50%] Built target MYFRINED_SHARED
Scanning dependencies of target main_cmake
[100%] Building CXX object CMakeFiles/main_cmake.dir/main.o
Linking CXX executable main_cmake
[100%] Built target main_cmake
[vvvcxjvvv@localhost build]$ ./main_cmake
Hello Chandler
总结
本文整理了在Linux环境下使用CMake编译C/C++工程文件的一些知识点,整理了CMake编译规则,常用指令以及常用变量,如何使用CMake生成静态库以及共享库。并列举了一些例子展示了如何进行内部构建和外部构建,以及如何对多源文件进行直接编译以及生成库编译。