Makefile(自动生成依赖项)

Makefile(自动生成依赖项),makefile,dependencies,gnu,Makefile,Dependencies,Gnu,仅用于快速术语: #basic makefile rule target: dependencies recipe 问题是:我想自动生成依赖项。 例如,我希望扭转这一局面: #one of my targets file.o: file.cpp 1.h 2.h 3.h 4.h 5.h 6.h 7.h 8.h another.h lots.h evenMore.h $(COMPILE) 为此: #one of my targets file.o: $(GENERATE)

仅用于快速术语:

#basic makefile rule
target: dependencies
    recipe
问题是:我想自动生成依赖项。 例如,我希望扭转这一局面:

#one of my targets
file.o: file.cpp 1.h 2.h 3.h 4.h 5.h 6.h 7.h 8.h another.h lots.h evenMore.h
    $(COMPILE)
为此:

#one of my targets
file.o: $(GENERATE)
    $(COMPILE)
我不太确定这是否可能

我所知道的是: 我可以使用此编译器标志:

g++ -MM file.cpp
它将返回正确的目标和依赖项。
因此,从示例中,它将返回:

file.o: file.cpp 1.h 2.h 3.h 4.h 5.h 6.h 7.h 8.h another.h lots.h evenMore.h  
但是,“make”不允许我在规则的目标或依赖项部分显式编写shell代码:(
我知道有一个叫make的函数

但我不能将其作为依赖项插入并进行解析,因为它依赖于表示目标的宏$@或者至少我认为这就是问题所在

我甚至尝试过用这个makefile函数替换“file.cpp”依赖项,但这也行不通

#it's suppose to turn the $@ (file.o) into file.cpp
THE_CPP := $(addsuffix $(.cpp),$(basename $@))

#one of my targets
file.o: $(THE_CPP) 1.h 2.h 3.h 4.h 5.h 6.h 7.h 8.h another.h lots.h evenMore.h
    $(COMPILE)
#this does not work
因此,在整个谷歌,似乎有两种解决方案。这两种解决方案我都没有完全掌握。

所以我的最终问题是:有没有可能按照我想要的方式去做,

如果没有,有人能把这些网站中的代码分解一下,并详细地向我解释它们是如何工作的吗?如果有必要,我会用其中一种方法来实现它,但我厌倦了在理解它之前只将一块代码粘贴到我的makefile中。

首先,你可以使用
的_CPP=$(patsubst%.o,%.CPP,$@)

然后可以运行
make-p
来理解
make

通常的做法是将makefile依赖项生成到
*.md
文件中:

%.o: %.c
       $(COMPILE.c) $(OUTPUT_OPTION) $< -MMD -MF $(patsubst %.c,%.md,$@)

但您也可以考虑使用其他的建设者和许多其他的生成器< /P> < P>来操纵文件名,当您已经知道依赖项应该是什么时,可以使用一个模式规则:

file.o: %.o : %.cpp 1.h 2.h 3.h 4.h 5.h 6.h 7.h 8.h another.h lots.h evenMore.h
    $(COMPILE)
您可以将该规则重新用于其他目标:

# Note these two rules without recipes:
file.o: 1.h 2.h 3.h 4.h 5.h 6.h 7.h 8.h another.h lots.h evenMore.h
anotherFile.o: 4.h 9.h yetAnother.h

file.o anotherFile.o: %.o : %.cpp
    $(COMPILE)
但是,如果您想自动计算依赖项列表,最好的方法(据我所知)是。它看起来像这样:

%.o : %.cc
        @g++ -MD -c -o $@ $<
        @cp $*.d $*.P; \
             sed -e 's/#.*//' -e 's/^[^:]*: *//' -e 's/ *\\$$//' \
                 -e '/^$$/ d' -e 's/$$/ :/' < $*.d >> $*.P; \
             rm -f $*.d

-include *.P
%.o:%.cc
@g++-MD-c-o$@$<
@cp$*.d$*.P\
sed-e's/#.*/'-e's/^[^::::*:*/'-e's/*\\$$/'\
-e'/^$$/d'-e's/$$/:/'<$*.d>$*.P\
rm-f$*.d
-包括*.P

基本上,当它构建
file.o
时,它也会构建
file.d
。然后它通过一个令人困惑的sed命令运行
file.d
,该命令将依赖项列表转换为一个没有配方的规则。最后一行是一条指令,指示
包含现有的任何此类规则。这里的逻辑微妙而巧妙:你不需要在您第一次构建
foo.o
时,它实际上不需要依赖项,因为Make已经知道必须构建
foo.o
,因为它不存在。下次运行Make时,它将使用上次创建的依赖项列表。如果您更改其中一个文件,使其实际上存在一个不在lis中的新依赖项t、 Make仍将重建
foo.o
,因为您更改了一个依赖项文件。试试看,它真的很有效!

WOOO!我在Beta的帖子中成功地将代码用于一个小型测试项目。
我应该注意到,对于任何可能遇到这种情况的人, 如果您使用的是bashshell(我曾经使用过),则需要在井号前面添加一个转义字符,以避免将表达式的其余部分作为注释

%.o:%.cpp
g++-c-MD-o$@$<
cp$*.d$*.P;\
sed-e's/\\\\\\\\\.*/'-e's/^[^:::*:*:*/'-e's/*\\$$/'\
-e'/^$$/d'-e's/$$/:/'<$*.d>>$*.P;\
rm-f$*.d
-包括*.P
现在我想分享我在中找到的信息,因为它指出了一些关于这个问题的重要问题,并提供了我还没有完全掌握的代码。
本书中出现的方法与上的方法类似。
看起来是这样的:

include $(subst .c,.d,$(SOURCES))

%.d: %.c
    $(CC) -M $(CPPFLAGS) $< > $@.$$$$; \
    sed 's,\($*\).o[ :]*,\1.o $@ : ,g' < $@.$$$$ > $@; \
    rm -f $@.$$$$
包括$(subst.c、.d、$(源代码))
%d.d:%
$(CC)-M$(CPPFLAGS)$<>$@.$$$\
sed's,\($*\).o[:]*,\1.o$@:,g'<$@.$$>$@\
rm-f$@$$$$
这就是我认为正在发生的事情。
“make”希望立即为每个源文件包含一个“.d”文件。
由于最初不存在.d文件,因此会反复运行代码块以创建所有缺少的.d文件。
这意味着make将一次又一次地重新开始,直到每个.d文件都被创建并包含在make文件中。
每个“.d”文件都是Beta版所说的:一个具有一组依赖项且没有配方的目标

如果头文件发生更改,则其中包含的规则将首先需要更新依赖项。这让我有点不舒服,代码块如何能够再次调用?它用于更新.d文件,因此如果.h文件发生更改,如何调用它?除此之外,我意识到默认规则用于编译对象。如对此解释有任何澄清/误解,敬请谅解


在本书的后面部分,它指出了这种方法存在的问题,以及我认为在高级自动依赖项生成实现中也存在的问题。
问题1:效率低下。“make”每次生成.d文件时都必须重新启动
问题2:make会为所有丢失的.d文件生成警告消息,这通常只是一个麻烦,可以通过在include语句前添加“-”来隐藏。
问题3:如果您删除一个src文件,因为它不再需要,“make”将在下次尝试编译时崩溃,因为某些.d文件将缺少的src作为依赖项,并且没有规则重新创建该src,make将拒绝进一步操作

他们说Tromey的方法可以解决这些问题,但代码看起来与网站上的代码非常不同。也许这只是因为他们使用了一些宏,将其作为函数调用,并编写了稍微不同的代码。我仍在研究,但我想
%.o : %.cpp  
    g++ -c -MD -o $@ $<  
    cp $*.d $*.P; \  
    sed -e 's/\#.*//' -e 's/^[^:]*: *//' -e 's/ *\\$$//' \  
        -e '/^$$/ d' -e 's/$$/ :/' < $*.d >> $*.P; \  
    rm -f $*.d  
-include *.P  
include $(subst .c,.d,$(SOURCES))

%.d: %.c
    $(CC) -M $(CPPFLAGS) $< > $@.$$$$; \
    sed 's,\($*\).o[ :]*,\1.o $@ : ,g' < $@.$$$$ > $@; \
    rm -f $@.$$$$
CPPFLAGS = -std=c++1y -MD -MP 

SRC = $(wildcard *.cpp)
all: main

main: $(SRC:%.cpp=%.o)
    g++ $(CPPFLAGS) -o $@ $^

-include $(SRC:%.cpp=%.d)
# List my sources
CPP_SOURCES := foo.cpp bar.cpp

# If I'm debugging, change my output location
ifeq (1,$(DEBUG))
  OBJ_DIR:=./obj/debug
  CXXFLAGS+= -g -DDEBUG -O0 -std=c++0x
else
  CXXFLAGS+= -s -O2 
  OBJ_DIR:=./obj/release
endif

# destination path macro we'll use below
df = $(OBJ_DIR)/$(*F)

# create a list of auto dependencies
AUTODEPS:= $(patsubst %.cpp,$(OBJ_DIR)/%.d,$(CPP_SOURCES))

# include by auto dependencies
-include $(AUTODEPS)

.... other rules

# and last but not least my generic compiler rule
$(OBJ_DIR)/%.o: %.cpp 
    @# Build the dependency file
    @$(CXX) -MM -MP -MT $(df).o -MT $(df).d $(CXXFLAGS) $< > $(df).d
    @# Compile the object file
    @echo " C++ : " $< " => " $@
    @$(CXX) -c $< $(CXXFLAGS) -o $@
SRCDIR = src
OBJDIR = obj
LIBDIR = lib
DOCDIR = doc

# Get Only the Internal Structure of Directories from SRCDIR
STRUCTURE := $(shell find $(SRCDIR) -type d)

#Filter-out hidden directories
STRUCTURE := $(filter-out $(shell find $(SRCDIR)/.* -type d),$(STRUCTURE))

# Get All Files From STRUCTURE
CODEFILES := $(addsuffix /*,$(STRUCTURE))
CODEFILES := $(wildcard $(CODEFILES))


## Filter Only Specific Files
SRCFILES := $(filter %.c,$(CODEFILES))
HDRFILES := $(filter %.h,$(CODEFILES))
OBJFILES := $(subst $(SRCDIR),$(OBJDIR),$(SRCFILES:%.c=%.o))
DOCFILES := $(addprefix $(DOCDIR)/,             \
            $(addsuffix .md,                    \
            $(basename $(SRCFILES))))


# Filter Out Function main for Libraries
LIBDEPS := $(filter-out $(OBJDIR)/main.o,$(OBJFILES))
# See http://make.mad-scientist.net/papers/advanced-auto-dependency-generation/
# for the template used to start this file

# -- TODO: customize the list below for your project ---
# List of source .c files used with the project
SRCS := main.c file1.c file2.c

# The aplication generated 
APPNAME = depend-generation-test
# -- End of customization section ---

# Replace .c extension on SRCS to get objfiles using gnu make pattern rules and substitution references.
# See https://www.gnu.org/software/make/manual/html_node/Pattern-Intro.html#Pattern-Intro for pattern rules and 
# https://www.gnu.org/software/make/manual/html_node/Substitution-Refs.html#Substitution-Refs for substitution references overview
OBJFILES := $(SRCS:%.c=%.o)

# Build the app you've specified in APPNAME for the "all" or "default" target
all : $(APPNAME)
default : $(APPNAME)

# Remove all build intermediates and output file
clean : ; @rm -rf $(APPNAME) *.o

# Build the application by running the link step with all objfile inputs
$(APPNAME) : $(OBJFILES)
    $(CC) $(LDFLAGS) $^ -o $(APPNAME)

# Add all warnings/errors to cflags default.  This is not required but is a best practice
CFLAGS += -Wall -Werror

# The below content is from  http://make.mad-scientist.net/papers/advanced-auto-dependency-generation/
# with the following changes:
#   1) Added comments
#   2) Removed TARGET_ARCH from COMPILE.c since it's no longer listed in the [default rules](https://www.gnu.org/software/make/manual/html_node/Catalogue-of-Rules.html#Catalogue-of-Rules) and [isn't documented](https://lists.gnu.org/archive/html/help-make/2010-06/msg00005.html)
# Original content below is:
# Copyright © 1997-2019 Paul D. Smith Verbatim copying and distribution is permitted in any medium, provided this notice is preserved.

# The directory (hidden) where dependency files will be stored
DEPDIR := .deps
# Flags passed to gcc to automatically build dependencies when compiling
# See https://www.gnu.org/software/make/manual/html_node/Automatic-Variables.html for detail about variable names
# $@ references the target file of the rule and will be "main.o" when compiling "main.c"
# $* references the stem of the rule, and will be "main" when target is "main.o"
DEPFLAGS = -MT $@ -MMD -MP -MF $(DEPDIR)/$*.d

# Rules for compiling a C file, including DEPFLAGS along with Implicit GCC variables.
# See https://www.gnu.org/software/make/manual/html_node/Implicit-Variables.html
# and see https://www.gnu.org/software/make/manual/html_node/Catalogue-of-Rules.html#Catalogue-of-Rules
# for the default c rule
COMPILE.c = $(CC) $(DEPFLAGS) $(CFLAGS) $(CPPFLAGS) -c

# Delete the built-in rules for building object files from .c files
%.o : %.c
# Define a rule to build object files based on .c or dependency files by making the associated dependency file
# a prerequisite of the target.  Make the DEPDIR an order only prerequisite of the target, so it will be created when needed, meaning
# the targets won't get rebuilt when the timestamp on DEPDIR changes
# See https://www.gnu.org/software/make/manual/html_node/Prerequisite-Types.html for order only prerequesites overview.
%.o : %.c $(DEPDIR)/%.d | $(DEPDIR)
    $(COMPILE.c) $(OUTPUT_OPTION) $<

# Create the DEPDIR when it doesn't exist
$(DEPDIR): ; @mkdir -p $@

# Use pattern rules to build a list of DEPFILES
DEPFILES := $(SRCS:%.c=$(DEPDIR)/%.d)
# Mention each of the dependency files as a target, so make won't fail if the file doesn't exist
$(DEPFILES):

# Include all dependency files which exist, to include the relevant targets.
# See https://www.gnu.org/software/make/manual/html_node/Wildcard-Function.html for wildcard function documentation
include $(wildcard $(DEPFILES))