From da81e09288a4f3c40beda65df0c8ab784b094ef7 Mon Sep 17 00:00:00 2001 From: alandefreitas Date: Thu, 10 Oct 2024 16:15:29 -0300 Subject: [PATCH 1/6] fix: lazy object construct when atomic shared pointers are unsupported --- include/mrdocs/Dom/Object.hpp | 35 +++++++++++++++++++++++++++++++---- src/lib/Dom/Object.cpp | 24 +++++++++++++++++++----- 2 files changed, 50 insertions(+), 9 deletions(-) diff --git a/include/mrdocs/Dom/Object.hpp b/include/mrdocs/Dom/Object.hpp index 3e4713664..1c9081ec9 100644 --- a/include/mrdocs/Dom/Object.hpp +++ b/include/mrdocs/Dom/Object.hpp @@ -420,14 +420,29 @@ class MRDOCS_DECL // //------------------------------------------------ -/** A lazy Object implementation. +/** Abstract lazy object interface. - This implementation is used to construct an - Object on demand. + This interface is used to define objects + that are constructed on demand. + + The subclass must override the `construct` + function to return the constructed object. + It will typically also store whatever + data is necessary to construct this object. + + When any of the object properties are accessed + for the first time, the object is constructed. + This can happen via any of the public functions, + such as `get`, `set`, `size`, `exists`, or `visit`. The underlying object storage is only initialized when the first property is - set or accessed. + set or accessed. In practice, it means + the object is never initialized if it's + not used in a template. + + When the object is initialized, the + */ class MRDOCS_DECL LazyObjectImpl : public ObjectImpl @@ -440,6 +455,18 @@ class MRDOCS_DECL using impl_type = Object::impl_type; + /* Return the constructed object. + + This function is invoked by all public + functions that access the object properties. + + When invoked for the first time, the object + is constructed and stored in the shared + pointer. + + Further invocations return a reference + to the existing value in the shared pointer. + */ ObjectImpl& obj() const; protected: diff --git a/src/lib/Dom/Object.cpp b/src/lib/Dom/Object.cpp index c34c0d19d..1c39cadbd 100644 --- a/src/lib/Dom/Object.cpp +++ b/src/lib/Dom/Object.cpp @@ -218,15 +218,29 @@ LazyObjectImpl:: obj() const { #ifdef __cpp_lib_atomic_shared_ptr - auto impl = sp_.load(); - if(impl) + std::shared_ptr impl = sp_.load(); + if (impl) + { + // Already initialized return *impl; - impl_type expected = nullptr; - if(sp_.compare_exchange_strong( - expected, construct().impl())) + } + + // Fetch the shared pointer from the factory + std::shared_ptr expected = nullptr; + std::shared_ptr desired = construct().impl(); + MRDOCS_ASSERT(desired); + if (sp_.compare_exchange_strong(expected, std::move(desired))) + { return *sp_.load(); + } return *expected; #else + if (sp_) + { + return *sp_; + } + sp_ = construct().impl(); + MRDOCS_ASSERT(sp_); return *sp_; #endif } From 15ef613be1ded30c23dc2beedff1abb78fc5b08c Mon Sep 17 00:00:00 2001 From: alandefreitas Date: Thu, 10 Oct 2024 16:33:55 -0300 Subject: [PATCH 2/6] docs: libc++ compiler requirements --- docs/modules/ROOT/pages/install.adoc | 3 +++ 1 file changed, 3 insertions(+) diff --git a/docs/modules/ROOT/pages/install.adoc b/docs/modules/ROOT/pages/install.adoc index cb95bec44..68c0b92ab 100644 --- a/docs/modules/ROOT/pages/install.adoc +++ b/docs/modules/ROOT/pages/install.adoc @@ -407,6 +407,9 @@ export CXX="./install/bin/clang++" export CC="./install/bin/clang" ---- +These options set the C and pass:[C++] compilers to the ones previously installed by LLVM. +MrDocs only depends on the pass:[LibC++] headers, so any compiler that works for this step should be fine. + Run a command such as the following to configure LLVM: [tabs] From 2d1147f83934d88f7faac8efa24b3c0266cc7825 Mon Sep 17 00:00:00 2001 From: alandefreitas Date: Thu, 10 Oct 2024 16:34:14 -0300 Subject: [PATCH 3/6] refactor(Platform): support arm64 --- include/mrdocs/Platform.hpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/include/mrdocs/Platform.hpp b/include/mrdocs/Platform.hpp index 3f488fd91..ea07c8af9 100644 --- a/include/mrdocs/Platform.hpp +++ b/include/mrdocs/Platform.hpp @@ -72,8 +72,8 @@ namespace mrdocs { # endif #endif -#if ! defined(__x86_64__) && ! defined(_WIN64) -# error mrdox requires a 64-bit archtecture +#if ! defined(__x86_64__) && ! defined(_WIN64) && ! defined(__aarch64__) +# error mrdocs requires a 64-bit architecture #endif } // mrdocs From d5203f33ef342b6adb9ed7478301dac600c44763 Mon Sep 17 00:00:00 2001 From: alandefreitas Date: Thu, 10 Oct 2024 16:34:58 -0300 Subject: [PATCH 4/6] refactor: compilation database ensures target --- src/lib/Lib/CMakeExecution.cpp | 3 + src/lib/Lib/MrDocsCompilationDatabase.cpp | 72 ++++++++++++++++++++++- src/lib/Support/Error.cpp | 2 +- 3 files changed, 74 insertions(+), 3 deletions(-) diff --git a/src/lib/Lib/CMakeExecution.cpp b/src/lib/Lib/CMakeExecution.cpp index 875de4abb..e2ed0b260 100644 --- a/src/lib/Lib/CMakeExecution.cpp +++ b/src/lib/Lib/CMakeExecution.cpp @@ -383,6 +383,9 @@ parseBashArgs(std::string_view str) return args; } +/* Pushes the CMake arguments to the `args` vector, replacing the + * default generator with Ninja if Visual Studio is the default generator. + */ Expected pushCMakeArgs( std::string const& cmakePath, diff --git a/src/lib/Lib/MrDocsCompilationDatabase.cpp b/src/lib/Lib/MrDocsCompilationDatabase.cpp index 4835ab511..98086517e 100644 --- a/src/lib/Lib/MrDocsCompilationDatabase.cpp +++ b/src/lib/Lib/MrDocsCompilationDatabase.cpp @@ -21,6 +21,8 @@ #include #include #include +#include +#include #include namespace clang { @@ -243,8 +245,8 @@ static std::vector adjustCommandLine( llvm::StringRef workingDir, - const std::vector& cmdline, - const std::vector& additional_defines, + std::vector const& cmdline, + std::vector const& additional_defines, std::unordered_map> const& implicitIncludeDirectories, std::vector const& stdlibIncludes, std::vector const& systemIncludes, @@ -292,6 +294,72 @@ adjustCommandLine( new_cmdline.emplace_back(is_clang_cl ? "/w" : "-w"); new_cmdline.emplace_back("-fsyntax-only"); + // ------------------------------------------------------ + // Target architecture + // ------------------------------------------------------ + constexpr auto is_target_option = [](std::string_view opt) { + return opt == "-target" || opt == "--target"; + }; + if (std::ranges::find_if(cmdline, is_target_option) == cmdline.end()) + { + auto getCommandCompilerTarget = [&]() -> std::string { + ScopedTempFile const outputPath("compiler-triple", "txt"); + if (!outputPath) { + return {}; + } + std::vector args = { + progName, "--print-target-triple" + }; + std::optional const redirects[] = { + llvm::StringRef(), + outputPath.path(), + llvm::StringRef() + }; + int const result = llvm::sys::ExecuteAndWait( + progName, args, std::nullopt, redirects); + if (result != 0) + { + return {}; + } + + auto const bufferOrError = llvm::MemoryBuffer::getFile( + outputPath.path()); + if (!bufferOrError) { + return {}; + } + return bufferOrError.get()->getBuffer().trim().str(); + }; + + [&]() { + std::string target = llvm::sys::getDefaultTargetTriple(); + + if (target.empty()) + { + target = llvm::sys::getProcessTriple(); + } + + if (target.empty()) + { + target = getCommandCompilerTarget(); + } + +#if defined(__APPLE__) + if (target.empty()) + { + target = "arm64-apple-darwin24.0.0"; + } +#else + if (target.empty()) + { + return; + } +#endif + + new_cmdline.emplace_back("-target"); + new_cmdline.emplace_back(target); + }(); + } + // ------------------------------------------------------ // Add additional defines // ------------------------------------------------------ diff --git a/src/lib/Support/Error.cpp b/src/lib/Support/Error.cpp index 94642b23c..584a5cab4 100644 --- a/src/lib/Support/Error.cpp +++ b/src/lib/Support/Error.cpp @@ -258,7 +258,7 @@ call_impl( e->location().line()); } os << fmt::format( - " Reported From: `{}` at line {}", + " Reported From: `{}` at line {}\n", ::SourceFileNames::getFileName(loc->file_name()), loc->line()); // VFALCO attach a stack trace for Level::fatal From 8e5dd83e2011a1518acdc13e96c7f52261c17bb1 Mon Sep 17 00:00:00 2001 From: alandefreitas Date: Thu, 10 Oct 2024 16:35:37 -0300 Subject: [PATCH 5/6] refactor: compilation database ensures std fix #694 --- src/lib/Lib/MrDocsCompilationDatabase.cpp | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/src/lib/Lib/MrDocsCompilationDatabase.cpp b/src/lib/Lib/MrDocsCompilationDatabase.cpp index 98086517e..2f42a6442 100644 --- a/src/lib/Lib/MrDocsCompilationDatabase.cpp +++ b/src/lib/Lib/MrDocsCompilationDatabase.cpp @@ -359,7 +359,18 @@ adjustCommandLine( new_cmdline.emplace_back(target); }(); } - + + // ------------------------------------------------------ + // Language standard + // ------------------------------------------------------ + constexpr auto is_std_option = [](std::string_view opt) { + return opt.starts_with("-std=") || opt.starts_with("--std=") || opt.starts_with("/std:"); + }; + if (std::ranges::find_if(cmdline, is_std_option) == cmdline.end()) + { + new_cmdline.emplace_back("-std=c++23"); + } + // ------------------------------------------------------ // Add additional defines // ------------------------------------------------------ From b05bb952b9350c584c94ce043b2656c56831d050 Mon Sep 17 00:00:00 2001 From: alandefreitas Date: Thu, 10 Oct 2024 16:33:39 -0300 Subject: [PATCH 6/6] ci: enable macos fix #558 --- .github/workflows/ci.yml | 83 ++++++++++++++++++++++++++++++---------- 1 file changed, 63 insertions(+), 20 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 03bdff804..7f33a097a 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -37,13 +37,17 @@ jobs: gcc 14 clang 18 msvc >=14.40 + apple-clang * standards: '20' - latest-factors: '' - factors: | + latest-factors: | msvc Optimized-Debug + factors: '' + runs-on: | + apple-clang: macos-15 build-types: | gcc: Release clang: Release + apple-clang: Release msvc: RelWithDebInfo msvc Optimized-Debug: Debug ccflags: | @@ -51,8 +55,8 @@ jobs: cxxflags: | msvc Optimized-Debug: /Ob1 /O2 /Zi install: | - gcc: git build-essential pkg-config python3 curl openjdk-11-jdk ninja-build pkg-config libncurses-dev libxml2-utils libxml2-dev - clang: git build-essential pkg-config python3 curl openjdk-11-jdk ninja-build pkg-config libncurses-dev libxml2-utils libxml2-dev + gcc: git build-essential pkg-config python3 curl openjdk-11-jdk pkg-config libncurses-dev libxml2-utils libxml2-dev + clang: git build-essential pkg-config python3 curl openjdk-11-jdk pkg-config libncurses-dev libxml2-utils libxml2-dev msvc: '' extra-values: | llvm-hash: e1065370aaacb1b1cb48e77d37d376bf024f4a39 @@ -68,6 +72,8 @@ jobs: llvm-archive-filename: {{ llvm-archive-basename }}.{{ llvm-archive-extension }} libcxx-runtimes: libcxx;libcxxabi{{#if (ine os 'windows') }};libunwind{{/if}} libcxx-targets: cxx {{#if (ine os 'windows') }}cxxabi unwind{{/if}} install-cxx {{#if (ine os 'windows') }}install-cxxabi install-unwind{{/if}} + libcxx-cxxflags: {{#if (ieq os 'windows') }}-D__ORDER_LITTLE_ENDIAN__=1234 -D__ORDER_BIG_ENDIAN__=4321 -D__BYTE_ORDER__=__ORDER_LITTLE_ENDIAN__{{/if}} + libcxx-cmake-args: -D LLVM_ENABLE_RUNTIMES="{{ libcxx-runtimes }}" {{#if (ieq os 'windows') }}-D LIBCXXABI_USE_LLVM_UNWINDER=OFF -D LIBCXXABI_ENABLE_SHARED=OFF -D LIBCXXABI_ENABLE_STATIC=ON -D LIBCXX_ENABLE_SHARED=OFF -D LIBCXX_NO_VCRUNTIME=ON{{/if}} {{#if (ieq os 'macos') }}-D CMAKE_OSX_ARCHITECTURES=""{{/if}} mrdocs-ccflags: {{ ccflags }} {{#if (eq compiler 'gcc') }}-static{{/if}} {{#if asan }}-static-libasan{{/if}} {{#if tsan }}-static-libtsan{{/if}} mrdocs-cxxflags: {{ cxxflags }} {{#if (eq compiler 'gcc') }}-static{{/if}} {{#if asan }}-static-libasan{{/if}} {{#if tsan }}-static-libtsan{{/if}} mrdocs-package-generators: {{#if (ieq os 'windows') }}7Z ZIP WIX{{else}}TGZ TXZ{{/if}} @@ -131,8 +137,7 @@ jobs: trace-commands: 'true' - name: Setup Ninja - uses: seanmiddleditch/gha-setup-ninja@v4 - if: ${{ runner.os == 'Windows' }} + uses: seanmiddleditch/gha-setup-ninja@v5 - name: Setup C++ uses: alandefreitas/cpp-actions/setup-cpp@v1.8.7 @@ -141,6 +146,15 @@ jobs: compiler: ${{ matrix.compiler }} version: ${{ matrix.version }} + # If apple-clang on macos, we run `clang -print-targets` to + # get the list of targets supported by the compiler. + - name: Print Clang Targets + if: matrix.compiler == 'apple-clang' + run: | + set -x + ${{ steps.setup-cpp.outputs.cxx }} --print-targets + ${{ steps.setup-cpp.outputs.cxx }} --print-target-triple + - name: Install System Packages uses: alandefreitas/cpp-actions/package-install@v1.8.7 if: matrix.compiler != 'msvc' @@ -323,24 +337,19 @@ jobs: source-dir: ../third-party/llvm-project/runtimes build-dir: ${sourceDir}/build-libcxx build-target: ${{ matrix.libcxx-targets }} - cc: ../third-party/llvm-project/install/bin/clang - cxx: ../third-party/llvm-project/install/bin/clang++ - cxxflags: ${{ runner.os == 'Windows' && '-D__ORDER_LITTLE_ENDIAN__=1234 -D__ORDER_BIG_ENDIAN__=4321 -D__BYTE_ORDER__=__ORDER_LITTLE_ENDIAN__' || '' }} + # MrDocs will only use the LibC++ headers: any compiler that works in this workflow will do + cc: ${{ runner.os == 'macOS' && steps.setup-cpp.outputs.cc || '../third-party/llvm-project/install/bin/clang' }} + cxx: ${{ runner.os == 'macOS' && steps.setup-cpp.outputs.cxx || '../third-party/llvm-project/install/bin/clang++' }} + cxxflags: ${{ matrix.libcxx-cxxflags }} generator: Ninja - extra-args: | - -D LLVM_ENABLE_RUNTIMES="${{ matrix.libcxx-runtimes }}" - ${{ runner.os == 'Windows' && '-D LIBCXXABI_USE_LLVM_UNWINDER=OFF' || '' }} - ${{ runner.os == 'Windows' && '-D LIBCXXABI_ENABLE_SHARED=OFF' || '' }} - ${{ runner.os == 'Windows' && '-D LIBCXXABI_ENABLE_STATIC=ON' || '' }} - ${{ runner.os == 'Windows' && '-D LIBCXX_ENABLE_SHARED=OFF' || '' }} - ${{ runner.os == 'Windows' && '-D LIBCXX_NO_VCRUNTIME=ON' || '' }} + extra-args: ${{ matrix.libcxx-cmake-args }} install: true install-prefix: ${sourceDir}/../install run-tests: false trace-commands: true - name: Install Node.js - uses: actions/setup-node@v3 + uses: actions/setup-node@v4 with: node-version: '20' @@ -427,12 +436,12 @@ jobs: uses: actions/checkout@v4 - name: Install Node.js - uses: actions/setup-node@v3 + uses: actions/setup-node@v4 with: node-version: '18' - name: Setup Ninja - uses: seanmiddleditch/gha-setup-ninja@v4 + uses: seanmiddleditch/gha-setup-ninja@v5 if: ${{ runner.os == 'Windows' }} - name: Download MrDocs package @@ -445,7 +454,8 @@ jobs: run: | set -x if [[ ${{ runner.os }} != 'Windows' ]]; then - dest_dir="/usr/local" + 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" @@ -475,6 +485,39 @@ jobs: modules-exclude-paths: '' trace-commands: true + - name: Set up llvm-symbolizer + if: ${{ runner.os == 'macOS' }} + run: | + set -x + + # Step 1: Check if llvm-symbolizer is installed + if ! command -v llvm-symbolizer &> /dev/null; then + echo "llvm-symbolizer is not installed. Installing via Homebrew..." + # Step 2: Install llvm if not installed + if command -v brew &> /dev/null; then + brew install llvm + else + echo "Homebrew is not installed. Please install Homebrew first: https://brew.sh/" + exit 1 + fi + fi + + # Step 3: Ensure llvm-symbolizer is in your PATH + llvm_bin_path=$(brew --prefix)/opt/llvm/bin + PATH="$PATH:$llvm_bin_path" + LLVM_SYMBOLIZER_PATH=$(which llvm-symbolizer) + if [ -z "$LLVM_SYMBOLIZER_PATH" ]; then + echo "llvm-symbolizer installation failed or it's not in the PATH." + exit 1 + else + echo "llvm-symbolizer found at: $LLVM_SYMBOLIZER_PATH" + fi + + # Step 4: Export LLVM_SYMBOLIZER_PATH environment variable + export LLVM_SYMBOLIZER_PATH="$LLVM_SYMBOLIZER_PATH" + echo -e "LLVM_SYMBOLIZER_PATH=$LLVM_SYMBOLIZER_PATH" >> $GITHUB_ENV + echo "Environment variable LLVM_SYMBOLIZER_PATH set to: $LLVM_SYMBOLIZER_PATH" + - name: Generate Landing Page working-directory: docs/website run: |