【问题标题】:Automatic dependency processing in MakefileMakefile 中的自动依赖处理
【发布时间】:2015-05-09 03:46:39
【问题描述】:

我有一个简单的生成文件。

IDIR =./include
CC=gcc
CFLAGS=-I$(IDIR)
SRCDIR = ./src
ODIR=obj
LDIR =./lib

LIBS=-lm

SRC = hellomake hellofunc
OBJ = ${SRC:%=$(ODIR)/%.o} 

_DEPS = hellomake.h
DEPS = ${_DEPS:%=$(IDIR)/%} 

$(ODIR)/%.o: $(SRCDIR)/%.c $(DEPS)
    $(CC) -c -o $@ $< $(CFLAGS)

hellomake: $(OBJ)
    gcc -o $@ $^ $(CFLAGS) $(LIBS)

.PHONY: clean

clean:
    rm -f $(ODIR)/*.o *~ hellomake

我不喜欢这个 Makefile 是依赖生成。

.c.o

是否可以教make文件.c在src目录,.o在obj目录来制作这个简单的文件?

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

头文件依赖

是否可以教make文件,当c文件包含的头文件发生变化时,所有c文件都会自动重新编译?

【问题讨论】:

  • 不,如果目标文件和源文件位于不同的目录中,则不能使用旧式后缀规则。您可以使用 make.mad-scientist.net/papers/… 之类的方式配置自动依赖检测

标签: makefile gnu-make


【解决方案1】:

预赛

生成依赖项

gcc 的 -MM -MG 可用于创建依赖项:gcc -MM -MG src/hellofunc.c -I./include 将创建 hellofunc.o: src/hellofunc.c include/hellomake.h。但是,我们需要将 .d 文件本身包含到 .d 文件中,因此我们使用sed 来实现该目标。

gcc -MM -MG src/hellofunc.c -I./include | sed -e 's@^\(.*\)\.o:@\1.d \1.o:@'

结果如下:

hellofunc.d hellofunc.o: src/hellofunc.c include/hellomake.h

当我们想要更改内容以包含不同的目录位置时,我们可以修改 sed 脚本。

gcc -MM -MG src/hellofunc.c -I./include | sed -e 's@^\(.*\)\.o:@obj/\1.d obj/\1.o:@'

结果如下:

obj/hellofunc.d obj/hellofunc.o: src/hellofunc.c include/hellomake.h

包括

-include $(DEPS) 将包含DEPS 目录中的文件,包含前面的- 教导make 在目录不退出时忽略。

模式匹配与替换

我们可以如下替换任何模式 (%) 或以 c (%.c) 结尾的模式:

OBJDIRS := $(patsubst %, $(OBJDIR)/%, $(MODULES))
OBJS := $(patsubst %.c, $(OBJDIR)/%.o, $(SRCS))

我们也可以有简写形式。

DEPS := $(OBJS:.o=.d)

过滤器

我们可以只选择一些带有过滤器的文件,这是一个例子:

OBJ := $(patsubst %.c, %.o,  $(filter %.c, $(SRC)))

方法一

在此方法中,我们指定依赖项(.d 依赖于.c),并将创建的依赖项文件包含在include 中。

.PHONY: clean depend

CC   := gcc
CXX  := g++ 
LD   := g++
CP   := cp

PROG := hellomake

MODULES := src

OBJDIR := obj

default: $(PROG)

OPTFLAGS  := -g -O

CFLAGS   += -Wall -Wno-unused-function $(OPTFLAGS) $(patsubst %, -I%, $(MODULES)) 

GARBAGE := core core.* *.stackdump ./tags $(PROG)

include $(patsubst %, %/module.make, $(MODULES))

OBJ := \
    $(patsubst %.c, %.o,  $(filter %.c, $(SRC)))

DEP := $(OBJ:.o=.d)

# implicit rules

%.d: %.c
    ./depends.sh $(CC) `dirname $*.c` $(CFLAGS) $*.c > $@

-include $(DEP)

# Actual targets

depend: $(DEP)

clean: 
    rm -rf $(PROG) $(OBJ) $(GARBAGE) $(DEP) depends

$(PROG): $(OBJ)
    $(LD) -o $@ $^ $(LIBS)

每个模块都应包含 make 文件 (module.make) 以指定 SRC 变量中包含哪些文件。

`SRC += src/hellofunc.c \
    src/hellomake.c`. 

这是生成依赖文件的脚本:

#!/bin/sh
#echo "## Got: $*"
CC="$1"
DIR="$2"
shift 2
case "$DIR" in
    "" | ".")
    $CC -MM -MG "$@" | sed -e 's@^\(.*\)\.o:@\1.d \1.o:@'
    ;;
    *)
    $CC -MM -MG "$@" | sed -e "s@^\(.*\)\.o:@$DIR/\1.d $DIR/\1.o:@"
    ;;
esac

这个方法很简单,但是目标文件和依赖文件是用这些语句在同一个src目录下创建的。

SRC += src/hellofunc.c src/hellomake.c 
OBJ := $(patsubst %.c, %.o,  $(filter %.c, $(SRC)))
DEP := $(OBJ:.o=.d)

方法二

此方法创建对象目录,并将所有生成的(中间)文件放入目录中。

它征集所有模块来指定目标文件和依赖文件生成的操作。

在示例中,我们只有一个模块,但是有多个模块,我们需要复制语句。

obj/src/%.o: src/%.c
    $(CC) -c $< -o $@ $(CFLAGS)
obj/src/%.d: src/%.c
    gcc -MM -MG $< $(CFLAGS) | sed -e 's@^\(.*\)\.o:@obj/src/\1.d obj/src/\1.o:@' > $@

这是生成文件:

.SUFFIX = .o .c
.PHONY: clean 

CC   := gcc
LD   := gcc

PROG := hellomake

OBJDIR = obj
MODULES := src 
SRCS := src/hellofunc.c src/hellomake.c

OBJDIRS := $(patsubst %, $(OBJDIR)/%, $(MODULES))
OBJS := $(patsubst %.c, $(OBJDIR)/%.o, $(SRCS))
DEPS := $(OBJS:.o=.d)

default: $(PROG)

CFLAGS   += -Wall -Wno-unused-function $(OPTFLAGS) $(patsubst %, -I%, $(MODULES)) 
CXXFLAGS += $(CFLAGS) 

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

$(PROG): $(OBJDIRS) $(OBJS)
    $(LD) $(filter %.o, $^) -o $(PROG)

-include $(DEPS)


obj/src/%.d: src/%.c
    gcc -MM -MG $< $(CFLAGS) | sed -e 's@^\(.*\)\.o:@obj/src/\1.d obj/src/\1.o:@' > $@

depend: $(DEPS)

GARBAGE := core core.* *.stackdump ./tags $(PROG)
clean:
    rm -rf $(PROG) obj/*

$(OBJDIRS):
    mkdir -p $@ 

参考

【讨论】:

    【解决方案2】:
    IDIR = ./include
    CC = gcc
    CFLAGS = -I$(IDIR)
    SRCDIR = src
    ODIR = obj
    LDIR = ./lib
    
    LIBS = -lm
    
    SRC = hellomake hellofunc
    OBJ = ${SRC:%=$(ODIR)/%.o}
    
    _DEPS = hellomake.h
    DEPS = ${_DEPS:%=$(IDIR)/%}
    
    %.o: ../$(SRCDIR)/%.c $(DEPS)
        $(CC) -c -o $@ $< $(CFLAGS)
    
    hellomake: $(OBJ) $(DEPS)
        gcc -o $@ $^ $(CFLAGS) $(LIBS)
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2023-04-11
      • 2011-01-29
      • 2012-06-20
      • 2018-04-05
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多