在实际开发中,项目的源代码文件比较多,按类型、功能、模块分别存放在不同的目录和文件中,哪些文件需要先编译,那些文件后编译,那些文件需要重新编译,还有更多更复杂的操作。
make是一个强大的实用工具,用于管理项目的编译和链接。make需要一个编译规则文件makefile,可实现自动化编译。
一、app/demo01.cpp
#include "public.h" // 包含通用函数和类的头文件。
#include "myapi.h" // 包含另一个通用函数和类的头文件。
using namespace std;
int main()
{
func(); // 调用通用的函数。
func1(); // 调用另一个通用的函数。
AA a; // 用通用类声明对象。
a.show(); // 调用对象的方法。
BB b; // 用另一个通用类声明对象。
b.show(); // 调用对象的方法。
}
二、app/makefile
INCLUDEDIR=-I/home/wucz/tools -I/home/wucz/api
LIBDIR=-L/home/wucz/tools -L/home/wucz/api
all:demo01 demo02 demo03
demo01:demo01.cpp
g++ -o demo01 demo01.cpp $(INCLUDEDIR) $(LIBDIR) -lpublic -lmyapi
cp demo01 /tmp/.
demo02:demo02.cpp
g++ -o demo02 demo02.cpp $(INCLUDEDIR) $(LIBDIR) -lpublic -lmyapi
demo03:demo03.cpp
g++ -o demo03 demo03.cpp $(INCLUDEDIR) $(LIBDIR) -lpublic -lmyapi
clean:
rm -f demo01 demo02 demo03
这段代码是一个简单的 Makefile,用于编译和链接三个 C++ 源文件(demo01.cpp,demo02.cpp,demo03.cpp),并生成对应的可执行文件。
让我来解释一下每个部分的含义:
1. `INCLUDEDIR=-I/home/wucz/tools -I/home/wucz/api`:定义了包含文件的路径,-I 选项告诉编译器在哪里搜索头文件。
2. `LIBDIR=-L/home/wucz/tools -L/home/wucz/api`:定义了库文件的路径,-L 选项告诉链接器在哪里搜索库文件。
3. `all:demo01 demo02 demo03`:声明了一个名为 "all" 的伪目标,它依赖于 demo01、demo02 和 demo03 这三个目标,表示当我们运行 `make all` 时,会依次编译这三个目标。
4. `demo01:demo01.cpp`:定义了一个目标 demo01,它依赖于 demo01.cpp 文件。当 demo01.cpp 文件被修改时,make 会重新编译 demo01。
5. 接下来的几行是编译和链接的命令,通过使用 `g++` 命令编译对应的源文件,并指定了包含文件路径 (`$(INCLUDEDIR)`) 和库文件路径 (`$(LIBDIR)`),以及所需要链接的库文件 (`-lpublic -lmyapi`)。
6. `cp demo01 /tmp/.`:将生成的可执行文件 demo01 复制到 /tmp 目录下。
7. 类似的规则也适用于 demo02 和 demo03。
8. `clean:`:定义了一个名为 "clean" 的目标,用于清理生成的可执行文件。执行 `make clean` 时,会删除所有生成的可执行文件。
这就是这个 Makefile 的基本结构和功能。
三、tools/public.h
// 通用函数和类的头文件。
#include <iostream>
// 声明一个通用的函数。
void func();
// 声明一个通用的类。
class AA
{
public:
void show();
};
四、tools/public.cpp
// 通用函数和类的代码实现文件。
#include "public.h"
using namespace std;
// 通用函数的代码实现。
void func()
{
cout << "升级了调用了func()函数。\n";
}
// 通用类的代码实现。
void AA::show()
{
cout << "升级了我是一只傻傻鸟。\n";
}
五、tools/makefile
# 指定编译的目标文件是libpublic.a和libpublic.so
all:libpublic.a \
libpublic.so
# 编译libpublic.a需要依赖public.h和public.cpp
# 如果被依赖文件内容发生了变化,将重新编译libpublic.a
libpublic.a:public.h public.cpp
g++ -c -o libpublic.a public.cpp
libpublic.so:public.h public.cpp
g++ -fPIC -shared -o libpublic.so public.cpp
# clean用于清理编译目标文件,仅在make clean才会执行。
clean:
rm -f libpublic.a libpublic.so
六、api/myapi.h
// 另一个通用函数和类的头文件。
#include <iostream>
// 声明一个通用的函数。
void func1();
// 声明一个通用的类。
class BB
{
public:
void show();
};
七、api/myapi.cpp
// 另一个通用函数和类的代码实现文件。
#include "myapi.h"
using namespace std;
// 通用函数的代码实现。
void func1()
{
cout << "调用了func1()函数。\n";
}
// 通用类的代码实现。
void BB::show()
{
cout << "你是一只傻傻鸟。\n";
}
八、api/makefile
# 指定编译的目标文件是libmyapi.a和libmyapi.so
all:libmyapi.a libmyapi.so
# 编译libmyapi.a需要依赖myapi.h和myapi.cpp
# 如果被依赖文件内容发生了变化,将重新编译libmyapi.a
libmyapi.a:myapi.h myapi.cpp
g++ -c -o libmyapi.a myapi.cpp
libmyapi.so:myapi.h myapi.cpp
g++ -fPIC -shared -o libmyapi.so myapi.cpp
# clean用于清理编译目标文件,仅在make clean才会执行。
clean:
rm -f libmyapi.a libmyapi.so