【问题标题】:makefile fails when creating object file for inner directory为内部目录创建目标文件时makefile失败
【发布时间】:2020-05-10 11:59:25
【问题描述】:

在当前目录中,我有以下文件:

election.c election.h extended_map.c extended_map.h main.c test_utilities.c utilities.c utilities.h

另外,我在当前文件夹中有一个名为 mtm_map 的内部文件夹,其中包括 map.c map.h

我创建了一个运行良好的makefile:

make main.o
make extended_map.o
make election.o
make utilities.o
make clean

但运行时失败:

-bash-4.2$ make map.o
cc    -c -o map.o map.c
map.c: In function ‘getIndexOfKey’:
map.c:36:5: error: ‘for’ loop initial declarations are only allowed in C99 mode
     for (int i = 0; i < map->size; i++)
     ^
map.c:36:5: note: use option -std=c99 or -std=gnu99 to compile your code
map.c: In function ‘initializeElements’:
map.c:59:5: error: ‘for’ loop initial declarations are only allowed in C99 mode
     for (int i=initial_index;i<last_index;i++)
     ^
map.c: In function ‘mapCopy’:
map.c:165:5: error: ‘for’ loop initial declarations are only allowed in C99 mode
     for (int i = 0; i < map->size; i++)
     ^
map.c: In function ‘mapGet’:
map.c:239:5: error: ‘for’ loop initial declarations are only allowed in C99 mode
     for (int i = 0; i < map->size; i++)
     ^
make: *** [map.o] Error 1

制作文件:

CC = gcc
OBJS = main.o ./mtm_map/map.o extended_map.o election.o utilities.o
EXEC = election
DEBUG_FLAG = -DNDEBUG
COMP_FLAG = -std=c99 -Wall -pedantic-errors -Werror
$(EXEC) : $(OBJS)
    $(CC) $(DEBUG_FLAG) $(OBJS) -o $@
main.o: main.c ./mtm_map/map.h election.h test_utilities.h
    $(CC) -c $(DEBUG_FLAG) $(COMP_FLAG) $*.c
map.o: ./mtm_map/map.c ./mtm_map/map.h utilities.h
    $(CC) -c $(DEBUG_FLAG) $(COMP_FLAG) $*.c
extended_map.o: extended_map.c extended_map.h ./mtm_map/map.h utilities.h
    $(CC) -c $(DEBUG_FLAG) $(COMP_FLAG) $*.c
election.o: election.c election.h ./mtm_map/map.h extended_map.h utilities.h
    $(CC) -c $(DEBUG_FLAG) $(COMP_FLAG) $*.c
utilities.o: utilities.c utilities.h
    $(CC) -c $(DEBUG_FLAG) $(COMP_FLAG) $*.c
clean:
    rm -f $(OBJS) $(EXEC)

关于如何解决这个问题的任何建议?请注意,我希望在当前目录中创建 map.o(而不是在 mtm_map 中)

【问题讨论】:

  • 请阅读编译器消息。这是一个编译问题,而不是一个make错误。您的代码中有几个语法错误,这些消息很好地解释了map.c 文件中的问题(第 36 行)
  • @LuisColorado 你读得不够仔细。问题不在于代码,问题在于编译行:它缺少所有编译器标志。特别是,它缺少 -c99 编译器标志,该标志告诉编译器在编译代码时使用 ISO C99 标准。缺少编译器标志的原因是make 使用其内置规则来创建目标文件,而不是生成文件中的规则。唯一可能的原因是,如果在运行 make 之前 OP 是 cd'd 到 mtm_map 子目录中。
  • @AnttiHaapala make 将同时读取Makefilemakefile,因此名称的大小写不是问题。请参阅我的其他评论和我的回答。
  • @MadScientist,我已经仔细阅读了,我已经回答了这个问题。正如您所说,问题确实在makefile中,但我已经写了一个答案,我专注于那里的问题。 OP询问了makefile,但随后显示了一个简单文件的编译,该文件根本不使用COMP_FLAG,所以他可能错误地命名了Makefile,或者他在不同的目录中。他正在使用默认规则将 map.c 编译成 map.o,他们使用 CFLAGS,而不是 COMP_FLAG
  • 您说您的代码中有几个语法错误。这不是真的。代码很好……它只是按照 C99 标准编写的。我已经在回答中解释了(可能)为什么会发生这种情况(从mtm_map 目录中运行make)。

标签: c linux gcc makefile


【解决方案1】:

您显示的错误不可能来自运行您提供的 makefile。

当您运行make map.o 时,您是从上层目录运行它,还是从mtm_map 目录运行它?如果是后者就可以解释了。

这里有很多问题。首先,如果您确实希望map.o 文件存在于顶级目录中,那么您的OBJS 设置是错误的;这个:

OBJS = main.o ./mtm_map/map.o extended_map.o election.o utilities.o
              ^^^^^^^^^^

应该是:

OBJS = main.o map.o extended_map.o election.o utilities.o

其次,您应该始终在规则中使用-o $@(我相信在过去几天您在 SO 上提出的类似问题中至少已经提到过两次)。

最后,当您在规则中引用源文件时,您应该使用$&lt; 而不是$*.c;前者扩展到第一个先决条件,包括其完整路径。后者中的$* 仅扩展为不包含路径的词干。

所以你的makefile应该是这样的:

CC = gcc
OBJS = main.o map.o extended_map.o election.o utilities.o
EXEC = election
DEBUG_FLAG = -DNDEBUG
COMP_FLAG = -std=c99 -Wall -pedantic-errors -Werror
$(EXEC) : $(OBJS)
        $(CC) $(DEBUG_FLAG) $(OBJS) -o $@
