Hello, Below is the final version of GCD for "Set search paths without
program wrappers", which means now this GCD start its deliberation
period (14 days), so team members please reply to
<76...@debbugs.gnu.org> with opinions.  Thanks!


link: 
https://git.savannah.gnu.org/cgit/guix/guix-consensus-documents.git/plain/004-set-search-paths-without-program-wrappers.md
title: Set search paths without program wrappers
id: 004
status: submitted
discussion: https://issues.guix.gnu.org/76428
authors: 宋文武 <iyzs...@envs.net>
sponsors: Maxim Cournoyer <maxim.courno...@gmail.com>
date-submitted: 2025-02-21
date: 2025-02-21
SPDX-License-Identifier: CC-BY-SA-4.0 OR GFDL-1.3-no-invariants-or-later
---

# Summary

Currently program wrappers are widely used to set search paths via
environment variables.  Those wrappers have some problems:

  - environment variables leakage from a process to its child
    processes;
  - duplicate entries in environment variables;
  - obscured process names.

To address those problems, we propose a way to set search paths with
some per-output configuration files, reduce the need of creating
program wrappers.


# Motivation

To make sure programs work out-of-the-box rather then depend on some
external settings, Guix encourages the use of [program 
wrappers](https://guix.gnu.org/manual/en/html_node/Build-Utilities.html#Wrappers)
when define packages.  In particular,  both `glib-or-gtk-build-system`
and `qt-build-system` includes a wrap phase to make program wrappers for every
GNOME and KDE program.

Those wrappers have some unsolved issues:

- [Program crash due to leaked environment 
variables](https://issues.guix.gnu.org/63203)
- [Duplicate entries in various environment 
variables](https://issues.guix.gnu.org/23118)
- [Ansible & others' problems with wrapped '.ansible-real' 
scripts](https://issues.guix.gnu.org/26752)

If we managed to find a way to set search paths without using program
wappers, then programs will be more robust.


# Detailed Design

In addition to environment variables, some programs also allow to set search
paths via configuration files, for example you can use
[path configuration files](https://docs.python.org/3/library/site.html)
to set `sys.path` for Python, and we have a per-output 
[`ld.so.cache`](https://guix.gnu.org/en/blog/2021/taming-the-stat-storm-with-a-loader-cache/)
to load shared libraries efficiently.  Inspired by them, we are going to patch
some programs and libraries, so that when they build a search path from an
environment variable, would also honor a per-output search path configuration
file.  The details are how to make those search path configuration files and
how to find them when an executable is running.

## Search path configuration files

We'll create search path configuration files under the `etc/search-path.d`
directory of each package output, with each file specify a search path.
The file name and its content are same to the corresponding environment
variable.  For example the output of the `gnome-console` package would have:

```
bin
  kgx
etc
  ld.so.cache
  search-paths.d
    GUIX_XDG_DATA_DIRS
    GUIX_GIO_EXTRA_MODULES
    GUIX_GTK4_PATH
lib
share
```

The content of its `GUIX_XDG_DATA_DIRS` file would be:
```
/gnu/store/...-shared-mime-info-2.3/share:/gnu/store/...-glib-2.78.0/share:/gnu/store/...-gsettings-desktop-schemas-44.0/share:/gnu/store/...-libadwaita-1.5.2/share:/gnu/store/...-gtk-4.14.5/share:/gnu/store/...-gnome-console-44.4/share
```

Those search path configuration files would be created by the package builder,
after the `install` phase, replace usages of `wrap-program` when possible.


## Find the location of the current executable

To find its search path configuration files when an executable is running,
we can first find the location of the executable.  Conveniently, Linux
provides a pseudo-file `/proc/self/exe` for this exact purpose, which works
well for ELF executables.   But for an interpreter script, `/proc/self/exe`
would return the file name of its interpreter instead of the script, so
we patch interpreters to set 2 environment variables:

  - `GUIX_INTERPRETER_FILE`: absolute file name of the interpreter
  - `GUIX_MAIN_SCRIPT_FILE`: absolute file name of the script

And when the executable's `/proc/self/exe` matches `GUIX_INTERPRETER_FILE`,
we can get the script file name from `GUIX_MAIN_SCRIPT_FILE`.  Alternatively,
we can try to construct the script file name from command line arguments, but
that won't work when you run a script using a relative file name and its
current working directory changed before we figure out the script file name.


## Set search paths with configuration files from search-paths.d

Finally, when the program want to build a search path from an
environment variable, we patch the code to search its `search-paths.d`
first, the result search path value will include both the content of
the search path configuration file and the environment variable.  This
usually happens in C/C++ libraries like GLib, GTK and Qt with a
`getenv` call, we need patch these `getenv` calls for each search path
we care.


## Implementation plan

A WIP implementation can be found in <https://issues.guix.gnu.org/75688>.

- Add a new function `g_guix_build_search_path_dirs` to GLib, which returns a
  search path as a list of file or directory names from a search path
  configuration file and an environment variable.
- Patch GLib to use `g_guix_build_search_path_dirs` for `GUIX_XDG_DATA_DIRS`,
  `GUIX_XDG_CONFIG_DIRS`, `GUIX_GIO_EXTRA_MODULES` and
  `GUIX_GSETTINGS_SCHEMA_DIR`.
- Patch Python to set `GUIX_INTERPRETER_FILE` and `GUIX_MAIN_SCRIPT_FILE`.
- Patch Qt to use `g_guix_build_search_path_dirs` for `GUIX_XDG_DATA_DIRS`,
  `GUIX_XDG_CONFIG_DIRS`, `GUIX_QT_PLUGIN_PATH`, `GUIX_QML_IMPORT_PATH`,
  `GUIX_QML2_IMPORT_PATH`.
- Modify `glib-or-gtk-build-system` to get rid of `wrap-program`.
- Modify `qt-build-system` to get rid of `wrap-program`.


# The Cost Of Reverting

We can revert to program wrappers by manually adding wrap phases on a case by
case basic, if needed.


# Drawbacks or Open Questions

If implemented, we would likely carry several custom patches for GLib,
GTK, Qt, Python, etc. forever.


This proposal focuses solving problems caused by program wrappers in desktop
environments, namely GNOME and KDE.  Individual `wrap-progam` usages are not
addressed.  We plan to handle that in build systems later, for example:

  - Handle `GUIX_GI_TYPELIB_PATH` and `GUIX_GDK_PIXBUF_MODULE_FILES` in
    `glib-or-gtk-build-system` without wrappers.
  - Handle `GUIX_PYTHONPATH` in `python-build-system` without wrappers.


There are still ABI problems caused by environment variables from
profiles, which may be addressed later as suggested by Maxime Devos in
<https://issues.guix.gnu.org/63203#5>.

Reply via email to