makefile 入门第一课

时间:2022-12-06 07:58:05


makefile入门第一课

百度百科makefile词条
一个工程中的源文件不计其数,其按类型、功能、模块分别放在若干个目录中。
makefile 定义了一系列的规则来指定,哪些文件需要先编译,哪些文件需要后编译,哪些文件需要重新编译,
甚至于进行更复杂的功能操作,因为 makefile 就像一个 Shell 脚本一样,其中也可以执行操作系统的命令。

简单了解 g++

g++ 是 GNU 的 C++ 编译器

用 g++ 编译单个文件生成可执行文件

在 vim 中编写下列代码,保存在 main.cpp 文件中:

// in main.cpp
#include <iostream>
using namespace std;

int main()
{
cout << "hello, g++!" << endl;
return 0;
}

在该文件夹下,执行下列语句编译该文件为执行文件:

g++ main.cpp -o hello

这句命令是编译 main.cpp 文件, 并将其输出文件命名为 hello
此时,可以发现,当前文件夹生成了可执行文件 hello,输入下列语句执行该文件:

./hello

此时,shell 输出 ​​hello, g++!​​。

用 g++ 通过编译中间文件生成可执行文件

可执行文件的生成一般包括编译链接,首先编译生成中间目标文件,然后将各个目标文件链接成可执行文件:

makefile 入门第一课


用 vim 编写下列代码,分别保存在不同的文件下:

  • hello.h
#ifndef SRC_HELLO_H
#define SRC_HELLO_H
class hello
{
public:
hello();
~hello();
};
#endif // SRC_HELLO_H
  • hello.cpp
#include "hello.h"
#include <iostream>

using std::cout;
using std::endl;

hello::hello()
{
cout << "hello, object!" << endl;
}

hello::~hello()
{
cout << "goodbye, obejct!" << endl;
}
  • main.cpp
#include <iostream>
#include "hello.h"
using namespace std;

int main()
{
hello h;
return 0;
}
  1. 在当前路径输入下列语句,编译 hello.cpp,生成中间目标文件 hello.o
g++ -c hello.cpp

此时,当前目录生成 hello.o 文件。

  1. 在当前路径输入下列语句,编译 main.cpp,生成中间目标文件 main.o
g++ -c main.cpp

此时,当前目录生成 main.o 文件。

  1. 在当前路径输入下列语句,链接 hello.omain.o,生成可执行文件 hello
g++ main.o hello.o -o hello

此时,当前文件夹生成可执行文件 hello

  1. 在当前路径输入下列语句,执行 hello 程序:
./hello

此时控制台输出为:

hello, object!
goodbye, obejct!

makefile 编译文件

makefile 的基本结构

makefile 由下面的基本结构组成:

target …  :  prerequisites …
recipe

​taget​​​ 通常是待生成的可执行文件目标文件,也可以是标签,
​​​prerequisites​​​ 是用来生成待生成文件的文件,即待生成文件所依赖的文件,
​​​recipe​​​ 是 ​​make​​ 命令需要执行的动作(action), 通常是不止一条的 shell 命令。

makefile 编译单个文件生成可执行文件

在当前路径下,创建下面的 .cpp 文件:

// in main.cpp
#include <iostream>
using namespace std;

int main()
{
cout << "hello, makefile!" << endl;
return 0;
}

用 vim 创建文件名为 makefile 的文件:

# in makefile
#可执行文件 hello 由 main.cpp 编译得到
hello: main.cpp
# 打印一句话
echo "Begin to compile..."
# 编译 main.cpp 生成可执行文件 hello 的命令行
g++ main.cpp -o hello
# 打印一句话
echo "Has been Compiled..."

在当前路径下,输入并执行 ​​make​​ 命令,控制台输出:

Begin to compile...
Has been compiled...

此时,当前路径下生成可执行文件 hello ,执行 hello 文件:

./hello

此时,控制台输出:

hello, makefile!

makefile 编译中间文件并链接为可执行文件

