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

revamp appimage functionality #76

Open
wants to merge 2 commits into
base: master
Choose a base branch
from

Conversation

Radvendii
Copy link

@Radvendii Radvendii commented Mar 26, 2021

I couldn't get the existing appimage part of nix-bundle working, so I went in and changed a bunch of stuff, and it now works for me. Note that this pull request is not quite ready, for reasons I'll get to at the end. EDIT: It's ready!

Overview of the changes:

  1. updated the nixpkgs package for appimagekit, and changed nix-bundle to depend on that, rather than packaging it itself
  2. muck with symlinks in the AppDir/nix/store files so that they point to the local files, not the global /nix/store files that won't exist on the host machine.
  3. muck with rpaths so they point to... well, see above.
  4. patchelf the interpreter to point to the system interpreter on most machines
  5. added a flake output for the appimage bundler
  6. appdir now attempts to create an icon / desktop file if they don't exist (making the wrapper around it unnecessary)
  7. i've moved everything into it's own appimage/ folder
  8. added glibc_2.24 overlay that downgrades glibc so that the produced appimages will be compatible with older distros. This has to be applied manually by the user to the nixpkgs they use to build the package that goes into the appimage.

Questions / Problems

  1. My updated appimagekit package is not in nixpkgs yet, so for now I have the input pointed at my personal fork. Once it does go in, it will still be necessary to use a very up to date copy of nixpkgs. I noticed that currently it's set to an older, stable branch, so I'm not sure how you feel about this change or whether it would affect the regular nix-bundle at all.

    EDIT: Solved! I just made multiple inputs.

  2. Style question: I found a list of libraries to exclude from appimages in the AppImage/pkg2appimage repo. Should I leave this as a file and parse it in the code, or should I turn it into a list in .nix file (this would also mean users could override it)
    EDIT: Solved! Not sure if this is the ideal solution, but I changed the file into a nix expression and then loaded it in as the default argument

  3. The AppImages produced by this code can run on other distros (TBH I've only tested ubuntu so far). However, they have to be extremely up to date versions of the distros (Ubuntu 20.10 not Ubuntu 20.04). The reason for this is glibc. We have to use the system glibc at runtime, but nixpkgs builds using the most current glibc.

    Glibc is backwards compatible but not forwards, so the right thing to do is to build using an older version of glibc, or use the .symver assembler instruction to force linking against older versions of the glibc symbols.

    I tried many variations of both of these options and made significant progress, but could not get anything fully working. I don't think this is a strictly necessary part of the tool (firefox, for example, deals with this on it's own and the AppImage runs fine). But it would be extremely useful to include an overlay that users could apply to their nixpkgs to build packages that link against older glibc symbols so that their appimages can run on older distros.

    I would greatly appreciate some help getting this last piece of the puzzle to work. The easiest way would probably be to schedule a call so I can explain what I've tried and what's going wrong, but I can try writing it all out if that's easier.

    EDIT: Solved! It's available as nix-bundle.overlays.glibc_2_24

@Radvendii
Copy link
Author

Update: my appimagekit PR was accepted into nixpkgs, so we can switch the input to nixos/nixpkgs. I'm moving today, so I might not have time for the next couple of days, but it's on my todo list.

@Radvendii
Copy link
Author

Alright, done. No dependencies on my fork of nixpkgs

@Radvendii
Copy link
Author

I think this resolves #3, #29 (possibly? at least, I don't need test-appimage.nix), #39 (somewhat), #44, #66, #75

now this bundler can be used with `nix bundle`
this is fully backward-compatible
@arximboldi
Copy link

arximboldi commented Oct 24, 2021

Hi @Radvendii !

Thank you so much for all the effort put into this PR. I would really really love to get AppImage support working for my desktop + OpenGL app and I'm willing to help as much as needed to get this PR working.

