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

MatterControl 2.x for Linux as an AppImage #3536

Open
probonopd opened this issue Jul 16, 2018 · 63 comments
Open

MatterControl 2.x for Linux as an AppImage #3536

probonopd opened this issue Jul 16, 2018 · 63 comments

Comments

@probonopd
Copy link

probonopd commented Jul 16, 2018

MatterControl 2.x for Linux can be built for Linux (I have done it today) but it is rather cumbersome.

Would you be interested in packaging MatterControl 2.x for Linux as an Providing an AppImage?

Doing so would have, among others, these advantages:

  • Applications packaged as an AppImage can run on many distributions (including Ubuntu, Fedora, openSUSE, CentOS, elementaryOS, Linux Mint, and others)
  • One app = one file = super simple for users: just download one AppImage file, make it executable, and run
  • No unpacking or installation necessary
  • No root needed
  • No system libraries changed
  • Works out of the box, no installation of runtimes needed
  • Optional desktop integration with appimaged
  • Optional binary delta updates, e.g., for continuous builds (only download the binary diff) using AppImageUpdate
  • Can optionally GPG2-sign your AppImages (inside the file)
  • Works on Live ISOs
  • Can use the same AppImages when dual-booting multiple distributions
  • Can be listed in the AppImageHub central directory of available AppImages
  • Can double as a self-extracting compressed archive with the --appimage-extract parameter

Especially in the 3D printing world, the format has gained a lot of traction, with most of the important slicers and CAD packages shipping official AppImages of release and pre-release versions:

  • Ultimaker Cura
  • Slic3r
  • Slic3r Prusa Edition
  • PrusaControl
  • FreeCAD
  • OpenSCAD
  • ...

Here is an overview of projects that are already distributing upstream-provided, official AppImages.

I would invest time into making this happen but since my Mono knowledge is rather limited I would do this only if MatterHackers is interested in providing and supporting an official AppImage, and if someone from the MatterControl project would be willing to work with me along the way.

We could set up automated build using Travis CI for each git push.

@jlewin
Copy link
Contributor

jlewin commented Jul 16, 2018

Thanks for the feedback and investigation. We'll look into this and report back

@probonopd
Copy link
Author

probonopd commented Jul 20, 2018

Work has started at https://gitlab.com/probono/MatterControlAppImage but I will likely need some support from the devs.

@probonopd
Copy link
Author

probonopd commented Jul 20, 2018

First build is available at https://gitlab.com/probono/MatterControlAppImage/-/jobs/83329584/artifacts/raw/MatterControl/bin/Release/MatterControl-x86_64.AppImage; it still has an issue though:

me@host:~$ '/home/me/Downloads/MatterControl-x86_64.AppImage'

Unhandled Exception:
System.ArgumentException: path string must not be an empty string or whitespace string
  at System.IO.Directory.SetCurrentDirectory (System.String path) [0x0001b] in <71d8ad678db34313b7f718a414dfcb25>:0 
  at MatterHackers.MatterControl.Program.Main () [0x00073] in <5e385a10cb1d44d8b2f642c1871d093e>:0 
[ERROR] FATAL UNHANDLED EXCEPTION: System.ArgumentException: path string must not be an empty string or whitespace string
  at System.IO.Directory.SetCurrentDirectory (System.String path) [0x0001b] in <71d8ad678db34313b7f718a414dfcb25>:0 
  at MatterHackers.MatterControl.Program.Main () [0x00073] in <5e385a10cb1d44d8b2f642c1871d093e>:0 

You can inspect the file's contents by running ./MatterControl-x86_64.AppImage --appimage-extract.

Can you tell what is going on here?

This is the file that was used to produce it:
https://gitlab.com/probono/MatterControlAppImage/blob/master/.gitlab-ci.yml

@unlimitedbacon
Copy link
Contributor

I think this is where the problem is happening.

Directory.SetCurrentDirectory(Path.GetDirectoryName(System.Reflection.Assembly.GetEntryAssembly().Location));

MatterControl tries to find the location of it's executable and loads resources from the same directory. I don't know much about how AppImages work, but I'm guessing that while it's running inside of one it cannot get a valid path.

@probonopd
Copy link
Author

Excellent, that must be it. I am using mkbundle from Mono. Unfortunately I don't know how its inner workings are but seemingly it gets this part wrong. Can I turn on some debugging mode to see which path it is trying to access?

@probonopd
Copy link
Author

probonopd commented Jul 20, 2018

I think the code you posted above may break when used with mkbundle. This is what I found out from http://lists.dot.net/pipermail/mono-devel-list/2017-May/044329.html:

#
# Make a small test program
#

cat > assytest.cs <<\EOF
using System.Reflection;
using System.Text;
using Mono.Unix.Native;

public class Test
{
    public static void Main()
    {
        Assembly thisassy = Assembly.GetEntryAssembly();
        System.Console.WriteLine("Assembly Type: " + thisassy.GetType());
        System.Console.WriteLine(" CodeBase: " + thisassy.CodeBase);
        System.Console.WriteLine(" FullName: " + thisassy.FullName);
        System.Console.WriteLine(" Location: " + thisassy.Location);
        var builder = new StringBuilder(1024);
        Syscall.readlink("/proc/self/exe", builder);
        System.Console.WriteLine("BundleEnvironment: " +
builder.ToString());
    }
}
EOF

#
# Compile the test program and inspect its output
#

mcs -r /usr/lib/mono/4.5/Mono.Posix.dll assytest.cs

./assytest.exe 

Assembly Type: System.Reflection.MonoAssembly
 CodeBase: file:///home/me/assytest.exe
 FullName: assytest, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null
 Location: /home/me/assytest.exe
BundleEnvironment: /usr/bin/mono-sgen

#
# Run the test program through mkbundle and inspect its output again
#

/usr/lib/mono/4.5/mkbundle.exe  ./assytest.exe --deps -L  /usr/lib/mono/4.5/ -o assytest

./assytest
Assembly Type: System.Reflection.MonoAssembly
 CodeBase: file:///home/me/assytest.exe
 FullName: assytest, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null
 Location: assytest.exe
BundleEnvironment: /home/me/assytest

So, Assembly.GetEntryAssembly().CodeBase seems to be consistent throughout the original and the bundled version.

@probonopd
Copy link
Author

