我该如何改进这个 Makefile?
我对创建 Makefile 不太了解,但我一直在阅读 make 手册 我已经取得了一些进展。 我的 Makefile 可以工作并执行我想要的操作。
我的情况通常涉及 1 到 3 个不同的程序需要编译并通过网络表单发送给我的助教进行标记等。 每个应用程序的结构是“prog.c”、“prog_lib.h”和“prog_lib.c”。 过去,我一直为每个程序创建单独的目录,并为每个目录创建单独的 Makefile 来构建其中包含的程序。 然后我将每个文件夹压缩并单独提交。
最近,助教一直要求将所有源文件放在一个目录中,并在一个包含要构建的各种目标的 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)
I don't know much about creating Makefiles, but I've been reading the make manual and I have made some progress. My Makefile works and does what I want.
My situation usually involves between 1 and 3 different program needed to be compiled and sent to my TA for marking and such via a webform. The structure of each application is 'prog.c', 'prog_lib.h', and 'prog_lib.c'. In the past, I have been creating separate directories for each program and creating separate Makefiles for each directory to build the program contained within. I then tar each folder and submit them separately.
Recently, the TAs have been asking for all source files to be in one directory and one Makefile with the various targets to be built so their marking applications can work without any human intervention.
I was wondering how someone more experienced would improve this Makefile and how my situation in general is usually solved? I would like to reduce the amount of typing I need to do when I move on to my next assignment and have to update several places.
Here is my 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 $@ lt;
.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)
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(4)
您确实不需要
$(CC) $(CFLAGS) $(DEBUG) $(LDFLAGS) $(FREQ_OBJECTS) -o $@
行。 make 已经知道如何构建二进制文件。如果您的文件名对于不同的二进制文件(binary.c 和 binary_lib.c)是不变的,您还可以为此创建一个通用规则:
编辑:它的工作原理如下:
You really don't need the
$(CC) $(CFLAGS) $(DEBUG) $(LDFLAGS) $(FREQ_OBJECTS) -o $@
lines. make already knows how to build binaries.If your filenames are constant for different binaries (binary.c and binary_lib.c), you can also create a general rule for that:
EDIT: Here's how it works:
将“all”目标设置为第一个目标,除非您确实确定用户必须在“make”之后键入一些内容才能构建项目。 “信息”目标很好,但很传统。
(我确实有一个 makefile,其中默认目标不是 all - 在一个包含 100 多个命令的源代码的目录中。我不希望“make all”成为默认目标;我希望只构建我想要的一两个有一个“all”。但通常情况下,默认值应该是“all”。)
此外,“$(FREQ_OUT)”和“$(DECODE_OUT)”都不是 PHONY 目标; 它们是真正的程序,不是吗? “all”、“info”、“dist”、“clean”、“realclean”等目标 - 这些都是假的。 但你构建的程序却不是。
Make the 'all' target the first one, unless you are really sure your users should have to type something after 'make' to get the project to build. The 'info' target is nice but aconventional.
(I do have one makefile where the default target is not all - in a directory with source code for 100+ commands. I do not want 'make all' to be the default; I expect to build just the one or two that I want to build. There is an 'all'. But that is very unusual. Normally, the default should be 'all'.)
Also, neither '$(FREQ_OUT)' nor '$(DECODE_OUT)' is a PHONY target; they are real programs, aren't they? The 'all', 'info', 'dist', 'clean', 'realclean' etc targets - those are phony. But the programs you build are not.
根据我的经验,您不应该需要其中的
.o
目标,这是隐式的。此外,隐式版本通常包含
$(CPPFLAGS)
的值,您应该在其中放置任何-I
path 或-D 您可能需要的宏选项。
我还将
$(DEBUG)
包含在$(CFLAGS)
中,而不是在任何构建目标中显式列出它。In my experience, you shouldn't need the
.o
target in there, that's implicit.Also, the implicit version normally includes the value of
$(CPPFLAGS)
, which is where you should put any-I
path or-D
macro options that you might require.I'd also include the
$(DEBUG)
in$(CFLAGS)
, rather than list it explicitly in any of the build targets.例子:
Example: