工程管理与makefile

一、为什么需要makefile和make

一个工程中的源文件可能很多,按照类型、功能、模块分别放在若干个目录中,为了有效地管理软件工程,更高效地编译整个工程,需要用到makefile 和 make 命令工具。Linux 程序员须学会写makefile,使用GNU make 来构建和管理自己的软件工程,利用makefile 进行编译,已成为了一种在工程方面的常见编译方法。makefile 带来的好处是“自动化编译”,一旦写好,只需要一个make 命令,整个工程完全自动编译,极大提高软件开发的效率。

二、makefile 主要编写规则

2.1编写格式

Target:Dependencies
(tab)命令
(tab)命令

例如:

prinA.cpp 包含prinA.h

printB.cpp 包含printB.h

main.cpp 包含printA.h printB.h

makefile:

main:main.o printA.o printB.o
g++ -o main main.o printA.o printB.o
main.o:main.cpp
g++ -c main.cpp
printA.o:printA.cpp
g++ -c printA.cpp
pritnB.o:printB.cpp
g++ -c printB.cpp
.PHONY : clean
clean:
rm *.o main

“.PHONY”表示,clean是个伪目标文件。

执行:make

g++ -c -o main.o main.cpp

g++ -c -o printA.o printA.cpp

g++ -c -o printB.o printB.cpp

g++ -o main main.o printA.o printB.o

生成 main.o pritnA.o printB.o main

执行:make clean

rm *.o main

删除 所有后缀为.o的文件 和 main 文件

2.2 让make 自动推导

GNU的make很强大,它可以自动推导文件以及文件依赖关系后面的命令,于是我们就没必要去在每一个 .o 文件后都写上类似的命令,因为,我们的make会自动识别,并自己推导命令。

利用make的自动推导,可以把makefile 简化

简化版makefile:

main:main.o printA.o printB.o
g++ -o main main.o printA.o printB.o
.PHONY : clean
clean:
rm *.o main

只要make 看到一个.o文件,它就会自动把其依赖项.c/.cpp 加在依赖关系中,并且推导出命令:

gcc/g++ -c -o .o .c/.cpp

执行make,便可以看到推导和编译结果:

g++ -c -o main.o main.cpp

g++ -c -o printA.o printA.cpp

g++ -c -o printB.o printB.cpp

g++ -o main main.o printA.o printB.o

2.3 使用变量

要设定一个变量,只要在一行的前端写下这个变量的名字,后面跟一个"=" 号,后面跟要是设定的这个变量的值就可.以后要引用这个变量,只写一个"$"符号,后面是在括号里的变量名即可.

在makefile中使用变量:

OBJS = main.o printA.o printB.o
XX = g++
CC = gcc
CFLAGS = -Wall -g -O
TARGET = main
$(TARGET):$(OBJS)
$(XX) -o $(TARGET) $(CFLAGS) $(OBJS)
.PHONY :clean
clean:
rm $(TARGET) $(OBJS)

CFLAGS = -Wall -g -O: 配置编译器设置,并把它复制给CFLAGS变量,其中每个部分含义为:

  • -Wall :输出所有警告信息
  • -O: 编译时进行优化
  • -g:便是编译debug版本

亦可使用常用的内部变量:

  • $@:扩展成当前规则的目的文件名
  • $<:扩展成依靠列表中的第一个依靠文件
  • $^:扩展成整个依靠的列表

使用内部变量makefile:

OBJS = main.o printA.o printB.o
XX = g++
CC = gcc
CFLAGS = -Wall -g -O
TARGET = main
$(TARGET):$(OBJS)
$(XX) -o $@ $(CFLAGS) $^
.PHONY :clean
clean:
rm $(TARGET) $(OBJS)

2.4 使用函数 wildcard patsubst

wildcard 用法:

$(wildcard PATTERN...)

在makefile 中,它被展开为已经存在的,使用空格分开的,匹配此模式的所有文件列表.如果不存在任何符合此模式的文件,函数会忽略模式字符并返回空

例子:

SOURCES = $(wildcard *.c *.cpp)

表示产生一个所有以.c .cpp 结尾的文件列表,然后存入变量SOURCES里

patsubst 用法:

(patsubst %.src , %.dst , $(dir))

表示用patsubst 把$(dir)中的变量符合后缀是 .src 全部替换成 .dst

例子:

$(patsubt %.c, %o,$(patsubt %.cpp, %.o $(SOURCES)))

这是一个嵌套使用,表示先把 $(SOURCES)中后缀符合为.cpp 的全部替换成.o,然后再从中把后缀符合为.c 的全部替换成 .o

整体实现把 $(SOURCES)中后缀符合为.c 和.cpp 的全部替换成.o

字符 '%' 的意思是匹配零或若干个字符

使用函数的makefile:

XX = g++
CC = gcc
CFLAGS = -Wall -g -O
TARGET = main SOURCES = $(wildcard *.cpp )
OBJS = $(patsubst %.cpp,%.o, $(SOURCES)) $(TARGET):$(OBJS)
$(XX) -o $@ $(CFLAGS) $^ .PHONY :clean
clean:
rm $(TARGET) $(OBJS)

:以上假定所有的文件都在同一个目录下,且没有子目录

2.5 多目录下编译

在做项目时,一般文件都会分几个目录来存放:

include/ bin/ src/ obj/ lib/ tools/

笔者习惯建工程时,创建前面4个目录

mkdir include bin src obj

include/ 存放头文件

bin/ 存放可执行文件

obj/ 存放后缀为.o 的文件

src/ 存放.c 和.cpp 的源文件

多文件目录工程管理的makefile:

