本文记录如何在 EDK II 项目中编写并编译自己的库模块(Library Module),并在其他模块中调用这个库函数。通过实战掌握 UEFI 模块化开发的重要组成部分——库的创建与复用。
一、前言
UEFI 开发中,代码高度模块化,库模块(Library Module)是其核心机制之一。很多驱动、应用程序都依赖于多个通用库进行构建。因此,学会创建和使用自己的库是 UEFI 学习的重要一步。
二、基础知识回顾
-
EDK II 工程核心文件类型:
-
.INF:模块定义文件 -
.DEC:包描述文件,声明头文件、LibraryClass 等 -
.DSC:平台配置文件,指定模块构建方式 -
.FDF:固件镜像配置文件(用于最终构建固件镜像)
-
-
Library Module 与普通 Module 区别:
-
普通模块可以独立运行或链接到 文件中(如 App、Driver)
-
Library Module 不可独立运行,必须被其他模块引用
-
-
LibraryClass 的作用:
-
每个库使用唯一的
LibraryClass名称,供外部模块引用 -
相当于一个命名接口,类似 C++ 虚基类的“接口名”
-
三、工程目录结构设计
我们假设创建一个名为 MyPkg 的包,内部包含一个名为 01MyLibrarytest的库模块:
MyPkg/
├── MyLibrary/
│ └── 01MyLibrarytest/
│ ├── 01MyLibrarytest.c // 库函数实现
│ ├── 01MyLibrarytest.h // 库函数头文件
│ └── 01MyLibrarytest.inf // 库模块描述文件
├── MyApplications/
│ └── MyHelloWorld/
│ ├── MyHelloWorld.c // 应用调用库
│ └── MyHelloWorld.inf // 应用模块描述文件
├── MyPkg.dec // 包描述文件
└── MyPkg.dsc // 平台描述文件
四、编写自己的库模块
1. 编写 .inf 文件(01MyLibrarytest.inf)
[Defines]
INF_VERSION = 0x00010006
BASE_NAME = 01MyLibrarytest
FILE_GUID = D8114FB9-2FDF-E1D6-D107-6FD899B8F433
MODULE_TYPE = BASE
VERSION_STRING = 1.0
LIBRARY_CLASS = 01MyLibrarytest
[Sources]
01MyLibrarytest.c
[Packages]
MdePkg/MdePkg.dec
[LibraryClasses]
UefiLib
BaseLib
关键字段说明:
-
MODULE_TYPE = BASE表示这是一个基础模块(通常为库) -
LIBRARY_CLASS =01MyLibrarytest 表示该库的接口名,外部模块使用这个名称引用它
2. 编写头文件(01MyLibrarytest.h)
#ifndef __MY_LIBRARY_TEST_H__
#define __MY_LIBRARY_TEST_H__
#include <Uefi.h>
#include <Library/UefiLib.h>
VOID EFIAPI MyLibraryTestFunction();
#endif
3. 编写实现文件(01MyLibrarytest.c)
#include "01MyLibrarytest.h"
VOID EFIAPI MyLibraryTestFunction()
{
Print(L"Hello from MyLibraryTestFunction!\n");
}
四、配置 MyPkg.dec
[Defines]
DEC_SPECIFICATION = 0x00010005
PACKAGE_NAME = MyPkg
PACKAGE_GUID = 263EC29A-EAB4-4504-FFFD-970978EA3246
PACKAGE_VERSION = 0.01
[Includes]
MyLibrary/01MyLibrarytest
[LibraryClasses]
01MyLibrarytest|MyLibrary/01MyLibrarytest/01MyLibrarytest.h
说明:
-
[Includes]让头文件能被外部模块找到(传给编译器的-I路径) -
[LibraryClasses]声明库类及其接口头文件路径
五、配置平台文件 MyPkg.dsc
[Defines]
PLATFORM_NAME = MyPkg
PLATFORM_GUID = 0D4E362C-6CBC-F881-7625-84B95963D6C8
PLATFORM_VERSION = 0.1
DSC_SPECIFICATION = 0X00010005
OUTPUT_DIRECTORY = Build/MyPkg
SUPPORTED_ARCHITECTURES = X64
BUILD_TARGETS = DEBUG|RELEASE
SKUID_IDENTIFIER = DEFAULT
#
# Debug output control
#
DEFINE DEBUG_ENABLE_OUTPUT = FALSE # Set to TRUE to enable debug output
DEFINE DEBUG_PRINT_ERROR_LEVEL = 0x80000040 # Flags to control amount of debug output
DEFINE DEBUG_PROPERTY_MASK = 0
[LibraryClasses]
UefiApplicationEntryPoint|MdePkg/Library/UefiApplicationEntryPoint/UefiApplicationEntryPoint.inf
UefiLib|MdePkg/Library/UefiLib/UefiLib.inf
PrintLib|MdePkg/Library/BasePrintLib/BasePrintLib.inf
PcdLib|MdePkg/Library/DxePcdLib/DxePcdLib.inf
MemoryAllocationLib|MdePkg/Library/UefiMemoryAllocationLib/UefiMemoryAllocationLib.inf
DebugLib|MdePkg/Library/BaseDebugLibNull/BaseDebugLibNull.inf
BaseMemoryLib|MdePkg/Library/BaseMemoryLib/BaseMemoryLib.inf
BaseLib|MdePkg/Library/BaseLib/BaseLib.inf
UefiBootServicesTableLib|MdePkg/Library/UefiBootServicesTableLib/UefiBootServicesTableLib.inf
DevicePathLib|MdePkg/Library/UefiDevicePathLib/UefiDevicePathLib.inf
UefiRuntimeServicesTableLib|MdePkg/Library/UefiRuntimeServicesTableLib/UefiRuntimeServicesTableLib.inf
RegisterFilterLib|MdePkg/Library/RegisterFilterLibNull/RegisterFilterLibNull.inf
StackCheckLib|MdePkg/Library/StackCheckLib/StackCheckLib.inf
StackCheckFailureHookLib|MdePkg/Library/StackCheckFailureHookLibNull/StackCheckFailureHookLibNull.inf
01MyLibrarytest|MyPkg/MyLibrary/01MyLibrarytest/01MyLibrarytest.inf
[Components]
MyPkg/MyLibrary/01MyLibrarytest/01MyLibrarytest.inf
MyPkg/MyApplications/MyHelloWorld/MyHelloWorld.inf
六、编写调用库的应用模块
✅ 1. MyHelloWorld.c
#include <Uefi.h>
#include <Library/UefiLib.h>
#include <01MyLibrarytest.h>
EFI_STATUS
EFIAPI
UefiMain(IN EFI_HANDLE ImageHandle, IN EFI_SYSTEM_TABLE *SystemTable)
{
Print(L"Hello,This is my first UEFI Application\n");
MyLibraryTestFunction();
return EFI_SUCCESS;
}
✅ 2. MyHelloWorld.inf
[Defines]
INF_VERSION = 0x00010006
BASE_NAME = MyHelloWorld
FILE_GUID = 22222222-2222-2222-2222-222222222222
MODULE_TYPE = UEFI_APPLICATION
ENTRY_POINT = UefiMain
[Sources]
MyHelloWorld.c
[Packages]
MdePkg/MdePkg.dec
MyPkg/MyPkg.dec # 需要添加这一行
[LibraryClasses]
UefiLib
01MyLibrarytest
七、构建并测试
✅ 构建命令:
build -p MyPkg/MyPkg.dsc -m MyPkg/MyApplications/MyHelloWorld/MyHelloWorld.inf
构建成功后,生成的 MyHelloWorld.efi 可在 UEFI Shell 或 QEMU 中运行:

269

被折叠的 条评论
为什么被折叠?



