Skip to content

Commit 7f47ff5

Browse files
committed
exposition on system dependencies
#docs fix #793
1 parent 5d6e8f7 commit 7f47ff5

File tree

1 file changed

+60
-5
lines changed

1 file changed

+60
-5
lines changed

docs/modules/ROOT/pages/usage.adoc

Lines changed: 60 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -207,28 +207,83 @@ f();
207207
In this pattern, the user wants to document the function `f` as `__implementation_defined__ f();` because the library contract is that the user should not rely on a specific return type here.
208208
However, this ill-formed pattern is problematic:
209209

210-
* `__implementation_defined__` is not a valid symbol so the code is ill-formed
211-
* `impl::f_return_t` doesn't express the intent of the user for the documentation
210+
* `__implementation_defined__` is not a valid symbol so the code is ill-formed
211+
* `impl::f_return_t` doesn't express the intent of the user for the documentation
212212
* the developer has to effectively maintain two versions of the code
213213
* the original source code becomes more and more unreadable
214214

215-
Instead, when using MrDocs, while the `\\__MRDOCS__` macro is still available for conditional compilation, the same function could be directly documented as:
215+
Instead, when using MrDocs, while the `\\__MRDOCS__` macro is still available for conditional compilation, the same function could be directly documented as:
216216

217217
[source,c++]
218218
----
219219
impl::f_return_t f();
220220
----
221221

222-
And the user can specify that `impl` as a namespace for implementation details in the configuration file:
222+
And the user can specify that symbols in the `impl` namespace are implementation details in the configuration file:
223223

224224
[source,yaml]
225225
----
226226
# ...
227-
implementation-detail: impl
227+
implementation-detail: impl::**
228228
# ...
229229
----
230230

231231
The xref:commands.adoc[] and xref:config-file.adoc[] pages contain a list of all available commands and options to identify and extract the relevant information as intended by the user.
232232

233233
MrDocs provides multiple mechanisms are provided to specify special {cpp} patterns, such as the example above.
234234
For each common {cpp} construct that would require macros and two versions of the code, MrDocs provides commands to identify the construct and extract the relevant information as intented by the user.
235+
236+
[#dependencies]
237+
=== Dependencies
238+
239+
Another consequence of relying on valid {cpp} code is that MrDocs needs to know about dependencies of the project for the code to be valid. In particular, it needs access to the header files of the project and its dependencies.
240+
241+
The `includes` option in the configuration file specifies the directories to search for header files. Suppose a library depends on an external library, such as https://www.boost.org[Boost,window=_blank]:
242+
243+
[source,yaml]
244+
----
245+
# A library that depends on an external library
246+
includes:
247+
- /path/to/boost/include
248+
----
249+
250+
Whatever is specified in the `includes` option is passed to Clang as include directories, regardless of the strategy used to generate the compilation database.
251+
252+
If a `compile_commands.json` file is used, these include directories are passed directly to Clang as `-I` flags.
253+
254+
If a `CMakeLists.txt` file is used, the `cmake` option in the configuration file can be used to provide the necessary parameters for CMake to find the appropriate header files.
255+
256+
[source,yaml]
257+
----
258+
cmake: '-D BOOST_ROOT=/path/to/boost'
259+
----
260+
261+
Another option supported by CMake is to set the `BOOST_ROOT` environment variable as `/path/to/boost` before running MrDocs.
262+
263+
=== System dependencies
264+
265+
It's also common for libraries to depend on the C++ standard library, the C standard library, or other system libraries. These dependencies are usually resolved by the compiler and are not explicitly specified in the source code:
266+
267+
* The {cpp} standard library: The compiler will look for specific paths according to the `-stdlib` option and include them as implicit `-isystem` paths. For instance, Clang can use different implementations of the {cpp} standard library. By default, that's Microsoft STL on Windows, libstdc++ on Linux and libc++ otherwise. This can be disabled with `-nostdinc++ -nostdlib++` or, in MrDocs, with `use-system-stdlib=false`.
268+
* The C standard library (and system libraries): Unlike with libc++, LLVM+Clang does not provide an implementation of the C standard library. It always depends on the system for that. The compiler will not look for specific paths but implicitly include all system libraries. This can be disabled with `-nostdinc` or, in MrDocs, with `use-system-libc=false`.
269+
270+
That means unless `-nostdinc` is defined, all systems include paths are included. This is what allows the user to also use headers like `<Windows.h>` or `<linux/version.h>` without explicitly including anything else, even though they are not part of the C standard library. This is often seen as a convenience but can lead to portability issues.
271+
272+
In this context, MrDocs provides the `use-system-stdlib` and `use-system-libc` options. Both are set as `false` by default, meaning MrDocs will compile the code as if the `-nostdinc&plus;&plus; -nostdlib&plus;&plus;` and `-nostdinc` flags were passed to Clang. Additionally:
273+
274+
- When `use-system-stdlib` is `false`, MrDocs will use the bundled libc&plus;&plus; headers available in `<mrdocs-root>/share/mrdocs/headers/libcxx` and `<mrdocs-root>/share/mrdocs/headers/clang`. These paths can be adjusted with the `stdlib-includes` option.
275+
- When `use-system-libc` is `false`, MrDocs will use the bundled libc stubs available in `<mrdocs-root>/share/mrdocs/headers/libc-stubs`. This path can be adjusted with the `libc-includes` option.
276+
277+
The rationale for that is reproducibility. You want to be able to build your documentation and don't want it to stop working because the platform or some platform details have changed.
278+
These default values also help avoid conflicts where the same symbol or header is defined twice if the compilation database includes system paths relevant to one specific compiler. That can breaks things when MrDocs attempts to compile it with clang.
279+
In other words, MrDocs becomes a sandboxed environment where only the C and C++ standard libraries are available.
280+
281+
The default values described above work for most libraries and applications that only depend on the C and C++ standard libraries. When there are no dependencies outside the standard libraries, the user probably won't even notice the difference between these options.
282+
283+
However, if you depend on other system libraries, that means you need to handle these dependencies explicitly. For instance, this is very common with networking libraries. There are a few solutions to this, and these solutions are in a continuum regarding the use of `use-system-stdlib`/`use-system-libc` and the design of the code:
284+
285+
1. Depending on the design of your library, you can implement a different path for MrDocs where you don't need these system headers. System headers are often guarded by macros to detect the platform: for instance, `&lowbar;&lowbar;linux&lowbar;&lowbar;` for `<linux/version.h>` and `&lowbar;WIN32` for `<Windows.h>`. You can use the `&lowbar;&lowbar;MRDOCS&lowbar;&lowbar;` macro to provide an implementation for MrDocs. This implementation would typically include stubs for the symbols you need in the documentation. Because symbols from system libraries are typically not exposed in the public API of your library, that gives you replacements that make sense for the documentation. However, this solution is not enough when other dependencies also depend on these system libraries.
286+
2. Handle it as an explicit dependency. Explicitly include the paths you need in your compilation database as if it's a dependency described in the <<dependencies>> section. For instance, you can get CMake to explicitly find `<linux/version.h>` or `<Windows.h>` and only include those directories with `-isystem` or `-I` in the compilation database.
287+
3. Enable `use-system-libc`. MrDocs will still use the bundled libc&plus;&plus; for the C&plus;&plus; standard library, and use the system headers for the C standard library, making all system paths available. That makes system headers such as `<linux/version.h>` or `<Windows.h>` available by default. The trade-off is losing the reproducibility guarantees described above.
288+
289+
The first option in this list provides the most control and the most reproducibility. The third option is the most convenient but also the most fragile.

0 commit comments

Comments
 (0)