Adrian Patterson
Adrian Patterson

Reputation: 105

Including Shared C Library (.SO) in a .NET Core Docker Image

I am trying to use a C# library in my .net Core 5.0 project, which is a C# wrapper for a C Assembly for ws281x LEDs. The library requires the that the Shared C library (ws2811.so) be built before running the framework. I have successfully built and installed the C shared library into /usr/lib for my raspberry pi, and have tested it to confirm it works.

The issue lies in that within my Dockerfile, I don't know how/where to properly install this shared C library. My current dockerfile is as follows:

# https://hub.docker.com/_/microsoft-dotnet
FROM mcr.microsoft.com/dotnet/sdk:5.0 AS build
WORKDIR /source
COPY ./ /source

# installs NodeJS and NPM
RUN apt-get update -yq && apt-get upgrade -yq && apt-get install -yq curl git nano
RUN curl -sL https://deb.nodesource.com/setup_12.x | bash - && apt-get install -yq nodejs build-essential

RUN npm install -g npm
RUN npm --version

# installing c wrapper for ws2811 -- Here is where I need HELP
RUN apt-get update && apt-get install -y python
RUN apt-get install -y python-setuptools python-dev build-essential python-pip

RUN pip install scons && git clone https://github.com/jgarff/rpi_ws281x.git \
         && cd rpi_ws281x && scons && gcc -shared -o ws2811.so *.o

# copy csproj and restore as distinct layers
COPY *.sln .
COPY control/ *.csproj ./control/
RUN dotnet restore -r linux-arm

# copy everything else and build app
COPY control/. ./control/
WORKDIR /source/control
RUN dotnet publish -c release -o /app -r linux-arm --self-contained false --no-restore

# final stage/image
FROM mcr.microsoft.com/dotnet/aspnet:5.0-buster-slim-arm32v7
WORKDIR /app
COPY --from=build /app ./
ENTRYPOINT ["./control"]

As it is now, the dockerfile builds correctly and the app launches. However, when I try to use a method to invoke the ws2811.so library through P/Invoke, I get the following error:

System.DllNotFoundException: Unable to load shared library 'ws2811.so' or one of its dependencies. In order to help diagnose loading problems, consider setting the LD_DEBUG environment variable: libws2811.so: cannot open shared object file: No such file or directory

Which is telling me that P/Invoke is unsuccessful in finding the ws2811.so library. Where should I put this ws2811.so library so that my C# code can access it? I've tried placing it with the source code, I've played around with installing it in docker, but am really at a standstill and don't know where to go from here.

For a bit more information, the C# code to invoke this C-shared library is as follows. It is essentially the same thing as done in the example on the ws281x GitHub (as linked earlier).

public void setRgb()
        {
            Console.WriteLine("R: " + r + "\tG: " + g + "\tB: " + b);

            var settings = Settings.CreateDefaultSettings(false);
            var controller = settings.AddController(88, Pin.Gpio18, StripType.WS2812_STRIP, 255, false);

            Color color = new Color();
            color = Color.FromArgb(r, g, b);

            using (var rpi = new WS281x(settings)) // EXCEPTION OCCURS HERE (System.DllNotFound)
            {
                rpi.SetLedCount(88);
                rpi.SetAll(color);
            }
        }

Any help, guidance, or resources are extremely appreciated! Thanks so much :)

Upvotes: 0

Views: 2997

Answers (1)

Matt Thalman
Matt Thalman

Reputation: 3965

Docker has the concept of a "build context". That defines the directory from which files are accessed. So when you say COPY foo /foo in your Dockerfile, that's copying the foo file from the build context and places it in the root folder of your container with the name foo. You set the build context when running the docker build command. Very often, people use . as the build context which means the current working directory that you're running the command from (e.g. docker build -t app .). So it depends on what directory your build context is. That's where you should be placing the .SO library so that you can then add a COPY instruction in your Dockerfile to copy it into your container image.

Upvotes: 2

Related Questions