make/compile错误gnu编译器的c++解释
c++ interpretation of make/compile error gnu compiler
我正在尝试 运行 外部计算机上的 c++ 程序 运行ning Linux,但我在编译时遇到问题。该程序在 Visual Studio 我个人的代码 Mac...
中编译得很好
我的编程和计算机知识有些有限,但我相信计算机使用的是 GNU 编译器,并且经过一些谷歌搜索。至少它在我的 mac 上使用了不同于 VS Code 的东西,因为我不得不更改 Makefile。
当我使用“make”命令构建我的程序(由几个 .h 和 .cpp 文件组成)时,出现一些我不知道如何解决的错误,但我认为它有一些问题处理我的两个 classes“子问题”和“标签”(请参阅此 post 底部的错误代码)
两个 classes 都有将另一个作为参数的成员函数。因此,我在 Label-class 的定义之前使用了 Subproblem-class 的前向声明。这是我在 Label.h 中的代码的简化版本,包括错误消息中引用的函数:
#pragma once
#include "Duals.h"
#include "Nodes.h"
#include <memory>
#include <iostream>
class Subproblem; // forward declaration
class Label : public std::enable_shared_from_this<Label> {
// private members
public:
Label();
std::vector<std::shared_ptr<Node> > const PossibleMoves(Subproblem* const sp, int startLB, int startUB, int endLB, int endUB);
std::shared_ptr<Label> ExtendLabel(std::shared_ptr<Node> destinationNode, Subproblem* const sp, Duals duals);
};
bool CheckDominance(std::shared_ptr<Label> l1, std::shared_ptr<Label> l2);
std::ostream& operator<<(std::ostream& os, const std::shared_ptr<Label> l);
bool operator< (const std::shared_ptr<Label>& lhs, const std::shared_ptr<Label>& rhs);
有没有人知道可能是什么问题以及我该如何解决它?我正在使用 c++17 和 g++。我是这个论坛的新手,如果我的描述中有不清楚或遗漏的地方,我深表歉意。
g++ -std=c++17 -c -o Subproblem.o Subproblem.cpp
g++ -o program.exe -I/share/apps/gurobi/9.5.1/include/ main.o BBnode.o BBtree.o Heuristic.o Label.o MasterProblem.o Nodes.o Pattern.o Solution.o Subproblem.o TestInstance.o Utilities.o -lm -L/share/apps/gurobi/9.5.1/lib -lgurobi_g++5.2 -lgurobi_c++ -lgurobi95
/usr/bin/ld.gold: error: Label.o:1:1: invalid character
Subproblem.o:Subproblem.cpp:function Subproblem::FindPaths(Duals, int, int, int, int): error: undefined reference to 'Label::PossibleMoves(Subproblem*, int, int, int, int)'
Subproblem.o:Subproblem.cpp:function Subproblem::FindPaths(Duals, int, int, int, int): error: undefined reference to 'operator<<(std::ostream&, std::shared_ptr<Label>)'
Subproblem.o:Subproblem.cpp:function Subproblem::FindPaths(Duals, int, int, int, int): error: undefined reference to 'Label::ExtendLabel(std::shared_ptr<Node>, Subproblem*, Duals)'
Subproblem.o:Subproblem.cpp:function Subproblem::FindPaths(Duals, int, int, int, int): error: undefined reference to 'operator<<(std::ostream&, std::shared_ptr<Label>)'
Subproblem.o:Subproblem.cpp:function Subproblem::FindPaths(Duals, int, int, int, int): error: undefined reference to 'CheckDominance(std::shared_ptr<Label>, std::shared_ptr<Label>)'
Subproblem.o:Subproblem.cpp:function Subproblem::FindPaths(Duals, int, int, int, int): error: undefined reference to 'operator<<(std::ostream&, std::shared_ptr<Label>)'
Subproblem.o:Subproblem.cpp:function Subproblem::FindPaths(Duals, int, int, int, int): error: undefined reference to 'CheckDominance(std::shared_ptr<Label>, std::shared_ptr<Label>)'
Subproblem.o:Subproblem.cpp:function Subproblem::FindPaths(Duals, int, int, int, int): error: undefined reference to 'operator<<(std::ostream&, std::shared_ptr<Label>)'
Subproblem.o:Subproblem.cpp:function Subproblem::FindPaths(Duals, int, int, int, int): error: undefined reference to 'CheckDominance(std::shared_ptr<Label>, std::shared_ptr<Label>)'
Subproblem.o:Subproblem.cpp:function Subproblem::FindPaths(Duals, int, int, int, int): error: undefined reference to 'CheckDominance(std::shared_ptr<Label>, std::shared_ptr<Label>)'
Subproblem.o:Subproblem.cpp:function bool __gnu_cxx::__ops::_Iter_less_iter::operator()<__gnu_cxx::__normal_iterator<std::shared_ptr<Label>*, std::vector<std::shared_ptr<Label>, std::allocator<std::shared_ptr<Label> > > >, __gnu_cxx::__normal_iterator<std::shared_ptr<Label>*, std::vector<std::shared_ptr<Label>, std::allocator<std::shared_ptr<Label> > > > >(__gnu_cxx::__normal_iterator<std::shared_ptr<Label>*, std::vector<std::shared_ptr<Label>, std::allocator<std::shared_ptr<Label> > > >, __gnu_cxx::__normal_iterator<std::shared_ptr<Label>*, std::vector<std::shared_ptr<Label>, std::allocator<std::shared_ptr<Label> > > >) const: error: undefined reference to 'operator<(std::shared_ptr<Label> const&, std::shared_ptr<Label> const&)'
Subproblem.o:Subproblem.cpp:function bool __gnu_cxx::__ops::_Val_less_iter::operator()<std::shared_ptr<Label>, __gnu_cxx::__normal_iterator<std::shared_ptr<Label>*, std::vector<std::shared_ptr<Label>, std::allocator<std::shared_ptr<Label> > > > >(std::shared_ptr<Label>&, __gnu_cxx::__normal_iterator<std::shared_ptr<Label>*, std::vector<std::shared_ptr<Label>, std::allocator<std::shared_ptr<Label> > > >) const: error: undefined reference to 'operator<(std::shared_ptr<Label> const&, std::shared_ptr<Label> const&)'
Subproblem.o:Subproblem.cpp:function bool __gnu_cxx::__ops::_Iter_less_val::operator()<__gnu_cxx::__normal_iterator<std::shared_ptr<Label>*, std::vector<std::shared_ptr<Label>, std::allocator<std::shared_ptr<Label> > > >, std::shared_ptr<Label> >(__gnu_cxx::__normal_iterator<std::shared_ptr<Label>*, std::vector<std::shared_ptr<Label>, std::allocator<std::shared_ptr<Label> > > >, std::shared_ptr<Label>&) const: error: undefined reference to 'operator<(std::shared_ptr<Label> const&, std::shared_ptr<Label> const&)'
collect2: error: ld returned 1 exit status
make: *** [program.exe] Error 1
这是我的 Makefile:
CXX=g++
CXXFLAGS= -std=c++17
src = $(wildcard *.cpp)
obj = $(src:.cpp=.o)
dep = $(obj:.o=.d)
LDFLAGS += -lm -L$(GUROBI_HOME)/lib -lgurobi_g++5.2 -lgurobi_c++ -lgurobi95
CPLUS_INCLUDE_PATH += -I$(GUROBI_HOME)/include/
all: program.exe
program.exe : main.o BBnode.o BBtree.o Heuristic.o Label.o MasterProblem.o Nodes.o Pattern.o Solution.o Subproblem.o TestInstance.o Utilities.o
$(CXX) -o program.exe $(CPLUS_INCLUDE_PATH) main.o BBnode.o BBtree.o Heuristic.o Label.o MasterProblem.o Nodes.o Pattern.o Solution.o Subproblem.o TestInstance.o Utilities.o $(LDFLAGS)
#$(CXX) -c $(CPLUS_INCLUDE_PATH) main.cpp $(LDFLAGS)
#$(CXX) -c $(CPLUS_INCLUDE_PATH) BBnode.cpp $(LDFLAGS)
#$(CXX) -c $(CPLUS_INCLUDE_PATH) BBtree.cpp $(LDFLAGS)
#$(CXX) -c $(CPLUS_INCLUDE_PATH) Heuristic.cpp $(LDFLAGS)
#$(CXX) -c $(CPLUS_INCLUDE_PATH) Label.cpp $(LDFLAGS)
#$(CXX) -c $(CPLUS_INCLUDE_PATH) MasterProblem.cpp $(LDFLAGS)
#$(CXX) -c $(CPLUS_INCLUDE_PATH) Nodes.cpp $(LDFLAGS)
#$(CXX) -c $(CPLUS_INCLUDE_PATH) Pattern.cpp $(LDFLAGS)
#$(CXX) -c $(CPLUS_INCLUDE_PATH) Solution.cpp $(LDFLAGS)
#$(CXX) -c $(CPLUS_INCLUDE_PATH) Subproblem.cpp $(LDFLAGS)
#$(CXX) -c $(CPLUS_INCLUDE_PATH) TestInstance.cpp $(LDFLAGS)
#$(CXX) -c $(CPLUS_INCLUDE_PATH) Utilities.cpp $(LDFLAGS)
-include $(dep)
.PHONY: clean
clean:
rm -f VRPTW.exe $(obj)
.PHONY: cleandep
cleandep:
rm -f $(dep)
Label.cpp的内容:
#include #include "Label.h"
#include "Subproblem.h"
#include <iostream>
#include <cstdlib>
#include <iterator>
#include <vector>
std::vector<std::shared_ptr<Node> > const
Label::PossibleMoves(Subproblem* const sp, int startLB, int startUB, int endLB, int endUB) { /* implementation */ }
std::shared_ptr<Label> Label::ExtendLabel(std::shared_ptr<Node> destinationNode, Subproblem* const sp, Duals duals){ /* implementation */ }
bool CheckDominance(std::shared_ptr<Label> l1, std::shared_ptr<Label> l2){ /* implementation */}
std::ostream& operator<<(std::ostream& os, const std::shared_ptr<Label> l){ /* implementation */}
bool operator< (const std::shared_ptr<Label>& lhs, const std::shared_ptr<Label>& rhs){ /* implementation*/ }
这还不是答案,但请尝试使用此 Makefile:
CXX=g++
CXXFLAGS= -std=c++17 -O2 -g
INCLUDES = -I$(GUROBI_HOME)/include
srcs = $(wildcard *.cpp)
objs = $(srcs:.cpp=.o)
deps = $(objs:.o=.d)
.cpp.o:
$(CXX) $(CXXFLAGS) $(INCLUDES) -c $< -o $@
GUROBI_HOME=gurobi52
LIBS = -lm -L$(GUROBI_HOME)/lib -lgurobi_g++5.2 -lgurobi_c++ -lgurobi95
LDFLAGS =
all: program
program : $(objs)
$(CXX) $(LDFLAGS) -o $@ $^ $(LIBS)
-include $(dep)
.PHONY: clean
clean:
rm -f $(objs)
.PHONY: cleandep
cleandep:
rm -f $(deps)
希望它更清晰易读,并以此为起点。
link$(CXX) $(LDFLAGS) -o $@ $^ $(LIBS)
中的自动变量等同于$(CXX) $(LDFLAGS) -o program $(objs) $(LIBS)
.
正在阅读@Thomas 的回答,您需要使用 $ make clean
对其进行清理。
如果仔细查看错误消息,您会发现参数有所不同。例如,抱怨 Label::PossibleMoves(Subproblem*, int, int, int, int)
的错误采用 Subproblem*
,而不是 header 和实现文件中所写的 Subproblem *const
。
这让我认为您链接的是 Subproblem.o
的旧版本,在您对 Label.cpp
和 Label.h
进行了一些更改后,该版本尚未重新编译。
这是有道理的,因为 Makefile
依赖于关于如何从 .cpp
生成 .o
的 隐式 规则,并且隐式规则假定 .o
仅 取决于 .cpp
。它不会扫描包含的 header 以查看那里是否有任何更改;该任务通常由一些 makefile 生成器(如 autotools 或 CMake)完成,或者手动写入 Makefile
本身。
在 program.exe
的 Makefile
规则的旧版本中(已注释掉),有一堆 $(CXX)
调用每次 .cpp
都会重新编译有些东西改变了。一个简单粗暴的解决方案。
如果您只需要编译一次并继续您的生活,请尝试删除所有 .o
文件并从头开始构建。我怀疑您会消除这些错误(并且可能会在 return 中得到令人兴奋的新错误)。
如果您需要合适的解决方案,请查看 CMake 或其他一些可以检测源文件之间依赖关系的 makefile 生成器或构建工具。
我正在尝试 运行 外部计算机上的 c++ 程序 运行ning Linux,但我在编译时遇到问题。该程序在 Visual Studio 我个人的代码 Mac...
中编译得很好我的编程和计算机知识有些有限,但我相信计算机使用的是 GNU 编译器,并且经过一些谷歌搜索。至少它在我的 mac 上使用了不同于 VS Code 的东西,因为我不得不更改 Makefile。
当我使用“make”命令构建我的程序(由几个 .h 和 .cpp 文件组成)时,出现一些我不知道如何解决的错误,但我认为它有一些问题处理我的两个 classes“子问题”和“标签”(请参阅此 post 底部的错误代码)
两个 classes 都有将另一个作为参数的成员函数。因此,我在 Label-class 的定义之前使用了 Subproblem-class 的前向声明。这是我在 Label.h 中的代码的简化版本,包括错误消息中引用的函数:
#pragma once
#include "Duals.h"
#include "Nodes.h"
#include <memory>
#include <iostream>
class Subproblem; // forward declaration
class Label : public std::enable_shared_from_this<Label> {
// private members
public:
Label();
std::vector<std::shared_ptr<Node> > const PossibleMoves(Subproblem* const sp, int startLB, int startUB, int endLB, int endUB);
std::shared_ptr<Label> ExtendLabel(std::shared_ptr<Node> destinationNode, Subproblem* const sp, Duals duals);
};
bool CheckDominance(std::shared_ptr<Label> l1, std::shared_ptr<Label> l2);
std::ostream& operator<<(std::ostream& os, const std::shared_ptr<Label> l);
bool operator< (const std::shared_ptr<Label>& lhs, const std::shared_ptr<Label>& rhs);
有没有人知道可能是什么问题以及我该如何解决它?我正在使用 c++17 和 g++。我是这个论坛的新手,如果我的描述中有不清楚或遗漏的地方,我深表歉意。
g++ -std=c++17 -c -o Subproblem.o Subproblem.cpp
g++ -o program.exe -I/share/apps/gurobi/9.5.1/include/ main.o BBnode.o BBtree.o Heuristic.o Label.o MasterProblem.o Nodes.o Pattern.o Solution.o Subproblem.o TestInstance.o Utilities.o -lm -L/share/apps/gurobi/9.5.1/lib -lgurobi_g++5.2 -lgurobi_c++ -lgurobi95
/usr/bin/ld.gold: error: Label.o:1:1: invalid character
Subproblem.o:Subproblem.cpp:function Subproblem::FindPaths(Duals, int, int, int, int): error: undefined reference to 'Label::PossibleMoves(Subproblem*, int, int, int, int)'
Subproblem.o:Subproblem.cpp:function Subproblem::FindPaths(Duals, int, int, int, int): error: undefined reference to 'operator<<(std::ostream&, std::shared_ptr<Label>)'
Subproblem.o:Subproblem.cpp:function Subproblem::FindPaths(Duals, int, int, int, int): error: undefined reference to 'Label::ExtendLabel(std::shared_ptr<Node>, Subproblem*, Duals)'
Subproblem.o:Subproblem.cpp:function Subproblem::FindPaths(Duals, int, int, int, int): error: undefined reference to 'operator<<(std::ostream&, std::shared_ptr<Label>)'
Subproblem.o:Subproblem.cpp:function Subproblem::FindPaths(Duals, int, int, int, int): error: undefined reference to 'CheckDominance(std::shared_ptr<Label>, std::shared_ptr<Label>)'
Subproblem.o:Subproblem.cpp:function Subproblem::FindPaths(Duals, int, int, int, int): error: undefined reference to 'operator<<(std::ostream&, std::shared_ptr<Label>)'
Subproblem.o:Subproblem.cpp:function Subproblem::FindPaths(Duals, int, int, int, int): error: undefined reference to 'CheckDominance(std::shared_ptr<Label>, std::shared_ptr<Label>)'
Subproblem.o:Subproblem.cpp:function Subproblem::FindPaths(Duals, int, int, int, int): error: undefined reference to 'operator<<(std::ostream&, std::shared_ptr<Label>)'
Subproblem.o:Subproblem.cpp:function Subproblem::FindPaths(Duals, int, int, int, int): error: undefined reference to 'CheckDominance(std::shared_ptr<Label>, std::shared_ptr<Label>)'
Subproblem.o:Subproblem.cpp:function Subproblem::FindPaths(Duals, int, int, int, int): error: undefined reference to 'CheckDominance(std::shared_ptr<Label>, std::shared_ptr<Label>)'
Subproblem.o:Subproblem.cpp:function bool __gnu_cxx::__ops::_Iter_less_iter::operator()<__gnu_cxx::__normal_iterator<std::shared_ptr<Label>*, std::vector<std::shared_ptr<Label>, std::allocator<std::shared_ptr<Label> > > >, __gnu_cxx::__normal_iterator<std::shared_ptr<Label>*, std::vector<std::shared_ptr<Label>, std::allocator<std::shared_ptr<Label> > > > >(__gnu_cxx::__normal_iterator<std::shared_ptr<Label>*, std::vector<std::shared_ptr<Label>, std::allocator<std::shared_ptr<Label> > > >, __gnu_cxx::__normal_iterator<std::shared_ptr<Label>*, std::vector<std::shared_ptr<Label>, std::allocator<std::shared_ptr<Label> > > >) const: error: undefined reference to 'operator<(std::shared_ptr<Label> const&, std::shared_ptr<Label> const&)'
Subproblem.o:Subproblem.cpp:function bool __gnu_cxx::__ops::_Val_less_iter::operator()<std::shared_ptr<Label>, __gnu_cxx::__normal_iterator<std::shared_ptr<Label>*, std::vector<std::shared_ptr<Label>, std::allocator<std::shared_ptr<Label> > > > >(std::shared_ptr<Label>&, __gnu_cxx::__normal_iterator<std::shared_ptr<Label>*, std::vector<std::shared_ptr<Label>, std::allocator<std::shared_ptr<Label> > > >) const: error: undefined reference to 'operator<(std::shared_ptr<Label> const&, std::shared_ptr<Label> const&)'
Subproblem.o:Subproblem.cpp:function bool __gnu_cxx::__ops::_Iter_less_val::operator()<__gnu_cxx::__normal_iterator<std::shared_ptr<Label>*, std::vector<std::shared_ptr<Label>, std::allocator<std::shared_ptr<Label> > > >, std::shared_ptr<Label> >(__gnu_cxx::__normal_iterator<std::shared_ptr<Label>*, std::vector<std::shared_ptr<Label>, std::allocator<std::shared_ptr<Label> > > >, std::shared_ptr<Label>&) const: error: undefined reference to 'operator<(std::shared_ptr<Label> const&, std::shared_ptr<Label> const&)'
collect2: error: ld returned 1 exit status
make: *** [program.exe] Error 1
这是我的 Makefile:
CXX=g++
CXXFLAGS= -std=c++17
src = $(wildcard *.cpp)
obj = $(src:.cpp=.o)
dep = $(obj:.o=.d)
LDFLAGS += -lm -L$(GUROBI_HOME)/lib -lgurobi_g++5.2 -lgurobi_c++ -lgurobi95
CPLUS_INCLUDE_PATH += -I$(GUROBI_HOME)/include/
all: program.exe
program.exe : main.o BBnode.o BBtree.o Heuristic.o Label.o MasterProblem.o Nodes.o Pattern.o Solution.o Subproblem.o TestInstance.o Utilities.o
$(CXX) -o program.exe $(CPLUS_INCLUDE_PATH) main.o BBnode.o BBtree.o Heuristic.o Label.o MasterProblem.o Nodes.o Pattern.o Solution.o Subproblem.o TestInstance.o Utilities.o $(LDFLAGS)
#$(CXX) -c $(CPLUS_INCLUDE_PATH) main.cpp $(LDFLAGS)
#$(CXX) -c $(CPLUS_INCLUDE_PATH) BBnode.cpp $(LDFLAGS)
#$(CXX) -c $(CPLUS_INCLUDE_PATH) BBtree.cpp $(LDFLAGS)
#$(CXX) -c $(CPLUS_INCLUDE_PATH) Heuristic.cpp $(LDFLAGS)
#$(CXX) -c $(CPLUS_INCLUDE_PATH) Label.cpp $(LDFLAGS)
#$(CXX) -c $(CPLUS_INCLUDE_PATH) MasterProblem.cpp $(LDFLAGS)
#$(CXX) -c $(CPLUS_INCLUDE_PATH) Nodes.cpp $(LDFLAGS)
#$(CXX) -c $(CPLUS_INCLUDE_PATH) Pattern.cpp $(LDFLAGS)
#$(CXX) -c $(CPLUS_INCLUDE_PATH) Solution.cpp $(LDFLAGS)
#$(CXX) -c $(CPLUS_INCLUDE_PATH) Subproblem.cpp $(LDFLAGS)
#$(CXX) -c $(CPLUS_INCLUDE_PATH) TestInstance.cpp $(LDFLAGS)
#$(CXX) -c $(CPLUS_INCLUDE_PATH) Utilities.cpp $(LDFLAGS)
-include $(dep)
.PHONY: clean
clean:
rm -f VRPTW.exe $(obj)
.PHONY: cleandep
cleandep:
rm -f $(dep)
Label.cpp的内容:
#include #include "Label.h"
#include "Subproblem.h"
#include <iostream>
#include <cstdlib>
#include <iterator>
#include <vector>
std::vector<std::shared_ptr<Node> > const
Label::PossibleMoves(Subproblem* const sp, int startLB, int startUB, int endLB, int endUB) { /* implementation */ }
std::shared_ptr<Label> Label::ExtendLabel(std::shared_ptr<Node> destinationNode, Subproblem* const sp, Duals duals){ /* implementation */ }
bool CheckDominance(std::shared_ptr<Label> l1, std::shared_ptr<Label> l2){ /* implementation */}
std::ostream& operator<<(std::ostream& os, const std::shared_ptr<Label> l){ /* implementation */}
bool operator< (const std::shared_ptr<Label>& lhs, const std::shared_ptr<Label>& rhs){ /* implementation*/ }
这还不是答案,但请尝试使用此 Makefile:
CXX=g++
CXXFLAGS= -std=c++17 -O2 -g
INCLUDES = -I$(GUROBI_HOME)/include
srcs = $(wildcard *.cpp)
objs = $(srcs:.cpp=.o)
deps = $(objs:.o=.d)
.cpp.o:
$(CXX) $(CXXFLAGS) $(INCLUDES) -c $< -o $@
GUROBI_HOME=gurobi52
LIBS = -lm -L$(GUROBI_HOME)/lib -lgurobi_g++5.2 -lgurobi_c++ -lgurobi95
LDFLAGS =
all: program
program : $(objs)
$(CXX) $(LDFLAGS) -o $@ $^ $(LIBS)
-include $(dep)
.PHONY: clean
clean:
rm -f $(objs)
.PHONY: cleandep
cleandep:
rm -f $(deps)
希望它更清晰易读,并以此为起点。
link$(CXX) $(LDFLAGS) -o $@ $^ $(LIBS)
中的自动变量等同于$(CXX) $(LDFLAGS) -o program $(objs) $(LIBS)
.
正在阅读@Thomas 的回答,您需要使用 $ make clean
对其进行清理。
如果仔细查看错误消息,您会发现参数有所不同。例如,抱怨 Label::PossibleMoves(Subproblem*, int, int, int, int)
的错误采用 Subproblem*
,而不是 header 和实现文件中所写的 Subproblem *const
。
这让我认为您链接的是 Subproblem.o
的旧版本,在您对 Label.cpp
和 Label.h
进行了一些更改后,该版本尚未重新编译。
这是有道理的,因为 Makefile
依赖于关于如何从 .cpp
生成 .o
的 隐式 规则,并且隐式规则假定 .o
仅 取决于 .cpp
。它不会扫描包含的 header 以查看那里是否有任何更改;该任务通常由一些 makefile 生成器(如 autotools 或 CMake)完成,或者手动写入 Makefile
本身。
在 program.exe
的 Makefile
规则的旧版本中(已注释掉),有一堆 $(CXX)
调用每次 .cpp
都会重新编译有些东西改变了。一个简单粗暴的解决方案。
如果您只需要编译一次并继续您的生活,请尝试删除所有 .o
文件并从头开始构建。我怀疑您会消除这些错误(并且可能会在 return 中得到令人兴奋的新错误)。
如果您需要合适的解决方案,请查看 CMake 或其他一些可以检测源文件之间依赖关系的 makefile 生成器或构建工具。