Makefile技术和应用总结
如何学习和运用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技术和应用总结的更多相关文章
- 【转】Linux makefile 教程 非常详细,且易懂
From: http://blog.csdn.net/liang13664759/article/details/1771246 最近在学习Linux下的C编程,买了一本叫<Linux环境下的C ...
- Makefile经典教程(掌握这些足够)
makefile很重要 什么是makefile?或许很多Winodws的程序员都不知道这个东西,因为那些Windows的IDE都为你做了这个工作,但我觉得要作一个好的和professional的程序员 ...
- Linux makefile 教程 非常详细,且易懂
最近在学习Linux下的C编程,买了一本叫<Linux环境下的C编程指南>读到makefile就越看越迷糊,可能是我的理解能不行. 于是google到了以下这篇文章.通俗易懂.然后把它贴出 ...
- [转] Makefile经典教程(掌握这些足够)
目录(?)[-] Makefile 介绍 1 Makefile的规则 2 一个示例 3 make是如何工作的 4 makefile中使用变量 5 让make自动推导 6 另类风格的makefile 7 ...
- 【转载】Linux下makefile详解--跟我一起写 Makefile
概述 —— 什么是makefile?或许很多Winodws的程序员都不知道这个东西,因为那些Windows的IDE都为你做了这个工作,但我觉得要作一个好的和professional的程序员,makef ...
- Makefile 如何轻松搞定
最近在学习Linux下的C编程,买了一本叫<Linux环境下的C编程指南>读到makefile就越看越迷糊,可能是我的理解能不行. 于是google到了以下这篇文章.通俗易懂.然后把它贴出 ...
- Linux makefile 教程 非常详细,且易懂 (转)
概述—— 什么是makefile?或许很多Winodws的程序员都不知道这 个东西,因为那些Windows的IDE都为你做了这个工作,但我觉得要作一个好的和professional的程序员,makef ...
- 一篇文章教你读懂Makefile
makefile很重要 什么是makefile?或许很多Winodws的程序员都不知道这个东西,因为那些Windows的IDE都为你做了这个工作,但我觉得要作一个好的和professiona ...
- Linux makefile教程之后序十一[转]
后序 —— 终 于到写结束语的时候了,以上基本上就是GNU make的Makefile的所有细节了.其它的产商的make基本上也就是这样的,无论什么样的make,都是以文件的依赖性为基础的,其基本是都 ...
随机推荐
- 黑盒测试与白盒测试(Black box Testing)
黑盒测试和白盒测试的优缺点 类别 优点 缺点 黑盒测试 不需要了解软件代码 从用户角度出发 无法保证代码内各个路径被覆盖到 白盒测试 强制测试开发工程师关注代码的具体实现 揭露隐藏在代码中的Bug 是 ...
- Android自动化初探:ADB
Info:经过一段时间的准备,从今天开始自学Android之旅,初步学习会有疏漏,以后的每篇文章,我都会不断修改补全,直到完美. 2014-10-09:初版 --------------------- ...
- POJ1364 King-差分
Description Once, in one kingdom, there was a queen and that queen was expecting a baby. The queen p ...
- MyBatis学习总结(八)——Mybatis3.x与Spring4.x整合
一.搭建开发环境 1.1.使用Maven创建Web项目 执行如下命令: mvn archetype:create -DgroupId=me.gacl -DartifactId=spring4-myba ...
- delphi 怎么获取工程版本号
function GetApplicationVersion:String; // Added 取得程序版本号 var FileName:String; InfoSize,Wnd:DWORD; Ver ...
- Ms sql 2000互转2005
BCP导入导出数据.非常的方便.速度很快.--还原部分,指定强制还原(使用WITH MOVE指定文件还原,RELPACE由于版本不一样,所以要指定REPLACE,如果不指定REPLACE参数,会提示版 ...
- Nginx 学习
1.Nginx编译安装 nginx依赖于pcre库,需要先安装pcre(二进制包,跟正则表达式有关),pcre-devel(头文件) configure --prefix=/usr/local/ng ...
- Linux命令之reset - 终端屏幕混乱的终结者
用途说明 reset命令是用来重新初始化终端的(terminal initialization).在有些情况,终端显示会混乱无比,比如不小心显示了一个二进制文件,以前我在不知道reset命令时,只好将 ...
- Hibernate之jpa实体映射的三种继承关系
在JPA中,实体继承关系的映射策略共有三种:单表继承策略(table per class).Joined策略(table per subclass)和Table_PER_Class策略. 1.单表继承 ...
- xfire webServeic 例子
xfire webServeic 例子,参考网上众多例子,自己写得完成了,给大家分享 大家只要按这个目录去建文件就可以了,然后运行,至于其中原理慢慢理会吧 环境:myeclipse 10 +xfire ...