Search code examples
c#visual-studiomonodependenciesmonodevelop

Copy Native Libraries to Output directory on every Build in Visual Studio or MonoDevelop based on current Operating System (Windows/Linux)


I'm working on a C# WinForms project currently being developed in VS 2017, although, it will be deployed on a Linux machine with Ubuntu 16.04 LTS using the Mono framework (MonoRuntime).

I'm referencing EmguCV v3.2 and SQLite in my project. Both of these are .NET Managed Assemblies with dependencies on their own native libraries (EmguCV uses cvextern.dll and SQLite uses SQLite.Interop.dll).

Since this app will be deployed on a Linux machine, I've compiled and built the .so library files for both of them (libcvextern.so and libSQLite.Interop.so to be precise) successfully.

For my application to work on Windows, the 2 .so files are redundant, whereas they are necessary for when my app runs on Linux under Mono (and they must be in the executing directory always!).

My question is, I want to make Visual Studio 2017 or MonoDevelop understand that If I'm building on Windows (either Debug/Release) I need the .dll files to be copied to Output directory (OR) similar with .so files if on Linux. How do you approach this?

So, How do I set a Post-Build event properly that is respected by both VS 2017 and MonoDevelop that they identify the underlying current operating system at build time and copy respective lib files to the output directory?

Apologies for any English grammar issues, I'm a non-native.

Any pointers are appreciated!


Solution

  • Ok, I've solved this problem (after searching for hours) in 3 steps.

    As stated above, My requirement was to copy .dll files to output directory if the project was built (Debug/Release) on Windows and to copy .so counterpart libs if the project was built (Debug/Release) on Linux using MonoDevelop.

    1. I copied the libraries to a directory in my project folder (somewhere safe) and then used the Add Existing Item in VS 2017 --> Selected desired lib files --> Used Add as Link instead of Open (Found this from here).
    2. I need them to be copied to Output directory without the folder structure inherited from when I added them to the project, so I followed the accepted answer to this question and was able instruct it to copy to Output dir on every Build.
    3. Now for the final requirement, which is to copy specific files based on the underlying Operating System, I used the Condition attribute in the ItemPropertyGroup in the .csproj file. Here's what I did:

    I have 1 .dll to be included if base OS is Windows or 2 .so files if it's linux, here's my configuration for them as modified in the .csproj file.

    <ContentWithTargetPath Include="references\libDependencies\linux64\libcvextern.so" Condition=" '$([System.Runtime.InteropServices.RuntimeInformation]::IsOSPlatform($([System.Runtime.InteropServices.OSPlatform]::Linux)))' ">
      <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
      <TargetPath>libcvextern.so</TargetPath>
    </ContentWithTargetPath>
    
    
    <ContentWithTargetPath Include="references\libDependencies\linux64\libSQLite.Interop.so" Condition=" '$([System.Runtime.InteropServices.RuntimeInformation]::IsOSPlatform($([System.Runtime.InteropServices.OSPlatform]::Linux)))' ">
      <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
      <TargetPath>libSQLite.Interop.so</TargetPath>
    </ContentWithTargetPath>
    
    
    <ContentWithTargetPath Include="references\libDependencies\win64\cvextern.dll" Condition=" '$(OS)' == 'Windows_NT' ">
      <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
      <TargetPath>cvextern.dll</TargetPath>
    </ContentWithTargetPath>
    

    As is expected, from now on, everytime you Build (Debug/Release) the corresponding libraries are copied to the Output directory. That is all it took, hope it will be of help to someone.