User:Vadcx/Linux change glibc version

From Official Factorio Wiki
Jump to navigation Jump to search

PLEASE NOTE: This is a DRAFT. If you follow these instructions, fix any issues or ask questions you have had along the way.

If you want to start Factorio 2.0 on an older Linux distro release (usually server OS distributions with long support cycles), you might encounter this:

user$ ./bin/x64/factorio

./bin/x64/factorio: /lib64/libm.so.6: version `GLIBC_2.29' not found (required by ./bin/x64/factorio)
./bin/x64/factorio: /lib64/libpthread.so.0: version `GLIBC_2.30' not found (required by ./bin/x64/factorio)

This error message means that Factorio was compiled with a newer GLIBC version and it's not found on your system. Generally, your entire operating system depends on one and only one GLIBC version that it has installed.

Preparation

Find your GLIBC version

user$ ldd --version

ldd (GNU libc) 2.24

Manual GLIBC compilation

Don't be afraid, there are enough guides out there. Warning: you must NOT "install" the freshly compiled GLIBC system-wide. You'll simply need it in a folder for Factorio to use.

Linux From Scratch is an elaborate and reliable book: https://www.linuxfromscratch.org/lfs/view/stable/chapter08/glibc.html

Official releases: https://ftp.gnu.org/gnu/glibc/

Solutions

Non-solution: don't replace your system-wide glibc

Everything depends on it and if it breaks, every single piece of your OS will stop working.

#1: Upgrade to a newer distro release

Not easy, but it's probably about time to update?

#2: Start Factorio with custom GLIBC using ldd

In short, you'll override the path to load a different GLIBC version.

This is the equivalent of "LD_PRELOAD" for regular dynamic libraries, but GLIBC is so fundamental to everything that it needs to be done differently.

Note: this works only because GLIBC strives to be backwards compatible in its ABI (Application Binary Interface). For other libraries, you would need to watch out for compilation settings and ABI changes: https://abi-laboratory.pro/index.php?view=timeline&l=glibc

Approach A

Follow "Side by Side glibc 2.18" by millisa & GodricSeer: https://forums.factorio.com/viewtopic.php?t=54654#p324493

It boils down to starting Factorio with "ld-linux-x86-64.so" yourself to override which GLIBC it will load. PATH=/opt/glibc-2.18/bin:$PATH LD_LIBRARY_PATH=/opt/glibc-2.18/lib:/usr/lib64 /opt/glibc-2.18/lib/ld-linux-x86-64.so.2 /home/factorio_user/factorio/bin/x64/factorio --create /home/factorio_user/factorio/saves/newmap16.zip

For our purposes the above should be equivalent to this (Factorio's binary is statically compiled):

user$ ~/f/s/b/x64 $ /opt/glib-2.40/bin/ld.so --library-path /opt/glib-2.40/lib ./factorio
Error: This is a headless executable, cannot start in graphical mode (use --start-server).

Downsides: Factorio will probably be unable to restart itself.

As a script:

#!/bin/sh
factorio_bin="$1"
echo "$1"
shift; # arguments to server start at $1 now

/opt/glib-2.40/bin/ld.so \
  --library-path /opt/glib-2.40/lib \
  "$factorio_bin" \
  "$@"

todo: variable for glib path

Other links:

Approach B

Patch the Factorio binary to request a different interpreter path of ld:

patchelf --set-interpreter /opt/glib-2.40/lib/ld-linux-x86-64.so.2 --set-rpath /opt/glib-2.40/lib factorio-patched

The below script patches it in-place and needs some refinement.

#!/usr/bin/env bash
SCRIPT_PATH=$(dirname "$0")
SCRIPT_PATH=$(readlink -f -- "$SCRIPT_PATH")
LD_LOADER=$(readelf -l "$SCRIPT_PATH/bin/x64/factorio" | grep -oP "\[Requesting program interpreter: (\K.*)(?=\])")
if [[ "$LD_LOADER" != "/opt/glib-2.40/lib/ld-linux-x86-64.so.2" ]]; then
  echo "Patching Factorio..."
  /usr/bin/patchelf \
    --set-interpreter \
    /opt/glib-2.40/lib/ld-linux-x86-64.so.2 \
    --set-rpath \
    /opt/glib-2.40/lib \
    "$SCRIPT_PATH/bin/x64/factorio"
fi
"$SCRIPT_PATH/bin/x64/factorio" "$@"

todo: variable for glib path, LC_ALL=C just in case (although readelf doesn't translate strings)

#3: Run Factorio in a chroot with custom GLIBC

Technically, you can have a whole different "universe" on your current system side-by-side, where all the software is compiled against another GLIBC version, separate from your ordinary system runtime.

This would be a proper solution and work for any other library with major breaking changes I suppose. But it's a lot of effort for a game server. Ain't nothing like a temporary and hacky workaround like #2, right?

Possible issues

Error configuring paths

Error configuring paths: There is no package core in /usr/share/factorio.

Factorio tries to determine its game folder and fails. A quick "./factorio --help" reveals this argument:

--executable-path PATH    Override autodetected __PATH__executable.
                          Usually not needed except on very weird systems.

Simply point it to the Factorio's binary folder: --executable-path /something/something/bin/x64/