编译组件

引言

编译组件代表编译功能的集合. 这包括可在已编译代码中使用的声明和可在顶层代码中使用的已安装函数. 编译组件提供了打包和分发此功能的框架.

创建基于编译器的程序包

与程序包系统的集成使得分发编译组件及相关构建可能在单个内核会话之外实现. 在这个示例中,定义了一个编译组件,它对一些已安装函数进行公开,并且依赖于外部库.

定义程序包

首先,创建一个新的程序包:
修改 PacletInfo.wl 文件以包含 "LibraryResources" 扩展名,这将使组件系统稍后可以定位组件构建库:
PacletObject[
    <|
        "Name" -> "ComponentPaclet",
        "Version" -> "0.0.1",
        "WolframVersion" -> "13.2+",
        "Extensions" -> {
                {"Kernel", "Root" -> "Kernel", "Context" -> "ComponentPaclet`"},
                {"LibraryResources"}
            }
    |>
]
修改程序包的源代码以创建和填充已编译的组件:
BeginPackage["ComponentPaclet`"]

AddOne
RaiseToPower

Begin["`Private`"]

(* Declare compiler declarations *)
DeclareCompiledComponent["ExampleComponent", {
    LibraryFunctionDeclaration["addone", "compilerDemoBase", {"CInt"}->"CInt"],

    FunctionDeclaration[AddOne,
        Typed[{"CInt"} -> "CInt"]@
        Function[arg, LibraryFunction["addone"][arg]]
    ],

    FunctionDeclaration[RaiseToPower,
        Typed[{"MachineInteger","MachineInteger"} -> "MachineInteger"]@
        Function[{x,y}, x^y]
    ]
}];

(* Declare installed functions *)
DeclareCompiledComponent["ExampleComponent", "InstalledFunctions" -> {
    AddOne,
    RaiseToPower
}];

(* Declare library functions *)
DeclareCompiledComponent["ExampleComponent", "LibraryFunctions" -> <|
    "sqrt" -> Function[Typed[arg,"Real64"], Sqrt[arg]]
|>];

(* Declare external library dependencies *)
DeclareCompiledComponent["ExampleComponent", "ExternalLibraries" -> {
    "compilerDemoBase"
}];

End[] (* End `Private` *)

EndPackage[]

加载程序包

加载程序包:
加载程序包导致组件被定义,然后可以在编译代码中使用:
由于该组件尚未构建,尝试使用其已安装的函数会导致错误:

构建组件

必须构建编译组件才能访问已编译的库函数和已安装的函数.

该组件可以使用 BuildCompiledComponent 构建. 通过将 PacletObject 指定为构建的目标,组件库将放置在程序包中:
BuildCompiledComponent 的调用创建并填充了程序包中的 LibraryResources 目录,其中包含由该组件指定的所有函数的动态库:

加载组件

现在组件已经构建,可以使用已安装的函数.

第一次调用已安装的函数时,它会尝试自动加载组件库:

这里使用 FindLibrary 来定位组件构建,它将在程序包中被找到,因为它在 PacletInfo.wl 文件中被赋予了 "LibraryResources" 扩展名.

或者,可以使用 LoadCompiledComponent 显式加载组件构建,从而可以访问构建的所有属性:
LoadCompiledComponent 使得访问组件中指定的库函数成为可能:

现在它已经被构建, "ComponentPaclet" 程序包可以立即在新的内核会话中使用,而无需重新编译其源代码. 它也可以分发到其他机器,但只与构建它所用的平台兼容. 如要构建跨平台组件库,BuildCompiledComponent 需要在每个目标平台上运行.