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

时间:2011-03-29 14:38:59

标签: 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

在没有任何参数的情况下调用 make 仅构建目标文件,但不链接可执行文件。应该有 prog 的隐含规则或者我错过了什么?我真的需要有人指出我正确的方向。

感谢。

我使第一个目标名称与源文件的前缀相同。现在拨打电话 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

由于某种原因,与g ++的链接起作用,但与cc的链接不起作用。

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

7 个答案:

答案 0 :(得分:14)

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

VPATH = src include
CPPFLAGS = -I include

main: implementation.o
main.o: header.hpp
implementation.o: header.hpp

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

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

答案 1 :(得分: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

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

答案 2 :(得分:5)

  

对于prog应该有一个隐含的规则,或者我错过了什么?

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

答案 3 :(得分:3)

我的回答(一个简洁的解决方案):添加

LDLIBS = -lstdc++

到Makefile。根据{{​​3}}:

  

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

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

cc -lstdc++ main.o -o main

哪个不起作用,而LDLIBS = -lstdc++生成

cc main.o -lstdc++ -o main

哪个有效。我不知道为什么顺序很重要,但根据两个内置变量的作用是有意义的。我不喜欢将CC替换为CXX,这似乎是黑客攻击,也让读者感到困惑。

LDFLAGS v.s. LDLIBS

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

  • UCCntu 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
    

    不会导致错误。 main.o不是必需的,但它仍然可以。

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

    VPATH = src include
    CPPFLAGS = -I include -MMD -MP
    CXXFLAGS = -g -W -Wall -Werror
    LDLIBS = -lstdc++
    
    target = main
    lib = implementation.cpp
    objects = $(target:=.o) $(lib:.cpp=.o)
    
    $(target): $(objects)
    %.o: %.cpp %.d
    %.d: ;
    
    -include $(objects:.o=.d)
    
    clean::
        $(RM) $(target) $(objects) $(objects:.o=.d)
    

    做了他所做的事情,并利用了隐含的规则。但是,这个完整的解决方案不应该在这里,因为它不是OP所希望的:OP只是想知道为什么他的Makefile不起作用,以及为什么。 &#34;自动依赖生成&#34;这是另一个值得整个教程的重要主题(如the manual)。所以我很抱歉,但他的答案实际上没有回答这个问题。

  3. 杰罗姆:我过去常常将LINK.o$(CC) $(LDFLAGS) $(TARGET_ARCH)更改为$(CXX) $(LDFLAGS) $(TARGET_ARCH)并且有效,但我更喜欢编辑LDLIBS,因为LINK.o不是记录(可能不是公共API的一部分)而不是面向未来的。我称之为黑客。

答案 4 :(得分:1)

链接目标文件的隐式规则是:

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

$(LINK.o)使用$(CC),这对编译C ++程序来说不太正确,所以最简单的解决方法是:

CC = $(CXX)

答案 5 :(得分:0)

嗯...

CXX = g++               # Just an example
CXXFLAGS = -Wall -O2    # Just an example

prog: main.o implementation.o
    $(CXX) $(CXXFLAGS) $^ -o $@

main.o: header.hpp
implementation.o: header.hpp

应该做的工作。为什么你的变体不起作用在 Konrad Rudolph 回答

中有解释

答案 6 :(得分:0)

如果要链接c ++对象文件,可以将LINK.o指定为顶部的LINK.cc

LINK.o := $(LINK.cc)

然后您应该在g++输出中看到cc而不是make