diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index f8a326a2f..7475a943f 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -104,9 +104,9 @@ jobs: cd fmt cmake -S . -B ./build -D FMT_DOC=OFF -D FMT_TEST=OFF -DCMAKE_BUILD_TYPE=${{ matrix.build-type }} -DCMAKE_CXX_COMPILER=${{ steps.setup-cpp.outputs.cxx }} -DCMAKE_C_COMPILER=${{ steps.setup-cpp.outputs.cc }} N_CORES=$(nproc 2>/dev/null || echo 1) - cmake --build ./build --config ${{ matrix.build-type }} --parallel $N_CORES + cmake --build ./build --config ${{ matrix.build-type }} --parallel $N_CORES cmake --install ./build --prefix ./install - + fmt_root=$(pwd)/install if [[ ${{ runner.os }} == 'Windows' ]]; then fmt_root=$(echo "$fmt_root" | sed 's/\\/\//g') @@ -135,9 +135,9 @@ jobs: fi cmake -S . -B ./build -DCMAKE_BUILD_TYPE=${{ matrix.build-type }} -DCMAKE_CXX_COMPILER=${{ steps.setup-cpp.outputs.cxx }} -DCMAKE_C_COMPILER=${{ steps.setup-cpp.outputs.cc }} N_CORES=$(nproc 2>/dev/null || echo 1) - cmake --build ./build --config ${{ matrix.build-type }} --parallel $N_CORES + cmake --build ./build --config ${{ matrix.build-type }} --parallel $N_CORES cmake --install ./build --prefix ./install - + duktape_root=$(pwd)/install if [[ ${{ runner.os }} == 'Windows' ]]; then duktape_root=$(echo "$duktape_root" | sed 's/\\/\//g') @@ -159,12 +159,12 @@ jobs: git config --global advice.detachedHead false git clone https://github.com/GNOME/libxml2 --branch v2.12.6 --depth 1 cd libxml2 - + cmake -S . -B ./build -DCMAKE_BUILD_TYPE=Release -DLIBXML2_WITH_PROGRAMS=ON -DLIBXML2_WITH_FTP=OFF -DLIBXML2_WITH_HTTP=OFF -DLIBXML2_WITH_ICONV=OFF -DLIBXML2_WITH_LEGACY=OFF -DLIBXML2_WITH_LZMA=OFF -DLIBXML2_WITH_ZLIB=OFF -DLIBXML2_WITH_ICU=OFF -DLIBXML2_WITH_TESTS=OFF -DLIBXML2_WITH_HTML=ON -DLIBXML2_WITH_C14N=ON -DLIBXML2_WITH_CATALOG=ON -DLIBXML2_WITH_DEBUG=ON -DLIBXML2_WITH_ISO8859X=ON -DLIBXML2_WITH_MEM_DEBUG=OFF -DLIBXML2_WITH_MODULES=ON -DLIBXML2_WITH_OUTPUT=ON -DLIBXML2_WITH_PATTERN=ON -DLIBXML2_WITH_PUSH=ON -DLIBXML2_WITH_PYTHON=OFF -DLIBXML2_WITH_READER=ON -DLIBXML2_WITH_REGEXPS=ON -DLIBXML2_WITH_SAX1=ON -DLIBXML2_WITH_SCHEMAS=ON -DLIBXML2_WITH_SCHEMATRON=ON -DLIBXML2_WITH_THREADS=ON -DLIBXML2_WITH_THREAD_ALLOC=OFF -DLIBXML2_WITH_TREE=ON -DLIBXML2_WITH_VALID=ON -DLIBXML2_WITH_WRITER=ON -DLIBXML2_WITH_XINCLUDE=ON -DLIBXML2_WITH_XPATH=ON -DLIBXML2_WITH_XPTR=ON -DCMAKE_CXX_COMPILER=${{ steps.setup-cpp.outputs.cxx || steps.parameters.outputs.clang-bin }} -DCMAKE_C_COMPILER=${{ steps.setup-cpp.outputs.cc || steps.parameters.outputs.clang-bin }} N_CORES=$(nproc 2>/dev/null || echo 1) - cmake --build ./build --config ${{ matrix.build-type }} --parallel $N_CORES + cmake --build ./build --config ${{ matrix.build-type }} --parallel $N_CORES cmake --install ./build --prefix ./install - + libxml2_root=$(pwd)/install if [[ ${{ runner.os }} == 'Windows' ]]; then libxml2_root=$(echo "$libxml2_root" | sed 's/\\/\//g') @@ -193,7 +193,7 @@ jobs: uses: actions/cache@v4 with: path: ${{ steps.llvm-parameters.outputs.llvm-root }} - key: llvm-${{ runner.os }}-${{ matrix.compiler }}-${{ matrix.version }}-${{ steps.llvm-parameters.outputs.llvm-build-preset }}-${{ steps.llvm-parameters.outputs.llvm-hash }} + key: llvm-libcxx-${{ runner.os }}-${{ matrix.compiler }}-${{ matrix.version }}-${{ steps.llvm-parameters.outputs.llvm-build-preset }}-${{ steps.llvm-parameters.outputs.llvm-hash }} - name: Install LLVM id: llvm-install @@ -202,7 +202,7 @@ jobs: run: | # LLVM is be installed with the default compiler set -x - + # Shallow clone LLVM_HASH in ../third-party/llvm cd .. mkdir -p third-party/llvm-project @@ -218,7 +218,7 @@ jobs: # Copy presets cp ../../mrdocs/third-party/llvm/CMakePresets.json ./llvm cp ../../mrdocs/third-party/llvm/CMakeUserPresets.json.example ./llvm/CMakeUserPresets.json - + # Build cd llvm llvm_root=$(pwd) @@ -226,11 +226,48 @@ jobs: cmake -S . -B ./build --preset=${{ steps.llvm-parameters.outputs.llvm-build-preset }} -DCMAKE_CXX_COMPILER=${{ steps.setup-cpp.outputs.cxx }} -DCMAKE_C_COMPILER=${{ steps.setup-cpp.outputs.cc }} if [[ ${{ runner.os }} == 'Linux' ]]; then cmake --build ./build --target help - fi + fi N_CORES=$(nproc 2>/dev/null || echo 1) cmake --build ./build --config Release --parallel $N_CORES cmake --install ./build --prefix "$llvm_project_root"/install + - name: Install LibC++ + id: libcxx-install + if: steps.llvm-cache.outputs.cache-hit != 'true' + shell: bash + run: | + set -x + cd ../third-party/llvm-project + llvm_project_root=$(pwd) + + export CXX="$llvm_project_root/install/bin/clang++" + export CC="$llvm_project_root/install/bin/clang" + + if [[ ${{ runner.os }} != 'Windows' ]]; then + cmake -G Ninja \ + -S runtimes \ + -B build-libcxx \ + -DLLVM_ENABLE_RUNTIMES="libcxx;libcxxabi;libunwind" \ + -DCMAKE_INSTALL_PREFIX="$llvm_project_root/install" + + ninja -C build-libcxx cxx cxxabi unwind + ninja -C build-libcxx install-cxx install-cxxabi install-unwind + else + cmake -G Ninja \ + -S runtimes \ + -B build-libcxx \ + -DLLVM_ENABLE_RUNTIMES="libcxx;libcxxabi" \ + -DCMAKE_INSTALL_PREFIX="$llvm_project_root/install" \ + -DLIBCXXABI_USE_LLVM_UNWINDER=OFF \ + -DLIBCXXABI_ENABLE_SHARED=OFF \ + -DLIBCXXABI_ENABLE_STATIC=ON \ + -DLIBCXX_ENABLE_SHARED=OFF \ + -DLIBCXX_NO_VCRUNTIME=ON \ + -DCMAKE_CXX_FLAGS="-D__ORDER_LITTLE_ENDIAN__=1234 -D__ORDER_BIG_ENDIAN__=4321 -D__BYTE_ORDER__=__ORDER_LITTLE_ENDIAN__" + ninja -C build-libcxx cxx + ninja -C build-libcxx install-cxx + fi + - name: Install Node.js uses: actions/setup-node@v3 with: @@ -256,7 +293,7 @@ jobs: -D duktape_ROOT=${{ steps.duktape-install.outputs.duktape-root }} -D Duktape_ROOT=${{ steps.duktape-install.outputs.duktape-root }} -D fmt_ROOT=${{ steps.fmt-install.outputs.fmt-root }} - ${{ (steps.libxml2-install.outputs.libxml2-root && format('-D libxml2_ROOT={0}', steps.libxml2-install.outputs.libxml2-root)) || '' }} + ${{ (steps.libxml2-install.outputs.libxml2-root && format('-D libxml2_ROOT={0}', steps.libxml2-install.outputs.libxml2-root)) || '' }} ${{ (steps.libxml2-install.outputs.libxml2-root && format('-D LibXml2_ROOT={0}', steps.libxml2-install.outputs.libxml2-root)) || '' }} export-compile-commands: true run-tests: true @@ -296,27 +333,17 @@ jobs: run: shell: bash name: Releases - timeout-minutes: 30 - runs-on: ubuntu-20.04 - container: ubuntu:23.04 + timeout-minutes: 30 + runs-on: ubuntu-latest + container: ubuntu:20.04 permissions: contents: write steps: - - name: Setup C++ - uses: alandefreitas/cpp-actions/setup-cpp@v1.8.4 - id: setup-cpp - with: - compiler: clang - version: 16 - check-latest: true - - name: Install packages uses: alandefreitas/cpp-actions/package-install@v1.8.4 id: package-install with: - apt-get: libstdc++-12-dev asciidoctor cmake bzip2 git - cc: ${{ steps.setup-cpp.outputs.cc }} - cxx: ${{ steps.setup-cpp.outputs.cxx }} + apt-get: build-essential asciidoctor cmake bzip2 git - name: Clone mrdocs uses: actions/checkout@v4 @@ -344,8 +371,6 @@ jobs: mrdocs --version MRDOCS_ROOT=/usr/local echo -e "MRDOCS_ROOT=$MRDOCS_ROOT" >> $GITHUB_ENV - CXX=/usr/bin/clang-16 - echo -e "CXX=$CXX" >> $GITHUB_ENV - name: Clone Boost.URL uses: alandefreitas/cpp-actions/boost-clone@v1.8.4 @@ -398,11 +423,6 @@ jobs: - name: Generate Demos run: | - CXX="${{ steps.setup-cpp.outputs.cxx }}" - export CXX - CC="${{ steps.setup-cpp.outputs.cc }}" - export CC - declare -a generators=( "adoc" "xml" @@ -443,15 +463,15 @@ jobs: id: compare-demos run: | set -x - + # Define URLs and directories LOCAL_DEMOS_DIR="./demos/" PREV_DEMOS_DIR="./demos-previous/" DIFF_DIR="./demos-diff/" - + # Create directories if they don't exist mkdir -p $PREV_DEMOS_DIR $DIFF_DIR - + # Iterate over the previous files and compare them with the corresponding local files find $PREV_DEMOS_DIR -type f | while read previous_file; do # Derive the corresponding local file path @@ -469,7 +489,7 @@ jobs: cat "$previous_file" >> "$diff_output" fi done - + # Iterate over the local files to find new files find $LOCAL_DEMOS_DIR -type f | while read local_file; do previous_file="${PREV_DEMOS_DIR}${local_file#$LOCAL_DEMOS_DIR}" @@ -480,7 +500,7 @@ jobs: echo "NEW CONTENT OF THE FILE IS:" >> "$diff_output" fi done - + # Check if the diff directory is empty if [[ -z $(ls -A $DIFF_DIR) ]]; then echo "No differences found." diff --git a/.gitignore b/.gitignore index 2a85a591d..b396488a2 100644 --- a/.gitignore +++ b/.gitignore @@ -10,4 +10,6 @@ /test-files/**/*.adoc /test-files/**/*.bad.xml docs/node_modules -docs/build \ No newline at end of file +docs/build +share/mrdocs/libcxx/ +share/mrdocs/clang/ diff --git a/CMakeLists.txt b/CMakeLists.txt index 760f53824..fd67d7c4d 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -92,6 +92,12 @@ elseif (LLVM_ROOT) endif() find_package(LLVM REQUIRED CONFIG) find_package(Clang REQUIRED CONFIG) + +if (LLVM_ROOT) + set(LIBCXX_DIR "${LLVM_ROOT}/include/c++/v1/") + set(STDLIB_INCLUDE_DIR "${LLVM_ROOT}/lib/clang/${Clang_VERSION_MAJOR}/include/") +endif() + list(APPEND CMAKE_MODULE_PATH "${LLVM_CMAKE_DIR}") include(HandleLLVMOptions) add_definitions(${LLVM_DEFINITIONS}) @@ -337,7 +343,9 @@ if (MRDOCS_BUILD_TESTS) --unit=false --action=test "${PROJECT_SOURCE_DIR}/test-files/golden-tests" - --addons="${CMAKE_SOURCE_DIR}/share/mrdocs/addons") + --addons="${CMAKE_SOURCE_DIR}/share/mrdocs/addons" + --system-includes="${LIBCXX_DIR}" + --system-includes="${STDLIB_INCLUDE_DIR}") foreach (action IN ITEMS create update) add_custom_target( mrdocs-${action}-test-fixtures @@ -347,6 +355,8 @@ if (MRDOCS_BUILD_TESTS) --action=${action} "${PROJECT_SOURCE_DIR}/test-files/golden-tests" --addons="${CMAKE_SOURCE_DIR}/share/mrdocs/addons" + --system-includes="${LIBCXX_DIR}" + --system-includes="${STDLIB_INCLUDE_DIR}" DEPENDS mrdocs-test ) endforeach () @@ -492,6 +502,13 @@ if (MRDOCS_INSTALL) #------------------------------------------------- # share #------------------------------------------------- + install(DIRECTORY ${LIBCXX_DIR} + DESTINATION ${CMAKE_INSTALL_DATAROOTDIR}/mrdocs/libcxx + FILES_MATCHING PATTERN "*") + install(DIRECTORY ${STDLIB_INCLUDE_DIR} + DESTINATION ${CMAKE_INSTALL_DATAROOTDIR}/mrdocs/clang + FILES_MATCHING PATTERN "*") + foreach (share_mrdocs_dir addons) install(DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/share/mrdocs/${share_mrdocs_dir} DESTINATION ${CMAKE_INSTALL_DATAROOTDIR}/mrdocs diff --git a/docs/modules/ROOT/pages/install.adoc b/docs/modules/ROOT/pages/install.adoc index e71887d68..c7eba42cb 100644 --- a/docs/modules/ROOT/pages/install.adoc +++ b/docs/modules/ROOT/pages/install.adoc @@ -382,12 +382,102 @@ cmake --install ./build --prefix ../install Replace 4 with the number of cores you want to use for building LLVM. -Return from `./third-party/llvm-project/llvm` to the parent directory to build and install MrDocs: +Return from `./third-party/llvm-project/llvm` to the LLVM project directory: [source,bash] ---- -cd ../../.. +cd ../.. +---- + +=== LibC++ + +In addition to LLVM, MrDocs requires a deterministic version of the C++ standard library (LibC++) to ensure consistent behavior across various environments. This step is crucial for replicating specific compiler and library configurations. + +**Download**: + +Continue using the same LLVM project directory. + +**Configure**: + +Configure and build LibC++ using the existing structure: + +[source,bash] +---- +export CXX="./install/bin/clang++" +export CC="./install/bin/clang" +---- + +Run a command such as the following to configure LLVM: + +[tabs] +==== +Windows PowerShell:: ++ +-- +[source,bash] +---- +cmake -G Ninja \ + -S runtimes \ + -B build-libcxx \ + -DLLVM_ENABLE_RUNTIMES="libcxx;libcxxabi" \ + -DCMAKE_INSTALL_PREFIX="$(pwd)/install" \ + -DLIBCXXABI_USE_LLVM_UNWINDER=OFF \ + -DLIBCXXABI_ENABLE_SHARED=OFF \ + -DLIBCXXABI_ENABLE_STATIC=ON \ + -DLIBCXX_ENABLE_SHARED=OFF \ + -DLIBCXX_NO_VCRUNTIME=ON \ + -DCMAKE_CXX_FLAGS="-D__ORDER_LITTLE_ENDIAN__=1234 -D__ORDER_BIG_ENDIAN__=4321 -D__BYTE_ORDER__=__ORDER_LITTLE_ENDIAN__" +---- +-- + +Unix Variants:: ++ +-- +[source,bash] +---- +cmake -G Ninja \ + -S runtimes \ + -B build-libcxx \ + -DLLVM_ENABLE_RUNTIMES="libcxx;libcxxabi;libunwind" \ + -DCMAKE_INSTALL_PREFIX="$(pwd)/install" ---- +-- +==== + +**Build**: + +Build and install the configured version of LibC++ with: + +[tabs] +==== +Windows PowerShell:: ++ +-- +[source,bash] +---- +ninja -C build-libcxx cxx +ninja -C build-libcxx install-cxx +---- +-- + +Unix Variants:: ++ +-- +[source,bash] +---- +ninja -C build-libcxx cxx cxxabi unwind +ninja -C build-libcxx install-cxx install-cxxabi install-unwind +---- +-- +==== + +Return from `./third-party/llvm-project` to the parent directory to build and install MrDocs: + +[source,bash] +---- +cd ../.. +---- + === MrDocs diff --git a/docs/website/render.js b/docs/website/render.js index c63400b04..f993b5c2a 100644 --- a/docs/website/render.js +++ b/docs/website/render.js @@ -57,7 +57,8 @@ for (let panel of data.panels) { // Create a CMakeLists.txt file for the snippet const cmakeListsPath = path.join(absSnippetsDir, 'CMakeLists.txt') - fs.writeFileSync(cmakeListsPath, `cmake_minimum_required(VERSION 3.13)\nproject(${sourceBasename})\nadd_executable(${sourceBasename} ${panel.source})\n`) + const cmakeListsContent = `cmake_minimum_required(VERSION 3.13)\nproject(${sourceBasename})\nadd_executable(${sourceBasename} ${panel.source})\n` + fs.writeFileSync(cmakeListsPath, cmakeListsContent) // Run mrdocs to generate documentation const mrdocsConfig = path.join(absSnippetsDir, 'mrdocs.yml') diff --git a/src/lib/Lib/ConfigOptions.json b/src/lib/Lib/ConfigOptions.json index 32cf3abb1..01ff74027 100644 --- a/src/lib/Lib/ConfigOptions.json +++ b/src/lib/Lib/ConfigOptions.json @@ -79,6 +79,35 @@ "details": "Additional defines passed to the compiler when building the source code. These defines are added to the compilation database regardless of the strategy to generate it.", "type": "list", "default": [] + }, + { + "name": "use-system-stdlib", + "brief": "Use the system standard library", + "details": "True if the compiler has to use just the system standard library. When set to true, the compiler uses the system standard library instead of the standard library provided by the compiler.", + "type": "bool", + "default": false + }, + { + "name": "stdlib-includes", + "brief": "Standard Library include paths", + "details": "Standard Library include paths. These paths are used to replace the standard library paths provided by the compiler.", + "type": "list", + "default": ["/share/mrdocs/libcxx", "/share/mrdocs/clang"], + "relativeto": "" + }, + { + "name": "system-includes", + "brief": "System include paths", + "details": "System include paths. These paths are used to add directories to the system include search path. The system include search path is used to search for system headers. The system headers are headers that are provided by the system and are not part of the project. The system headers are used to provide the standard library headers and other system headers. The system headers are not part of the project and are not checked for warnings and errors.", + "type": "list", + "default": [] + }, + { + "name": "includes", + "brief": "Include paths", + "details": "Include paths. These paths are used to add directories to the include search path. The include search path is used to search for headers. The headers are used to provide declarations and definitions of symbols. The headers are part of the project and are checked for warnings and errors.", + "type": "list", + "default": [] } ] }, diff --git a/src/lib/Lib/MrDocsCompilationDatabase.cpp b/src/lib/Lib/MrDocsCompilationDatabase.cpp index 21d271569..4835ab511 100644 --- a/src/lib/Lib/MrDocsCompilationDatabase.cpp +++ b/src/lib/Lib/MrDocsCompilationDatabase.cpp @@ -245,7 +245,11 @@ adjustCommandLine( llvm::StringRef workingDir, const std::vector& cmdline, const std::vector& additional_defines, - std::unordered_map> const& implicitIncludeDirectories) + std::unordered_map> const& implicitIncludeDirectories, + std::vector const& stdlibIncludes, + std::vector const& systemIncludes, + std::vector const& includes, + bool useSystemStdlib) { if (cmdline.empty()) { @@ -297,19 +301,46 @@ adjustCommandLine( new_cmdline.emplace_back(fmt::format("-D{}", def)); } - // ------------------------------------------------------ - // Add implicit include paths - // ------------------------------------------------------ - // Implicit include paths are those which are automatically - // added by the compiler. These will not be defined in the - // compile command, so we add them here so that clang - // can also find these headers. - if (auto it = implicitIncludeDirectories.find(progName); - it != implicitIncludeDirectories.end()) { - for (auto const& inc : it->second) + if (useSystemStdlib) + { + // ------------------------------------------------------ + // Add implicit include paths + // ------------------------------------------------------ + // Implicit include paths are those which are automatically + // added by the compiler. These will not be defined in the + // compile command, so we add them here so that clang + // can also find these headers. + if (auto const it = implicitIncludeDirectories.find(progName); + it != implicitIncludeDirectories.end()) { + for (auto const& inc : it->second) + { + new_cmdline.emplace_back(fmt::format("-isystem{}", inc)); + } + } + } + else + { + // ------------------------------------------------------ + // Add standard library and system includes + // ------------------------------------------------------ + for (auto const& inc : systemIncludes) + { + new_cmdline.emplace_back(fmt::format("-isystem{}", inc)); + } + for (auto const& inc : stdlibIncludes) { - new_cmdline.emplace_back(fmt::format("-I{}", inc)); + new_cmdline.emplace_back(fmt::format("-isystem{}", inc)); } + new_cmdline.emplace_back("-nostdinc++"); + new_cmdline.emplace_back("-nostdlib++"); + } + + // ------------------------------------------------------ + // Add directory to include search path + // ------------------------------------------------------ + for (auto const& inc : includes) + { + new_cmdline.emplace_back(fmt::format("-I{}", inc)); } // ------------------------------------------------------ @@ -390,7 +421,11 @@ MrDocsCompilationDatabase( workingDir, cmd0.CommandLine, (*config_impl)->defines, - implicitIncludeDirectories); + implicitIncludeDirectories, + (*config_impl)->stdlibIncludes, + (*config_impl)->systemIncludes, + (*config_impl)->includes, + (*config_impl)->useSystemStdlib); cmd.Directory = makeAbsoluteAndNative(workingDir, cmd0.Directory); cmd.Filename = makeAbsoluteAndNative(workingDir, cmd0.Filename); if (isCXXSrcFile(cmd.Filename)) diff --git a/src/lib/Metadata/Finalize.cpp b/src/lib/Metadata/Finalize.cpp index cc3daaa9f..1036e6705 100644 --- a/src/lib/Metadata/Finalize.cpp +++ b/src/lib/Metadata/Finalize.cpp @@ -12,6 +12,7 @@ #include "lib/Lib/Info.hpp" #include "lib/Support/NameParser.hpp" #include +#include #include #include diff --git a/src/test/TestArgs.cpp b/src/test/TestArgs.cpp index 7f6c6da4a..96687cb3e 100644 --- a/src/test/TestArgs.cpp +++ b/src/test/TestArgs.cpp @@ -80,6 +80,16 @@ R"( "addons", llvm::cl::desc("The directory with the addons."), llvm::cl::cat(commonCat)) + +, systemIncludes( + "system-includes", + llvm::cl::desc("A list of paths to the system headers."), + llvm::cl::cat(commonCat)) + +, includes( + "includes", + llvm::cl::desc("A list of paths to additional include directories."), + llvm::cl::cat(commonCat)) { } diff --git a/src/test/TestArgs.hpp b/src/test/TestArgs.hpp index 6a9c20288..17407761b 100644 --- a/src/test/TestArgs.hpp +++ b/src/test/TestArgs.hpp @@ -47,6 +47,8 @@ class TestArgs llvm::cl::opt unitOption; llvm::cl::list inputPaths; llvm::cl::opt addons; + llvm::cl::list systemIncludes; + llvm::cl::list includes; // Hide all options that don't belong to us void hideForeignOptions(); diff --git a/src/tool/Addons.cpp b/src/tool/Addons.cpp deleted file mode 100644 index e6d971c3a..000000000 --- a/src/tool/Addons.cpp +++ /dev/null @@ -1,55 +0,0 @@ -// -// Licensed under the Apache License v2.0 with LLVM Exceptions. -// See https://llvm.org/LICENSE.txt for license information. -// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -// -// Copyright (c) 2023 Vinnie Falco (vinnie.falco@gmail.com) -// -// Official repository: https://github.com/cppalliance/mrdocs -// - -#include "Addons.hpp" -#include -#include -#include -#include - -namespace clang { -namespace mrdocs { - -Expected -setupAddonsDir( - std::string& addonsDirArg, - std::string_view execPath) -{ - if (!addonsDirArg.empty()) - { - // Already set from mrdocs.yml or command line - return {}; - } - - // Set addons dir from environment variable - auto addonsEnvVar = llvm::sys::Process::GetEnv("MRDOCS_ADDONS_DIR"); - if (addonsEnvVar) - { - MRDOCS_CHECK(*addonsEnvVar, "MRDOCS_ADDONS_DIR is empty"); - std::string addonsDir = files::normalizePath(*addonsEnvVar); - MRDOCS_TRY(files::requireAbsolute(addonsDir)); - MRDOCS_TRY(files::requireDirectory(addonsDir)); - addonsDirArg = addonsDir; - return {}; - } - - // Set addons dir from process working directory - MRDOCS_CHECK(execPath, "getMainExecutable failed"); - std::string binDir = files::getParentDir(execPath); - std::string addonsDir = files::appendPath( - binDir, "..", "share", "mrdocs", "addons"); - Error err = files::requireDirectory(addonsDir); - MRDOCS_CHECK(err); - addonsDirArg = addonsDir; - return {}; -} - -} // mrdocs -} // clang diff --git a/src/tool/Addons.hpp b/src/tool/Addons.hpp deleted file mode 100644 index 15fbb31cc..000000000 --- a/src/tool/Addons.hpp +++ /dev/null @@ -1,33 +0,0 @@ -// -// Licensed under the Apache License v2.0 with LLVM Exceptions. -// See https://llvm.org/LICENSE.txt for license information. -// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -// -// Copyright (c) 2023 Vinnie Falco (vinnie.falco@gmail.com) -// -// Official repository: https://github.com/cppalliance/mrdocs -// - -#ifndef MRDOCS_TOOL_ADDONS_HPP -#define MRDOCS_TOOL_ADDONS_HPP - -#include -#include -#include - -namespace clang { -namespace mrdocs { - -/** Set the addons directory using the argument as a hint. - - @return The error if any occurred. -*/ -Expected -setupAddonsDir( - std::string& addonsDirArg, - std::string_view execPath); - -} // mrdocs -} // clang - -#endif diff --git a/src/tool/CompilerInfo.cpp b/src/tool/CompilerInfo.cpp index 523f9b4d0..ce5fe99bb 100644 --- a/src/tool/CompilerInfo.cpp +++ b/src/tool/CompilerInfo.cpp @@ -82,8 +82,12 @@ parseIncludePaths(std::string const& compilerOutput) } std::unordered_map> -getCompilersDefaultIncludeDir(clang::tooling::CompilationDatabase const& compDb) +getCompilersDefaultIncludeDir(clang::tooling::CompilationDatabase const& compDb, bool useSystemStdlib) { + if (!useSystemStdlib) + { + return {}; + } std::unordered_map> res; auto const allCommands = compDb.getAllCompileCommands(); diff --git a/src/tool/CompilerInfo.hpp b/src/tool/CompilerInfo.hpp index aa9d112ed..f0cdae0b0 100644 --- a/src/tool/CompilerInfo.hpp +++ b/src/tool/CompilerInfo.hpp @@ -44,10 +44,11 @@ parseIncludePaths(std::string const& compilerOutput); * @brief Get the compiler default include dir. * * @param compDb The compilation database. + * @param useSystemStdlib True if the compiler has to use just the system standard library. * @return std::unordered_map> The compiler default include dir. */ std::unordered_map> -getCompilersDefaultIncludeDir(clang::tooling::CompilationDatabase const& compDb); +getCompilersDefaultIncludeDir(clang::tooling::CompilationDatabase const& compDb, bool useSystemStdlib); } // mrdocs } // clang diff --git a/src/tool/GenerateAction.cpp b/src/tool/GenerateAction.cpp index 48afa49f4..44867230e 100644 --- a/src/tool/GenerateAction.cpp +++ b/src/tool/GenerateAction.cpp @@ -9,7 +9,6 @@ // Official repository: https://github.com/cppalliance/mrdocs // -#include "Addons.hpp" #include "CompilerInfo.hpp" #include "ToolArgs.hpp" #include @@ -171,7 +170,7 @@ DoGenerateAction( // Custom compilation database that applies settings from the configuration auto const defaultIncludePaths = getCompilersDefaultIncludeDir( - jsonDatabase); + jsonDatabase, (*config)->useSystemStdlib); auto compileCommandsDir = files::getParentDir(compileCommandsPath); MrDocsCompilationDatabase compilationDatabase( compileCommandsDir, diff --git a/src/tool/ToolArgs.cpp b/src/tool/ToolArgs.cpp index c1d902a5a..561f141e8 100644 --- a/src/tool/ToolArgs.cpp +++ b/src/tool/ToolArgs.cpp @@ -9,7 +9,6 @@ // #include "ToolArgs.hpp" -#include "Addons.hpp" #include #include #include diff --git a/util/generate-config-info.py b/util/generate-config-info.py index 091be0d2a..f57605387 100644 --- a/util/generate-config-info.py +++ b/util/generate-config-info.py @@ -499,6 +499,15 @@ def remove_reference_dir_from_path(path): return path +def get_reference_dir_from_path(path): + if path.startswith('<'): + closing_bracket = path.find('>') + if closing_bracket == -1: + raise ValueError(f'Invalid default value {path} for option') + return path[1:closing_bracket] + return None + + def option_validation_snippet(option): camel_name = to_camel_case(option['name']) contents = '' @@ -510,6 +519,7 @@ def option_validation_snippet(option): path_is_relativeto_dir = option['relativeto'] if path_is_relativeto_dir.startswith('<') and path_is_relativeto_dir.endswith('>'): path_is_relativeto_dir = path_is_relativeto_dir[1:-1] + default_is_relativeto_dir = path_is_relativeto_dir if 'default' in option and isinstance(option['default'], str): first_path_seg_is_reference = option['default'].startswith('<') @@ -520,6 +530,7 @@ def option_validation_snippet(option): default_is_relativeto_dir = option['default'][1:closing_bracket] else: default_is_relativeto_dir = 'cwd' + same_base_paths = default_is_relativeto_dir == path_is_relativeto_dir validation_contents = '' @@ -644,16 +655,18 @@ def option_validation_snippet(option): validation_contents += f'}}\n' else: if option['default']: - validation_contents += f'// s.{camel_name} paths are not required. The default value is "{option["default"]}"\n' + validation_contents += f'// s.{camel_name} paths are not required.\n' + validation_contents += f'// The default value is "{option["default"]}"\n' validation_contents += f'if (s.{camel_name}.empty())\n' validation_contents += f'{{\n' - validation_contents += f' s.{camel_name} = {{' + validation_contents += f' s.{camel_name} = {{\n' is_first = True for default_path in option['default']: if not is_first: - validation_contents += ', ' - validation_contents += f'" files::makeAbsolute("{remove_reference_dir_from_path(default_path)}", dirs.{to_camel_case(default_is_relativeto_dir)}")' + validation_contents += ',\n' + validation_contents += f' files::makeAbsolute("{remove_reference_dir_from_path(default_path)}", dirs.{to_camel_case(get_reference_dir_from_path(default_path))})' is_first = False + validation_contents += '\n' validation_contents += ' };\n' validation_contents += f'}}\n' validation_contents += f'else\n'