main.o: main.c ./mtm_map/map.h election.h test_utilities.h
        $(CC) -c $(DEBUG_FLAG) $(COMP_FLAG) -o $@ $<
map.o: ./mtm_map/map.c ./mtm_map/map.h utilities.h
        $(CC) -c $(DEBUG_FLAG) $(COMP_FLAG) -o $@ $<
extended_map.o: extended_map.c extended_map.h ./mtm_map/map.h utilities.h
        $(CC) -c $(DEBUG_FLAG) $(COMP_FLAG) -o $@ $<
election.o: election.c election.h ./mtm_map/map.h extended_map.h utilities.h
        $(CC) -c $(DEBUG_FLAG) $(COMP_FLAG) -o $@ $<
utilities.o: utilities.c utilities.h
        $(CC) -c $(DEBUG_FLAG) $(COMP_FLAG) -o $@ $<
clean:
        rm -f $(OBJS) $(EXEC)

【讨论】:

  • 整个问题是 $*.c 的原因
  • 不... $&lt; 仅用于自动规则,而不是在带有命令的显式规则中。他已经包含了源代码,所以没有选择自动编译规则。他必须使用$*.c,但请看我的回答。最好不要将CFLAGS 变量重命名为某个变量,因为他遇到了编译错误,-std=c99 应该避免这种情况。发布的./mtm_map/map.o 的设置是正确的。如果您将其包含在规则中,则 Make 应使用完整路径。
  • @LuisColorado 你不正确。在 OP 正在使用的 GNU make 中,$&lt; 对每个规则甚至是显式规则都有很好的定义。使用 GNU make 时,上面的 makefile 是 100% 正确的(尽管它可以大大简化——这是 OPs 关于同一主题的第三个问题,所以我想让它为他们工作)。如果您想编写一个严格符合 POSIX 的 make,那么您不能在配方中使用 either $&lt;$*,因为两者都仅针对 POSIX 中的后缀规则定义。 makefile 必须在配方中明确写出源文件。
【解决方案2】:

您的 Make 没有正确使用您在其中定义的 $(COMP_FLAG)

通常有一个CFLAGS 变量可以使用隐式规则来编译源文件,所以我将重写您的Makefile 以消除您包含在其中的大量冗余代码:

# I use the ?= operator, so you can redefine the compiler with make CC=clang ...
CC       ?= gcc 
EXEC      = election
TOCLEAN   = $(EXEC)

# NDEBUG is a compilation option, not a linking one.  The purpose of MY_CFLAGS is
# to allow you to define extra CFLAGS to be used on source code compilation.
CFLAGS    = -std=c99 -Wall -pedantic-errors -Werror -DNDEBUG $(MY_CFLAGS)
 
OBJS      = main.o mtm_map/map.o extended_map.o election.o utilities.o
# you can add files to clean in a more complex makefile
TOCLEAN  += $(OBJS)

$(EXEC): $(OBJS)
    $(CC) $(LDFLAGS) -o $@ $(OBJS)
clean:
    rm -f $(TOCLEAN)

# Extra dependencies (the dependency a.o : a.c is automatic)
main.o: mtm_map/map.h election.h utilities.h
mtm_map/map.o: mtm_map/map.h utilities.h
extended_map.o: extended_map.h mtm_map/map.h utilities.h
election.o: election.h mtm_map/map.h extended_map.h utilities.h
utilities.o: utilities.h

这应该可以正确构建您的项目。

注意

如果您决定某些源文件必须驻留在您拥有 Makefile 的目录之外的其他目录中,那么您必须考虑是否要将目标文件放在您的目录中或源文件所在的目录中。我遵循了我认为你想要的(在 this 目录中构建所有源文件可能会导致名称冲突,因为不同目录中的两个文件可以具有相同的名称)但是你必须使用对象的路径也(正如我在这里使用的那样)

还有另一种选择,是创建一个构建目录,因此所有文件都构建在副本或源中使用的层次结构中。但这也有其他一些缺点,因为您必须重写自动规则,以便在尝试将文件放入之前重建目录结构。

【讨论】:

  • OP 特别希望 map.o 位于当前目录(以及所有其他目标文件)中,而不是子目录中,因此此 makefile 与请求的行为不匹配。
  • 请注意:您不必使用?= 来允许在命令行上分配变量。运行make CC=gcc 将覆盖makefile 中的CFLAGS,即使它被分配了=:=。命令行设置总是覆盖生成文件中的设置。不过,使用?= 将允许环境中的CC=gcc 赋值覆盖makefile(默认情况下,makefile 变量优先于环境变量)。
  • 我不用,但是我用它来让make命令覆盖编译器。当然,如果您覆盖编译器,您可能还需要覆盖选项。这不是真的,但这只是建议。答案中提供的Makefile 已经过测试并且可以工作。如果你使用CC=gcc,那么你不能从命令行覆盖编译器。
  • OP 没有说要在其他地方使用 map.o。他展示了他所拥有的东西,但他在make 调用上命名map.o,然后他使用map.o 作为目标,而在依赖项中,他清楚地声明map.c 在不同的目录中。啊,他正在调用make map.o,很可能他正在尝试不在基目录中执行make,而是在mtm_map子目录中执行,其中mtm_map子目录中没有makefile,这就是他不执行的原因'根本不使用Makefile(只是默认规则,不使用COMP_FLAG
  • 你错了。在 make 命令行上分配一个变量,如 make CC=gcc,将覆盖 makefile 中类似 CC = cc 的分配。尝试一下。有关 make 变量赋值的优先级的更多信息,请参阅:gnu.org/software/make/manual/html_node/Overriding.html
猜你喜欢
  • 1970-01-01
  • 2021-05-19
  • 2016-04-09
  • 2011-06-07
  • 1970-01-01
  • 2018-06-06
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多