csproj copy files depending on operating system

匿名 (未验证) 提交于 2019-12-03 08:48:34

问题:

I am using .NET Core to build a cross platform class library. Depending on the operating system that the C# .NET Core project is built for using a .csproj file, I need to copy a native library to the project's output directory. E.g., for OS X I want to copy a .dylib file, for Windows I want to copy a .DLL file, for Linux I want to copy a .so file.

How can I do this with a Condition clause in a .csproj ItemGroup?

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

$(Platform) does not seem to work. Is there a different variable I can use?

回答1:

For differentiating between Windows & Mac/Linux you can use the $(os) property: this gives you Windows_NT for Windows and UNIX for Mac/Linux.

For differentiating between Mac & Linux, at least on recent versions of MSBuild, you can use RuntimeInformation.IsOSPlatform.

So, combined, your csproj can have something like this:

<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> 

To the best of my knowledge, this should work in all recent versions of .Net Core, Mono and .Net Framework.

In older versions, you'd need to resort to evil trickery for differentiating between Mac & Linux:

For Linux -> Condition=" '$(OS)' == 'Unix' and ! $([System.IO.File]::Exists('/usr/lib/libc.dylib')) "

For Mac -> Condition=" '$(OS)' == 'Unix' and $([System.IO.File]::Exists('/usr/lib/libc.dylib')) "

Sources:



回答2:

I did have a problem like this and ended up saving the dll in a resource and lodaing the dll for X86 or X64, when the library first initilized. It was the cleanst way for me.

Alternative when you include the dll in nuget you have also to make sure the same dll get recoped when the som one remove/clean the bin mapp.

So you have to add the file to nuger and also create a targets on build file to recopy the dll on build

Here is what i did.

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);          }     } } 

And then just call it

EmbeddedDllClass.LoadAllDll(); 


标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!