Makefile

make和Makefile介绍

make工具

  利用make工具可以自动完成编译工作。这些工作包括:如果仅修改了某几个源文件,则只重新编译这几个源文件;如果某个头文件被修改了,则重新编译所有包含该头文件的源文件。利用这种自动编译可大大简化开发工作,避免不必要的重新编译。

Makefile

  make工具通过一个称为Makefile的文件来完成并自动维护编译工作。Makefile文件描述了整个工程的编译、链接等规则。

Makefile基本规则

  • 规则
TARGET...:DEPENDENCIES ...
    COMMAND
    ...
  • 目标
      目标(TARGET)程序产生的文件,如可执行文件和目标文件;目标也可以是要执行的动作,如clean,也称为伪目标。

  • 依赖
      依赖(DEPENDENCIES)是用来产生目标的输入文件列表,一个目标通常依赖于多个文件。

  • 命令
      命令(COMMAND)是make执行的动作(命令是shell命令或是可在shell下执行的程序)。注意:每个命令行的起始字符必须是TAB字符!如果DEPENDENCIES中有一个或多个文件更新的话,COMMAND就要执行,这就是Makefile最核心的内容

简单的Makefile编写

main:main.o add.o sub.o
    gcc main.o add.o sub.o -o main

main.o:main.c add.h sub.h
    gcc -c main.c -o main.o

add.o:add.c add.h
    gcc -c add.c -o add.o

sub.o:sub.c sub.h
    gcc -c sub.c sub.o

clean:
    rm -rf main main.o add.o sub.o

Make自动化变量

选项名 作用
$@ 规则的目标文件名 (main)
$< 规则的第一个依赖文件名 (main.o)
$^ 规则的所有依赖文件列表 (main.o add.o sub.o)
.PHONY:clean
OBJECTS=main.o add.o sub.o
main:$(OBJECTS)
    gcc $^ -o $@

main.o:main.c add.h sub.h
    gcc -c $< -o $@

add.o:add.c add.h
    gcc -c $< -o $@

sub.o:sub.c sub.h
    gcc -c $< -o $@

clean:
    rm -rf main $(OBJECTS)

  执行make命令的时候,会查找Makefile或makefile文件;如果需要指定Makefile文件,可以使用

make clean -f Makefile.1

  执行命令的时候如果不想打印输出,可以加@

    @echo "begin clean ..."

Makefile编译多个可执行文件

模式规则
%.c : %.o

后缀规则
.c.o:

01test.c

int main(void)
{
    return 0;
}

02test.c

int main(void)
{
    return 0;
}

Makefile

.PHONY:clean all
BIN=01test 02test
all:$(BIN)

clean:
    rm -f *.o $(BIN)

  这里all也是伪目标,它依赖BIN,Makefile会生产BIN(01test 02test),当前并没有给出生成规则,编译器会自动推导,将通用的.c文件变成通用的可执行文件;如果不想使用推导的,也可以自己定义生产规则

.PHONY:clean all
BIN=01test 02test
all:$(BIN)

01test:01test.o
    gcc -Wall -g $^ -o $@
02test:02test.o
    gcc -Wall -g $^ -o $@

clean:
    rm -f *.o $(BIN)

  这时,01test.o、02test.o文件是自动推导生成的,从.o文件到可执行文件,是按照我们的指定的规则生成的;可以使用模式规则或后缀规则来指定.o文件的生成规则

.PHONY:clean all
BIN=01test 02test
all:$(BIN)

#将当前文件夹下的.c文件生产对应的.o文件
#%.o:%.c
.c.o:
    gcc -Wall -g -c $< -o $@

01test:01test.o
    gcc -Wall -g $^ -o $@
02test:02test.o
    gcc -Wall -g $^ -o $@

clean:
    rm -f *.o $(BIN)

  定义常用的变量

CC=gcc
CFLAGS=-Wall -g

