编写一个通用的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

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

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”这段代码。

[email protected]:表示目标;$^:表示全部依赖;$<:第一个依赖。

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

a.o:a.c a.h

%.o : %.c
    gcc -c -o [email protected] $<

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

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,[email protected] -c -o [email protected] $<

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 [email protected] -f $(TOPDIR)/Makefile.build

built-in.o : $(cur_objs) $(subdir_objs)
    $(LD) -r -o [email protected] $^

dep_file = [email protected]

%.o : %.c
    $(CC) $(CFLAGS) -Wp,-MD,$(dep_file) -c -o [email protected] $<

.PHONY : $(PHONY)

时间: 2024-11-05 07:48:51

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

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 调试

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文件

该Makefile适用于最后生成若干个可执行文件的小型C/C++工程,只要将该Makefile放在源码根目录下make,它会自动查找该目录下(包括子目录)的所有源码文件(支持.cpp .c .h格式)并自动生成正确的依赖关系,并且为了不污染源码文件夹,源码和编译过程中的中间文件会分开(Debug模式编译生成的中间文件在Debug目录下,Release模式在Release目录下). 1 ########################################################

一个通用的Makefile

一 makefile的作用 Makefile是用于自动编译和链接的,一个工程有很多文件组成,每一个文件的改变都会导致工程的重新链接,但是不是所有的文件都需要重新编译,Makefile中记录有文件的信 息,在make时会决定在链接的时候需要重新编译哪些文件.Makefile的宗旨就是:让编译器知道要编译一个文件需要依赖其他的哪些文件.当那些依赖文件有了改变,编译器会自动发现最终的生成文件已经过时,而应该重新编译相应的模块. makefile带来的好处就是—"自动化编译",一旦写好,只需要

一个通用的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

编写一个通用递归获取树形结构对象集合的方法

/// <summary> /// 通用递归获取树状子节点信息 /// </summary> /// <param name="item"></param> /// <param name="id"></param> /// <returns></returns> private List<T> getTreeListByPid<T, F>(Lis