probonopd commented Jul 20, 2018

@probonopd
Copy link
Author

Running /usr/lib/mono/4.5/mkbundle.exe MatterControl.exe --deps -L /usr/lib/mono/4.5/ -L /usr/lib/mono/4.5/Facades/ -L /usr/lib/mono/4.5-api/ -o MatterControl breaks the path finding. I haven't found the solution yet, partially because I have never ever worked with Mono. @unlimitedbacon can you have a look please?

@probonopd
Copy link
Author

probonopd commented Jul 21, 2018

In the meantime I have simply commented out the line

Directory.SetCurrentDirectory(Path.GetDirectoryName(System.Reflection.Assembly.GetEntryAssembly().Location));
and compiled on Ubuntu 14.04 like this:

#!/bin/bash

# Run this on the oldest still-supported distribution,
# e.g., a Docker container with Ubuntu 14.04

sudo apt-get update
sudo apt-get install -y apt-transport-https ca-certificates git wget
sudo apt-key adv --keyserver hkp://keyserver.ubuntu.com:80 --recv-keys 3FA7E0328081BFF6A14DA29AA6A19B38D3D831EF
echo "deb https://download.mono-project.com/repo/ubuntu stable-trusty main" | sudo tee /etc/apt/sources.list.d/mono-official-stable.list
sudo apt-get update
sudo apt-get -y install mono-complete nuget gcc
git clone --recursive https://github.com/MatterHackers/MatterControl.git
cd MatterControl/
nuget restore MatterControl.sln
sed -i -e 's|Directory.SetCurrentDirectory|// Directory.SetCurrentDirectory|g' Program.cs # https://github.com/MatterHackers/MatterControl/issues/3536#issuecomment-406704443
xbuild /p:Configuration=Release MatterControl.sln
cd ./bin/Release/
cp -r ../../StaticData/ .
/usr/lib/mono/4.5/mkbundle.exe MatterSlice.exe --deps -L  /usr/lib/mono/4.5/ -o MatterSlice
cp MatterSlice.exe MatterSlice.dll # FIXME
/usr/lib/mono/4.5/mkbundle.exe MatterControl.exe --deps -L  /usr/lib/mono/4.5/ -L /usr/lib/mono/4.5/Facades/ -L /usr/lib/mono/4.5-api/ -o MatterControl
mkdir -p appdir/usr/bin ; mv MatterSlice MatterControl StaticData appdir/usr/bin

Now I need to keep StaticData/ in my current working directory, but at least I can launch the application for now.

However, I get when launching the MatterControl executable:

me@host:~/MatterControl/bin/Release/appdir/usr/bin$ ./MatterControl 
Time to '': 1192
Time to 'ShowAsSystemWindow': 167
Time to 'First draw->RunOnIdle': 0
Time to 'MatterControlApplication.Initialize': 0
Time to 'PlatformInit': 0
# ...hangs here....

fail

Startup failure:
The type initializer for 'MatterHackers.Agg.PluginFinder' threw an execption.

How would I debug this? Is it trying to load resources from somewhere else in addition to the StaticData or Library directories?

Whereas the MatterControl.exe assembly works like this:

me@host:~/MatterControl/bin/Release$ cp -r ../../StaticData/ .
me@host:~/MatterControl/bin/Release$ mono MatterControl.exe
Time to '': 1190
Time to 'ShowAsSystemWindow': 166
Time to 'First draw->RunOnIdle': 0
Time to 'MatterControlApplication.Initialize': 0
Time to 'PlatformInit': 0
Time to 'ApplicationController': 185
Time to 'ProfileManager': 9
Time to 'MainView': 0
Time to 'Plugins': 0
Time to 'Process Commandline': 0
Time to 'OnLoadActions': 50
Time to 'AddChild->MainView': 281

and properly shows the Setup Wizard and application GUI.

ok

It seems to load bin/Release/MatterHackers.MatterControl.Plugins.dll which of course is not available in the version that was run through mkbundle.exe to produce the MatterControl executable.

@unlimitedbacon
Copy link
Contributor

I think you are on the right track. I know MatterControl loads a number of DLLs from the Release folder during startup. Sorry, I don't know enough about the startup process to help you further.

@probonopd
Copy link
Author

mkbundle.exe normally compiles those "dll" assemblies into the main executable. Are you doing anything special with regard to "dll" loading?

@jlewin
Copy link
Contributor

jlewin commented Jul 23, 2018

We are. You can find the code in PluginFinder.cs, LoadAssembliesFromFileSystem Line #20, where we load and iterate all assemblies in the bin folder looking for plugins. If I was to guess, it seems likely that the call to GetExecutingAssembly runs into the same issue that you resolved last week. I believe both cases were put in place to work around problems on Mac where the exe in the AppBundle is in a different physical location than the product assemblies.

@jlewin
Copy link
Contributor

jlewin commented Jul 23, 2018

You could try the following patch to see if it resolves the issue:
patch.zip

@probonopd
Copy link
Author

Thanks. How do I apply this? -p 0 or -p 1 and in which subdirectory?

@jlewin
Copy link
Contributor

jlewin commented Jul 23, 2018

I usually use git to apply. On my machine git apply patch.diff from root of the agg project works as expected.

@jlewin
Copy link
Contributor

jlewin commented Jul 23, 2018

Which would be MatterControl/Submodules/agg-sharp

@probonopd
Copy link
Author

probonopd commented Jul 24, 2018

Where can I see how you are creating the Mac .app bundle?

Currently getting

me@host:~$ Downloads/MatterControl-x86_64.AppImage 
System.TypeInitializationException trying to get all screens: The type initializer for 'System.Windows.Forms.XplatUI' threw an exception.

