AppImage / AppImageKit

Package desktop applications as AppImages that run on common Linux-based operating systems, such as RHEL, CentOS, openSUSE, SLED, Ubuntu, Fedora, debian and derivatives. Join #AppImage on irc.libera.chat
http://appimage.org
Other
8.77k stars 563 forks source link

Statically linked runtime #877

Open agowa opened 6 years ago

agowa commented 6 years ago

AppImages should run on all Linux Platforms, but currently they don't, this is because it is dynamically linked against glibc. I tried to run a AppImage on Alpine Linux and it failed because Alpine Linux is build around musl libc instead. I think AppImages should generally include all necessary dependencies and not some of them. Also adding libc would not increase the resulting size much, depending on the used libc, it may only be from 185k to 8M libc Comparison Chart. And if the binary is also stripped it can also be a much less.

AppImage should do something like this:

  1. When creating, check the required symbols of the application and determine the smallest fitting libc to include.
  2. Always produce statically linked binaries, that don't depend on anything on the system.
  3. Recommend using musl libc instead of glibc, for various reasons like License (MIT ./. LGPL), binary size (527k ./. 8M).
azubieta commented 2 years ago

I patched libfuse to fallback to fusermount if fusermount3 is not present and it seems to work. It would be great if you could help me testing.

patch: https://github.com/azubieta/appimage-runtime/commit/edb83c9517620eb7aa52f0ce03fa8a7e40ede086 reference issue: https://github.com/azubieta/appimage-runtime/issues/10

ell1e commented 2 years ago

https://github.com/rust-lang/rust/issues/65447#issuecomment-542417877 Was this considered in this process? Sorry I'm really not a qualified legal person this might be wrong: but if this is part of the final app image binary then it seems like it could mean it can't really be used to distribute programs that aren't LGPL-licensed (and also not something that allows relicensing to LGPL) and it would require these app image binaries to offer some way to get the glibc source code used to be specified along with them... I think? I could also be entirely wrong about this.

Jookia commented 2 years ago

Does this imply dropping i18n and l10n support too?

probonopd commented 2 years ago

@ell1e my interpretation is that since the AppImage runtime does not get linked with the payload application, this is a case of "mere aggregation". The runtime is simply prepended to a disk image file, but the contents of that disk image file do not link to the runtime.

probonopd commented 2 years ago

@Jookia

Does this imply dropping i18n and l10n support too?

What makes you think so?

ell1e commented 2 years ago

since the AppImage runtime does not get linked with the payload application, this is a case of "mere aggregation".

Hm, the ticket title literally says statically linked runtime, is that wrong? Because you're describing dynamic link but shipped glibc in the disk image. That btw might still require that e.g. the --help option says how to unaggregate it and might still require bringing the source for glibc with it. (Or not, I'm not a lawyer and if in doubt wrong on everything.)

Jookia commented 2 years ago

musl doesn't support locales

On Sun, Jul 17, 2022 at 11:44:49PM -0700, probonopd wrote:

@Jookia

Does this imply dropping i18n and l10n support too?

What makes you think so?

-- Reply to this email directly or view it on GitHub: https://github.com/AppImage/AppImageKit/issues/877#issuecomment-1186825778 You are receiving this because you were mentioned.

Message ID: @.***>

teras commented 2 years ago

I am a bit confused.

First of all (based on the other issues) the problem with fuse2/3 and Ubuntu, is of course that AppImage(s) should (?) have been statically linked, to avoid this kind of problems, not only now but also in the future.

In parallel, the current version of AppImage doesn't (couldn't?) support fuse3, although some work has been done, at least conceptually, to try fuse3 first and then fuse2 as a failsafe mechanism.

But this work is not published yet? Or is stale? Or, at any case, what is the state of this?

The fuse3 issue is closed, and asking your users to install a "random" library (in their eyes), when at the same time AppImage promises a self-contained environment/setup, is not an optimal solution.

Thus, please update if possible your situation and what could be done instead.

probonopd commented 2 years ago

go-appimage is already using the new static runtime, for example. So it's technically doable, but the change hasn't been made in the AppImageKit project yet.

In parallel, the current version of AppImage doesn't (couldn't?) support fuse3

Existing AppImages need sudo apt-get -y install libfuse2 to be used on Ubuntu.

ell1e commented 2 years ago

is of course that AppImage(s) should (?) have been statically linked,

I think for glibc that isn't the best idea for multiple reasons. Even statically linking just libfuse2 might not be a good idea since it appears to be LGPL (but what do I know). Might be best to just try to get libfuse3 to work.

probonopd commented 2 years ago

Static linking of LGPL is not a problem if the project is open source, which AppImageKit clearly is.

