Every time I add a development library (or any other application) that is not found in my distro‘s repositories, I ask myself how troublesome it will be. If you’re really lucky, it comes in a package (and repository) compatible with the target distribution (like a Debian package or a RPM) and everything is just fine: you install it from the package manager, and that’s it. But if not, you have to download a tarball from some (more or less trusted) location like Sourceforge. It usually comes with a rather well designed set of configure, make, and (sudo) make install scripts that reduces configuration to little more than launching the configuration script, check for any unmet dependencies, add them and rerun the configuration script until they are all met, and then make install performs a smart, standard location install and you’re done. You won’t have the automagical upgrades with everything else, but you can go on with your life.
Then again sometimes you have to install a library (or application) that either has a half-baked installation script, or is incompatible with your distro, or, cerise sur le gâteau, both. And, just to aggravate you just fine, it installs to a non-standard location requiring you to specify include and library paths in your make files or just to invoke the application. And, of course, default location will change from from /usr/local/shared/thislib/ to /usr/shared/include/thislib between version 2.1.5 and 2.1.6, just to make sure to break just about everything you set up.
Configuring the environment is not always very complicated when you’re doing this for your machine and your controlled modifications. However, if you have to deal with “exotic” code that has dependencies that are not in the official repositories (happens all the time with Red Hat), you have to make custom installations of those packages, and they’re not always smart enough to install in standard locations. Worse, if you’re not root on your machine, you have to resort to locations such as /home/yourname/etc/ and /home/yourname/lib/ to mock the FHS, but they don’t play all that well with default configurations. In fact, they’re just not supported.
Sometimes, it suffices to add a new path to the PATH environment variable, or maybe to LD_LIBRARY_PATH and we’re done. For some, you have to change LANG as well, plus a couple of other things, plus other application-specific environment variables, plus… In any cases, you really do not want to this by hand every time you invoke a given application.
I can see three options:
- Stuffing .bashrc, or .profilerc or a similar file that determines the contents of the current shell’s environment. This has the advantage of making sure all needed configurations (adding to paths, LD_LIBRARY_PATH, aliases, shell functions, etc.) are available in each shell you open. The main disadvantage is that it eventually ends up cluttered and it is hard to deal with mutually exclusive / conflicting setups. Shell functions can help, but they’re cumbersome to maintain and furthermore offer only a partial solution: if you affect directly the current shell’s environment, it’s about impossible to ‘undo’ changes reliably.
- A configuration script to invoke in the desired shell or environment. It has the advantages of limiting the contamination to the current context, of dealing with possibly conflicting configuration by not enabling them by default and by segregating them on a by-shell basis if necessary. It has the disadvantage that it must be sourced, not merely invoked, to make the changes appear in the current shell (and I found that testing reliably and portably how the script is executed—invoked or sourced—rather difficult). You must also remember to source it, since it’s not automagically performed.
- A wrapper will let you more or less transparently invoke the desired applications while calling any number of scripts, inspect any number of environment variables, and use as many shell functions you want. Well written, it ensures the correct environment for your application every time. It also has the advantage that it can be used from an application launcher (a window-manager specific thingie that let you start applications from a desktop icon or a global shortcut key) without explicitly opening a shell. It has the further advantage of limiting the modifications to the environment to the sub-shell that runs the wrapper and its children, leaving your original environment intact upon exit. It has the disadvantage of being custom-coded for every (group of) application(s) and it is therefore a rather error-prone process.
I am sure we could come up with hybrid solutions that are better suited for special cases, but the fact remains that it’s always a subtle, broken, balancing act of a script when you deal with software with incomplete or non-standard install procedures—the problem can be aggravated when you’re not root, but that’s another story.