当我尝试在我的Makefile中包含C源文件时,我发现了问题。此C源文件包含一个由C ++代码(list.cpp)通过外部C链接选项调用的函数。我想知道Makefile中哪个是正确的位置来包含这个C源代码,其源代码在C ++代码中被调用。如果我尝试在Makefile的SOURCES变量中添加此C文件以构建它,那么C ++代码无法正确解析C的函数调用,并且我得到链接器错误:未定义的引用
以下是我的Makefile内容:
CFLAGS =-c -g -Wall -std=c++11
SOURCES = list.cpp
OBJECTS = $(SOURCES:.cpp=.o)
EXEC = a.out
all: $(SOURCES) $(EXEC)
$(EXEC): $(OBJECTS)
@$(CXX) $(OBJECTS) -o $@ && $(EXEC)
.cpp.o:
@$(CXX) $(CFLAGS) $< -o $@
答案 0 :(得分:1)
我们假设构建中需要的C源文件是bar.c
,
并且它有一个关联的头文件bar.h
#include
list.cpp
,并且您已正确编码extern C
bar.h
中的样板文件。
然后以下makefile将满足您的需求:
<强>生成文件强>
CXX_SOURCES := list.cpp
C_SOURCES := bar.c
OBJECTS = $(C_SOURCES:.c=.o) $(CXX_SOURCES:.cpp=.o)
CXXFLAGS := -g -Wall -std=c++11
CFLAGS := -g -Wall
CPPFLAGS :=
LDFLAGS :=
LDLIBS :=
EXEC := a.out
.PHONY: all clean test
all: $(EXEC)
test: $(EXEC)
./$<
$(EXEC): $(OBJECTS)
$(CXX) $(LDFLAGS) $^ -o $@ $(LDLIBS)
list.o: bar.h
clean:
rm -f $(EXEC) *.o
这里有很多学习要点:
1。使用立即评估(:=
)而不是递归评估(=
)
除非你特别想要递归评估,否则创建变量。看到
6.2 The Two Flavors of Variables
2. 如果目标只是任务的名称而不是文件的名称
任务将创建,然后它是phony target
你应该告诉make
这是一个虚假的目标,如:
.PHONY: all clean test
3。构建程序运行程序的make-recipe是不正常的 好吧,就像你的:
@$(CXX) $(OBJECTS) -o $@ && $(EXEC)
你并不总是想要只是因为你已经构建了它而运行程序,并且 如果该程序是长期运行或交互式的那么这种方法 将使构建程序变得无法实现。
您可能希望运行程序 test 它已正确构建。
但是建设是一项任务,测试是另一项任务(可能需要更长的时间
涉及额外资源);所以你应该提供一个单独的假目标
用于检测。我在这个makefile中称它为test
:通常它被称为check
。
要在不测试的情况下构建程序,只需运行make
即可。要测试它,
运行make test
- 这将 (重新)构建程序,如果需要(重新)构建。
4。您无需编写规则即可从name.o
创建name.cpp
,或者
从name.o
制作name.c
的规则。 GNU make
有builtin rules
这是正确的,只要你正确设置了make变量即可
make
用于这些内置规则:
CC
:调用C编译或链接的命令,例如gcc
CXX
:调用C ++编译或链接的命令,例如g++
CFLAGS
:C编译选项CXXFLAGS
:C ++编译选项CPPFLAGS
:C / C ++预处理器的选项5. 具有传统含义的两个更重要的变量是:
LDFLAGS
:链接选项,不包括库(-l
)选项LDLIBS
:用于关联的图书馆选项(-l
)。在上面的简单makefile中,CPPFLAGS
,LDFLAGS
和LDLIBS
不是
需要,可以省略。相反,我已经为它们分配了空值
只是为了说明它们的用途。
6。 makefile应该有一个删除任何文件的假目标clean
makefile可能已创建,以便make clean
获取
准备从头开始构建任何东西。
<强> 7 即可。如果name.o
是从name.c
或name.cpp
汇编的,那么。{
课程name.o
取决于name.c
| name.cpp
,但也取决于
在 name.c
| name.cpp
包含的每个头文件中,以及
makefile需要表达所有这些依赖项才能可靠地工作。所以
在这种情况下,您需要(至少)规则:
list.o: bar.h
因此,如果您更改bar.h
,则make
会看到foo.o
已超出
日期并将执行重新制作foo.o
的方法。当你
开始构建复杂的程序对你来说是不切实际的
自己弄清楚所有这些头文件依赖:然后你需要
了解自动依赖关系生成。