Skip to content

It's Really Hard To Package Native Libraries for PowerShell Modules #8861

@vexx32

Description

@vexx32

OK, so... this is an issue that's been around for a long time, I'm sure. I've not really had reason to hit it before. And now I have.

Scenario

I'm trying to package a module with a dependency that does p/invoking via native runtime libraries. The library is SkiaSharp. This library cannot be used without native runtimes.

I'd like to be able to handle native runtimes correctly from a compiled PowerShell cmdlet / module.

Problem

The issue then becomes that these native runtimes are different on each platform. Each platform expects that the libraries will be in the same folder as the SkiaSharp.dll. This can't be done for every platform at once, as several of the platform-specific libraries have the same name.

The folder structure after running dotnet publish looks like this:

Tree Structure

Ignoring the tizen runtimes (I think they're for Android or something? not sure), a few of the libraries have the same filenames, namely the Windows libraries for the two architectures. A temporary workaround is to put as much as possible in the same folder and ignore that x86 Windows still exists.

Attempted Solutions

We have tried to work around the problem by selectively importing the native libraries, but this is entirely impossible with PowerShell as they throw Bad IL format errors. We have tried:

  1. Import-Module .\bin\Debug\netstandard2.0\publish\runtimes\<platform>\native\<runtime_file>
  2. Add-Type -Path .\bin\Debug\netstandard2.0\publish\runtimes\<platform>\native\<runtime_file>
  3. [System.Reflection.Assembly]::LoadFile((Resolve-Path ".\bin\Debug\netstandard2.0\publish\runtimes\<platform>\native\<runtime_file>"))

Possible Solutions

  • Ability to specify dependencies such as these by relative path in a PSD1 on a per-platform basis, which is respected with Import-Module and loaded correctly.
  • Some kind of handling in PowerShellGet for native runtimes on a per-platform basis? Possibly handled via NuGet in terms of pulling down the exact runtime required on a specific platform.

There's probably a neater solution I'm missing, feel free to add any suggestions.

Files

Source & module files for reference, if you should like to attempt anything with them:
https://github.com/vexx32/PSWordCloud/tree/Cmdlet/PSWordCloud

Running PSWordCloud

To use:

  1. Publish the source files for this module with dotnet publish
  2. Import the PSM1 file in the linked folder with Import-Module
  3. Attempt to pipe some text into New-WordCloud -Path .\test.svg

This will work on Windows thanks to the PSM1 manually modifying $env:Path to add all the native runtime folders. This solution is terribly messy and absolutely makes a right royal mess of $env:Path for anyone importing the module. I would like to avoid this.

It attempts to do similar on Mac OS and Linux, but in these cases it seems the path for native runtime libraries isn't searched correctly. The only currently available workaround is manually copying these libraries to the same folder as SkiaSharp.dll which is... less than great.

/cc @TylerLeonhardt @daxian-dbw @SteveL-MSFT

Metadata

Metadata

Assignees

No one assigned

    Labels

    Issue-Discussionthe issue may not have a clear classification yet. The issue may generate an RFC or may be reclassifIssue-Enhancementthe issue is more of a feature request than a bugResolution-FixedThe issue is fixed.

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions