【问题标题】:Set up my makefile to compile C with just "make"设置我的 makefile 以仅使用“make”编译 C
【发布时间】:2019-06-04 18:43:17
【问题描述】:

我正在上 Zed Shaw 的 Learn C The Hard Way 课程,在第 2 课中,我发现在视频和书中,作者只使用 make ex1 编译他的 C,而我需要运行 @987654322 @。这是我的 Makefile,似乎第一部分应该使 make 命令能够编译,但是“make”命令不能编译它。

CFLAGs=-Wall -g

clean:
    rm -f ex1.exe

all:
    gcc -Wall -g ex1.c -o ex1.exe




【问题讨论】:

  • CFLAGs,带有小写的s?
  • @JosephQuinsey,CFLAG[sS](任何字母大小写)的原因是什么,如果它没有在 Makefile 的其余部分中使用......该 Makefile 中没有依赖信息,所以没有自动规则将被选中,并且不会使用CFLAGS 变量。

标签: c makefile cmder


【解决方案1】:

默认目标是第一个目标,所以切换它们的顺序,使all成为默认目标。

the documentation on goals有更多细节:

默认情况下,目标是 makefile 中的第一个目标(不包括以句点开头的目标)。因此,通常编写 makefile,以便第一个目标是编译它们描述的整个程序或程序。如果 makefile 中的第一个规则有多个目标,则只有规则中的第一个目标成为默认目标,而不是整个列表。您可以使用 .DEFAULT_GOAL 变量从您的 makefile 中管理默认目标的选择

【讨论】:

  • 另外,ex1.exe 应该是all 的先决条件(all: ex1.exe 而不仅仅是all:),否则make 无法检测它是否是最新的。此外,还可以选择添加 .PHONY: all 以避免与字面上称为 all 的文件混淆。
  • @tadman 这不是我要找的,我的意思是只使用makemake all 仅适用于 ex1,我只想使用 make。
  • 我的错!这个答案大部分都有效!谢谢!
  • @anatolyg,不... ex1.exe 不需要成为任何东西的先决条件,因为它是all 目标,只需要在命令行中构建ex1.exeMakefile 的编写方式不是我的首选……但只要说 make all 就可以执行。没有关联信息。
【解决方案2】:

您的Makefile 没有包含在规则 形式中的依赖信息。规则是从左列(第 0 列)开始的行,在目标(要构建的对象)和必要条件(提供给规则的对象)之间有 : 分隔符

Make 会链接规则,因此在其先决条件具备之前无法构建目标,因此一个好的起点是:

ex1.exe: ex1.o

这意味着ex1.exeMakefile 中的第一个目标)依赖于ex1.o(编译后的对象)......但是如何。您在下面添加命令,但在命令行前面插入一个制表符:

[tab char]gcc -Wall -g ex1.o -o ex1.exe

首先,看看该命令如何将ex1.o 作为gcc 的输入并生成(通过选项-o)文件ex1.exe

所有这一切的意思是你总是缺少ex1.exe,或者它恰好在使用该命令的先决条件(ex1.o)之前被修改(从文件中的修改日期开始)。

现在,我们如何编译目标文件? (在您的 Makefile 中直接制作)

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

这一行需要更多解释(虽然如果你不使用它,它是由make程序自动提供的)它使用替换变量:$(CC)扩展为默认的C编译器(cc通常,但你可以改变它)。 $(CFLAGS) 是您在 Makefile 之上定义的变量,并扩展为通常用于编译程序的编译器选项。 $@ 由目标文件(在本例中为 ex1.o 文件)扩展,$&lt; 扩展至规则右侧部分的左侧先决条件。这个把C文件编译成目标文件很常见的规则是make自动为你生成的,更多的可以在make高级使用中创建(这里就不多说了,因为量大需要的空间)只是说它可以这样写:

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

这意味着:任何扩展名为 .o 的文件都可以通过使用下面的下一个命令行从具有相同名称但扩展名为 .c 的文件创建。这会自动依赖具有相同名称但扩展名为 .c 的文件中的每个 .o 文件,并预加载在 make 中。

所以,您最简单的Makefile 可能是:

CFLAGS=-Wall -g
src=ex1.c
ex1.exe: $(src)
    $(CC) $(CFLAGS) $(LDFLAGS) -o $@ $(src)