.PHONY:clean all
BIN=01test 02test
all:$(BIN)

#将当前文件夹下的.c文件生产对应的.o文件
#%.o:%.c
.c.o:
    $(CC) $(CFLAGS) -c $< -o $@

01test:01test.o
    $(CC) $(CFLAGS) $^ -o $@

#如果02test还依赖其他文件,只需要在02test.o 后加上其他文件即可
02test:02test.o
    $(CC) $(CFLAGS) $^ -o $@

clean:
    rm -f *.o $(BIN)

  编译器会自动根据自定义的CC和CFLAGS生产推导规则

CC=gcc
CFLAGS=-Wall -g

.PHONY:clean all
BIN=01test 02test
all:$(BIN)

.c.o:
    $(CC) $(CFLAGS) -c $< -o $@

clean:
    rm -f *.o $(BIN)

make常用内嵌函数

函数调用

    $(funcation arguments)

$(wildcard PATTERN)

  当前目录下匹配模式的文件

    src=$(wildcard *.c)

$(patsubst PATTERN,REPLACEMENT,TEXT)

  模式替换函数

    $(patsubst %.c,%.o,$src)  == $(src:.c=.o)

shell函数

  执行shell命令

    $(shell ls -d */)

多级目录Makefile

CC=gcc
CFLAGS=-Wall -g
BIN=main
SUBDIR=$(shell ls -d */)
ROOTSRC=$(wildcard *.c)
ROOTOBJ=$(ROOTSRC:%.c=%.o)
SUBSRC=$(shell find $(SUBNAME) -name '*.c')
SUBONJ=$(SUBSRC:%.c=%.o)

$(BIN):$(ROOTSRC) $(SUBOBJ)
    $(CC) $(CFLAGS) -o $(BIN) $(ROOTBIN) $(SUBOBJ)

%.o:%.c
    $(CC) $(CFLAGS) -c $< -o $@

clean:
    rm -f $(BIN) $(ROOTOBJ) $(SUBOBJ)

生产多个可执行文件

SUBDIRS = test1 test2
.PHONY:default all clean $(SUBDIRS)
#default是伪目标,依赖all
default:all

#生成all和clean
#$(MAKE)=make
#TARGET=$@  $@=all
all clean:
    $(MAKE) $(SUBDIRS) TARGET=$@

#-C表示会进入test1 test2文件夹,调用文件夹下的Makefile
$(SUBDIRS):
    $(MAKE) -C $@ $(TARGET)

test1 Mafile

CC=gcc
BIN=test1
OBJS=test1.o
.PHONY:all clean print

all:print $(BIN)

print:
    @echo "-----make all in $(PWD) ------"

$(BIN):$(OBJS)
    $(CC) $(OBJS) -o $@
%.o:%.c
    $(CC) -c $<
clean:
    @echo "------make clean in $(PWD) ------"
    rm -f $(BIN) $(OBJS)

test2 Makefile

CXX=g++
CPPFLAGS=-Wall -g
BIN=test2
OBJS=test2.o
.PHONY:all clean print

all:print $(BIN)

print:
    @echo "------make all in $(PWD)------"

$(BIN):$(OBJS)
    $(CXX) $(OBJS) -o $@
%.o:%.cpp
    $(CXX) -c $<
clean:
    @echo "------make clean in $(PWD)------"
    rm -f $(BIN) $(OBJS)

其它

#make就会在当前目录找不到的情况下,到所指定的目录中去找寻文件。
VPATH   = ./src1 ./src2 ./src3

#指定库文件路径
#LDFLAGS

#指定要链接的库
#LIBS

#静态库与动态库
STATIC_LIB= -Wl,-Bstatic  -lcrypto -lnet -lpcap
DYNAMIC_LIB= -Wl,-Bdynamic -lpthread  -lmysqlclient -Wl,--as-needed
posted @ 2019-09-02 13:32  sfdevs  阅读(180)  评论(0)    收藏  举报