On Linux there are only 2 software interfaces which exist outside of the Kernel which I ever need access to: X11 (to open a window) and GL (to display graphics). Everything else can be done easily using direct system calls (inline assembly to make syscall). With the exception of X11 and GL, no need to even link to anything, as I don't use anything from libc (I use -nostdlib). For both X11 and GL I simply dlopen() and dlsym() what I need at runtime. Unfortunately to get access to dlopen() and dlsym() one must link to libdl.so. Linking to libdl.so adds a dependency on libc.so. Fail.
Why not just implement dlopen() and dlsym()? How complex could it be? Very complex. Even for the "tiny" C libraries. The uClibc source for libdl.c is only 1000+ lines, but depends on ldso which has over 100K of source.
In theory one could just statically link to a bit of uClibc which provides dlopen() and dlsysm() including the bits of ldso, except then one gets screwed by uClibc's LGPL license (you'd need to provide your program's object files to your customers so they can optionally relink to a later version of uClibc). This starts to hint at the bigger problem plague the industry: engineering systems which force or cause a complexity explosion.
On one side there is the complexity explosion of hardware. In theory an operating system's kernel would funnel this complexity through a very simple syscall API (which is what Linux does for instance). From this very simple system call API the funnel expands into dynamic linking then into C++ then into the nightmare of complexity of interconnected dependent libraries and software.
The root of the problem on the user-space end is dynamic linking.
Dynamic linking forces the interface between things to be one tied to the massive complexities of a serial programming language (take a look at the gcc ABI policy guidelines for C++). Massive in many aspects, including the over 200 MB install of tools required just to compile "hello world".
Core system interfaces like graphics APIs ideally should not be defined in a language, but rather in a protocol interfaced via simple kernel syscalls. Use open() to open the device, ioctl() to configure, mmap() to allocate memory to interface with the device including a space to communicate to the graphics API, etc. Likewise, user-space APIs should ideally be defined in a similar way with a defined data protocol or structure for communicating in memory.
Why not just implement dlopen() and dlsym()? How complex could it be? Very complex. Even for the "tiny" C libraries. The uClibc source for libdl.c is only 1000+ lines, but depends on ldso which has over 100K of source.
In theory one could just statically link to a bit of uClibc which provides dlopen() and dlsysm() including the bits of ldso, except then one gets screwed by uClibc's LGPL license (you'd need to provide your program's object files to your customers so they can optionally relink to a later version of uClibc). This starts to hint at the bigger problem plague the industry: engineering systems which force or cause a complexity explosion.
On one side there is the complexity explosion of hardware. In theory an operating system's kernel would funnel this complexity through a very simple syscall API (which is what Linux does for instance). From this very simple system call API the funnel expands into dynamic linking then into C++ then into the nightmare of complexity of interconnected dependent libraries and software.
The root of the problem on the user-space end is dynamic linking.
Dynamic linking forces the interface between things to be one tied to the massive complexities of a serial programming language (take a look at the gcc ABI policy guidelines for C++). Massive in many aspects, including the over 200 MB install of tools required just to compile "hello world".
Core system interfaces like graphics APIs ideally should not be defined in a language, but rather in a protocol interfaced via simple kernel syscalls. Use open() to open the device, ioctl() to configure, mmap() to allocate memory to interface with the device including a space to communicate to the graphics API, etc. Likewise, user-space APIs should ideally be defined in a similar way with a defined data protocol or structure for communicating in memory.