如您所见,我使用变量src 来描述用于编译我的程序的C 源文件。 当您修改了任何或先决条件(现在只有一个,ex1.c 但可能更多)并且我在同一个编译中进行编译和链接时,才会发出依赖项,我需要传递编译标志和链接标志(未使用,您可以在此处删除对$(LDFLAGS) 的引用)确实可以这样写:

ex1.exe: ex1.c
     cc -g -Wall -o ex1.exe ex1.c
clean:
     rm -f ex1.exe

所以,默认操作是创建ex1.exe,它依赖于ex1.c(所以只有在修改ex1.c时,才会重新编译ex1.exe。要编译它,只需:

make ex1.exe

make

这将使用Makefile 的默认第一条规则。

clean 是一个假目标(没有要生成的名为 clean 的文件)所以当你使用时

make clean

它的相关命令总是被执行。它使make 删除您的目标文件(因为它删除了所有make 生成的文件),因此下次运行make 时,它将通过执行必要的编译来重新创建所有文件。

常见用途

对于简单的程序,比方说,几个源.c文件和一些.h文件,每个文件都单独编译(编译中的-c选项)和链接,我通常使用这种方法(定义目标文件每个目标程序都需要不同的变量)

# makefile for programs foo and bar.

targets = foo bar
TOCLEAN = $(TARGETS)  # this variable stores what should be erased on clean target.  Here we store the programs to erase.

foo_objs = a.o b.o c.o
TOCLEAN += $(foo_objs)  # here, we add the objects of foo

foo: $(foo_objs)
    $(CC) $(LDFLAGS) -o $@ $(foo_objs)

bar_objs = d.o e.o f.o
bar_libs = -lm -lintl -lX
TOCLEAN += $(bar_objs)  # here we add the objects of bar

bar: $(bar_objs)
    $(CC) $(LDFLAGS) -o $@ $(bar_objs) $(bar_libs)

clean:
    rm -f $(TOCLEAN)

a.o b.o c.o: a.h b.h c.h globals.h
b.o c.o d.o e.o f.o: my_defs.h

(如您所见,对头文件的依赖关系到编译后的对象 --- 不是 .c 源文件...源文件构建依赖关系,但目标文件是必须在其中重新创建的如果包含文件被修改,而不是包含.c文件)

【讨论】:

  • 您使用$(CC) $(LDFLAGS) 而不是标准的$(LINK.o) 的原因是什么? (例如,这可以防止特定于目标的 LINK.o = LINK.cc 用于链接 C++ 对象)。同样,使用$(RM) 而不是rm -f 是标准做法,尽管很少需要覆盖它。
  • 我也会使用特定于目标的bar: LDLIBS += -lm -lintl -lX,但这也许只是个人喜好?
  • 好吧,调用编译器进行链接阶段是有充分理由的。它将包括支持该语言所需的语言运行时模块。如果您直接调用链接器,则必须自己提供这些文件。这同样适用于标准 C 库。
  • 使用LDLIBS 全局变量make 不允许您为每个可执行文件指定不同的库。您可以将其用于一般项目库,然后为每个可执行文件拥有一组特定于程序的库。这不像编译标志那么重要,因为默认情况下make 中通常不包含用于链接的自动规则,但它在编译时很重要。如您所见,两个程序使用不同的对象和库。
  • 确实;这就是为什么我写了一个 target-specific LDLIBS.
【解决方案3】:
CFLAGS = -Wall -g

all: ex1

clean:
    $(RM) ex1

.PHONY: all clean

在开头修复了我的 CFLAGS 定义,并在末尾为 allclean 添加了 .PHONY,因此 make 知道不要为这些创建文件。

【讨论】:

  • 请,如果您使用ex1 作为all 的先决条件,那么请使用相同的ex1 作为rm -f 的参数
【解决方案4】:

对于一个非常简单的 makefile,我这样做:

qsorttest: qsorttest.c 
     gcc -Wall -g qsorttest.c -o qsorttest -lm

clean:
     rm -f qsorttest

“qsorttest.c”是我的源文件的名称,我创建的可执行文件是“qsorttest” 确保“程序名称:源文件”和“干净:”下的行被制表符插入,而不是用空格键移动。我用头撞墙了一会儿,直到我用谷歌搜索了我的出路。

我将它作为“Makefile”保存在与程序的其他文件相同的目录中,并且每次都可以使用。我只是根据需要更改源文件和程序名称,并在需要时添加用于链接库的额外参数。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-02-14
    • 2021-11-23
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多