来自NuGet包的DllImport本机依赖性在net472上不起作用,但在netcoreapp2.2上有效

时间:2019-04-14 19:04:10

标签: .net nuget pinvoke

我的项目当前在.NET Core(Linux / OSX / Windows / netcoreapp2.2)上可以正常运行。它也应该在net472上工作,但是由于某些原因,DllImport找不到本机依赖性。

可以找到一个简单的副本here,但为了后代,我将在这个问题上进一步扩展。

这里是包含本地依赖项的打包项目。

<Project Sdk="Microsoft.NET.Sdk">
  <Import Project="../../build/common.props" />
  <PropertyGroup>
    <TargetFramework>netstandard2.0</TargetFramework>
    <RuntimeIdentifier>win-x64</RuntimeIdentifier>
    <DisableImplicitFrameworkReferences>true</DisableImplicitFrameworkReferences>
    <EnableDefaultItems>false</EnableDefaultItems>
    <GenerateAssemblyInfo>false</GenerateAssemblyInfo>
    <IncludeBuildOutput>false</IncludeBuildOutput>
  </PropertyGroup>
  <ItemGroup>
    <ProjectReference Include="..\net\Qml.Net\Qml.Net.csproj" />
  </ItemGroup>
  <ItemGroup>
    <Content Include="output/**/*">
      <PackagePath>runtimes/win-x64/native/</PackagePath>
      <Pack>true</Pack>
    </Content>
  </ItemGroup>
</Project>

这将产生一个带有以下输出的NuGet包。

├── [Content_Types].xml
├── package
│   └── services
│       └── metadata
│           └── core-properties
│               └── e803485f4a674e8d9d0155224fa9cbc2.psmdcp
├── Qml.Net.WindowsBinaries.nuspec
├── _rels
└── runtimes
    └── win-x64
        └── native
            └── QmlNet.dll

8 directories, 4 files

这是我的消耗项目。

<Project Sdk="Microsoft.NET.Sdk">
  <PropertyGroup>
    <OutputType>Exe</OutputType>
    <TargetFramework>net472</TargetFramework>
    <RunWorkingDirectory>$(MSBuildProjectDirectory)</RunWorkingDirectory>
  </PropertyGroup>
  <ItemGroup>
    <None Remove="**\*.qmlc" />
  </ItemGroup>
  <ItemGroup>
    <PackageReference Include="Qml.Net" Version="0.9.0-alpha.5" />
    <PackageReference Include="Qml.Net.WindowsBinaries" Version="0.9.0-alpha.5" />
  </ItemGroup>
  <ItemGroup>
    <Content Include="images\**" CopyToPublishDirectory="Always" />
    <Content Include="pages\**" CopyToPublishDirectory="Always" />
    <Content Include="Main.qml" CopyToPublishDirectory="Always" />
  </ItemGroup>
</Project>

这是尝试执行PInvoke的简单代码。

using System;
using System.Runtime.InteropServices;
using Qml.Net.Runtimes;

namespace Features
{
    class Program
    {
        // NOTE: This works if I provide absolute path to QmlNet.dll
        [DllImport("QmlNet")]
        internal static extern long qml_net_getVersion();

        static int Main(string[] args)
        {
            // This is need to prep Qt runtime that QmlNet.dll depends on.
            // It is required, but it is irrelvant to the issue we are experiencing.
            RuntimeManager.DiscoverOrDownloadSuitableQtRuntime();

            // The following works on netcoreapp2.2, but not on 4.7.2.
            Console.WriteLine(qml_net_getVersion());

            return 0;
        }
    }
}

运行此命令时,我得到:

System.DllNotFoundException: 'Unable to load DLL 'QmlNet': The specified module could not be found. (Exception from HRESULT: 0x8007007E)'

我尝试在我的NuGet包中向net472添加一个显式目标,但是没有用。

使用的项目目标为netcoreapp2.2时,我没有任何错误。

在定位DllImport时,如何使我的本机依赖性成为通过net472发现的属性?

1 个答案:

答案 0 :(得分:-1)

This answer帮助我从nuget软件包中加载了本机文件。我唯一要做的就是使用这样的当前目录

private static IntPtr ImportResolver(string libraryName, Assembly assembly, DllImportSearchPath? searchPath)
{
    IntPtr libHandle = IntPtr.Zero;
    //TODO: Add check for windows if needed.
    if (libraryName == WrapperFFI && RuntimeInformation.IsOSPlatform(OSPlatform.Linux) && Environment.Is64BitOperatingSystem)
    {
        var res = NativeLibrary.TryLoad(System.IO.Directory.GetCurrentDirectory()+"/bin/Debug/netcoreapp3.1/runtimes/linux-x64/native/libwrapper_ffi.so", out libHandle);
        if (!res) {
            res = NativeLibrary.TryLoad(System.IO.Directory.GetCurrentDirectory()+"/bin/Release/netcoreapp3.1/runtimes/linux-x64/native/libwrapper_ffi.so", out libHandle);
        }
    } 
    return libHandle;
}

编辑:

即使上面的修复程序可以在大多数情况下起作用,但当我拉出基于私人仓库的nuget程序包时,它却无效。私有仓库的本机库是在centos上构建的,这会导致二进制文件更小,但是我仍然无法在ubuntu开发机上加载异常。 centos库比lubuntu库具有更多的ldd显示的依赖项

Ubuntu:

enter image description here

Centos:

enter image description here

所以我将创建一个ubuntu build boks来快速解决问题