如何学习和运用Makefile

怎么写Makefile?不想讲太多如何如何做。Makefile这东西,公司让一两个人来负责就好了,否则一定是一锅粥。每次看到招聘广告里说,要求懂Makefile,懂Linux多线程编程,哥就想呵呵呵,软件开发的初级阶段~~~

网路经常看到有人发帖求问Makefile如何写;当然答复也是五花八门,有些给出了样例。哥也俗一把,从example开始。不想看的直接跳过,哥准备了一套Makefile给你直接用,只要你会复制粘贴就行。

小小班:

OBJS := foo.o bar.o

# link
proggie: $(OBJS)
gcc $(OBJS) -o proggie # compile and generate dependency info
%.o: %.c
gcc -c $(CFLAGS) $*.c -o $*.o # remove compilation products
clean:
rm -f proggie *.o

这个makefile,基本上能满足学习做C语言的需求了。使用者需要把自己的文件名加入到makefile中,编译出来的目标文件都存放在项目根目录下。嗯,其实项目就一个根目录,当然,头文件倒是没特别限定,只需要额外定义$(CFLAGS)就好了。编译时,Make能够检测C文件是否有改动以决定是否重新编译。

不过,如果是头文件改动,就麻烦了,这个makefile发现不了的。

小班:

OBJS := foo.o bar.o

# link
proggie: $(OBJS)
gcc $(OBJS) -o proggie # pull in dependency info for *existing* .o files
-include $(OBJS:.o=.d) # compile and generate dependency info
%.o: %.c
gcc -c $(CFLAGS) $*.c -o $*.o
gcc -MM $(CFLAGS) $*.c > $*.d # remove compilation products
clean:
rm -f proggie *.o *.d

这个比小小班的好不了多少,不过多产生了个.d文件。.d文件是解决编译错误的一个很有价值的东东,不懂的赶紧看看,不管你是不是想学Makefile。

中班:

OBJS := foo.o bar.o

# link
proggie: $(OBJS)
gcc $(OBJS) -o proggie # pull in dependency info for *existing* .o files
-include $(OBJS:.o=.d) # compile and generate dependency info;
# more complicated dependency computation, so all prereqs listed
# will also become command-less, prereq-less targets
# sed:strip the target (everything before colon)
# sed:remove any continuation backslashes
# fmt -1: list words one per line
# sed:strip leading spaces
# sed:add trailing colons
%.o: %.c
gcc -c $(CFLAGS) $*.c -o $*.o
gcc -MM $(CFLAGS) $*.c > $*.d
cp -f $*.d $*.d.tmp
sed -e 's/.*://' -e 's/\\$$//' < $*.d.tmp | fmt -1 | sed -e 's/^ *//' -e 's/$$/:/' >> $*.d
rm -f $*.d.tmp # remove compilation products
clean:
rm -f proggie *.o *.d

这个要说一下,小班生成了.d文件,凡事有益必有害:将.h文件改名或是换个地方,就会出错。这个Makefile试图解决这个问题。Linux sed语法,有点难,跟Makefile没啥关系。

大班:

sources = bar.c foo.c far.cc sub/test.c
bin = obj
paths = $(addprefix $(bin)/, $(dir $(sources)))
out = $(bin)/proggie objects := $(addprefix $(bin)/, $(addsuffix .o, $(basename $(sources)))) all: $(bin) $(out) $(out): $(objects)
gcc $(objects) -o $(out) $(objects): | $(bin) $(bin):
mkdir -p $(paths) -include $(objects:.o=.d) $(bin)/%.o : %.c
gcc -c -MD $< -o $@ $(bin)/%.o : %.cc
gcc -c -MD $< -o $@ clean:
rm -rf $(bin)/

中班试图解决.h文件改名或是改路径,导致.d文件编译出错的事,现在,我们发起解决这个问题,毕竟那事极少发生,而且还有make-clean终极大招。大班做什么?解决多个平台的编译问题。这里将编译出来的目标文件放入obj目录,其实就是解决多平台编译的思路。

