fix: compilation with `BUILD_SHARED_LIBS` with MSVC
This fixes the compilation when building shared libraries instead of a statically linked executable. Building a shared library is required for #58[^1]. Since MSVC requires __declspec(dllexport), there were some linker errors. Additionally, there were some compiler errors about implicit special member functions being generated in include/dom/ (using clang-cl/lld-link as the compiler leads to much more helpful errors than cl/link).
For GCC-ish compilers, -fvisibility=hidden doesn't seem to be specified for mrdocs-core, because it's a static library. If it was specified, MRDOCS_DECL for GCC would need to be updated (similar to what CMake's GenerateExportHeader does).
Aside: A clang-format config would be great.
[^1]: Technically, the executable could still be statically linked while exporting the required symbols. That's basically what setting MRDOCS_BUILD_SHARED=ON without enabling BUILD_SHARED_LIBS does. I think ENABLE_EXPORTS would still be required for that executable to make sure an "import library" is created.
An automated preview of the documentation is available at https://776.mrdocs.prtest2.cppalliance.org/index.html
An automated preview of the documentation is available at https://776.mrdocs.prtest2.cppalliance.org/index.html
That's amazing, especially since it's now being checked in CI. The plugin system is not designed yet but it's a step we need to take. I'll review it in 2025.
Just had a look at this. The changes are great. These MRDOCS_DECLs were being tested at all. Just one question though: isn't the requirement https://github.com/cppalliance/mrdocs/issues/58 the other way around? That is, the compiled plugin is what needs to be a shared library but it doesn't really matter if mrdocs it's static. MrDocs only needs to load it when the system is implemented.
Yeah, that's what I initially thought, too. I was a bit confused by the BUILD_SHARED_LIBS option (this should only be honored for plugins, not for the core library). I think we shouldn't build a shared lib for mrdocs (core) at all, only for the plugins:
graph TD;
implib["mrdocs.lib<br>(import lib)"]
lib["mrdocs-core.lib<br>(static library with “public“ symbols)"]
lib---|linked to|mrdocs.exe;
mrdocs.exe---|derived|implib;
implib---|“linked“ to|plugin.dll;
mrdocs.exe---|loads|plugin.dll;
I'm not entirely sure what the equivalent of an import library on Linux and macOS is.
Yeah, that's what I initially thought, too. I was a bit confused by the BUILD_SHARED_LIBS option (this should only be honored for plugins, not for the core library).
Yes. If the user asks for BUILD_SHARED_LIBS when invoking CMake, we want to honor that. So that's what MRDOCS_DECL does.
I think we shouldn't build a shared lib for mrdocs (core) at all, only for the plugins:
Now, I'm not really sure about this. I think we can only find out once the plugin system is really implemented. But it's possible that mrdocs needs to be built with BUILD_SHARED_LIBS for plugins to work because the plugin will end up interacting with MrDocs' public API.
I'm not entirely sure what the equivalent of an import library on Linux and macOS is.
Yes. Shared libraries exist on Linux and MacOS. The API for interacting with them is what changes (but that's something to worry about when the plugin system is implemented). Boost.DLL abstracts these differences.
An automated preview of the documentation is available at https://776.mrdocs.prtest2.cppalliance.org/index.html
Now, I'm not really sure about this. I think we can only find out once the plugin system is really implemented. But it's possible that mrdocs needs to be built with BUILD_SHARED_LIBS for plugins to work because the plugin will end up interacting with MrDocs' public API.
To "just" support custom generators, exporting the symbols in the executable is enough. That's what enabling MRDOCS_BUILD_SHARED alone does. If the plugins need to be able to run the tool, then it needs to be a shared library.
Yes. Shared libraries exist on Linux and MacOS. The API for interacting with them is what changes (but that's something to worry about when the plugin system is implemented).
Yea, I wasn't sure how dynamic libraries on Linux and macOS would need to be compiled to use the provided functions. But it seems like one can target_link_libraries(library PRIVATE executable) and CMake does the rest.
Boost.DLL abstracts these differences.
LLVM also provides a facility to load dynamic libraries. That's how Clang loads its plugins.
Yea, I wasn't sure how dynamic libraries on Linux and macOS would need to be compiled to use the provided functions.
In CMake, that's transparent. You just ask CMake for shared libraries and it gives them to you.
LLVM also provides a facility to load dynamic libraries. That's how Clang loads its plugins.
That's nice. I haven't researched that yet, but I thought LLVM would have its version. LLVM comes with its implementation of almost all basic things.
Should this be .dll?
https://github.com/cppalliance/mrdocs/actions/runs/12588477114/job/35086468177?pr=776#step:17:397
An automated preview of the documentation is available at https://776.mrdocs.prtest2.cppalliance.org/index.html
An automated preview of the documentation is available at https://776.mrdocs.prtest2.cppalliance.org/index.html
An automated preview of the documentation is available at https://776.mrdocs.prtest2.cppalliance.org/index.html
An automated preview of the documentation is available at https://776.mrdocs.prtest2.cppalliance.org/index.html
An automated preview of the documentation is available at https://776.mrdocs.prtest2.cppalliance.org/index.html
Is there anything left here?
An automated preview of the documentation is available at https://776.mrdocs.prtest2.cppalliance.org/index.html
An automated preview of the documentation is available at https://776.mrdocs.prtest2.cppalliance.org/index.html
An automated preview of the documentation is available at https://776.mrdocs.prtest2.cppalliance.org/index.html
An automated preview of the documentation is available at https://776.mrdocs.prtest2.cppalliance.org/index.html