赞
踩
参考博客:https://blog.csdn.net/whahu1989/article/details/82078563
在命令行下使用cmake生成Makefile进行进行编译的方法。我们也可以使用图形化界面来生成Makefile文件。cmake-gui是cmake的一个图形化工具。
安装Cmake-gui:sudo apt install cmake-gui
启动cmake-gui:cmake-gui
CMake是开源、跨平台的构建工具,可以让我们通过编写简单的配置文件去生成本地的Makefile,这个配置文件是独立于运行平台和编译器的,这样就不用亲自去编写Makefile了,而且配置文件可以直接拿到其它平台上使用,无需修改,非常方便。
Ubuntu16.04,安装CMake使用命令:
sudo apt install cmake
安装完成之后,在终端下输入cmake -version
查看cmake版本:
liefyuan@ubuntu:~$ cmake -version
cmake version 3.5.1
CMake suite maintained and supported by Kitware (kitware.com/cmake).
编写一个hello.c
:
#include "stdio.h"
int main(void)
{
printf("Hello World!\r\n");
return 0;
}
在同目录下编写CMakeLists.txt
:
cmake_minimum_required (VERSION 2.8)
project (demo)
add_executable(hello hello.c)
hello
,使用的源文件叫hello.c
最后在同目录运行Cmake需输入命令:
cmake .
实际输出信息为:
liefyuan@ubuntu:~/Desktop/cmake_test$ 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/liefyuan/Desktop/cmake_test
同目录下会生成:
liefyuan@ubuntu:~/Desktop/cmake_test$ ls -l
总用量 36
-rw-rw-r-- 1 liefyuan liefyuan 11542 Nov 7 14:50 CMakeCache.txt
drwxrwxr-x 5 liefyuan liefyuan 4096 Nov 7 14:50 CMakeFiles
-rw-rw-r-- 1 liefyuan liefyuan 1377 Nov 7 14:50 cmake_install.cmake
-rw-rw-r-- 1 liefyuan liefyuan 84 Nov 7 14:45 CMakeLists.txt
-rw-rw-r-- 1 liefyuan liefyuan 80 Nov 7 14:44 hello.c
-rw-rw-r-- 1 liefyuan liefyuan 4734 Nov 7 14:50 Makefile
如上显示已经生成了Makefile文件,另外还有cmake运行而自动生成的文件。
接下来就可以使用make
命令进行编译了。
liefyuan@ubuntu:~/Desktop/cmake_test$ make
Scanning dependencies of target hello
[ 50%] Building C object CMakeFiles/hello.dir/hello.c.o
[100%] Linking C executable hello
[100%] Built target hello
再次看看生成文件:
liefyuan@ubuntu:~/Desktop/cmake_test$ ls -l
总用量 48
-rw-rw-r-- 1 liefyuan liefyuan 11542 Nov 7 14:50 CMakeCache.txt
drwxrwxr-x 5 liefyuan liefyuan 4096 Nov 7 14:53 CMakeFiles
-rw-rw-r-- 1 liefyuan liefyuan 1377 Nov 7 14:50 cmake_install.cmake
-rw-rw-r-- 1 liefyuan liefyuan 84 Nov 7 14:45 CMakeLists.txt
-rwxrwxr-x 1 liefyuan liefyuan 8600 Nov 7 14:53 hello
-rw-rw-r-- 1 liefyuan liefyuan 80 Nov 7 14:44 hello.c
-rw-rw-r-- 1 liefyuan liefyuan 4734 Nov 7 14:50 Makefile
可以看到已经生成了一个可执行的hello文件,输入./hello
运行该可执行文件:
liefyuan@ubuntu:~/Desktop/cmake_test$ ./hello
Hello World!
运行成功!如果需要重新编译,可以使用make clean
命令进行清除(删除旧的可执行文件)。
文件目录:
liefyuan@ubuntu:~/Desktop/cmake_multi_test$ ls -l
rw-rw-r-- 1 liefyuan liefyuan 93 Nov 7 16:41 CMakeLists.txt
-rw-rw-r-- 1 liefyuan liefyuan 107 Nov 7 16:34 function.c
-rw-rw-r-- 1 liefyuan liefyuan 86 Nov 7 16:38 function.h
-rw-rw-r-- 1 liefyuan liefyuan 85 Nov 7 16:30 main.c
function.h
#ifndef __FUNCTION_H__
#define __FUNCTION_H__
void func(unsigned int var);
#endif
function.c
#include <stdio.h>
#include "function.h"
void func(unsigned int var)
{
printf("para var:%d\r\n", var);
}
main.c
#include <stdio.h>
#include "function.h"
int main(void)
{
func(200);
return 0;
}
CMakeLists.txt
cmake_minimum_required (VERSION 2.8)
project (demo)
add_executable(main main.c function.c)
执行cmake .
生成Makefile并运行make
cmake .
liefyuan@ubuntu:~/Desktop/cmake_multi_test$ 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/liefyuan/Desktop/cmake_multi_test liefyuan@ubuntu:~/Desktop/cmake_multi_test$ make Scanning dependencies of target main [ 33%] Building C object CMakeFiles/main.dir/main.c.o [ 66%] Building C object CMakeFiles/main.dir/function.c.o [100%] Linking C executable main [100%] Built target main
liefyuan@ubuntu:~/Desktop/cmake_multi_test$ ./main
para var:200
运行成功!
总结
可以类推,如果在同一目录下有多个源文件,那么只要在add_executable里把所有源文件都添加进去就可以了。
但是如果有一百个源文件,再这样做就有点坑了,无法体现cmake的优越性,cmake提供了一个命令可以把指定目录下所有的源文件存储在一个变量中,这个命令就是 aux_source_directory(dir var)
。
第一个参数dir是指定目录,第二个参数var是用于存放源文件列表的变量。
再次增加文件function2.c
#include <stdio.h>
#include "function2.h"
void func2(unsigned int var)
{
printf("para var2:%d\r\n", var);
}
增加文件function2.h
#ifndef __FUNCTION2_H__
#define __FUNCTION2_H__
void func2(unsigned int var);
#endif
修改main.c
#include <stdio.h>
#include "function.h"
#include "function2.h"
int main(void)
{
func(200);
func2(100);
return 0;
}
修改CMakeLists.txt
cmake_minimum_required (VERSION 2.8)
project (demo)
aux_source_directory(. SRC_LIST)
add_executable(main ${SRC_LIST})
然后运行cmake .
和make
liefyuan@ubuntu:~/Desktop/cmake_multi_test$ cmake .
-- Configuring done
-- Generating done
-- Build files have been written to: /home/liefyuan/Desktop/cmake_multi_test
liefyuan@ubuntu:~/Desktop/cmake_multi_test$ make
Scanning dependencies of target main
[ 25%] Building C object CMakeFiles/main.dir/function.c.o
[ 50%] Building C object CMakeFiles/main.dir/function2.c.o
[ 75%] Building C object CMakeFiles/main.dir/main.c.o
[100%] Linking C executable main
[100%] Built target main
运行可执行文件./main
liefyuan@ubuntu:~/Desktop/cmake_multi_test$ ./main
para var:200
para var2:100
运行成功!
总结
aux_source_directory() 也存在弊端,它会把指定目录下的所有源文件都加进来,可能会加入一些我们不需要的文件,此时我们可以使用set命令去新建变量来存放需要的源文件,如下:
cmake_minimum_required (VERISON 2.8)
project (demo)
set(SRC_LIST
./main.c
./function.c
./function2.c)
add_executable(main ${SRC_LIST})
一般来说,当程序文件比较多时,我们会进行分类管理,把代码根据功能放在不同的目录下,这样方便查找。那么这种情况下如何编写CMakeLists.txt呢?
我们把之前的源文件整理一下(新建2个目录function和function2),整理好后整体文件结构如下
liefyuan@ubuntu:~/Desktop/cmake_multi_dir_test$ tree
.
├── CMakeLists.txt
├── function
│ ├── function.c
│ └── function.h
├── function2
│ ├── function2.c
│ └── function2.h
└── main.c
修改CmakeLists.txt文件
cmake_minimum_required (VERSION 2.8)
project (demo)
include_directories (function function2)
aux_source_directory(function SRC_LIST)
aux_source_directory(function2 SRC_LIST2)
add_executable(main main.c ${SRC_LIST} ${SRC_LIST2})
如上:
然后cmake .
再make
再运行./main
liefyuan@ubuntu:~/Desktop/cmake_multi_dir_test$ 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/liefyuan/Desktop/cmake_multi_dir_test liefyuan@ubuntu:~/Desktop/cmake_multi_dir_test$ make Scanning dependencies of target main [ 25%] Building C object CMakeFiles/main.dir/main.c.o [ 50%] Building C object CMakeFiles/main.dir/function/function.c.o [ 75%] Building C object CMakeFiles/main.dir/function2/function2.c.o [100%] Linking C executable main [100%] Built target main liefyuan@ubuntu:~/Desktop/cmake_multi_dir_test$ ./main para var:200 para var2:100
正常运行!
这里出现了一个新的命令:include_directories。该命令是用来向工程添加多个指定头文件的搜索路径,路径之间用空格分隔。
因为main.c里include了function.h和function2.h,如果没有这个命令来指定头文件所在位置,就会无法编译。当然,也可以在main.c里使用include来指定路径,如下:
#include "function/function.h"
#include "function2/function2.h"
这种写法不好看!
首先构建一个目录树下:
liefyuan@ubuntu:~/Desktop/cmake_dir$ tree
.
├── bin
├── build
├── include
│ ├── function2.h
│ └── function.h
└── src
├── function2.c
├── function.c
└── main.c
根目录下新建一个新的CMakeLists.txt
文件,内容如下:
cmake_minimum_required (VERSION 2.8)
project (demo)
add_subdirectory (src)
src目录下也需要新建一个新的CMakeLists.txt
文件,内容如下:
aux_source_directory (. SRC_LIST)
include_directories (../include)
add_executable (main ${SRC_LIST})
set (EXECUTABLE_OUTPUT_PATH ${PROJECT_SOURCE_DIR}/bin)
这里使用了一个新的命令set,是用于定义变量的,EXECUTABLE_OUT_PATH
和PROJECT_SOURCE_DIR
是CMake自带的预定义变量,其意义如下,
所以,这里set的意思是把存放elf文件的位置设置为工程根目录下的bin目录。(cmake有很多预定义变量,详细的可以网上搜索一下)
添加好以上这2个CMakeLists.txt后,整体文件结构如下,
liefyuan@ubuntu:~/Desktop/cmake_dir$ tree
.
├── bin
├── build
├── CMakeLists.txt
├── include
│ ├── function2.h
│ └── function.h
└── src
├── CMakeLists.txt
├── function2.c
├── function.c
└── main.c
构建,编译,运行
cmake ..
make
进行编译,在根目录的bin目录下就会生成一个可执行文件make
./main
liefyuan@ubuntu:~/Desktop/cmake_dir/build$ 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/liefyuan/Desktop/cmake_dir/build liefyuan@ubuntu:~/Desktop/cmake_dir/build$ make Scanning dependencies of target main [ 25%] Building C object src/CMakeFiles/main.dir/function.c.o [ 50%] Building C object src/CMakeFiles/main.dir/function2.c.o [ 75%] Building C object src/CMakeFiles/main.dir/main.c.o [100%] Linking C executable ../../bin/main [100%] Built target main liefyuan@ubuntu:~/Desktop/cmake_dir/build$ cd .. liefyuan@ubuntu:~/Desktop/cmake_dir$ cd bin liefyuan@ubuntu:~/Desktop/cmake_dir/bin$ ls main liefyuan@ubuntu:~/Desktop/cmake_dir/bin$ ./main para var:200 para var2:100
正常运行!
为什么在build目录下运行cmake?从前面几个例子中可以看到,如果不这样做,cmake运行时生成的附带文件就会跟源码文件混在一起,这样会对程序的目录结构造成污染,而在build目录下运行cmake,生成的附带文件就只会待在build目录下,如果我们不想要这些文件了就可以直接清空build目录,非常方便。
前面的工程使用了2个CMakeLists.txt,最外层的CMakeLists.txt用于掌控全局,使用add_subdirectory来控制其它目录下的CMakeLists.txt的运行。
上面的例子也可以只使用一个CMakeLists.txt,把最外层的CMakeLists.txt内容改成如下:
cmake_minimum_required (VERSION 2.8)
project (demo)
set (EXECUTABLE_OUTPUT_PATH ${PROJECT_SOURCE_DIR}/bin)
aux_source_directory (src SRC_LIST)
include_directories (include)
add_executable (main ${SRC_LIST})
再把src目录下的CMakeLists.txt删除掉。
目录如下:
liefyuan@ubuntu:~/Desktop/cmake_dir2$ tree
.
├── bin
├── build
├── CMakeLists.txt
├── include
│ ├── function2.h
│ └── function.h
└── src
├── function2.c
├── function.c
└── main.c
liefyuan@ubuntu:~/Desktop/cmake_dir2/build$ 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/liefyuan/Desktop/cmake_dir2/build liefyuan@ubuntu:~/Desktop/cmake_dir2/build$ ls CMakeCache.txt CMakeFiles cmake_install.cmake Makefile liefyuan@ubuntu:~/Desktop/cmake_dir2/build$ make Scanning dependencies of target main [ 25%] Building C object CMakeFiles/main.dir/src/function.c.o [ 50%] Building C object CMakeFiles/main.dir/src/function2.c.o [ 75%] Building C object CMakeFiles/main.dir/src/main.c.o [100%] Linking C executable ../bin/main [100%] Built target main liefyuan@ubuntu:~/Desktop/cmake_dir2/build$ cd .. liefyuan@ubuntu:~/Desktop/cmake_dir2$ cd bin liefyuan@ubuntu:~/Desktop/cmake_dir2/bin$ ls main liefyuan@ubuntu:~/Desktop/cmake_dir2/bin$ ./main para var:200 para var2:100
正常运行!
CMake编译动态库和静态库也是可以的。
构建一个文件架构:
liefyuan@ubuntu:~/Desktop/cmake_lib$ tree
.
├── build
├── CMakeLists.txt
├── function
│ ├── function.c
│ └── function.h
└── lib
在build目录下运行cmake,并把生成的库文件存放到lib目录下。
新建的CMakeLists.txt内容为:
cmake_minimum_required (VERSION 2.8)
project (demo)
set (SRC_LIST ${PROJECT_SOURCE_DIR}/function/function.c)
add_library (function_shared SHARED ${SRC_LIST})
add_library (function_static STATIC ${SRC_LIST})
set_target_properties (function_shared PROPERTIES OUTPUT_NAME "function")
set_target_properties (function_static PROPERTIES OUTPUT_NAME "function")
set (LIBRARY_OUTPUT_PATH ${PROJECT_SOURCE_DIR}/lib)
这里出现了新的命令和预定义变量:
进入build目录运行命令cmake ..
,生成Makefile文件后再运行make
。
liefyuan@ubuntu:~/Desktop/cmake_lib/build$ 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/liefyuan/Desktop/cmake_lib/build liefyuan@ubuntu:~/Desktop/cmake_lib/build$ make Scanning dependencies of target function_static [ 25%] Building C object CMakeFiles/function_static.dir/function/function.c.o [ 50%] Linking C static library ../lib/libfunction.a [ 50%] Built target function_static Scanning dependencies of target function_shared [ 75%] Building C object CMakeFiles/function_shared.dir/function/function.c.o [100%] Linking C shared library ../lib/libfunction.so [100%] Built target function_shared
编译成功后,进入lib目录下查看,发现已经成功生成了动态库和静态库。
liefyuan@ubuntu:~/Desktop/cmake_lib/build$ cd ..
liefyuan@ubuntu:~/Desktop/cmake_lib$ cd lib
liefyuan@ubuntu:~/Desktop/cmake_lib/lib$ ls
libfunction.a libfunction.so
前面使用set_target_properties重新定义了库的输出名称,如果不使用set_target_properties也可以,那么库的名称就是add_library里定义的名称,只是连续2次使用add_library指定库名称时(第一个参数),这个名称不能相同,而set_target_properties可以把名称设置为相同,只是最终生成的库文件后缀不同(一个是.so,一个是.a),这样相对来说会好看点。
前面已经生成了库,现在就进行库链接。
liefyuan@ubuntu:~/Desktop/cmake_lib_link$ tree
.
├── bin
├── build
├── CMakeLists.txt
├── function
│ ├── inc
│ │ └── function.h
│ └── lib
│ ├── libfunction.a
│ └── libfunction.so
└── src
└── main.c
main.c
#include <stdio.h>
#include "function.h"
int main(void)
{
func(300);
return 0;
}
CMakeLists.txt
cmake_minimum_required (VERSION 2.8)
project (demo)
set (EXECUTABLE_OUTPUT_PATH ${PROJECT_SOURCE_DIR}/bin)
set (SRC_LIST ${PROJECT_SOURCE_DIR}/src/main.c)
include_directories (${PROJECT_SOURCE_DIR}/function/inc)
find_library(FUNCTION_LIB function HINTS ${PROJECT_SOURCE_DIR}/function/lib)
add_executable (main ${SRC_LIST})
target_link_libraries (main ${FUNCTION_LIB})
新命令解释:
使用find_library的好处是在执行cmake ..
时就会去查找库是否存在,这样可以提前发现错误,不用等到链接时。
cd到build目录下,然后运行cmake .. && make
,最后进入到bin目录下查看,发现main已经生成,运行就好。
liefyuan@ubuntu:~/Desktop/cmake_lib_link/build$ cmake ..&& make -- 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/liefyuan/Desktop/cmake_lib_link/build Scanning dependencies of target main [ 50%] Building C object CMakeFiles/main.dir/src/main.c.o [100%] Linking C executable ../bin/main [100%] Built target main
运行:
liefyuan@ubuntu:~/Desktop/cmake_lib_link/build$ cd ..
liefyuan@ubuntu:~/Desktop/cmake_lib_link$ cd bin
liefyuan@ubuntu:~/Desktop/cmake_lib_link/bin$ ./main
para var:300
运行成功!
在lib目录下有function的静态库和动态库,find_library(FUNCTION_LIB function …默认是查找动态库,如果想直接指定使用动态库还是静态库,可以写成find_library(FUNCTION_LIB libfunction.so …或者find_library(FUNCTION_LIB libfunction.a …
有时编译程序时需要添加一些编译选项,如-Wall, -std=c++11
等,就可以使用add_compile_option
来进行操作。
#include <iostream>
int main(void)
{
auto data = 100;
std:cout << "data:" << data << "\n";
return 0;
}
CMakeLists.txt
cmake_minimum_required (VERSION 2.8)
project (demo)
set (EXECUTABLE_OUTPUT_PATH ${PROJECT_SOURCE_DIR}/bin)
add_compile_options(-std=c++11 -Wall)
add_executable(main main.cpp)
目录树如下:
liefyuan@ubuntu:~/Desktop/cmake_cpp$ tree
.
├── bin
├── build
├── CMakeLists.txt
└── main.cpp
然后cd到build目录下,执行cmake … && make命令,就可以在bin目录下得到main的elf文件
有时在编译代码时只编译一些指定的代码,可以使用cmake的option命令,主要遇到的情况分为2种:
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。