如何使用自动依赖生成器

时间:2016-11-27 05:23:15

标签: c++ c makefile

扩展到我之前的问题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 Generation4.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

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

1 个答案:

答案 0 :(得分:0)

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

如果要使用高级方法,请按照顶部“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)

就是这样。