cmake和make
学计算机的,在写代码的时候,IDE安装好,环境按着教程配置好,就直接代码了,编辑器的具体原理只是一知半解,现在来系统学习一下,为了方便以后学习HElib!
make和cmake
写程序大体步骤为:
1.用编辑器编写源代码,如.c文件。
2.用编译器编译代码生成目标文件,如.o。
3.用链接器连接目标代码生成可执行文件,如.exe。
gcc
gcc是GNU Compiler Collection(就是GNU编译器套件),也可以简单认为是编译器,它可以编译很多种编程语言(括C、C++、Objective-C、Fortran、Java等等)。
gcc如何编译参考:cmake 学习
当你的程序只有一个源文件时,直接就可以用gcc命令编译它。
但是当你的程序包含很多个源文件时,用gcc命令逐个去编译时,你就很容易混乱而且工作量大,一个一个编译时就会特别麻烦,于是人们想到,为什么不设计一种类似批处理的程序,来批处理编译源文件呢,于是就有了make工具。它是一个自动化编译工具,你可以使用一条命令实现完全编译。但是你需要编写一个规则文件,make依据它来批处理编译,这个文件就是makefile,所以编写makefile文件也是一个程序员所必备的技能。
对于一个大工程,编写makefile实在是件复杂的事,于是人们又想,为什么不设计一个工具,读入所有源文件之后,自动生成makefile呢,于是就出现了cmake工具,它能够输出各种各样的makefile或者project文件,从而帮助程序员减轻负担。但是随之而来也就是编写cmakelist文件,它是cmake所依据的规则。所以在编程的世界里没有捷径可走,还是要脚踏实地的。
所以流程如下:
cmake使用
由上面可知,我们想要编译,运行程序,只需要写一个cmakelist文件,用cmake去运行该文件,生成project文件和makefile文件,然后再使用make,运行makefile文件,进行编译。
我这里实验环境实在Centos8.0下,首先先安装,非常简单:
yum install -y cmake
然后,接下来主要的就是cmakelist文件的编写,下面学习具体语法:
单个源文件
1、准备一下源文件 main.c .该程序的用途是计算一个数的指数幂
#include <stdio.h>
#include <stdlib.h> /**
* power - Calculate the power of number.
* @param base: Base value.
* @param exponent: Exponent value.
*
* @return base raised to the power exponent.
*/
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;
}
2、编写 CMakeLists.txt 文件,并和main.c放在同一个目录 demo下
# CMake 最低版本号要求
cmake_minimum_required (VERSION 2.8) # 项目信息
project (demo) # 指定生成目标
add_executable(Demo main.c)
CMakeLists.txt 的语法比较简单,由命令、注释和空格组成,其中命令是不区分大小写的。符号 #
后面的内容被认为是注释。命令由命令名称、小括号和参数组成,参数之间使用空格进行间隔。
对于上面的 CMakeLists.txt 文件,依次出现了几个命令:
cmake_minimum_required
:指定运行此配置文件所需的 CMake 的最低版本;project
:参数值是 demo
,该命令表示项目的名称是 demo 。add_executable
: 将名为 main.c 的源文件编译成一个名称为 Demo 的可执行文件。
3、编译
在当前目录执行 cmake .
,得到 Makefile 后再使用 make
命令编译得到 Demo1 可执行文件
4、执行
./Demo
多个源文件
当在一个目录下,有多个源文件时,实验目录为demo1
1、编写源文件
上面的例子只有单个源文件。现在假如把 power
函数单独写进一个名为 MathFunctions.c
的源文件里,使得这个工程变成如下的形式:
main.c
#include "MathFunctions.h" 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;
}
MathFunctions.c
#include "MathFunctions.h" /**
* power - Calculate the power of number.
* @param base: Base value.
* @param exponent: Exponent value.
*
* @return base raised to the power exponent.
*/
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;
}
MathFunctions.h
#include <stdio.h>
#include <stdlib.h> double power(double base, int exponent);
、
2、编写CMakeLists.txt 文件,并和源文件放在同一个目录 demo1下
# CMake 最低版本号要求
cmake_minimum_required (VERSION 2.8) # 项目信息
project (demo1) # 指定生成目标
add_executable(Demo main.c MathFunctions.c)
唯一的改动只是在 add_executable
命令中增加了一个 MathFunctions.c
源文件。这样写当然没什么问题,但是如果源文件很多,把所有源文件的名字都加进去将是一件烦人的工作。更省事的方法是使用 aux_source_directory
命令,该命令会查找指定目录下的所有源文件,然后将结果存进指定变量名。其语法如下:
aux_source_directory(<dir> <variable>)
因此可以修改为:
# CMake 最低版本号要求
cmake_minimum_required (VERSION 2.8) # 项目信息
project (demo1) # 查找当前目录下的所有源文件
# 并将名称保存到 DIR_SRCS 变量
aux_source_directory(. DIR_SRCS) # 指定生成目标
add_executable(Demo ${DIR_SRCS})
这样,CMake 会将当前目录所有源文件的文件名赋值给变量 DIR_SRCS
,再指示变量 DIR_SRCS
中的源文件需要编译成一个名称为 Demo 的可执行文件。
3、编译和执行
多个目录,多个源文件
本实验在demo2目录下:
现在进一步将 MathFunctions.h 和 MathFunctions.c 文件移动到 math 目录下。
对于这种情况,需要分别在项目根目录 demo2 和 math 目录里各编写一个 CMakeLists.txt 文件。为了方便,我们可以先将 math 目录里的文件编译成静态库再由 main 函数调用。
根目录(demo2)中的 CMakeLists.txt :
# CMake 最低版本号要求
cmake_minimum_required (VERSION 2.8) # 项目信息
project (demo2) # 查找当前目录下的所有源文件
# 并将名称保存到 DIR_SRCS 变量
aux_source_directory(. DIR_SRCS) # 添加 math 子目录
add_subdirectory(math) # 指定生成目标
add_executable(Demo main.c) # 添加链接库
target_link_libraries(Demo MathFunctions)
该文件添加了下面的内容: 第3行,使用命令 add_subdirectory
指明本项目包含一个子目录 math,这样 math 目录下的 CMakeLists.txt 文件和源代码也会被处理 。第6行,使用命令 target_link_libraries
指明可执行文件 main 需要连接一个名为 MathFunctions 的链接库 。
子目录(math)中的 CMakeLists.txt:
# 查找当前目录下的所有源文件
# 并将名称保存到 DIR_LIB_SRCS 变量
aux_source_directory(. DIR_LIB_SRCS) # 生成链接库
add_library (MathFunctions ${DIR_LIB_SRCS})
在该文件中使用命令 add_library
将 src 目录中的源文件编译为静态链接库。
编译运行:
自定义编译
本次实验在demo3下:
CMake 允许为项目增加编译选项,从而可以根据用户的环境和需求选择最合适的编译方案。
例如,可以将 MathFunctions 库设为一个可选的库,如果 某选项 为 ON
,就使用该库定义的数学函数来进行运算。否则就调用标准库中的数学函数库。
只需修改CMakeLists.txt 文件:
1、主目录下CMakeLists.txt 文件:
# CMake 最低版本号要求
cmake_minimum_required (VERSION 2.8) # 项目信息
project (demo3) # 加入一个配置头文件,用于处理 CMake 对源码的设置
configure_file (
"${PROJECT_SOURCE_DIR}/config.h.in"
"${PROJECT_BINARY_DIR}/config.h"
) # 是否使用自己的 MathFunctions 库
option (USE_MYMATH
"Use provided math implementation" ON) # 是否加入 MathFunctions 库
if (USE_MYMATH)
include_directories ("${PROJECT_SOURCE_DIR}/math")
add_subdirectory (math)
set (EXTRA_LIBS ${EXTRA_LIBS} MathFunctions)
endif (USE_MYMATH) # 查找当前目录下的所有源文件
# 并将名称保存到 DIR_SRCS 变量
aux_source_directory(. DIR_SRCS) # 指定生成目标
add_executable(Demo ${DIR_SRCS})
target_link_libraries (Demo ${EXTRA_LIBS})
其中:
- 第7行的
configure_file
命令用于加入一个配置头文件 config.h ,这个文件由 CMake 从 config.h.in 生成,通过这样的机制,将可以通过预定义一些参数和变量来控制代码的生成。 - 第13行的
option
命令添加了一个USE_MYMATH
选项,并且默认值为ON
。 - 第17行根据
USE_MYMATH
变量的值来决定是否使用我们自己编写的 MathFunctions 库。
2、子目录下CMakeLists.txt 文件:
# 查找当前目录下的所有源文件
# 并将名称保存到 DIR_LIB_SRCS 变量
aux_source_directory(. DIR_LIB_SRCS) # 生成链接库
add_library (MathFunctions ${DIR_LIB_SRCS})
3、修改main.c
让其根据 USE_MYMATH
的预定义值来决定是否调用标准库还是 MathFunctions 库
#include <stdio.h>
#include <stdlib.h>
#include "config.h" #ifdef USE_MYMATH
#include "math/MathFunctions.h"
#else
#include <math.h>
#endif 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]); #ifdef USE_MYMATH
printf("Now we use our own Math library. \n");
double result = power(base, exponent);
#else
printf("Now we use the standard library. \n");
double result = pow(base, exponent);
#endif
printf("%g ^ %d is %g\n", base, exponent, result);
return 0;
}
4、编写config.h.in
上面的程序值得注意的是第2行,这里引用了一个 config.h 文件,这个文件预定义了 USE_MYMATH
的值。但我们并不直接编写这个文件,为了方便从 CMakeLists.txt 中导入配置,我们编写一个 config.h.in 文件,内容如下:
#cmakedefine USE_MYMATH
这样 CMake 会自动根据 CMakeLists 配置文件中的设置自动生成 config.h 文件。
打包
配置生成各种平台上的安装包,包括二进制安装包和源码安装包。为了完成这个任务,我们需要用到 CPack ,它同样也是由 CMake 提供的一个工具,专门用于打包。
1、首先在顶层的 CMakeLists.txt 文件尾部添加下面几行:
# 构建一个 CPack 安装包
include (InstallRequiredSystemLibraries)
set (CPACK_RESOURCE_FILE_LICENSE
"${CMAKE_CURRENT_SOURCE_DIR}/License.txt")
set (CPACK_PACKAGE_VERSION_MAJOR "${Demo_VERSION_MAJOR}")
set (CPACK_PACKAGE_VERSION_MINOR "${Demo_VERSION_MINOR}")
include (CPack)
上面的代码做了以下几个工作:
- 导入 InstallRequiredSystemLibraries 模块,以便之后导入 CPack 模块;
- 设置一些 CPack 相关变量,包括版权信息和版本信息,其中版本信息用了上一节定义的版本号;
- 导入 CPack 模块。
2、接下来的工作是像往常一样构建工程,并执行 cpack
命令。
- 生成二进制安装包:
cpack -C CPackConfig.cmake
这 3 个二进制包文件所包含的内容是完全相同的。我们可以执行其中一个。此时会出现一个由 CPack 自动生成的交互式安装界面:
- 生成源码安装包
cpack -C CPackSourceConfig.cmake
以上学习内容源自:CMake 入门实战
感谢大佬分享!
参考
cmake和make的更多相关文章
- 使用cmake自动构建工程
公司引擎是用cmake根据目标平台来构建工程的,刚接触的时候深深体会到cmake的方便:如果目标平台是windows,它可以帮你自动构建出vs工程:如果是安卓,自动构建出eclipse工程,如果是IO ...
- CMake
使用CMake编译跨平台静态库 http://www.tuicool.com/articles/3uu2Yj cmake命令 安装.用法简介 https://fukun.org/archives/04 ...
- CMake学习笔记
C++开发者必备技能CMake 先简单介绍一下,CMake是一个跨平台的编译工具,它可以根据不用的平台,不同的编译环境,生成不同的MakeFile,从而控制编译的过程. 使用CMake的步骤: 1. ...
- VS 2013编译64位版本QT 4.8.6及使用cmake为依赖QT生成VS项目时Could NOT find Qt4
对于一些已经解决的问题,本博客不再讨论.只将本人遇到的问题做简单的说明. 一.VS 2013编译64位版本QT 4.8.6 QT项目官网中,对于QT4,其只提供了windows X86的版本,并且支持 ...
- cmake cannot find package
cmake 找不到package,如 find_package (OpenMesh REQUIRED) 出现错误 在项目的文件夹中找到 FindOpenMesh.cmake 文件,将其所在路径添加到 ...
- Cmake的交叉编译
http://www.cmake.org/Wiki/CMake_Cross_Compiling
- CMake命令/函数汇总(翻译自官方手册)
查看官方文档 cmake命令 选项 CMake变量 CMake命令汇总 / add_custom_command add_custom_target/add_definitions/add_depen ...
- 《CMake实践》笔记一:PROJECT/MESSAGE/ADD_EXECUTABLE
<CMake实践>笔记一:PROJECT/MESSAGE/ADD_EXECUTABLE <CMake实践>笔记二:INSTALL/CMAKE_INSTALL_PREFIX &l ...
- 《CMake实践》笔记二:INSTALL/CMAKE_INSTALL_PREFIX
<CMake实践>笔记一:PROJECT/MESSAGE/ADD_EXECUTABLE <CMake实践>笔记二:INSTALL/CMAKE_INSTALL_PREFIX &l ...
- 《CMake实践》笔记三:构建静态库(.a) 与 动态库(.so) 及 如何使用外部共享库和头文件
<CMake实践>笔记一:PROJECT/MESSAGE/ADD_EXECUTABLE <CMake实践>笔记二:INSTALL/CMAKE_INSTALL_PREFIX &l ...
随机推荐
- Centos7安装Nacos单机模式以及集群模式(包含nignx安装以及实现集群)的相关配置
Nacos 致力于帮助您发现.配置和管理微服务.Nacos 提供了一组简单易用的特性集,帮助您快速实现动态服务发现.服务配置.服务元数据及流量管理. Nacos支持三种部署模式 单机模式 - 用于测试 ...
- Elasticsearch 集群优化-尽可能全面详细
Elasticsearch 集群优化-转载参考1 基本配置 基本配置,5台配置为 24C 125G 17T 的主机,每台主机上搭建了一个elasticsearch节点. 采用的elasticsearc ...
- vue-cli2 项目中使用node-sass
公司的项目,换了个电脑要重新安装一下依赖,但是直接npm install的时候报错了,提示node-sass未安装成功. 然后直接npn install node-sass --save 的时候还是下 ...
- malloc函数详解 glibc2.27
malloc 函数分析(glibc.2.27) 本人菜一只,如果分析的有错误,请大佬指正. __libc_malloc函数分析 void * __libc_malloc (size_t bytes) ...
- 2021年HW0day-奇安信 网康下一代防火墙 RCE漏洞细节
漏洞信息: 漏洞名称:奇安信 网康下一代防火墙 RCE漏洞. 漏洞性质:远程命令执行 漏洞利用特点:命令执行之后没有回显 利用方式:防火墙使用linux进行开发的,可以使用echo xxx >1 ...
- 自动化kolla-ansible部署ubuntu20.04+openstack-victoria之ceph部署-07
自动化kolla-ansible部署ubuntu20.04+openstack-victoria之ceph部署-07 欢迎加QQ群:1026880196 进行交流学习 近期我发现网上有人转载或者复制原 ...
- kubernetes-copyFromPod
import com.google.common.io.ByteStreams; import io.kubernetes.client.Copy; import io.kubernetes.clie ...
- Day15_87_通过反射机制获取某个特定的方法
通过反射机制获取某个特定的方法 反射是通过 方法名+形参列表来区分各个方法的(形参列表要用class类型.加.class) 示例代码 import java.lang.reflect.Method; ...
- 鸿蒙手机版JNI实战(JNI开发、SO库生成、SO库使用)
鸿蒙JNI开发现状 现阶段,不仅鸿蒙JNI相关的开发资料较少,而且Phone相关的JNI开发资料几乎没有,这对于新入行的鸿蒙开发者们来说,非常不友好. 也可能会给Android工程(使用了SO库的工程 ...
- D - The Frog's Games (二分)
The annual Games in frogs' kingdom started again. The most famous game is the Ironfrog Triathlon. On ...