Linux Makefile通用模板详解

2023-08-08 10:21:57 来源:CSDN-Acuity.

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、3个Makefile模板

2.1 编译可执行文件Makefile

VERSION=1.00CC=gccDEBUG=-DUSE_DEBUGCFLAGS=-WallSOURCES=$(wildcard./source/*.c)INCLUDES=-I./includeLIB_NAMES=-lfun_a-lfun_soLIB_PATH=-L./libOBJ=$(patsubst%.c,%.o,$(SOURCES))TARGET=app#links$(TARGET):$(OBJ)@mkdir-poutput$(CC)$(OBJ)$(LIB_PATH)$(LIB_NAMES)-ooutput/$(TARGET)$(VERSION)@rm-rf$(OBJ)#compile%.o:%.c$(CC)$(INCLUDES)$(DEBUG)-c$(CFLAGS)$<-o$@.PHONY:cleanclean:@echo"Removelinkedandcompiledfiles......"rm-rf$(OBJ)$(TARGET)output

【要点说明】

【1】程序版本

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

VERSION=1.00$(CC)$(OBJ)$(LIB_PATH)$(LIB_NAMES)-ooutput/$(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-poutput$(CC)$(OBJ)$(LIB_PATH)$(LIB_NAMES)-ooutput/$(TARGET).$(VERSION)@rm-rf$(OBJ)

【13】清除编译信息

执行“make clean”清除编译产生的临时文件。

.PHONY:cleanclean:@echo"Removelinkedandcompiledfiles......"rm-rf$(OBJ)$(TARGET)output

2.2 编译静态库Makefile

VERSION=CC=gccDEBUG=CFLAGS=-WallAR=arARFLAGS=rvSOURCES=$(wildcard*.c)INCLUDES=-I.LIB_NAMES=LIB_PATH=OBJ=$(patsubst%.c,%.o,$(SOURCES))TARGET=libfun_a#link$(TARGET):$(OBJ)@mkdir-poutput$(AR)$(ARFLAGS)output/$(TARGET)$(VERSION).a$(OBJ)@rm-rf$(OBJ)#compile%.o:%.c$(CC)$(INCLUDES)$(DEBUG)-c$(CFLAGS)$<-o$@.PHONY:cleanclean:@echo"Removelinkedandcompiledfiles......"rm-rf$(OBJ)$(TARGET)output

【要点说明】

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

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

2.3 编译动态库Makefile

VERSION=CC=gccDEBUG=CFLAGS=-fPIC-sharedLFLAGS=-fPIC-sharedSOURCES=$(wildcard*.c)INCLUDES=-I.LIB_NAMES=LIB_PATH=OBJ=$(patsubst%.c,%.o,$(SOURCES))TARGET=libfun_so#link$(TARGET):$(OBJ)@mkdir-poutput$(CC)$(OBJ)$(LIB_PATH)$(LIB_NAMES)$(LFLAGS)-ooutput/$(TARGET)$(VERSION).so@rm-rf$(OBJ)#compile%.o:%.c$(CC)$(INCLUDES)$(DEBUG)-c$(CFLAGS)$<-o$@.PHONY:cleanclean:@echo"Removelinkedandcompiledfiles......"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_#endifexternvoidfun0_printf(void);externvoidfun1_printf(void);/*源文件*/#include#include"fun0.h"voidfun0_printf(void){printf("Call"fun0".");}

源码2:

/*头文件*/#ifndef_FUN1_H_#define_FUN1_H_#endifexternvoidfun1_printf(void);/*源文件*/#include#include"fun1.h"voidfun1_printf(void){printf("Call"fun1".");}

主函数源码:

/*源文件*/#include#include"fun0.h"#include"fun1.h"#include"fun_lib_a.h"#include"fun_lib_so.h"intmain(void){#ifdefUSE_DEBUGprintf("DebugApplicationstartup.");#endiffun0_printf();fun1_printf();fun_lib_a_printf();fun_lib_so_printf();return0;}

库文件,“./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_#endifexternvoidfun_lib_a_printf(void);/*源文件*/#include#include"fun_lib_a.h"voidfun_lib_a_printf(void){printf("Call"fun_lib_a".");}

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

编译生成静态库:

3. 3 生成动态库

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

源文件:

/*头文件*/#ifndef_FUN_LIB_SO_H_#define_FUN_LIB_SO_H_#endifexternvoidfun_lib_so_printf(void);/*头文件*/#include#include"fun_lib_so.h"voidfun_lib_so_printf(void){printf("Call"fun_lib_so".");}

编译生成动态库:

审核编辑:汤梓红

标签:

上一篇:解析C语言断言函数的使用
下一篇:最后一页