SamJ's blog

linux下编译与makefile

Word count: 933Reading time: 3 min
2019/08/30 Share

gcc/g++编译器


gcc常用选项:

-c 表示编译源文件, -o表示输出文件, -g用gdb调试时要写上此参数, -D编译时将宏定义传入(DEBUG)

gcc编译过程:

  • 预处理:将源文件的宏展开,载入头文件 gcc -E … .i
  • 编译:将.c文件编译成汇编文件 gcc -S … .s
  • 汇编:将汇编文件编译成机器码 as … .o
  • 链接:将.o文件进行连接,得到可执行二进制文件 gcc

静态库与动态库


静态库:

​ 创建:先gcc -c add.c 编译add.c得到.o文件,再 ar crsv libadd.a add.o 对目标文件.o进行归档,将libadd.a拷贝到/lib或/usr/lib下

​ 编译时:gcc -o main main.c -ladd

编译时链接静态库会将静态库拷贝到可执行二进制文件中。

动态库:

​ 创建:gcc -fPIC -Wall -c add.c; gcc -shared -o libadd.so add.o; gcc -o main main.c -ladd,将库文件拷贝到/lib或者/usr/lib下

​ 使用:./main

动态库在执行时加载,而不是在编译时拷贝到程序中。静态库会使程序臃肿难以升级,动态库使程序易于升级但难以部署。


Makefile工程管理器


主要为了增量编译,防止只对少数文件进行修改时要重新编译所有文件。

Makefile格式:

1
2
target:dependency_files
command(gcc...)(前面是tab)

有一个较为简单的例子:

1
2
3
4
5
6
main:main.o func.o
gcc -o main main.o func.o
main.o:main.c
gcc -c main.c
func.o:func.c
gcc -c func.c

使用make时,make程序先读到第1行的目标文件main,和他的依赖文件main.o和func.o,之后去比较main文件和main.o和func.o的产生时间,若main比前两者旧(生成的时间要早),即执行第二条命令,此过程是一个递归过程,及会对main.o和func.o进行同样操作。

1
2
3
4
5
6
7
8
main:main.o func.o
gcc -o main main.o func.o
main.o:main.c
gcc -c main.c
func.o:func.c
gcc -c func.c
clean:
rm -rf main.o func.o main

输入make clean 命令可以删除生成的文件

1
2
3
4
5
6
7
8
9
10
11
12
#定义变量
OBJS:=main.o func.o
ELF:=main
#使用变量
$(ELF):$(OBJS)
gcc -o $(ELF) $(OBJS)
main.o:main.c
gcc -c main.c -o main.o
func.o:func.c
gcc -c func.c -o func.o
clean:
rm -rf $(ELF) $(OBJS)

常用的自动变量(使用时,自动用特定的值替换该变量):

变量 作用
$@ 当前规则的目标文件
$< 当前规则第一个依赖文件
$^ 当前规则所有依赖文件,以空格分隔
$(@D) 目标文件的目录名
$(@F) 目标文件的文件名

常用预定义变量(内部定义好的变量,值是固定的)

变量 作用
CC C编译器(默认cc)
CXX C++编译器(默认g++)
CFLAGS C编译器选项(CFLAGS:=…)
CXXFLAGS C++编译器选项

通过使用内部变量,可以将上述makefile改写为:

1
2
3
4
5
6
7
8
OBJS:=main.o func.o
CC:=gcc
main:$(OBJS)
$(CC) -o $@ $^
main.o:main.c
$(CC) -o $@ -c $^
func.o:func.c
$(CC) -o $@ -c $^

由于.o文件会自动依赖.c或者.cc文件,所以可以省略最后两个.o的书写。

1
2
3
4
5
6
7
OBJS:=main.o func.o
ELF:=main
CC:=gcc
$(ELF):$(OBJS)
$(CC) -o $@ $^ #相当于gcc -o main main.o func.o
clean:
rm -rf $(OBJS) $(ELF)

makefile 中常用的两个函数:

  1. wildcard会搜索当前目录下的文件,通过通配符进行匹配,并将所有符合要求的文件名展成一列,以空格隔开。如(SOURCES:=$(wildcard *.c))会将所有.c 文件按上述操作展成一列,并存入SOURCES变量中。
  2. patsubst字符串替换函数,用法:OBJS:=$(patsubst %.c,%.o,$(SOURCES)),将SOURCES中的.c换成.o

所以上面提到的makefile还可以这样写:

1
2
3
4
5
6
7
8
SRCS:=$(wildcard *.c)
OBJS:=$(patsubst %.c,%.o,$(SRCS))
ELF:=main
CC:=gcc
$(ELF):$(OBJS)
$(CC) -o $@ $^
clean:
rm -rf $(OBJS) $(ELF)
CATALOG
  1. 1. gcc/g++编译器
  2. 2. 静态库与动态库
  3. 3. Makefile工程管理器