我该如何改进这个 Makefile?

发布于 2024-07-14 12:57:13 字数 2096 浏览 6 评论 0原文

我对创建 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 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

梦归所梦 2024-07-21 12:57:13

您确实不需要 $(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. BIN 是相同的列表,删除了“_lib.c”后缀,因此它是二进制文件的列表。
  3. 最后一行是您的 make 规则。 该规则规定 $(BIN) 中的每个 foo 都依赖于 foo.o 和 foo_lib.o

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:

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

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

EDIT: Here's how it works:

  1. FOO is the list of all files ending with _lib.c
  2. BIN is the same list, with the "_lib.c" suffixes removed, so it's the list of your binaries
  3. The last line is your make rule. The rule states each foo in $(BIN) depends on foo.o and foo_lib.o
无声静候 2024-07-21 12:57:13

将“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.

趁年轻赶紧闹 2024-07-21 12:57:13

根据我的经验,您不应该需要其中的 .o 目标,这是隐式的。

此外,隐式版本通常包含 $(CPPFLAGS) 的值,您应该在其中放置任何 -Ipath-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 -Ipath or -Dmacro options that you might require.

I'd also include the $(DEBUG) in $(CFLAGS), rather than list it explicitly in any of the build targets.

初熏 2024-07-21 12:57:13

例子:

# 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$@ 
lt;

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

Example:

# 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$@ 
lt;

-include (MYPROG_OBJECTS:%.o=%.d)
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文