我对创建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)
答案 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 :(得分: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)