Skip to content

Commit

Permalink
fully support relocatable binaries, improving AppImages
Browse files Browse the repository at this point in the history
* You can now specify `--with-scitecodatadir` as a relative path,
  that will be interpreted relative to the binary's location.
* Win32 binaries already were relocatable, but this was a Windows-specific
  hack. Win32 binaries are now built with `--with-scitecodatadir=.`
  since everything is in a single directory.
* Ubuntu packages are now also built `--with-scitecodatadir=../share/sciteco`.
  This is not crucial for ordinary installations, but is meant for AppImage creation.
* Since AppImages are now built from relocatable packages,
  we no longer need the unionfs-workaround from pkg2appimage.
  This should fix the strange root contents when autocompleting in
  AppImage builds.
* This might also fix the appimage.github.io CI issues.
  I assume that because I could reproduce the issue on FreeBSD's
  Linuxulator in dependence of pkg2appimage's "union"-setting.
  See AppImage/appimage.github.io#3402
* Determining the binary location actually turned out be hard and
  very platform-dependant. There are now implementations for Windows
  (which could also read argv[0]), Linux and generic UNIX (which
  works on FreeBSD, but I am not sure about the others).
  I believe this could also be useful on Mac OS to create app bundles,
  but this needs to be tested - currently the Mac OS binaries are
  installed into fixed locations and don't use relocation.
  • Loading branch information
