我正在通过制作教程。我正在尝试构建的非常简单的测试项目只有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的链接不起作用。
我可以明确指定规则,但想学习如何使用隐式规则。
答案 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 = -lstdc++
:
但以下编译器接受LDFLAGS = -lstdc++
:
所以它大部分时间都有效,但不能保证。如果您希望makefile更具可移植性,请使用适用于所有上述环境的LDLIBS
。
Hasturkun:规则中有main.o
main: main.o implementation.o
不会导致错误。 main.o
不是必需的,但它仍然可以。
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)。所以我很抱歉,但他的答案实际上没有回答这个问题。
杰罗姆:我过去常常将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