编译
假设您想编写一个简单的“hello world”应用程序。您有 3 个文件,hello.cpp
hello-writer.cpp
并且hello-writer.h
,内容为
// hello-writer.h
void WriteHello(void);
// hello-writer.cpp
#include "hello-writer.h"
#include <stdio>
void WriteHello(void){
std::cout<<"Hello World"<<std::endl;
}
// hello.cpp
#include "hello-writer.h"
int main(int argc, char ** argv){
WriteHello();
}
g++
使用命令将 *.cpp 文件转换为目标文件
g++ -c hello.cpp -o hello.o
g++ -c hello-writer.cpp -o hello-writer.o
-c
标志暂时跳过链接。要将所有模块链接在一起需要运行
g++ hello.o hello-writer.o -o hello
创建程序hello
。如果您需要链接任何外部库,请将它们添加到这一行,例如-lm
数学库。实际的库文件看起来像libm.a
or libm.so
,您在添加链接器标志时忽略文件名的后缀和“lib”部分。
生成文件
要使构建过程自动化,您可以使用 makefile,它由一系列规则组成,列出要创建的事物以及创建它所需的文件。例如,hello.o
取决于hello.cpp
和hello-writer.h
,它的规则是
hello.o:hello.cpp hello-writer.h
g++ -c hello.cpp -o hello.o # This line must begin with a tab.
如果您想阅读 make 手册,它会告诉您如何使用变量和自动规则来简化事情。你应该可以写
hello.o:hello.cpp hello-writer.h
并且规则将自动创建。hello 示例的完整生成文件是
all:hello
hello:hello.o hello-writer.o
g++ hello.o hello-writer.o -o hello
hello.o:hello.cpp hello-writer.h
g++ -c hello.cpp -o hello.o
hello-writer.o:hello-writer.cpp hello-writer.h
g++ -c hello-writer.cpp -o hello-writer.o
请记住,缩进的行必须以制表符开头。并不是所有的规则都需要一个实际的文件,all
目标只是说 create hello
。这通常是 makefile 中的第一条规则,当您运行时自动创建第一条规则make
。
完成所有这些设置后,您应该能够转到命令行并运行
$ make
$ ./hello
Hello World
更高级的 Makefile 东西
您还可以在 makefile 中定义一些有用的变量,其中包括
- CXX: c++ 编译器
- CXXFLAGS:传递给编译器的附加标志(例如,包含带有 -I 的目录)
- LDFLAGS:要传递给链接器的附加标志
- LDLIBS:要链接的库
- CC:c编译器(也用来链接)
- CPPFLAGS:预处理器标志
使用 定义变量=
,使用 添加到变量+=
。
将 .cpp 文件转换为 .o 文件的默认规则是
$(CXX) $(CXXFLAGS) $(CPPFLAGS) -c $< -o $@
其中$<
是第一个依赖项,$@
是输出文件。通过将变量括在 中来扩展变量$()
,此规则将与模式一起运行hello.o:hello.cpp
同样,默认链接器规则是
$(CC) $(LDFLAGS) $^ -o $@ $(LDLIBS)
$^
所有的先决条件在哪里。此规则将与模式一起运行hello:hello.o hello-writer.o
。请注意,这使用 c 编译器,如果您不想覆盖此规则并使用 c++ 将库添加-lstdc++
到LDLIBS
该行
LDLIBS+=-lstdc++
在生成文件中。
最后,如果您不列出.o
文件的依赖关系,make 可以自己找到它们,所以最小的 makefile 可能是
LDFLAGS=-lstdc++
all:hello
hello:hello.o hello-writer.o
请注意,这忽略了两个文件对 的依赖关系hello-writer.h
,因此如果修改了标头,则不会重新构建程序。如果您有兴趣,请查看-MD
gcc 文档中的标志,了解如何自动生成此依赖关系。
最终生成文件
一个合理的最终生成文件将是
// Makefile
CC=gcc
CXX=g++
CXXFLAGS+=-Wall -Wextra -Werror
CXXFLAGS+=-Ipath/to/headers
LDLIBS+=-lstdc++ # You could instead use CC = $(CXX) for the same effect
# (watch out for c code though!)
all:hello # default target
hello:hello.o hello-world.o # linker
hello.o:hello.cpp hello-world.h # compile a module
hello-world.o:hello-world.cpp hello-world.h # compile another module
$(CXX) $(CXXFLAGS) -c $< -o $@ # command to run (same as the default rule)
# expands to g++ -Wall ... -c hello-world.cpp -o hello-world.o