首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >如何让Makefile变得更好?

如何让Makefile变得更好?
EN

Stack Overflow用户
提问于 2014-01-29 01:57:44
回答 3查看 335关注 0票数 1

我一直在尝试学习一个项目的makefile的“最佳实践”。

请查看我下面的Makefile文件,并建议对其进行改进。

dir布局:

代码语言:javascript
复制
root dir
---  Makefile
deps
---  deps
bin
---  binary
objs
---  all .o files
include
---  all .h files
src
---  all .c .cc files

makefile:

代码语言:javascript
复制
#
# 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"
EN

回答 3

Stack Overflow用户

发布于 2014-01-29 03:21:44

如果您希望其他人使用您的Makefile,请始终包含一个help目标,该目标打印出一条消息,详细说明从命令行调用的各种目标,以及可以合理设置以执行各种操作的各种环境变量……

票数 1
EN

Stack Overflow用户

发布于 2014-01-29 09:53:10

这里是一个修改过的makefile的建议,在一个7年前的Linux版本(RHEL 5)上进行了轻微的测试:

代码语言:javascript
复制
# 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

一些注意事项:

  • 原始版本的一个关键问题是生成了依赖项,但没有使用。这个问题已经用-include deps/*.d修复了(在最后)。
  • 既然使用了deps/*.d,makefile就不需要src/%.h case了。
  • 原来也把垃圾放进了这些文件中:在$(patsubst src/%,obj/%,%(patsubst %.cc,%.o,$<))中,第三个%应该是deps的修订版,依赖关系是使用-MMD与对象同时生成的。这更快,缩短了makefile,并添加了一些包含目录:为什么要麻烦包括标准系统INC目录?事实上,gcc显然会忽略你的-I /usr/include -I /usr/local/include,你对OBJS的两种不同的定义。不需要,并且可能会令人困惑。使用$^
  • make clean完全撤销所有make做的事情总是一个好主意,所以你只需要做你开始做的事情。但是子目录obj/和deps/正在创建,并且从未被删除。此外,bin/是预先假定存在的。
  • 用于链接,添加了$(LNK)LNK=gcc -g -Wl,--warn-common (但你可能不想要警告)。对于links.
  • Removed注释,所有其他常见的注释都会被忽略,这些注释(大多数)是distracting.
  • Repeated make: Nothing to be done for ....

$(CFLAGS) make;make现在给出的

另请参见gcc dependency generation for a different output directory

票数 1
EN

Stack Overflow用户

发布于 2014-01-29 14:33:52

有关Makefile的示例,请参阅thisthat答案。也可以运行make -p来理解GNU make中的内置规则,所以使用$(LINK.cc)来实现你的bin/tengine目标。

对于复杂的构建,请考虑升级到GNU make 4.0并使用其Guile功能。

您可能希望自动生成依赖项。阅读automatic prerequisites和关于autodependencies;也可以阅读关于GCC preprocessor options的文章,比如-M-MD等。

票数 -1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/21413195

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档