C++进阶3:Makefile入门

2022-07-08 08:36:11

0、作用

Makefile文件告诉Make怎样编译和连接成一个程序。

1、Makefiile基本语法与执行

1.1 示例

编译一个单文件HelloWorld.cpp

(1)编写Makefile

HelloWorld: HelloWorld.cpp
  g++ HelloWorld.cpp-o HelloWorld
clean:
  rm HelloWorld

(2)编译

make

(3)清空

make clean

1.2 构成

Makefile主要由多条规则构成,每条规则由三部分构成:目标(target)、依赖(prerequiries)和命令(command)。

1.3 格式

按如下格式编写Makefile

目标(target): 依赖(prerequiries)...
  命令(command)

(1)目标(target)通常是要产生的文件的名称,目标的例子是可执行文件或OBJ文件。目标也可是一个执行的动作名称,诸如‘clean’(仅仅表达动作的目标称为假想目标)。
(2)依赖是用来输入从而产生目标的文件,一个目标经常有几个依赖。
(3)命令是Make执行的动作,一个规则可以含有几个命令,每个命令占一行。
注意:
每个命令行前面必须是一个Tab字符,即命令行第一个字符是Tab。这是不小心容易出错的地方

1.4 说明:

(1)默认情况下,make最先执行第一条。
(2)使用make 目标名的方式,执行指定的规则。

2、Makefile多文件编译

2.1 示例

(1)string.h

#ifndef_STRING_H_#define_STRING_H_#include<iostream>usingnamespace std;#include<string.h>classString{public:String(constchar* cstr=NULL);String(const String& str);
    String&operator=(const String& str);~String();char*c_str()const{return m_data;}private:char* m_data;};
ostream&operator<<(ostream& os,const String& str);#endif// _STRING_H_

(2)string.cpp

#include"String.h"String::String(constchar* cstr/*= NULL*/){if(cstr){
        m_data=newchar[strlen(cstr)+1];strcpy(m_data, cstr);}else{
        m_data=newchar[1];*m_data='\0';}}String::String(const String& str){
    m_data=newchar[strlen(str.m_data)+1];strcpy(m_data, str.m_data);}
String& String::operator=(const String& str){//检测是否自我赋值if(this==&str)return*this;delete[] m_data;
    m_data=newchar[strlen(str.m_data)+1];strcpy(m_data, str.m_data);return*this;}String::~String(){delete[] m_data;}
ostream&operator<<(ostream& os,const String& str){
    os<< str.c_str();return os;}

(3)StringTest.cpp

#include"String.h"intmain(){
    String s1;
    Strings2("hello");
    Strings3(s1);//拷贝构造函数
    cout<< s3<< endl;
    s3= s2;//拷贝赋值函数
    cout<< s3<< endl;return0;}

(4)makefile

StringTest:StringTest.o String.o
  g++-o StringTest StringTest.o String.o
StringTest.o:StringTest.cpp String.h
  g++-c StringTest.cpp
String.o:String.cpp String.h
  g++-c String.cpp
clean:
  rm StringTest StringTest.o String.o

2.2 说明

make执行规则之前,检查依赖是否存在或者是否最新的。如果不是则执行依赖对应的规则,创建或者更新依赖。

3、使用变量简化makefile

**优点:**每次增加新的文件,需要在nakefile的很多地方增加依赖,容易导致遗漏。可以使用变量可以简化,避免这种出错的可能。
变量定义:变量=字符串
变量使用:$(变量名)

3.1 示例

(1)makefile

OBJS= StringTest.o String.o

StringTest:$(OBJS)
  g++-o StringTest $(OBJS)
StringTest.o:StringTest.cpp String.h
  g++-c StringTest.cpp
String.o:String.cpp String.h
  g++-c String.cpp
clean:
  rm StringTest $(OBJS)

在makefile文件中使用名为objects, OBJECTS, objs, OBJS, obj, 或 OBJ的变量代表所有OBJ文件已是约定成俗。

3.2 说明

变量是定义一个字符串,在多处替代该字符串使用。

4、命令自动推导

编译.o文件这类非常普遍并且常用,规则也比较简单

文件名.o:文件名.cpp 头文件
  g++-c 文件名.cpp

make提供一种简化写法,可以自动推导出该规则

文件名.o:头文件

