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

Error Loading Native Library in Docker .NET 6 #1513

Closed
leomoty opened this issue Nov 17, 2021 · 38 comments
Closed

Error Loading Native Library in Docker .NET 6 #1513

leomoty opened this issue Nov 17, 2021 · 38 comments

Comments

@leomoty
Copy link

leomoty commented Nov 17, 2021

I am not sure whether this is a supported use case, but it has been working just fine in .NET 5 for us, I ended up updating everything to .NET 6 and gui.cs is breaking on loading native library, strangely it doesn't seem to mention which library at all. Docker image is just based off mcr.microsoft.com/dotnet/runtime:6.0, nothing added to it.

I have attached the stack trace below, let me know if more information is necessary

Stack Trace:

Curses failed to initialize, the exception is: System.IO.IOException: Error loading native library ""
   at Unix.Terminal.UnmanagedLibrary..ctor(String[] libraryPathAlternatives, Boolean isFullPath)
   at Unix.Terminal.Curses.LoadMethods()
   at Unix.Terminal.Curses.FindNCurses()
   at Unix.Terminal.Curses.initscr()
   at Terminal.Gui.CursesDriver.Init(Action terminalResized)
Unhandled exception. System.NullReferenceException: Object reference not set to an instance of an object.
   at Unix.Terminal.Curses.doupdate()
   at Terminal.Gui.CursesDriver.Init(Action terminalResized)
   at Terminal.Gui.Application.Init(Func`1 topLevelFactory, ConsoleDriver driver, IMainLoopDriver mainLoopDriver)
   at Terminal.Gui.Application.Init(ConsoleDriver driver, IMainLoopDriver mainLoopDriver)
   ....
@BDisp
Copy link
Collaborator

BDisp commented Nov 17, 2021

Can you provide a functional gui.cs project for docker to check what is going on, please?

@leomoty
Copy link
Author

leomoty commented Nov 17, 2021

Let me see if I can find some time to do it, however, after writing that I noticed that the .NET 6 docker image doesn't have ncurses installed at all.

Even after installing it, result is still spotty, had to enable UseSystemConsole = true; and some components doesn't work as expected (i.e. RadioGroup button click are not working, worked before), this might be enough for now.

@BDisp
Copy link
Collaborator

BDisp commented Nov 17, 2021

UseSystemConsole = true uses NetDriver and not CursesDriver. I think there is some dependencies you must to install to the docker image. But if you can share later I would apreciate it. Thanks.

@leomoty
Copy link
Author

leomoty commented Nov 17, 2021

Thanks for the explanation, I dont have a reduced set, removed UseSystemConsole for testing, and got a black screen with the top bar:

image

@BDisp
Copy link
Collaborator

BDisp commented Nov 17, 2021

Check if the output of ~$ echo $TERM is xterm-256color.

@leomoty
Copy link
Author

leomoty commented Nov 17, 2021

$TERM was xterm, set up an env var with xterm-256color and we have progress, UI is partially rendered using ncurses, still worse than UseSystemConsole.

@leomoty
Copy link
Author

leomoty commented Nov 17, 2021

So I did some basic testing with UICatalog example, to get NET 6.0 binaries I have patched it like so:

diff --git a/Terminal.Gui/Terminal.Gui.csproj b/Terminal.Gui/Terminal.Gui.csproj
index bba15aa..789273d 100644
--- a/Terminal.Gui/Terminal.Gui.csproj
+++ b/Terminal.Gui/Terminal.Gui.csproj
@@ -25,7 +25,7 @@
     <!-- This enables prefixing version tags with v, e.g. v1.0.0 Instead of 1.0.0 -->
     <MinVerTagPrefix>v</MinVerTagPrefix>

-    <TargetFrameworks>net472;netstandard2.0;net5.0</TargetFrameworks>
+    <TargetFrameworks>net472;netstandard2.0;net5.0;net6.0</TargetFrameworks>
     <RootNamespace>Terminal.Gui</RootNamespace>
     <AssemblyName>Terminal.Gui</AssemblyName>
     <DocumentationFile>bin\Release\Terminal.Gui.xml</DocumentationFile>
diff --git a/UICatalog/UICatalog.csproj b/UICatalog/UICatalog.csproj
index 530eed7..cf6e128 100644
--- a/UICatalog/UICatalog.csproj
+++ b/UICatalog/UICatalog.csproj
@@ -2,7 +2,7 @@

   <PropertyGroup>
     <OutputType>Exe</OutputType>
-    <TargetFramework>net5.0</TargetFramework>
+    <TargetFrameworks>net5.0;net6.0</TargetFrameworks>
     <StartupObject>UICatalog.UICatalogApp</StartupObject>
     <AssemblyVersion>1.0.0.1</AssemblyVersion>
     <LangVersion>8.0</LangVersion>

Then I just ran the default dotnet build inside UICatalog folder and had 2 debug binaries built.

I am running docker on windows within a Powershell session (current directory is UICatalog folder), so your mileage may vary slightly to map it. Mapped the binaries to the runtime container:

.NET 5

docker run -v $pwd/bin/Debug/net5.0:/app `
    -it `
    -e "TERM=xterm-256color" `
    mcr.microsoft.com/dotnet/runtime:5.0-buster-slim `
    bash -c "apt-get update && apt-get -y install libncurses5-dev libncursesw5-dev && cd /app && dotnet UICatalog.dll" 

.NET 6

 docker run -v $pwd/bin/Debug/net6.0:/app `
    -it `
    -e "TERM=xterm-256color" `
    mcr.microsoft.com/dotnet/runtime:6.0-bullseye-slim `
    bash -c "apt-get update && apt-get -y install libncurses5-dev libncursesw5-dev && cd /app && dotnet UICatalog.dll"

One example that definitely doesn't work properly in .NET 6 is the Radio Group (Text Alignment) inside the Buttons demo. Whereas it seems to mostly work for .NET 5 build except the broken glyph.

Not sure if this helps but it shows some of the differences/issues I had. Interestingly I don't remember having ever installed ncurses in my previous .NET 5 based image, i'll double check tomorrow

@leomoty
Copy link
Author

leomoty commented Nov 18, 2021

so yep, .NET 5 image used to have ncurses shared library built in but .NET 6 does not. Also it is 6.x instead of the 5.x I installed previously

.NET 6 runtime image

leo@DESKTOP-RL4O6SD:~$ docker run mcr.microsoft.com/dotnet/runtime:6.0 dpkg -l '*ncurses*'
Unable to find image 'mcr.microsoft.com/dotnet/runtime:6.0' locally
6.0: Pulling from dotnet/runtime
Digest: sha256:c116244e350a7dce037220fc4f84ebf95858a6bbeab94ffad196d0ba00f2ad54
Status: Downloaded newer image for mcr.microsoft.com/dotnet/runtime:6.0
Desired=Unknown/Install/Remove/Purge/Hold
| Status=Not/Inst/Conf-files/Unpacked/halF-conf/Half-inst/trig-aWait/Trig-pend
|/ Err?=(none)/Reinst-required (Status,Err: uppercase=bad)
||/ Name            Version        Architecture Description
+++-===============-==============-============-=======================================
ii  ncurses-base    6.2+20201114-2 all          basic terminal type definitions
ii  ncurses-bin     6.2+20201114-2 amd64        terminal-related programs and man pages
un  ncurses-runtime <none>         <none>       (no description available)

.NET 5 runtime image

leo@DESKTOP-RL4O6SD:~$ docker run mcr.microsoft.com/dotnet/runtime:5.0 dpkg -l '*ncurses*'
Unable to find image 'mcr.microsoft.com/dotnet/runtime:5.0' locally
5.0: Pulling from dotnet/runtime
Digest: sha256:5220716366f9a17eea218e739372ecccdf8c2a35878d405af8a1ba9ac27f6fbf
Status: Downloaded newer image for mcr.microsoft.com/dotnet/runtime:5.0
Desired=Unknown/Install/Remove/Purge/Hold
| Status=Not/Inst/Conf-files/Unpacked/halF-conf/Half-inst/trig-aWait/Trig-pend
|/ Err?=(none)/Reinst-required (Status,Err: uppercase=bad)
||/ Name               Version                Architecture Description
+++-==================-======================-============-===============================================================
ii  libncursesw6:amd64 6.1+20181013-2+deb10u2 amd64        shared libraries for terminal handling (wide character support)
ii  ncurses-base       6.1+20181013-2+deb10u2 all          basic terminal type definitions
ii  ncurses-bin        6.1+20181013-2+deb10u2 amd64        terminal-related programs and man pages
un  ncurses-runtime    <none>                 <none>       (no description available)

@BDisp
Copy link
Collaborator

BDisp commented Nov 18, 2021

In my PR #1515 is using the "mcr.microsoft.com/vscode/devcontainers/dotnet:6.0" and it's working well. Please check.

@BDisp
Copy link
Collaborator

BDisp commented Nov 23, 2021

See discussion in #1519.

@leomoty
Copy link
Author

leomoty commented Nov 23, 2021

Sorry, so, even without setting setting it somewhat worked for me. I think it might have to do with my terminal emulator, I am using a Bitvise SSH terminal, so that might be where my issue arises. Using Windows built in powershell I get mostly a functional container while only changing TERM and making sure either ncurses is available.

So i'll be closing this, it is such an edge case and I got it to be functional enough for now, thanks for your help

@leomoty leomoty closed this as completed Nov 23, 2021
@chr1st0scli
Copy link

Hi.
I am not sure if it's ok to report this here since it's closed.

I am targeting .NET 6. I have the same error when running the container based on Linux.

DockerOnLinux

When the container is based on Windows, there is no problem.

DockerOnWindows

@Nutzzz
Copy link

Nutzzz commented Jun 13, 2023

It'd probably be better to open a new issue and reference this one.

In any case, I've not used this library with Linux much, but to get the discussion going... What version(s) of libncursesw do you have installed?

You might try not using curses, i.e., (from #415 ):

workaround is use the NetDriver by setting the Application.UseSystemConsole = true before call Application.Init().

Note that depending on what you're doing you might find performance may suffer or terminal features may be missing.

@tznind
Copy link
Collaborator

tznind commented Jun 13, 2023

Please also try referencing the v2 pre-release (or run UICatalog on the v2_develop branch).

Quite a bit of work has gone into the console drivers so it may be that this issue is fixed in v2 (at least worth a try).

@chr1st0scli
Copy link

@Nutzzz thank you for pointing out the workaround.

I have decided not to try it because I am not willing to sacrifice performance for something that might work in version 2. I will wait until then and check it again.

For now, I am disabling the terminal gui library altogether when my application runs in a container because
a. as reported here, it does not load if container runs linux.
b. there are other problems like invisible cursor and unclickable menus, when the container runs windows.

:-(

@leomoty
Copy link
Author

leomoty commented Jun 15, 2023

@chr1st0scli I dont believe Docker Desktop has the best terminal interface to evaluate whether it works well or not tho. Try Windows terminal instead, it could be your terminal emulator misbehaving and not necessarily the library.

check some previous discussion I had with @BDisp:

#1519 (comment)

@chr1st0scli
Copy link

@tznind thank you for your hint that version 2 might work.

I am not in the mood to download and compile, so I will wait until a nuget package with version 2, even a pre-release one, becomes available.

I will try it then and come back to you with my findings.

@leomoty
Copy link
Author

leomoty commented Jun 15, 2023

I am of course only talking about (b), not (a) from your points.

@chr1st0scli
Copy link

chr1st0scli commented Jun 15, 2023

@leomoty Yes indeed, running inside docker desktop was weird and had its own issues.

Therefore, I later tried to run the linux container directly from the windows terminal and got the same exception.

image

@Nutzzz
Copy link

Nutzzz commented Jun 15, 2023

I am not in the mood to download and compile, so I will wait until a nuget package with version 2, even a pre-release one, becomes available.

Actually, as of a few days ago you can now use the built packages, just edit your .csproj to something like so:
<PackageReference Include="Terminal.Gui" Version="2.0.0-tags-v2-0-0-alpha-12.1" />

But note there will likely be breaking changes.

@Nutzzz
Copy link

Nutzzz commented Jun 15, 2023

Therefore, I later tried to run the linux container directly from the windows terminal and got the same exception.

You never answered about what version(s) of libncursesw you have installed.

@chr1st0scli
Copy link

You never answered about what version(s) of libncursesw you have installed.

No, because it's not easy for me to answer :-). It's whatever that docker image has by default :-)...

I mean I assumed that since terminal.gui is cross platform, it will easily work in a typical docker container scenario using all the "defaults".
Maybe I my expectations were wrong... Apologies to everyone if I somehow mislead you.

I am suspecting this library is missing. Now I am just guessing here, I issued apt show libncursesw.so.6 and says unable to locate that package. I tried to install it with apt install libncursesw.so.6 and got the same thing.

Don't tell me I have to explicitly add a package source! :-)

So, are we talking about a special procedure that I need to follow if I want to publish a docker image?
I wonder if this is documented somewhere...

@Nutzzz
Copy link

Nutzzz commented Jun 15, 2023

Leave off the .so. For Ubuntu the packages are named libncursesw5 and/or libncursesw6.

Like I said, I've hardly used this library in Linux, and never with a container.

EDIT: I don't know if this helps, but it seems to be discussing exactly your problem.

@chr1st0scli
Copy link

I will have a look at the link you provided.

Just to report on the previous questions... After I installed the library, it loaded alright but it was just a black screen...

As for the other suggestion. I used the package 2.0.0-tags-v2-0-0-alpha-12.1. I had to bump to .net 7 and comment out
a lot of code because there were sadly many breaking changes :-(. Anyway, the same exception occurs and what is worse, I cannot run apt install libncursesw6 as I could with the .net 6 based docker image.

Anyway, I think this is enough... I will consult the link that you provided, it looks promising, thank you.

@BDisp
Copy link
Collaborator

BDisp commented Jun 15, 2023

@chr1st0scli see if this link help you somehow https://github.com/mcraiha/WhisperDragonCLI.
You may need do add ENV TERM=xterm-256color to the dockerfile.

@BDisp
Copy link
Collaborator

BDisp commented Jun 15, 2023

Here the initial discussion #1607.

@chr1st0scli
Copy link

@Nutzzz and @BDisp thank you for your help. I managed to run it successfully.

Based on the info you provided, I made just a few modifications to the default docker file that visual studio produces when you enable docker support and it works fine.

I had to also consult #1815 because I had the same problem with bash. One other difference I encountered, is that I could not publish it as a self contained assembly because it's a tool package.

I can even debug right now, by attaching the debugger to a running container.

One last thing, @BDisp, have you got any idea why one StatusItem key shortcut works and another one doesn't?
This problem only occurs in the container of course. I am confirming by debugging. I wonder if this means that it wouldn't work in a real Linux box either. Maybe I should set up a VM and test it...

This is how they are declared. Ctrl + F4 that quits works, whereas Ctrl + Enter doesn't. Evaluate and Quit are methods and only a breakpoint in the latter can be hit.

            var statusBarItems = new StatusItem[]
            {
                _cursorPosStatusItem,
                new(Key.CtrlMask | Key.Enter, Resources.EVALUATE, Evaluate),
                new(Key.CtrlMask | Key.F4, Resources.QUIT, Quit),
            };

@BDisp
Copy link
Collaborator

BDisp commented Jun 16, 2023

I was trying found the link you provided #1815 and I didn't found. I'll try to check this issue. Do you have your code on a repo where I can more easily test it?

@chr1st0scli
Copy link

Yes, it's this branch. https://github.com/chr1st0scli/RainLispConsole/tree/editor-on-docker

@BDisp
Copy link
Collaborator

BDisp commented Jun 17, 2023

On Linux Ctrl+Enter is not working. Ctrl+Enter generates the exact same sequence in terminal emulators as Enter, so there's no way for an app to distinguish these two. Maybe you can use Ctrl+F5, which is working well.

@BDisp
Copy link
Collaborator

BDisp commented Jun 17, 2023

Now if you mean if you can run or debug by pressing Docker as in the image, you can't. You'll get the same behavior as selecting WSL. They don't open a real console where the app can run normally. You can only debug the initial code but without keyboard input and visualization. If you are interested in this feature you can see this discussion #2594, where there is a link to the Visual Studio developer community where you can vote to add this feature. If you have another friends who also want this you can share with them.

imagem

@chr1st0scli
Copy link

chr1st0scli commented Jun 17, 2023

@BDisp , no I don't mean by pressing F5, the one you show... I have done so by attaching the debugger to an already running container.
https://learn.microsoft.com/en-us/visualstudio/debugger/attach-to-process-running-in-docker-container?view=vs-2022

In other words, I open a "normal" terminal window running in a container which I can interact with. Then I attach the debugger and I can debug normally.

@BDisp
Copy link
Collaborator

BDisp commented Jun 17, 2023

But for sure you cannot run the CodeEditor on a docker container but only on WSL, right?

@chr1st0scli
Copy link

I am sorry, because I am not sure what you are asking, I made this gif that demonstrates. In the end I am showing a docker setting that I suspect you are referring to.

DebugContainer

@BDisp
Copy link
Collaborator

BDisp commented Jun 17, 2023

Ah I'm now see that you are using alpine (which I know it work) but with the original Dockerfile you have in your repo, the CodeEditor doesn't run. Thanks for the fantastic demonstration.

@BDisp
Copy link
Collaborator

BDisp commented Jun 17, 2023

With the original Dockerfile it's possible get it to work with this modification:

#See https://aka.ms/customizecontainer to learn how to customize your debug container and how Visual Studio uses this Dockerfile to build your images for faster debugging.

FROM mcr.microsoft.com/dotnet/runtime:6.0 AS base
RUN apt-get update && apt-get upgrade -y && apt-get install -y ncurses-dev locales && \
	sed -i -e 's/# en_US.UTF-8 UTF-8/en_US.UTF-8 UTF-8/' /etc/locale.gen && \
    dpkg-reconfigure --frontend=noninteractive locales && \
    update-locale LANG=en_US.UTF-8
ENV LANG=en_US.UTF-8 \
	TERM=xterm-256color
WORKDIR /app

FROM mcr.microsoft.com/dotnet/sdk:6.0 AS build
WORKDIR /src
COPY ["RainLispConsole/RainLispConsole.csproj", "RainLispConsole/"]
RUN dotnet restore "RainLispConsole/RainLispConsole.csproj"
COPY . .
WORKDIR "/src/RainLispConsole"
RUN dotnet build "RainLispConsole.csproj" -c Release -o /app/build

FROM build AS publish
RUN dotnet publish "RainLispConsole.csproj" -c Release -o /app/publish /p:UseAppHost=false

FROM base AS final
WORKDIR /app
COPY --from=publish /app/publish .
ENTRYPOINT ["dotnet", "RainLispConsole.dll"]

@BDisp
Copy link
Collaborator

BDisp commented Jun 17, 2023

Now it's needed to provide clipboard to the container. But there will be permission access to handle.

@Aronizgan
Copy link

I had the same error ( running Terminal.Gui based application in Docker) ->Curses failed to initialize, the exception is: System.IO.IOException: Error loading native library "libncursesw.so.6, libncursesw.so.5". Thanks a lot for suggested changes to Dockerfile.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

6 participants