原文:https://blog.csdn.net/qq_20553613/article/details/90649734
大家好,我是ZhengN。
本次给大家带来三个Makefile模板:编译可执行程序、编译静态库、编译动态库。
往期相关推文:Makefile常用基础知识梳理!
对于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项目程序。
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
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。
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。
编写测试例程,文件存放目录结构如下,头文件存放在“include”目录,库文件存放在“lib”目录,源文件存放在“source”目录,Makefile在当前目录下。
源码1:
/*头文件*/
#ifndef _FUN0_H_
#define _FUN0_H_
#endif
extern void fun0_printf(void);
extern void fun1_printf(void);
/*源文件*/
#include
#include "fun0.h"
void fun0_printf(void)
{
printf("Call \'fun0\'. \r\n");
}
源码2:
/*头文件*/
#ifndef _FUN1_H_
#define _FUN1_H_
#endif
extern void fun1_printf(void);
/*源文件*/
#include
#include "fun1.h"
void fun1_printf(void)
{
printf("Call \'fun1\'.\r\n");
}
主函数源码:
/*源文件*/
#include
#include "fun0.h"
#include "fun1.h"
#include "fun_lib_a.h"
#include "fun_lib_so.h"
int main(void)
{
#ifdef USE_DEBUG
printf("Debug Application startup.\r\n");
#endif
fun0_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.1节”调用的库文件(libfun_a.a)。文件存放目录结构如下:
源文件:
/*头文件*/
#ifndef _FUN_LIB_A_H_
#define _FUN_LIB_A_H_
#endif
extern void fun_lib_a_printf(void);
/*源文件*/
#include
#include "fun_lib_a.h"
void fun_lib_a_printf(void)
{
printf("Call \'fun_lib_a\'.\r\n");
}
Makefile文件即为“2.2节”的Makefile模板。
编译生成静态库:
编写测试例程,生产的库文件即为“3.1节”调用的库文件(libfun_so.so)。文件存放目录结构如下:
源文件:
/*头文件*/
#ifndef _FUN_LIB_SO_H_
#define _FUN_LIB_SO_H_
#endif
extern void fun_lib_so_printf(void);
/*头文件*/
#include
#include "fun_lib_so.h"
void fun_lib_so_printf(void)
{
printf("Call \'fun_lib_so\'.\r\n");
}
编译生成动态库:
由于微信公众号近期改变了推送规则,如果您想经常看到我们的文章,可以在每次阅读后,在页面下方点一个「赞」或「在看」,这样每次推送的文章才会第一时间出现在您的订阅列表里。
免责声明:本文来源网络,免费传达知识,版权归原作者所有。如涉及作品版权问题,请联系我进行删除。
往期推荐:
跨平台构建工具,cmake是 yyds ?bjd !
C语言、嵌入式中几个非常实用的宏技巧
分享一个自用的、极简的log模块!
分享一个很酷的IDE!软工必备
C语言、嵌入式位操作精华技巧大汇总
嵌入式大杂烩周记 | 第 1 期
Hello系列 | cmake简明基础知识
干货 | 项目乏力?nanopb助你一臂之力
在公众号聊天界面回复1024,可获取嵌入式资源;回复 m ,可查看文章汇总。
点击阅读原文,查看更多分享。