代码结构
所有代码都已通过测试跑通,其中代码结构如下:
一、include文件夹
1.1 common.h
#ifndef _COMMON_H
#define _COMMON_Htypedef struct Region {int iLeftUpX; //区域左上方的坐标int iLeftUpY; //区域左下方的坐标int iWidth; //区域宽度int iHeigh; //区域高度
}Region, *PRegion;#endif
1.2 disp_manager.h
#ifndef _DISP_MANAGER_H //防止头文件重复包含,只要右边的出现过,就不会再往下编译
#define _DISP_MANAGER_H
#include<common.h>//区域结构体
typedef struct DispBuff {int iXres; int iYres; int iBpp; char *buff;
}DispBuff, *PDispBuff;
//区域结构体
/*
typedef struct Region {int iLeftUpX; //区域左上方的坐标int iLeftUpY; //区域左下方的坐标int iWidth; //区域宽度int iHeigh; //区域高度
}Region, *PRegion;
*/
//显示设备结构体(LCD设备或者是web设备),通过调用这个结构体中的函数来实现显示功能
typedef struct DispOpr {char *name; //设备名int (*DeviceInit)(void);//设备初始化函数int (*DeviceExit)(void);//设备清除int (*GetBuffer)(PDispBuff ptDispBuff);///用于获取lcd所需的内存空间,return内存空间的首地址//argument1-lcd屏长度,argument2-lcd屏宽度,argument3-每一个像素点的位数。int (*FlushRegion)(PRegion ptRegion, PDispBuff ptDispBuff);//刷新出argum1-按钮区域,argum2-区域数据struct DispOpr *ptNext;//结构体指针,指向下一个设备机构体 多设备输出
}DispOpr,*PDispOpr;void RegisterDisplay(PDispOpr ptDispOpr);
void DisplayInit(void);
int SelectDefaultDisplay(char *name);
int InitDefaultDisplay(void);
int PutPixel(int x, int y, unsigned int dwColor);
int FlushDisplayRegion(PRegion ptRegion, PDispBuff ptDispBuff);
PDispBuff GetDisplayBuffer(void);void DrawRegion(PRegion ptRegion, unsigned int dwColor);
void DrawTextInRegionCentral(char *name, PRegion ptRegion, unsigned int dwColor);#endif
1.3 font_manager.h
#ifndef _FONT_MANAGER_H
#define _FONT_MANAGER_H
#include <common.h>
//描述字体位图
typedef struct FontBitMap {Region tRegion;int iCurOriginX;//当期字符基点x坐标int iCurOriginY;//当期字符基点y坐标int iNextOriginX;//下一个字符基点x坐标int iNextOriginY;//下一个字符基点y坐标unsigned char *pucBuffer;
}FontBitMap, *PFontBitMap;
//描述字库操作
typedef struct FontOpr {char *name;int (*FontInit)(char *aFineName);//字体初始化int (*SetFontSize)(int iFontSize);//字体大小int (*GetFontBitMap)(unsigned int dwCode, PFontBitMap ptFontBitMap);//获得字符位图,存到ptFontBitMap中struct FontOpr *ptNext;//方便支持多种字库
}FontOpr, *PFontOpr;void RegisterFont(PFontOpr ptFontOpr);
void FontsRegister(void);
int SelectAndInitFont(char *aFontOprName, char *aFontFileName);
int SetFontSize(int iFontSize);
int GetFontBitMap(unsigned int dwCode, PFontBitMap ptFontBitMap);
#endif
1.4 input_manager.h
#ifndef _INPUT_MANAGER_H //防止头文件重复包含,只要右边的出现过,就不会再往下编译
#define _INPUT_MANAGER_H
#include <sys/time.h>#define INPUT_TYPE_TOUCH 1
#define INPUT_TYPE_NET 2
/* 上报的数据格式 */
typedef struct InputEvent
{struct timeval tTime; //加入时间管理int iType; //网络事件或者触摸事件类型int iX; //触摸事件x坐标int iY; //触摸事件y坐标int iPressure; //触摸事件压力char str[1024]; //网络事件字符串
} InputEvent, *PInputEvent;/* 不同的输入设备,应该模块化,使用下面的结构体表示输入设备 */
typedef struct InputDevice
{char *name; //设备名称int (*GetInputEvent)(PInputEvent ptInputEvent); //获得数据int (*DeviceInit)(void);int (*DeviceExit)(void);struct InputDevice *ptNext; //加入链表,将多个输入设备链接到一起
} InputDevice, *PInputDevice;#endif
1.5 ui.h
#ifndef _UI_H_
#define _UI_H_
#include<common.h>
#include<disp_manager.h>
#include<input_manager.h>#define BUTTON_DEFAULT_COLOR 0xff0000
#define BUTTON_PRESSED_COLOR 0x00ff00
#define BUTTON_TEXT_COLOR 0x000000struct Button;
/* 函数指针(绘制按键) */
typedef int (*ONDRAW_FUNC)(struct Button *ptButton, PDispBuff ptDispBuff);
/* 函数指针(按下按钮) */
typedef int (*ONPRESSED_FUNC)(struct Button *ptButton, PDispBuff ptDispBuff, PInputEvent ptInputEvent);typedef struct Button {char *name; // 按键 名字int status; //按键 按下状态Region tRegion; // 按键的区域ONDRAW_FUNC OnDraw; //一个 ONDRAW_FUNC 类型的函数指针,用于指向按钮绘制函数ONPRESSED_FUNC OnPressed; //一个 ONPRESSED_FUNC 类型的函数指针,用于指向按钮按下事件处理函数
}Button, *PButton;#endif
二、button文件夹
2.1 button.c
#include<ui.h>
#include <string.h>
#include <disp_manager.h>
static int DefaultOnDraw(struct Button *ptButton, PDispBuff ptDispBuff){/* 绘制底色 DrawRegion追加在disp_manager.c中 */DrawRegion(&ptButton->tRegion, BUTTON_DEFAULT_COLOR); // 红色 0xff0000/* 居中写文字 DrawTextInRegionCentral追加在disp_manager.c中*/DrawTextInRegionCentral(ptButton->name, &ptButton->tRegion, BUTTON_TEXT_COLOR); //黑色 0x000000/* flush to lcd/web */FlushDisplayRegion(&ptButton->tRegion, ptDispBuff);return 0;}
static int DefaultOnPressed(struct Button *ptButton, PDispBuff ptDispBuff, PInputEvent ptInputEvent)
{unsigned int dwColor = BUTTON_DEFAULT_COLOR; ptButton->status = !ptButton->status;if (ptButton->status)dwColor = BUTTON_PRESSED_COLOR;/* 绘制底色 */DrawRegion(&ptButton->tRegion, dwColor);/* 居中写文字 */DrawTextInRegionCentral(ptButton->name, &ptButton->tRegion, BUTTON_TEXT_COLOR);/* flush to lcd/web */FlushDisplayRegion(&ptButton->tRegion, ptDispBuff);return 0;
}void InitButton(PButton ptButton, char *name, PRegion ptRegion, ONDRAW_FUNC OnDraw, ONPRESSED_FUNC OnPressed)
{ptButton->status = 0; //初始状态为 0 ,未按下ptButton->name = name;ptButton->tRegion = *ptRegion; // 按钮的区域ptButton->OnDraw = OnDraw ? OnDraw : DefaultOnDraw; //若 OnDraw 为空,则执行默认绘制函数DefaultOnDrawptButton->OnPressed = OnPressed ? OnPressed : DefaultOnPressed; //若 OnPressed 为空,则执行默认绘制函数DefaultOnPressed
}
2.2 Makefile
EXTRA_CFLAGS :=
CFLAGS_file.o :=
obj-y +=button.o
三、display文件夹
3.1 disp_manager.c
#include "disp_manager.h"
#include "font_manager.h"
#include <stdio.h>
#include <string.h>
//管理底层lcd和web
/* display_manager.c */
static PDispOpr g_DispDevs = NULL;//设备链表表头
static PDispOpr g_DispDefault = NULL;
static DispBuff g_tDispBuff;static unsigned int line_width;
static unsigned int pixel_width;
//绘制像素
int PutPixel(int x, int y, unsigned int dwColor)
{char *pen_8 = g_tDispBuff.buff+y*line_width+x*pixel_width;unsigned short *pen_16; unsigned int *pen_32; unsigned int red, green, blue; pen_16 = (unsigned short *)pen_8;pen_32 = (unsigned int *)pen_8;switch (g_tDispBuff.iBpp){case 8:{*pen_8 = dwColor;break;}case 16:{/* 565 */red = (dwColor >> 16) & 0xff;green = (dwColor >> 8) & 0xff;blue = (dwColor >> 0) & 0xff;dwColor = ((red >> 3) << 11) | ((green >> 2) << 5) | (blue >> 3);*pen_16 = dwColor;break;}case 32:{*pen_32 = dwColor;break;}default:{printf("can't surport %dbpp\n", g_tDispBuff.iBpp);break;}}return 0;
}void RegisterDisplay(PDispOpr ptDispOpr)
{ptDispOpr->ptNext = g_DispDevs;g_DispDevs = ptDispOpr;
}//链表中如果存在多个设备,则需要进行设备选择
int SelectDefaultDisplay(char *name)
{PDispOpr pTmp = g_DispDevs;//从表头开始遍历while (pTmp) {if (strcmp(name, pTmp->name) == 0)//找到了{g_DispDefault = pTmp;return 0;}pTmp = pTmp->ptNext;}return -1;
}int InitDefaultDisplay(void)
{int ret;ret = g_DispDefault->DeviceInit(); /*在调用前文SelectDefaultDisplay函数后,g_DispDefault即为g_tFramebufferOpr*/if (ret){printf("DeviceInit err\n");return -1;}ret = g_DispDefault->GetBuffer(&g_tDispBuff);if (ret){printf("GetBuffer err\n");return -1;}line_width = g_tDispBuff.iXres * g_tDispBuff.iBpp/8;pixel_width = g_tDispBuff.iBpp/8;return 0;
}PDispBuff GetDisplayBuffer(void)
{return &g_tDispBuff;
}int FlushDisplayRegion(PRegion ptRegion, PDispBuff ptDispBuff)
{return g_DispDefault->FlushRegion(ptRegion, ptDispBuff);
}//文字绘制函数
void DrawFontBitMap(PFontBitMap ptFontBitMap, unsigned int dwColor)
{int i, j, p, q;int x = ptFontBitMap->tRegion.iLeftUpX;int y = ptFontBitMap->tRegion.iLeftUpY;int x_max = x + ptFontBitMap->tRegion.iWidth;int y_max = y + ptFontBitMap->tRegion.iHeigh;int width = ptFontBitMap->tRegion.iWidth;unsigned char *buffer = ptFontBitMap->pucBuffer;//printf("x = %d, y = %d\n", x, y);for ( j = y, q = 0; j < y_max; j++, q++ ){for ( i = x, p = 0; i < x_max; i++, p++ ){if ( i < 0 || j < 0 ||i >= g_tDispBuff.iXres || j >= g_tDispBuff.iYres )continue;//image[j][i] |= bitmap->buffer[q * bitmap->width + p];if (buffer[q * width + p])PutPixel(i, j, dwColor);}}}// 区域绘制函数
void DrawRegion(PRegion ptRegion, unsigned int dwColor)
{int x = ptRegion->iLeftUpX;int y = ptRegion->iLeftUpY;int width = ptRegion->iWidth;int heigh = ptRegion->iHeigh;int i,j;for (j = y; j < y + heigh; j++){for (i = x; i < x + width; i++)PutPixel(i, j, dwColor);}
}//文本绘制函数
void DrawTextInRegionCentral(char *name, PRegion ptRegion, unsigned int dwColor)
{int n = strlen(name);int iFontSize = ptRegion->iWidth / n / 2;FontBitMap tFontBitMap;int iOriginX, iOriginY;int i = 0;int error;if (iFontSize > ptRegion->iHeigh)iFontSize = ptRegion->iHeigh;iOriginX = (ptRegion->iWidth - n * iFontSize)/2 + ptRegion->iLeftUpX;iOriginY = (ptRegion->iHeigh - iFontSize)/2 + iFontSize + ptRegion->iLeftUpY;SetFontSize(iFontSize);while (name[i]){/* get bitmap */tFontBitMap.iCurOriginX = iOriginX;tFontBitMap.iCurOriginY = iOriginY;error = GetFontBitMap(name[i], &tFontBitMap);if (error){printf("SelectAndInitFont err\n");return;}/* draw on buffer */ DrawFontBitMap(&tFontBitMap, dwColor); iOriginX = tFontBitMap.iNextOriginX;iOriginY = tFontBitMap.iNextOriginY; i++;}
}/* display_manager.c */
void DisplayInit(void)
{extern void FramebufferInit(void); /*对应framebuffer设备lcd输出*/FramebufferInit();/*WebTnit()-对应web输出未实现*/
}
3.2 framebuffer.c
#include <sys/mman.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include <linux/fb.h>
#include <fcntl.h>
#include <stdio.h>
#include <string.h>
#include <sys/ioctl.h>#include "disp_manager.h"static int fd_fb; //设备节点的文件权柄
static struct fb_var_screeninfo var; /* Current var */
static int screen_size;
static unsigned char *fb_base;//LCD的framebuffer地址
static unsigned int line_width;
static unsigned int pixel_width;static int FbDeviceInit(void) //设备初始化函数
{fd_fb = open("/dev/fb0", O_RDWR);//打开设备节点if (fd_fb < 0){printf("can't open /dev/fb0\n");return -1;}if (ioctl(fd_fb, FBIOGET_VSCREENINFO, &var)){printf("can't get var\n");return -1;}//var.xres x方向的分辨率line_width = var.xres * var.bits_per_pixel / 8;pixel_width = var.bits_per_pixel / 8;screen_size = var.xres * var.yres * var.bits_per_pixel / 8;fb_base = (unsigned char *)mmap(NULL , screen_size, PROT_READ | PROT_WRITE, MAP_SHARED, fd_fb, 0);//内存映射if (fb_base == (unsigned char *)-1){printf("can't mmap\n");return -1;}return 0;
}static int FbDeviceExit(void) //设备退出函数,释放设备资源
{munmap(fb_base, screen_size);//取消内存映射close(fd_fb);return 0;
}/* 可以返回LCD的framebuffer, 以后上层APP可以直接操作LCD, 可以不用FbFlushRegion* 也可以malloc返回一块无关的buffer, 要使用FbFlushRegion*/
static int FbGetBuffer(PDispBuff ptDispBuff)//获取内存空间
{ptDispBuff->iXres = var.xres;ptDispBuff->iYres = var.yres;ptDispBuff->iBpp = var.bits_per_pixel;ptDispBuff->buff = (char *)fb_base;return 0;
}static int FbFlushRegion(PRegion ptRegion, char *buffer) //刷新函数
{return 0;
}// 构建framebuffer设备结构体
static DispOpr g_tFramebufferOpr = { .name = "fb", //设备的名字是fb.DeviceInit = FbDeviceInit, //.DeviceExit = FbDeviceExit, //.GetBuffer = FbGetBuffer, //获得buf空间中的数据.FlushRegion = FbFlushRegion, //刷新
};void FramebufferInit(void)
{RegisterDisplay(&g_tFramebufferOpr);
}
3.3 Makefile
EXTRA_CFLAGS :=
CFLAGS_file.o :=
obj-y +=disp_manager.o
obj-y +=framebuffer.o
四、freetype文件夹
4.1 font_manager.c
#include "font_manager.h"
#include <string.h>
static PFontOpr g_ptFonts = NULL;
static PFontOpr g_ptDefaulFontOpr = NULL;void RegisterFont(PFontOpr ptFontOpr)
{ptFontOpr->ptNext = g_ptFonts;g_ptFonts = ptFontOpr;
}void FontsRegister(void)
{extern void FreetypeRegister(void);FreetypeRegister();
}int SelectAndInitFont(char *aFontOprName, char *aFontFileName)
{PFontOpr ptTmp = g_ptFonts;while (ptTmp){if (strcmp(ptTmp->name, aFontOprName) == 0)break;ptTmp = ptTmp->ptNext;}if (!ptTmp)return -1;g_ptDefaulFontOpr = ptTmp;return ptTmp->FontInit(aFontFileName);
}int SetFontSize(int iFontSize)
{return g_ptDefaulFontOpr->SetFontSize(iFontSize);
}int GetFontBitMap(unsigned int dwCode, PFontBitMap ptFontBitMap)
{return g_ptDefaulFontOpr->GetFontBitMap(dwCode, ptFontBitMap);
}
4.2 freetype.c
#include <sys/mman.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include <linux/fb.h>
#include <fcntl.h>
#include <stdio.h>
#include <string.h>
#include <math.h>
#include <wchar.h>
#include <sys/ioctl.h>
#include "font_manager.h"
#include <ft2build.h>//freetype库中的一个头文件
#include FT_FREETYPE_H
#include FT_GLYPH_H
static FT_Face g_tFace;
static int g_iDefaultFontSize = 12;static int FreeTypeFontInit(char *aFineName)
{FT_Library library;int error;error = FT_Init_FreeType( &library ); /* initialize library */ if (error){printf("FT_Init_FreeType err\n");return -1;}error = FT_New_Face(library, aFineName, 0, &g_tFace ); /* create face object */if (error){printf("FT_New_Face err\n");return -1;}FT_Set_Pixel_Sizes(g_tFace, g_iDefaultFontSize, 0);return 0;
}static int FreeTypeSetFontSize(int iFontSize)
{FT_Set_Pixel_Sizes(g_tFace, iFontSize, 0);return 0;
}
//给编码值,得到位图
static int FreeTypeGetFontBitMap(unsigned int dwCode, PFontBitMap ptFontBitMap)
{int error;FT_Vector pen;FT_GlyphSlot slot = g_tFace->glyph;pen.x = ptFontBitMap->iCurOriginX * 64; /* 单位: 1/64像素 */pen.y = ptFontBitMap->iCurOriginY * 64; /* 单位: 1/64像素 *//* 转换:transformation */FT_Set_Transform(g_tFace, 0, &pen);//FT_Set_Transform是FreeType库中的函数/* 加载位图: load glyph image into the slot (erase previous one) */error = FT_Load_Char(g_tFace, dwCode, FT_LOAD_RENDER);if (error){printf("FT_Load_Char error\n");return -1;}ptFontBitMap->pucBuffer = slot->bitmap.buffer;ptFontBitMap->tRegion.iLeftUpX = slot->bitmap_left;ptFontBitMap->tRegion.iLeftUpY = ptFontBitMap->iCurOriginY*2 - slot->bitmap_top;ptFontBitMap->tRegion.iWidth = slot->bitmap.width;ptFontBitMap->tRegion.iHeigh = slot->bitmap.rows;ptFontBitMap->iNextOriginX = ptFontBitMap->iCurOriginX + slot->advance.x / 64;ptFontBitMap->iNextOriginY = ptFontBitMap->iCurOriginY;return 0;
}
//描述字库操作及对应具体实现
static FontOpr g_tFreetypeOpr = {.name = "freetype",.FontInit = FreeTypeFontInit,.SetFontSize = FreeTypeSetFontSize,.GetFontBitMap = FreeTypeGetFontBitMap,
};void FreetypeRegister(void)
{RegisterFont(&g_tFreetypeOpr);
}
4.3 front_manager.c
#include "font_manager.h"
#include <string.h>
static PFontOpr g_ptFonts = NULL;
static PFontOpr g_ptDefaulFontOpr = NULL;void RegisterFont(PFontOpr ptFontOpr)
{ptFontOpr->ptNext = g_ptFonts;g_ptFonts = ptFontOpr;
}void FontsRegister(void)
{extern void FreetypeRegister(void);FreetypeRegister();
}int SelectAndInitFont(char *aFontOprName, char *aFontFileName)
{PFontOpr ptTmp = g_ptFonts;while (ptTmp){if (strcmp(ptTmp->name, aFontOprName) == 0)break;ptTmp = ptTmp->ptNext;}if (!ptTmp)return -1;g_ptDefaulFontOpr = ptTmp;return ptTmp->FontInit(aFontFileName);
}int SetFontSize(int iFontSize)
{return g_ptDefaulFontOpr->SetFontSize(iFontSize);
}int GetFontBitMap(unsigned int dwCode, PFontBitMap ptFontBitMap)
{return g_ptDefaulFontOpr->GetFontBitMap(dwCode, ptFontBitMap);
}
4.4 Makefile
EXTRA_CFLAGS :=
CFLAGS_file.o :=
obj-y +=freetype.o
obj-y +=font_manager.o
五、uniotest文件夹
5.1 ui_test.c
#include <sys/mman.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include <linux/fb.h>
#include <fcntl.h>
#include <stdio.h>
#include <string.h>
#include <sys/ioctl.h>
#include <stdlib.h>
#include <disp_manager.h>#include <font_manager.h>
#include <ui.h> /*包含必要头文件*/int main(int argc, char **argv)
{PDispBuff ptBuffer;int error;Button tButton;Region tRegion;if (argc != 2){printf("Usage: %s <font_size>\n", argv[0]); //打印用法return -1;}DisplayInit(); //显示系统初始化SelectDefaultDisplay("fb"); //选择lcd设备显示InitDefaultDisplay(); //初始化lcd设备显示ptBuffer = GetDisplayBuffer();//获取内存FontsRegister(); //字体注册error = SelectAndInitFont("freetype", argv[1]);//字体大小设置if (error){printf("SelectAndInitFont err\n");return -1;}/*指定按键形状、位置信息*/tRegion.iLeftUpX = 200; tRegion.iLeftUpY = 200;tRegion.iWidth = 600;tRegion.iHeigh = 200;InitButton(&tButton,"Alexius_test", &tRegion, NULL, NULL); //按键初始化tButton.OnDraw(&tButton, ptBuffer); //绘制案件即显示红色按钮与对应按键名while (1) //按键按下颜色反转{tButton.OnPressed(&tButton, ptBuffer, NULL); sleep(2);}return 0;
}
5.2 Makefile
EXTRA_CFLAGS :=
CFLAGS_file.o :=
obj-y +=ui_test.o
六、顶层Makefile及Makefile.build
6.1 Makefile
#指定交叉编译工具链
COSS_COMPLE ?=arm-linux-gnueabihf-
AS = $(COSS_COMPLE)as
LD = $(COSS_COMPLE)ld
CC = $(COSS_COMPLE)gcc
CPP = $(CC) -E
AR = $(CROSS_COMPILE)ar
NM = $(CROSS_COMPILE)nmSTRIP = $(CROSS_COMPILE)strip
OBJCOPY = $(CROSS_COMPILE)objcopy
OBJDUMP = $(CROSS_COMPILE)objdump# export导出的变量是给子目录下的Makefile使用的
export AS LD CC CPP AR NM
export STRIP OBJCOPY OBJDUMP# 编译器在编译时的参数设置
CFLAGS := -Wall -O2 -g -DDEBUG
# 添加头文件路径,不添加的话include目录下的头文件编译时找不到
CFLAGS += -I $(shell pwd)/include -I/home/alexius/Downloads/freetype-2.10.2/install/include/freetype2# 链接器的链接参数设置,链接库
LDFLAGS := -L/home/alexius/Downloads/freetype-2.10.2/install/lib -lfreetype
#-L/home/alexius/Downloads/tslib-1.21/install/lib -lts -lpthread #触摸屏库链接export CFLAGS LDFLAGSTOPDIR := $(shell pwd)
export TOPDIR# 定义将来编译生成的可执行程序的名字
TARGET := ui_test# 添加项目中所有用到的源文件,有顶层目录下的.c文件,和子文件夹
# 添加顶层目录下的.c文件
#obj-y += main.o# 添加顶层目录下的子文件夹(注意目录名后面加一个/)
#obj-y += main.o
obj-y += button/
obj-y += uniotest/
obj-y += display/
obj-y += freetype/# 第一个目标
all : start_recursive_build $(TARGET)@echo $(TARGET) has been built!# 处理第一个依赖,**转到 Makefile.build 执行**
start_recursive_build:make -C ./ -f $(TOPDIR)/Makefile.build# 处理最终目标,把前期处理得出的 built-in.o 用上
$(TARGET) : built-in.o$(CC) -o $(TARGET) built-in.o $(LDFLAGS)# 清理
clean:rm -f $(shell find -name "*.o")rm -f $(TARGET)# 彻底清理
distclean:rm -f $(shell find -name "*.o")rm -f $(shell find -name "*.d")rm -f $(TARGET)
6.2 Makefile.build
# 将__build定义为伪目标
PHONY := __build
__build:# 这里初值为空,下面引入Makefile文件后会被覆盖
obj-y :=
subdir-y :=# 包含同级目录的Makefile
include Makefile# 从obj-y变量中,将"/"结尾的字符串提取出来,也就是包含的子文件夹目录
__subdir-y := $(patsubst %/,%,$(filter %/, $(obj-y)))
subdir-y += $(__subdir-y)# 将subdir-y变量中的字符串依次赋值给f变量,形成新的$(f)/built-in.o字符串
subdir_objs := $(foreach f,$(subdir-y),$(f)/built-in.o)# 筛选出obj-y中不以"/"结尾的字符串,也就是普通文件,一般是.o结尾
cur_objs := $(filter-out %/, $(obj-y))# 为每个.o文件生成.d文件
# 注意.$(f).d是隐藏文件,需要ls -a查看
dep_files := $(foreach f,$(cur_objs),.$(f).d)
dep_files := $(wildcard $(dep_files))# 如果.d文件不是空,则将.d文件都包含进来
ifneq ($(dep_files),)include $(dep_files)
endifPHONY += $(subdir-y)# __build是Makefile的目标__build : $(subdir-y) built-in.o# 依次跳转到子目录中,执行Makefile.build文件
$(subdir-y):make -C $@ -f $(TOPDIR)/Makefile.build# 生成当前目录的built-in.o,依赖当前目录的.o文件和子目录下的built-in.o文件
built-in.o : $(cur_objs) $(subdir_objs)$(LD) -r -o $@ $^# dep_file变量是用来生成.d文件的
dep_file = .$@.d# Makefile中的规则,把.c文件编译成.o文件
%.o : %.c$(CC) $(CFLAGS) -Wp,-MD,$(dep_file) -c -o $@ $<# 重新定义 .PHONY的依赖
.PHONY : $(PHONY)
七、编译及结果
7.1 编译
7.2 测试结果
将可执行文件ui_test及字库.ttc文件放入开发板下