GNU Make

大约 2 分钟

开始之前

构建程序的步骤(C为例)

  • 编译预处理-->.i
  • 编译成汇编代码-->.s
  • 汇编成目标代码-->.o
  • 链接成可执行程序-->.out

$gcc <filename.c> --save-temps 用于保存中间过程文件

$gcc -c <filename.c> 只产生目标文件不链接

例子程序的依赖关系

eg:

makefile固有变量(v1)

target: dependencies

actions

sum: main.o sum.o
    gcc -o sum main.o sum.o
    #gcc -o $@ main.o sum.o

main.o: main.c sum.h
    gcc -c main.c
    #gcc -c $*.c

sum.o: sum.c sum.h
    gcc -c sum.c

目的:使动作和具体的目标名无关

  • $@ 目标文件
  • $* 目标文件的前缀(即去掉后缀名)
  • $^ 所有的依赖文件
  • $< 第一个依赖文件

定义变量(v2)

目的:把变动的部分集中在makefile头部

  • <name> = <value> 定义变量
  • $(<name>) 使用变量
CC = gcc
TARGET = sum
OBJS = main.o sum.o

$(TARGET): $(OBJS)
    $(CC) -o $@ $^

$(OBJS): sum.h
    $(CC) -c $*.c

另一个例子

BASE = /home/blufox/base
CC =gcc
CFLAGS = -O –Wall
EFILE = $(BASE)/bin/compare_sorts INCLS = -I$(LOC)/include
LIBS        =   $(LOC)/lib/g_lib.a \
                     $(LOC)/lib/h_lib.a
LOC        =   /usr/local
OBJS = main.o    another_qsort.o    chk_order.o \
             compare.o    quicksort.o
$(EFILE): $(OBJS)
        @echo “linking ...”
        @$(CC) $(CFLAGS) –o $@ $(OBJS) $(LIBS)
$(OBJS): compare_sorts.h
        $(CC) $(CFLAGS) $(INCLS) –c $*.c

伪目标

clean:
    rm *~ $(OBJS)
  • make <target>会寻找当前目录下的makefile,以target为目标进行动作,例如make clean
  • 一个makefile可以有不同的动作

自动分析依赖关系(v3)

  • gcc -MMD -c main.c 会在编译main.c的同时分析其中引用的头文件,产生main.d文件:内容main.o: main.c sum.h
  • 在makefile里可以引用这些.d文件,形成依赖说明
  • -include main.d sum.d
CC = gcc
CFLAG = -MMD
TARGET = sum
OBJS = main.o sum.o
DEPS = $(OBJS:.o=.d)
$(TARGET): $(OBJS)
        $(CC) -o $@ $^
-include $(DEPS)
.c.o:
    $(CC) $(CFLAG) -c -o $@ $<
clean:
    rm $(TARGET) $(OBJS) $(DEPS)

库的发布和使用

目的:避免暴露源码,避免重复编译

创建静态库

$ar rcs libsum.a sum.o
#ar rcs /usr/bin/libsum.a sum.o指定输出目录
  • ar是一个Linux程序,它能将一个或多个.o打包成.a,即一个静态库
  • ar也可以用来删除、替换或提取.o文件
  • 一般一个.a配套一个.o文件

使用静态库

$gcc -o sum main.o -L. -lsum
  • -l:将libsum.a这个静态库和代码集成
  • -L.:库在当前目录
  • 库文件名没有lib也没有.a(实际文件名为libsum.a