开始学习makefile,干学效果不好,手上项目有限,只能随便自己编几个小项目,顺带用博客记录下学习历程,说不定碰上大佬能指点一二。
目前已经学习了一段时间,对makefile有了些许了解。这对我这个windows c++程序员算是一个全新的挑战。
不管怎么说,慢慢学吧,不指望一下就学会,按需学习吧。
自建小项目
使用的Ubuntu 20.04.1 LTS系统。
想法是,先在testso下生成my_addition.cpp和my_subtraction.cpp的动态链接库so文件。再从根目录下通过调用上述so文件来生成test应用程序。而且只需要在根目录下就能控制所有的makefile的生成和清理。
项目树如下所示
├── makefile
├── test.cpp
└── testso
├── inc
│ ├── my_addition.h
│ └── my_subtraction.h
├── makefile
└── src
├── my_addition.cpp
└── my_subtraction.cpp
其中,test.cpp
#include <stdio.h>
#include "./testso/inc/my_addition.h"
#include "./testso/inc/my_subtraction.h"
int main()
{
int a = 10;
int b = 5;
printf("%d + %d = %d\n", a,b,myAdd(a,b));
printf("%d - %d = %d\n", a,b,mySub(a,b));
return 0;
}
my_addition.cpp
#include "../inc/my_addition.h"
int myAdd(int num1, int num2)
{
return num1+num2;
}
my_subtraction.cpp
#include "../inc/my_subtraction.h"
int mySub(int num1, int num2)
{
return num1-num2;
}
生成so文件
先将testso文件夹下的cpp生成so文件。
testso文件夹下makefile文件如下
SRC_DIR = ./src #cpp文件所在目录
TAR := test.so #要生成的目标
COM := g++ #使用的编译器
SRC = $(wildcard $(SRC_DIR)/ *.cpp) #将生成目标所需要的所有cpp文件展开,等价my_addition.cpp my_subtraction.cpp
OBJ = $(SRC:.cpp=.o) #展开与cpp文件同名的o文件,等价my_addition.o my_subtraction.o
#CFLAGS = -I./inc #引入头文件,但是好像没用,就注释了
#test.so为目标,依赖my_addition.o和my_subtraction.o两个文件,而这两个文件并不存在,因此makefile会继续寻找两个文件的依赖关系。
$(TAR):$(OBJ) #目标(test.so):依赖(o文件)
$(COM) -fPIC -shared $^ -o $(TAR) #g++编译指令
clean:
rm -f $(SRC_DIR)/*.o test.so
直接在testso目录下make就能得到so文件
生成目标应用程序
目标是在根目录下生成test应用程序。
根目录下makefile如下
TAR := test
COM := g++
MOD_DIR = ./testso
OBJ = test.o #不知道为啥,写成 $(wildcard *.o) 就是不能通过编译
OBJ += ./testso/test.so
#不是很理解 $(MOD_DIR) 这里的用法
all:$(MOD_DIR) $(TAR)
#调用子目录的makefile,-C dir 大写C,进入指定文件夹dir
$(MOD_DIR):ECHO
make -C $@
#不是很理解这段
ECHO:
@echo $@
$(TAR):$(OBJ)
$(COM) $(OBJ) -o $(TAR)
#调用子目录的clean
CLEANDIR:ECHO
make -C $(MOD_DIR) clean
.PHONY : clean
clean:CLEANDIR
rm -f *.o test
到此,test应用程序就能通过根目录下的makefile直接生成和清除了。
总结
稍微总结下:
- 要写好makefile,不单要了解makefile,还要学好gcc编译规则;
- makefile完全按照 目标:依赖 原则;
- $(wildcard *.o) 不知道为啥,就是不能通过编译;
- 不是很理解 $(MOD_DIR) 这里的用法,这里应该是个文件夹,为啥也能做目标。