想玩儿github开源,怎能对make、cmake一知半解?

您所在的位置:网站首页 Cmake编译没有makefile怎么办 想玩儿github开源,怎能对make、cmake一知半解?

想玩儿github开源,怎能对make、cmake一知半解?

2024-02-05 21:07| 来源: 网络整理| 查看: 265

如果要接触源码,就不可避免地要触及 编译(python这种不需要编译的 解释性语言 源码除外!!!)为了完成编译动作,我们有众多的编译工具,很多情况下,编译工具的调用被集成到了 IDE 当中。然而,如果上手一些开源项目,我们会发现,更常见到的是「奇奇怪怪」的 MakeFile 和 CMakeLists.txt。我们参照 ReadMe 的教程,装这个装那个,然后运行同样奇奇怪怪的 make、cmake 命令……折腾半天或许成功完成了编译……但脑子是否还是一片混沌?别说定制修改MakeFile和CMakeLists.txt,甚至连自己做了些什么都无法记忆起来……Why?

因为我们没理清Ta们为什么存在!

认识 make & cmake,我们先看看可执行文件是如何生成的

一、从 main.c 到 可执行文件 输出 Hello World

我们编辑一份最简单的 main.c 文件(认真上过1节C语言课的同学该都可以看懂),并期望经过编译将其变为可执行文件,然后运行输出Hello World。

#include int main(int argc, char * argv[]) { printf("\nHello World!\n"); return 0; } Step1:预处理 Preprocess

预处理即将源文件中的宏、头文件进行 ”展开“。

参考命令: gcc -E main.c -o main_preprocess.c 预处理展开 Step2:汇编 Assembly

汇编可以将预处理后的代码转换为汇编语言,看看下面的汇编语言是不是特别「优美」捏!

参考命令: gcc -S main_preprocess.c 汇编 Step3:生成机器语言

机器语言(二进制命令语言)即计算机可以识别的语言,汇编代码可以进一步转化为机器语言

参考命令: gcc -c main.s 汇编 Step4:链接

将多个二进制文件(.o文件,虽然当前只有一个main.o)链接成一个文件,根据需求,可能是一个lib,也可能是一个可执行文件。

参考命令: gcc main.o -o main 链接 Step5:执行

向世界问好吧!:)

你好世界 二、用gcc、make、cmake编译同一套代码 2.1:使用gcc编译

GCC 是一个linux下的常用的编译工具。我们拟写了如下的源文件,并尝试用 GCC 对齐进行编译:

- ./main.c - #include "submodule.h" int main(int argc, char * argv[]) { subTest(10); return 0; } - ./include/submodule.h - #include int subTest(int a); - ./submodule/submodule.c - #include "submodule.h" int subTest(int a) { printf("\n Function Called... %d \n\n", __func__, __LINE__, a); return 1; }

gcc的命令很简单,只要如下 4条命令 就能完成可执行文件 main 的编译和调用:

# 1 生成subModel的二进制文件(.o) gcc ./submodule/submodule.c -c -I ./include -o ./submodule.o # 2 生成main的二进制文件(.o) gcc ./main.c -c -I ./include -o ./main.o # 3 链接二进制文件 gcc ./submodule.o ./mian.o -o ./main # 4 执行可执行文件 ./main 2.2 构造MakeFile文件,使用make编译

我们为什么要用MakeFile?如果是为了封装命令,方便调用,我们完全可以将相关的编译命令放置到一个shell脚本中,MakeFile 有什么其他优势呢?

1)它封装一套简单的指定编译目标的语法,这比写shell的参数解析简单得多 2)藉由这套语法,make封装了编译依赖、增量编译等逻辑。即大型工程进行小范围局部改动时候,重新的编译的速度会非常快。(未涉及改动的内容不会重编)

那么,同样的 main 和 submodule,使用 MakeFile 我们可以编辑两个 MakeFile 文件

