diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index ef6c11701..dfb5f64e2 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') @@ -173,6 +173,7 @@ jobs: fi echo -E "libxml2-root=$libxml2_root" >> $GITHUB_OUTPUT + - name: LLVM Parameters id: llvm-parameters run: | @@ -188,6 +189,14 @@ jobs: fi echo -E "llvm-root=$llvm_root" >> $GITHUB_OUTPUT + libcxx_root=$(pwd)/third-party/llvm-project/install + if [[ ${{ runner.os }} == 'Windows' ]]; then + libcxx_root=$(echo "$libcxx_root" | sed 's/\\/\//g') + libcxx_root=$(echo $libcxx_root | sed 's|^/d/|D:/|') + echo "$libcxx_root" + fi + echo -E "libcxx-root=$libcxx_root" >> $GITHUB_OUTPUT + - name: LLVM Binaries id: llvm-cache uses: actions/cache@v4 @@ -202,7 +211,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 +227,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,7 +235,7 @@ 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) if [ ${{ runner.os }} != 'Windows' ]; then cmake --build ./build --config Release --parallel $N_CORES @@ -253,6 +262,63 @@ jobs: fi cmake --install ./build --prefix "$llvm_project_root"/install + - name: LibC++ Binaries + id: libcxx-cache + uses: actions/cache@v4 + with: + path: ${{ steps.llvm-parameters.outputs.libcxx-root }} + key: libcxx-${{ runner.os }}-${{ matrix.compiler }}-${{ matrix.version }}-${{ steps.llvm-parameters.outputs.llvm-hash }} + + - name: Install LibC++ + id: libcxx-install + if: ${{ steps.libcxx-cache.outputs.cache-hit != 'true'}} + shell: bash + run: | + set -x + + cd .. + llvm_project_root="$(pwd)/third-party/llvm-project" + if [ ! -d "$llvm_project_root/runtimes" ]; then + mkdir -p $llvm_project_root + cd $llvm_project_root + git config --global init.defaultBranch master + git config --global advice.detachedHead false + git init + git remote add origin https://github.com/llvm/llvm-project.git + git fetch --depth 1 origin ${{ steps.llvm-parameters.outputs.llvm-hash }} + git checkout FETCH_HEAD + fi + + export CXX="$llvm_project_root/install/bin/clang++" + export CC="$llvm_project_root/install/bin/clang" + + cd $llvm_project_root + + 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: @@ -278,7 +344,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 @@ -419,7 +485,7 @@ jobs: export CXX CC="${{ steps.setup-cpp.outputs.cc }}" export CC - + declare -a generators=( "adoc" "html" @@ -461,15 +527,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 @@ -487,7 +553,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}" @@ -498,7 +564,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 4ab852e0c..87559ff97 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}/../libcxx/include/c++/v1/") + set(CLANG_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}) @@ -284,11 +290,11 @@ if (MRDOCS_BUILD_TESTS) endif () target_compile_definitions(mrdocs-test PRIVATE -DMRDOCS_TEST_FILES_DIR="${CMAKE_CURRENT_SOURCE_DIR}/test-files") add_test(NAME mrdocs-unit-tests COMMAND mrdocs-test --unit=true) - add_test(NAME mrdocs-golden-tests COMMAND mrdocs-test --unit=false --action=test "${PROJECT_SOURCE_DIR}/test-files/golden-tests" --addons="${CMAKE_SOURCE_DIR}/share/mrdocs/addons") + add_test(NAME mrdocs-golden-tests COMMAND mrdocs-test --unit=false --action=test "${PROJECT_SOURCE_DIR}/test-files/golden-tests" --addons="${CMAKE_SOURCE_DIR}/share/mrdocs/addons" --system-includes="${LIBCXX_DIR}") foreach (action IN ITEMS create update) add_custom_target( mrdocs-${action}-test-fixtures - COMMAND mrdocs-test --unit=false --action=${action} "${PROJECT_SOURCE_DIR}/test-files/golden-tests" --addons="${CMAKE_SOURCE_DIR}/share/mrdocs/addons" + COMMAND mrdocs-test --unit=false --action=${action} "${PROJECT_SOURCE_DIR}/test-files/golden-tests" --addons="${CMAKE_SOURCE_DIR}/share/mrdocs/addons" --system-includes="${LIBCXX_DIR}" DEPENDS mrdocs-test ) endforeach () @@ -442,6 +448,13 @@ if (MRDOCS_INSTALL) #------------------------------------------------- # share #------------------------------------------------- + install(DIRECTORY ${LIBCXX_DIR} + DESTINATION ${CMAKE_INSTALL_DATAROOTDIR}/mrdocs/libcxx + FILES_MATCHING PATTERN "*") + install(DIRECTORY ${CLANG_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/website/render.js b/docs/website/render.js index c63400b04..9c7dfedd5 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') @@ -65,6 +66,7 @@ for (let panel of data.panels) { const mrdocsOutput = path.join(absSnippetsDir, 'output') const command = `${mrdocsExecutable} --config=${mrdocsConfig} ${mrdocsInput} --output=${mrdocsOutput} --multipage=true --generate=adoc` console.log(`Running command: ${command}`) + console.log(`for: ${cmakeListsContent}`) execSync(command, {encoding: 'utf8'}); // Look for documentation file somewhere in the output directory diff --git a/include/mrdocs/Config.hpp b/include/mrdocs/Config.hpp index feb441c06..4d7720e44 100644 --- a/include/mrdocs/Config.hpp +++ b/include/mrdocs/Config.hpp @@ -104,6 +104,15 @@ class MRDOCS_DECL /// from CMakeLists.txt std::string cmake; + /// True if the compiler has to use just the system's standard library + bool useSystemStdLib = false; + + /// Standard Library include paths + std::vector systemIncludes; + + /// Additional include paths + std::vector includes; + /// Additional defines passed to the compiler std::vector defines; diff --git a/include/mrdocs/ConfigOptions.inc b/include/mrdocs/ConfigOptions.inc index e447b3c1c..cc9aa8e02 100644 --- a/include/mrdocs/ConfigOptions.inc +++ b/include/mrdocs/ConfigOptions.inc @@ -69,6 +69,9 @@ COMMON_OPTION (compilationDatabase , compilation-database , Path to the c // Build options COMMON_OPTION (cmake , cmake , CMake arguments when generating the compilation database from CMakeLists.txt) COMMON_OPTION (defines , defines , Additional defines passed to the compiler) +COMMON_OPTION (useSystemStdLib , use-system-stdlib , True if the compiler has to use just the system standard library) +COMMON_OPTION (systemIncludes , system-includes , Standard Library include paths) +COMMON_OPTION (includes , includes , Additional include paths) // Generators COMMON_OPTION (generate , generate , Documentation generator. Supported generators are: adoc/html/xml) diff --git a/src/lib/Lib/MrDocsCompilationDatabase.cpp b/src/lib/Lib/MrDocsCompilationDatabase.cpp index c61f1dd64..2132749f8 100644 --- a/src/lib/Lib/MrDocsCompilationDatabase.cpp +++ b/src/lib/Lib/MrDocsCompilationDatabase.cpp @@ -222,7 +222,10 @@ std::vector adjustCommandLine( const std::vector& cmdline, const std::vector& additional_defines, - std::unordered_map> const& implicitIncludeDirectories) + std::unordered_map> const& implicitIncludeDirectories, + std::vector const& systemIncludes, + std::vector const& includes, + bool useSystemStdLib) { if (cmdline.empty()) { @@ -274,19 +277,42 @@ 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 include directories + // ------------------------------------------------------ + for (auto const& inc : systemIncludes) { - 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 additional include directories + // ------------------------------------------------------ + for (auto const& inc : includes) + { + new_cmdline.emplace_back(fmt::format("-I{}", inc)); } // ------------------------------------------------------ @@ -366,7 +392,10 @@ MrDocsCompilationDatabase( cmd.CommandLine = adjustCommandLine( cmd0.CommandLine, (*config_impl)->defines, - implicitIncludeDirectories); + implicitIncludeDirectories, + (*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 90b0af062..b1fb17368 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..5c275289f 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 standard library."), + 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/test/TestRunner.cpp b/src/test/TestRunner.cpp index 8a568783c..0970b1aed 100644 --- a/src/test/TestRunner.cpp +++ b/src/test/TestRunner.cpp @@ -90,6 +90,8 @@ handleFile( publicSettings.config = configPath; publicSettings.configDir = files::getParentDir(filePath); publicSettings.configYaml = files::getFileText(publicSettings.config).value(); + publicSettings.systemIncludes = testArgs.systemIncludes; + publicSettings.includes = testArgs.includes; loadConfig(publicSettings, publicSettings.configYaml).value(); auto configFile = loadConfigFile( publicSettings, @@ -242,6 +244,8 @@ namespace { publicSettings.config = configPath; publicSettings.configDir = dirPath; publicSettings.configYaml = files::getFileText(publicSettings.config).value(); + publicSettings.systemIncludes = testArgs.systemIncludes; + publicSettings.includes = testArgs.includes; loadConfig(publicSettings, publicSettings.configYaml).value(); publicSettings.sourceRoot = files::makeAbsolute( publicSettings.sourceRoot, @@ -362,6 +366,8 @@ checkPath( publicSettings.config = configPath; publicSettings.configDir = files::getParentDir(inputPath); publicSettings.configYaml = files::getFileText(publicSettings.config).value(); + publicSettings.systemIncludes = testArgs.systemIncludes; + publicSettings.includes = testArgs.includes; if (testArgs.addons.getValue() != "") { publicSettings.addons = files::normalizeDir(testArgs.addons.getValue()); diff --git a/src/tool/StdLib.cpp b/src/tool/StdLib.cpp new file mode 100644 index 000000000..b8afdf73c --- /dev/null +++ b/src/tool/StdLib.cpp @@ -0,0 +1,61 @@ +// +// 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) 2024 Fernando Pelliccioni (fpelliccioni@gmail.com) +// +// Official repository: https://github.com/cppalliance/mrdocs +// + +#include "StdLib.hpp" +#include +#include +#include +#include + +namespace clang { +namespace mrdocs { + +Expected +setupStdLibDirs( + std::vector& stdLibDirsArg, + std::string_view execPath) +{ + if (stdLibDirsArg.empty()) + { + MRDOCS_CHECK(execPath, "getMainExecutable failed"); + + // Set LibC++ path from process working directory + std::string binDir = files::getParentDir(execPath); + report::info("execPath: {}", execPath); + report::info("binDir: {}", binDir); + { + std::string stdLibDir = files::makeDirsy(files::appendPath( + binDir, "..", "share", "mrdocs", "libcxx")); + report::info("Adding libcxx stdlib dir: {}", stdLibDir); + Error err = files::requireDirectory(stdLibDir); + MRDOCS_CHECK(err); + stdLibDirsArg.push_back(stdLibDir); + } + { + std::string clangDir = files::makeDirsy(files::appendPath( + binDir, "..", "share", "mrdocs", "clang")); + report::info("Adding clang stdlib dir: {}", clangDir); + Error err = files::requireDirectory(clangDir); + MRDOCS_CHECK(err); + stdLibDirsArg.push_back(clangDir); + } + } + else + { + for (auto& path : stdLibDirsArg) + { + path = files::makeDirsy(files::normalizePath(path)); + } + } + return {}; +} + +} // mrdocs +} // clang diff --git a/src/tool/StdLib.hpp b/src/tool/StdLib.hpp new file mode 100644 index 000000000..3e4375342 --- /dev/null +++ b/src/tool/StdLib.hpp @@ -0,0 +1,33 @@ +// +// 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) 2024 Fernando Pelliccioni (fpelliccioni@gmail.com) +// +// Official repository: https://github.com/cppalliance/mrdocs +// + +#ifndef MRDOCS_TOOL_STDLIB_HPP +#define MRDOCS_TOOL_STDLIB_HPP + +#include +#include +#include + +namespace clang { +namespace mrdocs { + +/** Set the StdLib directories using the argument as a hint. + + @return The error if any occurred. +*/ +Expected +setupStdLibDirs( + std::vector& stdLibDirsArg, + std::string_view execPath); + +} // mrdocs +} // clang + +#endif // MRDOCS_TOOL_STDLIB_HPP diff --git a/src/tool/ToolArgs.cpp b/src/tool/ToolArgs.cpp index 33e7ab914..0fb56cf59 100644 --- a/src/tool/ToolArgs.cpp +++ b/src/tool/ToolArgs.cpp @@ -10,6 +10,7 @@ #include "ToolArgs.hpp" #include "Addons.hpp" +#include "StdLib.hpp" #include #include #include @@ -50,6 +51,9 @@ R"( , output(llvm::cl::cat(pathsCat)) , compilationDatabase(llvm::cl::cat(pathsCat)) , cmake(llvm::cl::cat(buildOptsCat)) +, useSystemStdLib(llvm::cl::init(false), llvm::cl::cat(buildOptsCat)) +, systemIncludes(llvm::cl::cat(buildOptsCat)) +, includes(llvm::cl::cat(buildOptsCat)) , defines(llvm::cl::cat(buildOptsCat)) , generate(llvm::cl::init("adoc"), llvm::cl::cat(generatorCat)) , addons(llvm::cl::cat(generatorCat)) @@ -295,6 +299,17 @@ apply( } } + auto const exp = setupStdLibDirs(s.systemIncludes, execPath); + if (!exp) + { + return formatError( + "{}:\n" + "Could not locate the standard library directories because " + "the directories ../share/mrdocs/libcxx and ../share/mrdocs/clang " + "do not exist.", + exp.error()); + } + // Make all common relative paths relative to the config file and // make all directories dirsy auto makeRelativeToConfigDir = [&]( diff --git a/src/tool/ToolArgs.hpp b/src/tool/ToolArgs.hpp index 009d13898..615e88ee3 100644 --- a/src/tool/ToolArgs.hpp +++ b/src/tool/ToolArgs.hpp @@ -59,6 +59,15 @@ class ToolArgs /// from CMakeLists.txt llvm::cl::opt cmake; + /// True if the compiler has to use just the system's standard library + llvm::cl::opt useSystemStdLib; + + /// Standard Library include paths + llvm::cl::list systemIncludes; + + /// Additional include paths + llvm::cl::list includes; + /// Additional defines passed to the compiler llvm::cl::list defines;