Might be best to just try to get libfuse3 to work.

Then we'd have the same breakage when libfuse4 comes around.

ell1e commented 2 years ago

which AppImageKit clearly is.

Right, but the resulting combined App Image may not fully be. Also, you'd still need to ship the libfuse source code inside the App Image or along with it (or not, I'm not the person to ask or speak on this at all, but it reads like that to me).

What about using dlopen() to support multiple libfuse versions (without shipping them, I mean)?

teras commented 2 years ago

go-appimage is already using the new static runtime, for example. So it's technically doable, but the change hasn't been made in the AppImageKit project yet.

The two tools have incompatible command line arguments. So the confusion still remains -- has the go version the same functionality, especially in terms of packaging a (random) application, even without signing or auto-update enabled?

In parallel, the current version of AppImage doesn't (couldn't?) support fuse3

Existing AppImages need sudo apt-get -y install libfuse2 to be used on Ubuntu.

I am more worried for "future" AppImages. My preferred way of distributing my applications is AppImage, and (what a surprise) I hear complaints of missing fuse2. So I am practically asking if there's a way to produce new AppImages that would work right now on both, fuse2 and fuse3 systems.

teras commented 2 years ago

which AppImageKit clearly is.

Right, but the resulting combined App Image may not fully be. Also, you'd still need to ship the libfuse source code inside the App Image or along with it (or not, I guess I'm not the person to ask or speak on this at all, but it reads like that to me). I'm really not a lawyer, but seems like not that ideal to me.

What about using dlopen() to support multiple libfuse versions (without shipping them, I mean)?

The problem still remains when fuse4 comes out, @probonopd is right here.

About linking, the problem with GPL (not even LGPL) is if you link your application with this library. AFAIK there's no linking involved between the packaged application and the AppImage launcher. Is like saying, that, the Y program (which is distributed as a RAR archive), should have the same license as RAR itself.

ell1e commented 2 years ago

About linking, the problem with GPL (not even LGPL) is if you link your application with this library

And with shipping LGPL binaries, I think, being clueless however. (See my source code mention.) But I'm not a lawyer, I just got the gut feeling LGPL is a bad idea to include. Also, I don't think neither GPL nor LGPL define a link clearly, but again, I'm the wrong person to ask.

Using dlopen() would make it possible to solve for a libfuse4, and without shipping it.

teras commented 2 years ago

According to the source of truth, indeed you need to provide the source code of modified version of the library; even if it is a link to an FTP server (or in modern era, a github page). Here we don't even talk about modifications. So for me, even if I'm not a lawyer, there's no issue at all. And moreover we are talking about LGPL libraries, where where you are even allowed to link to closed source software (where AppImage clearly is not).

TheAssassin commented 2 years ago

I think you got this wrong. The argument regarding static linking is that it's rather unlike that the kernel will remove older APIs which libfuse3 might be using now. Thus, when linking libfuse3 statically, it should work virtually forever. When using dlopen(), old AppImages will again break when the expected libfuse versions can not be found, thus breaking similarly. The long term fix is to link either version statically, and since there's a version 3 which is newer, that's the version to use.

ell1e commented 2 years ago

@teras that might be wrong, just see this other one, there's no "modified" here: https://www.gnu.org/licenses/gpl-faq.en.html#UnchangedJustBinary (Or the license text.) While I'm again not qualified to be relied upon, I don't see how it's just for modified.

dlopen() might break really old binaries, but would be trivial to update them to work everywhere again. Right now, that doesn't seem to be the case. Generally, I don't think whatever you do it'll work forever without any updates ever, especially not for complex graphical stuff.

Jookia commented 2 years ago

Hi there, I'm someone a bit more knowledgeable! See the following licenses:

https://www.gnu.org/licenses/old-licenses/lgpl-2.1.en.html https://www.gnu.org/licenses/lgpl-3.0.html

The LGPL requires you to make it possible to replace the LGPL work in your application, static or dynamic. Dynamic linking just makes this easier.

TheAssassin commented 2 years ago

Guys, please stop. All of this is off topic. Feel free to continue your dispute on IRC.

ell1e commented 2 years ago

The LGPL requires you to make it possible to replace the LGPL work

That is a different clause maybe, yes. However, the source code clause also seems to exist. In any case, it's a very complex license. I think at least that in itself, the complexity, is not off-topic for considering what to do.

TheAssassin commented 2 years ago

We plan to separate the runtime bits, possibly rewrite them, and then provide a statically linked binary. All this is fine according to our research. Worst case is we'll have to relicense our code. But that would be fine for the runtime itself.

ell1e commented 2 years ago

My (quite uninformed) worry is the worst case rather is some app dev shipping an App Image would with that end up violating these licenses. But I'm repeating myself. just seems slightly risky.

