Skip to content

Infrastructure: Sentry integration#8540

Merged
vadi2 merged 39 commits intoMudlet:developmentfrom
NicolasKeita:feature/add-sentry
Nov 30, 2025
Merged

Infrastructure: Sentry integration#8540
vadi2 merged 39 commits intoMudlet:developmentfrom
NicolasKeita:feature/add-sentry

Conversation

@NicolasKeita
Copy link
Copy Markdown
Contributor

@NicolasKeita NicolasKeita commented Nov 17, 2025

Brief overview of PR changes/additions

You can view the demonstration video here.

  1. Added two compile-time variables:
    • SENTRY_SEND_DEBUG
    • WITH_SENTRY
cmake -S ./ -B build/ -DWITH_SENTRY=ON -DSENTRY_SEND_DEBUG=1
qmake6 ../src/mudlet.pro CONFIG+=WITH_SENTRY SENTRY_SEND_DEBUG=1

All PR code is wrapped with IF (WITH_SENTRY) blocks, making it easy to enable or disable the Sentry integration.

The SENTRY_SEND_DEBUG option is used to automatically upload debug files to Sentry.io. These files are required by Sentry to display the exact line of a crash.

Sentry requires both the executable and its corresponding debug symbols. Debug symbol files can be large (up to 350 MB for Mudlet), which is why this option SENTRY_SEND_DEBUG exists—to avoid uploading the full debug files on every CI push.

  • Windows: executable + .pdb file (all debug symbols are embedded directly in the Mudlet binary)
  • Linux: executable + .debug file
  • macOS: executable + .dSYM folder

