Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

pact_ffi.dll doesn't get copied over to output directory with Visual Studio #377

Closed
aucubin opened this issue Mar 8, 2022 · 11 comments
Closed
Labels
bug Indicates an unexpected problem or unintended behavior
Milestone

Comments

@aucubin
Copy link

aucubin commented Mar 8, 2022

Hi. I have an issue with the current PactNet Beta version (4.0.0-beta.3).
I added the nuget package to a new project and restored it.
Afterwards I can then see that the package is in the path WBServer\packages\PactNet.4.0.0-beta.3 where WBServer is the solution where I added the project that has the PactNet nuget package installed.

The issue now is that the pact_ffi.dll is not copied from the package folder WBServer\packages\PactNet.4.0.0-beta.3\runtimes\win-x64\native\pact_ffi.dll to the output directory (bin\Debug or bin\Release inside the project folder) of the Visual studio build process and I get the following error (basically saying that the pact_ffi.dll is not found):

 SetUp : System.DllNotFoundException : Die DLL "pact_ffi": Das angegebene Modul wurde nicht gefunden. (Ausnahme von
   HRESULT: 0x8007007E) kann nicht geladen werden.
     bei PactNet.Interop.NativeInterop.LogToBuffer<<Swapped(LevelFilter levelFilter)
     bei PactNet.Interop.NativeInterop.LogToBuffer(LevelFilter levelFilter)
     bei PactNet.PactExtensions.InitialiseLogging(PactLogLevel level)
     bei PactNet.PactExtensions.InitialiseServer(MockServer server, IPact pact, PactSpecification version)
     bei PactNet.PactExtensions.UsingNativeBackend(IPactV3 pact, Nullable`1 port, IPAddress host)

If I just add the pact_ffi.dll manually to the output directory the tests then run.

On PactNet v3 with Ruby the ruby runtime and all the pact scripts got copied automatically from the nuget package to the output package without me doing anything (but I think there this is done via the PactNet.Windows package), so my assumption was that something changed in the Nuget package that breaks that behaviour between PactNet v3 and PactNet v4.

@adamrodger
Copy link
Contributor

Are you using the old style csproj format and NuGet style? (i.e. a packages.config file instead of PackageReference elements in the csproj).

I think it'll only work with the new style

@aucubin
Copy link
Author

aucubin commented Mar 9, 2022

Hi.

The codebase is still on .NET Framework 4.8 so it used packages.config by default. I migrated it to PackageReference as per this guide.
It seemed to have succeeded as I have this block here now in the csproj:

<PackageReference Include="PactNet">
      <Version>4.0.0-beta.3</Version>
</PackageReference>

But it still doesn't copy the pact_ffi.dll to the output directory automatically.

@adamrodger
Copy link
Contributor

Are you using dotnet restore or nuget restore? I think it needs to be dotnet restore for it to unpack the native libs to the correct place

@adamrodger
Copy link
Contributor

The tests run under .Net 4.6.1 using new style csproj with PackageReference entries and dotnet restore to restore the deps, so I know it def works with that.

@aucubin
Copy link
Author

aucubin commented Mar 10, 2022

I checked out the PactNet repository and built the PactNet.Tests project. For that project I also get the pact_ffi.dll copied.
But I could now reproduce the issue with the following minimal working example . If I run dotnet restore in the folder with the pactdllcopytest.csproj and then dotnet build I will only get the PactNet and the PactNet.Abstractions.dll, but the pact_ffi.dll is missing and the test will only run succesfully if i copy the pact_ffi.dll manually from the folder where the nuget package was downloaded to.

@adamrodger
Copy link
Contributor

I've reproduced this locally (using Git Bash on Windows):

dotnet new console --target-framework-override net48 --langVersion 9.0
dotnet add package PactNet --version 4.0.0-beta.3

cat > Program.cs <<EOF
using System;
using System.Net;
using System.Net.Http;
using PactNet;

var pact = Pact.V3("Something API Consumer", "Something API");
var builder = pact.UsingNativeBackend();

builder.UponReceiving("a request")
        .WithRequest(HttpMethod.Get, "/")
        .WillRespond()
        .WithStatus(HttpStatusCode.OK);

await builder.VerifyAsync(async ctx =>
{
    var client = new HttpClient()
    {
        BaseAddress = ctx.MockServerUri
    };

    var response = await client.GetAsync("/");

    response.EnsureSuccessStatusCode();
});

Console.WriteLine("Success");
EOF

dotnet run

The FFI DLL isn't in the bin folder so it gives the DLL missing error. If you change the net48 to a net6.0 then it works absolutely fine, so it's something to do with .Net Framework not unpacking the runtimes section of the NuGet properly.

The other problem is that the .Net 6 version has also copied every platform DLL to the bin folder instead of just the appropriate one.

@adamrodger
Copy link
Contributor

I don't really understand why that's not working, because I've followed all the guidelines in the NuGet docs for bundling native assemblies:
https://docs.microsoft.com/en-us/nuget/create-packages/supporting-multiple-target-frameworks#architecture-specific-folders

@adamrodger
Copy link
Contributor

From having a quick Google around I found this StackOverflow thread in which it appears .Net Framework totally ignores the runtimes/ folder, so the files have to be copied into lib/ instead.... or something 😁

I'll give it a go, but in the meantime there's a workaround for .Net Framework. Specify the runtime explicitly every time you build/run:

dotnet build --runtime win-x64

or a better option is just add a <RuntimeIdentifier>win-x64</RuntimeIdentifier> property to your csproj and then it'll build properly:

image

That produces an output folder with the DLL copied in and runs as expected

@adamrodger
Copy link
Contributor

There's also an open issue in the NuGet repo saying that .Net Framework is just problematic in this area: NuGet/Home#6645

@adamrodger
Copy link
Contributor

I've added a custom targets file which will only be triggered on .Net Framework 4.6.1 and above. This copies the win-x64 runtime DLL to the output folder automatically on build.

For .Net (and .Net Core), the existing approach works fine, whereby the runtimes/ folder is unpacked to the output folder and then dotnet automatically finds the appropriate library at runtime.

@adamrodger adamrodger added this to the 4.0.0-beta.4 milestone Mar 13, 2022
@adamrodger adamrodger added the bug Indicates an unexpected problem or unintended behavior label Mar 13, 2022
@culudamar
Copy link

I'm having the same problem with the latest master branch. Could the changes be reverted at some point?

Error MSB3030 Could not copy the file "C:\Users\57046\Source\repos\pact-net\build\windows\x86_64\pact_ffi.dll" because it was not found. PactNet C:\Program Files\Microsoft Visual Studio\2022\Professional\MSBuild\Current\Bin\amd64\Microsoft.Common.CurrentVersion.targets 5150

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug Indicates an unexpected problem or unintended behavior
Projects
None yet
Development

No branches or pull requests

3 participants