一个通用的Makefile

一 makefile的作用

Makefile是用于自动编译和链接的,一个工程有很多文件组成,每一个文件的改变都会导致工程的重新链接,但是不是所有的文件都需要重新编译,Makefile中记录有文件的信 息,在make时会决定在链接的时候需要重新编译哪些文件。Makefile的宗旨就是:让编译器知道要编译一个文件需要依赖其他的哪些文件。当那些依赖文件有了改变,编译器会自动发现最终的生成文件已经过时,而应该重新编译相应的模块。 makefile带来的好处就是—"自动化编译",一旦写好,只需要一个make命令,整个工程完全自动编译,极大的提高了软件开发的效率。默认的情况下,make命令会在当前目录下按顺序找寻文件名为"GNUmakefile"、"makefile"、"Makefile"的文件,找到了解释这个文件。当然也可以使用make -f DIR/makefile 来指定用于makefile文件

二 makefile语法简述

2.1 makefile规则

target ... : dependencies ... 
            command

target目标文件,可以是Object File,也可以是执行文件,还可以是一个标签 
dependencies就是,要生成那个target所需要的文件或是目标。 
command也就是make需要执行的命令。(任意的Shell命令,可以有若干行)

这是一个文件的依赖关系,也就是说,target这一个或多个的目标文件依赖于dependencies中的文件,其生成规则定义在command中。dependencies 中如果有一个以上的文件时间要比target文件要新的话,command所定义的命令就会被执行。这就是 Makefile的规则。也就是Makefile中最核心的内容。在Makefile中的命令,必须要以[Tab]键开始。

2.2 变量定义

Makefile中变量的定义一般有两种: =和:=。 =符号定义的变量叫延时变量,只有在使用的时候才扩展开来; :=符号定义的变量为立即变量,一旦定义就扩展。 使用=定义的变量不能追加新值,使用:=定义的变量可以使用+=追加新值

2.3 文件指示

在Makefile使用include关键字可以把别的Makefile包含进来,这很像C语言的#include,被包含的文件会原模原样的放在当前文件的包含位置。include的语法是:include <filename> filename可以是当前操作系统Shell的文件模式(可以保含路径和通配符)

2.4 伪目标

    伪目标并不是一个文件,只是一个标签,由于伪目标不是文件,所以make无法生成它的依赖关系和决定 它是否要执行。我们只有通过显示地指明这个目标才能让其生效。当然,伪目标的取名不能和文件名重名,不然其就失去了伪目标的意义了。当然,为了避免和文件重名的这种情况,我们可以使用一个特殊的标记.PHONY来显示地指明一个目标是伪目标,向make说明,不管是否有这个文件,这个目标就是伪目标。

2.5 自动化变量

    $<    第一个依赖文件的名称

    $?    所有的依赖文件,以空格分开,这些依赖文件的修改日期比目标的创建日期晚

    [email protected]    目标的完整名称

    $^    所有的依赖文件,以空格分开,不包含重复的依赖文件

三 通用的makefile实例

工程必备:

顶层Makefile 顶层Makefile.build 子目录Makefile

编译过程:

从顶层开始递归进入子目录,当进入到一个目录的最底层时,开始使用GCC编译,再将该层的所有.o文件打包成build-in.o,返回它的上一层目录再递归进入子目录,当编译完所有的子目录后,就开始编译顶层的.c文件,最后将顶层的.o文件和顶层每个子目录的build-in.o链接成我们的目标文件

顶层Makefile解析(随工程而变):

#----------------------------------------------指定编译工具链---------------------------------------------------

CROSS_COMPILE =                             #指定编译器种类

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                           #将定义的变量导出,方便其他makefile使用

export STRIP OBJCOPY OBJDUMP                   #将定义的变量导出,方便其他makefile使用

CFLAGS := -Wall -O2 -g                                    #编译器参数

CFLAGS += -I $(shell pwd)/include                     #指定编译器头文件(根据实际项目手动修改)

LDFLAGS := -lm -lfreetype -lvga                         #指定编译器链接库(根据实际项目手动修改)

