简体   繁体   English

Makefile模式规则:循环makefile.o <-删除了makefile依赖项

[英]Makefile Pattern rule: Circular makefile.o <- makefile dependency dropped

I am working on a makefile for a C++ project that needs to support a few configurations, ie debug , release and maybe a few more customized ones in the future. 我正在为一个C ++项目制作一个makefile,该文件需要支持一些配置,例如,debug,release和将来可能的一些自定义配置。

Currently, my naming convention for generated .o files is $(SOURCE_FULLPATH).$(CONFIGURATION).o . 目前,我对生成的.o文件的命名约定是$(SOURCE_FULLPATH).$(CONFIGURATION).o For instance, ABC.cpp generates ABC.cpp.debug.o in debug mode. 例如, ABC.cpp在调试模式下生成ABC.cpp.debug.o

Now I would like to write the pattern rule for generating those object files in a configuration-independent way. 现在,我想编写模式规则,以独立于配置的方式生成那些目标文件。 What I did was: from each XX.o filename, I strip the .debug or .release suffix from XX , and use the remaining part of XX as the source filename. 我所做的是:从每个XX.o文件名,我剥去.debug.release从后缀XX ,并使用剩余部分XX作为源文件名。

%.o: $$(basename %)
    $(CC) $(CC_FLAGS) $(INCLUDE_FOLDERS) -c -o $@ $<

With this trick, I can build the executable correctly, except that I get one warning message from make: 使用此技巧,我可以正确构建可执行文件,但从make收到一条警告消息:

make: Circular makefile.o <- makefile dependency dropped.

I am puzzled because I do not list makefile or makefile.o as a target or dependency anywhere in my makefile. 我很困惑,因为我没有在makefile中的任何地方列出makefilemakefile.o作为目标或依赖项。 I did a search on SO, but most questions about Circular dependency is on a specific user source file, rather than the makefile itself. 我在SO上进行了搜索,但是有关循环依赖的大多数问题都在特定的用户源文件上,而不是在makefile本身上。 Can anyone help me understand what causes the circular dependency, and how to get rid of this warning message ? 谁能帮助我了解导致循环依赖的原因以及如何消除此警告消息

A sample makefile that can reproduce this issue is listed below. 下面列出了可以重现此问题的示例生成文件。

.SECONDEXPANSION:

PROJECT := helloworld
CC := clang++
BUILD_FOLDER := Build
OBJ_FILE_SUFFIX := .o

# Source
CPP_FILES :=\
    Source/hello.cpp \
    Source/mysqrt.cpp \

INCLUDE_FOLDERS := \
    -IInclude

# MMD outputs the dependency files (".d" files). These files will be used by
# this makefile to allow for dependency checking on .h files.
CC_FLAGS += -MMD

EXISTING_OBJ_FILES = $(wildcard $(addsuffix *.o, $(basename $(CPP_FILES))))

##--------------------
## Targets definition
##--------------------
.PHONY:default
default: all

.PHONY:all
all: debug release

.PHONY:debug release
# Add a 'debug'/'release' suffix to the name of the object file
# e.g. hello.cpp -> hello.cpp.debug.o
debug release: OBJ_FILES=$(addsuffix .$@$(OBJ_FILE_SUFFIX), $(CPP_FILES))
debug release: $${OBJ_FILES}    # Use Secondary Expansion to get the obj names
    $(CC) $^ -o $(BUILD_FOLDER)/$(PROJECT)_$@ 

# Strip configuration name from the end of the object file name
%.o: $$(basename %)
    $(CC) $(CC_FLAGS) $(INCLUDE_FOLDERS) -c -o $@ $<

## clean: remove executable, all object files, and all dependency files
.PHONY:clean
clean:
    -rm -f $(BUILD_FOLDER)/$(PROJECT) $(EXISTING_OBJ_FILES) $(EXISTING_OBJ_FILES:.o=.d)

# Include the dependent files so that in later builds, modified .h files 
# will cause all .cpp dependent on them to rebuild
-include $(OBJ_FILES:.o=.d)

The folder structure is 文件夹结构为

makefile
Source
- hello.cpp
- mysqrt.cpp
Include
- mysqrt.h

