我怎样才能使我的Makefiles更好? [英] How can I make my Makefiles better?
问题描述
我试图学习项目的最佳实践makefile。
请检查下面的Makefile文件,并提出改进以加强它。
目录布局:
root dir
- Makefile
deps
--- deps
bin
---二进制
objs
---全部.o文件
包括
---全部.h文件
src
- - 所有.c .cc文件
makefile:
#
#通用makefile
#
全部:tengine test2
#
#包含用于编译的文件以及用于链接的库。
#
INC = -I / usr / include -I / usr / local / include -I / usr / include / hiredis
LIB = -lhiredis
#
#调试还是不调试?
#
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)
#创建依赖文件的规则
deps /%。d:src /%。cc
@echo生成$ @
@mkdir -p $(dir $ @)
$(CXX)$(CXXFLAGS)$(INC)-MM -MT'$(patsubst src /%,obj /% ,%(patsubst%.cc,%。o,$<))'$< > $ @
deps /%。d:src /%。c
@echo生成$ @
@mkdir -p $(dir $ @)
$( CXX)$(CXXFLAGS)$(INC)-MM -MT'$(patsubst src /%,obj /%,%(patsubst%.c,%。o,$<))'$< > $ @
#编译规则
#
#含源头和无c ++代码的C源
obj /%o: src /%。c src /%。h deps /%。d
@echo编译$ @
@mkdir -p $(dir $ @)
$(CC)$(CFLAGS) $(INC)-o $ @ -c $<
#带源头的C ++源代码。
obj /%。o:src /%。cc src /%。h deps /%。d
@echo编译$ @
@mkdir -p $(dir $ @)
$(CXX)$(CXXFLAGS)$(INC)-o $ @ -c $<
没有头文件但没有c ++代码的C源代码
obj /%。o:src /%。c deps /%。d
@echo编译$ @
@mkdir -p $(dir $ @)
$(CC)$(CFLAGS)$(INC)-o $ @ -c $<
#无标题的C ++源代码。
obj /%。o:src /%。cc deps /%。d
@echo编译$ @
@mkdir -p $(dir $ @)
$(CXX)$(CXXFLAGS)$(INC)-o $ @ -c $<
########################################## #####################
#
#TARGET:tengine
#
####### ################################################## ######
OBJS = obj / main.o obj / tengine.o
tengine:$(OBJS)
$(CXX) - 管道$(CXXFLAGS)-o bin / tengine $(OBJS)$(LIB)
######################### ######################################
#
#TARGET: test2
#
######################################## #######################
OBJS = obj / main.o obj / test2.o
测试2:$(OBJS)
$(CXX) - 管道$(CXXFLAGS)-o bin / test2 $(OBJS)$(LIB)
######## ################################################## #####
#
#清理
#
######################### ######################################
clean:
rm -f * bin / * obj / * deps / * src / *〜gmon.out
help:
@echo
@ echomake-builds tengine
@echomake test2 - builds test2
@ech omake all - builds tengine test2
@echomake clean - 删除以前的版本
下面是一个修改后的makefile的建议,在一个7年的Linux版本(RHEL 5)上稍微测试过:
#通用makefile
TARGETS = tengine test2
$ b全部:$ {TARGETS}
帮助:
@echo
@echomake-builds $ {TARGETS}
@echomake tengine - builds tengine
@echomake test2 - builds test2
@echomake clean - 删除以前的版本
@echomake help - 打印此帮助
#开关:
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)
#通用规则:
obj /%。o:src /%。c
@echo编译$ @
@mkdir -p $(SUBDIRS)
$(CC)$(CFLAGS)$(INC )-MMD -MF'$(patsubst src /%。c,deps /%。d,$<)'-o $ @ -c $<
obj /%。o:src /%。cc
@echo编译$ @
@mkdir -p $(SUBDIRS)
$(CXX)$( CXXFLAGS)$(INC)-MMD -MF'$(patsubst src /%。c,deps /%。d,$<)'-o $ @ -c $<
$ {TARGETS}:%:bin /%
#特定目标规则:
in / 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
一些注释:
-
原始文件的一个关键问题是生成了依赖关系,但没有使用 。已经使用
-include deps / *。d
(最后)修正了这个问题。 -
现在使用deps / *。d时,makefile不需要具有
src /%。h
个案。 -
原始文件也将垃圾放入这些文件中:
$(patsubst src /%,obj /%,%(patsubst%.cc,%。o,$<))
第三个%
应该是$
。 -
在修订版本中,使用
-MMD
与对象同时生成依赖关系。 缩短 -
删除了 两个
OBJS
的不同定义。不需要,可能会令人困惑。使用$ ^
代替。 -
对于
make干净的
完全地撤消所有的make,所以你留下了你开始的东西。但是子目录obj /和deps /正在被创建,并且从未被删除。
对于链接,添加
$(LNK)
,LNK = gcc -g -Wl, - warn-common
(但你可能不需要警告)。 AFAIK,所有其他通常的$(CFLAGS)
都会被链接忽略。 -
重复执行两次
make; make
现在给出make:没有事情要做...
。
-I / usr / include -I / usr / local / include
。 I've trying to learn the "best practice" makefile's for a project.
Please review my Makefile file below and suggest changes to enhance it.
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"
Here is a suggestion for a revised makefile, tested slightly on a 7-year-old version of 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).Now that deps/*.d is used, the makefile doesn't need to have the
src/%.h
cases.The original was also putting garbage into these files: in
$(patsubst src/%,obj/%,%(patsubst %.cc,%.o,$<))
the third%
should have been a$
.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.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.Removed your two different definitions of
OBJS
. Not needed, and potentially confusing. Used$^
instead.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.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.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.
这篇关于我怎样才能使我的Makefiles更好?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!