Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

csproj copy files depending on operating system

Tags:

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?

like image 678
sakra Avatar asked Apr 14 '17 13:04

sakra


2 Answers

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:

  • https://github.com/Microsoft/msbuild/issues/539
  • https://github.com/Microsoft/msbuild/issues/2468
like image 97
tzachs Avatar answered Sep 21 '22 06:09

tzachs


As a follow-up to @tzachs accepted answer, since msbuild 15.3 (basically Visual Studio 2017+ or .NET Core 2+) you can shorten this to use the [MSBuild]::IsOSPlatform() method. (Documentation on this page.)

It accepts values of the OSPlatform struct, e.g. 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> 
like image 34
iinuwa Avatar answered Sep 18 '22 06:09

iinuwa