【问题标题】:Makefile tries to compile one of it's own rules as if it were a fileMakefile 尝试编译它自己的规则之一,就好像它是一个文件一样
【发布时间】:2021-12-27 21:47:21
【问题描述】:

我有一个简单的 makefile 来编译一些使用 OpenGL 库的 C 代码,但是,它似乎将它自己的规则之一解释为要编译的文件。简化版如下:

CC = gcc
COMPILEFLAGS = -Wall -lglut -lGL -lGLU -lm -c
LINKFLAGS = -lglut -lGL -lGLU -lm

castle: castle_link

run_castle:
    ./castle $(ARGS)

castle_link: castle_compile
    ${CC} -o castle castle.o ${LINKFLAGS}

castle_compile:
    ${CC} ${COMPILEFLAGS} castle.c

clean:
    rm *.o castle

执行make -n castle 会产生以下结果:

gcc -Wall -lglut -lGL -lGLU -lm -c castle.c
gcc -o castle castle.o -lglut -lGL -lGLU -lm
gcc   castle.o castle_link   -o castle 

我无法理解为什么会发生这种情况。在这个相同的文件上,还有另一组完全遵循相同模式的规则,只是更改文件名,可以完美运行。 (这只发生在执行规则make castle时,手动执行castle_compile然后castle_link不会导致这种情况。

非常感谢任何帮助。

【问题讨论】:

  • 相关问题:COMPILEFLAGS 中的-lXYZ 选项由于-c 选项而未使用,应将其删除。
  • 无法重现,我只看到前两行输出。
  • 使用make -d -f makefile.bad castle > output.bad 运行输出。然后用另一个你想要的makefile,也运行它make -d -f makefile.good program > output.good。然后比较操作——这将是乏味的。然而,有一个关键的区别。我们无法为您发现它,因为我们没有其他 makefile 可供比较。
  • IMO,最好多利用内置规则。设置CFLAGS = -WallLDLIBS = -lglut -lGL -lGLU -lm。写castle: castle.o,后面没有命令;完全删除castle_linkcastle_compile,然后代码可以正常工作——它将castle.c 编译为castle.o,然后将其与库链接以生成可执行文件。然而,这并不能解释为什么你会看到你所看到的。
  • 请注意,如果您只编写 castle: 而没有 castle.o 作为依赖项,则会执行一个命令:gcc -Wall castle.c -lglut -lGL -lGLU -lm -o castle,如果您没有特定用途,这可能很好目标文件。

标签: c makefile


【解决方案1】:

为了解释发生了什么,你有一个没有配方的规则:

castle: castle_link

这意味着make 将尝试为它找到一个隐式规则。来自the manual

如果目标的显式规则都没有配方,则搜索适用的隐式规则以找到一个

在该页面的前面,它说目标的先决条件是组合的:

一个文件可以是多个规则的目标。所有规则中提到的所有先决条件都合并到目标的先决条件列表中。

匹配的隐式规则将是:

%: %.o
    $(LINK.o) $^ $(LOADLIBES) $(LDLIBS) -o $@

如果.o 文件存在或:

%: %.c
    $(LINK.c) $^ $(LOADLIBES) $(LDLIBS) -o $@

如果没有。 (make -p 将打印隐式规则的定义)。

所以目标castle 的先决条件是:

  • 无论是 castle.o castle_link
  • 或 castle.c castle_link

并且来自隐式规则的配方中的$^变量会将它们放在cc命令中执行。让我们看看这个简化的 makefile:

castle: castle_link

castle_link: castle_compile
    $(CC) -o castle castle.o -lm

castle_compile:
    $(CC) -Wall -c castle.c

如果我们在一个干净的目录上执行它(即没有castle.o):

]$ make --debug=m castle
...
    Must remake target 'castle_compile'.
cc -Wall -c castle.c                                # This is our recipe, notice -Wall
    Successfully remade target file 'castle_compile'.
  Must remake target 'castle_link'.
cc -o castle castle.o -lm                           # This is our reicpe, notice -lm
  Successfully remade target file 'castle_link'.
Must remake target 'castle'.
cc     castle.c castle_link   -o castle             # This is implicit rule with castle.c
cc: error: castle_link: No such file or directory

现在castle.o已经创建好了,我们再次执行它:

]$ make --debug=m castle
...
    Must remake target 'castle_compile'.
cc -Wall -c castle.c                                # This is our recipe, notice -Wall
    Successfully remade target file 'castle_compile'.
  Must remake target 'castle_link'.
cc -o castle castle.o -lm                           # This is our recipe, notice -lm
  Successfully remade target file 'castle_link'.
 Prerequisite 'castle_link' of target 'castle' does not exist.
Must remake target 'castle'.
cc   castle.o castle_link   -o castle               # This is implicit rule with castle.o
cc: error: castle_link: No such file or directory

如您所见,第一次调用是“cc castle.c castle_link -o castle”,第二次调用是“cc castle.o castle_link -o castle”。

不要问我为什么只有第二个调用打印“目标 'castle' 的先决条件 'castle_link' 不存在。” :-)

【讨论】:

  • 好吧,我从没想过这样的事情是根本原因,非常感谢您的回答。
猜你喜欢
  • 2019-10-19
  • 2017-09-22
  • 1970-01-01
  • 1970-01-01
  • 2022-11-29
  • 2021-06-05
  • 1970-01-01
  • 2016-03-16
  • 2021-03-27
相关资源
最近更新 更多