学计算机的,在写代码的时候,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 入门实战

 感谢大佬分享!

参考

1、CMake与Make最简单直接的区别

2、关于gcc、make和CMake的区别

3、CMake 入门实战

最新文章

  1. webpack常用配置总结
  2. c语言实现的协程
  3. CentOS禁用触摸板
  4. XHTML的若干注意点
  5. 如何在 Linux 终端中知道你的公有 IP
  6. SecureCRT控制台显示中文字符的设置
  7. xcodebuild和xcrun实现自动打包iOS应用程序
  8. 7第七章联接和APPLY运算符(转载)
  9. 从Ecipse中导出程序至apk
  10. SQLServer 存储过程嵌套事务处理
  11. JAVA之旅(三十二)——JAVA网络请求,IP地址,TCP/UDP通讯协议概述,Socket,UDP传输,多线程UDP聊天应用
  12. vue element-ui 文件上传
  13. tape ——cf
  14. ansible笔记(8):常用模块之系统类模块(二)
  15. jquery ready方法实现原理
  16. 彻底清除Github上某个文件以及历史
  17. 使用 Selenium 实现基于 Web 的自动化测试
  18. leetcode674
  19. 阿里巴巴Java开发规约扫描插件-Alibaba Java Coding Guidelines 在idea上安装使用教程
  20. 在Delphi中使用键盘勾子获取键盘输入(译--5月7日)

热门文章

  1. Python爬虫系列之爬取美团美食板块商家数据(二)
  2. Android Studio 安装及配置
  3. 利用别名切换索引流程Elasticsearch 7.7
  4. 201871010203-陈鹏昱 实验二 个人项目—《D{0-1}KP问题》项目报告
  5. Unity2D项目-平台、解谜、战斗! 0.1 序言:团队、项目提出、初步设计、剧情大纲
  6. JavaWeb 补充(Filter&Listener)
  7. 数据库MySQL四
  8. Linux Nvidia显卡驱动安装
  9. 如何查看spark版本
  10. (十)VMware Harbor 日志管理