export CFLAGS LDFLAGS                                #将定义的变量导出,方便其他makefile使用

TOPDIR := $(shell pwd)                                     #获得当前程序的顶层目录

export TOPDIR                                                 #输出顶层目录

TARGET := show_file                                      #编译后的程序名(根据实际项目手动修改)

#-------------------------顶层要生成的.o文件以及顶层文件夹(根据实际项目手动修改)------------------

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    #将编译好的built-in.o文件链接生成我们的目标文件

#------------------------------------------------顶层的清除规则-------------------------------------------------------

clean:

rm -f $(shell find -name "*.o")                        #删除所有的.o文件

rm -f $(shell find -name "*.d")                        #删除所有的.d文件

rm -f $(TARGET)                                         #删除目标文件

.PHONY:all clean

顶层Makefile.build解析(无需改动):

PHONY := __build                                        #定义一个PHONY变量

__build:                                                       #开头说明__build伪目标,使其成为Makefile.build的第一个目标

obj-y :=                                                        #定义当前目录的目标变量,初始值为空

subdir-y :=                                                   #定义当前目录的子目录变量,初始值为空

include Makefile                                          #将当前目录的Makefile包含进来,初始化obj-y

#obj-y:=a.o b.o c/ d/

__subdir-y := $(patsubst %/,%,$(filter %/, $(obj-y)))   #筛选出当前目录的目标变量中的子目录,并且去掉/

#$(filter %/, $(obj-y)):c/ d/

#__subdir-y:c d

subdir-y += $(__subdir-y)                                           #将开始定义的subdir-y赋值为__subdir-y

#subdir-y:c d

subdir_objs := $(foreach f,$(subdir-y),$(f)/built-in.o)  #对于subdir-y里面的每一个值(目录),增加一个相应的目录/built-in.o的变量值

#subdir_objs:c/built-in.o d/built-in.o

cur_objs := $(filter-out %/, $(obj-y))                            #得到obj-y中的.o文件

#cur_objs:a.o b.o

dep_files := $(foreach f,$(cur_objs),.$(f).d)                #对于所有的.o文件,定义它的依赖文件名

#dep_files: .a.d .b.d

dep_files := $(wildcard $(dep_files))

ifneq ($(dep_files),)                                                    #根据依赖文件名,判断依赖文件是否存在,存在就包含就来

include $(dep_files)

endif

PHONY += $(subdir-y) #将$(subdir-y)也加入到变量PHONY中

--------------------------------------------Makefile. build的第一个规则--------------------------------------------------------------

__build : $(subdir-y) built-in.o                                    #第一个规则

$(subdir-y):                                                                #第一个规则的第一个依赖规则

make -C [email protected] -f $(TOPDIR)/Makefile.build              #依次进入该子目录变量里面存储的值,使用的Makefile.build进行编译

built-in.o : $(cur_objs) $(subdir_objs)                       #第一个规则的第二个依赖规则

$(LD) -r -o [email protected] $^                                                 #该规则的命令:将该目录下的.o和$(subdir_obj)打包成built-in.o文件

dep_file = [email protected]                                                        #

%.o : %.c                                                                   #第一个规则的第二个依赖规则的依赖规则

$(CC) $(CFLAGS) -Wp,-MD,$(dep_file) -c -o [email protected] $<#用于将目录下所有的.c文件编译成.o文件

.PHONY : $(PHONY)                                                  #将PHONY声明为伪目标

子目录Makefile(随工程而变):

子目录的Makefile就是包含该目录下所有的目标文件名和子目录文件夹名。

例如任何一个子目录可写成:

objs-y := a.o

objs-y += b.o

objs-y += c/

objs-y += d/

四 示例工程

http://pan.baidu.com/share/link?shareid=145262&uk=101680913

时间: 2024-10-12 20:48:01

一个通用的Makefile的相关文章

Linux C编程学习4---多文件项目管理、Makefile、一个通用的Makefile

