1.写在前面

对于Windows下开发,很多IDE都集成了编译器,如Visual Studio,提供了“一键编译”,编码完成后只需一个操作即可完成编译、链接、生成目标文件。Linux开发与Windows不同,Linux下一般用的的gcc/g++编译器,如果是开发ARM下的Linux程序,还需用到arm-linux-gcc/arm-linux-g++交叉编译器。Linux下也可以实现“一键编译”功能,此时需要一个编译脚本“Makefile”,Makefile可以手动编写,也可以借助自动化构建工具(如scons、CMake)生成。手动编写Makefile是Linux和Windows程序员的区别之一,一般地一个通用的Makefile能够适合大部分Linux项目程序。

2.通用Makefile模板

2.1 编译可执行文件Makefile

VERSION  =1.00
CC   =gcc
DEBUG   =-DUSE_DEBUG
CFLAGS  =-Wall
SOURCES   =$(wildcard ./source/*.c)
INCLUDES   =-I./include
LIB_NAMES  =-lfun_a -lfun_so
LIB_PATH  =-L./lib
OBJ   =$(patsubst %.c, %.o, $(SOURCES))
TARGET  =app#links
$(TARGET):$(OBJ)@mkdir -p output$(CC) $(OBJ) $(LIB_PATH) $(LIB_NAMES) -o output/$(TARGET)$(VERSION)@rm -rf $(OBJ)#compile
%.o: %.c$(CC) $(INCLUDES) $(DEBUG) -c $(CFLAGS) $< -o $@.PHONY:clean
clean:@echo "Remove linked and compiled files......"rm -rf $(OBJ) $(TARGET) output

【要点说明】

【1】程序版本 开发调试过程可能产生多个程序版本,可以在目标文件后(前)增加版本号标识。

VERSION = 1.00
$(CC) $(OBJ) $(LIB_PATH) $(LIB_NAMES) -o output/$(TARGET)$(VERSION)

【2】编译器选择 Linux下为gcc/g++;arm下为arm-linux-gcc;不同CPU厂商提供的定制交叉编译器名称可能不同,如Hisilicon“arm-hisiv300-linux-gcc”。

CC = gcc

【3】宏定义 开发过程,特殊代码一般增加宏条件来选择是否编译,如调试打印输出代码。-D是标识,后面接着的是“宏”。

DEBUG =-DUSE_DEBUG

【4】编译选项 可以指定编译条件,如显示警告(-Wall),优化等级(-O)。

CFLAGS =-Wall -O

【5】源文件 指定源文件目的路径,利用“wildcard”获取路径下所有依赖源文件。

SOURCES =$(wildcard ./source/*.c)

【6】头文件 包含依赖的头文件,包括源码文件和库文件的头文件。

INCLUDES =-I./include

【7】库文件名称 指定库文件名称,库文件有固定格式,静态库为libxxx.a;动态库为libxxx.so,指定库文件名称只需写“xxx”部分,

LIB_NAMES =-lfun_a -lfun_so

【8】库文件路径 指定依赖库文件的存放路径。注意如果引用的是动态库,动态库也许拷贝到“/lib”或者“/usr/lib”目录下,执行应用程序时,系统默认在该文件下索引动态库。

LIB_PATH =-L./lib

【9】目标文件 调用“patsubst”将源文件(.c)编译为目标文件(.o)。

OBJ =$(patsubst %.c, %.o, $(SOURCES))

【10】执行文件 执行文件名称

TARGET =app

【11】编译

%.o: %.c$(CC) $(INCLUDES) $(DEBUG) $(CFLAGS) $< -o $@

【12】链接 可创建一个“output”文件夹存放目标执行文件。链接完输出目标执行文件,可以删除编译产生的临时文件(.o)。

$(TARGET):$(OBJ)@mkdir -p output$(CC) $(OBJ) $(LIB_PATH) $(LIB_NAMES) -o output/$(TARGET).$(VERSION)@rm -rf $(OBJ)

【13】清除编译信息 执行“make clean”清除编译产生的临时文件。

.PHONY:clean
clean:@echo "Remove linked and compiled files......"rm -rf $(OBJ) $(TARGET) output

2.2 编译静态库Makefile

VERSION     =
CC          =gcc
DEBUG   =
CFLAGS  =-Wall
AR   =ar
ARFLAGS     =rv
SOURCES   =$(wildcard *.c)
INCLUDES    =-I.
LIB_NAMES   =
LIB_PATH  =
OBJ         =$(patsubst %.c, %.o, $(SOURCES))
TARGET      =libfun_a#link
$(TARGET):$(OBJ)@mkdir -p output$(AR) $(ARFLAGS) output/$(TARGET)$(VERSION).a $(OBJ)@rm -rf $(OBJ)#compile
%.o: %.c$(CC) $(INCLUDES) $(DEBUG) -c $(CFLAGS) $< -o $@.PHONY:clean
clean:@echo "Remove linked and compiled files......"rm -rf $(OBJ) $(TARGET) output

【要点说明】 基本格式与“编译可执行Makefile”一致,不同点包括以下。

【1】使用到“ar”命令将目标文件(.o)链接成静态库文件(.a)。静态库文件固定命名格式为:libxxx.a。

2.3 编译动态库Makefile

VERSION   =
CC        =gcc
DEBUG     =
CFLAGS    =-fPIC -shared
LFLAGS   =-fPIC -shared
SOURCES   =$(wildcard *.c)
INCLUDES  =-I.
LIB_NAMES =
LIB_PATH  =
OBJ       =$(patsubst %.c, %.o, $(SOURCES))
TARGET    =libfun_so#link
$(TARGET):$(OBJ)@mkdir -p output$(CC) $(OBJ) $(LIB_PATH) $(LIB_NAMES) $(LFLAGS) -o output/$(TARGET)$(VERSION).so@rm -rf $(OBJ)#compile
%.o: %.c$(CC) $(INCLUDES) $(DEBUG) -c $(CFLAGS) $< -o $@.PHONY:clean
clean:@echo "Remove linked and compiled files......"rm -rf $(OBJ) $(TARGET) output

【要点说明】 基本格式与“编译可执行Makefile”一致,不同点包括以下。

【1】编译选项和链接选项增加“-fPIC -shared ”选项。动态库文件固定命名格式为libxxx.so。

3.Demo

3.1 应用程序

编写测试例程,文件存放目录结构如下,头文件存放在“include”目录,库文件存放在“lib”目录,源文件存放在“source”目录,Makefile在当前目录下。

源码1

/*头文件*/
#ifndef _FUN0_H_
#define _FUN0_H_
#endifextern void fun0_printf(void);
extern void fun1_printf(void);/*源文件*/
#include <stdio.h>
#include "fun0.h"void fun0_printf(void)
{printf("Call \'fun0\'. \r\n");
}

源码2

/*头文件*/
#ifndef _FUN1_H_
#define _FUN1_H_
#endifextern void fun1_printf(void);/*源文件*/
#include <stdio.h>
#include "fun1.h"void fun1_printf(void)
{printf("Call \'fun1\'.\r\n");
}

主函数源码

/*源文件*/
#include <stdio.h>
#include "fun0.h"
#include "fun1.h"
#include "fun_lib_a.h"
#include "fun_lib_so.h"int main(void)
{#ifdef USE_DEBUGprintf("Debug Application startup.\r\n");#endiffun0_printf();fun1_printf();fun_lib_a_printf();fun_lib_so_printf();return 0;
}

库文件,“./lib”目录下存放两个库文件,一个静态库libfun_a.a,一个动态库libfun_so.so。

Makefile文件即为“2.1节”的Makefile模板。

测试运行:

【如果执行文件提示无“libfun_so.so”,则需拷贝“libfun_so.so”到根目录下的“/lib”或者“/usr/lib”目录下,因为系统执行程序,默认从该路径引脚动态库】

3. 2 生成静态库

编写测试例程,生产的库文件即为“3.1节”调用的库文件(libfun_a.a)。文件存放目录结构如下

源文件

/*头文件*/
#ifndef _FUN_LIB_A_H_
#define _FUN_LIB_A_H_
#endifextern void fun_lib_a_printf(void);/*源文件*/
#include <stdio.h>
#include "fun_lib_a.h"void fun_lib_a_printf(void)
{printf("Call \'fun_lib_a\'.\r\n");
}

Makefile文件即为“2.2节”的Makefile模板。

编译生成静态库

3. 3 生成静态库

编写测试例程,生产的库文件即为“3.1节”调用的库文件(libfun_so.so)。文件存放目录结构如下

源文件

/*头文件*/
#ifndef _FUN_LIB_SO_H_
#define _FUN_LIB_SO_H_
#endifextern void fun_lib_so_printf(void);/*头文件*/#include <stdio.h>
#include "fun_lib_so.h"void fun_lib_so_printf(void)
{printf("Call \'fun_lib_so\'.\r\n");
}

编译生成动态库

一个适用各类场合的Makefile模板相关推荐

  1. 一个使用多年的Makefile模板

    layout: post title: category : linux系统 tags : [Makefile] 许久以前,一直使用自己总结的Makefile模板,这个模板也是基于现有资料整理而成的. ...

  2. 一个STM32编译Makefile模板

    最近突然对STM32感兴趣,研究了一下.STM32的编译方式非常多,由于一直对gcc情有独钟,所以还是喜欢使用Makefile+gcc编译的方法.当时从51单片机转向AVR单片机开发时,也是通过这种方 ...

  3. 复杂多目录的Makefile模板及示例

    大约一年多以前,还在移植u-boot,当时参考了u-boot的Makefile,做了一个多目录的Makefile模板.如今,一年过去了,本篇文章还是折腾Makefile模板,本人的水平由此可见一斑.当 ...

  4. 复杂多目录的Makefile模板及示例-转

    大约一年多以前,还在移植u-boot,当时参考了u-boot的Makefile,做了一个多目录的Makefile模板.如今,一年过去了,本篇文章还是折腾Makefile模板,本人的水平由此可见一斑.当 ...

  5. Makefile模板的继续改进

    layout: post title: category : linux系统 tags : [Makefile] 上一文章的Makefile,存在一个比较大的问题,那就是生成可执行的二进制文件时,会链 ...

  6. GNU/Linux智能Makefile模板(多目录,多文件)

    本文提供一个在GNU/Linux环境下通用的智能Makefile模板,用户可以将其引入到自己的工程当中.即使用户对此 Makefile的工作原理不甚了解,但是只需要修改少数几个关键变量,就可以满足不同 ...

  7. 万能 Makefile 模板

    在 Linux 编程时,对于很多小工程来说,很多时候似乎没有必要用 autoconf 和 automake 工具来生成 Makefile,反而自己写一个 Makefile 更省事.这里给大家提供一个简 ...

  8. LINUX驱动Makefile模板

    网上有好多关于驱动的Makefile怎么写,驱动程序怎么运行,为什么驱动会没有main等等问题的问题的问题.下面我也给出我的驱动Makefile模板,这些东东都是在书籍和人家的研究成果上改进而来的,至 ...

  9. 关于中型工程的Makefile模板

    我们定义的中型工程 可能会有多层嵌套的源代码文件夹 一个源代码文件夹下可能有多个源代码子文件夹 中间文件应当在其源文件所在目录生成,而不是同一生成到一个目录下(如统一生成到obj目录下) (大多数情况 ...

最新文章

  1. Xcode 4.4 的新特性 | LLVM 4.0 的新语法
  2. 在windows7上的通过composer安装yii2
  3. Spring 的前世今生
  4. 多模态语义分析_情感分析、多模态NLP、多语言翻译...这场NLP知识盛宴不可错过!...
  5. Nginx学习笔记(五) 源码分析内存模块内存对齐
  6. 八个角最多可以把平面分成多少部分?_平面设计构图的基本形式
  7. joblib多线程、多进程学习案例(三)
  8. Git使用相关问题汇总
  9. 解决VC++6.0打开文件或添加文件到工程出错的问题
  10. 谷歌浏览器无法定位程序输入点解决方法
  11. 极验验证码(6.0.9)破解(一) 之 抓包分析
  12. java解二元一次方程组_如何用C语言解二元一次方程组
  13. 计算机复制粘贴不可用问题解决,电脑复制粘贴功能失效无法复制粘贴文字怎么办...
  14. 转 鲁迅《随感录》之一二
  15. jdk1.8 在綫英文+有道翻譯版
  16. GitHub使用gitBash配置用户名和邮箱和远程操作二
  17. 什么是前提、行为及后果?
  18. Adobe Flash Player已不再受支持怎么解决?
  19. iPad连android热点掉线,iphone热点总掉线怎么办?苹果手机保持热点不断开的方法...
  20. 手机gif图片怎么压缩变小?gif动图怎样缩小?

热门文章

  1. materialrefeshlayout下拉刷新,上拉加载更多
  2. Kali-linux使用Nessus
  3. ASP.NET后台调用前台JS函数的三种常见方法
  4. MEncoder 使用实例
  5. NoSuchElementException
  6. Flask爱家租房--订单(房东接单、拒单)
  7. Django models中关于blank与null的补充说明
  8. Django 时间与时区设置问题
  9. MySQL5.7升级到8.0 之后,配合ubantu18.04遇到的常规问题以及非常规问题的解决方案
  10. python中的常量是什么意思_第14p,Python中的常量与注释。