As mentioned in https://wildfiregames.com/forum/index.php?/topic/24985-installation-on-centos-7, there are times when a user may have two versions of a library installed - one installed from the OS package repository, and one that was installed manually.
To summarize:
- A user has CentOS 7, the latest stable release of the CentOS linux distribution (at the time of writing this), and wishes to compile pyrogenesis.
- One of the requirements of pyrogenesis is boost, with a minimum version of v1.57.
- Unfortunately, the most recent version of boost available from the CentOS (and EPEL) repos is v1.53.
- The recommended action is to find and use a more recent version of boost. The easiest way is to compile it oneself.
- However, there are various other applications of CentOS that also use boost, and are compiled against the repo-supplied version. Thus, replacing the repo-supplied-version with a newer version is not recommended.
- Thanks to the Filesystem Hierarchy Standard, there is a way round this:
- repo-provided libraries are installed under /usr/lib
- locally-generated libraries are installed under /usr/local/lib
- The user compiles and installs this more-up-to-date version of boost under /usr/local/lib
- The user then attempts to compile pyrogenesis...
...and this is where we hit a snag.
When it comes to linking in libraries, premake (via the generated {component}.make files) informs the compile-time linker (ld [1]) what libraries are needed, and the linker then attempts to find and link them.
ld (by default) searches for these libraries in a set of "standard directories", and searches them in a certain order. This is to be expected: the compiler (gcc) does something similar when looking for the correct headers to include. The standard directories that both gcc and ld search through are even similar. The problem arises in the order that the locations are searched. The default search order for ld is as follows [2]:
- /usr/lib
- /usr/local/lib
To put it another way, ld searches amongst the repo-provided libraries before considering any locally-generated ones. Thus, when asked to link in the boost libraries, ld finds the version of boost installed from the repo first and links that, instead of the more up-to-date version generated locally.
The solution is to tell the linker to look in /usr/local/lib first.
As this doesn't just affect boost, but potentially other locally-generated libraries as well, this revision adds a new argument to update-workspaces.sh: --prefer-local-libs that tells premake to add -L/usr/local/lib to the flags passed to the linker.
It should be noted that this only resolves compile-time linking. When pyrogenesis is run after being tied to a library located within /usr/local/lib, then the run-time linker (ld.so) will complain that it can't find the dependency.
There are two ways around this:
- Use -rpath instead of -L. This will possibly bring the ire of Fedora packagers down on us[3], and we've already had a ticket (#1421) trying to remove -rpath from our build system. (We use it to link the bundled spidermonkey.)
- Tell the user to create a suitable file in /etc/ld.so.conf.d/
- [1] - Not to be confused with ld.so, the run-time (or dynamic) linker that determines and loads program dependencies at the point of program execution.
- [2] - ld --verbose | grep SEARCH_DIR | tr -s ' ;' '\n' (For simplicity, I've excluded the architecture and distribution-specific paths.)
- [3] - https://docs.fedoraproject.org/en-US/packaging-guidelines/#_beware_of_rpath