GNU Make简介 大型项目的开发过程中,往往会划分出若干个功能模块,这样可以保证软件的易维护性. 作为项目的组成部分,各个模块不可避免的存在各种联系,如果其中某个模块发生改动,那么其他的模块需要相应的更新.如果通过手动去完成这个工作的话,对于小型的项目可能还行,但是对于比较大型的项目就几乎是不可能的. 因此Linux 系统提供了一个自动维护和生成目标程序的工具 make,它可以根据各个模块的更改情况去重新编译连接目标代码 Make 工具的作用就是实现编译连接过程的自动化.它定义了一种语言,用

一个通用的Makefile (转)

据http://bbs.chinaunix.net/thread-2300778-1-1.html的讨论,发现还是有很多人在问通用Makefile的问题,这里做一个总结.也作为以后的参考. 笔者在写程序的时候会遇到这样的烦恼:一个项目中可能会有很多个应用程序,而新建一个应用程序则所有的Makefile都要重写一遍,虽然可以部分的粘帖复制,但还是感觉应该找到更好的解决途径:另外当一个应用程序中包含多个文件夹时通常要在每个目录下创建一个Makefile,当有数十个文件夹时,要创建如此多的Makefi

编写一个通用的Makefile文件

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直接编译链接 1 gcc -o test a.c b.c 缺点:改变其中一

一个通用的Makefile框架

先做一个简单的记录,后续有时间再慢慢完善补充细节. 先上一个整体图片: 其中,最重要的文件就是:program_template.mk. 下面是program_template.mk最重要的内容: $(1)_COBJS = $$(patsubst $$($(1)_SDIR)%.c,$$($(1)_BIN)/%.o,$$($(1)_CSRCS)) $(1)_OBJS = $$($(1)_COBJS) $(1)_COBJDEPS = $$(patsubst $$($(1)_SDIR)%.c, $$(

发现了一个通用的Makefile

即使有子文件夹也能处理. Makefile: .PHONY: clean all # annotation when release version DEBUG := TARGET_PROG := main.out # project directory DEBUG_DIR := ./debug RELEASE_DIR := ./release BIN_DIR := $(if $(DEBUG), $(DEBUG_DIR), $(RELEASE_DIR)) # shell command CC :

我所使用的一个通用的Makefile模板

话不多说,请看: 我的项目有的目录结构有: dirls/ ├── include │   └── apue.h ├── lib │   ├── error.c │   ├── error.o │   └── Makefile ├── src │   ├── dirls.c │   ├── dirls.out │   └── Makefile └── test_client 而我的Makefile模板代码如下: SRCS = $(wildcard *.c ../lib/*.c) #wildcard

C/C++ 编写一个通用的Makefile 来编译.c .cpp 或混编

1.虽然能编译出程序,但是会提示错误.目前暂未解决 make: sinclude: Command not foundmake: *** [test] Error 127 2. 后续主要要修改的部分: 1> PROGRAM := hello # 设置运行程序名 2> SRCDIRS := .  # 源程序位于当前目录下 3> SRCEXTS := .c .cpp  # 源程序文件有 .c 和 .cpp 两种类型 4> CFLAGS := -g # 为 c 目标程序包含 gdb 调试

一个通用Makefile的编写

作者:杨老师,华清远见嵌入式学院讲师. 我们在Linux环境下开发程序,少不了要自己编写Makefile,一个稍微大一些的工程下面都会包含很多.c的源文件.如果我们用gcc去一个一个编译每一个源文件的话,效率会低很多,但是如果我们可以写一个Makefile,那么只需要执行一个make就OK了,这样大大提高了开发效率.但是Makefile的语法规则众多,而且缺乏参考资料,对于初学者来说,写起来还是有一定的难度,往往令很多人望而生畏.下面我们介绍一个比较通用而且简洁的Makefile,大家只要对它稍

一个通用的c/c++Makefile模版

一个codeproject上发现的通用c/c++的Makefile模版,比较简单好用,共享之 ############################################################################# # # Generic Makefile for C/C++ Program # # License: GPL (General Public License) # Author: whyglinux <whyglinux AT gmail DOT