TheAssassin commented 2 years ago

That is so unlikely to happen... just because you ship a software with broken licensing? I don't think a court would condemn you for it. Also, even if there is a violation, you'd have to wait for the libfuse authors to complain first. And they wouldn't go straight to court just because we made a mistake. So, really, no need to worry. We'll get it done correctly eventually.

ell1e commented 2 years ago

If it's a commercial software, why wouldn't a court do that? I at least thought AppImageKit was also meant for that. I mean maybe you're right, I really wouldn't know what's a realistic risk.

hchunhui commented 1 year ago

Hi, what is the progress of statically linked runtime? Maybe I have found a new way to solve the fuse2/3 problem. The PoC is at https://github.com/hchunhui/AppImageKit/releases/tag/builtin-libfuse , the patch is at https://github.com/hchunhui/libappimage/commit/f0517fe7cf7045fb6cacf2c34c80f7c339cf77ed . Now it works on both old linux distros and ubuntu 22.04 without libfuse2.

Instead of writing a new go runtime and statically link everything, it only ships a compressed libfuse.so.2 in the current runtime. If the file is not found, it extract the file in memory and load the library dynamically. The advantage is it only adds 60~70KB to the runtime, and requires a relatively small code change.

probonopd commented 1 year ago

https://github.com/probonopd/go-appimage/ is already using the statically linked runtime.

Instead of writing a new go runtime and statically link everything, it only ships a compressed libfuse.so.2 in the current runtime. If the file is not found, it extract the file in memory and load the library dynamically. The advantage is it only adds 60~70KB to the runtime, and requires a relatively small code change.

That is clever. Thanks for sharing this idea.

The downside is that such AppImages still need Linux libraries, e.g., one can't run them on FreeBSD (or on non-GNU Linux systems, or on e.g., NixOS) without having Linux libraries installed.

% chmod +x /tmp/appimagetool-x86_64.AppImage 
%  /tmp/appimagetool-x86_64.AppImage 
ld-elf.so.1: Shared object "libpthread.so.0" not found, required by "libglib-2.0.so.0"

So it may still be preferable to use the static runtime.

ell1e commented 1 year ago

I think most people agree that other than the licensing, a static runtime would solve a lot of things (or a baked in libfuse for that matter, sadly libfuse also being LGPL. I wonder if they could be swayed to just relicense it?).

hchunhui commented 1 year ago

OK, now we have a running static runtime. I agree it solves more problems besides fuse2/3.

probonopd commented 1 year ago

@ell1e, what issue do you see with libfuse being LGPL? All other code we are linking to it is open source and/or can be provided in object code format.

ell1e commented 1 year ago

I mean I'm just reiterating myself, but I think any AppImage containing libfuse would strictly speaking need to have a dialog in the application offering the libfuse source code in the exact contained version, which I assume no app actually offers. But I'm not a lawyer so don't trust anything I say anyway

probonopd commented 1 year ago

In case libfuse2 security fixes are no longer released, we may want to statically link libfuse3. Here is a PR that does that:

https://github.com/AppImage/type2-runtime/pull/6

TheAssassin commented 1 year ago

Putting pressure on people doesn't help. I'll review ASAP. Been busy fixing zsync2 and AppImageUpdate lately.

v3ss0n commented 1 year ago

Putting pressure on people doesn't help. I'll review ASAP. Been busy fixing zsync2 and AppImageUpdate lately.

Just add more people for maintaining then.

OK, now we have a running static runtime. I agree it solves more problems besides fuse2/3.

It is critical needs now. I can no longer deploy my projects using AppImage in ubuntu 22.04 servers , that users runs it by doing ./deploy.appimage due to libfuse requirement.

Cyriuz commented 1 year ago

You can solve it with https://github.com/AppImage/type2-runtime

Just use that with appimagetool --runtime-file and your AppImages will work fine.

v3ss0n commented 1 year ago

thanks @Cyriuz gonna give a try.

probonopd commented 1 year ago

Just add more people for maintaining then.

Just hire some people then. ;-)

A pull request that would remove the runtime source code from this repo and instead embed the runtime from https://github.com/AppImage/type2-runtime/releases/continuous into appimagetool would be appreciated. Any volunteers? Shouldn't be too hard.

probonopd commented 1 year ago

It has been possible to use the static runtime for a while now. In the tools I am using (go-appimage) I've been using it exclusively for a while now. There seem to be no technical showstoppers, but adoption has been slow since using the static runtime is not the default in appimagetool yet.

So I am proposing to switch appimagetool to use the static runtime by default.

If there are no substantial vetos or showstoppers within the next 4 weeks, I'd like to change the default to the static runtime.