rhaberkorn committed Nov 5, 2024
1 parent 36c7526 commit 9cce7d2
Show file tree
Hide file tree
Showing 11 changed files with 153 additions and 64 deletions.
19 changes: 12 additions & 7 deletions .github/workflows/nightly.yml
Original file line number Diff line number Diff line change
Expand Up @@ -218,9 +218,11 @@ jobs:
mkdir build-wingui build-wincon
(cd build-wingui
../configure --with-interface=pdcurses-gui --enable-html-manual --program-prefix=g \
--with-scitecodatadir=. \
PDCURSES_LIBS="-lpdcurses_wingui -lgdi32 -lcomdlg32 -lwinmm")
(cd build-wincon
../configure --with-interface=pdcurses --enable-html-manual \
--with-scitecodatadir=. \
PDCURSES_LIBS="-lpdcurses_wincon -lgdi32 -lwinmm")
- name: make
Expand All @@ -244,9 +246,10 @@ jobs:
run: |
mkdir temp-bin/
cd temp-bin/
cp /mingw32/bin/{gsciteco.exe,sciteco.exe,grosciteco.tes,tedoc.tes} ./
cp -r /mingw32/share/sciteco/{lib,*.tmac} ./
cp /mingw32/share/sciteco/sample.teco_ini .teco_ini
cp -r /mingw32/bin/{gsciteco.exe,sciteco.exe,grosciteco.tes,tedoc.tes} ./
# datadir is relative to bindir
cp -r /mingw32/bin/{lib,*.tmac} ./
cp /mingw32/bin/sample.teco_ini .teco_ini
cp -r /mingw32/share/doc/sciteco/* ./
cp ../COPYING ../ChangeLog ./
cp /mingw32/bin/gspawn-win32-helper*.exe ./
Expand Down Expand Up @@ -300,7 +303,8 @@ jobs:
LDFLAGS: -flto
run: |
autoreconf -i
./configure --with-interface=gtk --enable-html-manual
./configure --with-interface=gtk --enable-html-manual \
--with-scitecodatadir=.
- name: make
run: make -j 2
Expand All @@ -317,11 +321,12 @@ jobs:
mkdir temp-bin
cd temp-bin
cp /mingw32/bin/{sciteco.exe,grosciteco.tes,tedoc.tes} ./
cp -r /mingw32/share/sciteco/{lib,*.tmac} ./
# datadir is relative to bindir
cp -r /mingw32/bin/{lib,*.tmac} ./
# FIXME: Maybe there should be a separate win32/.teco_ini with
# a few pre-enabled settings?
cp /mingw32/share/sciteco/sample.teco_ini .teco_ini
cp /mingw32/share/sciteco/fallback.css .teco_css
cp /mingw32/bin/sample.teco_ini .teco_ini
cp /mingw32/bin/fallback.css .teco_css
cp -r /mingw32/share/doc/sciteco/* ./
cp ../COPYING ../ChangeLog ./
cp /mingw32/bin/gspawn-win32-helper*.exe ./
Expand Down
5 changes: 0 additions & 5 deletions AppImage/curses.yml
Original file line number Diff line number Diff line change
@@ -1,10 +1,5 @@
app: sciteco-curses

# We currently use paths hardcoded at build-time.
# Alternatively, it would be possible to customize the AppRun script or
# add a wrapper that sets $SCITECOPATH.
union: true

ingredients:
packages:
- sciteco-curses
Expand Down
5 changes: 0 additions & 5 deletions AppImage/gtk.yml
Original file line number Diff line number Diff line change
@@ -1,10 +1,5 @@
app: sciteco-gtk

# We currently use paths hardcoded at build-time.
# Alternatively, it would be possible to customize the AppRun script or
# add a wrapper that sets $SCITECOPATH.
union: true

ingredients:
packages:
- sciteco-gtk
Expand Down
5 changes: 0 additions & 5 deletions TODO
Original file line number Diff line number Diff line change
Expand Up @@ -466,11 +466,6 @@ Features:
* Get into mentors.debian.net. First step to being adopted
into the Debian repositories.
* Get meta-rhaberkorn into https://layers.openembedded.org
* Linux: Relocatable binaries instead of hardcoding the library path.
This makes it possible to run builds installed via
`make install DESTDIR=...` and will aid in creating AppImages.
Currently we have to define "union: true" and consequently
the root directory is not what we would expect.
* sample.teco_ini: Support opening files on certain lines
(filename:line).
Theoretically, this could also be added to the <EB> syntax,
Expand Down
17 changes: 13 additions & 4 deletions configure.ac
Original file line number Diff line number Diff line change
Expand Up @@ -173,29 +173,38 @@ AC_CHECK_FUNCS([memset setlocale strchr strrchr fstat sscanf], , [
# glib defines G_OS_UNIX instead...
case $host in
*-*-linux* | *-*-*bsd* | *-*-darwin* | *-*-cygwin* | *-*-haiku*)
AC_CHECK_FUNCS([realpath fchown dup dup2 getpid open read kill mmap], , [
AC_CHECK_FUNCS([realpath readlink fchown dup dup2 getpid open read kill mmap], , [
AC_MSG_ERROR([Missing libc function])
])
AC_SEARCH_LIBS(dladdr, [dl], , [
AC_MSG_ERROR([No library providing dladdr()!])
])
;;
esac

#
# Config options
#

# NOTE: This can be relative to the binary location for relocateable builds.
AC_ARG_WITH(scitecodatadir,
AS_HELP_STRING([--with-scitecodatadir=PATH],
[Installation directory of data [default=DATADIR/sciteco]]),
[scitecodatadir=$withval], [scitecodatadir=$datadir/$PACKAGE])
[scitecodatadir_rel=$withval], [scitecodatadir_rel=$datadir/$PACKAGE])
AC_SUBST(scitecodatadir_rel)
# The Automake installation directory needs to be absolute, though:
case "$scitecodatadir_rel" in
/*) scitecodatadir="$scitecodatadir_rel";;
*) scitecodatadir="$bindir/$scitecodatadir_rel";;
esac
AC_SUBST(scitecodatadir)
# SciTECO library macro directory
scitecolibdir=$scitecodatadir/lib
AC_SUBST(scitecolibdir)

# These paths can be changed at install-time and
# should not be written into config.h:
AM_CPPFLAGS="$AM_CPPFLAGS -D'SCITECODATADIR=\"\$(scitecodatadir)\"' \
-D'SCITECOLIBDIR=\"\$(scitecolibdir)\"'"
AM_CPPFLAGS="$AM_CPPFLAGS -D'SCITECODATADIR=\"\$(scitecodatadir_rel)\"'"

# FIXME: It does not really make sense to have this configurable.
# It would make more sense to allow linking against an externally-provided
Expand Down
9 changes: 7 additions & 2 deletions debian/rules
Original file line number Diff line number Diff line change
Expand Up @@ -31,11 +31,15 @@ endif

build build-arch build-indep: build-curses-stamp build-gtk-stamp;

# NOTE: The datadir will be relative to the binary location at runtime.
# This makes the binary relocateable, which is important when creating
# AppImages from the Debian packages.
build-curses-stamp:
dh_testdir
rm -rf build-curses
dh_auto_configure -Bbuild-curses -- \
--with-interface=ncurses
--with-interface=ncurses \
--with-scitecodatadir=../share/sciteco
dh_auto_build -Bbuild-curses
dh_auto_test -Bbuild-curses
touch $@
Expand All @@ -47,7 +51,8 @@ build-gtk-stamp:
rm -rf build-gtk
dh_auto_configure -Bbuild-gtk -- \
--program-prefix=g \
--with-interface=gtk
--with-interface=gtk \
--with-scitecodatadir=../share/sciteco
# NOTE: Since the Gtk+ version of SciTECO is called during the build,
# we need an XServer which may be missing on the build server.
# That's why we use xvfb.
Expand Down
5 changes: 3 additions & 2 deletions distribute.mk.in
Original file line number Diff line number Diff line change
Expand Up @@ -110,6 +110,7 @@ mingw-binary : @PACKAGE@-@[email protected]
PKG_CONFIG_LIBDIR=/usr/i686-w64-mingw32/lib/pkgconfig \
./configure --host=i686-w64-mingw32 build=i386-pc-linux-gnu \
--prefix=/usr \
--with-scitecodatadir=. \
--enable-static-executables \
--disable-dependency-tracking \
--with-interface=$(MINGW_UI) \
Expand All @@ -122,11 +123,11 @@ mingw-binary : @PACKAGE@-@[email protected]
install-strip DESTDIR=`pwd`/temp-install
rm -rf $(SCITECO_DIR)/
mkdir temp-bin/
cp -r temp-install/usr/bin/* temp-install/usr/share/sciteco/* \
cp -r temp-install/usr/bin/* \
temp-install/usr/share/doc/sciteco/* \
temp-bin/
cp @srcdir@/win32.teco_ini temp-bin/.teco_ini || \
cp temp-install/usr/share/sciteco/sample.teco_ini \
cp temp-install/usr/bin/sample.teco_ini \
temp-bin/.teco_ini
cp @srcdir@/COPYING @srcdir@/ChangeLog temp-bin/
rm -rf temp-install/
Expand Down
85 changes: 85 additions & 0 deletions src/file-utils.c
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
#include "config.h"
#endif

#define _GNU_SOURCE
#include <limits.h>
#include <stdlib.h>
#include <string.h>
Expand All @@ -35,6 +36,10 @@
#include <glib.h>
#include <glib/gstdio.h>

#ifdef G_OS_UNIX
#include <dlfcn.h>
#endif

#include "sciteco.h"
#include "qreg.h"
#include "interface.h"
Expand Down Expand Up @@ -179,6 +184,86 @@ teco_file_is_visible(const gchar *path)

#endif /* !G_OS_WIN32 */

