From ca1102a9564fbf3febd5d40b4450d97b93f154d8 Mon Sep 17 00:00:00 2001 From: Agustin Berge Date: Tue, 30 Sep 2025 11:35:51 +0200 Subject: [PATCH] feat: use system libs by default WIP --- .clang-format | 4 +++ .github/workflows/ci.yml | 36 ++++++++++++++----- CMakeLists.txt | 22 +++++------- docs/modules/ROOT/pages/usage.adoc | 2 +- docs/mrdocs.schema.json | 7 ++-- docs/website/snippets/sqrt.cpp | 1 - include/mrdocs/Support/Concepts.hpp | 8 +++-- src/lib/AST/ASTVisitor.cpp | 3 +- src/lib/AST/ExtractDocComment.cpp | 2 +- src/lib/ConfigOptions.json | 7 ++-- src/lib/MrDocsCompilationDatabase.cpp | 9 +++-- src/lib/MrDocsSettingsDB.cpp | 8 +++-- src/test/TestRunner.cpp | 7 +++- src/test/lib/MrDocsCompilationDatabase.cpp | 6 ++-- .../golden-tests/config/sfinae/redeclare.cpp | 3 +- .../golden-tests/config/sfinae/redeclare.yml | 2 ++ .../config/sfinae/return-based.yml | 2 ++ test-files/golden-tests/core/libcxx.yml | 2 ++ test-files/golden-tests/snippets/sqrt.cpp | 1 - test-files/golden-tests/snippets/sqrt.xml | 2 +- test-files/golden-tests/snippets/sqrt.yml | 2 ++ .../golden-tests/symbols/function/sfinae.cpp | 1 - .../golden-tests/symbols/function/sfinae.xml | 34 +++++++++--------- test-files/include/type_traits | 32 +++++++++++++++++ util/generate-config-info.py | 2 +- 25 files changed, 136 insertions(+), 69 deletions(-) create mode 100644 test-files/golden-tests/config/sfinae/redeclare.yml create mode 100644 test-files/golden-tests/config/sfinae/return-based.yml create mode 100644 test-files/golden-tests/core/libcxx.yml create mode 100644 test-files/golden-tests/snippets/sqrt.yml create mode 100644 test-files/include/type_traits diff --git a/.clang-format b/.clang-format index 1033103e53..f31bb5f342 100644 --- a/.clang-format +++ b/.clang-format @@ -227,3 +227,7 @@ IncludeCategories: # Comments FixNamespaceComments: true CommentPragmas: '^ clang-format' + +--- +Language: Json +BasedOnStyle: llvm diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 4b735644c2..225458476d 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -95,7 +95,7 @@ jobs: common-flags-base: {{#if (ieq compiler 'clang')}}-gz=zstd {{/if}} common-flags: {{{ common-flags-base }}}{{#if msan }}-fsanitize-memory-track-origins {{/if}} common-ccflags: {{{ ccflags }}} {{{ common-flags }}} - mrdocs-flags: {{{ warning-flags }}}{{#if (and (eq compiler 'gcc') (not asan)) }}-static {{/if}} + mrdocs-flags: {{{ warning-flags }}} mrdocs-ccflags: {{{ common-ccflags }}} {{{ mrdocs-flags }}} mrdocs-package-generators: {{#if (ieq os 'windows') }}7Z ZIP WIX{{else}}TGZ TXZ{{/if}} mrdocs-release-package-artifact: release-packages-{{{ lowercase os }}} @@ -287,7 +287,7 @@ jobs: # section, but which depend on paths not known at that point. - name: Resolved Matrix id: rmatrix - run: | + run: | set -euvx third_party_dir="$(realpath $(pwd)/..)/third-party" @@ -534,8 +534,7 @@ jobs: - name: CMake Workflow uses: alandefreitas/cpp-actions/cmake-workflow@v1.8.12 env: - # Bump per-test timeout on Windows to avoid CTest default (1500s) killing slow golden suites. - CTEST_TEST_TIMEOUT: ${{ runner.os == 'Windows' && '3600' || '' }} + CTEST_TEST_TIMEOUT: 3600 with: cmake-version: '>=3.26' cxxstd: ${{ matrix.cxxstd }} @@ -714,6 +713,22 @@ jobs: contents: write steps: + # This calculates a bunch of variables, which would normally go in to the regular matrix extra-values + # section, but which depend on paths not known at that point. + - name: Resolved Matrix + id: rmatrix + run: | + set -euvx + + third_party_dir="$(realpath $(pwd)/..)/third-party" + if [[ "${{ runner.os }}" == 'Windows' ]]; then + third_party_dir="$(echo "$third_party_dir" | sed 's/\\/\//g; s|^/d/|D:/|')" + fi + echo "third-party-dir=$third_party_dir" >> $GITHUB_OUTPUT + + llvm_path="$third_party_dir/llvm" + echo "llvm-path=$llvm_path" >> $GITHUB_OUTPUT + - name: Ensure Node if: matrix.container != '' && env.ACT == 'true' run: | @@ -756,6 +771,13 @@ jobs: compiler: ${{ matrix.compiler }} version: ${{ matrix.version }} + - name: Cached LLVM Binaries + id: llvm-cache + uses: actions/cache@v4 + with: + path: ${{ steps.rmatrix.outputs.llvm-path }} + key: ${{ matrix.llvm-archive-basename }} + - name: Download MrDocs package uses: actions/download-artifact@v4 with: @@ -772,13 +794,11 @@ jobs: # Print tree structure find packages -print | sed 's;[^/]*/;|____;g;s;____|; |;g' + dest_dir="${{ steps.rmatrix.outputs.llvm-path }}" + if [[ ${{ runner.os }} != 'Windows' ]]; then - dest_dir="$HOME/local" - mkdir -p "$dest_dir" find packages -maxdepth 1 -name 'MrDocs-*.tar.gz' -exec tar -vxzf {} -C $dest_dir --strip-components=1 \; else - dest_dir="$GITHUB_WORKSPACE/usr/local" - dest_dir=$(echo "$dest_dir" | sed 's/\\/\//g') find packages -maxdepth 1 -name "MrDocs-*.7z" -exec 7z x {} -o$dest_dir \; if [[ $(ls -1 $dest_dir | wc -l) -eq 1 ]]; then single_dir=$(ls -1 $dest_dir) diff --git a/CMakeLists.txt b/CMakeLists.txt index cd2db0f870..f57defab07 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -261,15 +261,6 @@ if (NOT EXISTS "${LIBCXX_DIR}") "Please provide a LLVM with libc++ enabled\n") endif() -set(STDLIB_INCLUDE_DIR "${LLVM_BINARY_DIR}/lib/clang/${Clang_VERSION_MAJOR}/include" - CACHE PATH "Path to the clang headers include directory") -message(STATUS "STDLIB_INCLUDE_DIR: ${STDLIB_INCLUDE_DIR}") -if (NOT EXISTS "${STDLIB_INCLUDE_DIR}") - message(FATAL_ERROR - "STDLIB_INCLUDE_DIR (${STDLIB_INCLUDE_DIR}) does not exist.\n" - "Missing clang headers\n") -endif() - list(APPEND CMAKE_MODULE_PATH "${LLVM_CMAKE_DIR}") include(HandleLLVMOptions) add_definitions(${LLVM_DEFINITIONS}) @@ -388,6 +379,7 @@ if (WIN32) mrdocs-core PUBLIC /permissive- # strict C++ + /Zc:__cplusplus # report C++ standard support /W4 # enable all warnings /MP # multi-processor compilation /EHs # C++ Exception handling @@ -411,6 +403,13 @@ if (MRDOCS_DOCUMENTATION_BUILD) return() endif() +# Replicate the clang resource directory structure within our own build, +# so that libclang will find it when executing directly from the build directory. +set(CMAKE_RUNTIME_OUTPUT_DIRECTORY "bin") +file(MAKE_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/lib/clang") +set(RESOURCE_DIR "lib/clang/${Clang_VERSION_MAJOR}") +file(CREATE_LINK "${LLVM_BINARY_DIR}/${RESOURCE_DIR}" "${CMAKE_CURRENT_BINARY_DIR}/${RESOURCE_DIR}" SYMBOLIC) + #------------------------------------------------- # # Tool @@ -490,7 +489,6 @@ if (MRDOCS_BUILD_TESTS) "--addons=${CMAKE_SOURCE_DIR}/share/mrdocs/addons" --generator=${testgenerator} "--stdlib-includes=${LIBCXX_DIR}" - "--stdlib-includes=${STDLIB_INCLUDE_DIR}" "--libc-includes=${CMAKE_SOURCE_DIR}/share/mrdocs/headers/libc-stubs" --log-level=warn ) @@ -505,7 +503,6 @@ if (MRDOCS_BUILD_TESTS) "--addons=${CMAKE_SOURCE_DIR}/share/mrdocs/addons" --generator=${testgenerator} "--stdlib-includes=${LIBCXX_DIR}" - "--stdlib-includes=${STDLIB_INCLUDE_DIR}" "--libc-includes=${CMAKE_SOURCE_DIR}/share/mrdocs/headers/libc-stubs" --log-level=warn DEPENDS mrdocs-test @@ -703,9 +700,6 @@ if (MRDOCS_INSTALL) install(DIRECTORY ${LIBCXX_DIR}/ DESTINATION ${CMAKE_INSTALL_DATAROOTDIR}/mrdocs/headers/libcxx FILES_MATCHING PATTERN "*") - install(DIRECTORY ${STDLIB_INCLUDE_DIR}/ - DESTINATION ${CMAKE_INSTALL_DATAROOTDIR}/mrdocs/headers/clang - FILES_MATCHING PATTERN "*") install(DIRECTORY ${CMAKE_SOURCE_DIR}/share/mrdocs/headers/libc-stubs/ DESTINATION ${CMAKE_INSTALL_DATAROOTDIR}/mrdocs/headers/libc-stubs FILES_MATCHING PATTERN "*") diff --git a/docs/modules/ROOT/pages/usage.adoc b/docs/modules/ROOT/pages/usage.adoc index 473aa42977..12eed36239 100644 --- a/docs/modules/ROOT/pages/usage.adoc +++ b/docs/modules/ROOT/pages/usage.adoc @@ -278,7 +278,7 @@ It's also common for libraries to depend on the C++ standard library, the C stan That means unless `-nostdinc` is defined, all systems include paths are included. This is what allows the user to also use headers like `` or `` 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. -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++ -nostdlib++` and `-nostdinc` flags were passed to Clang. Additionally: +In this context, MrDocs provides the `use-system-stdlib` and `use-system-libc` options. Both are set as `true` by default; setting both to `false` results in MrDocs compiling the code as if the `-nostdinc++ -nostdlib++` and `-nostdinc` flags were passed to Clang. Additionally: - When `use-system-stdlib` is `false`, MrDocs will use the bundled libc++ headers available in `/share/mrdocs/headers/libcxx` and `/share/mrdocs/headers/clang`. These paths can be adjusted with the `stdlib-includes` option. - When `use-system-libc` is `false`, MrDocs will use the bundled libc stubs available in `/share/mrdocs/headers/libc-stubs`. This path can be adjusted with the `libc-includes` option. diff --git a/docs/mrdocs.schema.json b/docs/mrdocs.schema.json index 1e5f2b06ba..ec7d7e89d4 100644 --- a/docs/mrdocs.schema.json +++ b/docs/mrdocs.schema.json @@ -561,8 +561,7 @@ }, "stdlib-includes": { "default": [ - "/share/mrdocs/headers/libcxx", - "/share/mrdocs/headers/clang" + "/share/mrdocs/headers/libcxx" ], "description": "When `use-system-stdlib` is disabled, the C++ standard library headers are available in these paths.", "items": { @@ -602,7 +601,7 @@ "type": "string" }, "use-system-libc": { - "default": false, + "default": true, "description": "To achieve reproducible results, MrDocs bundles the LibC headers with its definitions. To use the C standard library available in the system instead, set this option to true.", "enum": [ true, @@ -612,7 +611,7 @@ "type": "boolean" }, "use-system-stdlib": { - "default": false, + "default": true, "description": "To achieve reproducible results, MrDocs bundles the LibC++ headers. To use the C++ standard library available in the system instead, set this option to true.", "enum": [ true, diff --git a/docs/website/snippets/sqrt.cpp b/docs/website/snippets/sqrt.cpp index 24d30487a4..dde92f52c9 100644 --- a/docs/website/snippets/sqrt.cpp +++ b/docs/website/snippets/sqrt.cpp @@ -1,5 +1,4 @@ #include -#include /** Computes the square root of an integral value. diff --git a/include/mrdocs/Support/Concepts.hpp b/include/mrdocs/Support/Concepts.hpp index 054547e807..54780d6550 100644 --- a/include/mrdocs/Support/Concepts.hpp +++ b/include/mrdocs/Support/Concepts.hpp @@ -137,8 +137,12 @@ concept range_of_tuple_like = std::ranges::range && tuple_like>; #ifdef __cpp_lib_reference_from_temporary - using std::reference_constructs_from_temporary_v; - using std::reference_converts_from_temporary_v; +/** True when binding `To` from `From` would require a temporary conversion. + */ +using std::reference_constructs_from_temporary_v; +/** Like `reference_converts_from_temporary_v`, but for construction. + */ +using std::reference_converts_from_temporary_v; #else /** True when binding `To` from `From` would require a temporary conversion. */ diff --git a/src/lib/AST/ASTVisitor.cpp b/src/lib/AST/ASTVisitor.cpp index 10f5703615..3af1e895c6 100644 --- a/src/lib/AST/ASTVisitor.cpp +++ b/src/lib/AST/ASTVisitor.cpp @@ -2379,7 +2379,8 @@ extractSFINAEInfo(clang::QualType const T) Result.Type = resultType->getAsType(); for (std::size_t I = 0; I < Args.size(); ++I) { - if (SFINAEControl->ControllingParams[I]) + if (I < SFINAEControl->ControllingParams.size() + && SFINAEControl->ControllingParams[I]) { MRDOCS_SYMBOL_TRACE(Args[I], context_); clang::TemplateArgument ArgsI = Args[I]; diff --git a/src/lib/AST/ExtractDocComment.cpp b/src/lib/AST/ExtractDocComment.cpp index 93b4980963..f987457c64 100644 --- a/src/lib/AST/ExtractDocComment.cpp +++ b/src/lib/AST/ExtractDocComment.cpp @@ -627,7 +627,7 @@ class DocCommentVisitor auto compsExp = parseHTMLStartSpan(C, cur); if (!compsExp) { - report::error( + report::warn( "{} at {} ({})", compsExp.error().message(), filename, diff --git a/src/lib/ConfigOptions.json b/src/lib/ConfigOptions.json index 019b0ec176..50ee0cbf36 100644 --- a/src/lib/ConfigOptions.json +++ b/src/lib/ConfigOptions.json @@ -528,7 +528,7 @@ "brief": "Use the system C++ standard library", "details": "To achieve reproducible results, MrDocs bundles the LibC++ headers. To use the C++ standard library available in the system instead, set this option to true.", "type": "bool", - "default": false + "default": true }, { "name": "stdlib-includes", @@ -536,8 +536,7 @@ "details": "When `use-system-stdlib` is disabled, the C++ standard library headers are available in these paths.", "type": "list", "default": [ - "/share/mrdocs/headers/libcxx", - "/share/mrdocs/headers/clang" + "/share/mrdocs/headers/libcxx" ], "relative-to": "", "must-exist": false, @@ -548,7 +547,7 @@ "brief": "Use the system C standard library", "details": "To achieve reproducible results, MrDocs bundles the LibC headers with its definitions. To use the C standard library available in the system instead, set this option to true.", "type": "bool", - "default": false + "default": true }, { "name": "libc-includes", diff --git a/src/lib/MrDocsCompilationDatabase.cpp b/src/lib/MrDocsCompilationDatabase.cpp index 61cd76aea2..188ca52afa 100644 --- a/src/lib/MrDocsCompilationDatabase.cpp +++ b/src/lib/MrDocsCompilationDatabase.cpp @@ -302,7 +302,10 @@ adjustCommandLine( cmdLineCStrs.data(), cmdLineCStrs.data() + cmdLineCStrs.size()); - auto const systemIncludeFlag = is_clang_cl ? "-external:I" : "-isystem"; + char const* systemIncludeFlag = is_clang_cl ? "-external:I" : "-isystem"; + // FIXME: No CL equivalent, but not really needed there? + char const* afterIncludeFlag = is_clang_cl ? "-external:I" : "-idirafter"; + // ------------------------------------------------------ // Supress all warnings @@ -406,10 +409,10 @@ adjustCommandLine( if (!(*config)->useSystemLibc) { - new_cmdline.emplace_back("-nostdinc"); + new_cmdline.emplace_back(is_clang_cl ? "-X" : "-nostdlibinc"); for (auto const& inc : (*config)->libcIncludes) { - new_cmdline.emplace_back(systemIncludeFlag); + new_cmdline.emplace_back(afterIncludeFlag); new_cmdline.emplace_back(inc); } } diff --git a/src/lib/MrDocsSettingsDB.cpp b/src/lib/MrDocsSettingsDB.cpp index d32b0cc6b9..edbc9e0cec 100644 --- a/src/lib/MrDocsSettingsDB.cpp +++ b/src/lib/MrDocsSettingsDB.cpp @@ -11,6 +11,7 @@ #include "MrDocsSettingsDB.hpp" #include +#include namespace mrdocs { @@ -60,17 +61,18 @@ MrDocsSettingsDB::MrDocsSettingsDB(ConfigImpl const& config) }); } + llvm::ErrorOr clangPath = llvm::sys::findProgramByName( + "clang"); + for (auto const& pathName: sourceFiles) { // auto fileName = files::getFileName(pathName); auto parentDir = files::getParentDir(pathName); std::vector cmds; - cmds.emplace_back("clang"); + cmds.emplace_back(clangPath ? *clangPath : "clang"); cmds.emplace_back("-fsyntax-only"); cmds.emplace_back("-std=c++23"); - cmds.emplace_back("-pedantic-errors"); - cmds.emplace_back("-Werror"); cmds.emplace_back("-x"); cmds.emplace_back("c++"); cmds.emplace_back(pathName); diff --git a/src/test/TestRunner.cpp b/src/test/TestRunner.cpp index 3ad80a428f..400338c5f7 100644 --- a/src/test/TestRunner.cpp +++ b/src/test/TestRunner.cpp @@ -184,11 +184,16 @@ handleFile( auto runWith = [&](std::vector command) { auto const db = makeSingleFileDB(filePath, std::move(command)); + std::unordered_map> + defaultIncludePaths = { + { "clang", { MRDOCS_TEST_FILES_DIR "/include" } }, + { "clang-cl", { MRDOCS_TEST_FILES_DIR "/include" } }, + }; MrDocsCompilationDatabase compilations( llvm::StringRef(files::getParentDir(filePath)), db, config, - std::unordered_map>{}); + defaultIncludePaths); handleCompilationDatabase(filePath, compilations, config, layout); }; diff --git a/src/test/lib/MrDocsCompilationDatabase.cpp b/src/test/lib/MrDocsCompilationDatabase.cpp index 444ec9de69..d877e53a29 100644 --- a/src/test/lib/MrDocsCompilationDatabase.cpp +++ b/src/test/lib/MrDocsCompilationDatabase.cpp @@ -179,8 +179,8 @@ struct MrDocsCompilationDatabase_test { config->settings_.libcIncludes.push_back("libc-path"); auto adjusted = adjustCompileCommand({ programName }, config); - BOOST_TEST(has(adjusted, "-nostdinc")); - BOOST_TEST(has(adjusted, { "-isystem", "libc-path" })); + BOOST_TEST(has(adjusted, "-nostdlibinc")); + BOOST_TEST(has(adjusted, { "-idirafter", "libc-path" })); } } @@ -302,7 +302,7 @@ struct MrDocsCompilationDatabase_test { config->settings_.libcIncludes.push_back("libc-path"); auto adjusted = adjustCompileCommand({ programName }, config); - BOOST_TEST(has(adjusted, "-nostdinc")); + BOOST_TEST(has(adjusted, "-X")); BOOST_TEST(has(adjusted, { "-external:I", "libc-path" })); } } diff --git a/test-files/golden-tests/config/sfinae/redeclare.cpp b/test-files/golden-tests/config/sfinae/redeclare.cpp index 7eb75ff959..7b122fa88f 100644 --- a/test-files/golden-tests/config/sfinae/redeclare.cpp +++ b/test-files/golden-tests/config/sfinae/redeclare.cpp @@ -10,5 +10,4 @@ void f(std::enable_if_t>); template void f(std::enable_if_t>) -{ -} \ No newline at end of file +{} diff --git a/test-files/golden-tests/config/sfinae/redeclare.yml b/test-files/golden-tests/config/sfinae/redeclare.yml new file mode 100644 index 0000000000..8061ae78c2 --- /dev/null +++ b/test-files/golden-tests/config/sfinae/redeclare.yml @@ -0,0 +1,2 @@ +warn-if-doc-error: false +warn-no-paramdoc: false diff --git a/test-files/golden-tests/config/sfinae/return-based.yml b/test-files/golden-tests/config/sfinae/return-based.yml new file mode 100644 index 0000000000..8061ae78c2 --- /dev/null +++ b/test-files/golden-tests/config/sfinae/return-based.yml @@ -0,0 +1,2 @@ +warn-if-doc-error: false +warn-no-paramdoc: false diff --git a/test-files/golden-tests/core/libcxx.yml b/test-files/golden-tests/core/libcxx.yml new file mode 100644 index 0000000000..b3b0f2a2da --- /dev/null +++ b/test-files/golden-tests/core/libcxx.yml @@ -0,0 +1,2 @@ +use-system-stdlib: false +use-system-libc: false diff --git a/test-files/golden-tests/snippets/sqrt.cpp b/test-files/golden-tests/snippets/sqrt.cpp index 24d30487a4..dde92f52c9 100644 --- a/test-files/golden-tests/snippets/sqrt.cpp +++ b/test-files/golden-tests/snippets/sqrt.cpp @@ -1,5 +1,4 @@ #include -#include /** Computes the square root of an integral value. diff --git a/test-files/golden-tests/snippets/sqrt.xml b/test-files/golden-tests/snippets/sqrt.xml index ef5b19c514..3840317a1d 100644 --- a/test-files/golden-tests/snippets/sqrt.xml +++ b/test-files/golden-tests/snippets/sqrt.xml @@ -5,7 +5,7 @@