1.1在这之前,我们需要了解程序的编译过程

a.预处理:检查语法错误,展开宏,包含头文件等

b.编译:*.c-->*.S

c.汇编:*.S-->*.o

d.链接:.o +库文件=*.exe

1.2体验在VC下程序的编译

a.先编译,在链接

b.修改了哪个文件,就单独编译此文件,在链接

c.修改了哪个头文件,就单独编译使用该头文件的源文件,在链接

1.3在linux下实现上述要求

2.编写一个测试的Makefile

2.1直接编译链接

gcc -o test a.c b.c

缺点:改变其中一个文件,还需要重新编译所有文件,最后链接,效率低

2.2编写一个通用的Makefile

核心:规则

目标:依赖1 依赖2...

  命令

命令的执行条件:

a.依赖文件比目标文件新

b.没有目标文件

2.2.1一个简单的Makefile文件

test:a.c b.c a.h
gcc -o test a.c b.c

缺点:当其中一个文件发生改变时,另一个文件又将从新编译链接

2.2.2针对上述,改为如下

test:a.o b.o
gcc -o test a.o b.o a.o : a.c
gcc -c -o a.o a.c b.o : b.c
gcc -c -o b.o b.c

缺点:a.如果test依赖于多个文件,将写许多代码。

b.修改a.h程序没有反应。

2.2.3

针对上述a,可将其改为通配符;针对b,可增加“a.o:a.c a.h”这段代码。

$@:表示目标;$^:表示全部依赖;$<:第一个依赖。

test:a.o b.o
gcc -o test a.o b.o a.o:a.c a.h %.o : %.c
gcc -c -o $@ $<

缺点:如果一个文件的头文件非常多,不可能一个一个列出来,应该生成一个依赖文件。

2.2.4生成依赖文件

wildcard:检查文件是否存在

-Wp,-MD:生成依赖文件

objs := a.o b.o

test:$(objs)
gcc -o test $^ # .a.o.d .b.o.d
dep_files := $(foreach f,$(objs),.$(f).d)//对于objs里的每个文件,生成对应的依赖文件。eg:a.o-->.a.o.d
dep_files := $(wildcard $(dep_files)) ifneq ($(dep_files),)
include $(dep_files)
endif %.o : %.c
gcc -Wp,-MD,.$@.d -c -o $@ $< clean:
rm *.o test

3.参照内核的Makefile和上述的test_Makefile,编写一个通用的Makefile

3.1子目录下的Makefile
   它最简单,形式如下:
obj-y += file.o
obj-y += subdir/
   
   "obj-y += file.o"表示把当前目录下的file.c编进程序里,
   "obj-y += subdir/"表示要进入subdir这个子目录下去寻找文件来编进程序里,是哪些文件由subdir目录下的Makefile决定。

注意: "subdir/"中的斜杠"/"不可省略

3.2顶层目录的Makefile:
   它除了定义obj-y来指定根目录下要编进程序去的文件、子目录外,主要是定义工具链、编译参数、链接参数──就是文件中用export导出的各变量。

CROSS_COMPILE = arm-linux-      //交叉编译工具链
AS = $(CROSS_COMPILE)as
LD = $(CROSS_COMPILE)ld
CC = $(CROSS_COMPILE)gcc
CPP = $(CC) -E
AR = $(CROSS_COMPILE)ar
NM = $(CROSS_COMPILE)nm STRIP = $(CROSS_COMPILE)strip
OBJCOPY = $(CROSS_COMPILE)objcopy
OBJDUMP = $(CROSS_COMPILE)objdump export AS LD CC CPP AR NM //导出变量
export STRIP OBJCOPY OBJDUMP CFLAGS := -Wall -O2 -g //编译选项
CFLAGS += -I $(shell pwd)/include LDFLAGS := -lm -lfreetype //链接选项 export CFLAGS LDFLAGS TOPDIR := $(shell pwd)
export TOPDIR TARGET := show_file obj-y += main.o
obj-y += display/
obj-y += draw/
obj-y += encoding/
obj-y += fonts/ all :
make -C ./ -f $(TOPDIR)/Makefile.build //打开文件,按照顶层目录下的Makefile.build来编译
$(CC) $(LDFLAGS) -o $(TARGET) built-in.o //link clean:
rm -f $(shell find -name "*.o")
rm -f $(TARGET) distclean:
rm -f $(shell find -name "*.o")
rm -f $(shell find -name "*.d")
rm -f $(TARGET)

3.3顶层目录的Makefile.build:
   这是最复杂的部分,它的功能就是把某个目录及它的所有子目录中、需要编进程序去的文件都编译出来,打包为built-in.o。

PHONY := __build
__build: obj-y :=
subdir-y := include Makefile
__subdir-y := $(patsubst %/,%,$(filter %/, $(obj-y)))
subdir-y += $(__subdir-y)
subdir_objs := $(foreach f,$(subdir-y),$(f)/built-in.o) cur_objs := $(filter-out %/, $(obj-y))
dep_files := $(foreach f,$(cur_objs),.$(f).d)
dep_files := $(wildcard $(dep_files)) ifneq ($(dep_files),)
include $(dep_files)
endif PHONY += $(subdir-y) __build : $(subdir-y) built-in.o $(subdir-y):
make -C $@ -f $(TOPDIR)/Makefile.build built-in.o : $(cur_objs) $(subdir_objs)
$(LD) -r -o $@ $^ dep_file = .$@.d %.o : %.c
$(CC) $(CFLAGS) -Wp,-MD,$(dep_file) -c -o $@ $< .PHONY : $(PHONY)

