Makefile学习(四)提取makefile的公共部分,简化makefile

在上节我们完成了通过make编译多个项目,但是我们发现,两个项目里其实有非常多的重复部分,并且每个项目的makefile都非常长。

于是想到能不能把公共部分都提取出来,自定义一个makefile配置

于是本章节通过在项目中包含一个公共的makefile来实现makefile的简化

(一)成果预览

首先看看简化后的Test_s_lib的makefile

ifeq ($(STATIC),1)
LIBTYPE=.a
else
LIBTYPE=.so
endif
include ../makefile.mk

这是简化后的Test_d_lib的makefile

LIBTYPE=.so
include ../makefile.mk

是的一共就这么几行!!!比起原来的少了非常多

(二)编写配置用的makefile

(1)提取TARGET

再每个makefile项目里都需要目标项和目标依赖项,而且基本每个目标和缪表依赖项都和目录名一致,除了多了后缀名,于是我们可以将其提取出来

通过ifndef来判断是否已经确定目标

ifndef TARGET
TARGET:=$(notdir $(shell pwd)) #test_include
endif

在上一章节中提到过可以通过$(shell pwd)获取到当前路径

这里再引入一个新的makefile函数 :notdir 

1、notdir函数:

作用是从文件路径中提取文件名部分,去掉路径部分。

当有一个文件路径/home/user/documents/file.txt,

使用notdir函数后,$(notir /home/user/documents/file.txt)  返回的结果是file.txt

(2)提取编译器环境变量

变量的意思已经再第二章节解释过,这就不在解释一遍啦


Makefile学习(二)加入动态编译库和静态编译库

CXXFLAGS:=$(CXXFLAGS) -I../../include -std=c++17 
LDFLAGS:=$(LDFLAGS) 
LDLIBS:=$(LDLIBS) -lpthread 

-std=c++17是告诉编译器要使用 C++ 17 标准来编译代码。

这里只是引入原项目中的变量,后面还会对变量进一步设置

(3)提取目标依赖项

SRCS:=$(wildcard *.cpp *.cc *.c)
OBJS:=$(patsubst %.cpp,%.o,$(SRCS))
OBJS:=$(patsubst %.cc,%.o,$(OBJS))
OBJS:=$(patsubst %.c,%.o,$(OBJS)) 

1、wildcard 函数:

用于获取符合特定模式的文件名列表。它的主要作用是在构建过程中自动发现源文件或其他相关文件,从而方便地管理文件依赖关系。
$(wildcard PATTERN),其中PATTERN是一个包含通配符的文件名模式。通配符通常有*(匹配零个或多个任意字符)例如,$(wildcard *.c)会返回当前目录下所有以.c结尾的文件列表。

当Makefile中的文件列表依赖于wildcard函数获取的结果时,添加或删除符合模式的文件后,make命令会自动重新构建相关的目标。这对于管理项目中的文件更新非常方便,

2、patsubst函数:

在 Makefile 中,patsubst是一个文本处理函数,用于模式替换。它的主要作用是将文本中的一种模式替换为另一种模式。
语法格式为:$(patsubst <pattern>,<replacement>,<text>)。
其中<pattern>是要匹配的模式,<replacement>是替换后的内容,<text>是要进行处理的原始文本,可以是变量或者字符串列表。

即我们这里第一个patsubst是把SRCS里的.cpp文件替换成对应的.o文件

后面的也都一样

(4)区分动态静态库

ifeq ($(LIBTYPE),.so)
	TARGET:=lib$(strip $(TARGET)).so  
	LDLIBS:=$(LDLIBS) -shared
	CXXFLAGS:=$(CXXFLAGS) -fPIC
endif
ifeq ($(LIBTYPE),.a)
	TARGET:=lib$(strip $(TARGET)).a  
endif

变量LIBTYPE是在原项目中设定变量,用于确定要编译为什么库

ifeq的功能是对比两个字符是否相等,在上一章节也已经提到过

当传进来的LIBTYPE是.so,说明要编译的是动态库

动态库和静态库用到的变量和参数也都已经在上一章节讲解过,这里说下用到的新函数strip

1、strip函数

它的主要作用是去除字符串开头和结尾的空格(包括空格、制表符等空白字符)。这在处理文件路径、变量值等可能包含多余空白字符的字符串时非常有用。

(5)目标生成

$(TARGET):$(OBJS)
ifeq ($(LIBTYPE),.a)
	$(AR) -cvr $@ $^
else
	$(CXX) $(LDFLAGS) $^ -o $@  $(LDLIBS)
endif

这里也通过LIBTYPE来决定是生成动态库路还是静态库

变量和参数也都在上一章节提到过啦

Makefile学习(三)通过make编译多个项目

(6)完整配置makefile

最后的clean和伪目标的设置也已经用过很多次,就不再提了

ifndef TARGET
TARGET:=$(notdir $(shell pwd)) #test_include
endif

CXXFLAGS:=$(CXXFLAGS) -I../../include -std=c++17 
LDFLAGS:=$(LDFLAGS) 
LDLIBS:=$(LDLIBS) -lpthread 


SRCS:=$(wildcard *.cpp *.cc *.c) 
OBJS:=$(patsubst %.cpp,%.o,$(SRCS)) 
OBJS:=$(patsubst %.cc,%.o,$(OBJS))
OBJS:=$(patsubst %.c,%.o,$(OBJS)) 

ifeq ($(LIBTYPE),.so) 
	TARGET:=lib$(strip $(TARGET)).so  
	LDLIBS:=$(LDLIBS) -shared
	CXXFLAGS:=$(CXXFLAGS) -fPIC
endif
ifeq ($(LIBTYPE),.a)
	TARGET:=lib$(strip $(TARGET)).a  
endif


$(TARGET):$(OBJS)
ifeq ($(LIBTYPE),.a) 
	$(AR) -cvr $@ $^
else
	$(CXX) $(LDFLAGS) $^ -o $@  $(LDLIBS)
endif

#rm -r test.o test

clean:
	$(RM) $(OBJS)  $(TARGET) 

.PHONY: clean 

(三)使用配置的makefile

把上一章节Test_s_lib的makefile和Test_d_lib的makefile都换成这章的makefile

ifeq ($(STATIC),1)
LIBTYPE=.a
else
LIBTYPE=.so
endif
include ../makefile.mk
LIBTYPE=.so
include ../makefile.mk

 然后

把makefile.mk放在外面那个目录

再执行上章节写好的make就可以直接编译啦

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值