单个MakeFile管理项目(跨平台)

单个MakeFile管理项目(跨平台)


阅读本文,你应该要拥有基础的linux知识和基本的makefile知识


  • 摘要:使用一个MakeFile就可以管理整个项目,新建项目时只需要将模板Make File移动至新项目根目录即可;Windows(MinGw),Linux(GCC)系统实测可用,理论上支持makefile的所有平台皆可使用;同时配置对应变量即可实现 C / C++ 嵌入式C 的项目管理;

  • 局限:某一种项目只能自动导入某个单一后缀的源文件(头文件没有影响);例如C++ 只能识别到*.cpp的文件,对于 *.c 类型并不能识别;

1. makefile的超简单入门知识

  • 为什么要使用makefile
    在没有图像界面的linux控制窗口中,编译代码都是使用命令行来进行编译;例如:最为简单的C语言编译

    gcc hello-world.c -o hello.out #编译hello-world.c文件生成可执行文件 hello.out
    

    对于单个文件编译可能十分简单;但是我们真正使用C/C++的使用都不会仅仅使用一个文件,通常的多个文件夹,多个文件嵌套使用.因此这里就需要使用makefile来做一个自动化编译的脚本;
    例如我们把 上述 gcc hello-world.c -o hello.out写进一个名字为makefile的文件中,然后使用make指令,就可以实现与上局完全一样的功能;除此之外还增加了许多新的令人大赞的功能;

  • makefile的执行原则
    makefile的执行原则:

    <目标文件>:<源文件>
        生成目标文件的命令行方法
    
    • 所有的makefile中只有这一个最为重要,其他的就像函数中被main调用的函数,你只要找到它,那么你就可以慢慢的梳理整个makefile在处理些什么;

    • makefile是一个基于文件操作的脚本,它会根据文件的最新修改日期选择性的做是否执行 生成目标文件的命令行方法 .这一点十分有用处,例如某大型项目一共1000多个源文件,如果我们每编译一次,都需要1000多个文件同时编译链接,那么基本上我们上班->执行编译命令->执行->debug,2到3轮之后既可以下班回家了,如果是使用makefie,那么他将会只编译你改动了的文件(为理解方便),从而达到节省时间的目的;

    • 具体规则:

      目标文件状态 源文件状态 是否执行下方命令
      不存在 不存在 不执行 && 报错
      不存在 存在 执行
      存在 & 最新编辑时间最晚 存在 不执行
      存在 存在&任意一个文件编辑时间最晚 执行

      并且主目标文件的源文件也可以是其他目标关系的目标文件,当出现需要时会进行递归调用最终生成主目标文件;第一个出现的[公式]就是主目标文件;

  • makefile的应用场景

    • makefile大量应用在各种项目场合,开源项目几乎都是用此方式管理和编译项目.但是超大型项目一般都是使用多个makefile穿插在各个文件夹中,这样可以很方便的管理各个模块的开关和复用.
    • 但是对于处于学习阶段的同学来说,他可能会频繁的新建项目验证各类问题,但是说大不大,说小不小,如果使用多个makefile有点大材小用,用单个makefile是最好的选择;
    • 但是单个makefile现在网络上大多数都是需要你自己手动加入文件路径的makefile,作为懒人的我,肯定不想这样啦,于是,就有了这边文章;

2. 单个makefile管理项目思维拓展

  • 单个makefile管理项目,首先需要递归的寻找到当前问件夹中的所有文件
  • 依次找到每个源文件对应的需要h文件,并且建立对应关系
  • 定义编译器宏,文件后缀宏,等等为跨平台做良好接口
  • 自定义复制文件结构将所有的中间文件生成至build文件夹中并保持原有文件结构方便查看
  • 定义clean伪目标,清理中间文件
  • 定义各种伪目标清理build文件夹,清理可执行文件等

3. makefile源码分析

  • 接下来我会使用基础步骤由最终的目标文件开始介绍,逐次的转向内部实现;
#指定AllLibs为终极目标 即:最新的Bin 
AllLibs:$(Bin)

#生成文件的最终表达式
$(Bin) : $(OBJS)  
      @echo bulding....
      @$(COMPILER) $(OBJS) $(ARGS)  $(COMPILERFLAG) $(Bin)
      @echo created file: $(target)

COMPILER:编译器的宏定义,展开后一般为gcc或g++,当然也可以自己定义

COMPILERFLAG = 
#条件编译使得其满足C项目 以及 C++项目
ifeq ($(TYPE),C)      #如果TYPE为"C" 那么COMPILER = gcc
      COMPILER := $(CC)
      COMPILERFLAG := $(CFLAGS)
      PROJECTTYPE = .c
  else
