The library linking

The library systems in current operating systems suffer from many bugs and inconsistencies. They are buggy, broken and hard to use. And all these problems add unnecessary burden to the developers so they are distracted from their true goals.

Linking against libraries

Under all operating systems available today (at least all of them I seen in my life) the programmer needs to know what libraries are used and tell the complier to link against them explicitly. If you forget to tell it about one library, the compilation fails in linking stage with a missing symbol. If you specify some libraries that are in fact not needed, no error is reported but the resulting executable is larger (when linking statically) or an unneeded dependency of the resulting program binary on the unneeded library is created (when linking dynamically).

This is not a big problem, when there are one or two libraries used by the program. But large software projects need to use code from many libraries (this list can reach hundreths of items in size for very large projects) and the management of the list of the needed libraries quickly becomes unfeasible. The true problem shows up when the developer is faced to indirect library references such as "libA uses libB and libB uses libC but the program only uses libA, but not libB nor libC". Some platforms want the user to mention all such libraries to the compiler (in our example all three libraries are required to be mentioned).

The library system on many operating systems is so fragile and error prone that programmers often decide to copy the needed code into their project rather than link against the library. Some libraries are often copied verbatim into the software that uses them, especially when they are quite small. This copying practice avoids problems with fragile library systems but creates another problems with the recency of such copied libraries. The libraries often, once copied, go obsolete and suffer from bugs and vulnerabilities discovered after the library was copied. Also the advantages of shared libraries are getting faded out by this phenomena.

Under OSHS there are strict rules on how the libraries are written and how the programs can use them. These strict rules allow the build system to determine the list of needed libraries by looking at the source code of the software. Even indirect library referencies can be obtained automatically by looking at the libraries installed in the system. There is no need to externally learn the compiler and/or the build system about the used libraries anymore.

The symbol visibility

Another problem with library systems available today is the visibility of the symbols defined by the library. A symbol can be either local to one module in the library or global to the whole program. There is no way to create a symbol that is local to the library as a whole but nothing else. This means that if an internal library symbol has to be shared between more than one module, it must be made a public symbol.

This design bug of current library systems leads to all sorts of problems. It is too easy to abuse the fact that some of the internal library symbols are visible to the program that uses the library. But if the program uses symbols that are internal to the library, the program will no longer be compatible with the library when the symbol disappears or changes meaning.

At the other side of this problem are all these name clash problems, which are the reason of using strangely mangled names for the library public symbols such as SDL_initialize or pthread_sys_kill_thread. These names must be mangled to lower the chance being hit with another library; however this will not eliminate this threat completely.

In OSHS no such strangely mangled names are needed. The compiler and the linker automatically know which name is from which library. And when they don't know (because of a name clash in a particular module, for example when the module imports two modules from two different libraries (say foo and bar) that both declare a name (say Initialize() function)), a classified name can (and must) be used to guide the build system to the correct symbol (in our example foo.Initialize if the developer wants to use Initialize() from the foo library or bar.Initialize if he wants the one from bar).