本机动态库嵌入为资源文件示例; Example of native library embed as resource;
应该有更简单的方法,但还没有深入探究;
.net增加aot发布后,第三方包引用的已编译本机库不会嵌入到可执行文件中,导致发布后需要分发多个文件,此示例演示一种将本机库嵌入可执行文件作为资源的办法;
在 csproj
中添加嵌入资源的操作,示例为 sqlite
本机库
<!-- 仅当启用 aot 发布,且编译条件为 Release ,且指定运行时时进行嵌入 -->
<ItemGroup Condition="'$(PublishAot)' == 'true' and '$(Configuration)' == 'Release' and '$(RuntimeIdentifier)' != ''">
<!-- 嵌入 obj/embed_depends_files 目录下的所有文件 -->
<EmbeddedResource Include="$(IntermediateOutputPath)embed_depends_files\**\*" Link="\%(RecursiveDir)%(FileName)%(Extension)">
<CopyToOutputDirectory>Never</CopyToOutputDirectory>
</EmbeddedResource>
</ItemGroup>
<!-- 仅当启用 aot 发布,且编译条件为 Release ,且指定运行时时在构建中复制目标文件到 obj 目录下 -->
<Target Name="__CopyEmbedDependsFilesToIntermediateOutput"
AfterTargets="CopyFilesToOutputDirectory"
Condition="'$(PublishAot)' == 'true' and '$(Configuration)' == 'Release' and '$(RuntimeIdentifier)' != ''">
<ItemGroup>
<!-- 复制输出目录的 e_sqlite3.* 和 libe_sqlite3.* 等文件,此值需要确认要嵌入的库可能的名称(windows、linux等不同的系统名称不同) -->
<EmbedDependsFiles Include="$(OutputPath)e_sqlite3.*;$(OutputPath)libe_sqlite3.*" />
</ItemGroup>
<!-- 复制文件到 obj/embed_depends_files 目录下 -->
<Copy SourceFiles="@(EmbedDependsFiles)" DestinationFolder="$(IntermediateOutputPath)embed_depends_files\" SkipUnchangedFiles="true" />
</Target>
在 AssemblyLoadContext.Default.ResolvingUnmanagedDl
中将嵌入的资源文件复制到物理路径,然后进行加载,示例为 sqlite
本机库
AssemblyLoadContext.Default.ResolvingUnmanagedDll += (Assembly _, string libraryName) =>
{
//当库名称不为 e_sqlite3 时不进行处理
if (!libraryName.Equals("e_sqlite3"))
{
return default;
}
var assembly = Assembly.GetExecutingAssembly();
//获取 sqlite 本机库的嵌入资源名称
var resourceName = assembly.GetManifestResourceNames().Single(str => str.Contains("e_sqlite3"));
//读取资源
using var stream = assembly.GetManifestResourceStream(resourceName);
if (stream is null)
{
return default;
}
//构造临时路径
var sqliteLibraryPath = Path.Combine(Path.GetTempPath(), Path.GetFileName(resourceName));
if (!File.Exists(sqliteLibraryPath))
{
//将本机库复制到临时路径
using var file = File.OpenWrite(sqliteLibraryPath);
stream.CopyTo(file);
}
//进行加载
return NativeLibrary.Load(sqliteLibraryPath);
};
示例:
dotnet build -c Release -r win-x64 --no-incremental
dotnet build -c Release -r win-x64 --no-incremental
dotnet publish -c Release -r win-x64