Unhandled Exception:
System.Reflection.TargetInvocationException: Exception has been thrown by the target of an invocation. ---> System.TypeInitializationException: The type initializer for 'System.Windows.Forms.Screen' threw an exception. ---> System.TypeInitializationException: The type initializer for 'System.Windows.Forms.XplatUI' threw an exception. ---> System.DllNotFoundException: libc
  at (wrapper managed-to-native) System.Windows.Forms.XplatUI.uname(intptr)
  at System.Windows.Forms.XplatUI..cctor () [0x00034] in <33c9ef2431ee44bfb02f81d92160d180>:0 
   --- End of inner exception stack trace ---
  at System.Windows.Forms.Screen..cctor () [0x00034] in <33c9ef2431ee44bfb02f81d92160d180>:0 
   --- End of inner exception stack trace ---
  at MatterHackers.Agg.Platform.WinformsInformationProvider..ctor () [0x00012] in <d112f1e2da3e4759960d7840eac60f58>:0 
  at (wrapper managed-to-native) System.Reflection.MonoCMethod.InternalInvoke(System.Reflection.MonoCMethod,object,object[],System.Exception&)
  at System.Reflection.MonoCMethod.InternalInvoke (System.Object obj, System.Object[] parameters) [0x00002] in <71d8ad678db34313b7f718a414dfcb25>:0 
   --- End of inner exception stack trace ---
  at System.Reflection.MonoCMethod.InternalInvoke (System.Object obj, System.Object[] parameters) [0x00014] in <71d8ad678db34313b7f718a414dfcb25>:0 
  at System.RuntimeType.CreateInstanceMono (System.Boolean nonPublic) [0x000a8] in <71d8ad678db34313b7f718a414dfcb25>:0 
  at System.RuntimeType.CreateInstanceSlow (System.Boolean publicOnly, System.Boolean skipCheckThis, System.Boolean fillCache, System.Threading.StackCrawlMark& stackMark) [0x00009] in <71d8ad678db34313b7f718a414dfcb25>:0 
  at System.RuntimeType.CreateInstanceDefaultCtor (System.Boolean publicOnly, System.Boolean skipCheckThis, System.Boolean fillCache, System.Threading.StackCrawlMark& stackMark) [0x00027] in <71d8ad678db34313b7f718a414dfcb25>:0 
  at System.Activator.CreateInstance (System.Type type, System.Boolean nonPublic) [0x00020] in <71d8ad678db34313b7f718a414dfcb25>:0 
  at System.Activator.CreateInstance (System.Type type) [0x00000] in <71d8ad678db34313b7f718a414dfcb25>:0 
  at MatterHackers.Agg.Platform.AggContext.CreateInstanceFrom[T] (System.String typeString) [0x00010] in <179418f207c74efab0dd3c3c06d2f2a5>:0 
  at MatterHackers.Agg.Platform.AggContext.get_OsInformation () [0x00016] in <179418f207c74efab0dd3c3c06d2f2a5>:0 
  at MatterHackers.Agg.Platform.AggContext.get_OperatingSystem () [0x00000] in <179418f207c74efab0dd3c3c06d2f2a5>:0 
  at MatterHackers.MatterControl.Program.Main () [0x00032] in <7e873c8a0bf9412db7d16d93ce942e65>:0 
[ERROR] FATAL UNHANDLED EXCEPTION: System.Reflection.TargetInvocationException: Exception has been thrown by the target of an invocation. ---> System.TypeInitializationException: The type initializer for 'System.Windows.Forms.Screen' threw an exception. ---> System.TypeInitializationException: The type initializer for 'System.Windows.Forms.XplatUI' threw an exception. ---> System.DllNotFoundException: libc
  at (wrapper managed-to-native) System.Windows.Forms.XplatUI.uname(intptr)
  at System.Windows.Forms.XplatUI..cctor () [0x00034] in <33c9ef2431ee44bfb02f81d92160d180>:0 
   --- End of inner exception stack trace ---
  at System.Windows.Forms.Screen..cctor () [0x00034] in <33c9ef2431ee44bfb02f81d92160d180>:0 
   --- End of inner exception stack trace ---
  at MatterHackers.Agg.Platform.WinformsInformationProvider..ctor () [0x00012] in <d112f1e2da3e4759960d7840eac60f58>:0 
  at (wrapper managed-to-native) System.Reflection.MonoCMethod.InternalInvoke(System.Reflection.MonoCMethod,object,object[],System.Exception&)
  at System.Reflection.MonoCMethod.InternalInvoke (System.Object obj, System.Object[] parameters) [0x00002] in <71d8ad678db34313b7f718a414dfcb25>:0 
   --- End of inner exception stack trace ---
  at System.Reflection.MonoCMethod.InternalInvoke (System.Object obj, System.Object[] parameters) [0x00014] in <71d8ad678db34313b7f718a414dfcb25>:0 
  at System.RuntimeType.CreateInstanceMono (System.Boolean nonPublic) [0x000a8] in <71d8ad678db34313b7f718a414dfcb25>:0 
  at System.RuntimeType.CreateInstanceSlow (System.Boolean publicOnly, System.Boolean skipCheckThis, System.Boolean fillCache, System.Threading.StackCrawlMark& stackMark) [0x00009] in <71d8ad678db34313b7f718a414dfcb25>:0 
  at System.RuntimeType.CreateInstanceDefaultCtor (System.Boolean publicOnly, System.Boolean skipCheckThis, System.Boolean fillCache, System.Threading.StackCrawlMark& stackMark) [0x00027] in <71d8ad678db34313b7f718a414dfcb25>:0 
  at System.Activator.CreateInstance (System.Type type, System.Boolean nonPublic) [0x00020] in <71d8ad678db34313b7f718a414dfcb25>:0 
  at System.Activator.CreateInstance (System.Type type) [0x00000] in <71d8ad678db34313b7f718a414dfcb25>:0 
  at MatterHackers.Agg.Platform.AggContext.CreateInstanceFrom[T] (System.String typeString) [0x00010] in <179418f207c74efab0dd3c3c06d2f2a5>:0 
  at MatterHackers.Agg.Platform.AggContext.get_OsInformation () [0x00016] in <179418f207c74efab0dd3c3c06d2f2a5>:0 
  at MatterHackers.Agg.Platform.AggContext.get_OperatingSystem () [0x00000] in <179418f207c74efab0dd3c3c06d2f2a5>:0 
  at MatterHackers.MatterControl.Program.Main () [0x00032] in <7e873c8a0bf9412db7d16d93ce942e65>:0 

@jlewin
Copy link
Contributor

jlewin commented Jul 24, 2018

The Mac project would be even more confusing as it's essentially a wrapper around the normal solution which produces an exe with Xamarin.Mac bindings.

Since your call stack suggests issues with libc/uname when running under the bundle, I'd try a less generic version of the OsInformationProvider to see if you can continue progressing forward. If it was me I'd replace the current WinformsInformationProvider with something like the following:

using Microsoft.VisualBasic.Devices;
using System;
using System.IO;

namespace MatterHackers.Agg.Platform
{
	public class WinformsInformationProvider : IOsInformationProvider
	{
		public WinformsInformationProvider()
		{
			this.OperatingSystem = OSType.X11;

			var size = System.Windows.Forms.Screen.PrimaryScreen.WorkingArea.Size;
			this.DesktopSize = new Point2D(size.Width, size.Height);
		}

		public OSType OperatingSystem { get; }

		public Point2D DesktopSize { get; }

		public long PhysicalMemory
		{
			get
			{
				var computerInfo = new ComputerInfo();
				return (long)computerInfo.TotalPhysicalMemory;
			}
		}
	}
}

@jlewin
Copy link
Contributor

jlewin commented Jul 24, 2018

Also, rather than apply modifications to the source as ad-hoc steps in the yml file, might it be easier to build off of a named branch that tracks progress of this task? If you were building off of said branch, I could have thrown in the above troubleshooting step in response to your feedback and just kicked off another build for evaluation, without as much manual effort on your end.

@probonopd
Copy link
Author

Also, rather than apply modifications to the source as ad-hoc steps in the yml file, might it be easier to build off of a named branch that tracks progress of this task?

Please let me know the name of such a branch, then I can set it up accordingly. Thanks!

@jlewin
Copy link
Contributor

jlewin commented Jul 25, 2018

I forked your project and have been working through various issues trying to get to a point where I could reference something. I don't believe I'll have anything today but I'll likely have some additional questions tomorrow.

@jlewin
Copy link
Contributor

jlewin commented Jul 25, 2018

With a few caveats, I finally got a version of MatterControl to load via the generated AppImage. The icons aren't right and it wouldn't load until I put a local copy of the StaticData directory sitting next to the .AppImage file, but it's a start

You can see the artifact and revised .yml file at:
https://gitlab.com/lewin76/MatterControlAppImage/-/jobs/84127559

At first glance I believe whatever originally caused .Net to return the wrong paths on the GetExecutingAssembly calls is also causing .Net file system calls to escape the sandbox and get back to the normal filesystem. I'll keep investigating to make sure we're not doing anything funny, but baring that, is there anything special that might be required for .Net to see the packaged StaticData folder?

@probonopd
Copy link
Author

probonopd commented Jul 25, 2018

That's great progress. Thank you.

is there anything special that might be required for .Net to see the packaged StaticData folder?

You need to load it from a location that you construct from the location of the running executable itself. For now I had just commented out the line that changes the current working directory because due to my lack of .net knowledge I did not really know what I was doing there.

Pseudo-code: Instead of open("./StaticData/some.thing"); do something like

location = Path.GetDirectoryName(System.Reflection.Assembly.GetExecutingAssembly().Location);
open(location + "StaticData/some.thing");

I think GetExecutingAssembly needs to be used to construct the path, and changing directories should be avoided. Rather, the resources should be loaded from a path constcuted from GetExecutingAssembly.

@jlewin
Copy link
Contributor

jlewin commented Jul 25, 2018

I can set about concatenating the current exe path with the relative paths previously used by the application but it feels like a step backwards. When we're run from any normal shell (Explorer, bash, Nautilus, Finder, etc..), the working directory is effectively the startup directory. The proposed workaround seems to be based on the premise that my application can no longer use relative paths from the working directory and must use absolute paths everywhere. That seems like a bit of a failure of AppImage to not match behavior that's consistent everywhere else and instead force a change in our application. Am I just thinking about this wrong?

@jlewin
Copy link
Contributor

jlewin commented Jul 25, 2018

This might actually be more of an mkbundle issue, still researching and trying to understand.

My main concern is if I drop support for relative paths and convert to computed absolute paths, I just have to do it everywhere. There's probably only a couple of places where we load content using relative paths but it's hard to know for sure and it's likely to break until they are all tracked down and updated.

@jlewin
Copy link
Contributor

jlewin commented Jul 25, 2018

Realizing this was all discussed above, definitely should have tried using .CodeBase as suggested. Will work on some revisions and see how they perform

@probonopd
Copy link
Author

probonopd commented Jul 25, 2018

I can set about concatenating the current exe path with the relative paths previously used by the application but it feels like a step backwards.

I think it is no problem to keep the change directory if you would like to continue using that logic, it just doesn't feel very clean to me but maybe it's a matter of personal preference.

My main concern is if I drop support for relative paths and convert to computed absolute paths, I just have to do it everywhere.

Understand.

The only thing is that you need to change directory not to System.Reflection.Assembly.GetEntryAssembly().Location but to GetExecutingAssembly (I think), because the "entry assembly" points to the the wrong place. (Some experimentation may be needed.)

Alternatively we could have a small AppRun bash script inside the AppImage that can set and export paths, change to a certain directory etc. before launching the payload application. Let me know if you would use this route.

@unlimitedbacon
Copy link
Contributor

We already use a small launching script in the Debian package. This is /usr/bin/mattercontrol;

#!/bin/sh
cd /usr/lib/mattercontrol/
MONO_IOMAP=case exec mono /usr/lib/mattercontrol/MatterControl.exe $@

@jlewin
Copy link
Contributor

jlewin commented Jul 25, 2018

The reason for GetEntryAssembly versus GetExecutingAssembly I believe goes back to quirks on Mac where MatterControl is not the startup process and GetExecutingAssembly either had the wrong path or had null values in some contexts. At a glance I don't see details backing up that claim but I seem to recall working around problems in some platforms by switching away from GetExecutingAssembly. Continuing to test and troubleshoot...

@probonopd
Copy link
Author

probonopd commented Jul 27, 2018

Launch failure if .Net is not installed

This, of course, is a major issue. The AppImage is supposed to run without the need of mono-core to be installed.

mono/mono#6187- mkbundle Linux - program doesn't run on system unless mono-core is installed

Are you sure that this really the same issue? I suspect more that the plugins that are getting loaded from .dll files are not taken into account then mkbundle.exe calculates (and embeds) dependencies into the main binary.

Maybe we need to instruct it to process all *.dll files in the directory like mentioned in https://stackoverflow.com/a/27536070?

