2017-04-14 50 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();