csproj 根据操作系统复制文件
csproj copy files depending on operating system
我正在使用 .NET Core 构建跨平台 class 库。根据为使用 .csproj 文件构建 C# .NET Core 项目的操作系统,我需要将本机库复制到项目的输出目录。例如,对于 OS X 我想复制一个 .dylib 文件,对于 Windows 我想复制一个 .DLL 文件,对于 Linux 我想复制一个 .so 文件。
如何使用 .csproj ItemGroup 中的条件子句执行此操作?
<ItemGroup>
<Content Include="libNative.dylib" Condition=" '$(Configuration)|$(Platform)' == 'Debug|OSX' ">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
</ItemGroup>
$(Platform)
好像不行。我可以使用其他变量吗?
为了区分 Windows 和 Mac/Linux,您可以使用 $(os)
属性:这为 Windows 和 Windows_NT
UNIX
对于 Mac/Linux.
为了区分 Mac 和 Linux,至少在最新版本的 MSBuild 上,您可以使用 RuntimeInformation.IsOSPlatform
.
所以,结合起来,你的 csproj 可以有这样的东西:
<ItemGroup>
<Content Include="libNative.dll" Condition=" '$(OS)' == 'Windows_NT' ">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
<Content Include="libNative.so" Condition=" '$([System.Runtime.InteropServices.RuntimeInformation]::IsOSPlatform($([System.Runtime.InteropServices.OSPlatform]::Linux)))' ">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
<Content Include="libNative.dylib" Condition=" '$([System.Runtime.InteropServices.RuntimeInformation]::IsOSPlatform($([System.Runtime.InteropServices.OSPlatform]::OSX)))' ">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
</ItemGroup>
据我所知,这应该适用于所有最新版本的 .Net Core、Mono 和 .Net Framework。
在旧版本中,您需要使用邪恶的手段来区分 Mac 和 Linux:
对于Linux -> Condition=" '$(OS)' == 'Unix' and ! $([System.IO.File]::Exists('/usr/lib/libc.dylib')) "
对于Mac -> Condition=" '$(OS)' == 'Unix' and $([System.IO.File]::Exists('/usr/lib/libc.dylib')) "
来源:
我确实遇到过这样的问题,最终在库首次初始化时将 dll 保存在资源中并加载 X86 或 X64 的 dll。这对我来说是最干净的方式。
或者,当您在 nuget 中包含 dll 时,您还必须确保在 som 一个 remove/clean bin mapp 时重新复制相同的 dll。
因此您必须将文件添加到 nuger 并在构建文件上创建目标以在构建时重新复制 dll
这是我做的。
internal class EmbeddedDllClass
{
public static void LoadAllDll()
{
Assembly assem = Assembly.GetExecutingAssembly();
if (IntPtr.Size == 8)
{
var path = Path.Combine(string.Join("\", assem.Location.Split('\').Reverse().Skip(1).Reverse()), "x64");
if (!Directory.Exists(path))
Directory.CreateDirectory(path);
path = Path.Combine(path, "SQLite.Interop.dll");
if (!File.Exists(path))
File.WriteAllBytes(path, Properties.Resources.SQLite_Interop_64);
}
else if (IntPtr.Size == 4)
{
var path = Path.Combine(string.Join("\", assem.Location.Split('\').Reverse().Skip(1).Reverse()), "x86");
if (!Directory.Exists(path))
Directory.CreateDirectory(path);
path = Path.Combine(path, "SQLite.Interop.dll");
if (!File.Exists(path))
File.WriteAllBytes(path, Properties.Resources.SQLite_Interop_86);
}
}
}
然后直接调用它
EmbeddedDllClass.LoadAllDll();
也想为我的 Nuget 包创建跨平台。
在 .csproj.
中尝试了以下代码
<Content Include="libNative.win" Condition=" '$(OS)' == 'Windows_NT' ">
<Content Include="libNative.dylib" Condition=" '$(OS)' != 'Windows_NT' ">
因此创建了 .nupkg。
当引用相同的 .nupkg 时,在 linux 上,因为 $(OS) 已经设置为 Windows_NT,添加了 libNative.win 而不是 libNative.dylib(这是预期的).
所以这个 $(OS) 是在创建 nuget 时设置的,而不是在添加时设置的。
更多详细信息:您可以在<Description>
中使用$(OS)或$(Platform),看看该值是如何设置的。
作为@tzachs 接受的答案的后续行动,自 msbuild 15.3(基本上是 Visual Studio 2017+ 或 .NET Core 2+)以来,您可以缩短它以使用 [MSBuild]::IsOSPlatform()
方法。 (this page 上的文档。)
它接受 OSPlatform struct 的值,例如Windows
, Linux
, OSX
, FreeBSD
.
<ItemGroup>
<Content Include="libNative.dll" Condition="$([MSBuild]::IsOSPlatform('Windows'))">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
<Content Include="libNative.so" Condition="$([MSBuild]::IsOSPlatform('Linux'))">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
<Content Include="libNative.dylib" Condition="$([MSBuild]::IsOSPlatform('OSX'))">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
</ItemGroup>
我正在使用 .NET Core 构建跨平台 class 库。根据为使用 .csproj 文件构建 C# .NET Core 项目的操作系统,我需要将本机库复制到项目的输出目录。例如,对于 OS X 我想复制一个 .dylib 文件,对于 Windows 我想复制一个 .DLL 文件,对于 Linux 我想复制一个 .so 文件。
如何使用 .csproj ItemGroup 中的条件子句执行此操作?
<ItemGroup>
<Content Include="libNative.dylib" Condition=" '$(Configuration)|$(Platform)' == 'Debug|OSX' ">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
</ItemGroup>
$(Platform)
好像不行。我可以使用其他变量吗?
为了区分 Windows 和 Mac/Linux,您可以使用 $(os)
属性:这为 Windows 和 Windows_NT
UNIX
对于 Mac/Linux.
为了区分 Mac 和 Linux,至少在最新版本的 MSBuild 上,您可以使用 RuntimeInformation.IsOSPlatform
.
所以,结合起来,你的 csproj 可以有这样的东西:
<ItemGroup>
<Content Include="libNative.dll" Condition=" '$(OS)' == 'Windows_NT' ">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
<Content Include="libNative.so" Condition=" '$([System.Runtime.InteropServices.RuntimeInformation]::IsOSPlatform($([System.Runtime.InteropServices.OSPlatform]::Linux)))' ">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
<Content Include="libNative.dylib" Condition=" '$([System.Runtime.InteropServices.RuntimeInformation]::IsOSPlatform($([System.Runtime.InteropServices.OSPlatform]::OSX)))' ">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
</ItemGroup>
据我所知,这应该适用于所有最新版本的 .Net Core、Mono 和 .Net Framework。
在旧版本中,您需要使用邪恶的手段来区分 Mac 和 Linux:
对于Linux -> Condition=" '$(OS)' == 'Unix' and ! $([System.IO.File]::Exists('/usr/lib/libc.dylib')) "
对于Mac -> Condition=" '$(OS)' == 'Unix' and $([System.IO.File]::Exists('/usr/lib/libc.dylib')) "
来源:
我确实遇到过这样的问题,最终在库首次初始化时将 dll 保存在资源中并加载 X86 或 X64 的 dll。这对我来说是最干净的方式。
或者,当您在 nuget 中包含 dll 时,您还必须确保在 som 一个 remove/clean bin mapp 时重新复制相同的 dll。
因此您必须将文件添加到 nuger 并在构建文件上创建目标以在构建时重新复制 dll
这是我做的。
internal class EmbeddedDllClass
{
public static void LoadAllDll()
{
Assembly assem = Assembly.GetExecutingAssembly();
if (IntPtr.Size == 8)
{
var path = Path.Combine(string.Join("\", assem.Location.Split('\').Reverse().Skip(1).Reverse()), "x64");
if (!Directory.Exists(path))
Directory.CreateDirectory(path);
path = Path.Combine(path, "SQLite.Interop.dll");
if (!File.Exists(path))
File.WriteAllBytes(path, Properties.Resources.SQLite_Interop_64);
}
else if (IntPtr.Size == 4)
{
var path = Path.Combine(string.Join("\", assem.Location.Split('\').Reverse().Skip(1).Reverse()), "x86");
if (!Directory.Exists(path))
Directory.CreateDirectory(path);
path = Path.Combine(path, "SQLite.Interop.dll");
if (!File.Exists(path))
File.WriteAllBytes(path, Properties.Resources.SQLite_Interop_86);
}
}
}
然后直接调用它
EmbeddedDllClass.LoadAllDll();
也想为我的 Nuget 包创建跨平台。 在 .csproj.
中尝试了以下代码<Content Include="libNative.win" Condition=" '$(OS)' == 'Windows_NT' ">
<Content Include="libNative.dylib" Condition=" '$(OS)' != 'Windows_NT' ">
因此创建了 .nupkg。
当引用相同的 .nupkg 时,在 linux 上,因为 $(OS) 已经设置为 Windows_NT,添加了 libNative.win 而不是 libNative.dylib(这是预期的).
所以这个 $(OS) 是在创建 nuget 时设置的,而不是在添加时设置的。
更多详细信息:您可以在<Description>
中使用$(OS)或$(Platform),看看该值是如何设置的。
作为@tzachs 接受的答案的后续行动,自 msbuild 15.3(基本上是 Visual Studio 2017+ 或 .NET Core 2+)以来,您可以缩短它以使用 [MSBuild]::IsOSPlatform()
方法。 (this page 上的文档。)
它接受 OSPlatform struct 的值,例如Windows
, Linux
, OSX
, FreeBSD
.
<ItemGroup>
<Content Include="libNative.dll" Condition="$([MSBuild]::IsOSPlatform('Windows'))">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
<Content Include="libNative.so" Condition="$([MSBuild]::IsOSPlatform('Linux'))">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
<Content Include="libNative.dylib" Condition="$([MSBuild]::IsOSPlatform('OSX'))">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
</ItemGroup>