github自动编译c语言,想玩儿github开源,怎能对make、cmake一知半解?

如果要接触源码,就不可避免地要触及 编译(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 文件,现在能看懂一些了嘛?

还有问题也可以留言交流哦~

你可能感兴趣的:(github自动编译c语言)