about summary refs log tree commit diff
path: root/pkgs/games/steam/fhsenv.nix
blob: 6a4a1e002058f83bf1939b4db0a3f9aee21fee6e (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
{ lib, stdenv, writeShellScript, buildFHSEnv, steam, mesa-demos-i686
, steam-runtime-wrapped, steam-runtime-wrapped-i686 ? null
, extraPkgs ? pkgs: [ ] # extra packages to add to targetPkgs
, extraLibraries ? pkgs: [ ] # extra packages to add to multiPkgs
, extraProfile ? "" # string to append to profile
, extraPreBwrapCmds ? "" # extra commands to run before calling bubblewrap (real default is at usage site)
, extraBwrapArgs ? [ ] # extra arguments to pass to bubblewrap (real default is at usage site)
, extraArgs ? "" # arguments to always pass to steam
, extraEnv ? { } # Environment variables to pass to Steam

# steamwebhelper deletes unrelated electron programs' singleton cookies from /tmp on startup:
# https://github.com/ValveSoftware/steam-for-linux/issues/9121
, privateTmp ? true # Whether to separate steam's /tmp from the host system

, withGameSpecificLibraries ? true # include game specific libraries
}@args:

let
  commonTargetPkgs = pkgs: with pkgs; [
    # Needed for operating system detection until
    # https://github.com/ValveSoftware/steam-for-linux/issues/5909 is resolved
    lsb-release
    # Errors in output without those
    pciutils
    # run.sh wants ldconfig
    glibc_multi.bin
    # Games' dependencies
    xorg.xrandr
    which
    # Needed by gdialog, including in the steam-runtime
    perl
    # Open URLs
    xdg-utils
    iana-etc
    # Steam Play / Proton
    python3
    # Steam VR
    procps
    usbutils

    # It tries to execute xdg-user-dir and spams the log with command not founds
    xdg-user-dirs

    # electron based launchers need newer versions of these libraries than what runtime provides
    mesa
    sqlite
  ] ++ extraPkgs pkgs;

  ldPath = lib.optionals stdenv.hostPlatform.is64bit [ "/lib64" ]
  ++ [ "/lib32" ]
  ++ map (x: "/steamrt/${steam-runtime-wrapped.arch}/" + x) steam-runtime-wrapped.libs
  ++ lib.optionals (steam-runtime-wrapped-i686 != null) (map (x: "/steamrt/${steam-runtime-wrapped-i686.arch}/" + x) steam-runtime-wrapped-i686.libs);

  # Zachtronics and a few other studios expect STEAM_LD_LIBRARY_PATH to be present
  exportLDPath = ''
    export LD_LIBRARY_PATH=${lib.concatStringsSep ":" ldPath}''${LD_LIBRARY_PATH:+:}$LD_LIBRARY_PATH
    export STEAM_LD_LIBRARY_PATH="$STEAM_LD_LIBRARY_PATH''${STEAM_LD_LIBRARY_PATH:+:}$LD_LIBRARY_PATH"
  '';

  # bootstrap.tar.xz has 444 permissions, which means that simple deletes fail
  # and steam will not be able to start
  fixBootstrap = ''
    if [ -r $HOME/.steam/steam/bootstrap.tar.xz ]; then
      chmod +w $HOME/.steam/steam/bootstrap.tar.xz
    fi
  '';

  envScript = ''
    # prevents various error messages
    unset GIO_EXTRA_MODULES

    # This is needed for IME (e.g. iBus, fcitx5) to function correctly on non-CJK locales
    # https://github.com/ValveSoftware/steam-for-linux/issues/781#issuecomment-2004757379
    GTK_IM_MODULE='xim'
  '' + lib.toShellVars extraEnv;

in buildFHSEnv rec {
  name = "steam";

  # Steam still needs 32bit and various native games do too
  multiArch = true;

  targetPkgs = pkgs: with pkgs; [
    steam
    # License agreement
    zenity
  ] ++ commonTargetPkgs pkgs;

  multiPkgs = pkgs: with pkgs; [
    # These are required by steam with proper errors
    xorg.libXcomposite
    xorg.libXtst
    xorg.libXrandr
    xorg.libXext
    xorg.libX11
    xorg.libXfixes
    libGL
    libva
    pipewire

    # steamwebhelper
    harfbuzz
    libthai
    pango

    lsof # friends options won't display "Launch Game" without it
    file # called by steam's setup.sh

    # dependencies for mesa drivers, needed inside pressure-vessel
    mesa.llvmPackages.llvm.lib
    vulkan-loader
    expat
    wayland
    xorg.libxcb
    xorg.libXdamage
    xorg.libxshmfence
    xorg.libXxf86vm
    elfutils

    # Without these it silently fails
    xorg.libXinerama
    xorg.libXcursor
    xorg.libXrender
    xorg.libXScrnSaver
    xorg.libXi
    xorg.libSM
    xorg.libICE
    curl
    nspr
    nss
    cups
    libcap
    SDL2
    libusb1
    dbus-glib
    gsettings-desktop-schemas
    ffmpeg
    libudev0-shim

    # Verified games requirements
    fontconfig
    freetype
    xorg.libXt
    xorg.libXmu
    libogg
    libvorbis
    SDL
    SDL2_image
    glew110
    libdrm
    libidn
    tbb
    zlib

    # SteamVR
    udev
    dbus

    # Other things from runtime
    glib
    gtk2
    bzip2
    flac
    libglut
    libjpeg
    libpng
    libpng12
    libsamplerate
    libmikmod
    libtheora
    libtiff
    pixman
    speex
    SDL_image
    SDL_ttf
    SDL_mixer
    SDL2_ttf
    SDL2_mixer
    libappindicator-gtk2
    libdbusmenu-gtk2
    libindicator-gtk2
    libcaca
    libcanberra
    libgcrypt
    libunwind
    libvpx
    librsvg
    xorg.libXft
    libvdpau

    # required by coreutils stuff to run correctly
    # Steam ends up with LD_LIBRARY_PATH=/usr/lib:<bunch of runtime stuff>:<etc>
    # which overrides DT_RUNPATH in our binaries, so it tries to dynload the
    # very old versions of stuff from the runtime.
    # FIXME: how do we even fix this correctly
    attr
    # same thing, but for Xwayland (usually via gamescope), already in the closure
    libkrb5
    keyutils
  ] ++ lib.optionals withGameSpecificLibraries [
    # Not formally in runtime but needed by some games
    at-spi2-atk
    at-spi2-core   # CrossCode
    gst_all_1.gstreamer
    gst_all_1.gst-plugins-ugly
    gst_all_1.gst-plugins-base
    json-glib # paradox launcher (Stellaris)
    libxkbcommon # paradox launcher
    libvorbis # Dead Cells
    libxcrypt # Alien Isolation, XCOM 2, Company of Heroes 2
    mono
    ncurses # Crusader Kings III
    openssl
    xorg.xkeyboardconfig
    xorg.libpciaccess
    xorg.libXScrnSaver # Dead Cells
    icu # dotnet runtime, e.g. Stardew Valley

    # screeps dependencies
    gtk3
    zlib
    atk
    cairo
    gdk-pixbuf

    # Prison Architect
    libGLU
    libuuid
    libbsd
    alsa-lib

    # Loop Hero
    # FIXME: Also requires openssl_1_1, which is EOL. Either find an alternative solution, or remove these dependencies (if not needed by other games)
    libidn2
    libpsl
    nghttp2.lib
    rtmpdump
  ]
  # This needs to come from pkgs as the passed-in steam-runtime-wrapped may not be the same architecture
  ++ pkgs.steamPackages.steam-runtime-wrapped.overridePkgs
  ++ extraLibraries pkgs;

  extraInstallCommands = lib.optionalString (steam != null) ''
    mkdir -p $out/share/applications
    ln -s ${steam}/share/icons $out/share
    ln -s ${steam}/share/pixmaps $out/share
    ln -s ${steam}/share/applications/steam.desktop $out/share/applications/steam.desktop
  '';

  profile = ''
    # Workaround for issue #44254 (Steam cannot connect to friends network)
    # https://github.com/NixOS/nixpkgs/issues/44254
    if [ -z ''${TZ+x} ]; then
      new_TZ="$(readlink -f /etc/localtime | grep -P -o '(?<=/zoneinfo/).*$')"
      if [ $? -eq 0 ]; then
        export TZ="$new_TZ"
      fi
    fi

    # udev event notifications don't work reliably inside containers.
    # SDL2 already tries to automatically detect flatpak and pressure-vessel
    # and falls back to inotify-based discovery [1]. We make SDL2 do the
    # same by telling it explicitly.
    #
    # [1] <https://github.com/libsdl-org/SDL/commit/8e2746cfb6e1f1a1da5088241a1440fd2535e321>
    export SDL_JOYSTICK_DISABLE_UDEV=1
  '' + extraProfile;

  runScript = writeShellScript "steam-wrapper.sh" ''
    if [ -f /etc/NIXOS ]; then   # Check only useful on NixOS
      ${mesa-demos-i686}/bin/glxinfo 2>&1 | grep -q Error
      # If there was an error running glxinfo, we know something is wrong with the configuration
      if [ $? -eq 0 ]; then
        cat <<EOF > /dev/stderr
    **
    WARNING: Steam is not set up. Add the following options to /etc/nixos/configuration.nix
    and then run \`sudo nixos-rebuild switch\`:
    {
      hardware.graphics.enable32Bit = true;
      hardware.pulseaudio.support32Bit = true;
    }
    **
    EOF
      fi
    fi

    ${exportLDPath}
    ${fixBootstrap}

    set -o allexport # Export the following env vars
    ${envScript}
    exec steam ${extraArgs} "$@"
  '';

  inherit privateTmp;

  extraPreBwrapCmds = ''
    install -m 1777 -d /tmp/dumps
  '' + args.extraPreBwrapCmds or "";

  extraBwrapArgs = [
    "--bind-try /etc/NIXOS /etc/NIXOS" # required 32bit driver check in runScript
    "--bind-try /tmp/dumps /tmp/dumps"
  ] ++ args.extraBwrapArgs or [];

  meta =
    if steam != null
    then
      steam.meta // lib.optionalAttrs (!withGameSpecificLibraries) {
        description = steam.meta.description + " (without game specific libraries)";
        mainProgram = "steam";
      }
    else {
      description = "Steam dependencies (dummy package, do not use)";
    };

  passthru.steamargs = args;
  passthru.run = buildFHSEnv {
    name = "steam-run";

    targetPkgs = commonTargetPkgs;
    inherit multiArch multiPkgs profile extraInstallCommands extraBwrapArgs;

    runScript = writeShellScript "steam-run" ''
      run="$1"
      if [ "$run" = "" ]; then
        echo "Usage: steam-run command-to-run args..." >&2
        exit 1
      fi
      shift

      ${exportLDPath}
      ${fixBootstrap}

      set -o allexport # Export the following env vars
      ${envScript}
      exec -- "$run" "$@"
    '';

    meta = (steam.meta or {}) // {
      description = "Run commands in the same FHS environment that is used for Steam";
      mainProgram = "steam-run";
      name = "steam-run";
      # steam-run itself is just a script that lives in nixpkgs (which is licensed under MIT).
      # steam is a dependency and already unfree, so normal steam-run will not install without
      # allowing unfree packages or appropriate `allowUnfreePredicate` rules.
      license = lib.licenses.mit;
    };
  };
}