Makefile学习

C语言的编译过程

预处理(Preprocessing)

-E是让编译器在预处理之后就退出,不进行后续编译过程;-o是指定输出文件名。

gcc -E hello.c -o hello.i

编译(Compilation)

Makefile学习_第1张图片

这里的编译不是指程序从源文件到二进制程序的全部过程,而是指将经过预处理文件(test.i)之后的程序转换成特定汇编(test.s)代码的过程。

gcc -S hello.i -o hello.s

汇编

汇编过程将上一步的汇编代码转换成机器码,这一步产生的文件叫做目标文件,是二进制格式。

gcc -c hello.s -o hello.o

链接

链接过程使用链接器将该目标文件与其他目标文件、库文件、启动文件等链接起来生成可执行文件。附加的目标文件包括静态连接库和动态连接库。

gcc hello.o -o hello

总结

生成可执行程序过程为成四个步骤:

1、由.c文件到.i文件,这个过程叫预处理。
2、由.i文件到.s文件,这个过程叫编译。
3、由.s文件到.o文件,这个过程叫汇编。
4、由.o文件到可执行文件,这个过程叫链接。

静态库

在编译的过程中,会被直接载入到可执行文件中,将多个文件组成一个库,实现复用,以lib开头,以.a结尾,使用ar命令

动态库

在程序编译时并不会被连接到目标代码中,而是在程序运行是才被载入。这就带来了一个明显的好处:不同的应用程序如果调用相同的库,那么在内存里只需要有一份该共享库的实例,减小了各个模块之间的耦合程度,也减小了可执行文件的体积。

MakeFile

基本格式

target ... : prerequisites ...
    command
    ...
    ...

make debug执行下面的命令

debug:
	echo hello
.PHONY: clean # 伪目标
clean:
	rm *.o

变量

cpp := src/main.cpp
obj := obj/main.o

${obj}: ${cpp}
	g++ -c ${cpp} -o ${obj}
	# $@ target的名称
	# $< 第一个依赖文件
	# $^ 所有的依赖文件

compile: ${obj}

clean:
	rm -rf obj
	# Windows下使用del obj

.PHONY: clean debug

运算符号

:=:赋值后不可改变

= :可以改变

?=:在变量尚未设置时才将其设置为值

+=:添加

\:续行符

函数

shell:把执行操作系统命令后的输出作为函数返回,本质上就是执行shell命令。

cpp_srcs := ${shell find src -name *.cpp}

subst、patsubst

格式:源字符串都是的内容

$(subst ,,)
$(patsubst ,,) # pattern中的%和replacement中的%相同

foreach

$(foreach ,,)

# eg
names := a b c d
files := $(foreach n,$(names),$(n).o)
# $(file) := a.o b.o c.o d.o 

dir

$(dir ) #取目录函数
$(dir src/foo.c hacks) # 返回值是 src/ ./

notdir、filter

$(notdir ) # 取文件函数
$(notdir src/foo.c hacks) # 返回值是 foo.c hacks
$(filter ,) # 过滤出text中符合pattern的字符串
sources := foo.c bar.c baz.s ugh.h
foo: $(sources)
	cc $(filter %.c %.s,$(sources)) -o foo # $(filter %.c %.s,$(sources)) 返回的值是 foo.c bar.c baz.s

编译带有头文件的项目

Makefile示例(1):

cpp_srcs := $(shell find src -name *.cpp)
cpp_objs := $(patsubst src/%.cpp,objs/%.o,$(cpp_srcs))

# 你的头文件所在文件夹路径(建议绝对路径)
include_paths := 
I_flag        := $(include_paths:%=-I%)


objs/%.o : src/%.cpp
	@mkdir -p $(dir $@)
	@g++ -c $^ -o $@ $(I_flag)

workspace/exec : $(cpp_objs)
	@mkdir -p $(dir $@)
	@g++ $^ -o $@ 

run : workspace/exec
	@./$<

debug :
	@echo $(I_flag)

clean :
	@rm -rf objs

.PHONY : debug run

Makefile示例(2):

# Compiler
CXX := g++

# cpp sources
cpp_srcs := ${shell find src -name *.cpp}
# $(warning cpp_srcs is ${cpp_srcs})

# cpp objects
cpp_objs := ${patsubst src/%.cpp,objs/%.o,${cpp_srcs}}
# $(warning cpp_objs is ${cpp_objs})

# cpp include path
include_path := /home/mirac/Desktop/Retest/include
I_flags := ${include_path:%=-I%}
# ${warning I_flags is ${I_flags}}

# compile option
Compile_option := -g -O3 -w
Compile_option += ${I_flags}
# $(warning Compile_option is ${Compile_option})

objs/%.o : src/%.cpp
	@mkdir -p ${dir $@}
	@${CXX} -o $@ -c $^  ${Compile_option}

workspace/testJson: ${cpp_objs}
	@${CXX} -o $@  $^ 

run : workspace/testJson
	@./$<

debug:
	echo ${cpp_srcs}
	echo ${cpp_objs}
	echo ${I_flags}
# @echo ${CC} -o $@ -c $^  ${Compile_option}

clean : 
	@rm -r objs
	@rm -r workspace/*

.PHONY: clean debug

你可能感兴趣的:(学习)