Ideally, the executable is "stripped" of all debug symbols to reduce its size, while the debug symbol files contain all the necessary debugging information. Both the stripped executable and the debug files are sent to Sentry, which is sufficient for accurate crash reporting.

  1. Added a secondary program: A small window prompts the user for consent to send the crash report. This program is located at src/crash_reporter/main.cpp.

  2. Copied a mandatory Sentry-provided executable (crash_handler) required for proper functioning, which must be placed alongside the Mudlet executable.

  3. Generated a mandatory cache directory at runtime for storing Sentry crash reports.

      Expected cache locations:
        Linux   : ~/.cache/mudlet/sentry
        macOS   : ~/Library/Caches/mudlet/sentry
        Windows : C:\Users\...\AppData\Local\Cache\Mudlet\sentry
  1. Added a git submodule : sentry-native

  2. Added two CI secret variables

  • ${{ secrets.SENTRY_DSN }} sets the default DSN at compile time (developers can override it via an environment variable named SENTRY_DSN).
  • ${{secrets.SENTRY_AUTH_TOKEN}} is used to send debug files. (dev can also override it via a environment variable SENTRY_AUTH_TOKEN

How to Test

  1. Create a Sentry account on the Sentry website.
  2. Create a new project (name it mudlet) and obtain the project's DSN then add it to the console environment: export SENTRY_DSN="..."
  3. export MUDLET_CRASH_TEST=1 (thanks to this variable, Mudlet will crash whenever you open a profile. Let's use Sentry to see exactly where I inserted the crash.)
  4. Start Mudlet like a normal user and open a game. Mudlet should crash.
  5. You should now see the crash on the Sentry website.

But without the debug files, it doesn't show exactly where the crash is.

  1. Obtain your organization’s auth token from the Sentry website and set it in your console environment:
    export=SENTRY_AUTH_TOKEN="..."
  2. Upload the debug files by recompiling with:
    • -DSENTRY_SEND_DEBUG=1
      • Or the provided script:
    • CI/send_debug_files_to_sentry.sh
  3. Run Mudlet and trigger the crash.
  4. Verify the crash details on the Sentry website.

Motivation for adding to Mudlet

/claim #7126,
fixes #7126.

Other info (issues closed, discussion etc)

I pushed a working snippet for qmake (mudlet.pro) aswell,
Although QMake is expected to be removed out soon, I added this snippet to ensure compatibility for the time being.

@add-deployment-links
Copy link
Copy Markdown

add-deployment-links bot commented Nov 17, 2025

Hey there! Thanks for helping Mudlet improve. 🌟

Test versions

You can directly test the changes here:

No need to install anything - just unzip and run.
Let us know if it works well, and if it doesn't, please give details.

@NicolasKeita NicolasKeita changed the title Add: Sentry integration Infrastructure: Sentry integration Nov 17, 2025
@NicolasKeita NicolasKeita marked this pull request as ready for review November 17, 2025 11:28
@NicolasKeita NicolasKeita requested a review from a team as a code owner November 17, 2025 11:28
@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai bot commented Nov 17, 2025

📝 Walkthrough

Walkthrough

This pull request integrates Sentry crash reporting into Mudlet across multiple build systems and platforms. Changes include adding sentry-native as a Git submodule, updating GitHub workflows to enable recursive submodule initialization and pass Sentry authentication tokens, modifying Windows and Linux build scripts to conditionally compile and configure Sentry support, and creating new source files for Sentry initialization and a Qt-based crash reporter application. Build system modifications span CMake, Qt Pro files, and shell scripts. Additionally, Lua utility functions are refactored to use a custom substitution routine, and debug file upload automation is introduced via CI scripts.

✨ Finishing touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 6

🧹 Nitpick comments (15)
src/mudlet-lua/lua/GUIUtils.lua (1)

2055-2055: Improve comment to explain the reason for custom implementation.

The comment is informal and lacks technical detail about why rex.gsub was crashing. Consider documenting:

  • The specific issue with rex.gsub (e.g., crash conditions, bug reference)
  • Any behavioral differences from the original
  • Limitations of the custom implementation (e.g., only uses first capture group)
--- rex.gsub was crashing so here is a homemade
+-- Custom implementation of rex.gsub to work around crashes in the native implementation.
+-- Note: Only the first capture group is used if the pattern has multiple captures.
src/mudlet-lua/lua/DateTime.lua (2)

49-49: Enhance the comment with crash details.

The comment briefly states that rex.gsub was crashing but lacks important context such as the conditions under which it crashes, affected platforms (Linux/macOS/Windows), or any relation to the Sentry integration. Consider documenting:

  • Specific error or crash behavior observed
  • Platforms or build configurations where the crash occurs
  • Whether this is a known issue with the rex library version in use

50-73: Approve implementation but refactor to eliminate code duplication.

The custom rex_gsub_custom implementation correctly handles the datetime directive substitution use case. The logic is sound: it iterates through matches, assembles output pieces, and properly handles both function and static replacements.

However, this exact function also exists in GUIUtils.lua (lines 2055-2078). Duplicating utility functions across multiple files violates the DRY principle and increases maintenance burden.

Consider extracting this function into a shared utility module (e.g., StringUtils.lua or RexUtils.lua) that both DateTime.lua and GUIUtils.lua can require.

.github/workflows/update-en-us-plural.yml (1)

21-22: Submodule initialization is redundant with checkout configuration.

The checkout step on line 19 already specifies submodules: true, which initializes submodules. The additional recursive initialization step may only be necessary if the sentry-native submodule contains nested submodules that require explicit recursive initialization.

Consider whether the sentry-native submodule actually requires recursive initialization. If it doesn't have nested submodules, you could simplify by either:

  1. Removing this step entirely and relying on the checkout action's submodules: true, or
  2. Changing the checkout action to submodules: recursive and removing this separate step:
     - uses: actions/checkout@v5
       with:
         ref: development
-        submodules: true
+        submodules: recursive
-
-    - name: Init all submodules recursively
-      run: git submodule update --init --recursive
src/sentry_dsn.txt (1)

1-1: Document that users should configure their own Sentry DSN.

This file contains a Sentry DSN (Data Source Name) in plaintext. While DSNs are designed to be client-facing and don't grant access to view crash reports, this appears to be the Mudlet project's DSN. Users building their own forks or variants should be instructed to:

  1. Create their own Sentry project
  2. Replace this DSN with their own
  3. Set appropriate SENTRY_AUTH_TOKEN for debug file uploads

Consider adding a comment or documentation (perhaps in a nearby README or build documentation) explaining:

  • This DSN is for the official Mudlet project
  • Fork maintainers should create their own Sentry project and replace this DSN
  • How to disable Sentry entirely by building without -DWITH_SENTRY=ON

Example comment at the top of this file:

+# Official Mudlet Sentry DSN for crash reporting
+# If you're building a fork, create your own Sentry project at https://sentry.io
+# and replace this DSN with your own, or build without -DWITH_SENTRY=ON
 https://b207505f6b88191fa4bbcb9b166f61ae@o4510296017338368.ingest.de.sentry.io/4510330003849296
.github/workflows/performance-analysis.yml (1)

30-31: Submodule initialization may be redundant with checkout configuration.

The checkout step on line 28 already specifies submodules: true. This additional recursive initialization step is only necessary if nested submodules exist within the sentry-native submodule.

See the comment on .github/workflows/update-en-us-plural.yml lines 21-22 for consolidation options.

.github/workflows/clangtidy-diff-analysis.yml (1)

39-40: Submodule initialization may be redundant with checkout configuration.

The checkout step on line 32 already specifies submodules: true. See the comment on .github/workflows/update-en-us-plural.yml lines 21-22 for consolidation options.

.github/workflows/update-translations.yml (1)

24-25: Submodule initialization may be redundant with checkout configuration.

The checkout step on line 20 already specifies submodules: true. See the comment on .github/workflows/update-en-us-plural.yml lines 21-22 for consolidation options.

.github/workflows/codeql-analysis.yml (1)

49-50: Redundant submodule initialization.

The checkout action at line 47 already has submodules: true, which initializes submodules. The explicit git submodule update --init --recursive step is redundant.

Consider removing this step:

-    - name: Init all submodules recursively
-      run: git submodule update --init --recursive
-

Note: If the intent is to initialize submodules recursively (which submodules: true does not do by default in older actions/checkout versions), you can use submodules: recursive in the checkout step instead.

.github/workflows/update-3rdparty.yml (2)

107-108: Redundant submodule initialization.

The checkout action at line 104 already has submodules: true, making this explicit initialization redundant.

Consider removing this step or use submodules: recursive in the checkout action if recursive initialization is specifically needed:

-      - name: Init all submodules recursively
-        run: git submodule update --init --recursive
-

151-152: Redundant submodule initialization.

The checkout action at line 148 already has submodules: true, making this explicit initialization redundant.

Consider removing this step or use submodules: recursive in the checkout action if recursive initialization is specifically needed:

-      - name: Init all submodules recursively
-        run: git submodule update --init --recursive
-
.github/workflows/build-mudlet.yml (1)

69-70: Redundant submodule initialization.

The checkout action at line 66 already has submodules: true, making this explicit initialization redundant.

Consider removing this step or use submodules: recursive in the checkout action if recursive initialization is specifically needed:

-    - name: Init all submodules recursively
-      run: git submodule update --init --recursive
-
.github/workflows/build-mudlet-win.yml (1)

35-36: Redundant submodule initialization.

The checkout action at line 32 already has submodules: true, making this explicit initialization redundant.

Consider removing this step or use submodules: recursive in the checkout action if recursive initialization is specifically needed:

-    - name: Init all submodules recursively
-      run: git submodule update --init --recursive
-
src/crash_reporter/CMakeLists.txt (1)

7-36: Avoid version duplication and make EXE_MUDLET_TARGET usage more robust

  • APP_VERSION is hard-coded to 4.19.1 here while the main project already carries the version elsewhere (qmake VERSION and top-level CMake). This will drift on the next release and desynchronize Sentry crash reports from the actual app version. Prefer wiring this from the top-level (e.g. via a cache variable, project(VERSION ...), or a generated header) instead of hard-coding it locally.

  • if(TARGET ${EXE_MUDLET_TARGET}) assumes EXE_MUDLET_TARGET is always defined. If this file is ever reused without that variable set, CMake will see if(TARGET ) and error. A safer pattern is:

if(DEFINED EXE_MUDLET_TARGET AND TARGET "${EXE_MUDLET_TARGET}")
    set_target_properties(MudletCrashReporter PROPERTIES
        RUNTIME_OUTPUT_DIRECTORY $<TARGET_FILE_DIR:${EXE_MUDLET_TARGET}>
    )
endif()
  • If you ever include this crash reporter subdirectory from the same CMake build that defines the sentry_native ExternalProject (in WithSentry.cmake), consider adding an explicit dependency so the Sentry libraries are guaranteed to exist before linking, e.g.:
add_dependencies(MudletCrashReporter sentry_native)

This avoids order-of-build surprises when building everything purely via CMake.

CI/send_debug_files_to_sentry.sh (1)

79-81: Remove unused SCRIPT_DIR or put it to use

SCRIPT_DIR is computed but never referenced, which ShellCheck also flags (SC2034). Either drop the assignment or use it to e.g. resolve the script-relative path to send_debug_files_to_sentry.sh or other assets. Keeping unused locals around makes maintenance harder and can hide real issues in static-analysis noise.

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 1bbf944 and abb32ac.

📒 Files selected for processing (26)
  • .github/workflows/build-mudlet-win.yml (2 hunks)
  • .github/workflows/build-mudlet.yml (5 hunks)
  • .github/workflows/clangtidy-diff-analysis.yml (1 hunks)
  • .github/workflows/codeql-analysis.yml (1 hunks)
  • .github/workflows/performance-analysis.yml (1 hunks)
  • .github/workflows/update-3rdparty.yml (2 hunks)
  • .github/workflows/update-en-us-plural.yml (1 hunks)
  • .github/workflows/update-translations.yml (1 hunks)
  • .gitignore (1 hunks)
  • .gitmodules (1 hunks)
  • 3rdparty/sentry-native (1 hunks)
  • CI/build-mudlet-for-windows.sh (1 hunks)
  • CI/package-mudlet-for-windows.sh (1 hunks)
  • CI/send_debug_files_to_sentry.sh (1 hunks)
  • CI/setup-windows-sdk.sh (1 hunks)
  • CMakeLists.txt (1 hunks)
  • src/CMakeLists.txt (2 hunks)
  • src/SentryWrapper.cpp (1 hunks)
  • src/cmake/WithSentry.cmake (1 hunks)
  • src/crash_reporter/CMakeLists.txt (1 hunks)
  • src/crash_reporter/main.cpp (1 hunks)
  • src/main.cpp (2 hunks)
  • src/mudlet-lua/lua/DateTime.lua (2 hunks)
  • src/mudlet-lua/lua/GUIUtils.lua (2 hunks)
  • src/mudlet.pro (2 hunks)
  • src/sentry_dsn.txt (1 hunks)
🧰 Additional context used
🧠 Learnings (1)
📚 Learning: 2025-11-14T14:16:57.626Z
Learnt from: vadi2
Repo: Mudlet/Mudlet PR: 8515
File: test/CMakeLists.txt:56-58
Timestamp: 2025-11-14T14:16:57.626Z
Learning: In the Mudlet Windows MSYS2 build environment, the Qt6Keychain package (mingw-w64-x86_64-qtkeychain-qt6) provides the CMake target named `qt6keychain` (lowercase, non-namespaced), not the standard `Qt6Keychain::Qt6Keychain` target. The test/CMakeLists.txt and src/CMakeLists.txt files correctly use `qt6keychain` for both USE_OWN_QTKEYCHAIN=ON and USE_OWN_QTKEYCHAIN=OFF cases.

Applied to files:

  • .gitmodules
  • src/crash_reporter/CMakeLists.txt
  • CI/package-mudlet-for-windows.sh
🧬 Code graph analysis (3)
src/mudlet-lua/lua/DateTime.lua (1)
src/mudlet-lua/lua/GUIUtils.lua (1)
  • rex_gsub_custom (2056-2079)
src/main.cpp (1)
src/SentryWrapper.cpp (2)
  • initSentry (41-59)
  • initSentry (41-41)
src/mudlet-lua/lua/GUIUtils.lua (1)
src/mudlet-lua/lua/DateTime.lua (1)
  • rex_gsub_custom (50-73)
🪛 actionlint (1.7.8)
.github/workflows/build-mudlet.yml

205-205: shellcheck reported issue in this script: SC2086:info:1:27: Double quote to prevent globbing and word splitting

(shellcheck)


205-205: shellcheck reported issue in this script: SC2086:info:3:33: Double quote to prevent globbing and word splitting

(shellcheck)


205-205: shellcheck reported issue in this script: SC2086:info:5:33: Double quote to prevent globbing and word splitting

(shellcheck)

🪛 Shellcheck (0.11.0)
CI/send_debug_files_to_sentry.sh

[warning] 79-79: SCRIPT_DIR appears unused. Verify use (or export if used externally).

(SC2034)

🔇 Additional comments (18)
.gitignore (1)

14-14: Good addition.

Adding src/crash_reporter/build/ follows the established pattern for ignoring build directories within the repository and appropriately excludes build artifacts from the new crash reporter component introduced in this PR.

src/mudlet-lua/lua/GUIUtils.lua (1)

2084-2084: Verify the custom rex_gsub_custom produces correct results with actual ANSI inputs.

The custom implementation at lines 2056-2076 correctly handles the single capture group from ansiPattern (which captures codes like "0;36;40"). However, no test coverage was found for ansi2string or ansi2decho functions. Since this replaces the native rex.gsub due to crashes, manual verification with representative ANSI escape sequences is recommended to ensure correctness before merging.

Also applies to: 2098-2098

src/mudlet-lua/lua/DateTime.lua (1)

93-93: Code implementation is correct; verify crash resolution and datetime functionality on all platforms.

The rex_gsub_custom workaround is properly implemented and correctly applied at line 93. The function properly uses rex.find() instead of rex.gsub(), and no direct rex.gsub() calls remain in DateTime.lua. The pattern "(%[A-Za-z])" correctly captures datetime directives, and the replacement function appropriately handles directive lookup via datetime._directives.

To ensure the fix fully addresses the issue:

  • Verify the crash no longer occurs on Linux, macOS, and Windows
  • Confirm datetime parsing works correctly with various format strings
  • Consider adding test cases to prevent regressions
.gitmodules (1)

19-21: Submodule entry is well-formed and follows established patterns.

The new sentry-native submodule entry is correctly formatted, consistent with existing submodule definitions, and references the official Sentry repository. The path placement in 3rdparty/ aligns with the project's dependency organization.

To ensure smooth integration, verify that all CI workflows and developer setup documentation include git clone --recurse-submodules or equivalent initialization to fetch this submodule. The PR objectives mention CI integration with submodule initialization—confirm that workflows like .github/workflows/build.yml include the necessary git submodule update --init --recursive steps and that the Sentry DSN and auth token environment variables are properly configured downstream in build steps.

3rdparty/sentry-native (1)

1-1: Submodule configuration verified as correct.

All verification checks passed:

  • .gitmodules: Properly configured with sentry-native pointing to https://github.com/getsentry/sentry-native.git
  • CMake integration: src/cmake/WithSentry.cmake correctly references 3rdparty/sentry-native and uses ExternalProject_Add for building
  • CI submodule initialization: Both build-mudlet.yml and build-mudlet-win.yml initialize submodules via actions/checkout@v5 with submodules: true and explicit git submodule update --init --recursive commands
  • Build system configuration: Properly integrated and will build from the submodule

The submodule pointer update is correctly configured and will function as intended in CI/CD pipelines.

src/main.cpp (2)

60-60: LGTM: Forward declaration properly placed.

The forward declaration of initSentry() is correctly positioned with other forward declarations.


163-165: LGTM: Sentry initialization correctly placed early in main().

The Sentry initialization is properly guarded by #ifdef WITH_SENTRY and called very early in main(), before QApplication construction. This is the correct placement for crash reporting initialization, as it needs to be active before any potential crashes occur.

src/CMakeLists.txt (2)

112-112: SentryWrapper.cpp verified successfully.

The file exists at src/SentryWrapper.cpp and contains the complete initSentry() function implementation with proper Sentry initialization logic, conditional compilation guards, and helper utilities for platform-specific paths.


701-705: The review comment is incorrect. The Sentry options are properly declared in the root CMakeLists.txt.

The WITH_SENTRY and SENTRY_SEND_DEBUG options are correctly declared at CMakeLists.txt:81-82 (not in src/CMakeLists.txt). This is the proper CMake pattern—options are declared in the root CMakeLists.txt and inherited by subdirectories. The code at src/CMakeLists.txt:701 correctly uses WITH_SENTRY as a CMake variable without needing to declare it again.

However, a real issue exists: the code at line 702 includes cmake/WithSentry.cmake, but this file does not exist in the repository.

Likely an incorrect or invalid review comment.

CI/setup-windows-sdk.sh (1)

128-132: Based on verification results, I can now provide the rewritten review comment:


Remove duplicate cmake package; verify lld and uasm necessity.

Line 132 adds mingw-w64-${BUILDCOMPONENT}-cmake, but this package is already listed on line 124, creating a redundant specification.

Additionally, mingw-w64-${BUILDCOMPONENT}-lld and mingw-w64-${BUILDCOMPONENT}-uasm show no direct usage in the codebase (not found in Sentry build files or CMake configuration). While curl and clang are confirmed necessary for Sentry integration, verify that lld and uasm are required as transitive dependencies or general MinGW toolchain components before including them.

Apply this diff to remove the duplicate:

     "mingw-w64-${BUILDCOMPONENT}-curl" \
     "mingw-w64-${BUILDCOMPONENT}-uasm" \
     "mingw-w64-${BUILDCOMPONENT}-clang" \
-    "mingw-w64-${BUILDCOMPONENT}-lld" \
-    "mingw-w64-${BUILDCOMPONENT}-cmake"; then
+    "mingw-w64-${BUILDCOMPONENT}-lld"; then
       break
   fi
CMakeLists.txt (1)

81-82: LGTM! Clean CMake option declarations.

The two new options for Sentry integration are well-named and appropriately defaulted to OFF, allowing opt-in behavior.

CI/build-mudlet-for-windows.sh (1)

148-154: LGTM! Conditional Sentry flag injection is correct.

The conditional logic properly appends Sentry-related CMake arguments to CMAKE_ARGS when the environment variables are set.

.github/workflows/build-mudlet.yml (2)

160-160: LGTM! Appropriate dependencies for Sentry integration.

The addition of libcurl4-openssl-dev, libssl-dev, openssl, and ca-certificates is necessary for Sentry's HTTP transport functionality.

Also applies to: 174-176


258-259: LGTM! Sentry CMake flags properly configured.

The Sentry flags are correctly passed to CMake, and SENTRY_AUTH_TOKEN is properly exposed for authenticated operations during the build.

Also applies to: 262-262

.github/workflows/build-mudlet-win.yml (2)

80-80: LGTM! SENTRY_AUTH_TOKEN properly exposed.

The authentication token is correctly passed to the build environment for Sentry operations.


45-55: Quote variable to prevent word splitting.

The shell script uses an unquoted variable that should be quoted.

Apply this diff:

       run: |
         echo "WITH_SENTRY=yes" >> $GITHUB_ENV
-        if [ -n "$SENTRY_SEND_DEBUG_SECRET" ]; then
+        if [ -n "${SENTRY_SEND_DEBUG_SECRET}" ]; then
           echo "SENTRY_SEND_DEBUG=1" >> $GITHUB_ENV
         else
           echo "SENTRY_SEND_DEBUG=0" >> $GITHUB_ENV

Likely an incorrect or invalid review comment.

src/crash_reporter/main.cpp (1)

57-57: SENTRY_DSN is properly defined via CMake configuration.

Verification confirms that SENTRY_DSN is correctly configured as a compile-time flag. The build system reads the DSN from src/sentry_dsn.txt and passes it as -DSENTRY_DSN=... to the compiler via target_compile_definitions() in src/crash_reporter/CMakeLists.txt (line 30) and src/cmake/WithSentry.cmake.

src/mudlet.pro (1)

616-674: Fix platform-specific code in qmake WITH_SENTRY block and avoid baking build-tree paths into binaries

  1. WITH_SENTRY block lacks Windows-only guards; will fail on Linux/macOS

The qmake WITH_SENTRY { ... } block (line 616) contains Windows-specific code without platform guards:

  • Line 648: -lwinhttp -ldbghelp -lversion are linked unconditionally
  • Lines 656, 670, 673: Post-link commands reference mudlet.exe unconditionally
  • Line 673: strip --strip-debug $$APP_DIR_PATH/mudlet.exe will fail if mudlet.exe doesn't exist

The CMake build (src/cmake/WithSentry.cmake) correctly guards these with if(WIN32), if(APPLE), and if(UNIX) blocks, but the qmake build does not. Wrap Windows-specific code:

win32:WITH_SENTRY {
    # current content
}

or move cross-platform logic to CMake only and disable qmake+Sentry on non-Windows.

  1. Compile-time APP_DIR_PATH from build tree breaks post-install relocation

APP_DIR_PATH = $$OUT_PWD/$$BUILD_SUBDIR (line 629) is compiled into the binary via DEFINES. Once Mudlet is packaged and installed elsewhere, this path no longer exists. SentryWrapper.cpp lines 53–54 rely on this hardcoded path to locate crashpad_handler and MudletCrashReporter at runtime, so the app will crash if binaries are moved.

Replace with QCoreApplication::applicationDirPath() at runtime instead of hardcoding. This also eliminates duplication between qmake and CMake (which defines APP_DIR_PATH="${CMAKE_BINARY_DIR}/src" separately).

  1. DSN and toolchain assumptions differ between qmake and CMake
  • qmake line 626 reads SENTRY_DSN = $$system(cat $$PWD/sentry_dsn.txt) without trimming; if sentry_dsn.txt has a trailing newline, the macro will include it. CMake correctly uses string(STRIP ...) to remove whitespace.
  • Both qmake and CMake force -DCMAKE_C_COMPILER=clang and -DCMAKE_CXX_COMPILER=clang++ unconditionally. On systems with no clang or when the main build uses GCC, this can fail or cause mixed-toolchain linking issues. Let CMake detect or inherit the compiler from the main build.
  1. SentryWrapper.cpp inclusion is properly guarded

File correctly uses #ifdef WITH_SENTRY (lines 21–23, 45–57), so unconditional inclusion in SOURCES is safe.

Comment on lines +2056 to +2079
local function rex_gsub_custom(str, pattern, repl)
local out = {}
local last_end = 1

while true do
local start_pos, end_pos, cap = rex.find(str, pattern, last_end)
if not start_pos then
table.insert(out, str:sub(last_end))
break
end

table.insert(out, str:sub(last_end, start_pos - 1))

if type(repl) == "function" then
table.insert(out, repl(cap))
else
table.insert(out, repl)
end

last_end = end_pos + 1
end

return table.concat(out)
end
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion | 🟠 Major

Extract duplicated rex_gsub_custom to a shared utility module.

This function is identical to the one in DateTime.lua (lines 49-72). Code duplication increases maintenance burden—if a bug is found or enhancement is needed, both copies must be updated.

Consider extracting this to a shared utility module (e.g., LuaGlobal.lua or a new StringUtils.lua) and importing it in both files.

-- In a shared utility module:
function rex_gsub_custom(str, pattern, repl)
    local out = {}
    local last_end = 1

    while true do
        local start_pos, end_pos, cap = rex.find(str, pattern, last_end)
        if not start_pos then
            table.insert(out, str:sub(last_end))
            break
        end

        table.insert(out, str:sub(last_end, start_pos - 1))

        if type(repl) == "function" then
            table.insert(out, repl(cap))
        else
            table.insert(out, repl)
        end

        last_end = end_pos + 1
    end

    return table.concat(out)
end
🤖 Prompt for AI Agents
In src/mudlet-lua/lua/GUIUtils.lua around lines 2056 to 2079, the
rex_gsub_custom implementation is duplicated from DateTime.lua; extract this
function into a shared utility module (e.g., src/mudlet-lua/lua/StringUtils.lua
or LuaGlobal.lua) that returns/exports rex_gsub_custom, replace the local
definition in GUIUtils.lua with a require(...) import and call the imported
function, remove the duplicate from DateTime.lua and update it to require the
same shared module, ensure the new module uses the same function signature,
update any local references if needed, and run the project/tests to confirm no
breakages.

Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 3

♻️ Duplicate comments (4)
src/cmake/WithSentry.cmake (4)

11-12: This issue was previously flagged: Remove hard-coded toolchain and generator.

As noted in the previous review, forcing clang/clang++ and Ninja (lines 11-12, 16) breaks builds on systems where these tools are unavailable or when the main project uses a different toolchain (MSVC, GCC). The ExternalProject should inherit the parent's toolchain and generator.

Also applies to: 16-16


66-66: This issue was previously flagged: Remove APP_DIR_PATH compile definition.

As noted in the previous review, APP_DIR_PATH="${CMAKE_BINARY_DIR}/src" (lines 66, 72) bakes a build-time path into the binary that won't exist after installation. The runtime code should use QCoreApplication::applicationDirPath() instead.

Also applies to: 72-72


92-92: This issue was previously flagged: Unconditional curl linking will fail on Windows.

As noted in the previous review, curl is linked unconditionally (line 92) but SENTRY_TRANSPORT=curl is only set for UNIX AND NOT APPLE (line 20). On Windows or systems without libcurl, this will cause link failures. Either guard the curl link with UNIX AND NOT APPLE or verify that sentry-native provides it.


138-138: This issue was previously flagged: bash dependency breaks Windows builds.

As noted in the previous review, the bash command (line 138) will fail on Windows systems without bash. If this feature is CI-only, document it; otherwise, guard it with UNIX or provide a portable wrapper.

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between abb32ac and 6ff4d68.

📒 Files selected for processing (1)
  • src/cmake/WithSentry.cmake (1 hunks)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (6)
  • GitHub Check: ubuntu / clang
  • GitHub Check: ubuntu / gcc / lua tests
  • GitHub Check: ubuntu (x86_64)
  • GitHub Check: macos (arm64) / c++, lua tests
  • GitHub Check: macos (x86_64) / c++, lua tests
  • GitHub Check: windows64

Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 0

♻️ Duplicate comments (1)
src/crash_reporter/main.cpp (1)

24-28: Avoid private Sentry headers/transport internals and add proper error handling & cleanup.

This function still relies on Sentry’s internal transport details and lacks basic error handling/cleanup:

  • Lines 24–28: Including "sentry_options.h" and "sentry_transport.h" exposes you to internal, unstable APIs. The public integration should only need "sentry.h".
  • Lines 52–63: opts->transport and the sentry__transport_* calls are private/internal APIs; they depend on the layout of sentry_options_t and can break with Sentry upgrades. There’s also:
    • No check that the envelope file exists or is readable before calling sentry_envelope_read_from_file.
    • No logging on failure.
    • No sentry_options_free or sentry_envelope_free on any path (including the if (!opts || !envelope) early return), leaking resources.

Refactor this to use only the documented public API and clean up resources, e.g.:

-#include "sentry.h"
-#include "sentry_options.h"
-extern "C" {
-    #include "sentry_transport.h"
-}
+#include "sentry.h"
@@
 void sendCrashReport(const char *envelopePath)
 {
-    sentry_options_t *  opts = sentry_options_new();
-    sentry_envelope_t * envelope = sentry_envelope_read_from_file(envelopePath);
-
-    if (!opts || !envelope) {
-        return;
-    }
-    sentry_options_set_dsn(opts, SENTRY_DSN);
-    sentry__transport_startup(opts->transport, opts);
-    sentry__transport_send_envelope(opts->transport, envelope);
-    sentry__transport_shutdown(opts->transport, 30 * 1000);
+    QFileInfo fileInfo(envelopePath);
+    if (!fileInfo.exists() || !fileInfo.isReadable()) {
+        qWarning() << "Envelope file does not exist or is not readable:" << envelopePath;
+        return;
+    }
+
+    sentry_options_t *opts = sentry_options_new();
+    if (!opts) {
+        qWarning() << "Failed to create Sentry options";
+        return;
+    }
+
+    sentry_envelope_t *envelope = sentry_envelope_read_from_file(envelopePath);
+    if (!envelope) {
+        qWarning() << "Failed to read envelope from file:" << envelopePath;
+        sentry_options_free(opts);
+        return;
+    }
+
+    sentry_options_set_dsn(opts, SENTRY_DSN);
+
+    // Use public API: initialize, capture the envelope, then shut down.
+    if (sentry_init(opts) == 0) {
+        sentry_capture_envelope(envelope);  // Sentry now owns the envelope.
+        sentry_close();
+    } else {
+        qWarning() << "Failed to initialize Sentry";
+        sentry_envelope_free(envelope);
+        sentry_options_free(opts);
+    }
 }

Note: Adjust the exact calls if your sentry-native version differs, but the key points are:

  • Drop the private headers and sentry__transport_* usage.
  • Use sentry_init / sentry_capture_envelope / sentry_close as the public flow.
  • Ensure every allocation (opts, envelope) is freed on failure paths.

Also applies to: 52-63

🧹 Nitpick comments (3)
src/SentryWrapper.h (1)

1-8: Add header guard / pragma once and fix minor header hygiene (optional).

This header is small but should still follow typical header hygiene: add an include guard or #pragma once, and ensure there is a newline at EOF. If the project expects a GPL copyright header on all public headers (as in src/crash_reporter/main.cpp), consider adding the standard license block here for consistency.

src/mudlet-lua/lua/StringUtils.lua (2)

224-224: Potential infinite loop risk with zero-width matches.

While advancing by end_pos + 1 (line 235) generally prevents infinite loops, if rex.find returns start_pos == end_pos for a zero-width match at the end of the string, the next iteration will start beyond the string length. Consider adding a safeguard to detect when start_pos == end_pos == #str to explicitly break.

Apply this diff to add a safeguard:

     local start_pos, end_pos, cap = rex.find(str, pattern, last_end)
-    if not start_pos then
+    if not start_pos or (start_pos == end_pos and end_pos == #str) then
       table.insert(out, str:sub(last_end))
       break
     end

219-220: Add documentation for the new global function.

Since rex_gsub_custom is now part of the public API used across multiple modules, it should have documentation similar to other functions in this file. Include the purpose, parameters, return value, and any known limitations (e.g., multiple captures, return value compatibility).

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 58a2447 and f194c1c.

📒 Files selected for processing (16)
  • .github/workflows/build-mudlet-win.yml (3 hunks)
  • .github/workflows/build-mudlet.yml (5 hunks)
  • .github/workflows/clangtidy-diff-analysis.yml (1 hunks)
  • .github/workflows/codeql-analysis.yml (1 hunks)
  • .github/workflows/performance-analysis.yml (1 hunks)
  • .github/workflows/update-3rdparty.yml (2 hunks)
  • .github/workflows/update-en-us-plural.yml (1 hunks)
  • .github/workflows/update-translations.yml (1 hunks)
  • src/CMakeLists.txt (3 hunks)
  • src/SentryWrapper.cpp (1 hunks)
  • src/SentryWrapper.h (1 hunks)
  • src/crash_reporter/main.cpp (1 hunks)
  • src/main.cpp (2 hunks)
  • src/mudlet-lua/lua/DateTime.lua (2 hunks)
  • src/mudlet-lua/lua/GUIUtils.lua (2 hunks)
  • src/mudlet-lua/lua/StringUtils.lua (1 hunks)
🚧 Files skipped from review as they are similar to previous changes (11)
  • .github/workflows/clangtidy-diff-analysis.yml
  • src/CMakeLists.txt
  • src/mudlet-lua/lua/GUIUtils.lua
  • src/SentryWrapper.cpp
  • .github/workflows/update-3rdparty.yml
  • src/mudlet-lua/lua/DateTime.lua
  • .github/workflows/codeql-analysis.yml
  • .github/workflows/build-mudlet.yml
  • .github/workflows/performance-analysis.yml
  • .github/workflows/update-en-us-plural.yml
  • src/main.cpp
🧰 Additional context used
🧬 Code graph analysis (1)
src/SentryWrapper.h (1)
src/SentryWrapper.cpp (4)
  • makeExecutablePath (58-64)
  • makeExecutablePath (58-58)
  • initSentry (39-56)
  • initSentry (39-39)
🪛 GitHub Check: CodeFactor
src/SentryWrapper.h

[notice] 8-8: src/SentryWrapper.h#L8
Could not find a newline character at the end of the file. (whitespace/ending_newline)


[notice] 1-1: src/SentryWrapper.h#L1
No copyright message found. You should have a line: "Copyright [year] ". (legal/copyright)

⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (6)
  • GitHub Check: windows64
  • GitHub Check: ubuntu / gcc / lua tests
  • GitHub Check: macos (x86_64) / c++, lua tests
  • GitHub Check: macos (arm64) / c++, lua tests
  • GitHub Check: ubuntu (x86_64)
  • GitHub Check: ubuntu / clang
🔇 Additional comments (4)
src/mudlet-lua/lua/StringUtils.lua (1)

218-238: Let me search for more context about the rex.gsub crash:

No critical issues found. The implementation is correct for actual usage patterns.

The script output reveals that the original review comment's concerns about API incompatibility do not reflect actual usage:

  1. Multiple captures: All patterns in the codebase have exactly ONE capture group:

    • DateTime.lua uses (%[A-Za-z]) with one capture
    • GUIUtils.lua uses \\e\\[([0-9:;]*?)m with one capture
    • The function correctly handles this case
  2. Return value incompatibility: No callers expect a count return value; all assign the result to a single variable

  3. Root cause: GUIUtils.lua confirms "rex.gsub was crashing", indicating a legitimate issue with the rex library itself. Implementing a workaround is appropriate for library crashes.

The custom implementation is fit for purpose in this codebase, though it remains less general than rex.gsub (e.g., only handles single captures). For the current usage patterns, this is not a concern.

.github/workflows/update-translations.yml (1)

17-22: Submodule initialization strategy is consistent across workflows.

The change from submodules: true to submodules: recursive aligns with the PR's broader approach to initializing the new sentry-native git submodule across all CI workflows.

.github/workflows/build-mudlet-win.yml (2)

42-52: Sentry enablement step is well-designed and follows PR guidance.

The conditional logic for SENTRY_SEND_DEBUG correctly gates debug symbol uploads behind secret presence, aligning with the PR objective: "set secrets.SENTRY_SEND_DEBUG=1 to allow CI to upload debug symbol files."


70-78: Verify downstream build script handles Sentry environment variables correctly.

The SENTRY_AUTH_TOKEN, WITH_SENTRY, and SENTRY_SEND_DEBUG environment variables are now passed to the build step. Ensure CI/build-mudlet-for-windows.sh correctly:

  1. Receives and passes these variables to CMake
  2. Handles the case where SENTRY_AUTH_TOKEN may be empty (if the secret is not set)
  3. Properly configures debug symbol upload when SENTRY_SEND_DEBUG=1

Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

♻️ Duplicate comments (1)
src/SentryWrapper.cpp (1)

39-42: Cache path doc vs actual QStandardPaths layout

The comment (Lines 39–42) documents cache paths like ~/.cache/mudlet/sentry, but QStandardPaths::CacheLocation is already app‑specific. Appending "/mudlet/sentry" on Line 49 can easily yield something like ~/.cache/mudlet/mudlet/sentry (or ~/.cache/Mudlet/mudlet/sentry), which diverges from what’s documented.

To align behavior with the comment, either:

  • Base this on GenericCacheLocation and append "mudlet/sentry", or
  • Append only "/sentry" to CacheLocation and update the comment accordingly.

Also applies to: 49-49

🧹 Nitpick comments (4)
src/SentryWrapper.h (2)

23-26: Avoid pulling Sentry/Qt internals into this public header

The header doesn’t use qScopeGuard or any Sentry types; only the implementation in SentryWrapper.cpp needs them. Including <QtCore/qscopeguard.h> and "sentry.h" here increases coupling and rebuild surface for every includer. Consider moving these includes into SentryWrapper.cpp and keeping the header limited to <string> and forward declarations.


34-34: Add trailing newline to satisfy linters

CodeFactor is flagging the missing newline at end of file. Adding a final newline after Line 34 will silence the warning and follow the usual POSIX text‑file convention.

src/SentryWrapper.cpp (2)

44-62: Wire sentry_close() to application shutdown rather than never calling it

initSentry() now initializes Sentry and leaves it running for the process lifetime, which is much better than the previous immediate sentry_close(). However, there is currently no shutdown at all, so queued events may not be flushed on clean exit and SDK resources are never released.

Consider:

  • Ensuring initSentry() is only called once (e.g., with a static bool initialized guard), and
  • Registering a single sentry_close() at application shutdown (e.g., via a static qScopeGuard, std::atexit, or a QCoreApplication::aboutToQuit handler).

This keeps crash reporting active while still following sentry‑native’s recommended init/close lifecycle.


91-91: Add trailing newline to satisfy linters

Similar to the header, CodeFactor is reporting a missing newline at end of file. Adding a final newline after Line 91 will clear the warning.

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between f194c1c and 306bee1.

📒 Files selected for processing (3)
  • .github/workflows/performance-analysis.yml (1 hunks)
  • src/SentryWrapper.cpp (1 hunks)
  • src/SentryWrapper.h (1 hunks)
🧰 Additional context used
🧬 Code graph analysis (1)
src/SentryWrapper.h (1)
src/SentryWrapper.cpp (6)
  • initSentry (44-62)
  • initSentry (44-44)
  • makeExecutablePath (64-71)
  • makeExecutablePath (64-64)
  • getExeDir (73-91)
  • getExeDir (73-73)
🪛 GitHub Check: CodeFactor
src/SentryWrapper.cpp

[notice] 91-91: src/SentryWrapper.cpp#L91
Could not find a newline character at the end of the file. (whitespace/ending_newline)


[failure] 86-86: src/SentryWrapper.cpp#L86
Possible race condition (CWE-362, CWE-20) (flawfinder7-readlink)

src/SentryWrapper.h

[notice] 34-34: src/SentryWrapper.h#L34
Could not find a newline character at the end of the file. (whitespace/ending_newline)

⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (6)
  • GitHub Check: windows64
  • GitHub Check: macos (arm64) / c++, lua tests
  • GitHub Check: ubuntu / clang
  • GitHub Check: ubuntu / gcc / lua tests
  • GitHub Check: macos (x86_64) / c++, lua tests
  • GitHub Check: ubuntu (x86_64)
🔇 Additional comments (2)
.github/workflows/performance-analysis.yml (1)

24-28: The build is compatible with recursive submodule initialization.

Verification confirms:

  • WITH_SENTRY defaults to OFF
  • crash_reporter (which requires sentry-native) is only added to the build when WITH_SENTRY=ON, and this is already guarded in src/CMakeLists.txt
  • Since the performance-analysis workflow does not set WITH_SENTRY, the build will succeed without attempting to use the sentry-native submodule
  • The submodule will be fetched recursively but remain unused—slightly inefficient but not a correctness issue

The change to submodules: recursive is safe.

src/SentryWrapper.cpp (1)

64-71: makeExecutablePath helper looks good

The platform split here (adding .exe only on Windows) is straightforward and appropriate; no issues spotted with this helper.

Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 0

♻️ Duplicate comments (1)
src/SentryWrapper.cpp (1)

54-54: Remove redundant "mudlet" subdirectory nesting in cache path.

QStandardPaths::CacheLocation is application-specific and already includes the app name in the path. Mudlet sets setApplicationName("Mudlet") and setOrganizationName("Mudlet"), so CacheLocation on Linux resolves to ~/.cache/mudlet. Appending /mudlet/sentry creates redundant nesting: ~/.cache/mudlet/mudlet/sentry.

Other cache usages in the codebase—dlgProfilePreferences.cpp:3496 and TMedia.cpp:904—use CacheLocation directly without adding /mudlet. Align with this pattern:

-        QString path = QStandardPaths::writableLocation(QStandardPaths::CacheLocation) + "/mudlet/sentry";
+        QString path = QStandardPaths::writableLocation(QStandardPaths::CacheLocation) + "/sentry";
🧹 Nitpick comments (3)
src/SentryWrapper.h (1)

23-26: Remove unused qscopeguard.h include.

The #include <QtCore/qscopeguard.h> is no longer needed. The original implementation used qScopeGuard to call sentry_close(), but that code was removed per previous review feedback. Since qscopeguard.h serves no purpose now, remove it to reduce unnecessary dependencies.

Apply this diff:

 #ifdef WITH_SENTRY
-    #include <QtCore/qscopeguard.h>
     #include "sentry.h"
 #endif
src/SentryWrapper.cpp (2)

53-53: Consider using Qt's applicationDirPath() for simplicity and consistency.

The current getExeDir() implementation works correctly across platforms, but the codebase already uses QCoreApplication::applicationDirPath() extensively elsewhere. Using Qt's API here would:

  • Reduce platform-specific code
  • Improve maintainability
  • Align with established patterns in the codebase

Apply this diff:

-        std::string         runtimeAppDir = getExeDir();
+        std::string         runtimeAppDir = QCoreApplication::applicationDirPath().toStdString();

If you adopt this, you could also simplify or remove the getExeDir() function if it's not needed elsewhere. Note that initSentry() must be called after the QCoreApplication instance is created in main().

Also applies to: 62-63


78-114: Consider caching the executable directory for better performance.

The function is thread-safe, but it recomputes the executable path on every call. Since this path doesn't change during process lifetime, you could cache it:

 std::string getExeDir()
 {
-    static std::mutex mtx;
-    std::lock_guard<std::mutex> lock(mtx);
+    static std::once_flag flag;
+    static std::string cachedDir;
+    
+    std::call_once(flag, []() {
 
     #if defined(_WIN32) || defined(_WIN64)
         char path[MAX_PATH];
         GetModuleFileNameA(NULL, path, MAX_PATH);
         std::string exePath(path);
         size_t pos = exePath.find_last_of("\\/");
-        std::string dir = exePath.substr(0, pos);
-        std::replace(dir.begin(), dir.end(), '\\', '/');
-
-        return dir;
+        cachedDir = exePath.substr(0, pos);
+        std::replace(cachedDir.begin(), cachedDir.end(), '\\', '/');
     #elif defined(__APPLE__)
         char path[PATH_MAX];
         uint32_t size = sizeof(path);
         if (_NSGetExecutablePath(path, &size) != 0) {
-            return ".";
+            cachedDir = ".";
+            return;
         }
         std::string exePath(path);
         size_t pos = exePath.find_last_of("/");
         if (pos == std::string::npos) {
-            return exePath;
+            cachedDir = exePath;
+            return;
         }
-        return exePath.substr(0, pos);
+        cachedDir = exePath.substr(0, pos);
     #else
         char result[PATH_MAX];
         ssize_t count = readlink("/proc/self/exe", result, PATH_MAX);
         if (count <= 0) {
-            return std::string(".");
+            cachedDir = ".";
+            return;
         }
         std::string exePath(result, count);
         size_t pos = exePath.find_last_of("/");
-        return exePath.substr(0, pos);
+        cachedDir = exePath.substr(0, pos);
     #endif
+    });
+    
+    return cachedDir;
 }

Note: The static analysis warning about a race condition at line 106 (readlink("/proc/self/exe")) is a false positive—reading /proc/self/exe is safe and has no time-of-check-to-time-of-use issue.

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 306bee1 and d7a5811.

📒 Files selected for processing (2)
  • src/SentryWrapper.cpp (1 hunks)
  • src/SentryWrapper.h (1 hunks)
🧰 Additional context used
🧬 Code graph analysis (1)
src/SentryWrapper.h (1)
src/SentryWrapper.cpp (6)
  • initSentry (49-67)
  • initSentry (49-49)
  • makeExecutablePath (69-76)
  • makeExecutablePath (69-69)
  • getExeDir (78-114)
  • getExeDir (78-78)
🪛 GitHub Check: CodeFactor
src/SentryWrapper.cpp

[failure] 86-86: src/SentryWrapper.cpp#L86
Possible race condition (CWE-362, CWE-20) (flawfinder7-readlink)

⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (6)
  • GitHub Check: windows64
  • GitHub Check: macos (x86_64) / c++, lua tests
  • GitHub Check: macos (arm64) / c++, lua tests
  • GitHub Check: ubuntu / gcc / lua tests
  • GitHub Check: ubuntu (x86_64)
  • GitHub Check: ubuntu / clang
🔇 Additional comments (1)
src/SentryWrapper.cpp (1)

69-76: LGTM!

The platform-specific executable path construction is correct and straightforward.

Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🧹 Nitpick comments (1)
src/SentryWrapper.cpp (1)

78-82: Consider whether the mutex is necessary

The mutex protects getExeDir() for thread safety, but the executable path is constant throughout the process lifetime and the platform APIs used are thread-safe for reads. Even if multiple threads call simultaneously, they'd compute the same result and return by value (no shared mutable state).

The mutex adds overhead (minimal, but measureable if called frequently), though it provides defensive safety. If getExeDir() is only called once at startup via initSentry(), the mutex is harmless but not strictly necessary.

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between d7a5811 and b426211.

📒 Files selected for processing (2)
  • src/SentryWrapper.cpp (1 hunks)
  • src/TBuffer.cpp (1 hunks)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (6)
  • GitHub Check: windows64
  • GitHub Check: macos (arm64) / c++, lua tests
  • GitHub Check: macos (x86_64) / c++, lua tests
  • GitHub Check: ubuntu / clang
  • GitHub Check: ubuntu / gcc / lua tests
  • GitHub Check: ubuntu (x86_64)
🔇 Additional comments (1)
src/SentryWrapper.cpp (1)

54-65: Remove invalid dangling pointer concern at line 60; verify string handling at lines 62-63 and error handling at line 65

The web search confirmed that the Sentry C SDK's sentry_options_set_database_path copies the string into the options (not merely storing your pointer), making line 60 safe. However, two other concerns warrant manual verification:

Lines 62-63: Verify string copying for handler and reporter paths

The Sentry documentation does not explicitly confirm whether sentry_options_set_handler_path and sentry_options_set_external_crash_reporter_path copy strings or store pointers. To be safe, consider storing the temporary std::string results before passing them:

const std::string handlerPath = makeExecutablePath(runtimeAppDir, "crashpad_handler");
const std::string reporterPath = makeExecutablePath(runtimeAppDir, "MudletCrashReporter");
sentry_options_set_handler_path(options, handlerPath.c_str());
sentry_options_set_external_crash_reporter_path(options, reporterPath.c_str());

Line 65: Consider error handling for sentry_init()

While the official Sentry examples show sentry_init(options) called without error checking, the function's return value semantics are undocumented. You may optionally check for errors:

if (sentry_init(options) != 0) {
    // Handle initialization failure
}

@vadi2
Copy link
Copy Markdown
Member

vadi2 commented Nov 18, 2025

@NicolasKeita feel free to stop when you feel coderabbit comments are enough, your call

@NicolasKeita
Copy link
Copy Markdown
Contributor Author

@vadi2 I’ve just finished reviewing all of the CodeRabbit comments. The PR should now be in good shape. I had actually missed one thing initially, so codeRabbit was helpful :)

Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 6

🧹 Nitpick comments (1)
src/mudlet.pro (1)

658-659: Add error handling for crash_reporter build.

The cmake commands to configure and build crash_reporter lack error checking. If these commands fail, the build continues silently, potentially leading to runtime issues.

Add error checking similar to the pattern used elsewhere in qmake:

-    system(cmake -S $$PWD/crash_reporter/ -B $$PWD/crash_reporter/build/ -DCMAKE_RUNTIME_OUTPUT_DIRECTORY=$$APP_DIR_PATH/)
-    system(cmake --build $$PWD/crash_reporter/build/)
+    !system(cmake -S $$PWD/crash_reporter/ -B $$PWD/crash_reporter/build/ -DCMAKE_RUNTIME_OUTPUT_DIRECTORY=$$APP_DIR_PATH/) {
+        error("Failed to configure crash_reporter with CMake")
+    }
+    !system(cmake --build $$PWD/crash_reporter/build/) {
+        error("Failed to build crash_reporter")
+    }

Apply the same pattern to the sentry-native build commands at lines 637-639.

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 861bd6c and ec69375.

📒 Files selected for processing (1)
  • src/mudlet.pro (2 hunks)
🧰 Additional context used
🧠 Learnings (2)
📓 Common learnings
Learnt from: NicolasKeita
Repo: Mudlet/Mudlet PR: 8540
File: CI/package-mudlet-for-windows.sh:111-113
Timestamp: 2025-11-18T19:24:57.339Z
Learning: In CI/package-mudlet-for-windows.sh for the Mudlet project, when WITH_SENTRY is enabled, the Sentry binaries (crashpad_handler.exe and crashpad_wer.dll) are mandatory and the script should fail with an error if they are missing, rather than continuing with a warning.
📚 Learning: 2025-11-18T19:24:57.339Z
Learnt from: NicolasKeita
Repo: Mudlet/Mudlet PR: 8540
File: CI/package-mudlet-for-windows.sh:111-113
Timestamp: 2025-11-18T19:24:57.339Z
Learning: In CI/package-mudlet-for-windows.sh for the Mudlet project, when WITH_SENTRY is enabled, the Sentry binaries (crashpad_handler.exe and crashpad_wer.dll) are mandatory and the script should fail with an error if they are missing, rather than continuing with a warning.

Applied to files:

  • src/mudlet.pro
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (6)
  • GitHub Check: windows64
  • GitHub Check: ubuntu (x86_64)
  • GitHub Check: ubuntu / gcc / lua tests
  • GitHub Check: macos (x86_64) / c++, lua tests
  • GitHub Check: ubuntu / clang
  • GitHub Check: macos (arm64) / c++, lua tests

Comment on lines +634 to +640
!exists($$SENTRY_PATH/install) {
message("Sentry install missing, building sentry-native from sources")

system(cmake -S $$SENTRY_PATH -B $$SENTRY_PATH/build -DCMAKE_C_COMPILER=clang -DCMAKE_CXX_COMPILER=clang++ -DSENTRY_BACKEND=crashpad -D SENTRY_BUILD_SHARED_LIBS=OFF --log-level=ERROR)
system(cmake --build $$SENTRY_PATH/build --parallel)
system(cmake --install $$SENTRY_PATH/build --prefix $$SENTRY_PATH/install)
}
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

Major: Missing git submodule initialization for sentry-native.

The code checks if $$SENTRY_PATH/install exists and attempts to build sentry-native if missing, but there's no check or initialization of the git submodule itself (unlike other dependencies).

Other dependencies in this file (edbee-lib, lcf, qtkeychain) properly check for submodule presence and initialize them if needed (see lines 520-569). According to the PR objectives, sentry-native is added as a git submodule.

Add submodule initialization before the install check, following the pattern used for other dependencies:

     SENTRY_PATH = $$PWD/../3rdparty/sentry-native
+
+    win32 {
+        !exists("$${PWD}/../3rdparty/sentry-native/CMakeLists.txt") {
+            message("git submodule for required sentry-native source code missing, executing 'git submodule update --init' to get it...")
+            system("cd $${PWD}\.. & git submodule update --init 3rdparty/sentry-native")
+        }
+    } else {
+        !exists("$${PWD}/../3rdparty/sentry-native/CMakeLists.txt") {
+            message("git submodule for required sentry-native source code missing, executing 'git submodule update --init' to get it...")
+            system("cd $${PWD}/.. ; git submodule update --init 3rdparty/sentry-native")
+        }
+    }
 
     !exists($$SENTRY_PATH/install) {
         message("Sentry install missing, building sentry-native from sources")
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
!exists($$SENTRY_PATH/install) {
message("Sentry install missing, building sentry-native from sources")
system(cmake -S $$SENTRY_PATH -B $$SENTRY_PATH/build -DCMAKE_C_COMPILER=clang -DCMAKE_CXX_COMPILER=clang++ -DSENTRY_BACKEND=crashpad -D SENTRY_BUILD_SHARED_LIBS=OFF --log-level=ERROR)
system(cmake --build $$SENTRY_PATH/build --parallel)
system(cmake --install $$SENTRY_PATH/build --prefix $$SENTRY_PATH/install)
}
SENTRY_PATH = $$PWD/../3rdparty/sentry-native
win32 {
!exists("$${PWD}/../3rdparty/sentry-native/CMakeLists.txt") {
message("git submodule for required sentry-native source code missing, executing 'git submodule update --init' to get it...")
system("cd $${PWD}\.. & git submodule update --init 3rdparty/sentry-native")
}
} else {
!exists("$${PWD}/../3rdparty/sentry-native/CMakeLists.txt") {
message("git submodule for required sentry-native source code missing, executing 'git submodule update --init' to get it...")
system("cd $${PWD}/.. ; git submodule update --init 3rdparty/sentry-native")
}
}
!exists($$SENTRY_PATH/install) {
message("Sentry install missing, building sentry-native from sources")
system(cmake -S $$SENTRY_PATH -B $$SENTRY_PATH/build -DCMAKE_C_COMPILER=clang -DCMAKE_CXX_COMPILER=clang++ -DSENTRY_BACKEND=crashpad -D SENTRY_BUILD_SHARED_LIBS=OFF --log-level=ERROR)
system(cmake --build $$SENTRY_PATH/build --parallel)
system(cmake --install $$SENTRY_PATH/build --prefix $$SENTRY_PATH/install)
}
🤖 Prompt for AI Agents
In src/mudlet.pro around lines 634 to 640, the sentry-native submodule is never
initialized before attempting to build/install; add a submodule initialization
step (following the pattern used for edbee-lib/lcf/qtkeychain) that checks for
the submodule (e.g., test for $$SENTRY_PATH/.git or existence) and runs git
submodule update --init --recursive for $$SENTRY_PATH when missing, then proceed
with the existing install/build check and commands.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is still unresolved. (But like the prior issue I am looking at it right now as I try to get development branch code buildable in my development environment - currently Windows but am thinking about other OSes as well).

!exists($$SENTRY_PATH/install) {
message("Sentry install missing, building sentry-native from sources")

system(cmake -S $$SENTRY_PATH -B $$SENTRY_PATH/build -DCMAKE_C_COMPILER=clang -DCMAKE_CXX_COMPILER=clang++ -DSENTRY_BACKEND=crashpad -D SENTRY_BUILD_SHARED_LIBS=OFF --log-level=ERROR)
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

Major: CMake configuration errors.

This line has two issues:

  1. Syntax error: There's a space in -D SENTRY_BUILD_SHARED_LIBS=OFF which should be -DSENTRY_BUILD_SHARED_LIBS=OFF.

  2. Incorrect compiler override: Hardcoding -DCMAKE_C_COMPILER=clang -DCMAKE_CXX_COMPILER=clang++ conflicts with the MinGW/MSYS2 environment indicated by the rest of this file (see MINGW_BASE_DIR usage at lines 415-452). This will fail when the specified compilers are not available or incompatible.

Apply this fix:

-        system(cmake -S $$SENTRY_PATH -B $$SENTRY_PATH/build -DCMAKE_C_COMPILER=clang -DCMAKE_CXX_COMPILER=clang++ -DSENTRY_BACKEND=crashpad -D SENTRY_BUILD_SHARED_LIBS=OFF --log-level=ERROR)
+        system(cmake -S $$SENTRY_PATH -B $$SENTRY_PATH/build -DSENTRY_BACKEND=crashpad -DSENTRY_BUILD_SHARED_LIBS=OFF --log-level=ERROR)

Let CMake use the system's default compiler chain (which qmake is already using for the main build) rather than forcing a specific one. If you need to override the compiler, it should match the platform and the compiler used by the parent qmake build.

📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
system(cmake -S $$SENTRY_PATH -B $$SENTRY_PATH/build -DCMAKE_C_COMPILER=clang -DCMAKE_CXX_COMPILER=clang++ -DSENTRY_BACKEND=crashpad -D SENTRY_BUILD_SHARED_LIBS=OFF --log-level=ERROR)
system(cmake -S $$SENTRY_PATH -B $$SENTRY_PATH/build -DSENTRY_BACKEND=crashpad -DSENTRY_BUILD_SHARED_LIBS=OFF --log-level=ERROR)
🤖 Prompt for AI Agents
In src/mudlet.pro around line 637, the cmake invocation has two problems: a
misplaced space in the -D flag and an inappropriate hardcoded compiler override;
change `-D SENTRY_BUILD_SHARED_LIBS=OFF` to `-DSENTRY_BUILD_SHARED_LIBS=OFF` and
remove the `-DCMAKE_C_COMPILER=clang -DCMAKE_CXX_COMPILER=clang++` flags so
CMake will default to the system/compiler already selected by the parent qmake
build (or if an override is required, use the same compiler variables/config
from the MINGW/Msys2 qmake environment so compilers match the rest of the
build).

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This trivial error is still in place and needs to be applied should anyone try to use QMake. Yes I know it is deprecated but in some situations it is still usable/useful (particularly given how hard CMake makes it to examine files not being directly used in the compilation and linkage stages of the build process)...



QMAKE_POST_LINK += $$quote($$QMAKE_MOVE $$OUT_PWD/mudlet.pdb $$APP_DIR_PATH/) ;
QMAKE_POST_LINK += $$quote(cp -f $$SENTRY_PATH/install/bin/* $$APP_DIR_PATH/) ;
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

Major: Non-portable copy command.

Line 656 uses cp -f, which is a Unix command and won't work on Windows cmd.exe (though it might work in MSYS2 bash). Line 655 correctly uses $$QMAKE_MOVE for portability.

Use qmake's cross-platform copy variable:

-    QMAKE_POST_LINK += $$quote(cp -f $$SENTRY_PATH/install/bin/* $$APP_DIR_PATH/) ;
+    QMAKE_POST_LINK += $$quote($$QMAKE_COPY $$SENTRY_PATH/install/bin/* $$APP_DIR_PATH/) ;

Note: You may need to iterate over files individually if wildcard expansion doesn't work with $$QMAKE_COPY, as qmake's copy might not support wildcards on all platforms.

📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
QMAKE_POST_LINK += $$quote(cp -f $$SENTRY_PATH/install/bin/* $$APP_DIR_PATH/) ;
QMAKE_POST_LINK += $$quote($$QMAKE_COPY $$SENTRY_PATH/install/bin/* $$APP_DIR_PATH/) ;
🤖 Prompt for AI Agents
In src/mudlet.pro around line 656, the post-link command uses the Unix-only `cp
-f` which is not portable to Windows; replace it with qmake's cross-platform
copy mechanism (`$$QMAKE_COPY`) and, if wildcards are not supported on the
target platform, expand the install/bin files and call `$$QMAKE_COPY` on each
file individually (e.g., iterate the list of files and run the qmake copy for
each) so the operation works across platforms and preserves the intended
behavior.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

QMAKE_MOVE now present or the QMAKE_COPY imagined here are both AI fantasies - there is not such function in QMake. 😡

@vadi2
Copy link
Copy Markdown
Member

vadi2 commented Nov 22, 2025

A few notes for the original post. When compiling with sentry enabled,

  • git submoduled need to be checked out recursively
  • SENTRY_AUTH_TOKEN needs to be set
  • profile needs to be loaded in online mode, not offline
  • sanitizers need to be disabled for sentry reporting to work

Copy link
Copy Markdown
Member

@vadi2 vadi2 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Confirmed works well on Linux. Could you resolve the merge conflicts? The windows build has expired since, and I'd like to test it there.

@NicolasKeita
Copy link
Copy Markdown
Contributor Author

I updated the PR. Solved the merge conflict.

Could you make this i18n friendly and add an option, selected by default, to send + remember sending in the future?

Here’s what I came up with:

image

There’s also a QComboBox in Preferences, in case the user wants to change it later:

image

@vadi2
Copy link
Copy Markdown
Member

vadi2 commented Nov 23, 2025

Looks solid, thanks.

@vadi2
Copy link
Copy Markdown
Member

vadi2 commented Nov 25, 2025

/refresh links

@NicolasKeita NicolasKeita requested a review from vadi2 November 28, 2025 05:15
@vadi2
Copy link
Copy Markdown
Member

vadi2 commented Nov 28, 2025

How can I get the crash handler to trigger on Windows?

Screencast.from.2025-11-28.06-33-55.mp4

I previously got it working macOS and Linux in this PR, but Windows was the hard part.

@NicolasKeita NicolasKeita marked this pull request as draft November 28, 2025 14:29
@vadi2
Copy link
Copy Markdown
Member

vadi2 commented Nov 29, 2025

Clang-tidy should work with latest development merged in

@vadi2
Copy link
Copy Markdown
Member

vadi2 commented Nov 29, 2025

Fair call on the size. Lets try uploading them on release and PTB builds only, and as a once-off on this PR (so the stack unwinding can be tested)

@vadi2
Copy link
Copy Markdown
Member

vadi2 commented Nov 30, 2025

Works great -
image

@vadi2 vadi2 merged commit e6726a4 into Mudlet:development Nov 30, 2025
13 checks passed
@SlySven
Copy link
Copy Markdown
Member

SlySven commented Dec 8, 2025

Sentry requires both the executable and its corresponding debug symbols. Debug symbol files can be large (up to 350 MB for Mudlet), which is why this option SENTRY_SEND_DEBUG exists—to avoid uploading the full debug files on every CI push.

Windows: executable + .pdb file
Linux: executable + .debug file
macOS: executable + .dSYM folder

This is RONG - Windows builds use the MSYS2+Mingw64 toolchain and clang and gcc BOTH produce .debug files on that platform - .pdb files are MSVC files and we don't make those.

@NicolasKeita
Copy link
Copy Markdown
Contributor Author

NicolasKeita commented Dec 11, 2025

@SlySven

I agree that by default, GCC under MinGW generates executables containing DWARF debug information, not CodeView.

DWARF symbols can be split into a separate .debug file, whereas the equivalent external symbol file for CodeView would be a .pdb file.
Therefore, with our current toolchain, no .pdb files are generated by default.

Additionally, Sentry specifically requires debug information in CodeView format on Windows in order to correctly process stack traces.

For this reason, I enabled the GCC option -gcodeview (which I have read somewhere is still a little bit experimental) :

target_link_options(${EXE_MUDLET_TARGET} PRIVATE -g -gcodeview)

With this option enabled, the final mudlet.exe contains the CodeView symbols itself, and uploading the executable is enough for Sentry to resolve stack traces with accuracy. Sentry accepts this approach, so we do not need two separate files (binary + external debug file) for windows.

After uploading to Sentry, the executable is stripped to reduce its size.
Even in stripped form, Sentry is still able to correctly process crash information with accuracy.

About the .pdb file:

Using -gcodeview also causes GCC to emit a .pdb file.
However because the option is still experimental, this .pdb does not contain the full set of symbols and is not reliable.

For this reason, the .pdb file is simply removed after the build and not used.

    add_custom_command(TARGET ${EXE_MUDLET_TARGET} POST_BUILD
        COMMAND ${CMAKE_COMMAND} -E remove "${CMAKE_BINARY_DIR}/mudlet.pdb"
    )

My original post was confusing when mentioning an external .pdb file. I apologize for that and have updated it.


On another note, I think Sentry could benefit from supporting DWARF symbols (.debug files) for Windows executables, as MinGW is a commonly used toolchain.

@SlySven
Copy link
Copy Markdown
Member

SlySven commented Dec 11, 2025

On another note, I think Sentry could benefit from supporting DWARF symbols (.debug files) for Windows executables, as MinGW is a commonly used toolchain.

Let's see if getsentry/sentry#104738 gets any traction...

@SlySven
Copy link
Copy Markdown
Member

SlySven commented Dec 11, 2025

I agree that by default, GCC under MinGW generates executables containing DWARF debug information, not CodeView.

DWARF symbols can be split into a separate .debug file, whereas the equivalent external symbol file for CodeView would be a .pdb file.
Therefore, with our current toolchain, no .pdb files are generated by default.

Additionally, Sentry specifically requires debug information in CodeView format on Windows in order to correctly process stack traces.

For this reason, I enabled the GCC option -gcodeview (which I have read somewhere is still a little bit experimental) :

I understand that clang does a better job and I have tried to get things to build with the MINGW64 environments clang but still using CMake {as the QMake build file was unparsable by Qmake} - I've fixed things enough that not setting WITH_SENTRY=ON will build and also completely excludes the ./src/SentryWrapper.cpp and ./src/SentryWrapper.h files from the build. This is so otherwise the build borks on the absence of sentry related files when they are not needed/present which hackers developers on their own builds won't need. However I am running into a problem where two different parts of the sentry-native build use different versions of the same files.
Edited to hide some personal path details by making some absolute paths relative to base of Mudlet source code:

.\mudlet\3rdparty\sentry-native\external\crashpad\third_party\mpack\mpack.h:7256: error: multiple definition of `mpack_tree_size'; ../../3rdparty/sentry-native/libsentry.a(mpack.c.obj):.\mudlet\3rdparty\sentry-native\vendor/mpack.h:6230: first defined here
C:/msys64/mingw64/bin/ld: ../../3rdparty/sentry-native/crashpad_build/client/libcrashpad_client.a(crash_report_database.cc.obj): in function `mpack_tree_size':
./mudlet/3rdparty/sentry-native/external/crashpad/third_party/mpack/mpack.h:7256: multiple definition of `mpack_tree_size'; ../../3rdparty/sentry-native/libsentry.a(mpack.c.obj):.\mudlet\3rdparty\sentry-native\vendor/mpack.h:6230: first defined here

Basically, these (version 1.0) files:

.\mudlet\3rdparty\sentry-native\vendor\mpack.h
.\mudlet\3rdparty\sentry-native\vendor\mpack.c

clash with these (version 1.1.1) files:

.\mudlet\3rdparty\sentry-native\external\crashpad\third_party\mpack\mpack.h
.\mudlet\3rdparty\sentry-native\external\crashpad\third_party\mpack\mpack.cc

🤷

@NicolasKeita
Copy link
Copy Markdown
Contributor Author

NicolasKeita commented Dec 16, 2025

I wasn’t able to reproduce the exact same issue on my side, but I did encounter similar
“multiple definition” problems when building sentry-native multiple times with different
configurations.

In my experience, these issues are usually resolved by starting from a completely clean state, for example:

  rm -rf 3rdparty/
  git restore 3rdparty/
  git submodule update --init --recursive
Details For details, this is how sentry-native is currently compiled via CMake:
set(SENTRY_COMMON_ARGS
    -DCMAKE_BUILD_TYPE=RelWithDebInfo
    -DCMAKE_C_COMPILER=clang
    -DCMAKE_CXX_COMPILER=clang++
    -DSENTRY_BACKEND=crashpad
    -DSENTRY_BUILD_SHARED_LIBS=OFF
    -DSENTRY_INTEGRATION_QT=OFF
    -G Ninja
)

ExternalProject_Add(
    sentry_without_transport
    SOURCE_DIR ${SENTRY_PATH}
    CMAKE_ARGS
        -DCMAKE_INSTALL_PREFIX=${SENTRY_PATH}/install_without_transport
        ${SENTRY_COMMON_ARGS}
        -DSENTRY_TRANSPORT=none
)

These correspond to the two manual commands:

cmake -S 3rdparty/sentry-native -B 3rdparty/sentry-native/build \
    -DCMAKE_INSTALL_PREFIX=3rdparty/sentry-native/install_without_transport \
    -DCMAKE_BUILD_TYPE=RelWithDebInfo \
    -DCMAKE_C_COMPILER=clang \
    -DCMAKE_CXX_COMPILER=clang++ \
    -DSENTRY_BACKEND=crashpad \
    -DSENTRY_BUILD_SHARED_LIBS=OFF \
    -DSENTRY_INTEGRATION_QT=OFF \
    -DSENTRY_TRANSPORT=none \
    -G Ninja

cmake --build 3rdparty/sentry-native/build --target install

Post-build, on my setup, mpack_tree_size is only present in libsentry.a. libcrashpad_client.a does not contain it:

  $ nm 3rdparty/sentry-native/install_with_transport/lib/libsentry.a | grep "mpack_tree_size"
  0000000000002ec0 T mpack_tree_size

  $ nm 3rdparty/sentry-native/install_with_transport/lib/libcrashpad_client.a | grep "mpack_tree_size"
  (no output)

Hopefully starting from a clean state helps avoid these conflicts, and in the meanwhile I fixed/updated the mudlet.pro in a PR to keep backward compatibility.

@SlySven
Copy link
Copy Markdown
Member

SlySven commented Dec 19, 2025

In my experience, these issues are usually resolved by starting from a completely clean state, for example:

 rm -rf 3rdparty/
 git restore 3rdparty/
 git submodule update --init --recursive

Initially I thought that rm -rf 3rdparty/ would be a problem for me as I thought it would wipe out all my local repositories of ALL the 3rdparty stuff - but realising that the git submodule data is actually stored under the parent (Mudlet) .git subdirectory.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Implement sentry.io's Qt SDK for crash reporting

3 participants