I've trying to learn the "best practice" makefile's for a project.
我正在尝试学习项目的“最佳实践”makefile。
Please review my Makefile file below and suggest changes to enhance it.
请查看下面的Makefile文件并提出更改以加强它。
The dir layout:
目录布局:
root dir
--- Makefile
deps
--- deps
bin
--- binary
objs
--- all .o files
include
--- all .h files
src
--- all .c .cc files
The makefile:
#
# Generic makefile
#
all: tengine test2
#
# Include files for compiling, and libraries for linking.
#
INC=-I /usr/include -I /usr/local/include -I /usr/include/hiredis
LIB=-lhiredis
#
# Debug or not debug?
#
DEBUG=1
ifdef DEBUG
CFLAGS=-Wall -Winline -pipe -g -DDEBUG #-pedantic -pg
else
CFLAGS=-Wall -Winline -pipe -O3 -march=native -funroll-all-loops \
-finline-functions #-pedantic
endif
#CXXFLAGS=$(CFLAGS)
# Rules for creating dependency files
deps/%.d: src/%.cc
@echo Generating $@
@mkdir -p $(dir $@)
$(CXX) $(CXXFLAGS) $(INC) -MM -MT '$(patsubst src/%,obj/%,%(patsubst %.cc,%.o,$<))' $< > $@
deps/%.d: src/%.c
@echo Generating $@
@mkdir -p $(dir $@)
$(CXX) $(CXXFLAGS) $(INC) -MM -MT '$(patsubst src/%,obj/%,%(patsubst %.c,%.o,$<))' $< > $@
# Rules for compilation
#
# C source with header and no c++ code
obj/%.o: src/%.c src/%.h deps/%.d
@echo Compiling $@
@mkdir -p $(dir $@)
$(CC) $(CFLAGS) $(INC) -o $@ -c $<
# C++ source with header.
obj/%.o: src/%.cc src/%.h deps/%.d
@echo Compiling $@
@mkdir -p $(dir $@)
$(CXX) $(CXXFLAGS) $(INC) -o $@ -c $<
# C source without header and no c++ code
obj/%.o: src/%.c deps/%.d
@echo Compiling $@
@mkdir -p $(dir $@)
$(CC) $(CFLAGS) $(INC) -o $@ -c $<
# C++ source without header.
obj/%.o: src/%.cc deps/%.d
@echo Compiling $@
@mkdir -p $(dir $@)
$(CXX) $(CXXFLAGS) $(INC) -o $@ -c $<
# ##############################################################
#
# TARGET: tengine
#
# ##############################################################
OBJS= obj/main.o obj/tengine.o
tengine: $(OBJS)
$(CXX) -pipe $(CXXFLAGS) -o bin/tengine $(OBJS) $(LIB)
# ##############################################################
#
# TARGET: test2
#
# ##############################################################
OBJS= obj/main.o obj/test2.o
test2: $(OBJS)
$(CXX) -pipe $(CXXFLAGS) -o bin/test2 $(OBJS) $(LIB)
# ##############################################################
#
# Cleanup
#
# ##############################################################
clean:
rm -f *~ bin/* obj/* deps/* src/*~ gmon.out
help:
@echo ""
@echo "make - builds tengine"
@echo "make test2 - builds test2"
@echo "make all - builds tengine test2"
@echo "make clean - deletes prior build"
3 个解决方案
#1
1
If you expect other people to use your Makefile, always include a help
target that prints out a message detailing the various targets that are sensible to call from the command line, and the various environment vars which can be reasonably set to do various things...
如果您希望其他人使用您的Makefile,请始终包含一个帮助目标,该目标打印出一条消息,详细说明了从命令行调用的各种目标,以及可以合理设置为执行各种操作的各种环境变量。 。
#2
1
Here is a suggestion for a revised makefile, tested slightly on a 7-year-old version of Linux (RHEL 5):
以下是修改后的makefile的建议,在7岁版本的Linux(RHEL 5)上稍作测试:
# Generic makefile
TARGETS=tengine test2
all: ${TARGETS}
help:
@echo ""
@echo "make - builds ${TARGETS}"
@echo "make tengine - builds tengine"
@echo "make test2 - builds test2"
@echo "make clean - deletes prior build"
@echo "make help - prints this help"
# Switches:
INC=-I/usr/include/hiredis
LIB=-lhiredis
SUBDIRS=obj deps bin
LNK=gcc -g -Wl,--warn-common
DEBUG=1
ifdef DEBUG
CFLAGS=-Wall -Winline -pipe -g -DDEBUG #-pedantic -pg
else
CFLAGS=-Wall -Winline -pipe -O3 -march=native -funroll-all-loops \
-finline-functions #-pedantic
endif
#CXXFLAGS=$(CFLAGS)
# Generic rules:
obj/%.o: src/%.c
@echo Compiling $@
@mkdir -p $(SUBDIRS)
$(CC) $(CFLAGS) $(INC) -MMD -MF '$(patsubst src/%.c,deps/%.d,$<)' -o $@ -c $<
obj/%.o: src/%.cc
@echo Compiling $@
@mkdir -p $(SUBDIRS)
$(CXX) $(CXXFLAGS) $(INC) -MMD -MF '$(patsubst src/%.c,deps/%.d,$<)' -o $@ -c $<
${TARGETS}: %:bin/%
# Specific target rules:
bin/tengine: obj/main.o obj/tengine.o
$(LNK) $^ $(LIB) -o $@
bin/test2: obj/main.o obj/test2.o
$(LNK) $^ $(LIB) -o $@
clean:
rm -f *~ src/*~ gmon.out
rm -fr $(SUBDIRS)
-include deps/*.d
Some notes:
-
A key problem with the original was that the dependency were generated, but not used. This has been fixed using
-include deps/*.d
(at the end).原始的一个关键问题是生成了依赖,但没有使用。这已经使用-include deps / * .d(最后)修复。
-
Now that deps/*.d is used, the makefile doesn't need to have the
src/%.h
cases.现在使用deps / * .d,makefile不需要具有src /%.h的情况。
-
The original was also putting garbage into these files: in
$(patsubst src/%,obj/%,%(patsubst %.cc,%.o,$<))
the third%
should have been a$
.原来也把垃圾放到这些文件中:在$(patsubst src /%,obj /%,%(patsubst%。cc,%。o,$ <))中,第三个应该是$。
-
In the revised version, the dependencies are generated at the same time as the object, using
-MMD
. This is quicker, shortens the makefile, and adds some DRY.在修订版中,使用-MMD与对象同时生成依赖项。这样更快,缩短了makefile,并添加了一些DRY。
-
Shortened
INC
: why bother including the standard system include directories? And in fact gcc will apparently ignore your-I /usr/include -I /usr/local/include
anyway.缩短的INC:为什么还要包括标准系统包括目录呢?事实上,gcc显然会忽略你的-I / usr / include -I / usr / local / include。
-
Removed your two different definitions of
OBJS
. Not needed, and potentially confusing. Used$^
instead.删除了两个不同的OBJS定义。不需要,也可能令人困惑。使用$ ^代替。
-
It is always a good idea for
make clean
to completely undo everything make does, so you are left with what you started. But the sub-directories obj/ and deps/ were being created, and never deleted. Also, bin/ was pre-supposed to exist.make clean是一个好主意,可以完全撤消make所做的一切,所以你留下了你的开始。但是子目录obj /和deps /正在创建,并且从未被删除。此外,bin /被认为存在。
-
For the linking, added
$(LNK)
, withLNK=gcc -g -Wl,--warn-common
(but you may not want the warnings). AFAIK, all the other usual$(CFLAGS)
are ignored for links.对于链接,添加$(LNK),LNK = gcc -g -Wl, - warn-common(但您可能不需要警告)。 AFAIK,所有其他通常的$(CFLAGS)都被忽略了链接。
-
Removed comments, which were (mostly) distracting.
删除了评论,这些评论(主要)分散了注意力。
-
Repeated twice
make;make
now givesmake: Nothing to be done for ...
.重复两次制作;制作现在制作:没有什么可做的....
See also gcc dependency generation for a different output directory.
另请参阅不同输出目录的gcc依赖关系生成。
#3
-1
See this and that answers for examples about Makefile
. Also run make -p
to understand the builtin rules inside GNU make, so use $(LINK.cc)
for e.g. your bin/tengine
target.
有关Makefile的示例,请参阅此答案和答案。还要运行make -p来理解GNU make中的内置规则,所以使用$(LINK.cc)来实现例如你的bin / tengine目标。
For complex builds, consider upgrading to GNU make 4.0 and use its Guile ability.
对于复杂的构建,请考虑升级到GNU make 4.0并使用其Guile功能。
You may want to generate automatically dependencies. Read automatic prerequisites and about autodependencies; read also about GCC preprocessor options like -M
or -MD
etc etc ....
您可能希望自动生成依赖项。阅读自动先决条件和自动相关性;另请阅读GCC预处理器选项,如-M或-MD等等....
#1
1
If you expect other people to use your Makefile, always include a help
target that prints out a message detailing the various targets that are sensible to call from the command line, and the various environment vars which can be reasonably set to do various things...
如果您希望其他人使用您的Makefile,请始终包含一个帮助目标,该目标打印出一条消息,详细说明了从命令行调用的各种目标,以及可以合理设置为执行各种操作的各种环境变量。 。
#2
1
Here is a suggestion for a revised makefile, tested slightly on a 7-year-old version of Linux (RHEL 5):
以下是修改后的makefile的建议,在7岁版本的Linux(RHEL 5)上稍作测试:
# Generic makefile
TARGETS=tengine test2
all: ${TARGETS}
help:
@echo ""
@echo "make - builds ${TARGETS}"
@echo "make tengine - builds tengine"
@echo "make test2 - builds test2"
@echo "make clean - deletes prior build"
@echo "make help - prints this help"
# Switches:
INC=-I/usr/include/hiredis
LIB=-lhiredis
SUBDIRS=obj deps bin
LNK=gcc -g -Wl,--warn-common
DEBUG=1
ifdef DEBUG
CFLAGS=-Wall -Winline -pipe -g -DDEBUG #-pedantic -pg
else
CFLAGS=-Wall -Winline -pipe -O3 -march=native -funroll-all-loops \
-finline-functions #-pedantic
endif
#CXXFLAGS=$(CFLAGS)
# Generic rules:
obj/%.o: src/%.c
@echo Compiling $@
@mkdir -p $(SUBDIRS)
$(CC) $(CFLAGS) $(INC) -MMD -MF '$(patsubst src/%.c,deps/%.d,$<)' -o $@ -c $<
obj/%.o: src/%.cc
@echo Compiling $@
@mkdir -p $(SUBDIRS)
$(CXX) $(CXXFLAGS) $(INC) -MMD -MF '$(patsubst src/%.c,deps/%.d,$<)' -o $@ -c $<
${TARGETS}: %:bin/%
# Specific target rules:
bin/tengine: obj/main.o obj/tengine.o
$(LNK) $^ $(LIB) -o $@
bin/test2: obj/main.o obj/test2.o
$(LNK) $^ $(LIB) -o $@
clean:
rm -f *~ src/*~ gmon.out
rm -fr $(SUBDIRS)
-include deps/*.d
Some notes:
-
A key problem with the original was that the dependency were generated, but not used. This has been fixed using
-include deps/*.d
(at the end).原始的一个关键问题是生成了依赖,但没有使用。这已经使用-include deps / * .d(最后)修复。
-
Now that deps/*.d is used, the makefile doesn't need to have the
src/%.h
cases.现在使用deps / * .d,makefile不需要具有src /%.h的情况。
-
The original was also putting garbage into these files: in
$(patsubst src/%,obj/%,%(patsubst %.cc,%.o,$<))
the third%
should have been a$
.原来也把垃圾放到这些文件中:在$(patsubst src /%,obj /%,%(patsubst%。cc,%。o,$ <))中,第三个应该是$。
-
In the revised version, the dependencies are generated at the same time as the object, using
-MMD
. This is quicker, shortens the makefile, and adds some DRY.在修订版中,使用-MMD与对象同时生成依赖项。这样更快,缩短了makefile,并添加了一些DRY。
-
Shortened
INC
: why bother including the standard system include directories? And in fact gcc will apparently ignore your-I /usr/include -I /usr/local/include
anyway.缩短的INC:为什么还要包括标准系统包括目录呢?事实上,gcc显然会忽略你的-I / usr / include -I / usr / local / include。
-
Removed your two different definitions of
OBJS
. Not needed, and potentially confusing. Used$^
instead.删除了两个不同的OBJS定义。不需要,也可能令人困惑。使用$ ^代替。
-
It is always a good idea for
make clean
to completely undo everything make does, so you are left with what you started. But the sub-directories obj/ and deps/ were being created, and never deleted. Also, bin/ was pre-supposed to exist.make clean是一个好主意,可以完全撤消make所做的一切,所以你留下了你的开始。但是子目录obj /和deps /正在创建,并且从未被删除。此外,bin /被认为存在。
-
For the linking, added
$(LNK)
, withLNK=gcc -g -Wl,--warn-common
(but you may not want the warnings). AFAIK, all the other usual$(CFLAGS)
are ignored for links.对于链接,添加$(LNK),LNK = gcc -g -Wl, - warn-common(但您可能不需要警告)。 AFAIK,所有其他通常的$(CFLAGS)都被忽略了链接。
-
Removed comments, which were (mostly) distracting.
删除了评论,这些评论(主要)分散了注意力。
-
Repeated twice
make;make
now givesmake: Nothing to be done for ...
.重复两次制作;制作现在制作:没有什么可做的....
See also gcc dependency generation for a different output directory.
另请参阅不同输出目录的gcc依赖关系生成。
#3
-1
See this and that answers for examples about Makefile
. Also run make -p
to understand the builtin rules inside GNU make, so use $(LINK.cc)
for e.g. your bin/tengine
target.
有关Makefile的示例,请参阅此答案和答案。还要运行make -p来理解GNU make中的内置规则,所以使用$(LINK.cc)来实现例如你的bin / tengine目标。
For complex builds, consider upgrading to GNU make 4.0 and use its Guile ability.
对于复杂的构建,请考虑升级到GNU make 4.0并使用其Guile功能。
You may want to generate automatically dependencies. Read automatic prerequisites and about autodependencies; read also about GCC preprocessor options like -M
or -MD
etc etc ....
您可能希望自动生成依赖项。阅读自动先决条件和自动相关性;另请阅读GCC预处理器选项,如-M或-MD等等....