ICode9

精准搜索请尝试: 精确搜索
首页 > 编程语言> 文章详细

C++之Makefile语法与写法

2022-04-23 22:31:24  阅读:203  来源: 互联网

标签:aa bb make Makefile PHONY C++ 目标 规则 写法


始、Makefile的规则

教学博客 系统性的博客2

关键:规则的嵌套——会先完成规则的先验条件

   变量使用时都用${ }包围起来,才能取到变量的实际值,否则取到的就是一个值为变量名的东西了。变量能赋值的,要不然怎么叫变量呢

  这里的变量在实际执行时,会被换成它们的实际值,变量名起简化和占位符的作用。

 

一、变量与函数

1. 函数notdir,wildcard和patsubst

博客

这三个都是函数名,函数格式为:return = $(func arg1,arg2,..),即 $ 和 () 的结合。

例:将当前文件夹中所有以 .c为后缀的文件名替换为以 .o为后缀,并返回一个以空格为间隔的列表

SRC = $(patsubst %.c,%.o,${./})

 2. 逻辑判断  ——参考博客

  ifeq (arg1, arg2):当arg1 == arg2 时,为true。

# 1. 连续的结构,只需要一个endif
ifeq (${mode}, TE)
    EXECUTABLE := te
else ifeq (${mode}, TR)
    EXECUTABLE := tr 
endif

# 2. 非连续的两个结构,每个结构都需要一个endif
ifeq (${mode}, TE)
    EXECUTABLE := te
endif
ifeq (${mode}, TR)
    EXECUTABLE := tr
endif

 

 

二、Makefile中的自动化变量$@, $^, $< , $?, $%, $+, $* 等的含义  ——参考博客

$@   表示目标文件
$^   表示所有的依赖文件
$+   这个变量很像“$^”,也是所有依赖目标的集合。只是它不去除重复的依赖目标
$<   表示第一个依赖文件
$?   表示比目标还要新的依赖文件列表 
$%   仅当目标是函数库文件时,表示规则中的目标成员名。例如,如果一个目标是“foo.a(bar.o)”,那么,“$%”就是“bar.o”,“$@”就是“foo.a”。如果目标不是函数库文件(Unix下是[.a],Windows下是[.lib]),那么,其值为空

$*   这个变量表示目标模式中“%”及其之前的部分。如果目标是“dir/a.foo.b”,并且目标的模式是“a.%.b”,那么,“$*”的值就是“dir/a.foo”。这个变量对于构造有关联的文件名是比较有较。
    如果目标中没有模式的定义,那么“$*”也就不能被推导出,但是,如果目标文件的后缀是make所识别的,那么“$*”就是除了后缀的那一部分。例如:如果目标是“foo.c”,因为“.c”是make所能识别的后缀名,所以,“$*”的值就是“foo”。
    这个特性是GNU make的,很有可能不兼容于其它版本的make,所以,你应该尽量避免使用“$*”,除非是在隐含规则或是静态模式中。如果目标中的后缀是make所不能识别的,那么“$*”就是空值。

 

三、规则  ——参考 博客

1. makefile中的规则的基本格式如下:

targets:dependeds
    commands

targets:要生成的文件(多个文件则以空格分开),或者是一个动作,可用称为伪目标;若target为空(未赋值的变量),则该规则无效

dependeds:执行此规则所必须的依赖,可以是其它target,形成递归嵌套;所有依赖都满足后才会执行command生成target;

command:规则所执行的命令,以tab键开始;规则后的所有连续的 以tab键开始的行 都会被视作command。tab、多个空格 二者是不等效的

eg:

...

main.o:main.cpp
    gcc -o main.o ...

test:test.o
  ...

.PHONY:clean
clean:
  rm -rf ...

  

  一次执行makefile,有一个最终目标,这个最终目标可能会带动其它依赖目标的生成。

2. 规则的执行:

1)直接执行 make 时,先查找makefile中的第一个规则,以这个规则的目标(若有多个目标,则以第一个)为最终目标,完成这个规则的执行;  ==》如果要执行其它规则,需要指定目标,如 make test、 make clean。

2)依赖项dependeds将从左往右检查是否存在,如果需要执行其它嵌套的规则,会先执行,若不存在且无生成规则,则停止并放弃检查后面的依赖项。

3)除了第一个规则或者指定的规则,.PHONY指定的目标也会在执行时生成。

  

3. 伪目标

  上面的clean是伪目标,所以也不会真正生成clean文件。由于它没有依赖项,make无法判断伪目标的依赖关系,所以要执行相关命令需要显式地指定目标,如:make clean,这种规则每次指定时都一定会执行。

  .PHONY可以将目标显示地声明为伪目标。即使真的有一个文件和伪目标同名,.PHONY指定的伪目标的规则在执行时也不会生成文件。

  .PHONY也可以用于指定一个伪目标,该伪目标依赖于多个真实目标,如下: 

.PHONY:all  # .PHONY后面跟着all,all没有具体的生成命令,但是all依赖于aa和bb,故而aa、bb会先生成
all:aa bb
aa: xxx
  ...

   伪目标每次要生成时都会生成,无论是否有更改;其它规则如果是未更改则不会重新生成。

* 遇到一个问题,以上面的.PHONY:all为例,会出现  make: Nothing to be donefor'all'. 

解决:改为以下写法即可达到每次make都重新执行规定的目标

.PHONY:all aa bb
all:aa bb

.PHONY不影响第一规则为默认规则,若.PHONY所在规则不是第一规则,其指定的规则用make是不会默认执行的。

  下面写法里,执行 make,则aa,bb都会生成,.PHONY行 和 伪目标all行可以调换顺序,等效。

.PHONY:all aa bb
all:aa bb
aa: xxx
  ...

  下面的例子中,执行 make,只有aa会生成。

aa: xxx
  ...
.PHONY:all aa bb
all:aa bb

 

四、参数传递

一个例子 :这个用 -D 传递进去是一个宏,这个宏也可以赋值 更多

-DDEBUG   #相当于在代码里面定义了 #define DEBUG 1
-DDEBUG=2  #相当于在代码里面定义了 #define DEBUG 2。

另一个例子

Makefile文件:
 
ARCH := $(shell arch)
 
ifeq ($(ARCH), "x86_64")
SETTING := 1
else
SETTING := 0
endif
 
CXX := g++ -std=c++11
CFLAGS := -Wall -g -O2 -D${SETTING}
ALL = main
OBJECT =  main.o
LIBS =
 
%.o:%.cpp
    $(CXX) -c $^ -o $@  $(LIBS) $(CFLAGS)
 
$(ALL):$(OBJECT)
    $(CXX) -o $@ $^ $(LIBS) $(CFLAGS)
 
.PHONY:clean
clean:
    rm -rf $(ALL) $(OBJECT)
// main.cpp
#include <iostream> using namespace std; int main(){ cout << "Hello World!" << endl; #ifdef SETTING cout<<"setting = 1"<<endl; #else cout<<"setting = 0"<<endl; #endif return 0; }

 

也可以用传统的传参方法,传给main函数的argv。

 

标签:aa,bb,make,Makefile,PHONY,C++,目标,规则,写法
来源: https://www.cnblogs.com/grainrain/p/15394676.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有