#ifdef G_OS_WIN32

gchar *
teco_file_get_program_path(void)
{
TCHAR buf[MAX_PATH];
if (!GetModuleFileNameW(NULL, buf, G_N_ELEMENTS(buf))
return g_get_current_dir();
g_autofree gchar *exe = g_utf16_to_utf8(buf, -1, NULL, NULL, NULL);
return g_path_get_dirname(exe);
}

#elif defined(__linux__)

gchar *
teco_file_get_program_path(void)
{
gchar buf[PATH_MAX];
ssize_t len = readlink("/proc/self/exe", buf, sizeof(buf)-1);
if (G_UNLIKELY(len < 0))
/* almost certainly wrong */
return g_get_current_dir();
buf[len] = '\0';

return g_path_get_dirname(buf);
}

#elif defined(G_OS_UNIX)

/*
* At least works on FreeBSD, even though it also has
* sysctl(KERN_PROC_PATHNAME).
* We assume it works on all other UNIXes as well.
*/
gchar *
teco_file_get_program_path(void)
{
Dl_info info;
return dladdr(teco_file_get_program_path, &info)
? g_path_get_dirname(info.dli_fname) : g_get_current_dir();
}

#else /* !G_OS_WIN32 && !__linux__ && !G_OS_UNIX */

/*
* This is almost guaranteed to be wrong,
* meaning that SciTECO cannot be made relocatable on these platforms.
* It may be worth evaluating argv[0] on these platforms.
*/
gchar *
teco_file_get_program_path(void)
{
return g_get_current_dir();
}

#endif

/**
* Get the datadir.
*
* By default it is hardcoded to an absolute path at
* build time.
* However, you can also build relocateable binaries
* where the datadir is relative to the program's executable.
*
* @note Beginning with glib v2.58, we could directly use
* g_canonicalize_filename().
*/
gchar *
teco_file_get_datadir(void)
{
if (g_path_is_absolute(SCITECODATADIR))
return g_strdup(SCITECODATADIR);

/* relocateable binary - datadir is relative to binary */
g_autofree gchar *program_path = teco_file_get_program_path();
g_autofree gchar *datadir = g_build_filename(program_path, SCITECODATADIR, NULL);
return teco_file_get_absolute_path(datadir);
}

/**
* Perform tilde expansion on a file name or path.
*
Expand Down
12 changes: 12 additions & 0 deletions src/file-utils.h
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,18 @@ teco_file_normalize_path(gchar *path)

gboolean teco_file_is_visible(const gchar *path);

/**
* Get absolute path of the program executable.
*
* This may return the current working directory on
* unsupported platforms.
*
* @return Newly-allocated path.
*/
gchar *teco_file_get_program_path(void);

gchar *teco_file_get_datadir(void);

gchar *teco_file_expand_path(const gchar *path);

/**
Expand Down
32 changes: 11 additions & 21 deletions src/interface-gtk/interface.c
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,7 @@
#include "sciteco.h"
#include "error.h"
#include "string-utils.h"
#include "file-utils.h"
#include "cmdline.h"
#include "qreg.h"
#include "ring.h"
Expand Down Expand Up @@ -1124,6 +1125,8 @@ teco_interface_event_loop(GError **error)
}
g_assert(scitecoconfig.data != NULL);

g_autofree gchar *datadir = teco_file_get_datadir();

/*
* Initialize the CSS variable provider and the CSS provider
* for the included fallback.css.
Expand All @@ -1138,14 +1141,7 @@ teco_interface_event_loop(GError **error)
if (!g_file_test(user_css_file, G_FILE_TEST_IS_REGULAR)) {
/* use fallback CSS */
g_free(user_css_file);
/*
* FIXME: See above for icons.
*/
#ifdef G_OS_WIN32
user_css_file = g_build_filename(scitecoconfig.data, "fallback.css", NULL);
#else
user_css_file = g_build_filename(SCITECODATADIR, "fallback.css", NULL);
#endif
user_css_file = g_build_filename(datadir, "fallback.css", NULL);
}

