Ubuntu下比较通用的makefile实例
本文转自http://blog.chinaunix.net/uid-20608849-id-360294.html
- src/a/a.c
- src/b/b.c
- src/main.c
- build/a/a.o 和a.d
- build/b/b.o 和b.d
- build/main.o 和main.d
- ......
- TARGETMAIN = testmk
- OBJECTDIR = build
- VPATH = $(shell ls -AxR ./src|grep ":"|grep -v "\.svn"|tr -d ':')
- SOURCEDIRS = $(VPATH)
- # search source file in the current dirs
- SOURCES = $(foreach subdir,$(SOURCEDIRS),$(wildcard $(subdir)/*.c))
- SRCOBJS = $(patsubst %.c,%.o,$(SOURCES))
- BASE_FILES = $(notdir $(TMSRCOBJS))
- BUILDOBJS = $(BASE_FILES:%=$(OBJECTDIR)/%)
- all:$(TARGETMAIN)
- $(TARGETMAIN) :$(BUILDOBJS)
- $(CC) $(CFLAGS) -o $@ -c $<
- @$(STRIP) --strip-unneeded $(TARGETMAIN)
- ......
- $(OBJECTDIR)/%.o: %.c $(DEPS_DIR)
- @$(CC) $(CPPFLAGS) $(CFLAGS) -o $@ -c $<
- #声明伪目标,防止Makefile去生成all等
- .PHONY = all install clean
- #定义路径变量,所有.c文件和所有非公开的.h应该放在src下,所有需要的.a文件放在lib
- #下,所有公开的.h(比如生成库文件的时候)或者多个.c公用的.h放在include文件夹下
- #global directory defined
- TOPDIR = $(shell pwd)
- SRCDIR = $(TOPDIR)/src
- LIBDIR = $(TOPDIR)/lib
- OBJECTDIR = $(TOPDIR)/build
- INCLUDEDIR = $(TOPDIR)/include
- #定义交叉编译环境变量,当需要编译arm/mips等平台应用程序/库的时候修改它
- #cross compile tools defined
- 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
- RANLIB = $(CROSS_COMPILE)ranlib
- #本机相关的命令,一般无需修改
- #local host tools defined
- CP := cp
- RM := rm
- MKDIR := mkdir
- SED := sed
- FIND := find
- MKDIR := mkdir
- XARGS := xargs
- #目标名称,这里我们给出了三种常用的目标格式:目标文件,静态库和共享库
- #target name
- TARGETMAIN = testmk
- TARGETLIBS = libmk.a
- TARGETSLIBS = libmk.so
- #所有源码文件的路径被放入SOURCEDIRS,所有.c源码文件(含路径)放入SOURCES
- #.c .o and .d files defined
- VPATH = $(shell ls -AxR $(SRCDIR)|grep ":"|grep -v "\.svn"|tr -d ':')
- SOURCEDIRS = $(VPATH)
- SOURCES = $(foreach subdir,$(SOURCEDIRS),$(wildcard $(subdir)/*.c))
- #所有目标文件.o(含路径)放入BUILDOBJS,注意它们的路径已经是build了。
- SRCOBJS = $(patsubst %.c,%.o,$(SOURCES))
- BUILDOBJS = $(subst $(SRCDIR),$(OBJECTDIR),$(SRCOBJS))
- #所有.d依赖文件放入DEPS
- DEPS = $(patsubst %.o,%.d,$(BUILDOBJS))
- #注意-MD,是为了生成.d文件后,构造对.h的依赖
- #external include file define
- CFLAGS = -O2 -Wall -MD $(foreach dir,$(INCLUDEDIR),-I$(dir))
- ARFLAGS = rc
- #special parameters for app
- CFLAGS +=
- #LDFLAGS指明所有-llibxx,libxx.a应该放到lib下,当然也可以添加.so。Xlinker是为了
- #在提供多个.a时,未知它们之间的依赖顺序时,自动查找依赖顺序
- #c file compile parameters and linked libraries
- CPPFLAGS =
- LDFLAGS =
- XLDFLAGS = -Xlinker "-(" $(LDFLAGS) -Xlinker "-)"
- LDLIBS += -L $(LIBDIR)
- #如果要生成.a或者.so,那么不要将main函数所在的.c放入src。另外添加$(TARGETLIBS)
- #或$(TARGETSLIBS)到all中
- #defaut target:compile the currrent dir file and sub dir
- all: $(TARGETMAIN)
- #for .h header files dependence
- -include $(DEPS)
- $(TARGETMAIN) :$(BUILDOBJS)
- @$(CC) $(subst $(SRCDIR),$(OBJECTDIR),$^) $(CPPFLAGS) $(CFLAGS) $(XLDFLAGS) -o $@ $(LDLIBS)
- @$(STRIP) --strip-unneeded $(TARGETMAIN)
- $(TARGETLIBS) :$(BUILDOBJS)
- @$(AR) $(ARFLAGS) $@ $(BUILDOBJS)
- @$(RANLIB) $@
- $(TARGETSLIBS) :$(BUILDOBJS)
- @$(CC) -shared $(subst $(SRCDIR),$(OBJECTDIR),$^) $(CPPFLAGS) $(CFLAGS) $(XLDFLAGS) -o $@ $(LDLIBS)
- #这里是Makefile的核心,根据%中的内容,查找src路径下对应的.c,注意到$@和$<自动
- #变量的取值,首先查看路径build/xx是否存在,不存在则创建,然后我们尝试将$@中的src
- #替换为build,这样所有的.o和.d都将被创建到对应的build下了。
- $(OBJECTDIR)%.o: $(SRCDIR)%.c
- @[ ! -d $(dir $(subst $(SRCDIR),$(OBJECTDIR),$@)) ] & $(MKDIR) -p $(dir $(subst $(SRCDIR),$(OBJECTDIR),$@))
- @$(CC) $(CPPFLAGS) $(CFLAGS) -o $(subst $(SRCDIR),$(OBJECTDIR),$@) -c $<
- #添加安装的路径
- intall:
- clean:
- @$(FIND) $(OBJECTDIR) -name "*.o" -o -name "*.d" | $(XARGS) $(RM) -f
- @$(RM) -f $(TARGETMAIN) $(TARGETLIBS) $(TARGETSLIBS)
经测试,完全满足了要求,虽然不是完美无缺,但是对于通常的工程项目,是绰绰有余了,欢迎大家指正,以便改善。
另外对于Makefile的理解,个人认为可以分成几个部分:依赖关系,自定义变量和自动变量以及Makefile提供的相关函数。理解了它们,对写出结构良好,通用性强的Makefile会有大的帮助,虽然现在有了automake,但是研究一下Makefile的写法还是有收获的。
附件testmk.rar中提供了一个完整的测试程序,目录如下:
- |-- build
- |-- include
- | `-- hello.h
- |-- lib
- |-- Makefile
- `-- src
- |-- a
- | `-- a.c
- |-- b
- | `-- b.c
- `-- main.c
- 6 directories, 5 files
在linux下解压开后运行命令一下命令,可以根据需要定制Makefile。
- #make // 当前目录下生成testmk
- #make libmk.a // 当前目录下生成libmk.a
- #make libmk.so // 当前目录下生成libmk.so
参考资料:
- 跟我一起写Makefile(通俗易懂,易于理解)
- GNU make中文手册(内容很全,是对GNU makefile手册的完全翻译,做手册参考)
思考:
根据Makefile的依赖原理,似乎应该使用一个树类型的结构,a依赖b,c等,b又依赖其他的文件,但是不能反方向依赖(否则为死循环),但是d可以同时依赖b,c,所以不是简单的树形结构,应该是一个图,另外依赖是有方向性的,所以应该是一个有向图结构的实现,不知道对不对?
--------------------------------------------------------------------------------分割线--------------------------------------------------------------------------------------
文件testCmakefile和testCPPmakefile分别是真的c和c++的两个实例,两者makefile内容主要的区别就是编译器gcc和g++,以及后缀.c和.cpp。其他的地方都不用修改。
Ubuntu下比较通用的makefile实例的更多相关文章
- Ubuntu下通过makefile生成静态库和动态库简单实例
本文转自http://blog.csdn.net/fengbingchun/article/details/17994489 Ubuntu环境:14.04 首先创建一个test_makefile_gc ...
- Ubuntu 14.04下 Java通用安装方法
参考: 解决Floodlight1.2+Mininet问题及使用安装 Ubuntu下安装JDK1.7图文详解 Ubuntu 14.04下 Java通用安装方法 1.到oracle官网下下载对应jdk包 ...
- 在Ubuntu下安装imx6linux系统的交叉编译环境遇到的问题总结
这段时间一直忙于手上的嵌入式项目,可以说自己从嵌入式的菜鸟一点点的入门了,关于嵌入式和imx6核心板的开发有了一点的了解,尤其是对于板子环境的搭建.硬件的开发,搭建环境,是一个很大的工程量,也是很重要 ...
- 搭建Ubuntu下c/c++编译环境【转】
1. 安装Ubuntu. 2. 安装gcc 方法一: sudo apt-get install build-essential 安装完了可以执行 gcc--version的 ...
- ubuntu下常用命令
目录 一.查找命令 二.打开相应文件 三.查看系统资源占用 四.Ubantu解压文件 五.虚拟机ubuntu server 14.0 根目录扩容 七.ubuntu 关机,重启,注销命令 1 关机命令 ...
- 编写一个通用的Makefile文件
1.1在这之前,我们需要了解程序的编译过程 a.预处理:检查语法错误,展开宏,包含头文件等 b.编译:*.c-->*.S c.汇编:*.S-->*.o d.链接:.o +库文件=*.exe ...
- Linux C编程学习之开发工具3---多文件项目管理、Makefile、一个通用的Makefile
GNU Make简介 大型项目的开发过程中,往往会划分出若干个功能模块,这样可以保证软件的易维护性. 作为项目的组成部分,各个模块不可避免的存在各种联系,如果其中某个模块发生改动,那么其他的模块需要相 ...
- 来杯Caffe——在ubuntu下安装Caffe框架并测试
Caffe是一种深度学习框架...blablabla...... Caffe要在ubuntu下安装 1. 安装依赖 sudo apt-get install libatlas-base-dev sud ...
- windows、ubuntu下eclipse搭建java、Python环境问题总结
前两篇博文分别讲述了如何在windows.ubuntu下用eclipse搭建java.python环境,下面就针对本人遇到的问题做一个总结. 一.windows下关于java环境变量JAVA_HOME ...
随机推荐
- 关于ng-options
在实际使用过程中对angular的ng-options指令有点不解,有的时候觉得很容易理解和上手,但其实等到遇到问题时,发现它很是生疏,(key,value)键值对获取,as关键词,track by ...
- java集合系列——List集合之LinkedList介绍(三)
1. LinkedList的简介 JDK 1.7 LinkedList是基于链表实现的,从源码可以看出是一个双向链表.除了当做链表使用外,它也可以被当作堆栈.队列或双端队列进行操作.不是线程安全的,继 ...
- JAVA HashMap 解析
1.简介(其实是HashMap注释的大致翻译) 本文基于JDK1.8,与JDK1.7中的HashMap有一些区别,看官注意区别. HashMap实现了Map接口,提供了高效的Key-Value访问.H ...
- 读Zepto源码之IOS3模块
IOS3 模块是针对 IOS 的兼容模块,实现了两个常用方法的兼容,这两个方法分别是 trim 和 reduce . 读 Zepto 源码系列文章已经放到了github上,欢迎star: readin ...
- Spring Boot-------JPA——EntityManager构建通用DAO
EntityManager EntityManager 是用来对实体Bean 进行操作的辅助类.他可以用来产生/删除持久化的实体Bean,通过主键查找实体bean,也可以通过EJB3 QL 语言查找满 ...
- NOIP2017SummerTraining0712
个人感受:打了三个小时不到的第一题,然后也就没有多少时间去搞第二题了,特别是第二题还看到了期望这样的东西,这个难以理解,第三题的树分治,myx大佬说50分好拿,但是我觉得也挺难拿的. 单词检索 时间限 ...
- Codeforces Round #430 (Div. 2)
A. Kirill And The Game time limit per test 2 seconds memory limit per test 256 megabytes input stand ...
- PHP的ntohl网络字节序函数及相关知识
PHP与C服务器的socket通信,在做数据转换的时候,PHP没有提供对应将网络字节序和机器字节序相互转换的程序,但是根据函数的意义,我们可以做相应的转换来实现这一函数: function ntohl ...
- PS 软件操作应用处理——粒子化任务效果
前 言 JRedu 上次分享中,给大家介绍了一些图片的处理方法,主要是通过滤镜里的功能,把图片处理成素描效果或者水彩画效果,营造出不同的氛围. PS是一款非常强大的软件,包含了非常多的功能,合成 ...
- Python面试题之copy/deepcopy详解
copy和deepcopy有什么区别? http://blog.csdn.net/qq_32907349/article/details/52190796 http://iaman.actor/blo ...