I have given it a try and sadly it is not working for me. The issues are the following:

  • On NixOs I run with appimage-run .... I sadly get this error:

    Uncompress <My_App>_x86_64.AppImage of type 02 @ offset 86496
    [=====================================================================================================================/] 24268/24268 100%
    <My_App>_x86_64.AppImage is now installed in /home/raskolnikov/.cache/appimage-run/c516b58ff6b4a1b6c48bbd55e5e655643671b42a7126fd705d662dd4b6272db4
    /nix/store/dpjnjrqbgbm8a5wvi1hya01vd8wyvsq4-bash-4.4-p23/bin/bash: /usr/lib/libc.so.6: version `GLIBC_2.33' not found (required by /nix/store/dpjnjrqbgbm8a5wvi1hya01vd8wyvsq4-bash-4.4-p23/bin/bash)
    
  • On Ubuntu I get:

    Error: Error executing '/nix/store/4z0j378jmj690m5nl0n2lbfjrf2aizwf-<my-app>/bin/<my-app>` No such file or directory
    

    In this case I tried putting the full path in the .desktop file. I have tried also simply using <my-app> or bin/<my-app> and I got the same result. I also have tried playing with different options in the exec parameter to appimage or appdir.

    As I commented in OpenGL: unable to open display #23, this already happened to me when I just copied the AppRun.c from latest original source into master nix-bundle. I suspect some of the stuff the custom code included in master nix-bundle/AppRun.c may be needed to run the app?


