【问题标题】:How can I make my Makefiles better?我怎样才能使我的 Makefile 更好?
【发布时间】:2014-01-28 17:57:43
【问题描述】:

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

请查看下面我的 Makefile 文件并提出改进建议。

目录布局:

root dir
---  Makefile
deps
---  deps
bin
---  binary
objs
---  all .o files
include
---  all .h files
src
---  all .c .cc files

生成文件:

#
# 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"

【问题讨论】:

  • 你真的需要那么多章节标题吗?
  • 您可能需要将test2 部分中的tengine 更改为test2。我会删除 Makefile 中的很多 cmets,因为它们大多是噪音。您还应该在链接行中为g++ 和-pipe 使用宏。如果您的 makefile 要健壮,则应在对象之后列出库。您似乎也没有设置 CXXFLAGS 但您使用它。
  • 谢谢。我做了这些改变。我出于 SO 的目的添加了 cmets,通常我的 Makefile 中没有它们。 CXXFLAGS 在原帖中被注释掉了。

标签: linux gcc makefile g++


【解决方案1】:

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

【讨论】:

  • 我喜欢!将其添加到最后。
【解决方案2】:

以下是修改后的 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

一些注意事项:

  • 原始版本的一个关键问题是生成了依赖项,但没有使用。已使用-include deps/*.d(最后)修复了此问题。

  • 现在使用了 deps/*.d,makefile 不需要有 src/%.h 的情况。

  • 原版也将垃圾放入这些文件中:在$(patsubst src/%,obj/%,%(patsubst %.cc,%.o,$&lt;)) 中,第三个% 应该是$。

  • 在修订版中,依赖项与对象同时生成,使用-MMD。这更快,缩短了 makefile,并添加了一些 DRY。

  • 缩短INC:为什么还要包含标准系统包含目录?事实上,gcc 显然会忽略你的-I /usr/include -I /usr/local/include。

  • 删除了您对OBJS 的两个 不同定义。不需要,并且可能令人困惑。改用$^。

  • 让make clean 完全撤消 make 所做的一切总是一个好主意,这样你就可以开始做。但是子目录 obj/ 和 deps/ 正在被创建,并且从未被删除。此外,bin/ 是预先假定存在的。

  • 对于链接,添加了$(LNK) 和LNK=gcc -g -Wl,--warn-common(但您可能不想要警告)。 AFAIK,所有其他常见的$(CFLAGS) 都被链接忽略了。

  • 移除了(大部分)分散注意力的 cmets。

  • 重复两次make;make 现在给出make: Nothing to be done for ...。

另见gcc dependency generation for a different output directory。

【讨论】:

    【解决方案3】:

    有关Makefile 的示例,请参阅this 和that 答案。还可以运行make -p 以了解GNU make 中的内置规则,因此请使用$(LINK.cc),例如你的bin/tengine 目标。

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

    您可能希望自动生成依赖项。阅读automatic prerequisites 和关于autodependencies;还可以阅读有关GCC preprocessor options 的信息,例如-M 或-MD 等......

    【讨论】:

      猜你喜欢
      • 2013-06-04
      • 2013-08-29
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多