好了,说完这些,对于学习Makefile来说,也就基本讲完了,剩下的就是如何工程化了。这个挺难的,如果不是想专业搞Makefile或是开发架构设计(下回讨论怎么做开发架构),就别太费心琢磨,该干嘛干嘛去,别浪费时间在这产生不了价值的事情上。

记得下载,解压到Linux上练练手: http://files.cnblogs.com/files/hhao020/cshell_prj.re0.001.rar

cshell_prj/Makefile

编译x32和x64两种平台: # programs for cshell .PHONY: all clean rebuild

exe:
make -f linux.i64.mk target=$(target)
make -f linux.i32.mk target=$(target) clean:
make -f linux.i64.mk clean target=$(target)
make -f linux.i32.mk clean target=$(target) rebuild:
make -f linux.i64.mk rebuild target=$(target)
make -f linux.i32.mk rebuild target=$(target)

cshell_prj/linux.i64.mk

编译64位intel程序:

# programs for cshell

MAKE_RULE := linux.i64
SAL_DIR := salLinux64 PRJ_DIR := $(dir $(abspath $(lastword $(MAKEFILE_LIST)))) export PRJ_DIR MAKE_RULE CC := gcc
LD := gcc CFLAGS := -Wall -g -MD -m64 -c
SELF_CFLAGS :=
LDFLAGS := SOURCES := user_main.c
BIN = $(PRJ_DIR)/bin/$(MAKE_RULE)
PATHS = $(addprefix $(BIN)/, $(dir $(SOURCES))) OUT=$(BIN)/user.exe OBJECTS := $(addprefix $(BIN)/, $(addsuffix .o, $(basename $(SOURCES)))) #must keep cshell as the first lib
LIBDIRS := cshell userapp LDDIRS := -L$(BIN) LDLIBS := $(addprefix -l, $(LIBDIRS)) LIBFILES := $(addprefix $(BIN)/lib, $(addsuffix .a, $(LIBDIRS))) LDFLAGS += -m64 $(LDLIBS) $(LDDIRS) -lpthread INCLIBS = -I$(PRJ_DIR)export $(addsuffix /export, $(addprefix -I$(PRJ_DIR), $(LIBDIRS)))
export INCLIBS .PHONY: all clean all: yacc $(BIN) exe #$(OBJECTS): | $(BIN) yacc $(BIN):
mkdir -p $(PATHS) yacc:
ifeq ($(target), )
( cd cshell && (perl $(PRJ_DIR)/tools/p_readelf.pl ))
#( cd cshell && (bison -d cshell.y && flex -ocshell.lex.c cshell.l && perl $(PRJ_DIR)/tools/p_readelf.pl ))
endif -include $(OBJECTS:.o=.d) exe: $(OBJECTS)
ifneq ($(target), )
make -C $(target) TARGET=$(target)
else
for dir in $(LIBDIRS); do (make -C $$dir TARGET=$$dir || exit 1) || exit 1; done
(cd cshell && rm -rf c_sym_table.* && perl $(PRJ_DIR)/tools/p_readelf.pl $(LIBFILES) $(OBJECTS)) || exit 1;
rm -rf $(BIN)/libcshell.a
make -C cshell TARGET=cshell $(INCLIBS)
$(LD) -o $(OUT) $^ $(LDFLAGS)
endif $(BIN)/%.o: %.c
$(CC) -c -o $@ $< $(CFLAGS) $(INCLIBS) clean:
ifneq ($(target), )
make -C $(target) TARGET=$(target) clean
else
rm -f $(BIN)/*.o $(BIN)/*.d $(BIN)/*.a $(BIN)/*.sym.txt $(OUT) *.sym.txt *.a
for dir in $(LIBDIRS); do (make -C $$dir clean || exit 1) || exit 1; done
endif rebuild: clean exe

cshell_prj/xxx/Makefile

每个源码子目录放一份,新目录拷贝就成,记得在cshell_prj/xxx.mk里添加这个目录到库列表。做项目时,这个文件要杜绝一般开发者人员的修改。当然,一般来说,这个文件在标准版本编译时,应该使用工具全部重新生成一份,免得有人偷偷修改过。

#------------------------------------------------------------
# makefile.def : common template for makefile
# Author : hhao020
# Date : 2011-06-30
#------------------------------------------------------------ ifeq ($(PRJ_DIR), )
env_err:
@echo Error: must define PRJ_DIR environment variable.
endif ifeq ($(MAKE_RULE), )
env_err:
@echo Error: must define MAKE_RULE environment variable.
endif # source files' list
SOURCES = # private compiler flags and include file path
SELF_ASFLAGS =
SELF_CFLAGS =
SELF_CPPFLAGS =
SELF_INCLUDE = # private macro or compiler conditions definations
SELF_DEFINE =
#-DNET_SELF_TEST # private link definations
SELF_LINK_OPT = include $(PRJ_DIR)/build/$(MAKE_RULE)

cshell_prj/build/linux.i64

特定平台编译模板。做项目时,这个文件要杜绝一般开发者人员的修改。

#------------------------------------------------------------
# makefile.def : common definitions for makefile
# Author : hhao020
# Date : 2011-06-30
#------------------------------------------------------------ ifeq "$(strip $(SOURCES))" ""
SOURCES := $(wildcard *.s) $(wildcard *.c) $(wildcard *.cpp)
endif BIN = bin/$(MAKE_RULE)
PATHS = $(addprefix $(BIN)/, $(dir $(SOURCES))) OUT = $(PRJ_DIR)/$(BIN)/lib$(TARGET).a OBJECTS := $(addprefix $(BIN)/, $(addsuffix .o, $(basename $(SOURCES)))) #default tool chains
AR = ar -rcs
AS = as
CC = gcc
RM = rm -rf COMM_DEFS = -g -DLINUX -DCPU64 \
-I./ \
-I./inc ASFLAGS = -Wall -c
CPP_FLAGS =
CFLAGS= -Wall -g -MD -m64 -c LINK_OPT = ASFLAGS += $(SELF_ASFLAGS) ..s.o:
$(AS) $(COMM_DEFS) $(ASFLAGS) $(SELF_ASFLAGS) $(SELF_INCLUDE) $(INCLIBS) $(SELF_DEFINE) $< $(BIN)/%.o : %.c
$(CC) $(COMM_DEFS) $(CFLAGS) $(SELF_CFLAGS) $(SELF_INCLUDE) $(INCLIBS) $(SELF_DEFINE) -c $< -o $@ $(BIN)/%.o : %.cpp
$(CC) $(COMM_DEFS) $(CPPFLAGS) $(SELF_CPPFLAGS) $(CFLAGS) $(SELF_CFLAGS) $(SELF_INCLUDE) $(INCLIBS) $(SELF_DEFINE) -c $< $(OUT) : $(OBJECTS)
$(AR) $(OUT) $^ $(OBJECTS): | $(BIN) $(BIN):
mkdir -p $(PATHS) -include $(OBJECTS:.o=.d) .PHONY : exe clean rebuild exe : $(OUT) clean :
$(RM) $(BIN)/*.d $(BIN)/*.o /$(OUT) rebuild: clean exe

Makefile这东西,其实是跟软件的开发架构紧密关联的。若是开发架构不好,Makefile自然就没那么容易搞,或者很难懂。再有,就是防不住小朋友们捣乱,特别是刚毕业的,总是喜欢改一下Makefile,添加点头文件路径,或是编译设置,而这些都直接危害着最后的产品;一个不小心,编译出来的东西就不是你原本想要的了!因此,杜绝大家都来改Makefile绝对是根本!这套Makefile,让一般开发人员只能复制整个文件到新目录,而无需关系具体细节,大概能让添加新文件和新目录的事,变得容易些!


Makefile技术和应用总结的更多相关文章

  1. 【转】Linux makefile 教程 非常详细,且易懂

    From: http://blog.csdn.net/liang13664759/article/details/1771246 最近在学习Linux下的C编程,买了一本叫<Linux环境下的C ...

  2. Makefile经典教程(掌握这些足够)

    makefile很重要 什么是makefile?或许很多Winodws的程序员都不知道这个东西,因为那些Windows的IDE都为你做了这个工作,但我觉得要作一个好的和professional的程序员 ...

  3. Linux makefile 教程 非常详细,且易懂

    最近在学习Linux下的C编程,买了一本叫<Linux环境下的C编程指南>读到makefile就越看越迷糊,可能是我的理解能不行. 于是google到了以下这篇文章.通俗易懂.然后把它贴出 ...

  4. [转] Makefile经典教程(掌握这些足够)

    目录(?)[-] Makefile 介绍 1 Makefile的规则 2 一个示例 3 make是如何工作的 4 makefile中使用变量 5 让make自动推导 6 另类风格的makefile 7 ...

  5. 【转载】Linux下makefile详解--跟我一起写 Makefile

    概述 —— 什么是makefile?或许很多Winodws的程序员都不知道这个东西,因为那些Windows的IDE都为你做了这个工作,但我觉得要作一个好的和professional的程序员,makef ...

  6. Makefile 如何轻松搞定

    最近在学习Linux下的C编程,买了一本叫<Linux环境下的C编程指南>读到makefile就越看越迷糊,可能是我的理解能不行. 于是google到了以下这篇文章.通俗易懂.然后把它贴出 ...

  7. Linux makefile 教程 非常详细,且易懂 (转)

    概述—— 什么是makefile?或许很多Winodws的程序员都不知道这 个东西,因为那些Windows的IDE都为你做了这个工作,但我觉得要作一个好的和professional的程序员,makef ...

  8. 一篇文章教你读懂Makefile

    makefile很重要      什么是makefile?或许很多Winodws的程序员都不知道这个东西,因为那些Windows的IDE都为你做了这个工作,但我觉得要作一个好的和professiona ...

  9. Linux makefile教程之后序十一[转]

    后序 —— 终 于到写结束语的时候了,以上基本上就是GNU make的Makefile的所有细节了.其它的产商的make基本上也就是这样的,无论什么样的make,都是以文件的依赖性为基础的,其基本是都 ...

随机推荐

  1. string.Format 格式化输出日期

    string.Format("{0:d}",System.DateTime.Now) 结果为:2009-3-20 (月份位置不是03) string.Format("{0 ...

  2. Servlet的过滤器Filter

    Servlet 编写过滤器 Servlet 过滤器可以动态地拦截请求和响应,以变换或使用包含在请求或响应中的信息. 可以将一个或多个 Servlet 过滤器附加到一个 Servlet 或一组 Serv ...

  3. IDEA 用了maven后的 智能提示 不出现问题,项目的依赖包没有加载依赖库中的问题。

  4. 8天掌握EF的Code First开发系列之2 简单的CRUD操作

    本文出自8天掌握EF的Code First开发系列,经过自己的实践整理出来. 本篇目录 创建控制台项目 根据.Net中的类来创建数据库 简单的CRUD操作 数据库模式更改介绍 本章小结 本人的实验环境 ...

  5. IOleItemContainer的接口定义

      IOleItemContainer的接口定义

  6. SQL语句调优 - 统计信息的含义与作用及维护计算

    统计信息的含义与作用                                                                                          ...

  7. LeetCode:Longest Palindromic Substring 最长回文子串

    题目链接 Given a string S, find the longest palindromic substring in S. You may assume that the maximum ...

  8. android笔记:DatePickerDialog日期设置对话框

    在开发中,可以通过DatePickerDialog来设置日期,TimePickerDialog来设置时间. 实例化DatePickerDialog对象之后,再调用show方法就可以显示对话框了. 具体 ...

  9. 第一章 tomcat安装与启动

    一.安装 1.下载tomcat安装包 2.解压安装包 3.配置环境变量 打开~/.bash_profile文件,输入一下两句话: export TOMCAT_HOME=/Users/enniu1/De ...

  10. 2016---ios面试题

    1.对数组中的元素去重复 例如:   1 2 3   NSArray *array = @[@"12-11", @"12-11", @"12-11&q ...