BIN = ./bin
SRC = ./src
OBJ = ./obj
INCLUDE =./include
SOURCES = $(wildcard $(SRC)/*.cpp )
#要加notdir,去掉选定源文件的目录,否则替换会出错
OBJS = $(patsubst %.cpp,$(OBJ)/%.o, $(notdir $(SOURCES))) TARGET = $(BIN)/main XX = g++
#-I$(INCLUDE) :$(INCLUDE)下寻找头文件
CFLAGS = -Wall -g -I$(INCLUDE)
#用所有的.o文件生成目的可执行文件
$(TARGET):$(OBJS)
$(XX) -o $@ $^
#生成各个.o 文件
$(OBJ)/%.o:$(SRC)/%.cpp
$(XX) -c $(CFLAGS) -o $@ $< .PHONY :clean
clean:
rm $(TARGET) $(OBJS)

转载请注明原文出处:

http://www.cnblogs.com/pz-Feng/p/8289410.html

若有错误不当之处,望大家指正,谢谢!

学习总结:工程管理与makefile的更多相关文章

  1. 工程管理之makefile与自动创建makefile文件过程

    (风雪之隅 http://www.laruence.com/2009/11/18/1154.html) Linux Makefile自动编译和链接使用的环境 想知道到Linux Makefile系统的 ...

  2. Makefile 工程管理

    Makefile 工程管理 Makefile 规则 --变量 在Makefile中,用户除了可以自己定义变量外,还可以使用存在系统已经定义好的默认变量 $^:代表所有的依赖文件 $@:代表目标 $&l ...

  3. ARM裸机开发之交叉工具链和MakeFile工程管理

    一.交叉工具链 嵌入式Linux开发采用交叉开发,简单来说就是在宿主机(PC机)上面编译出能够在其他硬件平台上面运行的程序.在这个过程中,需要用到许多的交叉工具,这些交叉工具的集合就叫做交叉工具链.下 ...

  4. 使用BLADE构建c++工程管理

    使用BLADE构建c++工程管理 字数764 阅读2753 评论2 喜欢4 一. c++工程依赖管理 之前在百度一直使用comake2构建c++项目,十分方便.免去了手写Makefile的痛苦,很多项 ...

  5. emacs工程管理,cedet ede插件自动构建Make,Automake

    鉴于自己一直都是在做客户端开发方面的工作,服务端很多知识都随着时间淡忘了,最近有一个计划,用一些时间补一下基础.所以早上很早就起床,花了一点时间大致浏览了一下BSD socket的相关API,然后用G ...

  6. make工程管理器

    1.概述 大型程序中,人们希望工具自动识别修改的文件,而且不需要输入冗长的命令,就可以进行编译链接等操作,于是make工程管理器应运而生. make可以自动识别文件时间戳,只处理修改的文件: make ...

  7. go语言基础之工程管理和工作区介绍

    1.工程管理 在实际的开发工作中,直接调用编译器进行编译和链接的场景是少而又少,因为在工程中不会简单到只有一个源代码文件,且源文件之间会有相互的依赖关系.如果这样一个文件一个文件逐步编译,那不亚于一场 ...

  8. Qt工程管理

    Qt Creator工程管理Qt Creator以工程项目的方式对源码进行管理一个Qt Creator工程包含不同类型的文件 .pro项目描述文件.pro.user用户配置描述文件 //由Qt Cre ...

  9. Linux工程管理器——make

    一.定义 工程管理器,顾名思义,是指管理较多的文件 Make工程管理器也就是个“自动编译管理器”,这里的“自动”是指它能构根据文件时间戳自动发现更新过的文件而减少编译的工作量,同时,它通过读入Make ...

随机推荐

  1. 自学Zabbix3.5.6-监控项item-Value mapping值映射

    zabbix为了显示更人性化的数据,在使用过程中,我们可以将获取到得数据映射为一个字符串.比如,我们写脚本监控MySQL是否在运行中, 一般返回0表示数据库挂了,1表示数据库正常,还有各种各样的监控都 ...

  2. git 设置和取消代理

    # 设置ss git config --global http.proxy 'socks5://127.0.0.1:1080' git config --global https.proxy 'soc ...

  3. [数据结构]C语言链表实现

    我学数据结构的时候也是感觉很困难,当我学完后我发现了之所以困难时因为我没有系统的进行学习,而且很多教授都只是注重数据结构思想,而忽略了代码方面,为此我写了这些博文给那些试图自学数据结构的朋友,希望你们 ...

  4. HttpClient4.5 post请求xml到服务器

    1.加入HttpClient4.5和junit依赖包 <dependencies> <dependency> <groupId>org.apache.httpcom ...

  5. 让 kibana 后台启动的方案

    为了解决启动kibana后关闭shell终端kibana自动关闭的问题,记录2种解决方案,试验后均可行. 假设kibana安装的目录为 /usr/local/kibana/ 方案一: 使用nohup ...

  6. [编织消息框架][JAVA核心技术]动态代理应用11-水平扩展实现

    由于示例,远程服务地址配置在properties文件,通过QMConfig类加载,最优方式是上节介绍过,放在共享内存上,只需要维护一份数据即可,如放在redis上 /** 服务地址<servic ...

  7. thinkphp 官方文件执行引入流程

    官方手册上的执行流程图: 系统流程 用户URL请求 调用应用入口文件(通常是网站的index.php) 载入框架入口文件(ThinkPHP.php) 记录初始运行时间和内存开销 系统常量判断及定义 载 ...

  8. C#语言和SQL Server 数据库处理

    ---恢复内容开始--- 第七章 用表组织数据 1:数据性分类: 1>实体完整性的约束:检验每行数据是否符合要求 检验每列数据是否符合要求 2>域完整性约束:给定列输入的有效性 3> ...

  9. JAVA NIO学习四:Path&Paths&Files 学习

    今天我们将学习NIO 的最后一章,前面大部分涉及IO 和 NIO 的知识都已经讲过了,那么本章将要讲解的是关于Path 以及Paths 和 Files 相关的知识点,以对前面知识点的补充,好了言归正传 ...

  10. 2017 年终总结 & 2018 年度计划

    不立几个 Flag,都不知道怎么作死 2017 年度计划完成情况: 1.健身时间不少于350天:  未完成 中断了22天,实际运动 343天   2.至少每个月看一本书:  及格 <切尔诺贝利的 ...