几个Makefile通用模板分享!

news/2024/6/29 11:51:22 标签: 嵌入式, 编译器, java, linux, c++

原文:https://blog.csdn.net/qq_20553613/article/details/90649734

大家好,我是ZhengN。

本次给大家带来三个Makefile模板:编译可执行程序、编译静态库、编译动态库。

往期相关推文:Makefile常用基础知识梳理!

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.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在当前目录下。

5362852f6f86c2b82799fd5c7b47f2c6.png

源码1:

/*头文件*/
#ifndef _FUN0_H_
#define _FUN0_H_
#endif

extern 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_
#endif

extern 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_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模板。

测试运行:

17997ca32bf31d2d8423028395d0401e.png

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

3. 2 生成静态库

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

2cc88f8b943cde1d1fc4cc60c1381f18.png

源文件:

/*头文件*/
#ifndef _FUN_LIB_A_H_
#define _FUN_LIB_A_H_
#endif

extern 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模板。

编译生成静态库:

c47bd6f24035d4d2d23c7a52f05fdf35.png

3. 3 生成动态库

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

7d2c6081f4f64bee0f22ec5bffabc993.png

源文件:

/*头文件*/
#ifndef _FUN_LIB_SO_H_
#define _FUN_LIB_SO_H_
#endif

extern 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");
}

编译生成动态库:

b356ddd92fc6f8c34ec5e24637e61724.png

温馨提示

由于微信公众号近期改变了推送规则,如果您想经常看到我们的文章,可以在每次阅读后,在页面下方点一个「赞」或「在看」,这样每次推送的文章才会第一时间出现在您的订阅列表里。

免责声明:本文来源网络,免费传达知识,版权归原作者所有。如涉及作品版权问题,请联系我进行删除。

往期推荐:

跨平台构建工具,cmake是 yyds ?bjd !

C语言、嵌入式中几个非常实用的宏技巧

分享一个自用的、极简的log模块!

分享一个很酷的IDE!软工必备

C语言、嵌入式位操作精华技巧大汇总

嵌入式大杂烩周记 | 第 1 期

Hello系列 | cmake简明基础知识

干货 | 项目乏力?nanopb助你一臂之力

在公众号聊天界面回复1024,可获取嵌入式资源;回复 m ,可查看文章汇总。

点击阅读原文,查看更多分享。


http://www.niftyadmin.cn/n/503824.html

相关文章

word排版快捷指令_WORD排版键盘流,快捷键是啥了?

展开全部很简单的&#xff0c;熟能生巧&#xff0c;WORD常用快捷键&#xff1a;62616964757a686964616fe59b9ee7ad9431333332633662 CtrlShiftSpacebar   创建不间断空格Ctrl -(连字符)     创建不间断连字符CtrlB          使字符变为粗体CtrlI       …

晒晒公司的权限管理(一)

阅读全文&#xff1a;http://www.cckan.net/forum.php?modviewthread&tid315 先谈想法 我记得我之前用很不怎么样的代码规范写过一个关于权限管理 的系统&#xff0c;分享一下自己动手做出来的后台权限管理系统 因为当时的水平有限&#xff0c;呵呵&#xff0c; 这个权限管…

adc0804模数转换实验报告_ADC0804 模数转换51单片机程序+电路图

51单片机驱动 adc0804模数转换 &#xff0c;下面是电路图#include#include "lcd.h"#include#define uint unsigned int#define uchar unsigned charuchar lcd[]"0123456789";sbit rdP3^6; //IO口定义sbit wrP3^5;sbit csP3^7;read_adc0804()//控制并读取ad…

干货 | 嵌入式OTA升级实现原理

原文&#xff1a;https://blog.csdn.net/bulebin/article/details/108428643一、简介 1.1 概念OTA&#xff1a;Over-the-Air Technology&#xff0c;即空中下载技术。OTA升级&#xff1a;通过OTA方式实现固件或软件的升级。只要是通过无线通信方式实现升级的&#xff0c;都可以…

电子商务市场的主要分类

整个电子商务处理过程中&#xff0c;可将商务分为&#xff1a;企业内部、企业间及企业与消费者之间三种类型。1、企业内部商务通过防火墙&#xff0c;公司将自己的内部网与Internet隔离&#xff0c;企业内部网(Internet)是一种有效的商务工具&#xff0c;它可以用来自动处理商务…

嵌入式大杂烩周记 | 第 3 期:sys/queue.h

大家好&#xff0c;我是杂烩君。 嵌入式大杂烩周记主要是一些实用项目学习分享&#xff0c;每周一篇&#xff0c;每篇一个主题。 内容主要来源于我们之前收集的资料&#xff1a; https://gitee.com/zhengnianli/EmbedSummary 本期主角&#xff1a;sys/queue.h queue.h是Linux、…

fopen失败导致程序直接结束_6174数字黑洞的程序证明(附源代码)

在小学生的趣味数学的读物中&#xff0c;很容易读到一个有趣的命题&#xff1a;6174数字黑洞。这个数字黑洞的意思是&#xff1a;一个四位数&#xff0c;只要四个数字不是全都一样(不是1111&#xff0c;2222…这样)&#xff0c;进行以下操作&#xff1a;把数字从大到小排列成一…

Virtualization with Xen

Basic requirement: cpu need to have pae(physical memory extention)# yum groupinstall virtualization转载于:https://blog.51cto.com/johnnyxing/406858