GtkCssProvider *user_css_provider = gtk_css_provider_new();
Expand All @@ -1170,33 +1166,27 @@ teco_interface_event_loop(GError **error)
/*
* FIXME: This is necessary so that the icon themes are found in the same
* directory as sciteco.exe.
* This fails of course when $SCITECOCONFIG is changed.
* We should perhaps always use the absolute path of sciteco.exe.
* If you want to install SciTECO differently, you can still set
* $XDG_DATA_DIRS.
*
* FIXME FIXME FIXME: This is also currently broken.
*/
//g_autofree char *theme_path = g_build_filename(scitecoconfig.data, "icons");
//gtk_icon_theme_prepend_search_path(gtk_icon_theme_get_default(), theme_path);
g_autofree gchar *program_path = teco_file_get_program_path();
g_autofree gchar *theme_path = g_build_filename(program_path, "icons", NULL);
gtk_icon_theme_prepend_search_path(gtk_icon_theme_get_default(), theme_path);
#else
/*
* Load icons for the GTK window.
* This is not necessary on Windows since the icon included
* as a resource will be used by default.
*/
static const gchar *icon_files[] = {
SCITECODATADIR G_DIR_SEPARATOR_S "sciteco-48.png",
SCITECODATADIR G_DIR_SEPARATOR_S "sciteco-32.png",
SCITECODATADIR G_DIR_SEPARATOR_S "sciteco-16.png"
"sciteco-48.png", "sciteco-32.png", "sciteco-16.png"
};
GList *icon_list = NULL;

for (gint i = 0; i < G_N_ELEMENTS(icon_files); i++) {
GdkPixbuf *icon_pixbuf = gdk_pixbuf_new_from_file(icon_files[i], NULL);
g_autofree gchar *icon_file = g_build_filename(datadir, icon_files[i], NULL);
GdkPixbuf *icon_pixbuf = gdk_pixbuf_new_from_file(icon_file, NULL);

/* fail silently if there's a problem with one of the icons */
if (icon_pixbuf)
if (G_LIKELY(icon_pixbuf != NULL))
icon_list = g_list_append(icon_list, icon_pixbuf);
}

Expand Down
Loading

0 comments on commit 9cce7d2

Please sign in to comment.