DllImport无法在Docker上运行-DllNotFoundException

时间:2019-10-22 14:36:17

标签: c# docker .net-core dllimport

我有一个使用.NET Core和C#开发的项目,该项目在Docker上运行,必须在用C ++开发的DLL上调用一些函数。 问题是:当我在不使用Docker的情况下运行项目时,在Windows上使用Visual Code可以平稳运行代码,但是当我在Docker的Linux容器上运行时,尝试执行DLL函数时,代码会引发错误。

我已经尝试过将.dll文件复制到/ lib文件夹,将其更改为项目的父文件夹,但没有一个起作用。我开始怀疑问题是找不到该文件,并且通过做一些研究,我发现它可能与文件权限有关,因此我在.dll文件上运行chmod a + wrx,也没有成功。

这是我的Dockerfile配置:

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"]

这是尝试访问DLL函数的代码:

[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);
}

当行'dllfunction(args.Length,argv);'时发生错误被执行。

确切的消息是:

“无法加载共享库'MyDll.dll'或其依赖项之一。为了帮助诊断加载问题,请考虑设置LD_DEBUG环境变量:libMyDll.dll:无法打开共享库文件:没有此类文件或目录“

此外,如果有人可以教我如何设置LD_DEBUG环境变量,我将不胜感激。

2 个答案:

答案 0 :(得分:1)

  

我有一个使用.NET Core和C#开发的项目,该项目在Docker上运行,必须在用C ++开发的DLL上调用一些函数。问题是:当我在不使用Docker的情况下运行项目时,在Windows上使用Visual Code可以平稳运行代码,但是当我在Docker的Linux容器上运行时,尝试执行DLL函数时,代码会引发错误。

如果我没看错,您有一个C ++应用程序,已将其编译为ParentObject{myPojo=MyPojo{indicatorI=true, indicatorJ=null, indicatorK=false}} (在Windows上)。您可以.dll在Windows上DllImport,但不能在Linux(容器)上.dll。是吗?

您是否知道编译到.dll(共享库)中的C ++代码是Windows特定的东西?非托管代码是特定于体系结构和平台的。在x64上编译的非托管.dll无法在arm64上运行。在Windows上编译的不受管理的.dll无法在Linux上运行。

Linux(和Linux容器,例如docker中的Linux容器)不能使用从Windows上的非托管代码构建的.dll。 Linux需要将非托管(C ++)代码编译到共享库(.so文件)中,以便DllImport(以及基础的dlopen调用)在Linux上工作。理想情况下,它将与将在其中运行容器的平台位于同一平台上。

mono文档涵盖了DllImport的(一个特定)实现,并提供了在Linux上如何工作的更多背景信息:

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

(但是请记住,Mono!= .NET Core。它仍然应该为您提供更多背景信息。)

答案 1 :(得分:1)

这不能解决 OP 的问题,但有助于回答他的第二个问题

<块引用>

另外,如果有人能教我如何设置 LD_DEBUG 环境变量,我将不胜感激。

我面临着类似的问题,并且也在努力理解如何处理这个 LD_DEBUG 环境变量。事实证明,它控制着 Unix 动态链接器调试信息的详细程度。

按照建议 here,在 Linux 终端中运行 LD_DEBUG=help cat 将为您提供设置 LD_DEBUG 的所有有效选项。

这是该命令输出的屏幕截图: enter image description here

其他有用的资源:

引用上面提到的 LD.SO 手册页:

<块引用>

LD_DEBUG(自 glibc 2.1 起) 输出有关操作的详细调试信息 动态链接器。这个变量的内容是一个 以下类别中的更多类别,以冒号分隔, 逗号,或(如果值被引用)空格:

          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).