编写一个通用的Makefile文件的更多相关文章

  1. 14、编写一个通用的Makefile

    编译test_Makefile的方法:a. gcc -o test a.c b.c对于a.c: 预处理.编译(C文件转换成汇编).汇编(汇编转换成机器码)对于b.c:预处理.编译.汇编最后链接优点:命 ...

  2. Linux C编程学习之开发工具3---多文件项目管理、Makefile、一个通用的Makefile

    GNU Make简介 大型项目的开发过程中,往往会划分出若干个功能模块,这样可以保证软件的易维护性. 作为项目的组成部分,各个模块不可避免的存在各种联系,如果其中某个模块发生改动,那么其他的模块需要相 ...

  3. 一个简单的makefile文件

    一个简单的makefile文件:可以编译指定目录下的所有c和cpp文件,暂未加入自动头文件的依赖. #!/bin/bash #编译器 CROSS_COMPILING_PATH = #源文件路径 VPA ...

  4. 一个简单的makefile文件编写

    下午闲来无聊,就打开很久没动过的linux系统想熟悉熟悉在linux上面编译代码,结果一个makefile文件搞到晚上才搞定,哈哈! 先把代码简单贴上来,就写了一个冒泡排序: sort.h: #ifn ...

  5. 一个通用的Makefile (转)

    据http://bbs.chinaunix.net/thread-2300778-1-1.html的讨论,发现还是有很多人在问通用Makefile的问题,这里做一个总结.也作为以后的参考.       ...

  6. 一个通用的makefile(一)

    最近在编写Android编译系统时,需要遍历每一个目录下每一个文件夹下的makefile,网上的方法有些繁琐 :就直接贴上自己遍历子目录深度为1:(for  temporary)(之后会继续更新) 下 ...

  7. 一步一步写一个简单通用的makefile(四)--写一个通用的makefile编译android可执行文件

    通常要把我们自己的的代码编译成在android里面编译的可执行文件,我们通常是建一个文件夹 . ├── Android.mk ├── Application.mk ├── convolve.cl ├─ ...

  8. 一个通用的Makefile(二)

    1.各级子目录的Makefile: obj-y += file.o obj-y += subdir/ “obj-y += file.o” 表示把当前目录下的file.c编进程序里. “obj-y += ...

  9. 一个通用的Makefile框架

    先做一个简单的记录,后续有时间再慢慢完善补充细节. 先上一个整体图片: 其中,最重要的文件就是:program_template.mk. 下面是program_template.mk最重要的内容: $ ...

随机推荐

  1. 消息队列 Kafka 的基本知识及 .NET Core 客户端

    前言 最新项目中要用到消息队列来做消息的传输,之所以选着 Kafka 是因为要配合其他 java 项目中,所以就对 Kafka 了解了一下,也算是做个笔记吧. 本篇不谈论 Kafka 和其他的一些消息 ...

  2. 如何优雅的使用RabbitMQ

    RabbitMQ无疑是目前最流行的消息队列之一,对各种语言环境的支持也很丰富,作为一个.NET developer有必要学习和了解这一工具.消息队列的使用场景大概有3种: 1.系统集成,分布式系统的设 ...

  3. Xshell 连接CentOS服务器解密

    平台之大势何人能挡? 带着你的Net飞奔吧!http://www.cnblogs.com/dunitian/p/4822808.html Xshell生成密钥key(用于Linux 免密码登录)htt ...

  4. Android混合开发之WebView与Javascript交互

    前言: 最近公司的App为了加快开发效率选择了一部分功能采用H5开发,从目前市面的大部分App来讲,大致分成Native App.Web App.Hybrid App三种方式,个人觉得目前以Hybri ...

  5. javascript中的操作符详解1

    好久没有写点什么了,根据博主的技术,仍然写一点javascript新手入门文章,接下来我们一起来探讨javascript的操作符. 一.前言 javascript中有许多操作符,但是许多初学者并不理解 ...

  6. 破解SQLServer for Linux预览版的3.5GB内存限制 (RHEL篇)

    微软发布了SQLServer for Linux,但是安装竟然需要3.5GB内存,这让大部分云主机用户都没办法尝试这个新东西 这篇我将讲解如何破解这个内存限制 要看关键的可以直接跳到第6步,只需要替换 ...

  7. 小兔JS教程(三)-- 彻底攻略JS回调函数

    这一讲来谈谈回调函数. 其实一句话就能概括这个东西: 回调函数就是把一个函数当做参数,传入另一个函数中.传进去的目的仅仅是为了在某个时刻去执行它. 如果不执行,那么你传一个函数进去干嘛呢? 就比如说对 ...

  8. PHP static静态属性和静态方法

    这里分析了php面向对象中static静态属性和静态方法的调用.关于它们的调用(能不能调用,怎么样调用),需要弄明白了他们在内存中存放位置,这样就非常容易理解了.静态属性.方法(包括静态与非静态)在内 ...

  9. DDD领域驱动设计 - 设计文档模板

    设计文档模板: 系统背景和定位 业务需求描述 系统用例图 关键业务流程图 领域语言整理,主要是整理领域中的各种术语的定义,名词解释 领域划分(分析出子域.核心域.支撑域) 每个子域的领域模型设计(实体 ...

  10. JavaScript求两个数字之间所有数字的和

    这是在fcc上的中级算法中的第一题,拉出来的原因并不是因为有什么好说的,而是我刚看时以为是求两个数字的和, 很显然错了.我感觉自己的文字理解能力被严重鄙视了- -.故拉出来折腾折腾. 要求: 给你一个 ...