这种简化规则称为隐含规则,非简化规则成为具体规则。

4.1 示例

(1)makefile

OBJS= StringTest.o String.o

StringTest:$(OBJS)
  g++-o StringTest $(OBJS)
StringTest.o:String.h
String.o:String.h

clean:
  rm StringTest $(OBJS)

(2)小知识

通常,规则按照目标进行分组。规则也可以按照依赖分组。例如,例子中String.o和StringTest.o都依赖String.h。那么,可以这两个合并到一个规则中。

OBJS= StringTest.o String.o

StringTest:$(OBJS)
 g++-o StringTest $(OBJS)
StringTest.o String.o:String.h

clean:
 rm StringTest $(OBJS)

按照依赖分组规则可以减少规则数量,规则按照目标分组更符合我们日常思维习惯。

5、假想动作

表达动作的目标称为假想目标。通常规则会生成或者更新与目标的同名文件,但是假想目标不生成文件,只是作为几个命令组成特殊规则的名称。例如例子中的clean,只是执行清理动作。**如果,makefile同级目录存在与假象目标同名的文件(例如:clean),那么会导致命令不会被执行。**所以需要把目标显示声明为假想目标。

5.1 示例

(1)makefile

OBJS= StringTest.o String.o.PHONY: all clean

all:StringTest

StringTest:$(OBJS)
  g++-o StringTest $(OBJS)
StringTest.o:String.h
String.o:String.h

clean:
  rm StringTest $(OBJS)

(2)常用假想目标

6、通配符与变量

编译.o文件可以写成更通用的方式,使用我们之前已经定义好的变量$(OBJS),自动推导出需要生成的规则。

6.1 makefile

OBJS= StringTest.o String.o.PHONY: all clean

all:StringTest

StringTest:$(OBJS)
  g++-o StringTest $^
$(OBJS):%.o:%.cpp
  $(CXX)-c $(CXXFLAGS) $<-o $@.PHONY: clean

clean:
  rm StringTest $(OBJS)

6.2 说明

(1)通配符

通配符主要用于匹配文件名,makefile中使用%作为通配符。从匹配目标格式的目标名中依据通配符抽取部分字符串,再按照抽取字符串分配到每一个依赖格式中产生依赖名。例如,使用%.o:%.cpp。

(2)自动变量

自动变量是在规则每次执行时都基于目标和依赖产生新值的变量。下面是常用的自动变量。
在这里插入图片描述
在这里插入图片描述

(3)预定义变量

预定义变量是makefile已经定义好的变量,用户可以在makefile文件中改变变量的值。
程序名变量
在这里插入图片描述
程序运行参数的变量
在这里插入图片描述

7、其他

注释#
换行
回显命令@echo

8、总结

在这里插入图片描述

9、常见makefile的用法汇总

#规则:(命令构成的一组操作)
#默认只执行第一条规则 
#若想执行其他规则,make+命令名字
#目标:依赖
#	命令
##g++ overload.o Test.o

#只执行第一条规则,然后先找依赖在下面存在不存在,如果存在,先执行依赖,再执行第一条,依赖是串联规则执行的条件
#表示前面的TARGET,$^表示前面的OBJECTS,$<表示第一个依赖。

#前面的总的定义
TARGET=Test  #生成的文件名
OBJECTS= overload.o\
		  Test.o#变量做替换的#CXX=clang  CXX可以改成其他的编程方式,例如gcc等等
CXXFLAGS=-g #可以变成调试版本的.PHONY: clean
#虚假目标,用来无视其他干扰,只执行makefile里面的命令
#第一条规则,也是总的规则
all:$(TARGET)
$(TARGET):$(OBJECTS)
	@echo 生成可执行文件$(TARGET)
	$(CXX) $(CXXFLAGS) $^-o $@#overload.o:overload.cpp
# 	$(CXX) $(CXXFLAGS)-c $<#Test.o:Test.cpp
#  	$(CXX) $(CXXFLAGS)-c $<

#%表示通配符
#通配符推导
$(OBJECTS):%.o:%.cpp
	$(CXX) $(CXXFLAGS)-c $<

clean:
	@echo 清空文件
	$(RM) Test*.o
  • 作者:软软kk
  • 原文链接:https://blog.csdn.net/k0512/article/details/124275493
    更新时间:2022-07-08 08:36:11