在当前路径下,创建下面的 .cpp 文件和 .h 文件:

  • hello.h
#ifndef SRC_HELLO_H
#define SRC_HELLO_H

class hello
{
public:
hello();
~hello();
};

#endif // SRC_HELLO_H
  • hello.cpp
#include "hello.h"
#include <iostream>

using std::cout;
using std::endl;

hello::hello()
{
cout << "hello, makefile!" << endl;
}

hello::~hello()
{
cout << "goodbye, makefile!" << endl;
}
  • main.cpp
#include <iostream>
#include "hello.h"
using namespace std;

int main()
{
hello h;
return 0;
}

用 vim 创建文件名为 makefile 的文件:

#可执行文件 hello 由中间目标文件 main.o 和 hello.o 链接得到
hello: main.o hello.o
# 打印一句话
echo "Begin to link main.o and hello.o..."
# 链接 main.o 和 hello.o 生成可执行文件 hello 的命令行
g++ main.o hello.o -o hello
# 打印一句话
echo "main.o and hello.o have been linked..."
#中间目标文件 hello.o 由 hello.cpp 编译得到
hello.o: hello.cpp
# 打印一句话
echo "Begin to compile hello.o..."
# 编译 hello.cpp 生成中间目标文件 hello.o
g++ -c hello.cpp
# 打印一句话
echo "hello.o has been compiled..."
main.o: main.cpp
# 打印一句话
echo "Begin to compile main.o..."
# 编译 main.cpp 生成中间目标文件 main.o
g++ -c main.cpp
# 打印一句话
echo "main.o has been compiled..."

在当前路径下,输入并执行 ​​make​​ 命令,控制台输出:

Begin to compile main.o...
main.o has been compiled...
Begin to compile hello.o...
hello.o has been compiled...
Begin to link main.o and hello.o...
main.o and hello.o have been linked...

此时,当前路径下生成中间目标文件 hello.omain.o 和可执行文件 hello ,执行 hello 文件:

./hello

此时,控制台输出:

hello, makefile!
goodbye, makefile!

makefile 删除编译过程中产生的中间目标文件

在上一 part 的 makefile 文件末尾加上 ​​clean​​ 标签及相关清理中间目标文件的,命令行,就可以在生成最终文件后自动删除相关中间文件:

clean:
rm -f main.o hello.o

则原文件变为:

#可执行文件 hello 由中间目标文件 main.o 和 hello.o 链接得到
hello: main.o hello.o
# 打印一句话
echo "Begin to link main.o and hello.o..."
# 链接 main.o 和 hello.o 生成可执行文件 hello 的命令行
g++ main.o hello.o -o hello
# 打印一句话
echo "main.o and hello.o has been linked..."
#中间目标文件 hello.o 由 hello.cpp 编译得到
hello.o: hello.cpp
# 打印一句话
echo "Begin to compile hello.o..."
# 编译 hello.cpp 生成中间目标文件 hello.o
g++ -c hello.cpp
# 打印一句话
echo "hello.o has been compiled..."
main.o: main.cpp
# 打印一句话
echo "Begin to compile main.o..."
# 编译 main.cpp 生成中间目标文件 main.o
g++ -c main.cpp
# 打印一句话
echo "main.o has been compiled..."
# 清理中间目标文件
clean:
rm -f main.o hello.o

执行 make 命令后,显式执行 ​​make clean​​。此时当前路径下只有可执行文件 hello,而没有相关中间目标文件。

后记

本文主要是为从零开始学习 makefile 抛砖引玉, 相关内容尽量简单处理,详细介绍,让新手可以跟着一步一步的操作。
因此,本文可能对有一定基础的童鞋来说有一点冗长。见谅。

另外,点击下列参考文献的名称就可以跳转到相关下载页面。相关细节,参考文献中有具体的介绍。

参考文献

  • ​​跟我一起写 Makefile, 陈浩​​
  • ​​GNU make​​