我怎么能改进这个Makefile?

时间:2009-03-12 22:49:38

标签: c makefile

我对创建Makefile知之甚少,但我一直在阅读make manual,我已经取得了一些进展。我的Makefile可以工作并完成我想要的工作。

我的情况通常涉及1至3个不同的程序需要编译并发送到我的TA进行标记,并通过网络表单。每个应用程序的结构是'prog.c',​​'prog_lib.h'和'prog_lib.c'。过去,我一直在为每个程序创建单独的目录,并为每个目录创建单独的Makefile以构建其中包含的程序。我然后tar每个文件夹并单独提交。

最近,TA一直要求将所有源文件放在一个目录中,并且要求一个Makefile包含要构建的各种目标,这样它们的标记应用程序就可以在没有任何人为干预的情况下工作。

我想知道更有经验的人会如何改进这个Makefile以及我的情况通常如何解决?我希望减少进入下一个作业时需要做的输入量,并且必须更新几个地方。

这是我的Makefile:

ASSIGNMENT = 3
TARNAME = Assignment$(ASSIGNMENT).tar.bz2

CC = gcc
CFLAGS = -O2 -Wall -ansi -pedantic -W # I like warnings
LDFLAGS = -lm
DEBUG = -g # to resolve symbols in GDB and valgrind

FREQ_OUT = frequency_table
FREQ_SOURCES = frequency_table.c frequency_table_lib.c
FREQ_OBJECTS = frequency_table.o frequency_table_lib.o

DECODE_OUT = decode
DECODE_SOURCES = decode.c decode_lib.c
DECODE_OBJECTS = decode.o decode_lib.o

SOURCES = $(FREQ_SOURCES) $(DECODE_SOURCES)
OBJECTS = $(FREQ_OBJECTS) $(DECODE_OBJECTS)
OUT = $(FREQ_OUT) $(DECODE_OUT)

.PHONY: info
info:
    @echo -e "make info\n" \
            "\tmake all \t\t\tMake all targets\n" \
            "\tmake frequency_table \t\tMakes frequency table\n" \
            "\tmake decode \t\t\tMakes decode\n" \
            "\tmake dist \t\t\tMakes tar archive of sources and Makefile\n" \
            "\tmake clean \t\t\tRemoves all the object files and executables\n" \
            "\tmake distclean \t\t\tPerforms clean and removes tar archive"

.PHONY: all
all:    $(OUT)

$(FREQ_OUT):    $(FREQ_OBJECTS)
    $(CC) $(CFLAGS) $(DEBUG) $(LDFLAGS) $(FREQ_OBJECTS) -o $@

$(DECODE_OUT):  $(DECODE_OBJECTS)
    $(CC) $(CFLAGS) $(DEBUG) $(LDFLAGS) $(DECODE_OBJECTS) -o $@

.o:
    $(CC) -c $(CFLAGS) -o $@ $<

.PHONY: dist
dist: $(SOURCES)
    @echo "Creating tar archive. See $(TARNAME)"
    tar cvjf $(TARNAME) $(SOURCES) $(wildcard *_lib.h) Makefile

.PHONY: clean
clean:
    rm -f $(OUT) $(OBJECTS)

.PHONY: distclean
distclean: clean
    rm -f $(TARNAME)

4 个答案:

答案 0 :(得分:3)

你真的不需要$(CC) $(CFLAGS) $(DEBUG) $(LDFLAGS) $(FREQ_OBJECTS) -o $@行。 make已经知道如何构建二进制文件。

如果您的文件名对于不同的二进制文件(binary.c和binary_lib.c)是常量,您还可以为其创建一般规则:

FOO := $(shell ls *_lib.c)
BIN = $(FOO:%_lib.c=%)

$(BIN) : % : %.o %_lib.o

编辑:以下是它的工作原理:

  1. FOO是以_lib.c
  2. 结尾的所有文件的列表
  3. BIN是相同的列表,删除了“_lib.c”后缀,因此它是您的二进制文件列表
  4. 最后一行是你的制定规则。规则规定$(BIN)中的每个foo取决于foo.o和foo_lib.o

答案 1 :(得分:3)

将'all'目标设为第一个,除非您确定您的用户必须在'make'之后键入内容才能构建项目。 “信息”目标很好,但很常见。

(我确实有一个makefile,默认目标不是全部 - 在一个包含100多个命令的源代码的目录中。我不希望'make all'成为默认目标;我希望只构建一个或两个我想要建立。有一个'全部'。但这是非常不寻常的。通常,默认值应该是'all'。)

此外,'$(FREQ_OUT)'和'$(DECODE_OUT)'都不是PHONY目标;他们是真正的节目,不是吗? 'all','info','dist','clean','realclean'等目标 - 那些都是虚假的。但是你建立的程序不是。

答案 2 :(得分:2)

根据我的经验,你不应该在那里需要.o目标,这是隐含的。

此外,隐式版本通常包含$(CPPFLAGS)的值,您应该在其中放置任何-I 路径-D 宏< / em>您可能需要的选项。

我还会在$(DEBUG)中加入$(CFLAGS),而不是在任何构建目标中明确列出。

答案 3 :(得分:1)

示例:

# CC, CFLAGS, etc. go here

# Object variables go here
MYPROG_OBJECTS = main.o someother.o

# all, info, etc. targets go here

# first actual target:
myprog: $(MYPROG_OBJECTS)
    <Do the linking stuff>

# This will take care of the objects, sources are placed in src directory:
%.o: src/%.c
   <The usual compilation commands>

# Automatic dependency magic:
%.d: src/%.c
   $(CC) -MM -o$@ $<

-include (MYPROG_OBJECTS:%.o=%.d)