v3ss0n commented 1 year ago

i will test

bksubhuti commented 1 year ago

i can test if you want, but I need the command line I have a 23.04 buntu with no fuse on it and no dev tools except libsqlite3-dev

Is there a way to static link that libsqlite-dev too?

s09bQ5 commented 1 year ago

I don't think statically linking everything is a good idea in all cases. There will be cases where the AppImage wants to use libraries from the host system (OpenGL/Vulkan/etc. graphics drivers and the JACK audio API come to mind), so it has to assume that a certain C library is used. And when it already makes this assumption for the main application, it would be a waste of space to still link the runtime statically.

This whole "I want to be able to run the AppImage on a system which uses musl instead of Glibc" is the same as Wayland vs. X11 and systemd vs. system V init. One of them is the de-facto standard and someone using the other one has to live with the consequences. Running several AppImages on a musl system that all each include a different version of Glibc also isn't really elegant. Startup times will be worse for everyone using the AppImages because more code has to be loaded and none of it is shared with other applications. What is stopping Alpine Linux users from installing Glibc in parallel to musl except their idealism? The ELF interpreter has a different file name and all the other libraries can be placed in a different directory. IMHO musl is useful when size matters or the LGPL is a no-go. But then running AppImages which include a Glibc should also be a no-go.

Statically linking only libfuse is a compromise I'd be willing to accept, but people who run a kernel with support for FUSE and who want to run AppImages usually don't have a problem with installing libfuse. Statically linking an old version of libfuse is worse than forcing users to have to keep an old version around since the latter still allows updates in case of security issues.

So in my opinion the statically linked runtime should coexist with the current dynamically linked runtime and the AppImage specification should not mandate that the runtime has to be statically linked. If appimagetool allows to select between the two runtimes, it should also check that all libraries are included when the statically linked runtime is used and it should warn when some of these are known to use dlopen to load plugins from the outside to do their work (like libvulkan).

probonopd commented 1 year ago

The runtime has nothing to do with graphics libraries. We are not talking about mandating that the contents of the AppImage shall be statically linked. The runtime is just the piece that mounts the filesystem and executes the AppRun file inside it.

s09bQ5 commented 1 year ago

I know, but statically linking the runtime to a C library makes no sense if the application inside the AppImage is dynamically linked to a C library on the outside.

probonopd commented 1 year ago

Partly. It (hopefully) makes AppImages robust against distributions replacing libfuseX with a newer version.

And yes, to make the payload application also as robust as possible, either statically linking or bundling all shared libraries may be beneficial, but that is outside the scope of this issue.

bksubhuti commented 1 year ago

installing fuse will crash ubuntu. This is something you don't consider. I'm through telling people to install fuse. or libfuse2. Once bit 2wice shy. I caused someone to crash his computer because of this old instruction sudo apt install fuse.

In any case.. I just built an appimage with github workflow and it was impossible to get the appimage to run.. I guess i'm more technical than others. So I resort to my extract, rezip then ship.. "It just works" that is what the appimage is supposed to do. But I have libfuse2 installed and it does not work.. (unless I need to reboot?).
I'm still against the Appimages if they need libfuse2 installed.

s09bQ5 commented 1 year ago

Why is linking everything statically into the runtime preferred over linking only libfuse statically?

bksubhuti commented 1 year ago

For me the fuse is a bad thing. I don't care about other things . In fact we need SQLite to run. We can and do tell people to install it. But fuse has me so turned off why did they make a fuse 3 that crashes Ubuntu. Was this a plan to promot snap.?

Because of all of this , I make an appimage extract and then zip and ship. It works and it is portable.. and no fear of fuse

probonopd commented 1 year ago

installing fuse will crash ubuntu. This is something you don't consider.

What? That is a misunderstanding.

sudo add-apt-repository universe
sudo apt install libfuse2

should not crash anything. The only issue is that Ubuntu does no longer ship it by default, like it did for decades. And we did not get a couple of years to transition from libfuse2 to libfuse3. They did not ship both in parallel for a few years as would have been the thing to do (in my opinion).

probonopd commented 1 year ago

Why is linking everything statically into the runtime preferred over linking only libfuse statically?

So that the runtime can also work on non-glibc systems. Only what the runtime needs is linked statically, not everything.

I'm still against the Appimages if they need libfuse2 installed.

This will no longer be an issue with the statically linked runtime.

s09bQ5 commented 1 year ago

Only what the runtime needs is linked statically, not everything.

The runtime still ended up being 3x as big. I stick to my opinion from above. A fully statically linked runtime makes sense only when the application inside the AppImage is self contained. For all other cases I am fine with linking libfuse statically.