L XF SHELL
Revealing the shell behind the shell
In the last iteration of the shell, Ferenc Deák managed to reveal the password for his home computer…
OUR EXPERT
Ferenc Deák sees no way back from the C++ mayhem he brought upon readers with this quick and dirty shell, so you just have to accept it. C++.
QUICK TIP
The code for the shell can still be found at https://github. com/fritzone/lxf-shell.
In the first three parts of our mini series, the basic operational aspect of our shell was I solidly established, showcasing its proficiency in executing programs. Now our focus shifts towards integrating advanced features. We are happy to call in the heavy cavalry to extend the shell’s repertoire by a modular plugin architecture. With these refinements we not only broaden the range of tasks the shell can perform but also contribute to a more versatile and open environment, and provide a framework for anyone willing to enhance its functionality.
To properly implement a flexible and easy-to-use plugin architecture, we need to present another basic component of the Linux ecosystem: shared object files. These files, having the .so extension, are instrumental in constructing plugin architectures, offering a dynamic means to augment the existing software functionality. In a plugin system, these shared libraries serve as modular components, enabling developers to extend a base application without altering its core code.
The .so and the not so
Shared libraries are one of the few basic components of modern operating systems. In Linux (and other Unixlike OSes), they materialise as SO files; under Windows, they are the infamous DLL files. Generally, they are pivotal components of the OS, facilitating dynamic linking, a process where programs access libraries during runtime rather than compile time.
Dynamic linking enables flexibility and resource efficiency, as multiple programs can share (or link with) a common SO file dynamically. This encourages the reuse of code, particularly for system libraries and frequently employed functions. Changes to shared objects automatically apply to all linked programs, streamlining maintenance and reducing redundancy. During program execution, the dynamic linker/ loader, often referred to as ld.so or ld-linux.so, loads the necessary SO files into memory and resolves the required dependencies, thus reducing the memory footprint and startup time of the application.
Part four!
Don’t miss next issue, subscribe on page 16!
Shared object files adhere to a naming convention, typically lib.so.major.minor. Symbolic links, such as lib.so, point to the latest version, aiding in version management and compatibility.
Since CMake is our build system, here’s a snippet on how to build shared object files with it. Instead of add_ application , which was used until now, we simply use add_library , and also optionally specify the version: add_library(mylibrary SHARED source1.cpp source2.cpp) set_target_properties(mylibrary PROPERTIES VERSION 1.2.3 SOVERSION 1)
Here, CMakeLists.txt defines a shared library named mylibrary, and specifies source files to include.
Plugin loaders
One of the main benefits of shared libraries is that they can be dynamically loaded upon request without the need to explicitly link to them via a build system. This step delays the loading of the shared library until the user needs it, with the expense that extra code needs to be written, but it has the advantage that if the user (a client application) does not need the functionality provided by a specific library, it does not load it. This feature stands at the base of our plugin architecture: we will dynamically load the libraries (from now on referred to as plugins) when we start the application, without knowing how many of them we have, and we will create a common interface for these plugins in order to correctly integrate into our shell.