上一篇介绍了 .inf文件, .inf文件相当于Visual Studio中的工程文件。而 .dsc(Platform Description File)则相当于Visual Studio中的 solution 文件。每个包都要包含一个.dec(Package Declaration File)文件、一个 .dsc文件。如果这个包还用于固件Iamge或Option Rom Image的生成,则还需要添加 .fdf(Flash Description File)文件, .fdf文件还用于启动Image。
build命令用于编译包,编译时需要一个 .dsc文件以及一个或多个 .inf文件。
GenFW命令用于制作固件或Option Rom Image,它需要一个 .dec文件和一个 .fdf文件。
EDK2文件及EDK2工具链命令之间的关系如下:
接下来了解一下常用的两种文件: .dsc与 .dec文件。
1、 .dsc文件
.inf用于编译一个模块,而 .dsc文件用于编译一个Package,它包含了[Defines]、[LibraryClasses]、[Components]几个必须部分以及[PCD]、[BuildOptions]等几个可选部分。
[Defines]块
[Defines]用于设置build相关的全局宏变量,这些变量可以被 .dsc文件的其他模块引用。[Defines]块必须时 .dsc文件的第一个部分,格式如下:
[Defines]
宏变量名 = 值
EDFINE 宏变量名 = 值
EDK_GLOBAL 宏变量名 = 值
[Defines]块中通过DEFINE和EDK_GLOBAL定义的宏可以在 .dsc文件和 .fdf文件中通过$(宏变量名)使用。
.dsc文件中[Defines]块必须定义的宏变量。
宏变量名 | 值类型 | 说明 |
---|---|---|
DSC_SPECIFICATION | 数值 | DSC Spec 1.22对应的值为0x00010006.目前的常用值为0x00010005.DSC必须保证向后兼容 |
PLATFORM_GUID | GUID | 平台GUID,每个.dsc文件必须有一个唯一的GUID |
PLATFORM_VERSION | 数值 | .dsc文件变化时,增加此数值 |
PLATFORM_NAME | 标识符 | 标识符字符串中只能包含英文字符数字、横线、下划线 |
SKUID_IDENTIFIER | 标识符 | 该宏可以通过命令行在build时传入。可以为Default或[SkuIds]中的一个 |
SUPPORTED_ARCHITECTUPES | 列表 | 通过“|”分隔的列表,表示该 .dsc所支持平台的体系结构。例如支持IA32和X64:IA32|X64 |
BUILD_TARGETS | 列表 | 通过“|”分隔的列表,表示该 .dsc所支持的编译目标,例如BUILD或BUILD|RELEASE。 |
.dsc文件 [Defines]块的可选宏变量
宏变量名 | 值类型 | 说明 |
---|---|---|
OUTPUT_DIRECTORY | 路径 | 目标文件路径。可以时绝对路径,也可以是相对路径。默认为 ( W O R K S P A C E ) / B u i l d / (WORKSPACE)/Build/ (WORKSPACE)/Build/(PLATFORM_NAME) |
FLASH_DEFINTTION | 文件名FILE_NAME | FDF文件。可以是文件名,也可以是带带路径的文件名。如果仅是文件名,则该文件必须在.dsc所在的目录 |
BUILD_NUMBER | 最多四个字符 | 用于Mkefile文件 |
FIX_LOAD_TOP_MEMORY_ADD RESS | 地址 | 驱动、应用程序在内存中的起始地址 |
TIME_STAMP_FILE | 文件名 | 时间戳文件。可以是文件名,也可以是带路径的文件名。该文件中包含了一个时间戳,所有编译过程中生成的文件都使用该时间戳 |
DEFINE | MACRO=PATH|Value ? | 宏定义,定义的宏可以在 .dsc文件中调用。例如,DEFINE DEBUG_ENABLE_OUTPUT=FALSE,在后续的 .dsc文件中可以直接:!if$(DEBUG_ENABLE_OUTPUT) \n !endif |
EDK_GLOBAL | MACRO=PATH|Value | 仅在EDK模块适用,EDK2模块会自动忽略 |
RfC_lANGUAGES | RFC 4646语言代码列表 | RFC4646语言代码字符串中,各个语言代码之间使用分号“;”分隔。用于在AutoGen阶段处理Unicode字符串。字符串必须用“包裹”? |
VPD_TOOL_GUID | GUID | 在AutoGen阶段调用此GUID对应的VPD程序。VPD程序定义在Conf\tool_def.txt文件中,默认为BPDG |
PCD_INFO_GENERATION_GENERATION | BOOL值 | TRUE表示在PCD数据库中存在PCD信息 |
Nt32Pkg中 .dsc文件的[defines]部分:
[Defines]
PLATFORM_NAME =NT32
PLATFORM_GUID =EB12332-123S-21XZ-1DD1-AS231ER523C2
PLATFORM_VERSION =0.4
DSC_SPECIFICATION =0x00010005
OUTPUT_SPECIFICATION =Build/NT32
SUPPORTED_ARCHITECTURES =IA32
BUILD_TARGETS =DEBUG|RELEASE
SKUID_IDENTIFIER =DEFAULT
FLASH_DEFINITION =Nt32Pkg/Nt32Pkg.fdf
[LibraryClasses]块
在[LibraryClasses]块中定义了库的名字以及库的 .inf文件的路径。这些库可以被[Components]块引用。
1)语法:
[LibraryClasses]块 语法如下:
#方法一
[LibraryClasses.$(Arch).$(MODULE_TYPE)]
LibraryName | Path/LibraryName.inf
或
#方法二
[LibraryClasses.$(Arch).$(MODULE_TYPE), LibraryClasses.$(Arch1).$(MODULE_TYPE1)]
LibraryName | Path/LibraryName.inf
( A r c h ) 和 (Arch)和 (Arch)和(MODULE_TYPE)是可选项。用“ , ”表示并列关系,块内的库对LibraryClasses. ( A r c h ) . (Arch). (Arch).(MODULE_TYPE)和LibraryClasses. ( A r c h 1 ) . (Arch1). (Arch1).(MODULE_TYPE1)都有效。
$(Arch)表示体系结构,可以是下列值之一:IA32、X64、IPF、EBC、ARM、common。其中,common表示对所有体系结构都有效。
KaTeX parse error: Undefined control sequence: \? at position 35: …*类别**,块内列出的库只能(\̲?̲用于)提供(MODULE_TYPE)类别的模块链接。$(MODULE_TYPE)可以是以下值:SEC、PEI_CORE、PEIM、DXE_CORE、DXE_SAL_DRIVER、DEX_RUNTIME_DRIVER、BASE、UEFI_DRIVER等。
通常, .dsc文件中都有[LibraryClasses]区块,表示块内定义的库对所有体系结构和所有类型的模块都有效。
2)示例:
在Nt32Pkg.dsc中有:
[LibraryClasses.common.PEIM, LibraryClasses.common.PEI_CORE]
HobLib | MdePkg/Library/PeiHobLib/PeiHobLib.inf
在ShellPkg.dsc中有:
[LibraryClasses.ARM]
NULL | ArmPkg/Library/CompilerIntrinsicsLib/CompilerIntrinsicsLib.inf
引用库是在 .inf 文件的[LibraryClasses]块中完成的。例如,上上篇博客中第一个示例程序的 .inf文件中引用了UefiApplicationEntryPoint和UefiLib,如下代码所示:
[LibraryClasses]
UefiApplicationEntryPoint
UefiLib
[Components]块
在[Components]块内定义的模块都会被build工具编译、并生成.efi文件,其格式如下:
#格式一
[Components.$(Arch)]
Path\Exectuables.inf
或者
#格式二
[Components.$(Arch)]
Path\Exectuables.inf{
#嵌套块
LibraryName | Path/LibraryName.inf
#嵌套块
#子块中还可以包含
}
如果Path是相对路径,则相对路径起始于 ( W O R K S P A C E ) , (WORKSPACE), (WORKSPACE),(WORKSPACE)通常是EDK2的根目录。在Path中可以使用通过 DEFINE命令 定义的宏。例如:
[Components]
DEFINE MYSOURCE_PATH = D:/Source
$(MYSOURCE_PATH)/Hello.inf #相当于 D:/Source/Hello.inf
格式二中大括号内的内容仅对本模块有效,例如下面的代码中[Components]声明的DevicePathDxe.inf会调用在MdePkg/Library/UefiDevicePathLib/UefiDevicePathLib.inf中定义的DevicePathLib库,而其它的模块则使用在全局[LibraryClasses]块中声明的UefiDevicePathLibDevicePathProtocol.inf对应的DevicePathLib库。
[LibraryClasses]
DevicePathLib | MdePkg/Library/UefiDevicePathLibDevicePathProtocol/UefiDevicePathLibPathProtocol.inf
[Components]
...
MdeModulePkg/Universal/DevicePathDxe/DevicePathDxe.inf{
DevicePathLib | MdePkg/Library/UefiDevicePathLib/UefiDevicePathLib.inf
}
下面编写一个MdeMoudlePkg.dsc中的一个实例,这个块内的模块对IA32、X64和IPF体系结构有效:
[Components.IA32, Components.X64, Components.IPF]
MdeModulePkg/Universal/Network/UefiPxeBcDxe/UefiPxeBcDxe.inf
MdeModulePkg/Universal/DebugSupportDxe/DebugSupportDxe.inf
MdeModulePkg/Universal/EbcDxe/EbcDxe.inf
[BuildOptions]块
[BuildOptions]格式在 .inf文件中以及进行过介绍, .dsc文件的[BuildOptions]与 .inf文件的[BuildOptions]格式大致相同,区别在于 .dsc文件的[BuildOptions]对 .dsc文件内的所有模块有效。 .dsc文件的[BuildOptions]模块格式如下:
[BuildOptions.$(Arch).$(CodeBase)]
[编译器]:[$(Target)]_[Tool]_[$(Arch)]_[CC|DLINK]_FLAGS =
( A r c h ) 与 (Arch)与 (Arch)与(CodeBase)都是可选项。 ( C o d e B a s e ) 的 值 是 E D K 和 E D K 2 中 的 一 个 。 (CodeBase)的值是EDK和EDK2中的一个。 (CodeBase)的值是EDK和EDK2中的一个。(Arch)是体系结构,如IA32、X64等。
$(Target)选项的值是DEBUG、RELEASE、*中的某个;Tool是编译工具的名字,如VS2012、GCC44等;CC表示编译选项;DLIKN表示连接选项。
AppPkg.dsc中的[BuildOptions]块中的代码如下:
[BuildOptions]
!ifndef $(EMULATE)
INTEL:*_*_*_CC_FLAGS = /Qfreestanding /D UEFI_C_SOURCE
MSFT:*_*_*_CC_FLAGS = /X /Zc:wchar_t /D UEFI_C_SOURCE
...
!else
INTEL:*_*_IA32_CC_FLAGS = /Od /D UEFI_C_SOURCE
MSFT:*_*_IA32_CC_FLAGS = /Od /D UEFI_C_SOURCE
...
!endif
在 .dsc文件中可使用" ! “命令。” !include “用于加载其他文件。” !if、!ifdef、!ifndef、!else、!end"等则是条件处理语句。
最后简单介绍下[PCD]块。[PCD]块用于定义平台配置数据。其目的是在不改动 .inf文件和源文件的情况下完成对平台的配置。例如在UEFI模拟器Nt32Pkg的 .dsc文件Nt32Pkg.dsc 中可以通过PCD的PcdWinNtFileSystem配置模拟器文件系统路径,如下所示:
gEfiNt32PkgTokenSpaceGuid.PcdWinNtFileSystem | L".!..\..\..\..\EdkShellBinPkg\Bin\Ia32\Apps" | VOID* | 106
配置文件被" | "分成四个部分:第一部分中gEfiNt32PkgTokenSpaceGuid是命名空间,PcdWinNtFileSystem是变量名;第二部分是值;第三部分是变量类型。第四部分是变量数据的最大长度。
在源文件中可以通过LIbPcdGetPtr(_PCD_TOKEN_PcdWinNtFileSystem)获得gEfiNt32PkgTokenSpaceGuid.PcdWinNtFileSystem定义的值。
2、 .dec文件
.dec文件定义了公开的数据和接口以供其他模块使用。包含有必须模块[Defines]以及可选区块[Includes]、[LibraryClasse、[Guids]、[Protocols]、[Ppis]和[PCD]等部分。
[Defines]块
[Defines]块用于提供package的名称、GUID、版本号等信息,格式如下:
[Defines]
Name = Vlaue
其中,Name的取值范围是[DEC_SPECIFICATION、PACKAGE_NAME、PACKAGE_GUID、PACKAGE_VERSION]。
例如,MdePkg.dsc中的[Defines]部分如下所示:
[Defines]
Dec_SPECIFICATION = 0x00010001
PACKAGE_NAME = MdePkg
PACKAGE_GUID = 1W2323F-F31S-1242-SDC1-F23C123F1211
PACKAGE_VERSION = 1.03
[Includes]块
[includes]块列出了本Package提供的头文件所在的目录,格式如下:
[Includes.$(Arch)]
Path
Path只能是相对路径,该相对路径起始于本Package的.dsc所在的目录。
MdePkg.dec文件中的[Includes]部分如下:
[Include]
Include
[Include.IA32] #编译 32 位程序时的头文件路径
Include/Ia32
[Include.X64] #编译x86——64位程序时的头文件路径
Include/X64
[LibraryClasses]块
package可以通过 .dec文件对外提供库,每个库都必须有一个头文件,放在Include\Library目录下。[LibraryClasses]块用于明确库和头文件的对应关系。其格式如下:
[LibraryClasses.$(Arch)]
LibraryName | Path/LibraryHeader.h
MdePkg.dec中[LibraryClasses]块中代码的一部分如下:
[LibraryClasses]
UefiUsbLib | Include/Library/UefiUsbLib.h
[LibraryClasses.IA32, LibraryClasses.X64]
SmmLib | Include/Library/SmmLib.h
[Guids]块
在Package\Include\Guid目录中有很多文件,每个文件内定义了一个或几个GUID,例如在MdePkg\Include\Gpt.h文件中定义了Gpt分区相关的GUID,如下所示:
extern EFI_GUID gEfiPartTypeUnusedGuid;
extern EFI_GUID gEfiPartTypeSystemPartGuid;
extern EFI_GUID gEfiPartTypeLegacyMbrGuid
可以看出这些定义只是声明了变量,并未对其进行赋值。真正的常量定义?在AutoGen.c中,其值定义在 .dec文件的[Guids]块中。格式为:
[Guid.$(Arch)]
GUIDName = GUID
上文中提到的Gpt相关的GUID,定义在在MdePkg.dec中,这些GUID定义如下:
[Guids]
...
## include/Guid/Gpt.h
gEfiPartTypeLegacyMbrGuid = { 0x024DEE41, 0x33E7, 0x11D3, { 0x9d, 0x69, 0x00, 0x08, 0xc7, 0x81, 0xF3, 0x9F}}
gEfiPartTypeSystemPartGuid = { 0xC12A7328, 0xF81F, 0x11D2, { 0xBA, 0x4B, 0x00, 0xA0, 0xC9, 0x3E, 0xC9, 0x3B}}
gEfiPartTypeUnusedGuid = { 0x00000000, 0x0000, 0x0000, {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}
[Protocols]块
与Guids相似,在Package\Include\Protocols 目录下有很多头文件,每个头文件定义了一个或多个Protocol,这些Protocol的GUID值就定义在 .dec文件的[Protocols]块,格式如下:
[Protocols.$(Arch)]
ProtocolName = GUID
如,在MdePkg\Include\Protocol目录下BlockIo.h定义的BlockIo Protocol
extern EFI_GUID gEfiBlockIoProtocolGuid;
gEfiBlockIoProtocolGuid的值定义在MdePkg.dec的[Protocls]块中。
[Protocols]
gEfiBlockProtocolGuid = { 0x964EB21, 0x6459, 0x11D2, { 0x8E, 0x39, 0x00, 0x00, 0xC9, 0x69, 0xE2, 0x2C}}
[Ppis]块、[PCD]块、[UserExtensions]块
[Ppis]块用于定义源文件中用到的PPI(PPI是PEI阶段,PEI模块间通信的接口),语法类似于[Protocols]。
[PCD]块是 .dsc文件中对[PCD]块的补充,
[UserExtensions]块