me@host:~$ wget https://gitlab.com/lewin76/MatterControlAppImage/-/jobs/84690721/artifacts/raw/MatterControl/bin/Release/MatterControl-x86_64.AppImage
me@host:~$ chmod +x MatterControl-x86_64.AppImage 
me@host:~$ ./MatterControl-x86_64.AppImage 
System.TypeInitializationException trying to get all screens: The type initializer for 'System.Windows.Forms.XplatUI' threw an exception.

Unhandled Exception:
System.Reflection.TargetInvocationException: Exception has been thrown by the target of an invocation. ---> System.TypeInitializationException: The type initializer for 'System.Windows.Forms.Screen' threw an exception. ---> System.TypeInitializationException: The type initializer for 'System.Windows.Forms.XplatUI' threw an exception. ---> System.TypeInitializationException: The type initializer for 'System.Drawing.GDIPlus' threw an exception. ---> System.DllNotFoundException: libgdiplus.so.0
  at (wrapper managed-to-native) System.Drawing.GDIPlus.GdiplusStartup(ulong&,System.Drawing.GdiplusStartupInput&,System.Drawing.GdiplusStartupOutput&)
  at System.Drawing.GDIPlus..cctor () [0x000b0] in <b8b6ffaf51344842a77744e1fb2e4390>:0 
   --- End of inner exception stack trace ---
  at (wrapper managed-to-native) System.Object.__icall_wrapper_mono_generic_class_init(intptr)
  at System.Drawing.Graphics.FromHdcInternal (System.IntPtr hdc) [0x00000] in <b8b6ffaf51344842a77744e1fb2e4390>:0 
  at System.Windows.Forms.XplatUIX11.SetDisplay (System.IntPtr display_handle) [0x00073] in <69b1a555258c430e86ee1f3ef27d8ea6>:0 
  at System.Windows.Forms.XplatUIX11..ctor () [0x00077] in <69b1a555258c430e86ee1f3ef27d8ea6>:0 
  at System.Windows.Forms.XplatUIX11.GetInstance () [0x00019] in <69b1a555258c430e86ee1f3ef27d8ea6>:0 
  at System.Windows.Forms.XplatUI..cctor () [0x00066] in <69b1a555258c430e86ee1f3ef27d8ea6>:0 
   --- End of inner exception stack trace ---
  at System.Windows.Forms.Screen..cctor () [0x00034] in <69b1a555258c430e86ee1f3ef27d8ea6>:0 
   --- End of inner exception stack trace ---
  at MatterHackers.Agg.Platform.WinformsInformationProvider..ctor () [0x0000d] in <5ca4ce1190ec4f8eab82b26aa14f1bc2>:0 
  at (wrapper managed-to-native) System.Reflection.MonoCMethod.InternalInvoke(System.Reflection.MonoCMethod,object,object[],System.Exception&)
  at System.Reflection.MonoCMethod.InternalInvoke (System.Object obj, System.Object[] parameters) [0x00002] in <b0e1ad7573a24fd5a9f2af9595e677e7>:0 
   --- End of inner exception stack trace ---
  at System.Reflection.MonoCMethod.InternalInvoke (System.Object obj, System.Object[] parameters) [0x00014] in <b0e1ad7573a24fd5a9f2af9595e677e7>:0 
  at System.RuntimeType.CreateInstanceMono (System.Boolean nonPublic) [0x000a8] in <b0e1ad7573a24fd5a9f2af9595e677e7>:0 
  at System.RuntimeType.CreateInstanceSlow (System.Boolean publicOnly, System.Boolean skipCheckThis, System.Boolean fillCache, System.Threading.StackCrawlMark& stackMark) [0x00009] in <b0e1ad7573a24fd5a9f2af9595e677e7>:0 
  at System.RuntimeType.CreateInstanceDefaultCtor (System.Boolean publicOnly, System.Boolean skipCheckThis, System.Boolean fillCache, System.Threading.StackCrawlMark& stackMark) [0x00027] in <b0e1ad7573a24fd5a9f2af9595e677e7>:0 
  at System.Activator.CreateInstance (System.Type type, System.Boolean nonPublic) [0x00020] in <b0e1ad7573a24fd5a9f2af9595e677e7>:0 
  at System.Activator.CreateInstance (System.Type type) [0x00000] in <b0e1ad7573a24fd5a9f2af9595e677e7>:0 
  at MatterHackers.Agg.Platform.AggContext.CreateInstanceFrom[T] (System.String typeString) [0x00010] in <e83e5811429c49dbbb5c700ae287cbd7>:0 
  at MatterHackers.Agg.Platform.AggContext.get_OsInformation () [0x00016] in <e83e5811429c49dbbb5c700ae287cbd7>:0 
  at MatterHackers.Agg.Platform.AggContext.get_OperatingSystem () [0x00000] in <e83e5811429c49dbbb5c700ae287cbd7>:0 
  at MatterHackers.MatterControl.Program.Main () [0x00032] in <9ef3c78f48084576b544ec75c3c1e46d>:0 