- ./MakeFile - INCLUDE_PATH := ./include SRCS += $(wildcard ./*.c) OBJS += $(SRCS:.c=.o) SUB_DIR = ./submodule SUB_SRCS = $(wildcard ${SUB_DIR}/*.c) SUB_OBJS += $(SUB_SRCS:.c=.o) TARGET := main all: clean build linkobjs linkobjs: gcc ${OBJS} ${SUB_OBJS} -o ${TARGET} build: cd ${SUB_DIR} && make build gcc -c ${SRCS} -I${INCLUDE_PATH} clean: cd ${SUB_DIR} && make clean rm -rf ${OBJS} rm -rf ${TARGET} - ./submodule/MakeFile - INCLUDE_PATH := ../include SRCS += $(wildcard ./*.c) OBJS += $(wildcard ./*.o) all: clean build build: gcc -c ${SRCS} -I${INCLUDE_PATH} clean: rm -rf ${OBJS}

然后,在 main.c 所在的目录执行 make all 就好啦

编写好MakeFile,执行make all

关于MakeFile,有几个 tips 可能对大家上手有帮助: 1)其完成支持语法和Shell脚本是有些相似的 2)各个编译目标下可以执行 linux 命令 3)编译目标要执行的命令,前面要加4个空格(这个和 python 的函数语法有些相似) 4)示例中的「all : clean build」表示「make all」等同于顺序执行「make clean」「make build」

2.3 构造CMakeLists.txt,使用 cmake 命令生成MakeFile,再make

cmake 定义了另一套语法来组织 CMakeLists.txt 文件,然后通过 cmake 命令可以结合 CMakeLists.txt 文件的”配置“生成 MakeFile,然后再……make……

最终同样是使用MakeFile,干嘛加一步再让大家学习cmake的语法呢?

原来,不同平台(linux、Windows、Macos……)的编译环境是有差异的,为了应对这种差异,各平台编译所需的 MakeFile 文件也各不相同。而 cmake 抽象了一套上层的编译配置语法,并负责了将Ta针对平台进行 MakeFile 文件翻译的任务。

还是同样的 main 和 submodule,使用 cmake 我们将构造两个 CMakeLists.txt 文件:

- ./CMakeLists.txt - # cmake最低版本约定 cmake_minimum_required(VERSION 2.8) # 工程名称 project(main) # 宏开关 option(DT "Demo Test Switch" OFF) if(DT) add_definitions("-DDEMO_TEST=1") endif() # include目录 include_directories(./include) # 子模块文件目录 add_subdirectory(./submodule) # 查找当前文件夹源文件 aux_source_directory(. SRCS) # 生成可执行文件 add_executable(main ${SRCS}) # 可执行文件链接静态库 target_link_libraries(main submodule) - ./submodule/CMakeLists.txt - # cmake最低版本约定 cmake_minimum_required(VERSION 2.8) # include目录 include_directories(../include) # 查找当前文件夹源文件 aux_source_directory(. SRCS) # 生成静态链接库 add_library(submodule ${SRCS})

然后,我们创建一个 build 文件夹,并进行 cmake

mkdir build cd build cmake ../

build 目录下回生成一系列文件,我们可以理解Ta们都是为了支持 Makefile 存在的就好。👇

cmake生成的MakeFile

那么,在 build 下执行 make 吧!

make

成功编译出我们的目标。👇

目标出现了

有没有发现 cmake 的另一点「优雅」:Ta能将所有的编译信息有效地管理在一个文件夹下!当我们想清理编译数据时,只需要删除build文件夹就好了。

三、草草结束

相关的示例代码我放在了 这里 然后看看之前在 github 上遇到的 Makefile、CMakeLists.txt 文件,现在能看懂一些了嘛? 还有问题也可以留言交流哦~



【本文地址】


今日新闻


推荐新闻


CopyRight 2018-2019 办公设备维修网 版权所有 豫ICP备15022753号-3