为啥我的 makefile 调用 gcc 虽然我设置了 CC=g++? [关闭]

Posted

技术标签:

【中文标题】为啥我的 makefile 调用 gcc 虽然我设置了 CC=g++? [关闭]【英文标题】:Why does my makefile call gcc although I set CC=g++? [closed]为什么我的 makefile 调用 gcc 虽然我设置了 CC=g++? [关闭] 【发布时间】:2017-05-23 17:25:09 【问题描述】:

我有一个与g++ -std=c++17 -Wall -Og -g -o main *.cc 完美编译的小代码。现在我想要一个makefile,到目前为止我得到了这个:

CC = g++
CFLAGS = -Wall -std=c++17 -Og -g
DEPS = random_tools.h
OBJ = main.o random_tools.o

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

main: $(OBJ)
    gcc $(CFLAGS) -o $@ $^

但是,当我运行 make 时它崩溃了,告诉我

g++    -c -o main.o main.cc
g++    -c -o random_tools.o random_tools.cc
gcc -Wall -o main main.o random_tools.o
main.o: In function `main':
main.cc:(.text+0x1d): undefined reference to `std::cout'
main.cc:(.text+0x22): undefined reference to `std::ostream::operator<<(int)'
main.cc:(.text+0x27): undefined reference to `std::basic_ostream<char, std::char_traits<char> >& std::endl<char, std::char_traits<char> >(std::basic_ostream<char, std::char_traits<char> >&)'
main.cc:(.text+0x2f): undefined reference to `std::ostream::operator<<(std::ostream& (*)(std::ostream&))'
main.o: In function `__static_initialization_and_destruction_0(int, int)':
main.cc:(.text+0x5d): undefined reference to `std::ios_base::Init::Init()'
main.cc:(.text+0x6c): undefined reference to `std::ios_base::Init::~Init()'
collect2: error: ld returned 1 exit status
make: *** [makefile:10: main] Error 1

我真的不明白为什么它使用gcc 而不是g++ - 我告诉它使用g++。有人可以阐明这里发生的事情以及我如何让make 照我说的去做吗?谢谢。

【问题讨论】:

因为您在链接器命令中明确使用它:gcc $(CFLAGS) -o $@ $^? 请注意,CC 通常被认为是 C 编译器,而不是 C++ 编译器。 C++ 编译器的正常变量是CXXCXXFLAGS 将通常与 C 相关联的 make 变量用于 C++ 是个坏主意。给 C++ 源文件添加 .c 后缀也是一个坏主意。 @Barmar 感谢您的提示。它只是一个命名约定还是会触发不同的行为? 这是默认规则使用的命名约定。 【参考方案1】:

这条规则

main: $(OBJ)
    gcc $(CFLAGS) -o $@ $^

已将“gcc”硬连线到其中。将其更改为$(CC),它将按您的预期运行。

也就是说,最好像这样编写这个 Makefile:

CXX = g++
CXXFLAGS = -Wall -std=c++17 -Og -g
DEPS = random_tools.h
OBJ = main.o random_tools.o

# Default goal
main: $(OBJ)
    $(LINK.cc) $^ -o $@ $(LDLIBS)

# Header dependencies
$(OBJ): $(DEPS)

这使用了内置的 Make 约定,因此以后扩展起来会容易得多。 (我没有篇幅在这里解释所有内置的 Make 约定。我建议您阅读 GNU Make manual 封面。)

(请注意,如果您实际上将源文件命名为 main.crandom_tools.c 而不是 main.ccrandom_tools.cc,这将不会达到您的预期。但您应该使用 @987654329 @ 用于 C++ 源文件。)

【讨论】:

您应该在链接器命令中考虑LDLIBSLDFLAGS;使用$(LINK.cc) $(OUTPUT_OPTION) $^ - 或$(LINK.cc) -o $@ $^ 最容易做到这一点 - 请参阅其他答案。 @TobySpeight 答案已更正,但请注意,除了我之前所说的 OUTPUT_OPTION 之外,LDLIBS 包含在 LINK.cc 中,因为 -l 选项需要最后死掉在命令行上。 TBH,当我需要这样的规则时,我运行make --print-data-base 并复制/粘贴——这是我在评论时应该做的! @TobySpeight 这是一个好习惯,我这样做是为了提醒自己$(LINK.cc) 扩展为什么。但在这种情况下,它可能会让你误入歧途,因为默认链接规则中有 $(LOADLIBES),我不得不在手册中查找它以了解它是 $(LDLIBS) 的过时替代名称,为了向后兼容而保留,并且不需要复制到新的 Makefile 中。【参考方案2】:

您在 Makefile 的 main 部分(第 9 行)中使用了 gcc 命令。您应该将其替换为:$(CC) $(CFLAGS) -o $@ $^

【讨论】:

更好的是,替换为$(LINK.cc) $(OUTPUT_OPTION) $^,这样LDLIBS 等等就可以轻松工作。 @TobySpeight $(OUTPUT_OPTION) 不应在链接规则中使用,因为在某些情况下它会扩展为 ; mv -f $(&lt;F).o $@,这显然在链接规则中不起作用。 真的 - 这是怎么回事?它应该始终扩展到-o $@ AFAICT。 @TobySpeight 当 Make 认为编译器不支持 -o-c 时会发生这种情况,这在当今非常罕见,但并非完全不可能。我不记得 Make 如何决定编译器是否支持-o-c 在这种情况下,$(LINK.cc) -o $@ $^。我坐得更正了。

以上是关于为啥我的 makefile 调用 gcc 虽然我设置了 CC=g++? [关闭]的主要内容,如果未能解决你的问题,请参考以下文章

makefile 中的多个 gcc 版本

Emscripten - 如何将我的makefile与emcc一起使用而不是gcc?

你如何为 clang 和 gcc 编写一个 makefile?

gcc makefile错误:“没有规则来制作目标......”

为啥要为 c 和 c++ 使用 gcc 和 g++ 编译器驱动程序

为啥centos7系统我设了中文但还是显示英文的?按照网上的步骤也已经安装了中文字库还是不行。