csproj复制文件取决于操作系统

时间:2017-04-14 13:05:56

标签: c# .net .net-core csproj

我正在使用.NET Core构建跨平台类库。根据为使用.csproj文件构建C#.NET Core项目的操作系统,我需要将本机库复制到项目的输出目录。例如,对于OS X,我想复制.dylib文件,对于Windows,我要复制.DLL文件,对于Linux我要复制.so文件。

如何使用.csproj ItemGroup中的Condition子句执行此操作?

  <ItemGroup>
    <Content Include="libNative.dylib" Condition=" '$(Configuration)|$(Platform)' == 'Debug|OSX' ">
      <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
    </Content>
  </ItemGroup>   

$(Platform)似乎不起作用。我可以使用不同的变量吗?

3 个答案:

答案 0 :(得分:8)

区分Windows&amp; Mac / Linux您可以使用$(os)属性:这为Windows提供了Windows_NT,为Mac / Linux提供了UNIX

区分Mac&amp; 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&amp; Linux:

对于Linux - &gt; Condition=" '$(OS)' == 'Unix' and ! $([System.IO.File]::Exists('/usr/lib/libc.dylib')) "

对于Mac - &gt; Condition=" '$(OS)' == 'Unix' and $([System.IO.File]::Exists('/usr/lib/libc.dylib')) "

来源:

答案 1 :(得分:0)

我确实有这样的问题,最后在资源中保存了dll,并在库首次启动时为x86或X64暂停了dll。这对我来说是最干净的方式。

替代当您在nuget中包含dll时,您还必须确保在som删除/清理b​​in 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();

答案 2 :(得分:0)

还想为我的 Nuget 包创建跨平台。 在 .csproj 中尝试了以下代码。

<Content Include="libNative.win" Condition=" '$(OS)' == 'Windows_NT' ">
<Content Include="libNative.dylib" Condition=" '$(OS)' != 'Windows_NT' ">

因此创建了 .nupkg。

当在 Linux 上引用相同的 .nupkg 时,因为 $(OS) 已经设置为 Windows_NT,添加了 libNative.win 而不是 libNative.dylib(这是预期的)。

所以这个 $(OS) 是在创建 nuget 时设置的,而不是在添加时设置的。 有关更多详细信息:您可以在 <Description> 中使用 $(OS) 或 $(Platform) 并查看值是如何设置的。