[ERROR] FATAL UNHANDLED EXCEPTION: System.Reflection.TargetInvocationException: Exception has been thrown by the target of an invocation. ---> System.TypeInitializationException: The type initializer for 'System.Windows.Forms.Screen' threw an exception. ---> System.TypeInitializationException: The type initializer for 'System.Windows.Forms.XplatUI' threw an exception. ---> System.TypeInitializationException: The type initializer for 'System.Drawing.GDIPlus' threw an exception. ---> System.DllNotFoundException: libgdiplus.so.0
  at (wrapper managed-to-native) System.Drawing.GDIPlus.GdiplusStartup(ulong&,System.Drawing.GdiplusStartupInput&,System.Drawing.GdiplusStartupOutput&)
  at System.Drawing.GDIPlus..cctor () [0x000b0] in <b8b6ffaf51344842a77744e1fb2e4390>:0 
   --- End of inner exception stack trace ---
  at (wrapper managed-to-native) System.Object.__icall_wrapper_mono_generic_class_init(intptr)
  at System.Drawing.Graphics.FromHdcInternal (System.IntPtr hdc) [0x00000] in <b8b6ffaf51344842a77744e1fb2e4390>:0 
  at System.Windows.Forms.XplatUIX11.SetDisplay (System.IntPtr display_handle) [0x00073] in <69b1a555258c430e86ee1f3ef27d8ea6>:0 
  at System.Windows.Forms.XplatUIX11..ctor () [0x00077] in <69b1a555258c430e86ee1f3ef27d8ea6>:0 
  at System.Windows.Forms.XplatUIX11.GetInstance () [0x00019] in <69b1a555258c430e86ee1f3ef27d8ea6>:0 
  at System.Windows.Forms.XplatUI..cctor () [0x00066] in <69b1a555258c430e86ee1f3ef27d8ea6>:0 
   --- End of inner exception stack trace ---
  at System.Windows.Forms.Screen..cctor () [0x00034] in <69b1a555258c430e86ee1f3ef27d8ea6>:0 
   --- End of inner exception stack trace ---
  at MatterHackers.Agg.Platform.WinformsInformationProvider..ctor () [0x0000d] in <5ca4ce1190ec4f8eab82b26aa14f1bc2>:0 
  at (wrapper managed-to-native) System.Reflection.MonoCMethod.InternalInvoke(System.Reflection.MonoCMethod,object,object[],System.Exception&)
  at System.Reflection.MonoCMethod.InternalInvoke (System.Object obj, System.Object[] parameters) [0x00002] in <b0e1ad7573a24fd5a9f2af9595e677e7>:0 
   --- End of inner exception stack trace ---
  at System.Reflection.MonoCMethod.InternalInvoke (System.Object obj, System.Object[] parameters) [0x00014] in <b0e1ad7573a24fd5a9f2af9595e677e7>:0 
  at System.RuntimeType.CreateInstanceMono (System.Boolean nonPublic) [0x000a8] in <b0e1ad7573a24fd5a9f2af9595e677e7>:0 
  at System.RuntimeType.CreateInstanceSlow (System.Boolean publicOnly, System.Boolean skipCheckThis, System.Boolean fillCache, System.Threading.StackCrawlMark& stackMark) [0x00009] in <b0e1ad7573a24fd5a9f2af9595e677e7>:0 
  at System.RuntimeType.CreateInstanceDefaultCtor (System.Boolean publicOnly, System.Boolean skipCheckThis, System.Boolean fillCache, System.Threading.StackCrawlMark& stackMark) [0x00027] in <b0e1ad7573a24fd5a9f2af9595e677e7>:0 
  at System.Activator.CreateInstance (System.Type type, System.Boolean nonPublic) [0x00020] in <b0e1ad7573a24fd5a9f2af9595e677e7>:0 
  at System.Activator.CreateInstance (System.Type type) [0x00000] in <b0e1ad7573a24fd5a9f2af9595e677e7>:0 
  at MatterHackers.Agg.Platform.AggContext.CreateInstanceFrom[T] (System.String typeString) [0x00010] in <e83e5811429c49dbbb5c700ae287cbd7>:0 
  at MatterHackers.Agg.Platform.AggContext.get_OsInformation () [0x00016] in <e83e5811429c49dbbb5c700ae287cbd7>:0 
  at MatterHackers.Agg.Platform.AggContext.get_OperatingSystem () [0x00000] in <e83e5811429c49dbbb5c700ae287cbd7>:0 
  at MatterHackers.MatterControl.Program.Main () [0x00032] in <9ef3c78f48084576b544ec75c3c1e46d>:0 ```

@probonopd
Copy link
Author

probonopd commented Jul 27, 2018

Need to update internal build scripts to participate with gitlab packaging or port to gitlab completely

I just used GitLab as a matter of personal preference; it should be possible to achieve the same result by using Travis CI with GitHub. Let me know if I should do the conversion.

Need to package port workarounds for 250000 baud (libSetSerial.so - https://github.com/MatterHackers/MatterControl/blob/master/MatterControl.Printing/SerialHelper/build.sh)

It should be easy to bundle a private .so library.

Research if dlls copied to usr/bin are redundant - expect mkbundle --deps to pull in what's required as part of the MatterControl bundle

I assumed those are plugins loaded by the application at runtime, am I wrong? If no, they may be not needed after all...

@probonopd
Copy link
Author

Maybe we are now at a point where we need someone with intimate Mono knowledge like @directhex to look into why mkbundle.exe is failing us here...

@directhex
Copy link

--library /usr/lib/libgdiplus.so.0 to bundle that C lib?

@jlewin
Copy link
Contributor

jlewin commented Jul 27, 2018

Launch failure if .Net is not installed

This looks like a straight-forward occurrence of mono/mono#6187 - same complications with libc as detailed in that issue. I just haven't had any time yet to sort out how to pass the correct mkbundle parameters for this case and it didn't work the first few attempts I made.

As far as plugins go, they likely will need to be considered by mkbundle to package their dependencies but that's a later stage issue, once some actually get added to the packaging process.

@directhex - in mono/mono#6187 you guys discuss this problem and appear to suggest the solution is to pass --config and --machine-config params to mkbundle to resolve. I'll try the suggestion though, thx

@jlewin
Copy link
Contributor

jlewin commented Jul 27, 2018

@probonopd - no need to switch to Travis; using GitLab has been a great experience. We currently use AppVeyor, Travis with GitHub but I'm impressed with GitLab and appreciate working with and learning a new set of tools

@probonopd
Copy link
Author

probonopd commented Jul 27, 2018

Getting segfaults on https://gitlab.com/probono/MatterControlAppImage/commits/master 790accc0 and 2fd59d2b. Not on 7f61806a but there libgdiplus.so.0 is missing.

Perhaps we need to bundle this .so and its "unusal" dependencies in the AppImage?
When I do this, I get a little bit further:

export LD_LIBRARY_PATH='/home/me/Downloads/libgdiplus_2.11+git20131008.9732566-5ubuntu1_amd64/usr/lib'

 LD_DEBUG=libs '/home/me/Downloads/MatterControl-x86_64(3).AppImage'

(...)

      6682:	find library=libMonoSupportW.so [0]; searching
      6682:	 search path=/home/me/Downloads/libgdiplus_2.11+git20131008.9732566-5ubuntu1_amd64/usr/lib		(LD_LIBRARY_PATH)
      6682:	  trying file=/home/me/Downloads/libgdiplus_2.11+git20131008.9732566-5ubuntu1_amd64/usr/lib/libMonoSupportW.so
      6682:	 search path=/tmp/.mount_MatterwtExrK/usr/bin/../lib		(RUNPATH from file /tmp/.mount_MatterwtExrK/usr/bin/MatterControl)
      6682:	  trying file=/tmp/.mount_MatterwtExrK/usr/bin/../lib/libMonoSupportW.so
      6682:	 search cache=/etc/ld.so.cache
      6682:	 search path=/lib/x86_64-linux-gnu:/usr/lib/x86_64-linux-gnu:/lib:/usr/lib		(system search path)
      6682:	  trying file=/lib/x86_64-linux-gnu/libMonoSupportW.so
      6682:	  trying file=/usr/lib/x86_64-linux-gnu/libMonoSupportW.so
      6682:	  trying file=/lib/libMonoSupportW.so
      6682:	  trying file=/usr/lib/libMonoSupportW.so
      6682:	
      6682:	/home/me/Downloads/libgdiplus_2.11+git20131008.9732566-5ubuntu1_amd64/usr/lib/libgdiplus.so.0: error: symbol lookup error: undefined symbol: DeleteObject (fatal)
      6682:	/home/me/Downloads/libgdiplus_2.11+git20131008.9732566-5ubuntu1_amd64/usr/lib/libgdiplus.so.0: error: symbol lookup error: undefined symbol: DeleteObject (fatal)
      6682:	/home/me/Downloads/libgdiplus_2.11+git20131008.9732566-5ubuntu1_amd64/usr/lib/libgdiplus.so.0: error: symbol lookup error: undefined symbol: DeleteObjectA (fatal)
      6682:	/home/me/Downloads/libgdiplus_2.11+git20131008.9732566-5ubuntu1_amd64/usr/lib/libgdiplus.so.0: error: symbol lookup error: undefined symbol: DeleteObjectA (fatal)
exception inside UnhandledException handler: Could not load file or assembly 'Microsoft.VisualBasic, Version=10.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a' or one of its dependencies.

[ERROR] FATAL UNHANDLED EXCEPTION: System.TypeInitializationException: The type initializer for 'Mono.Unix.Native.Syscall' threw an exception. ---> System.DllNotFoundException: /libMonoPosixHelper.so
  at (wrapper managed-to-native) Mono.Unix.Native.Syscall.get_at_fdcwd()
  at Mono.Unix.Native.Syscall..cctor () [0x0000a] in <b85cda8056b64ede80089abcb7802705>:0 
   --- End of inner exception stack trace ---
  at System.Windows.Forms.XplatUIX11.UpdateMessageQueue (System.Windows.Forms.XEventQueue queue, System.Boolean allowIdle) [0x000f2] in <69b1a555258c430e86ee1f3ef27d8ea6>:0 
  at System.Windows.Forms.XplatUIX11.UpdateMessageQueue (System.Windows.Forms.XEventQueue queue) [0x00000] in <69b1a555258c430e86ee1f3ef27d8ea6>:0 
  at System.Windows.Forms.XplatUIX11.GetMessage (System.Object queue_id, System.Windows.Forms.MSG& msg, System.IntPtr handle, System.Int32 wFilterMin, System.Int32 wFilterMax) [0x0001c] in <69b1a555258c430e86ee1f3ef27d8ea6>:0 
  at System.Windows.Forms.XplatUI.GetMessage (System.Object queue_id, System.Windows.Forms.MSG& msg, System.IntPtr hWnd, System.Int32 wFilterMin, System.Int32 wFilterMax) [0x00000] in <69b1a555258c430e86ee1f3ef27d8ea6>:0 
  at System.Windows.Forms.Application.RunLoop (System.Boolean Modal, System.Windows.Forms.ApplicationContext context) [0x00331] in <69b1a555258c430e86ee1f3ef27d8ea6>:0 
  at System.Windows.Forms.Application.Run (System.Windows.Forms.ApplicationContext context) [0x00011] in <69b1a555258c430e86ee1f3ef27d8ea6>:0 
  at System.Windows.Forms.Application.Run (System.Windows.Forms.Form mainForm) [0x00006] in <69b1a555258c430e86ee1f3ef27d8ea6>:0 
  at MatterHackers.Agg.UI.WinformsSystemWindow.ShowSystemWindow (MatterHackers.Agg.UI.SystemWindow systemWindow) [0x00076] in <a60ce51005574a6b8aeb1747a540e45e>:0 
  at MatterHackers.Agg.UI.WinformsSystemWindowProvider.ShowSystemWindow (MatterHackers.Agg.UI.SystemWindow systemWindow) [0x0005d] in <a60ce51005574a6b8aeb1747a540e45e>:0 
  at MatterHackers.Agg.UI.SystemWindow.ShowAsSystemWindow () [0x0003e] in <380c41e6abd2444192861ceadc2b8ce5>:0 
  at MatterHackers.MatterControl.Program.Main () [0x00111] in <6af2f6a251ab40eaa9db2d3cbfe257ea>:0 
      6682:	
      6682:	calling fini: /tmp/.mount_MatterwtExrK/usr/bin/MatterControl [0]

If only I knew the least bit about Mono...

@jlewin
Copy link
Contributor

jlewin commented Jul 27, 2018

My takeaway from the 6187 issue was binding errors that appear on systems lacking Mono can initially be attributed to incorrect dllmaps, which should be mitigated with the --config and --machine-config mkbundle params.

I tried this, it didn't work but I'm hopeful that I simply did it wrong and/or the options conflict with other params being passed. I think we may also need to cross compile as well but for a Windows developer like myself, this all takes time to work through and I'm attempting to mix this task in with my existing workload, so it's slow going. Hopefully with a few more days we'll have a build that works on machines that lack Mono, for now I'm elated with the progress that's been made and the tasks that remain

@probonopd
Copy link
Author

Thanks @jlewin for your great support of this feature request until here. I realize that it's an extra burden for you but I hope it will pay off in the end by many happy Linux users that will be able to get MatterControl easily. Interesting that bundling MatterSlicer seemed to have worked on the first attempt.

Maybe @directhex can have another look at this at some time.

@johnmark
Copy link

Is there any more progress on this? Would love to have a Linux package.

@ghost
Copy link

ghost commented Apr 30, 2019

Dear probonopd,
did you progress on this project because I also need it to be able to use it on my Linux workstation.
Thank you.

@probonopd
Copy link
Author

Hi @miguipda1 unfortunately I did not fully succeed yet to make an AppImage out of this application, partly because I don't really know anything about how Mono works. I guess I will need help from someone who knows Mono. I am still happy to help (I know AppImage really well).

@lalanikarim
Copy link

Hi @probonopd. I am familiar with Mono and Linux but not as much with AppImage creation. I've built MC 2.x beta on Linux in the past and even had to find my way around a timing issue happing inside AggSharp. Perhaps we can collaborate on this. Please let me know if I can be of any help.

@probonopd
Copy link
Author

probonopd commented May 7, 2019

Hi @jimmy00784 thanks for offering your help. I'd be more than happy to work with you on this.

To get started, can you have a look at https://gitlab.com/lewin76/MatterControlAppImage/-/jobs/84690721/artifacts/raw/MatterControl/bin/Release/MatterControl-x86_64.AppImage and see what is going wrong? You can inspect the contents of the AppImage by running it with the --appimage-extract parameter.

This is how the AppImage gets produced:
https://gitlab.com/lewin76/MatterControlAppImage/blob/master/.gitlab-ci.yml
The linuxdeployqt tool is explained at https://github.com/probonopd/linuxdeployqt/. Shoot any questions at me that you might have.

@lalanikarim
Copy link

@probonopd Initial findings:
Running AppImage: App loads but UI remains in a somewhat unresponsive state. The button hover effect is clearly visible but won't respond to clicks.
Running the extracted application: App loads and seems to be functioning without any errors.
The noticeable difference seems to be at startup in console messages.
When running AppImage, the console output stops at
Time to '': 209
When running the extracted binary, the console output shows all of the below:

Time to '': 583
Time to 'ShowAsSystemWindow': 270
Time to 'First draw->RunOnIdle': 0
Time to 'MatterControlApplication.Initialize': 0
Time to 'PlatformInit': 0
Time to 'ApplicationController': 200
Time to 'ProfileManager': 29
Time to 'MainView': 0
Time to 'Plugins': 15
Time to 'Process Commandline': 0
Time to 'OnLoadActions': 7
Time to 'AddChild->MainView': 448
libpng warning: iCCP: known incorrect sRGB profile
libpng warning: iCCP: known incorrect sRGB profile
libpng warning: iCCP: cHRM chunk does not match sRGB
Time To Load Seconds: 2.49

The individual "Time to" messages are printed by MatterControl modules that are loaded at startup.
The absence of those when running AppImage tells me that the AppImage run is running into a deadlock of some sort resulting in failure to load all necessary modules.

@probonopd
Copy link
Author

Does sudo strace -f ./MatterControl-x86_64.AppImage give any clues as to what might be going wrong?

@lalanikarim
Copy link

@probonopd with strace, I get a similar unresponsive UI. There might be a timing issue here. I'll try and rebuild the code on my machine and see if I can replicate the issue.

@probonopd
Copy link
Author

You can also run the tests on the extracted contents of the AppImage, although I doubt it'll make a big difference.

@lalanikarim
Copy link

If I recall correctly, a few months ago, I ran into a similar issue with a local build where the UI wouldn't respond in a similar fashion. It ended up being a small timeout value on the UI refresh. I had a bug report open for that issue as well. I'll rebuild again to see if that issue is still there.
Where exactly are you stuck with the AppImage?

@probonopd
Copy link
Author

Where exactly are you stuck with the AppImage?

#3536 (comment)

@lalanikarim
Copy link

Local build runs without any issues.
How can I build an AppImage from it?

@probonopd
Copy link
Author

How can I build an AppImage from it?

Follow each step from https://gitlab.com/lewin76/MatterControlAppImage/blob/master/.gitlab-ci.yml

@probonopd
Copy link
Author

probonopd commented Aug 16, 2020

Just stumbled across this .NET Core AppImage example of how to deploy .NET Core (Mono) applications as an AppImage using dotnet publish -f netcoreapp3.1 -r linux-x64 from within a .cs program.

Maybe it can be useful for MatterControl @jlewin @larsbrubaker?

@jlewin
Copy link
Contributor

jlewin commented Aug 25, 2020

@probonopd - thanks for all your help on this issue and for continuing to staying interested in the solution. At first glace I'd think we can't compile to the netcoreapp3.1 framework/profile as we require Mono on Linux for Winforms support. Microsoft announced netcore Winforms support but it's only on Windows and they have yet to announce cross platform support. Further, Mono never kept up the Winforms effort and we've been plagued by Linux crashes due to poor support. It's plausible that the Winforms layer could be replace with GTK+ or similar however work on that has remained on the back burner for a long time.

I'm no longer with MatterHackers but I remain interested in this option and may resume looking at it in the future and will definitely consider the netcore AppImage example if that happens, thanks.

@probonopd
Copy link
Author

probonopd commented Aug 25, 2020

Thanks for the insights @jlewin - I don't even pretend to know all the subtle differences between the different Core and non-Core .NET and Mono implementations from Ximian, Xamarin, Microsoft, and whatnot (looks complicated, if not to say "like a giant mess" from the outside). But now that Microsoft itself owns Mono maybe the two will one day be merged altogether.

@jlewin
Copy link
Contributor

jlewin commented Aug 25, 2020

But now that Microsoft itself owns Mono maybe the two will one day be merged altogether

Definitely, I believe that's already in the works and is what .NET 5 will be. Unfortunately Microsoft has only committed to .NET 5 Winforms support on Windows and from what I've gathered the prototype in Mono won't be in the .NET 5 Linux package. Maybe I have it wrong though.

We only use Winforms as the OpenTK implementation seemed to provide decent cross platform support. agg-sharp can easily be revised to run on alternative windowing systems and hopefully a .NET 5 compatible one will emerge and this roadblock will be resolved. Ultimately Microsoft needs a cross platform 3D API for .NET and I remain hopeful that they secretly have support planned and coming in a near future release. So far though, that remains a fantasy.

@nerdCopter
Copy link

+1 for AppImage. hopefully avoiding installation of mono-complete, but fine either way.

@Marieholm20
Copy link

Any progress for Linux Mint 21 and matter control 2. for Linux support using appimage ?
It should be fantastic !
Lars.herrnsdorf@gmail.com

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

8 participants