ifeq ($(TYPE),C++)    #如果TYPE为"C++" 那么COMPILER = g++
      COMPILER := $(CXX)
      COMPILERFLAG := $(CXXFLAGS)
      PROJECTTYPE = .cpp
else
ifeq ($(TYPE),ARMC)   #如果TYPE为"ARMC",那么COMPLIER = gcc 实际上这里应该是arm-gcc交叉编译链的gcc
      COMPILER := $(CC)
      COMPILERFLAG := $(CFLAGS)
      PROJECTTYPE = .c
else                  #3个都不是,所有设置清空
      COMPILER :=
      COMPILERFLAG := 
      PROJECTTYPE := 
endif
endif
endif
  • OBJS的生成与关系
#处理得到*.o 后缀文件名
OBJS := $(patsubst %$(PROJECTTYPE),%.o, $(buildPath))  

#对于include中的*.d文件,只要里面任意有一个文件被修改,那么就会触发此规则生成一个新的  *.o文件
%.o: %.d
  @echo compile $(patsubst %.d,%$(PROJECTTYPE),$(subst build/,,$<)) 
  @$(COMPILER) -c $(patsubst %.d,%$(PROJECTTYPE),$(subst build/,,$<)) $  (DEBUG) $(DEF) $(INCLUDE_PATH) $(ARGS) $(COMPILERFLAG) $@ 

include $(buildPath:$(PROJECTTYPE)=.d) # 这句话很重要,你可以编译之后打开.d文件你就明白啦

  • 默认的主要表达式
#生成文件的最终表达式
$(Bin) : $(OBJS)  
  @echo bulding....
  @$(COMPILER) $(OBJS) $(ARGS)  $(COMPILERFLAG) $(Bin)
  @echo created file: $(target)   

上面有一行

#指定AllLibs为终极目标 即:最新的Bin 
AllLibs:$(Bin)

也就是说 获得最新的 Bin是默认目标,依存为 Objs的诸多文件,而生成途径 就是使用之间我们生成的 OBJS 的*.o文件链接起来生成 target;

  • 其他目标任务
#删除所有编译带来的文件
.PHONY : clean  
clean:clean_out clean_build clean_bin

#删除 *.o文件
.PHONY : clean_out  
clean_out:
      @echo 'removeing all *.o file ...'
      @$(RM) -r $(pes_parent_dir)/build/*.o
      @echo 'done'

#删除 build 文件夹
.PHONY : clean_build  
clean_build:
      @echo 'removeing all build temp file ...'
      @$(RM) -r $(pes_parent_dir)/build
      @echo 'done'

#删除 可执行文件
.PHONY : clean_bin  
clean_bin:
      @echo 'removeing executable file ...'
      @$(RM) $(Bin)
      @echo 'done'

      
#重新编译
.PHONY : rebuild
rebuild: clean_out AllLibs

#显示帮助
.PHONY : help
help:
      @echo "本makefile 一共实现了以下几种命令模式"
      @echo "AllLibs \t\t默认的命令,含义为编译当前项目并输出可执行文件 $(target)\n"
      @echo "clean \t\t清理命令,删除由makefile带来的所有文件\n"
      @echo "clean_out \t\t清理中间文件命令,删除由编译带来的所有文件 *.o\n"
      @echo "clean_build \t\t清理中间文件命令,删除编译临时文件夹 /build\n"
      @echo "clean_bin \t\t删除可执行文件 $(target)\n"
      @echo "rebuild \t\t重新编译\n"
      @echo "|----------------------------------------------|"
      @echo "内建一些逻辑,以及传参即可改变\n"
      @echo "ARGS \t\t用户自我追加的一些编译参数,例如多线程中需要加入 -lpthread 参数\n"
      @echo "TYPE \t\t用于确认当前项目是C++ 项目还是 C语言项目 (默认为C) 如果是C++ 那么自动编译*.cpp文件 ,如果是 C 那么自动编译*.c文件,暂不支持混合添加\n"
      @echo "target \t\t用户自定义生成的可执行文件名,例如windows下 生成obj.exe Linux下生成 obj.out\n"
      @echo "DEBUG \t\t一般传入 -g 表示支持单步调试,\n"
      @echo "PREDEF \t\t预先定义一些宏,在程序中起到开关裁剪的作用\n"
      @echo "Please check the console encoding format in case of garbled codes. The initial encoding format of this makefile is UTF8\n"


最后makefile 项目已经上传到 GitHub 点击这里

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 204,793评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 87,567评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 151,342评论 0 338
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,825评论 1 277
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,814评论 5 368
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,680评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,033评论 3 399
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,687评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 42,175评论 1 300
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,668评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,775评论 1 332
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,419评论 4 321
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,020评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,978评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,206评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,092评论 2 351
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,510评论 2 343

推荐阅读更多精彩内容