Here are some details about my system:

  • I'm using pinned nixpkgs, oldschool way, no flakes:
{
  rev     ? "08ef0f28e3a41424b92ba1d203de64257a9fca6a",
  sha256  ? "1mql1gp86bk6pfsrp0lcww6hw5civi6f8542d4nh356506jdxmcy",
  nixpkgs ? builtins.fetchTarball {
    name   = "nixpkgs-${rev}";
    url    = "https://github.com/nixos/nixpkgs/archive/${rev}.tar.gz";
    sha256 = sha256;
  }
}
  • This is the version I'm using from your branch:
  let
  nix-bundle-src = pkgs.fetchFromGitHub {
    owner = "radvendii";
    repo = "nix-bundle";
    rev = "5e1e68dab10013871481d922038c6be57da92dc7";
    sha256 = "08aypxfw7l2a648qpsmrk3f13k6f9rrlpmnippy755crf7mcp9yw";
  };
  nix-bundle_appimage = import "${nix-bundle-src}/appimage" { inherit pkgs; };
  • Not sure if relevant, but my app is a Qt + QML app. There is a binary that is wrapped using qt.wrapQtAppsHook. Inspecting the generated .AppDir I've noticed that bin/my-app is copied into the /usr/bin, but not bin/.my-app-wrapped. I think that's fine because bin/my-app is a bash scripts that contains a hard-coded path to .my-app-wrapped into the Nix store. (this was a mistake, probably I wasn't seeing the hidden files -- obviously /usr is just a symlink to the actual package so contents are exactly the same.)

Again, thank you very much and let me know if there is anything I can try or any other way you think I can help. ❤️

Cheers!

@arximboldi
Copy link

The first issue I guess it's because I was not using the glibc overlay. I'm, trying that now... building overnight... let's see how that goes :)

@arximboldi
Copy link

Ok, that has failed as well 😢
Error:

...
gcc ../sysdeps/x86_64/multiarch/memmove-ssse3.S -c     -I../include -I/build/build/string  -I/build/build  -I../sysdeps/unix/sysv/linux/x86_64/64  -I../sysdeps/unix/sysv/linux/x86_64  -I../sysdeps/unix/sysv/linux/x86  -I../sysdeps/unix/sysv/linux/wordsize-64  -I../sysdeps/x86_64/nptl  -I../sysdeps/unix/sysv/linux/include -I../sysdeps/unix/sysv/linux  -I../sysdeps/nptl  -I../sysdeps/pthread  -I../sysdeps/gnu  -I../sysdeps/unix/inet  -I../sysdeps/unix/sysv  -I../sysdeps/unix/x86_64  -I../sysdeps/unix  -I../sysdeps/posix  -I../sysdeps/x86_64/64  -I../sysdeps/x86_64/fpu/multiarch  -I../sysdeps/x86_64/fpu  -I../sysdeps/x86/fpu/include -I../sysdeps/x86/fpu  -I../sysdeps/x86_64/multiarch  -I../sysdeps/x86_64  -I../sysdeps/x86  -I../sysdeps/ieee754/ldbl-96  -I../sysdeps/ieee754/dbl-64/wordsize-64  -I../sysdeps/ieee754/dbl-64  -I../sysdeps/ieee754/flt-32  -I../sysdeps/wordsize-64  -I../sysdeps/ieee754  -I../sysdeps/generic  -I.. -I../libio -I. -nostdinc -isystem /nix/store/p4s4jf7aq6v6z9iazll1aiqwb34aqxq9-bootstrap-tools/bin/../lib/gcc/x86_64-unknown-linux-gnu/8.3.0/include -isystem /nix/store/p4s4jf7aq6v6z9iazll1aiqwb34aqxq9-bootstrap-tools/bin/../lib/gcc/x86_64-unknown-linux-gnu/8.3.0/include-fixed -isystem /nix/store/ph2k4vnsa1zfxlckrmfg997byhbm0z17-linux-headers-5.12/include  -D_LIBC_REENTRANT -include /build/build/libc-modules.h -DMODULE_NAME=libc -include ../include/libc-symbols.h  -DPIC     -DASSEMBLER  -g -Werror=undef -Wa,--noexecstack   -o /build/build/string/memmove-ssse3.o -MD -MP -MF /build/build/string/memmove-ssse3.o.dt -MT /build/build/string/memmove-ssse3.o
../sysdeps/x86_64/multiarch/memcpy-ssse3.S: Assembler messages:
../sysdeps/x86_64/multiarch/memcpy-ssse3.S:65: Error: operand type mismatch for `jb'
make[2]: *** [/build/build/sysd-rules:1855: /build/build/string/memmove-ssse3.o] Error 1
make[2]: Leaving directory '/build/glibc-2.24/string'
make[1]: *** [Makefile:214: string/subdir_lib] Error 2
make[1]: Leaving directory '/build/glibc-2.24'
make: *** [Makefile:9: all] Error 2
builder for '/nix/store/f0zx1mnsmkrc830jp3bypvdhqlia4i2d-glibc-2.24.drv' failed with exit code 2

@arximboldi
Copy link

Ok, I worked around that with this: arximboldi@8c27151

New error:

res_debug.c: In function '__p_secstodate':
res_debug.c:1042:23: error: '%02d' directive writing between 2 and 11 bytes into a region of size between 4 and 11 [-Werror=format-overflow=]
  sprintf(output, "%04d%02d%02d%02d%02d%02d",
                       ^~~~
res_debug.c:1042:18: note: directive argument in the range [-2147483647, 2147483647]
  sprintf(output, "%04d%02d%02d%02d%02d%02d",
                  ^~~~~~~~~~~~~~~~~~~~~~~~~~
res_debug.c:1042:2: note: 'sprintf' output between 15 and 67 bytes into a destination of size 15
  sprintf(output, "%04d%02d%02d%02d%02d%02d",
  ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
   time->tm_year, time->tm_mon, time->tm_mday,
   ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
   time->tm_hour, time->tm_min, time->tm_sec);
   ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
cc1: all warnings being treated as errors

@arximboldi
Copy link

Ok, moved past that with this: arximboldi@b5ca53b

Now it fails at zlib:

building '/nix/store/k3jw7zq6s9vsqj1dx8rhnwa32m2nimh1-zlib-1.2.11.drv'...
unpacking sources
unpacking source archive /nix/store/rrzja19jbqxbfryp2zchb2ma5h041rxh-zlib-1.2.11.tar.gz
source root is zlib-1.2.11
setting SOURCE_DATE_EPOCH to timestamp 1484501380 of file zlib-1.2.11/zutil.c
patching sources
configuring
configure flags: --prefix=/nix/store/ja8qry62dmjlllnhv1a9rd172pqq0nwr-zlib-1.2.11 --shared
Checking for shared library support...
No shared library support; try without defining CC and CFLAGS
Building static library libz.a version 1.2.11 with gcc.
Checking for size_t... Yes.
Checking for off64_t... Yes.
Checking for fseeko... Yes.
Checking for strerror... No.
Checking for unistd.h... Yes.
Checking for stdarg.h... Yes.
Checking whether to use vs[n]printf() or s[n]printf()... using vs[n]printf().
Checking for vsnprintf() in stdio.h... No.
  WARNING: vsnprintf() not found, falling back to vsprintf(). zlib
  can build but will be open to possible buffer-overflow security
  vulnerabilities.
Checking for return value of vsprintf()... Yes.
Checking for attribute(visibility) support... Yes.
building
build flags: -j32 -l32 SHELL=/nix/store/p4s4jf7aq6v6z9iazll1aiqwb34aqxq9-bootstrap-tools/bin/bash PREFIX= SHARED_MODE=1
gcc -O3 -D_LARGEFILE64_SOURCE=1 -DNO_STRERROR -DNO_vsnprintf -DHAVE_HIDDEN -I. -c -o example.o test/example.c
gcc -O3 -D_LARGEFILE64_SOURCE=1 -DNO_STRERROR -DNO_vsnprintf -DHAVE_HIDDEN  -c -o adler32.o adler32.c
gcc -O3 -D_LARGEFILE64_SOURCE=1 -DNO_STRERROR -DNO_vsnprintf -DHAVE_HIDDEN  -c -o crc32.o crc32.c
gcc -O3 -D_LARGEFILE64_SOURCE=1 -DNO_STRERROR -DNO_vsnprintf -DHAVE_HIDDEN  -c -o deflate.o deflate.c
gcc -O3 -D_LARGEFILE64_SOURCE=1 -DNO_STRERROR -DNO_vsnprintf -DHAVE_HIDDEN  -c -o infback.o infback.c
gcc -O3 -D_LARGEFILE64_SOURCE=1 -DNO_STRERROR -DNO_vsnprintf -DHAVE_HIDDEN  -c -o inffast.o inffast.c
gcc -O3 -D_LARGEFILE64_SOURCE=1 -DNO_STRERROR -DNO_vsnprintf -DHAVE_HIDDEN  -c -o inflate.o inflate.c
gcc -O3 -D_LARGEFILE64_SOURCE=1 -DNO_STRERROR -DNO_vsnprintf -DHAVE_HIDDEN  -c -o inftrees.o inftrees.c
gcc -O3 -D_LARGEFILE64_SOURCE=1 -DNO_STRERROR -DNO_vsnprintf -DHAVE_HIDDEN  -c -o trees.o trees.c
gcc -O3 -D_LARGEFILE64_SOURCE=1 -DNO_STRERROR -DNO_vsnprintf -DHAVE_HIDDEN  -c -o zutil.o zutil.c
gcc -O3 -D_LARGEFILE64_SOURCE=1 -DNO_STRERROR -DNO_vsnprintf -DHAVE_HIDDEN  -c -o compress.o compress.c
gcc -O3 -D_LARGEFILE64_SOURCE=1 -DNO_STRERROR -DNO_vsnprintf -DHAVE_HIDDEN  -c -o uncompr.o uncompr.c
gcc -O3 -D_LARGEFILE64_SOURCE=1 -DNO_STRERROR -DNO_vsnprintf -DHAVE_HIDDEN  -c -o gzclose.o gzclose.c
gcc -O3 -D_LARGEFILE64_SOURCE=1 -DNO_STRERROR -DNO_vsnprintf -DHAVE_HIDDEN  -c -o gzlib.o gzlib.c
gcc -O3 -D_LARGEFILE64_SOURCE=1 -DNO_STRERROR -DNO_vsnprintf -DHAVE_HIDDEN  -c -o gzread.o gzread.c
gcc -O3 -D_LARGEFILE64_SOURCE=1 -DNO_STRERROR -DNO_vsnprintf -DHAVE_HIDDEN  -c -o gzwrite.o gzwrite.c
gcc -O3 -D_LARGEFILE64_SOURCE=1 -DNO_STRERROR -DNO_vsnprintf -DHAVE_HIDDEN -I. -c -o minigzip.o test/minigzip.c
gcc -O3 -D_LARGEFILE64_SOURCE=1 -DNO_STRERROR -DNO_vsnprintf -DHAVE_HIDDEN -I. -D_FILE_OFFSET_BITS=64 -c -o example64.o test/example.c
gcc -O3 -D_LARGEFILE64_SOURCE=1 -DNO_STRERROR -DNO_vsnprintf -DHAVE_HIDDEN -I. -D_FILE_OFFSET_BITS=64 -c -o minigzip64.o test/minigzip.c
ar rc libz.a adler32.o crc32.o deflate.o infback.o inffast.o inflate.o inftrees.o trees.o zutil.o compress.o uncompr.o gzclose.o gzlib.o gzread.o gzwrite.o
gcc -O3 -D_LARGEFILE64_SOURCE=1 -DNO_STRERROR -DNO_vsnprintf -DHAVE_HIDDEN -o example example.o -L. libz.a
gcc -O3 -D_LARGEFILE64_SOURCE=1 -DNO_STRERROR -DNO_vsnprintf -DHAVE_HIDDEN -o minigzip minigzip.o -L. libz.a
gcc -O3 -D_LARGEFILE64_SOURCE=1 -DNO_STRERROR -DNO_vsnprintf -DHAVE_HIDDEN -o example64 example64.o -L. libz.a
gcc -O3 -D_LARGEFILE64_SOURCE=1 -DNO_STRERROR -DNO_vsnprintf -DHAVE_HIDDEN -o minigzip64 minigzip64.o -L. libz.a
/nix/store/qivi8nv2603ywnys7b3q96vqszq2npdr-binutils-2.35.1/bin/ld: /nix/store/ri41dzin0jja98l1q2i16jklb3wyqjjp-glibc-2.24/lib/libc.so.6: version `GLIBC_2.27' not found (required by /nix/store/qivi8nv2603ywnys7b3q96vqszq2npdr-binutils-2.35.1/bin/ld)
collect2: error: ld returned 1 exit status
/nix/store/qivi8nv2603ywnys7b3q96vqszq2npdr-binutils-2.35.1/bin/ld: /nix/store/ri41dzin0jja98l1q2i16jklb3wyqjjp-glibc-2.24/lib/libc.so.6: version `GLIBC_2.27' not found (required by /nix/store/qivi8nv2603ywnys7b3q96vqszq2npdr-binutilsmake: *** [Makefile:292: minigzip] Error 1
-2.35.1/bin/ldmake: *** Waiting for unfinished jobs....
)
collect2: error: ld returned 1 exit status
make: *** [Makefile:301: example64] Error 1
/nix/store/qivi8nv2603ywnys7b3q96vqszq2npdr-binutils-2.35.1/bin/ld: /nix/store/ri41dzin0jja98l1q2i16jklb3wyqjjp-glibc-2.24/lib/libc.so.6: version `GLIBC_2.27' not found (required by /nix/store/qivi8nv2603ywnys7b3q96vqszq2npdr-binutils-2.35.1/bin/ld)
collect2: error: ld returned 1 exit status
make: *** [Makefile:289: example] Error 1
/nix/store/qivi8nv2603ywnys7b3q96vqszq2npdr-binutils-2.35.1/bin/ld: /nix/store/ri41dzin0jja98l1q2i16jklb3wyqjjp-glibc-2.24/lib/libc.so.6: version `GLIBC_2.27' not found (required by /nix/store/qivi8nv2603ywnys7b3q96vqszq2npdr-binutils-2.35.1/bin/ld)
collect2: error: ld returned 1 exit status
make: *** [Makefile:304: minigzip64] Error 1
builder for '/nix/store/k3jw7zq6s9vsqj1dx8rhnwa32m2nimh1-zlib-1.2.11.drv' failed with exit code 2

@arximboldi
Copy link

I've tried also downgrading binutils but I've failed... My brain is a bit fried.

I guess I'm having all these issues because I am using a more recent nixpkgs as base (08ef0f28e3a41424b92ba1d203de64257a9fca6a is from August). Looking at the flakes.nix in nix-bundle, this is using 20.03 which is rather old by current standards... Maybe you can take a look at see how to change the glibc overlay so it works on newer nixpkgs?

@arximboldi
Copy link

Progress!!!

So I decided that glibc 2.24 was too old. The oldest Ubuntu LTS uses glibc 2.27. After a lot of fighting, I managed to make an overlay for glibc 2.27 build:
arximboldi@622547d

But now I'm back at:

  • On Ubuntu:
Error: Error executing 'myapp' No such file or directory
  • On NixOS appimage-run:
/nix/store/nxk5nx6i74ncfk6skfd5xh66lx23lhcx-bash-4.4-p23/bin/bash: relocation error: /usr/lib/libc.so.6: symbol _dl_fatal_printf version GLIBC_PRIVATE not defined in file ld-linux-x86-64.so.2 with link time reference

@arximboldi
Copy link

I suspect that the first error is due to using an unpatched AppRun.c, since I have had a similar case in the past: #23 (comment)

@@ -74,7 +74,7 @@ NIX_PATH="nixpkgs=https://github.com/matthewbauer/nixpkgs/archive/nix-bundle.tar

This will create a file at Emacs-x86_64.AppImage which you can execute.

Notice that there is only one argument for nix2appimage.sh. This is because the target executable will be detected from the .desktop file in ```/share/applications/*.desktop```. As a side-effect, AppImage requires your package to have a .desktop file, so packages like "hello", "coreutils", etc. will not work.
Notice that there is only one argument for nix2appimage.sh. This is because the target executable will be detected from the .desktop file in ```/share/applications/*.desktop```. If there is no .desktop file, nix2appimage will attempt to create one. If, however, there are more than one executable in the bin/ directory, we can't pick one, and there will have to be a .desktop file.

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What if there are multiple .desktop files?

@piegamesde
Copy link

piegamesde commented Apr 23, 2022

Thank you, this looks like a huge improvement. I am still struggling with the usage of the command line tools though (similar to #55). I naively tried ./nix2appimage.sh ~/Documents/myproject/default.nix and it wan't happy about that somehow :(


Edit: I got it working now by directly invoking the Nix expression. The CLI issue I had is just the shell script being weird in general and has nothing to do with the PR. (It definitely craves an overhaul too, but this is probably out of score for this PR)

Now that I've built my AppImage, I can confirm the "undefined symbol: _dl_catch_error_ptr, version GLIBC_PRIVATE" error on Arch w/Nix. Could we maybe work around this by switching to the Go implementation of appimagetool, since IIRC that one does not depend on libc?

@arximboldi
Copy link

@Radvendii... are there any news on this? Have you been managing to create appimages with OpenGL support via this or some other mechanism lately? I'm still shopping for a solution 😅

@Radvendii
Copy link
Author

Not recently. https://github.com/Radvendii/MAR1D is the last I worked on this.

@arximboldi
Copy link

Cool, thanks! I'll try build that project see what happens...

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

Successfully merging this pull request may close these issues.

3 participants