make:链接c ++项目的隐式规则

pic*_*c11 16 c++ makefile

我正在通过制作教程.我正在尝试构建的非常简单的测试项目只有3个文件:./ src/main.cpp ./src/implementation.cpp./include/header.hpp这是make文件.

VPATH = src include
CPPFLAGS = -I include

main: main.o implementation.o
main.o: header.hpp
implementation.o: header.hpp
Run Code Online (Sandbox Code Playgroud)

当调用时没有任何参数使得建立唯一对象的文件,但不链接的可执行文件.应该有一个隐含的前卫规则或我错过了什么?我真的需要有人指出我正确的方向.

谢谢.

我使第一个目标名称与源文件的前缀相同.现在调用cc来链接目标文件.

g++  -I include  -c -o main.o src/main.cpp    
g++  -I include  -c -o implementation.o src/implementation.cpp
cc   main.o implementation.o   -o main
Run Code Online (Sandbox Code Playgroud)

由于某些原因,与g ++链接工作,但与cc链接不起作用.

我可以明确指定规则,但想学习如何使用隐式规则.

Has*_*kun 15

根据make手册,如果其中一个与可执行文件名匹配,则可以将隐式链接规则与多个对象一起使用,例如:

VPATH = src include
CPPFLAGS = -I include

main: implementation.o
main.o: header.hpp
implementation.o: header.hpp
Run Code Online (Sandbox Code Playgroud)

这将从main.o和implementation.o构建一个名为main的可执行文件.

但请注意,内置隐式规则使用C编译器进行链接,默认情况下不会链接到C++ std库,您需要将其明确地添加到LDFLAGS

  • 这修正了它:**LDFLAGS = -lstdc ++**.顺便问一下,为什么不设置CC = g ++?如果我的项目有C源文件或链接到C库,会不会引起任何问题? (8认同)
  • 尽管`LDFLAGS`在技术上有效,[文档说](https://www.gnu.org/software/make/manual/html_node/Implicit-Variables.html#Implicit-Variables)`LDLIBS`(以前称为`LOADLIBES `) 是像 `-lstdc++` 这样的 `-l` 选项。 (3认同)
  • @PavelŠimerda:从手册:"这个规则对于只有一个源文件的简单程序是正确的.如果有多个目标文件(可能来自各种其他源文件),它也会做正确的事情,其中​​一个的名称与可执行文件的名称相匹配" (2认同)

Sim*_*ter 6

对于最小的Makefile,这个怎么样:

SOURCES = src/main.cpp src/implementation.cpp

CXX = g++
CXXFLAGS = -g -W -Wall -Werror
LDFLAGS = -g

OBJECTS = $(SOURCES:.cpp=.o)

prog: $(OBJECTS)
    $(CXX) $(LDFLAGS) -o $@ $^

clean::
    $(RM) prog

.cpp.o:
    $(CXX) -MD -MP $(CXXFLAGS) -o $@ -c $<

clean::
    $(RM) src/*.o

DEPENDS = $(SOURCES:.cpp=.d)

-include $(DEPENDS)

%.d:
    @touch $@

clean::
    $(RM) src/*.d
Run Code Online (Sandbox Code Playgroud)

这假定GNU make和gcc,但它添加了适当的依赖关系跟踪,因此不需要显式列出头文件依赖关系.

  • 可以,但是我正在尝试学习如何使用隐式规则。 (2认同)

Kon*_*lph 5

应该有一个隐含的前卫规则或我错过了什么?

没有隐含的规则.make不知道如何构建,prog因为它不知道prog应该是一个可执行文件.make仅使用文件名作为模式来推断构建规则.prog是没有扩展名的通用文件名,所以make不知道如何对待它.


Fra*_* Yu 5

我的答案(一个巧妙的解决方案):添加

LDLIBS = -lstdc++
Run Code Online (Sandbox Code Playgroud)

到 Makefile。根据手册

-lfoo应改为将库 ( ) 添加到LDLIBS变量中。

LDFLAGS专为库目录标志而设计,例如-L. 在我的 Linux (Ubuntu 14.04) 上,LDFLAGS = -lstdc++产生

cc -lstdc++ main.o -o main
Run Code Online (Sandbox Code Playgroud)

这不起作用,而LDLIBS = -lstdc++产生

cc main.o -lstdc++ -o main
Run Code Online (Sandbox Code Playgroud)

哪个有效。我不知道为什么顺序很重要,但根据两个内置变量的作用,它是有道理的。我不喜欢的别名CCCXX这似乎是黑客攻击,以及为读者混淆。

LDFLAGS 与 LDLIBS

我刚刚试过,发现这个编译器不适用于LDFLAGS = -lstdc++

  • Ubuntu 14.04 上的 GCC 4.8.5

但以下编译器接受LDFLAGS = -lstdc++

  • Ubuntu 14.04 上的 Clang 3.4
  • Debian Wheezy 上的 GCC 4.7.2
  • OS X 上的 Clang 7.3.0 (703.0.31)

所以它大部分时间都有效,但不能保证。如果您希望您的 makefile 更便携,请使用LDLIBS适用于上述所有环境的文件。

为什么不是上面的其他解决方案?

  1. Hasturkun:有main.o规则

    main: main.o implementation.o
    
    Run Code Online (Sandbox Code Playgroud)

    不会导致错误。该main.o是没有必要的,但它仍然会。

  2. Simon Richter:该解决方案不需要跟踪标题(这真的很棒),但是 OP 需要一个隐式规则。我们实际上可以充分利用两者:

    LDLIBS = -lstdc++
    
    Run Code Online (Sandbox Code Playgroud)

    这做他所做的,以及利用隐含规则。然而,这个完整的解决方案不应该在这里,因为它不是 OP 所希望的:OP 只是想知道为什么他的 Makefile 不起作用,以及为什么。“Auto-Dependency Generation”是另一个值得一整个教程(就像这个)的巨大话题。所以我很抱歉,但他的回答实际上并没有回答这个问题。

  3. Jerome:我曾经LINK.o$(CC) $(LDFLAGS) $(TARGET_ARCH)改为$(CXX) $(LDFLAGS) $(TARGET_ARCH)并且它起作用了,但我更喜欢编辑,LDLIBS因为LINK.o没有记录(并且可能不是公共 API 的一部分)并且没有未来证明。我会称之为黑客。