我们需要使用Makefile将所有内容整合到我们的项目中,但我们的教授从未向我们展示如何使用。
我只有一个文件,a3driver.cpp
。
驱动程序从位置"/user/cse232/Examples/example32.sequence.cpp"
导入一个类。
就是这样,其他一切都包含在.cpp
。
我如何制作一个简单的Makefile来创建一个名为a3a.exe
的可执行文件?
答案 0 :(得分:492)
答案 1 :(得分:50)
我一直认为通过一个详细的例子更容易学习,所以这就是我对makefile的看法。对于每个部分,您有一行不缩进的行,它显示该部分的名称,后跟依赖项。依赖项可以是其他部分(将在当前部分之前运行)或文件(如果更新将导致下次运行make
时再次运行当前部分)。
这是一个快速示例(请记住,我使用的是4个空格,我应该使用选项卡,Stack Overflow不会让我使用制表符):
a3driver: a3driver.o
g++ -o a3driver a3driver.o
a3driver.o: a3driver.cpp
g++ -c a3driver.cpp
当您键入make
时,它将选择第一部分(a3driver)。 a3driver依赖于a3driver.o,所以它将转到该部分。 a3driver.o依赖于a3driver.cpp,所以它只会在a3driver.cpp自上次运行以来发生变化时运行。假设它已经(或从未运行过),它会将a3driver.cpp编译为.o文件,然后返回a3driver并编译最终的可执行文件。
由于只有一个文件,它甚至可以简化为:
a3driver: a3driver.cpp
g++ -o a3driver a3driver.cpp
我展示第一个例子的原因是它显示了makefile的强大功能。如果需要编译另一个文件,可以添加另一个部分。这是一个带有secondFile.cpp的示例(它在一个名为secondFile.h的头文件中加载):
a3driver: a3driver.o secondFile.o
g++ -o a3driver a3driver.o secondFile.o
a3driver.o: a3driver.cpp
g++ -c a3driver.cpp
secondFile.o: secondFile.cpp secondFile.h
g++ -c secondFile.cpp
这样,如果你在secondFile.cpp或secondFile.h中更改某些东西并重新编译,它只会重新编译secondFile.cpp(而不是a3driver.cpp)。或者,如果你在a3driver.cpp中更改某些内容,它将不会重新编译secondFile.cpp。
如果您对此有任何疑问,请与我们联系。
包括名为“all”的部分和名为“clean”的部分也是传统的。 “all”通常会构建所有可执行文件,而“clean”将删除像.o文件和可执行文件这样的“构建工件”:
all: a3driver ;
clean:
# -f so this will succeed even if the files don't exist
rm -f a3driver a3driver.o
编辑:我没注意到你在Windows上。我认为唯一的区别是将-o a3driver
更改为-o a3driver.exe
。
答案 2 :(得分:32)
为什么每个人都喜欢列出源文件?一个简单的find命令可以很容易地解决这个问题。
这是一个简单的C ++ Makefile的例子。只需将其放在包含.C
个文件的目录中,然后键入make
...
appname := myapp
CXX := clang++
CXXFLAGS := -std=c++11
srcfiles := $(shell find . -name "*.C")
objects := $(patsubst %.C, %.o, $(srcfiles))
all: $(appname)
$(appname): $(objects)
$(CXX) $(CXXFLAGS) $(LDFLAGS) -o $(appname) $(objects) $(LDLIBS)
depend: .depend
.depend: $(srcfiles)
rm -f ./.depend
$(CXX) $(CXXFLAGS) -MM $^>>./.depend;
clean:
rm -f $(objects)
dist-clean: clean
rm -f *~ .depend
include .depend
答案 3 :(得分:12)
老问题,我知道,但对后代来说。你有两个选择。
选项1:最简单的makefile = NO MAKEFILE。
将“a3driver.cpp”重命名为“a3a.cpp”,然后在命令行上写:
nmake a3a.exe
就是这样。如果您正在使用gnu-make,请使用“make”或“gmake”或其他任何内容。
选项2:2行生成文件。
a3a.exe: a3driver.obj
link /out:a3a.exe a3driver.obj
瞧。
答案 4 :(得分:6)
您的make文件将具有一个或两个依赖关系规则,具体取决于您是使用单个命令编译和链接,还是使用一个用于编译的命令和一个用于链接的命令。
依赖是一个规则树,如下所示:
main_target : source1 source2 etc
command to build main_target from sources
source1 : dependents for source1
command to build source1
在目标命令之后必须是一个空行,并且在命令之前不必须是空白行。 makefile中的第一个目标是总体目标,仅当第一个目标依赖于它们时才构建其他目标。
所以你的makefile看起来像这样。
a3a.exe : a3driver.obj
link /out:a3a.exe a3driver.obj
a3driver.obj : a3driver.cpp
cc a3driver.cpp
答案 5 :(得分:5)
我使用了Friedmud的回答。我对此进行了一段时间的研究,这似乎是一个很好的入门方式。此解决方案还有一个定义良好的添加编译器标志的方法。我再次回答,因为我做了更改,使其在我的环境,Ubuntu和g ++中工作。更多工作实例有时是最好的老师。
appname := myapp
CXX := g++
CXXFLAGS := -Wall -g
srcfiles := $(shell find . -maxdepth 1 -name "*.cpp")
objects := $(patsubst %.cpp, %.o, $(srcfiles))
all: $(appname)
$(appname): $(objects)
$(CXX) $(CXXFLAGS) $(LDFLAGS) -o $(appname) $(objects) $(LDLIBS)
depend: .depend
.depend: $(srcfiles)
rm -f ./.depend
$(CXX) $(CXXFLAGS) -MM $^>>./.depend;
clean:
rm -f $(objects)
dist-clean: clean
rm -f *~ .depend
include .depend
makefile似乎非常复杂。我正在使用一个,但它产生了一个与不链接g ++库有关的错误。这种配置解决了这个问题。
答案 6 :(得分:5)
我建议:
tool: tool.o file1.o file2.o
$(CXX) $(LDFLAGS) $^ $(LDLIBS) -o $@
或
LINK.o = $(CXX) $(LDFLAGS) $(TARGET_ARCH)
tool: tool.o file1.o file2.o
后者的建议略胜一筹,因为它重用了GNU make隐式规则。但是,为了工作,源文件必须具有与最终可执行文件相同的名称(即:tool.c
和tool
)。
注意,没有必要申报来源。使用隐式规则生成中间目标文件。因此,这Makefile
适用于C和C ++(以及Fortran等...)。
另请注意,默认情况下,Makefile使用$(CC)
作为链接器。 $(CC)
无法链接C ++对象。我们仅因此而修改LINK.o
。如果您想编译C代码,则不必强制LINK.o
值。
当然,您还可以使用变量CFLAGS
添加编译标记,并在LDLIBS
中添加库。例如:
CFLAGS = -Wall
LDLIBS = -lm
一方面注意:如果您必须使用外部库,我建议use pkg-config正确设置CFLAGS
和LDLIBS
:
CFLAGS += $(shell pkg-config --cflags libssl)
LDLIBS += $(shell pkg-config --libs libssl)
细心的读者注意,如果更改了一个标头,则Makefile
无法正确重建。添加以下行以解决问题:
override CPPFLAGS += -MMD
include $(wildcard *.d)
-MMD
允许构建包含有关头依赖关系的Makefile片段的.d文件。第二行只是使用它们。
当然,编写良好的Makefile还应包含clean
和distclean
规则:
clean:
$(RM) *.o *.d
distclean: clean
$(RM) tool
请注意,$(RM)
相当于rm -f
,但最好不要直接致电rm
。
all
规则也表示赞赏。为了工作,它应该是您文件的第一条规则:
all: tool
您还可以添加install
规则:
PREFIX = /usr/local
install:
install -m 755 tool $(DESTDIR)$(PREFIX)/bin
默认情况下, DESTDIR
为空。用户可以将其设置为将程序安装到备用系统(交叉编译过程必需)。用于多次分发的软件包维护者也可能会更改PREFIX
,以便在/usr
中安装您的软件包。
最后一句话,不要将源文件放在子目录中。如果您真的想这样做,请将此Makefile
保留在根目录中,并使用完整路径来识别您的文件(即subdir/file.o
)。
总而言之,您的完整Makefile应如下所示:
LINK.o = $(CXX) $(LDFLAGS) $(TARGET_ARCH)
PREFIX = /usr/local
override CPPFLAGS += -MMD
include $(wildcard *.d)
all: tool
tool: tool.o file1.o file2.o
clean:
$(RM) *.o *.d
distclean: clean
$(RM) tool
install:
install -m 755 tool $(DESTDIR)$(PREFIX)/bin