Collectives™ on Stack Overflow

Find centralized, trusted content and collaborate around the technologies you use most.

Learn more about Collectives

Teams

Q&A for work

Connect and share knowledge within a single location that is structured and easy to search.

Learn more about Teams

I have a project developed with .NET Core and C#, running on Docker, that has to call a few functions on a DLL developed with C++. The problem is: when I run my project without Docker, on Windows using Visual Code, the code runs smoothly, but when I run on Docker, on a Linux container, the code throws an error when trying to execute the DLL function.

I already tried copying the .dll file to the /lib folder, changing it to the parent folder of the project and none of that worked. I started to doubt that the problem is that the file is not found and, by doing some research, I saw that it could be related to the file permissions, so I ran chmod a+wrx on the .dll file, also no success.

This is my Dockerfile configuration:

FROM mcr.microsoft.com/dotnet/core/aspnet:2.2 AS base
WORKDIR /app
EXPOSE 80
RUN apt-get update \
    && apt-get install -y --allow-unauthenticated \
        libc6-dev \
        libgdiplus \
        libx11-dev \
     && rm -rf /var/lib/apt/lists/*
RUN apt-get update \
    && apt-get install -y poppler-utils
FROM mcr.microsoft.com/dotnet/core/sdk:2.2 AS build-env
WORKDIR /app
COPY . .
RUN dotnet restore --configfile Nuget.config -nowarn:msb3202,nu1503
RUN dotnet publish -c Release -o ./out 
FROM base AS final
WORKDIR /app
COPY --from=build-env /app/out .
ENTRYPOINT ["dotnet", "MdeGateway.dll"]

This is the code that tries to access the DLL function:

[DllImport("MyDll.dll")]
private static extern int dllfunction(Int32 argc, IntPtr[] argv);
public static void CallDll(string[] args)
    IntPtr[] argv = ArrayToArgs(args);
    dllfunction(args.Length, argv);
    FreeMemory(args, argv);

The error occurs when the line 'dllfunction(args.Length, argv);' is executed.

The exact message is:

"Unable to load shared library 'MyDll.dll' or one of its dependencies. In order to help diagnose loading problems, consider setting the LD_DEBUG environment variable: libMyDll.dll: cannot open shared object file: No such file or directory"

Also, if someone can teach me how to set the LD_DEBUG environment variable I would appreciate it.

You can set environment variables in docker either with the docker run step via -e "LD_DEBUG=true" (no idea if true is the right value), or via ENV LD_DEBUG=true in the dockerfile. vsupalov.com/docker-arg-env-variable-guide/#setting-env-values – Der Kommissar Oct 22, 2019 at 16:06 @DerKommissar: I get warning: debug option true' unknown; when adding ENV LD_DEBUG=true to my dockerfile, so true is not a valid value for this variable. Added an answer below addressing setting valid values to LD_DEBUG. – Veverke Mar 8, 2021 at 13:36

I have a project developed with .NET Core and C#, running on Docker, that has to call a few functions on a DLL developed with C++. The problem is: when I run my project without Docker, on Windows using Visual Code, the code runs smoothly, but when I run on Docker, on a Linux container, the code throws an error when trying to execute the DLL function.

If I am reading this right, you have a C++ application that you compiled to a .dll (on Windows). You can DllImport this .dll on Windows, but not on Linux (container). Is that right?

Are you aware that C++ code compiled into a .dll (shared library) is a Windows-specific thing? Unmanaged code is architecture and platform specific. An unmanaged .dll compiled on x64 won't run on arm64. A unmanaged .dll compiled on Windows wont run on Linux.

Linux (and Linux containers, such as in docker) can't use a .dll built from unmanaged code on Windows. Linux needs the unmanaged (C++) code to be compiled into a shared library (.so file) for DllImport (and the underlying dlopen calls) to work on Linux. Ideally on the same platform as the container it will be running in.

The mono docs cover an (one particular) implementation of DllImport and give more background on how this works on Linux:

https://www.mono-project.com/docs/advanced/pinvoke/

(But keep in mind that Mono != .NET Core. It should still give you some more background information.)

Yes. That's exactly the case. I knew that a .dll is a Windows-specific, but I thought that DllImport would still be able to execute no matter the platform. But since this is the case I have to find a way to compile the C++ library to a .so file. Thanks a lot for your help! – Leonardo Dias Oct 23, 2019 at 3:46 Just do add, DllImport will work on Linux if you instead reference a ".so" shared library folder. – Eduard G Dec 23, 2020 at 17:20 Thank you for your answer, it helped me a lot. I needed to use a 3rd party library provided as a C# class wrapping a C++ .dll library. When I containerized it in Docker on Ubuntu, I got the same issue. I was able to find an equivalent .so library with the same interface and just rewrite the path in DllImport statements, and it is working now. – Vojta Baránek Mar 31 at 13:48

This does not give the solution to OP's problem, but helps answer his 2nd question

Also, if someone can teach me how to set the LD_DEBUG environment variable I would appreciate it.

I am facing a similar issue, and am also struggling to understand what to do with this LD_DEBUG env variable. Turns out that it controls the verbosity of the debugging info for Unix's dynamic linker.

Following the advice here, running LD_DEBUG=help cat in a linux terminal will give you all the valid options for setting LD_DEBUG.

Here's a screenshot of the output of such command:

Additional useful resources:

  • Linux Apps Debugging Techniques - The Dynamic Linker
  • Linux LS.SO man page
  • Quoting from LD.SO man page mentioned above:

    LD_DEBUG (since glibc 2.1) Output verbose debugging information about operation of the dynamic linker. The content of this variable is one of more of the following categories, separated by colons, commas, or (if the value is quoted) spaces:

              help   Specifying help in the value of this variable does
                     not run the specified program, and displays a help
                     message about which categories can be specified in
                     this environment variable.
              all    Print all debugging information (except statistics
                     and unused; see below).
              bindings
                     Display information about which definition each
                     symbol is bound to.
              files  Display progress for input file.
              libs   Display library search paths.
              reloc  Display relocation processing.
              scopes Display scope information.
              statistics
                     Display relocation statistics.
              symbols
                     Display search paths for each symbol look-up.
              unused Determine unused DSOs.
              versions
                     Display version dependencies.
              Since glibc 2.3.4, LD_DEBUG is ignored in secure-execution
              mode, unless the file /etc/suid-debug exists (the content
              of the file is irrelevant).
            

    Thanks for contributing an answer to Stack Overflow!

    • Please be sure to answer the question. Provide details and share your research!

    But avoid

    • Asking for help, clarification, or responding to other answers.
    • Making statements based on opinion; back them up with references or personal experience.

    To learn more, see our tips on writing great answers.