The full output of make debug is make debug的完整输出为

make: Circular makefile.o <- makefile dependency dropped.
clang++ -MMD -IInclude -c -o Source/hello.cpp.debug.o Source/hello.cpp
clang++ -MMD -IInclude -c -o Source/mysqrt.cpp.debug.o Source/mysqrt.cpp
clang++ Source/hello.cpp.debug.o Source/mysqrt.cpp.debug.o -o Build/helloworld_debug 

Everything is good except for the first line. 除了第一行,其他一切都很好。

I would also really appreciate it if anyone can point to me if there is any bad practice in my makefile (I am still a newbie in makefile). 如果有人在我的makefile中存在任何不良做法(如果我仍然是makefile中的新手),那么如果有人可以指向我,我也将非常感激。 Thank you in advance! 先感谢您!

GNU Make always attempts to update the makefile(s) it has read before making anything else. GNU Make总是在尝试进行其他操作之前尝试更新已读取的makefile。 If it finds rules and prerequisites that tell it to update makefile(s), then it does so and then starts again from scratch - including attempting to update the makefile(s). 如果发现规则和先决条件要求其更新Makefile,则它将这样做,然后从头开始-包括尝试更新Makefile。 See 3.5 How Makefiles Are Remade . 请参见3.5如何重新制作Makefile

In your recipe: 在您的食谱中:

%.o: $$(basename %)
    $(CC) $(CC_FLAGS) $(INCLUDE_FOLDERS) -c -o $@ $<

you have provided make with a rule for making makefile.o from makefile . 您所提供make与制作规则makefile.omakefile

It is also the inverse of the rule in the builtin recipe 这也是内置配方中规则的逆向

%: %.o
    $(LINK.o) $^ $(LOADLIBES) $(LDLIBS) -o $@

which makes an executable from a single object file. 从单个目标文件生成可执行文件。 So your recipe has introduced the circularity: 因此,您的配方已引入了圆度:

makefile.o <- makefile <- makefile.o

when make is considering makefile itself as a target. makemakefile本身作为目标时。 You could suppress the circularity by expressly deleting the builtin inverse rule, by writing the empty rule: 通过编写空规则,可以明确删除内置的逆规则来抑制圆度:

%: %.o

in the makefile. 在makefile中。 Then you could observe the following confusion on the part of the compiler: 然后,您可以在编译器部分观察到以下混乱:

$ make makefile.o
clang++   -c -o makefile.o makefile
clang: warning: makefile: 'linker' input unused

And the same would occur if you attempted to make any target that depended on makefile.o . 如果尝试创建任何依赖makefile.o目标,也会发生同样的情况。

It is probably safe to assume that you will have no targets that depend on makefile.o . 可以肯定地假设您将没有依赖于makefile.o目标。 Nevertheless a rule that would attempt to compile foo.o from any existing file foo is clearly more sweeping that you want or need. 但是,尝试从任何现有文件foo编译foo.o的规则显然更加需要或需要。 For the particular pattern of dependency that you wish to capture: 对于您希望捕获的特定依赖性模式:

foo.cpp.{debug|release}.o: foo.cpp

You'd be better off with: 您最好拥有:

%.o: $$(basename $$(basename %)).cpp
    $(CC) $(CC_FLAGS) $(INCLUDE_FOLDERS) -c -o $@ $<

Note, BTW, that in GNU Make conventions - the conventions that are assumed by GNU Make's builtin rules - CC denotes your C compiler while CXX denotes your C++ compiler. 注意,顺便说一句,在GNU Make约定中-由GNU Make的内置规则假定的约定CC表示您的C编译器,而CXX表示您的C ++编译器。 Likewise flags for the C compiler are denoted CFLAGS and flags for the C++ compiler are denoted CXXFLAGS . 同样,C编译器的标志表示为CFLAGS ,C ++编译器的标志表示为CXXFLAGS

Flags for the preprocessor are denoted CPPFLAGS , and -I path options - which are preprocessor options - are conventionally be passed through CPPFLAGS . 用于预处理器的标志表示为CPPFLAGS ,并且-I 路径选项(即预处理器选项)通常通过CPPFLAGS传递。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM