Create shared object interfaces

This page is a capture in the next bucket of the product backlog — a pre-sprint idea, not yet pulled into a sprint as a story.

At present we are building shared objects / DLLs for the ores components, but we did not bother defining proper interfaces, exporting symbols etc. This causes problems on windows:

LINK : fatal error LNK1104: cannot open file 'projects\ores.utility\ores.utility.lib'

This is happening because we are not exporting explicitly any symbols. To fix this we did a hack:

if(WIN32 AND MSVC)
    # Export all symbols on windows for now. Bit of a hack.
    set(CMAKE_WINDOWS_EXPORT_ALL_SYMBOLS ON)
endif()

The right solution for this is to annotate all the public types of each SO correctly, exporting symbols for all platforms:

Deep seek analysis:

Yes, Boost provides a cross-platform wrapper for exporting symbols using the
`BOOST_SYMBOL_EXPORT` macro from the **Boost.DLL** library. This macro abstracts
away the compiler-specific keywords required for different platforms.

### 🗂️ Boost's Cross-Platform Symbol Exporting

To export a symbol, you use the `BOOST_SYMBOL_EXPORT` macro in your code. Under
the hood, it expands to the correct compiler-specific attribute:

- On **Windows** with MSVC, it becomes `__declspec(dllexport)`
- On **macOS** and **Linux** with GCC/Clang, it becomes `__attribute__((visibility("default")))`

Here is a basic example of how to use it to export a global variable:

```cpp
#include <boost/config.hpp> // For BOOST_SYMBOL_EXPORT

class my_plugin_api {
    // Your interface definition
};

namespace my_namespace {
    class my_plugin_sum : public my_plugin_api {
        // Implementation
    };

    // Export the 'plugin' variable
    extern "C" BOOST_SYMBOL_EXPORT my_plugin_sum plugin;
    my_plugin_sum plugin;
}
```
*Note: The `extern "C"` is used here to prevent C++ name mangling, making the symbol name
predictable for tools that use C linkage. This is often crucial for a library's public API.*

For exporting factory functions, Boost offers the `BOOST_DLL_ALIAS` macro, which
is often more convenient:

```cpp
#include <boost/dll/alias.hpp> // For BOOST_DLL_ALIAS

namespace my_namespace {
    class my_plugin_aggregator : public my_plugin_api {
        // Implementation
    };

    // Factory function
    boost::shared_ptr<my_plugin_api> create() {
        return boost::shared_ptr<my_plugin_aggregator>(new my_plugin_aggregator());
    }

    // Export the factory function with the alias "create_plugin"
    BOOST_DLL_ALIAS(my_namespace::create, create_plugin)
}
```

### 💡 A Complementary Approach: Controlling Visibility

While Boost's macro solves the declaration problem, for finer control and to
minimize your shared library's public API, combine it with compiler flags that
hide all symbols by default.

- **On Linux and other ELF platforms**, use the `-fvisibility=hidden` flag. You
  can then use a **linker version script** to explicitly list the symbols you
  want to export.
- **On macOS**, use the `-fvisibility=hidden` flag and an **exported symbols
  list** with `-exported_symbols_list` during linking.
- **On Windows**, symbol visibility is typically controlled explicitly via
  `__declspec(dllexport)` or a module definition (.def) file, which
  `BOOST_SYMBOL_EXPORT` already handles.

Setting default visibility to hidden helps create a cleaner, more efficient
library by reducing its footprint, improving load times, and avoiding potential
symbol conflicts.

### 🔧 Summary

For a complete cross-platform solution:

1. **Use Boost.DLL macros**: Incorporate `BOOST_SYMBOL_EXPORT` or
   `BOOST_DLL_ALIAS` in your code to handle platform-specific export keywords.
2. **Hide symbols by default**: Compile your shared library with
   `-fvisibility=hidden` on Linux and macOS. This works in conjunction with the
   Boost macros.
3. **Use version scripts (optional)**: For maximum control on ELF platforms
   (Linux) or via an exported symbols list on macOS, use these linker features
   to define a precise public API.

I hope this helps you build your cross-platform shared library! If you have more
questions about using the Boost.DLL library for loading these symbols at
runtime, feel free to ask.

Links:

Emacs 29.1 (Org mode 9.6.6)