From: cek@sdc.boeing.com (Conrad Kimball)
Newsgroups: comp.windows.x
Subject: Location-indepedent X installation
Date: 5 Sep 92 00:26:51 GMT
Organization: Boeing Computer Services, Seattle, WA

Hello X-Perts:

I'd like to be able to build X such that the resultant installable
files can be installed in any target directory and executed from that
directory with very minor impact on my users or my sysadmins.  I'd also
like to be able to move X around in my filesystems after it has been
installed, again with minor impact.  Furthermore, I'd like to be able
to install multiple versions (say, R4, R5, and OpenWindows) and allow
users to use applications from each version in the same session,
without the versions stepping on each other's toes.

Unfortunately there are several problems:

1.  If I build X (as delivered by MIT) the resultant object code
    contains a number of hard-coded path names such as
    "/usr/lib/X11/rgb.txt", "/usr/lib/X11/XKeysymDB", etc.  In some
    cases X allows the user to specify an alternate path using an
    environment variable, and in other cases the path is simply
    immutable at runtime.  This means that I've got to define, at build
    time, the directory in which X will live :(.

    The R3->R4->R5 progression has gradually provided more environment
    variables to override the compiled-in paths, but even R5 still has
    some run-time immutable paths (e.g. for XErrorDB), and xdpr still
    contains hard-coded paths of "/usr/bin/X11".

    Some games can be played using symbolic links to separate the
    physical directory in which X is installed from the compiled-in
    logical directory for which it was built, but this is a gross
    hack that our sysadmins hate.

2.  If and when there is a complete set of environment variables capable
    of overriding all the compiled-in paths, there are still the
    problems that this set is too big (i.e. more than 1) and is highly
    confusing to all but X-Perts, and that this set affects all
    applications that are run in that session, regardless of whether it
    is an R4, R5, or OpenWindows application.

Better by far, IMHO, would be a single environment variable that
specifies the home directory in which X lives, and which uniformly
influences the default paths built into X at build time.

Sun's OpenWindows seems to have adopted this approach, albeit only
partially.  $OPENWINHOME directly controls only some elements, leaving
the control of most elements to the X-provided set of environment
variables which the openwin(1) script will conveniently set for you
based on the value of $OPENWINHOME.  This approach of simply setting
other, existing environment variables is inadequate since it can cause
conflicts with other versions of X that I may wish to run in the same
session.

Some of these environment variables (e.g. XKEYSYMDB and XCMSDB in R5)
specify a single file, so I must either have all my applications use
the same file or futz around with the environment variables every time
I start an application.  Even for variables like XFILESEARCHPATH, that
specify a set of paths, there is still the question of search order.
For OpenWindows applications I want to use the OpenWindows application
defaults files and for R5 I want to use the R5 application defaults,
yet the XFILESEARCHPATH mechanism requires me to specify a specific
precedence, or else again futz around with the environment variables
every time I start an application.

I'd like to propose the following.  Comments are most welcome, either
critiquing these proposals or discussing how others have approached
the problem.

PROPOSAL 1
----------

1.  Arrange for all compiled-in paths to contain a token which will,
    at run time, be replaced by the value of this single environment
    variable.  Some compiled-in paths such as XFILESEARCHPATH would
    normally have multiple occurences of this token.  It seems only
    natural to use shell "$name" or "${name}" syntax for this
    substitution token.

    This can be accomplished by the DestDir mechanism in R4 or the
    ProjectRoot mechanism in R5, which feed the definitions of Makefile
    variables such as $(ADMDIR), $(BINDIR), $(FONTDIR), $(INCDIR),
    $(INCROOT), $(LIBDIR), $(MANPATH), $(USRLIBDIR), and
    $(XAPPLOADDIR), which are in turn passed on to the .c files via the
    "-Dname=value" mechanism on the cc command line.  Some changes to
    the Imakefiles will likely be necessary to protect "-Dname=value"
    values from the shell.

2.  Wherever these compiled-in strings are used in X, the code must
    first pass the compiled-in string through an environment variable
    expansion process and then use the resulting string.
    
    If the code is a shell script rather than a .c file the shell does
    this expansion automatically if the substitution token uses the
    shell syntax.  For .c files, there would be a new library function
    that accepts an unexpanded string and returns an expanded string.
    Then in XErrDes.c, for example, it would be trivial to replace:

	db = XrmGetFileDatabase(ERRORDB);

    with:

	db = XrmGetFileDatabase(XExpandVars(ERRORDB));

3.  To extend the substitution token shell syntax even further, the
    environment variable expansion function would also recognize the
    "${name:-word}" syntax, arbitrarily nested.  Then one could build
    and install R4 with DestDir set to something like:

	${X11R4HOME:-${X11HOME:-/usr/local}}

    and R5 with ProjectRoot set to:

	${X11R5HOME:-${X11HOME:-/usr/local}}

    These would expand to the value of $X11R4HOME/$X11R5HOME if that
    was defined, or else $X11HOME if that was defined, or "/usr/local"
    if neither environment variable was defined.  This would make it
    easy for a user to run both R4 and R5 in the same session and each
    version of X would be totally self-contained.  If I only wanted
    to run one version, I could leave $X11R4HOME/$X11R5HOME undefined
    and set $X11HOME to the version I want.

4.  The result is that each build/install of X is self-contained,
    self-referential, and can be freely installed in or moved to any
    directory, at the discretion of the sysadmin.

    The downside is that, at least for the set of compiled-in paths,
    unwanted substitution may occur.  If using the shell syntax that
    means paths could no longer contain '$'.  The substitution
    mechanism could be given an escape character (as in the shell), or
    we can ignore the problem, since the set of affected paths is small
    and has historically never contained a '$'.


PROPOSAL 2
----------

1.  Build compiled-in paths with a substitution token, as above.

2.  Rather than doing substitution before the compiled-in path is
    used, let that compiled-in path be used as is.  Instead, wherever
    X does an fopen(3) or open(2), perform environment variable
    substitution on the path at that point.

    This handles all the cases that the first proposal does, and in
    addition it automatically provides environment variable expansion
    on any path that is opened by X.
    
    Pro:  Reduces the need for applications to do explicit substitution
	  of those paths that will be passed to X functions, such as
	  application resources.

    Pro:  Allows substitution on paths specified by widget resources,
	  such as the Athena Label "bitmap" resource, that are extremely
	  awkward to do in the application.  This can be a big win for
	  application defaults files that contain path names.

    Con:  Extends the potential impact of unwanted substitution beyond
	  the limited set of compiled-in paths, possibly to all files
	  manipulated by the application (could be messy for something
	  like a file selection box).


Your thoughts, please...

--
Conrad Kimball		| Unix Server Tech Services, Boeing Computer Services
cek@sdc.boeing.com	| P.O. Box 24346, MS 7A-35
(206) 865-6410		| Seattle, WA  98124-0346