如何使用自动依赖生成器编写 make 文件

Posted

技术标签:

【中文标题】如何使用自动依赖生成器编写 make 文件【英文标题】:How to write make files with auto dependancy generator 【发布时间】:2016-11-27 05:23:15 【问题描述】:

扩展我之前的问题how to write a makefile for structured file system:

文件结构:

.
├── Headers
│   ├── function.h
│   └── test.h
├── makefile
├── README.md
└── Sources
    ├── function.c
    ├── main.c
    └── test.c

我正在尝试编写一个 makefile,它可以读取任何给定源文件上的 #include<...> 并根据需要进行编译。

原来我的make文件是这样的:

INC_DIR = Headers
SRC_DIR = Sources
OBJ_DIR = Objects
#CXXFLAGS = -c -Wall -I. -IHeaders
CXXFLAGS = -c -Wall -I. -IHeaders
CC = gcc

SRCS = $(SRC_DIR)/*.c 
OBJS = $(OBJ_DIR)/*.o
#The wildcard and patsubt commads will come handy

DEPS = $(INC_DIR)/*.h
#need to use an automatic dependency generator

output: $(OBJ_DIR)/main.o $(OBJ_DIR)/function.o
    $(CC) $^ -o $@

$(OBJ_DIR)/%.o: $(SRC_DIR)/%.c $(DEPS)
    $(CC) $(CXXFLAGS) $< -o $@


run: output
    ./output

clean: 
    rm $(OBJ_DIR)/*.o 
    rm output
-@echo "Clean completed"

这意味着对于output 所依赖的每个源文件,我必须将该对象添加到这一行。

output: $(OBJ_DIR)/main.o $(OBJ_DIR)/function.o $(OBJ_DIR)/test.o
    $(CC) $^ -o $@

任何其他源文件是否依赖于一个或多个源,必须添加额外的规则。

要解决这个问题: 这是我从Auto-Dependency Generation 和4.14 Generating Prerequisites Automatically 收集到的信息

正如社区成员所提到的,我对依赖项生成以及如何使用生成的文件有不同的理解。

DEP_DIR = .d
$(shell mkdir -p $(DEP_DIR) >/dev/null)

DEPFLAGS = -MT $@ -MMD -MP -MF $(DEP_DIR)/$*.Td

INC_DIR = Headers
SRC_DIR = Sources
OBJ_DIR = Objects
$(shell mkdir -p $(OBJ_DIR) >/dev/null)
CXXFLAGS = -c -Wall -I. -IHeaders
CC = gcc

SRCS = $(SRC_DIR)/*.c 
OBJS = $(OBJ_DIR)/*.o
#The wildcard and patsubt commads will come handy

#DEPS = $(INC_DIR)/*.h

MAKEDEPEND = $(CC) $(CXXFLAGS) $< \
               | sed -n 's/^\# *[0-9][0-9]* *"\([^"]*\)".*/$*.o: \1/p' \
               | sort | uniq > $*.Td

COMPILE.c = $(CC) $(DEPFLAGS) $(CXXFLAGS)
#need to use an automatic dependency generator

#%.d: %.c
#   @set -e; rm -f $@; \
#   $(CC) -MP -MD $(CXXFLAGS) $< > $@.$$$$; \
#   sed 's,\($*\)\.o[ :]*,\1.o $@ : ,g' < $@.$$$$ > $@; \
#   rm -f $@.$$$$

$(OBJ_DIR)/%.o: $(SRC_DIR)/%.c $(DEP_DIR)/%.d
    @$(MAKEDEPEND); \
    cp $*.Td $*.d; \
    sed -e 's/#.*//' -e 's/^[^:]*: *//' -e 's/ *\\$$//' \
    -e '/^$$/ d' -e 's/$$/ :/' < $*.Td >> $*.d; \
    rm -f $*.Td
    #$(COMPILE.c) -o $@ $<  
    $(CC) $(CXXFLAGS) $(DEPFLAGS) $< -o $@

-include $(SRCS:.c=.d)

$(DEP_DIR)/%.d: ;
.PRECIOUS: $(DEP_DIR)/%.d

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

run: output
    ./output

clean: 
    rm -r $(OBJ_DIR) 
    rm -r $(DEP_DIR) 
    rm output
    -@echo "Clean completed"

make执行时的错误是:

$ make
gcc -c -Wall -I. -IHeaders -MT Objects/*.o -MMD -MP -MF .d/*.Td Sources/function.c -o Objects/*.o
gcc Objects/*.o -o output
/usr/lib/gcc/x86_64-linux-gnu/5/../../../x86_64-linux-gnu/crt1.o: In function `_start':
(.text+0x20): undefined reference to `main'
collect2: error: ld returned 1 exit status
makefile:48: recipe for target 'output' failed
make: *** [output] Error 1

所以,我希望实现自动依赖检测和编译。我认为错误在于检测依赖项的方式以及为给定源文件生成它们的方式。

【问题讨论】:

你的问题是什么? 正如标题所说!而且我写的makefile不起作用 “不起作用”不是有用的问题描述。此外,SO 不是您发布一堆代码并要求人们为您修复它的地方。在您尝试自己回答特定问题之后,SO 是您来寻找特定问题的答案的地方。在上面我只是指出你的MAKEDEPEND 的未注释版本是完全错误的:你正在调用带有普通标志的C 编译器,这些标志告诉它创建一个目标文件,而不是生成依赖项。您也可以尝试阅读make.mad-scientist.net/papers/… @MadScientist 我已经阅读了那篇文章,并在我的帖子中提到了它。另外,我试图先解决我的问题,但我没有得到任何结果!你会在这里帮忙吗? 我确实提供了帮助:我要求您创建一个可以回答的问题,这意味着显示您认为 makefile 的哪个部分是错误的,为什么您认为它是错误的(显示您键入的命令和你得到的结果,如果不是很明显,为什么你认为这个结果是错误的)。发布一个大的 makefile 并在没有任何其他细节的情况下说“它不起作用”不是一个有用的问题。 【参考方案1】:

在我看来,您正在尝试组合多种不同的方式来生成依赖信息,但这是行不通的。高级帖子讨论了解决问题的多种方法:您需要选择一个而不是尝试将它们一起使用。

如果您想使用高级方法,请按照顶部“TL;DR”部分中的说明使用它,或者在底部的“组合编译和依赖项生成”部分中使用它。如果您使用的是 GCC,则不需要 MAKEDEPENDsed 等。

高级帖子说您的规则应如下所示:

COMPILE.c = $(CC) $(DEPFLAGS) $(CFLAGS) $(CPPFLAGS) $(TARGET_ARCH) -c
POSTCOMPILE = mv -f $(DEPDIR)/$*.Td $(DEPDIR)/$*.d

%.o : %.c
%.o : %.c $(DEPDIR)/%.d
        $(COMPILE.c) $(OUTPUT_OPTION) $<
        $(POSTCOMPILE)

就是这样。

【讨论】:

以上是关于如何使用自动依赖生成器编写 make 文件的主要内容,如果未能解决你的问题,请参考以下文章

make自动生成依赖文件的两种形式

Makefile使用

用make生成c源的目标文件时如何生成依赖文件

Shell脚本——make命令和Makefile文件

GCC学习 如何编写makefile

make 备忘清单_开发速查表分享