2017-04-14 51 views
3

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

如何在.csproj ItemGroup中使用Condition子句做到这一点?

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

$(Platform)似乎并没有工作。是否有我可以使用的另一个变量?

+0

$(平台)有不同的价值观,像任何CPU,86,64。我会检查它是如何完成具有平台特定依赖性的开源库的。据我所知,有些通过单独的nuget软件包提供这种平台特定的依赖关系。就像他们在https://www.nuget.org/packages/CoreCompat.System.Drawing/1.0.0-beta006 –

+0

中所做的那样,当您针对OSX构建时,$(Platform)变量的值是多少? –

+0

'Platform = AnyCPU',但对于Windows和Linux版本来说则是一样的。 – sakra

回答

2

为了区分Windows & Mac/Linux,您可以使用$(os)属性:这会给你Windows的Windows_NT和Mac/Linux的UNIX

为区分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核心,单声道和.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')) "

来源:

0

我确实有这样的问题,并最终节省资源DLL和lodaing为x86或x64,当库第一次initilized的DLL。这对我来说是最清洁的方式。

另一种方式,当你在nuget中包含dll时,你也必须确保当som一个删除/清除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();