diff --git a/.github/workflows/build_all.yml b/.github/workflows/build_all.yml index 640f110c43..2fe102dbe1 100644 --- a/.github/workflows/build_all.yml +++ b/.github/workflows/build_all.yml @@ -151,7 +151,7 @@ jobs: if-no-files-found: error - name: Deploy Flatpak to nightly release - if: ${{github.ref == 'refs/heads/main' || github.ref == 'refs/heads/2.2.0'}} + if: ${{github.ref == 'refs/heads/main' || github.ref == 'refs/heads/2.2.1'}} uses: WebFreak001/deploy-nightly@v3.2.0 with: upload_url: https://uploads.github.com/repos/Snapmaker/OrcaSlicer/releases/169912305/assets{?name,label} diff --git a/.github/workflows/build_deps.yml b/.github/workflows/build_deps.yml index a33b234f2e..6cd71744b1 100644 --- a/.github/workflows/build_deps.yml +++ b/.github/workflows/build_deps.yml @@ -150,3 +150,14 @@ jobs: os: ${{ inputs.os }} arch: ${{ inputs.arch }} secrets: inherit + + upload_symbols: + name: Upload Debug Symbols to Sentry + needs: [build_orca] + if: ${{ !cancelled() && needs.build_orca.result == 'success' }} + uses: ./.github/workflows/sentry_cli.yml + with: + os: ${{ inputs.os }} + pdb-artifact-name: PDB + release: ${{ github.sha }} + secrets: inherit \ No newline at end of file diff --git a/.github/workflows/build_orca.yml b/.github/workflows/build_orca.yml index 0fcf640657..b9411fd28d 100644 --- a/.github/workflows/build_orca.yml +++ b/.github/workflows/build_orca.yml @@ -18,6 +18,8 @@ jobs: build_orca: name: Build Snapmaker_Orca runs-on: ${{ inputs.os }} + outputs: + release: ${{ steps.set_release.outputs.release || steps.set_release_win.outputs.release }} env: date: ver: @@ -77,6 +79,21 @@ jobs: echo "date: ${{ env.date }} version: ${{ env.ver }}" shell: pwsh + - name: Set release output (non-Windows) + id: set_release + if: inputs.os != 'windows-latest' + run: | + echo "release=$ver" >> $GITHUB_OUTPUT + shell: bash + + - name: Set release output (Windows) + id: set_release_win + if: inputs.os == 'windows-latest' + run: | + $release = $env:ver + Write-Output ("release=$release") | Out-File -Append -FilePath $env:GITHUB_OUTPUT -Encoding utf8 + shell: pwsh + # Mac - name: Install tools mac if: inputs.os == 'macos-14' @@ -289,7 +306,7 @@ jobs: path: ${{ github.workspace }}/build/src/Release/Snapmaker_Orca_profile_validator.exe - name: Deploy Windows release portable - if: (github.ref == 'refs/heads/main' || github.ref == 'refs/heads/2.2.0') && inputs.os == 'windows-latest' + if: (github.ref == 'refs/heads/main' || github.ref == 'refs/heads/2.2.1') && inputs.os == 'windows-latest' uses: WebFreak001/deploy-nightly@v3.2.0 with: upload_url: https://uploads.github.com/repos/Snapmaker/OrcaSlicer/releases/169912305/assets{?name,label} @@ -300,7 +317,7 @@ jobs: max_releases: 1 - name: Deploy Windows release installer - if: (github.ref == 'refs/heads/main' || github.ref == 'refs/heads/2.2.0') && inputs.os == 'windows-latest' + if: (github.ref == 'refs/heads/main' || github.ref == 'refs/heads/2.2.1') && inputs.os == 'windows-latest' uses: WebFreak001/deploy-nightly@v3.2.0 with: upload_url: https://uploads.github.com/repos/Snapmaker/OrcaSlicer/releases/169912305/assets{?name,label} @@ -311,7 +328,7 @@ jobs: max_releases: 1 - name: Deploy Windows Snapmaker_Orca_profile_validator release - if: (github.ref == 'refs/heads/main' || github.ref == 'refs/heads/2.2.0') && inputs.os == 'windows-latest' + if: (github.ref == 'refs/heads/main' || github.ref == 'refs/heads/2.2.1') && inputs.os == 'windows-latest' uses: WebFreak001/deploy-nightly@v3.2.0 with: upload_url: https://uploads.github.com/repos/Snapmaker/OrcaSlicer/releases/169912305/assets{?name,label} @@ -385,7 +402,7 @@ jobs: path: './build/src/Release/Snapmaker_Orca_profile_validator' - name: Deploy Ubuntu release - if: ${{ ! env.ACT && (github.ref == 'refs/heads/main' || github.ref == 'refs/heads/2.2.0') && (inputs.os == 'ubuntu-20.04' || inputs.os == 'ubuntu-24.04') }} + if: ${{ ! env.ACT && (github.ref == 'refs/heads/main' || github.ref == 'refs/heads/2.2.1') && (inputs.os == 'ubuntu-20.04' || inputs.os == 'ubuntu-24.04') }} env: ubuntu-ver-str: ${{ (inputs.os == 'ubuntu-24.04' && '_Ubuntu2404') || '' }} uses: WebFreak001/deploy-nightly@v3.2.0 @@ -406,7 +423,7 @@ jobs: message: "nightly-builds" - name: Deploy Ubuntu Snapmaker_Orca_profile_validator release - if: ${{ ! env.ACT && (github.ref == 'refs/heads/main' || github.ref == 'refs/heads/2.2.0') && (inputs.os == 'ubuntu-20.04' || inputs.os == 'ubuntu-24.04') }} + if: ${{ ! env.ACT && (github.ref == 'refs/heads/main' || github.ref == 'refs/heads/2.2.1') && (inputs.os == 'ubuntu-20.04' || inputs.os == 'ubuntu-24.04') }} env: ubuntu-ver-str: ${{ (inputs.os == 'ubuntu-24.04' && '_Ubuntu2404') || '' }} uses: WebFreak001/deploy-nightly@v3.2.0 @@ -419,7 +436,7 @@ jobs: max_releases: 1 - name: Deploy orca_custom_preset_tests - if: ${{ ! env.ACT && (github.ref == 'refs/heads/main' || github.ref == 'refs/heads/2.2.0') && inputs.os == 'ubuntu-24.04' }} + if: ${{ ! env.ACT && (github.ref == 'refs/heads/main' || github.ref == 'refs/heads/2.2.1') && inputs.os == 'ubuntu-24.04' }} uses: WebFreak001/deploy-nightly@v3.2.0 with: upload_url: https://uploads.github.com/repos/Snapmaker/OrcaSlicer/releases/169912305/assets{?name,label} diff --git a/.github/workflows/sentry_cli.yml b/.github/workflows/sentry_cli.yml new file mode 100644 index 0000000000..0693fab2a0 --- /dev/null +++ b/.github/workflows/sentry_cli.yml @@ -0,0 +1,92 @@ +name: Upload Debug Symbols to Sentry + +on: + workflow_call: + inputs: + os: + required: true + type: string + description: "Target OS: windows-latest, macos-14, ubuntu-20.04, ubuntu-24.04" + pdb-artifact-name: + required: false + type: string + description: "Artifact name for Windows PDB archive (e.g., 'PDB')" + release: + required: true + type: string + description: "Release version/tag" + +jobs: + upload_symbols: + name: Upload Debug Symbols to Sentry + runs-on: ${{ inputs.os }} + steps: + # ==================== Windows ==================== + - name: "[Windows] Install sentry-cli via choco" + if: inputs.os == 'windows-latest' + shell: pwsh + run: | + choco install sentry-cli -y -y 2>&1 | Out-Null + + - name: "[Windows] Download PDB artifact" + if: inputs.os == 'windows-latest' + uses: actions/download-artifact@v4 + with: + name: ${{ inputs.pdb-artifact-name }} + path: ./symbols + + - name: "[Windows] Extract PDB archive" + if: inputs.os == 'windows-latest' + shell: pwsh + run: | + $archive = Get-ChildItem -Path ./symbols -Filter "*.7z" -File | Select-Object -First 1 + if ($archive) { + Write-Host "Found archive: $($archive.FullName)" + Write-Host "Extracting to ./symbols/extracted ..." + 7z x "$($archive.FullName)" -o"./symbols/extracted" -y + if ($LASTEXITCODE -ne 0) { + Write-Host "::error::Failed to extract archive with exit code $LASTEXITCODE" + exit $LASTEXITCODE + } + Write-Host "Extraction complete. Contents:" + Get-ChildItem -Path ./symbols/extracted -Recurse | ForEach-Object { Write-Host " $($_.FullName)" } + } else { + Write-Host "No .7z archive found, assuming PDB files are already extracted" + Get-ChildItem -Path ./symbols -Recurse | ForEach-Object { Write-Host " Found: $($_.FullName)" } + } + + - name: "[Windows] Upload PDB to Sentry (sentry-cli)" + if: inputs.os == 'windows-latest' + shell: pwsh + env: + SENTRY_AUTH_TOKEN: ${{ secrets.SENTRY_AUTH_TOKEN }} + SENTRY_LOG_LEVEL: debug + run: | + # Determine upload path - prefer extracted folder if it exists + $uploadPath = "./symbols" + if (Test-Path "./symbols/extracted") { + $uploadPath = "./symbols/extracted" + } + + $pdbFiles = Get-ChildItem -Path $uploadPath -Filter "*.pdb" -File -Recurse + if ($pdbFiles.Count -gt 0) { + Write-Host "Found $($pdbFiles.Count) PDB file(s) to upload from $uploadPath :" + $pdbFiles | ForEach-Object { Write-Host " - $($_.FullName)" } + Write-Host "" + Write-Host "Starting Sentry upload with debug logging..." + sentry-cli.exe --log-level=debug --auth-token $env:SENTRY_AUTH_TOKEN upload-dif --org "${{ secrets.SENTRY_ORG }}" --project "${{ secrets.SENTRY_PROJECT }}" $uploadPath 2>&1 | Out-Host + if ($LASTEXITCODE -ne 0) { + Write-Host "::error::Sentry upload failed with exit code $LASTEXITCODE" + exit $LASTEXITCODE + } + } else { + Write-Host "::error::No PDB files found in $uploadPath" + Get-ChildItem -Path ./symbols -Recurse | ForEach-Object { Write-Host " Found: $($_.FullName)" } + exit 1 + } + + # ==================== macOS ==================== + + + # ==================== Linux ==================== + diff --git a/CMakeLists.txt b/CMakeLists.txt index 430bfc82a3..13642a8cb2 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -99,6 +99,14 @@ option(SLIC3R_MSVC_COMPILE_PARALLEL "Compile on Visual Studio in parallel" 1) option(SLIC3R_MSVC_PDB "Generate PDB files on MSVC in Release mode" 1) option(SLIC3R_PERL_XS "Compile XS Perl module and enable Perl unit and integration tests" 0) option(SLIC3R_ASAN "Enable ASan on Clang and GCC" 0) + +# Sentry crash reporting - enabled only on Windows by default +if (WIN32) + set(SLIC3R_SENTRY_DEFAULT ON) +else() + set(SLIC3R_SENTRY_DEFAULT OFF) +endif() +option(SLIC3R_SENTRY "Enable Sentry crash reporting SDK" ${SLIC3R_SENTRY_DEFAULT}) # If SLIC3R_FHS is 1 -> SLIC3R_DESKTOP_INTEGRATION is always 0, othrewise variable. CMAKE_DEPENDENT_OPTION(SLIC3R_DESKTOP_INTEGRATION "Allow perfoming desktop integration during runtime" 1 "NOT SLIC3R_FHS" 0) @@ -534,6 +542,9 @@ find_package(TBB REQUIRED) find_package(OpenSSL REQUIRED) find_package(CURL REQUIRED) +if (SLIC3R_SENTRY) + find_package(Sentry REQUIRED) +endif() find_package(Freetype REQUIRED) @@ -543,6 +554,24 @@ target_link_libraries(libcurl INTERFACE CURL::libcurl) find_package(ZLIB REQUIRED) target_link_libraries(libcurl INTERFACE ZLIB::ZLIB) +if (SLIC3R_SENTRY) + add_library(sentry INTERFACE) + target_link_libraries(sentry INTERFACE sentry::sentry) + + # Add sentry library directory and link sentry.lib explicitly for Windows + if (WIN32 AND CMAKE_PREFIX_PATH) + # Try to find sentry.lib in the install prefix + file(GLOB _sentry_lib "${CMAKE_PREFIX_PATH}/lib/sentry.lib") + if (_sentry_lib) + target_link_directories(sentry INTERFACE "${CMAKE_PREFIX_PATH}/lib") + target_link_libraries(sentry INTERFACE "sentry.lib") + message(STATUS "Found sentry.lib at: ${CMAKE_PREFIX_PATH}/lib") + else() + message(WARNING "sentry.lib not found in ${CMAKE_PREFIX_PATH}/lib. Sentry SDK may not have been built yet.") + endif() + endif() +endif() + # Fixing curl's cmake config script bugs if (NOT WIN32) # Required by libcurl @@ -727,6 +756,14 @@ function(Snapmaker_Orca_copy_dlls target config postfix output_dlls) ${TOP_LEVEL_PROJECT_DIR}/deps/WebView2/lib/win-${_arch}/WebView2Loader.dll DESTINATION ${_out_dir}) + # Copy Sentry and Crashpad artifacts if they were built by deps + if (SLIC3R_SENTRY AND EXISTS "${CMAKE_PREFIX_PATH}/bin/sentry.dll") + file(COPY "${CMAKE_PREFIX_PATH}/bin/sentry.dll" + "${CMAKE_PREFIX_PATH}/bin/crashpad_handler.exe" + DESTINATION ${_out_dir} + ) + endif() + file(COPY ${CMAKE_PREFIX_PATH}/bin/occt/TKBO.dll ${CMAKE_PREFIX_PATH}/bin/occt/TKBRep.dll ${CMAKE_PREFIX_PATH}/bin/occt/TKCAF.dll @@ -793,6 +830,16 @@ function(Snapmaker_Orca_copy_dlls target config postfix output_dlls) PARENT_SCOPE ) + # Add Sentry DLLs to the output list if Sentry is enabled + if (SLIC3R_SENTRY) + set(${output_dlls} + ${${output_dlls}} + ${_out_dir}/sentry.dll + ${_out_dir}/crashpad_handler.exe + PARENT_SCOPE + ) + endif() + endfunction() diff --git a/deps/CMakeLists.txt b/deps/CMakeLists.txt index 1bbd244f17..de9fae0bc5 100644 --- a/deps/CMakeLists.txt +++ b/deps/CMakeLists.txt @@ -62,6 +62,14 @@ if(CMAKE_SYSTEM_NAME STREQUAL "Linux") option(DEP_WX_GTK3 "Build wxWidgets against GTK3" OFF) endif() +# Sentry crash reporting - enabled only on Windows by default +if (WIN32) + set(SLIC3R_SENTRY_DEFAULT ON) +else() + set(SLIC3R_SENTRY_DEFAULT OFF) +endif() +option(SLIC3R_SENTRY "Enable Sentry crash reporting SDK" ${SLIC3R_SENTRY_DEFAULT}) + set(IS_CROSS_COMPILE FALSE) if (APPLE) @@ -314,6 +322,12 @@ if (NOT OPENSSL_FOUND OR NOT CURL_FOUND) set(CURL_PKG dep_CURL) endif () +set(SENTRY_PKG "") +if (SLIC3R_SENTRY AND NOT SENTRY_FOUND) + include(Sentry/Sentry.cmake) + set(SENTRY_PKG dep_Sentry) +endif() + set(JPEG_PKG "") if (NOT JPEG_FOUND) include(JPEG/JPEG.cmake) @@ -355,6 +369,7 @@ set(_dep_list dep_TBB ${OPENSSL_PKG} ${CURL_PKG} + ${SENTRY_PKG} ${WXWIDGETS_PKG} dep_Cereal dep_NLopt diff --git a/deps/Sentry/Sentry.cmake b/deps/Sentry/Sentry.cmake new file mode 100644 index 0000000000..91e49fc74b --- /dev/null +++ b/deps/Sentry/Sentry.cmake @@ -0,0 +1,63 @@ +set(_sentry_platform_flags + -DCMAKE_POSITION_INDEPENDENT_CODE=ON + -DSENTRY_BUILD_TESTS=OFF + -DSENTRY_EXAMPLES=OFF + -DSENTRY_CRASHPAD_BACKEND=ON + -DSENTRY_ENABLE_INSTALL=ON +) + +# Platform-specific CMake generator and flags +set(_sentry_cmake_generator "") +set(_sentry_build_config "Release") + +if (WIN32) + # Windows: build shared libs so we get sentry.dll + set(_sentry_platform_flags ${_sentry_platform_flags} + -DSENTRY_TRANSPORT_WINHTTP=ON + -DSENTRY_BUILD_SHARED_LIBS=ON + -DCMAKE_BUILD_TYPE:STRING=RelWithDebInfo + -DCMAKE_C_FLAGS_RELWITHDEBINFO:STRING=/Zi /O2 + -DCMAKE_CXX_FLAGS_RELWITHDEBINFO:STRING=/Zi /O2 + -DCMAKE_EXE_LINKER_FLAGS:STRING=/DEBUG + -DCMAKE_SHARED_LINKER_FLAGS:STRING=/DEBUG + ) + if (MSVC) + set(_sentry_cmake_generator -G "Visual Studio 17 2022") + endif() +elseif (APPLE) + # macOS: Use Unix Makefiles (install will put libs in ${DESTDIR}/bin or lib) + set(_sentry_platform_flags + ${_sentry_platform_flags} + -DSENTRY_TRANSPORT_CURL=ON + -DSENTRY_BUILD_SHARED_LIBS=OFF + -DCMAKE_BUILD_TYPE:STRING=RelWithDebInfo + -DCMAKE_C_FLAGS:STRING=-g -O2 + -DCMAKE_CXX_FLAGS:STRING=-g -O2 + ) + set(_sentry_cmake_generator -G "Unix Makefiles") +elseif(CMAKE_SYSTEM_NAME STREQUAL "Linux") + # Linux: Use Unix Makefiles + set(_sentry_platform_flags + ${_sentry_platform_flags} + -DSENTRY_TRANSPORT_CURL=ON + -DSENTRY_BUILD_SHARED_LIBS=OFF + -DCMAKE_BUILD_TYPE:STRING=RelWithDebInfo + -DCMAKE_C_FLAGS:STRING=-g -O2 + -DCMAKE_CXX_FLAGS:STRING=-g -O2 + ) + set(_sentry_cmake_generator -G "Unix Makefiles") +endif () + +Snapmaker_Orca_add_cmake_project(Sentry + GIT_REPOSITORY https://github.com/getsentry/sentry-native.git + GIT_TAG 0.12.1 + PATCH_COMMAND ${GIT_EXECUTABLE} submodule update --init --recursive && ${CMAKE_COMMAND} -S external/crashpad -B external/crashpad/build ${_sentry_cmake_generator} -DCMAKE_BUILD_TYPE=Release && ${CMAKE_COMMAND} --build external/crashpad/build --config Release + CMAKE_ARGS + ${_sentry_cmake_generator} + -DCMAKE_INSTALL_DATADIR:STRING=share + ${_sentry_platform_flags} +) + +if (MSVC) + add_debug_dep(dep_Sentry) +endif () diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 3958bf2884..ca9e209e0c 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -115,7 +115,7 @@ configure_file(${CMAKE_CURRENT_SOURCE_DIR}/dev-utils/platform/msw/Snapmaker_Orca configure_file(${CMAKE_CURRENT_SOURCE_DIR}/dev-utils/platform/msw/Snapmaker_Orca.manifest.in ${CMAKE_CURRENT_BINARY_DIR}/Snapmaker_Orca.manifest @ONLY) configure_file(${CMAKE_CURRENT_SOURCE_DIR}/dev-utils/platform/osx/Info.plist.in ${CMAKE_CURRENT_BINARY_DIR}/Info.plist @ONLY) if (WIN32) - add_library(Snapmaker_Orca SHARED Snapmaker_Orca.cpp Snapmaker_Orca.hpp dev-utils/BaseException.cpp dev-utils/BaseException.h dev-utils/StackWalker.cpp dev-utils/StackWalker.h) + add_library(Snapmaker_Orca SHARED Snapmaker_Orca.cpp Snapmaker_Orca.hpp dev-utils/BaseException.cpp dev-utils/BaseException.h dev-utils/StackWalker.cpp dev-utils/StackWalker.h sentry_wrapper/SentryWrapper.hpp sentry_wrapper/SentryWrapper.cpp) else () add_executable(Snapmaker_Orca Snapmaker_Orca.cpp Snapmaker_Orca.hpp) endif () @@ -168,6 +168,12 @@ target_link_libraries(Snapmaker_Orca libslic3r_gui) #endif () endif () +# Sentry crash reporting integration +if (SLIC3R_SENTRY) + target_compile_definitions(Snapmaker_Orca PUBLIC SLIC3R_SENTRY) + target_link_libraries(Snapmaker_Orca sentry::sentry) +endif() + # On Windows, a shim application is required to produce a console / non console version of the Slic3r application. # Also the shim may load the Mesa software OpenGL renderer if the default renderer does not support OpenGL 2.0 and higher. if (WIN32) @@ -175,7 +181,7 @@ if (WIN32) set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -municode") endif() - add_executable(Snapmaker_Orca_app_gui WIN32 Snapmaker_Orca_app_msvc.cpp ${CMAKE_CURRENT_BINARY_DIR}/Snapmaker_Orca.rc) + add_executable(Snapmaker_Orca_app_gui WIN32 Snapmaker_Orca_app_msvc.cpp sentry_wrapper/SentryWrapper.cpp ${CMAKE_CURRENT_BINARY_DIR}/Snapmaker_Orca.rc) # Generate debug symbols even in release mode. if(MSVC) target_link_options(Snapmaker_Orca_app_gui PUBLIC "$<$:/DEBUG>") @@ -183,7 +189,14 @@ if (WIN32) target_compile_definitions(Snapmaker_Orca_app_gui PRIVATE -DSLIC3R_WRAPPER_NOCONSOLE) add_dependencies(Snapmaker_Orca_app_gui Snapmaker_Orca) set_target_properties(Snapmaker_Orca_app_gui PROPERTIES OUTPUT_NAME "snapmaker-orca") - target_link_libraries(Snapmaker_Orca_app_gui PRIVATE boost_headeronly) + if (SLIC3R_SENTRY) + target_link_libraries(Snapmaker_Orca_app_gui PRIVATE boost_headeronly sentry::sentry) + else() + target_link_libraries(Snapmaker_Orca_app_gui PRIVATE boost_headeronly) + endif() + if (SLIC3R_SENTRY) + target_compile_definitions(Snapmaker_Orca_app_gui PRIVATE SLIC3R_SENTRY) + endif() endif () # Link the resources dir to where Slic3r GUI expects it diff --git a/src/Snapmaker_Orca.cpp b/src/Snapmaker_Orca.cpp index 910468d867..60176d5c3a 100644 --- a/src/Snapmaker_Orca.cpp +++ b/src/Snapmaker_Orca.cpp @@ -6268,63 +6268,6 @@ std::string CLI::output_filepath(const ModelObject &object, unsigned int index, } -//BBS: dump stack debug codes, don't delete currently -//#include -//#pragma comment(lib, "version.lib") -//#pragma comment( lib, "dbghelp.lib" ) -/*DWORD main_thread_id; -std::string TraceStack() -{ - static const int MAX_STACK_FRAMES = 16; - - void* pStack[MAX_STACK_FRAMES]; - - HANDLE process = GetCurrentProcess(); - SymInitialize(process, NULL, TRUE); - WORD frames = CaptureStackBackTrace(0, MAX_STACK_FRAMES, pStack, NULL); - - std::ostringstream oss; - oss << "stack traceback: frames="<< frames << std::endl; - for (WORD i = 0; i < frames; ++i) { - DWORD64 address = (DWORD64)(pStack[i]); - - DWORD64 displacementSym = 0; - char buffer[sizeof(SYMBOL_INFO) + MAX_SYM_NAME * sizeof(TCHAR)]; - PSYMBOL_INFO pSymbol = (PSYMBOL_INFO)buffer; - pSymbol->SizeOfStruct = sizeof(SYMBOL_INFO); - pSymbol->MaxNameLen = MAX_SYM_NAME; - - DWORD displacementLine = 0; - IMAGEHLP_LINE64 line; - //SymSetOptions(SYMOPT_LOAD_LINES); - line.SizeOfStruct = sizeof(IMAGEHLP_LINE64); - - if (SymFromAddr(process, address, &displacementSym, pSymbol) - && SymGetLineFromAddr64(process, address, &displacementLine, &line)) { - oss << "\t" << pSymbol->Name << " at " << line.FileName << ":" << line.LineNumber << "(0x" << std::hex << pSymbol->Address << std::dec << ")" << std::endl; - } - else { - oss << "\terror: " << GetLastError() << std::endl; - } - } - return oss.str(); -} - -LONG WINAPI VectoredExceptionHandler(PEXCEPTION_POINTERS pExceptionInfo) -{ - std::ofstream f; - - DWORD cur_thread_id = GetCurrentThreadId(); - f.open("VectoredExceptionHandler.txt", std::ios::out | std::ios::app); - f << "main thread id="< #include #include - - +#include +#include "sentry_wrapper/SentryWrapper.hpp" #ifdef SLIC3R_GUI -extern "C" -{ - // Let the NVIDIA and AMD know we want to use their graphics card - // on a dual graphics card system. - __declspec(dllexport) DWORD NvOptimusEnablement = 0x00000000; - __declspec(dllexport) int AmdPowerXpressRequestHighPerformance = 0; +extern "C" { +// Let the NVIDIA and AMD know we want to use their graphics card +// on a dual graphics card system. +__declspec(dllexport) DWORD NvOptimusEnablement = 0x00000000; +__declspec(dllexport) int AmdPowerXpressRequestHighPerformance = 0; } #endif /* SLIC3R_GUI */ @@ -23,7 +22,7 @@ extern "C" #include #ifdef SLIC3R_GUI - #include +#include #endif /* SLIC3R_GUI */ #include @@ -31,9 +30,11 @@ extern "C" #include #include - +#include #include +using namespace Slic3r; + #ifdef SLIC3R_GUI class OpenGLVersionCheck { @@ -43,23 +44,24 @@ public: std::string vendor; std::string renderer; - HINSTANCE hOpenGL = nullptr; - bool success = false; + HINSTANCE hOpenGL = nullptr; + bool success = false; bool load_opengl_dll() { MSG msg = {0}; WNDCLASS wc = {0}; wc.lpfnWndProc = OpenGLVersionCheck::supports_opengl2_wndproc; - wc.hInstance = (HINSTANCE)GetModuleHandle(nullptr); - wc.hbrBackground = (HBRUSH)(COLOR_BACKGROUND); + wc.hInstance = (HINSTANCE) GetModuleHandle(nullptr); + wc.hbrBackground = (HBRUSH) (COLOR_BACKGROUND); wc.lpszClassName = L"Snapmaker_Orca_opengl_version_check"; - wc.style = CS_OWNDC; + wc.style = CS_OWNDC; if (RegisterClass(&wc)) { - HWND hwnd = CreateWindowW(wc.lpszClassName, L"Snapmaker_Orca_opengl_version_check", WS_OVERLAPPEDWINDOW, 0, 0, 640, 480, 0, 0, wc.hInstance, (LPVOID)this); + HWND hwnd = CreateWindowW(wc.lpszClassName, L"Snapmaker_Orca_opengl_version_check", WS_OVERLAPPEDWINDOW, 0, 0, 640, 480, 0, 0, + wc.hInstance, (LPVOID) this); if (hwnd) { message_pump_exit = false; - while (GetMessage(&msg, NULL, 0, 0 ) > 0 && ! message_pump_exit) + while (GetMessage(&msg, NULL, 0, 0) > 0 && !message_pump_exit) DispatchMessage(&msg); } } @@ -115,40 +117,47 @@ protected: return; } - typedef HGLRC (WINAPI *Func_wglCreateContext)(HDC); - typedef BOOL (WINAPI *Func_wglMakeCurrent )(HDC, HGLRC); - typedef BOOL (WINAPI *Func_wglDeleteContext)(HGLRC); - typedef GLubyte* (WINAPI *Func_glGetString )(GLenum); + typedef HGLRC(WINAPI * Func_wglCreateContext)(HDC); + typedef BOOL(WINAPI * Func_wglMakeCurrent)(HDC, HGLRC); + typedef BOOL(WINAPI * Func_wglDeleteContext)(HGLRC); + typedef GLubyte*(WINAPI * Func_glGetString)(GLenum); - Func_wglCreateContext wglCreateContext = (Func_wglCreateContext)GetProcAddress(hOpenGL, "wglCreateContext"); - Func_wglMakeCurrent wglMakeCurrent = (Func_wglMakeCurrent) GetProcAddress(hOpenGL, "wglMakeCurrent"); - Func_wglDeleteContext wglDeleteContext = (Func_wglDeleteContext)GetProcAddress(hOpenGL, "wglDeleteContext"); - Func_glGetString glGetString = (Func_glGetString) GetProcAddress(hOpenGL, "glGetString"); + Func_wglCreateContext wglCreateContext = (Func_wglCreateContext) GetProcAddress(hOpenGL, "wglCreateContext"); + Func_wglMakeCurrent wglMakeCurrent = (Func_wglMakeCurrent) GetProcAddress(hOpenGL, "wglMakeCurrent"); + Func_wglDeleteContext wglDeleteContext = (Func_wglDeleteContext) GetProcAddress(hOpenGL, "wglDeleteContext"); + Func_glGetString glGetString = (Func_glGetString) GetProcAddress(hOpenGL, "glGetString"); if (wglCreateContext == nullptr || wglMakeCurrent == nullptr || wglDeleteContext == nullptr || glGetString == nullptr) { printf("Failed loading the system opengl32.dll: The library is invalid.\n"); return; } - PIXELFORMATDESCRIPTOR pfd = - { - sizeof(PIXELFORMATDESCRIPTOR), - 1, - PFD_DRAW_TO_WINDOW | PFD_SUPPORT_OPENGL | PFD_DOUBLEBUFFER, - PFD_TYPE_RGBA, // The kind of framebuffer. RGBA or palette. - 32, // Color depth of the framebuffer. - 0, 0, 0, 0, 0, 0, - 0, - 0, - 0, - 0, 0, 0, 0, - 24, // Number of bits for the depthbuffer - 8, // Number of bits for the stencilbuffer - 0, // Number of Aux buffers in the framebuffer. - PFD_MAIN_PLANE, - 0, - 0, 0, 0 - }; + PIXELFORMATDESCRIPTOR pfd = {sizeof(PIXELFORMATDESCRIPTOR), + 1, + PFD_DRAW_TO_WINDOW | PFD_SUPPORT_OPENGL | PFD_DOUBLEBUFFER, + PFD_TYPE_RGBA, // The kind of framebuffer. RGBA or palette. + 32, // Color depth of the framebuffer. + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 24, // Number of bits for the depthbuffer + 8, // Number of bits for the stencilbuffer + 0, // Number of Aux buffers in the framebuffer. + PFD_MAIN_PLANE, + 0, + 0, + 0, + 0}; HDC ourWindowHandleToDeviceContext = ::GetDC(hWnd); // Gdi32.dll @@ -159,17 +168,17 @@ protected: HGLRC glcontext = wglCreateContext(ourWindowHandleToDeviceContext); wglMakeCurrent(ourWindowHandleToDeviceContext, glcontext); // Opengl32.dll - const char *data = (const char*)glGetString(GL_VERSION); + const char* data = (const char*) glGetString(GL_VERSION); if (data != nullptr) this->version = data; // printf("check -version: %s\n", version.c_str()); - data = (const char*)glGetString(0x8B8C); // GL_SHADING_LANGUAGE_VERSION + data = (const char*) glGetString(0x8B8C); // GL_SHADING_LANGUAGE_VERSION if (data != nullptr) this->glsl_version = data; - data = (const char*)glGetString(GL_VENDOR); + data = (const char*) glGetString(GL_VENDOR); if (data != nullptr) this->vendor = data; - data = (const char*)glGetString(GL_RENDERER); + data = (const char*) glGetString(GL_RENDERER); if (data != nullptr) this->renderer = data; // Opengl32.dll @@ -180,21 +189,16 @@ protected: static LRESULT CALLBACK supports_opengl2_wndproc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) { - switch(message) - { - case WM_CREATE: - { - CREATESTRUCT *pCreate = reinterpret_cast(lParam); - OpenGLVersionCheck *ogl_data = reinterpret_cast(pCreate->lpCreateParams); + switch (message) { + case WM_CREATE: { + CREATESTRUCT* pCreate = reinterpret_cast(lParam); + OpenGLVersionCheck* ogl_data = reinterpret_cast(pCreate->lpCreateParams); ogl_data->check(hWnd); DestroyWindow(hWnd); return 0; } - case WM_NCDESTROY: - message_pump_exit = true; - return 0; - default: - return DefWindowProc(hWnd, message, wParam, lParam); + case WM_NCDESTROY: message_pump_exit = true; return 0; + default: return DefWindowProc(hWnd, message, wParam, lParam); } } }; @@ -203,18 +207,18 @@ bool OpenGLVersionCheck::message_pump_exit = false; #endif /* SLIC3R_GUI */ extern "C" { - typedef int (__stdcall *Slic3rMainFunc)(int argc, wchar_t **argv); - Slic3rMainFunc Snapmaker_Orca_main = nullptr; +typedef int(__stdcall* Slic3rMainFunc)(int argc, wchar_t** argv); +Slic3rMainFunc Snapmaker_Orca_main = nullptr; } extern "C" { #ifdef SLIC3R_WRAPPER_NOCONSOLE int APIENTRY wWinMain(HINSTANCE /* hInstance */, HINSTANCE /* hPrevInstance */, PWSTR /* lpCmdLine */, int /* nCmdShow */) { - int argc; - wchar_t **argv = ::CommandLineToArgvW(::GetCommandLineW(), &argc); + int argc; + wchar_t** argv = ::CommandLineToArgvW(::GetCommandLineW(), &argc); #else -int wmain(int argc, wchar_t **argv) +int wmain(int argc, wchar_t** argv) { #endif // Allow the asserts to open message box, such message box allows to ignore the assert and continue with the application. @@ -222,9 +226,10 @@ int wmain(int argc, wchar_t **argv) // the application will be killed even if "Ignore" button is pressed. _set_error_mode(_OUT_TO_MSGBOX); + initSentry(); + std::vector argv_extended; argv_extended.emplace_back(argv[0]); - #ifdef SLIC3R_WRAPPER_GCODEVIEWER wchar_t gcodeviewer_param[] = L"--gcodeviewer"; argv_extended.emplace_back(gcodeviewer_param); @@ -234,7 +239,7 @@ int wmain(int argc, wchar_t **argv) // Here one may push some additional parameters based on the wrapper type. bool force_mesa = false; #endif /* SLIC3R_GUI */ - for (int i = 1; i < argc; ++ i) { + for (int i = 1; i < argc; ++i) { #ifdef SLIC3R_GUI if (wcscmp(argv[i], L"--sw-renderer") == 0) force_mesa = true; @@ -247,14 +252,14 @@ int wmain(int argc, wchar_t **argv) #ifdef SLIC3R_GUI OpenGLVersionCheck opengl_version_check; - bool load_mesa = + bool load_mesa = // Forced from the command line. force_mesa || // Try to load the default OpenGL driver and test its context version. - ! opengl_version_check.load_opengl_dll() || ! opengl_version_check.is_version_greater_or_equal_to(2, 0); + !opengl_version_check.load_opengl_dll() || !opengl_version_check.is_version_greater_or_equal_to(2, 0); #endif /* SLIC3R_GUI */ - wchar_t path_to_exe[MAX_PATH + 1] = { 0 }; + wchar_t path_to_exe[MAX_PATH + 1] = {0}; ::GetModuleFileNameW(nullptr, path_to_exe, MAX_PATH); wchar_t drive[_MAX_DRIVE]; wchar_t dir[_MAX_DIR]; @@ -264,11 +269,11 @@ int wmain(int argc, wchar_t **argv) _wmakepath(path_to_exe, drive, dir, nullptr, nullptr); #ifdef SLIC3R_GUI -// https://wiki.qt.io/Cross_compiling_Mesa_for_Windows -// http://download.qt.io/development_releases/prebuilt/llvmpipe/windows/ + // https://wiki.qt.io/Cross_compiling_Mesa_for_Windows + // http://download.qt.io/development_releases/prebuilt/llvmpipe/windows/ if (load_mesa) { opengl_version_check.unload_opengl_dll(); - wchar_t path_to_mesa[MAX_PATH + 1] = { 0 }; + wchar_t path_to_mesa[MAX_PATH + 1] = {0}; wcscpy(path_to_mesa, path_to_exe); wcscat(path_to_mesa, L"mesa\\opengl32.dll"); printf("Loading MESA OpenGL library: %S\n", path_to_mesa); @@ -280,31 +285,36 @@ int wmain(int argc, wchar_t **argv) } #endif /* SLIC3R_GUI */ - - wchar_t path_to_slic3r[MAX_PATH + 1] = { 0 }; + wchar_t path_to_slic3r[MAX_PATH + 1] = {0}; wcscpy(path_to_slic3r, path_to_exe); wcscat(path_to_slic3r, L"Snapmaker_Orca.dll"); -// printf("Loading Slic3r library: %S\n", path_to_slic3r); + // printf("Loading Slic3r library: %S\n", path_to_slic3r); HINSTANCE hInstance_Slic3r = LoadLibraryExW(path_to_slic3r, nullptr, 0); if (hInstance_Slic3r == nullptr) { printf("Snapmaker_Orca.dll was not loaded, error=%d\n", GetLastError()); + exitSentry(); return -1; } // resolve function address here - Snapmaker_Orca_main = (Slic3rMainFunc)GetProcAddress(hInstance_Slic3r, + Snapmaker_Orca_main = (Slic3rMainFunc) + GetProcAddress(hInstance_Slic3r, #ifdef _WIN64 - // there is just a single calling conversion, therefore no mangling of the function name. - "Snapmaker_Orca_main" -#else // stdcall calling convention declaration - "_bambustu_main@8" + // there is just a single calling conversion, therefore no mangling of the function name. + "Snapmaker_Orca_main" +#else // stdcall calling convention declaration + "_bambustu_main@8" #endif ); if (Snapmaker_Orca_main == nullptr) { printf("could not locate the function Snapmaker_Orca_main in Snapmaker_Orca.dll\n"); + exitSentry(); return -1; } + // argc minus the trailing nullptr of the argv - return Snapmaker_Orca_main((int)argv_extended.size() - 1, argv_extended.data()); + auto res = Snapmaker_Orca_main((int) argv_extended.size() - 1, argv_extended.data()); + exitSentry(); + return res; } } diff --git a/src/dev-utils/BaseException.h b/src/dev-utils/BaseException.h index 2cb65d945e..af047cf475 100644 --- a/src/dev-utils/BaseException.h +++ b/src/dev-utils/BaseException.h @@ -26,6 +26,4 @@ protected: boost::nowide::ofstream *output_file; }; -#define SET_DEFULTER_HANDLER() SetUnhandledExceptionFilter(CBaseException::UnhandledExceptionFilter) - #define SET_DEFAUL_EXCEPTION() _set_se_translator(CBaseException::STF) \ No newline at end of file diff --git a/src/libslic3r/CMakeLists.txt b/src/libslic3r/CMakeLists.txt index d85c65fd51..7ddad94f1d 100644 --- a/src/libslic3r/CMakeLists.txt +++ b/src/libslic3r/CMakeLists.txt @@ -511,7 +511,8 @@ endif () encoding_check(libslic3r) target_compile_definitions(libslic3r PUBLIC -DUSE_TBB -DTBB_USE_CAPTURED_EXCEPTION=0) -target_include_directories(libslic3r PRIVATE ${CMAKE_CURRENT_SOURCE_DIR} PUBLIC ${CMAKE_CURRENT_BINARY_DIR}) +# Make source directory PUBLIC so other modules (like libslic3r_gui) can include headers like SentryWrapper.hpp +target_include_directories(libslic3r PUBLIC ${CMAKE_CURRENT_SOURCE_DIR} ${CMAKE_CURRENT_BINARY_DIR}) target_include_directories(libslic3r SYSTEM PUBLIC ${EXPAT_INCLUDE_DIRS}) # Find the OCCT and related libraries @@ -610,3 +611,9 @@ endif() if (SLIC3R_PCH AND NOT SLIC3R_SYNTAXONLY) add_precompiled_header(libslic3r pchheader.hpp FORCEINCLUDE) endif () + +# Sentry crash reporting integration +if (SLIC3R_SENTRY) + target_compile_definitions(libslic3r PUBLIC SLIC3R_SENTRY) + target_link_libraries(libslic3r PUBLIC sentry::sentry) +endif() diff --git a/src/libslic3r/PresetBundle.cpp b/src/libslic3r/PresetBundle.cpp index c3401edcb4..79071cc061 100644 --- a/src/libslic3r/PresetBundle.cpp +++ b/src/libslic3r/PresetBundle.cpp @@ -1837,7 +1837,7 @@ void PresetBundle::export_selections(AppConfig &config) void PresetBundle::update_num_filaments(unsigned int to_del_filament_id) { unsigned old_filament_count = this->filament_presets.size(); - assert(to_del_flament_id < old_filament_count); + assert(to_del_filament_id < old_filament_count); filament_presets.erase(filament_presets.begin() + to_del_filament_id); ConfigOptionStrings* filament_color = project_config.option("filament_colour"); diff --git a/src/sentry_wrapper/SentryWrapper.cpp b/src/sentry_wrapper/SentryWrapper.cpp new file mode 100644 index 0000000000..1103fbb420 --- /dev/null +++ b/src/sentry_wrapper/SentryWrapper.cpp @@ -0,0 +1,194 @@ +/** + * @file SentryWrapper.cpp + * @brief Sentry crash reporting wrapper implementation for cross-platform support. + * + * This implementation provides a unified API for Sentry integration. + * When SLIC3R_SENTRY is not defined, all functions become no-ops. + */ + +#include "SentryWrapper.hpp" + +#ifdef SLIC3R_SENTRY +#include "sentry.h" + +#ifdef _WIN32 +#include +#include +#endif + +#endif + +#include + +namespace Slic3r { + +#ifdef SLIC3R_SENTRY + +static sentry_value_t on_crash_callback(const sentry_ucontext_t* uctx, sentry_value_t event, void* closure) +{ + (void) uctx; + (void) closure; + + // tell the backend to retain the event + return event; +} + +void initSentryEx() +{ + sentry_options_t* options = sentry_options_new(); + { +#ifdef WIN32 + std::string dsn = std::string("https://c74b617c2aedc291444d3a238d23e780@o4508125599563776.ingest.us.sentry.io/4510425163956224"); + + sentry_options_set_dsn(options, dsn.c_str()); + + wchar_t exeDir[MAX_PATH]; + ::GetModuleFileNameW(nullptr, exeDir, MAX_PATH); + std::wstring wsExeDir(exeDir); + int nPos = wsExeDir.find_last_of('\\'); + std::wstring wsDmpDir = wsExeDir.substr(0, nPos + 1); + + std::wstring handlerDir = wsDmpDir + L"crashpad_handler.exe"; + wsDmpDir += L"dump"; + + auto wstringTostring = [](std::wstring wTmpStr) -> std::string { + std::string resStr = std::string(); + int len = WideCharToMultiByte(CP_UTF8, 0, wTmpStr.c_str(), -1, nullptr, 0, nullptr, nullptr); + + if (len <= 0) + return std::string(); + std::string desStr(len, 0); + + WideCharToMultiByte(CP_UTF8, 0, wTmpStr.c_str(), -1, &desStr[0], len, nullptr, nullptr); + + resStr = desStr; + + return resStr; + }; + + std::string desDir = wstringTostring(handlerDir); + if (!desDir.empty()) + sentry_options_set_handler_path(options, desDir.c_str()); + desDir = wstringTostring(wsDmpDir); + desDir = wstringTostring(wsDmpDir); + wchar_t appDataPath[MAX_PATH] = {0}; + auto hr = SHGetFolderPathW(NULL, CSIDL_LOCAL_APPDATA, NULL, SHGFP_TYPE_CURRENT, appDataPath); + char* path = new char[MAX_PATH]; + size_t pathLength; + wcstombs_s(&pathLength, path, MAX_PATH, appDataPath, MAX_PATH); + std::string filePath = path; + std::string appName = "\\" + std::string("Snapmaker_Orca\\"); + filePath = filePath + appName; + + if (!filePath.empty()) + sentry_options_set_database_path(options, filePath.c_str()); +#endif + std::string softVersion = "snapmaker_orca_2.2.0_beta2"; + // Snapmaker_VERSION + sentry_options_set_release(options, softVersion.c_str()); + +#if defined(_DEBUG) || !defined(NDEBUG) + sentry_options_set_debug(options, 1); +#else + sentry_options_set_debug(options, 0); +#endif + // release version environment(Testing/production/development/Staging) + sentry_options_set_environment(options, "develop"); + sentry_options_set_auto_session_tracking(options, false); + sentry_options_set_symbolize_stacktraces(options, true); + sentry_options_set_on_crash(options, on_crash_callback, NULL); + // Enable before_send hook for filtering sensitive data + sentry_options_set_before_send(options, NULL, NULL); + + // Ensure all events and crashes are captured (sample rate 100%) + sentry_options_set_sample_rate(options, 1.0); // Capture 100% of events + sentry_options_set_traces_sample_rate(options, 1.0); // Capture 100% of traces + + sentry_init(options); + sentry_start_session(); + } +} + +void exitSentryEx() +{ + sentry_close(); +} +void sentryReportLogEx(SENTRY_LOG_LEVEL logLevel, + const std::string& logContent, + const std::string& funcModule, + const std::string& logTagKey, + const std::string& logTagValue, + const std::string& logTraceId) +{ + sentry_level_t sentry_msg_level; + switch (logLevel) + { + case SENTRY_LOG_TRACE: + sentry_msg_level = SENTRY_LEVEL_TRACE; + break; + case SENTRY_LOG_DEBUG: + sentry_msg_level = SENTRY_LEVEL_DEBUG; + break; + case SENTRY_LOG_INFO: + sentry_msg_level = SENTRY_LEVEL_INFO; + break; + case SENTRY_LOG_WARNING: + sentry_msg_level = SENTRY_LEVEL_WARNING; + break; + case SENTRY_LOG_ERROR: + sentry_msg_level = SENTRY_LEVEL_ERROR; + break; + case SENTRY_LOG_FATAL: + sentry_msg_level = SENTRY_LEVEL_FATAL; + break; + default: + return; + } + + sentry_value_t event = sentry_value_new_message_event(sentry_msg_level, + funcModule.c_str(), + logContent.c_str() + ); + + if (!logTraceId.empty()) + sentry_set_trace(logTraceId.c_str(), ""); + + if (!logTagKey.empty()) + sentry_set_tag(logTagKey.c_str(), logTagValue.c_str()); + + sentry_capture_event(event); +} + + +#else // SLIC3R_SENTRY not defined - provide no-op implementations + + +#endif // SLIC3R_SENTRY + +void initSentry() +{ +#ifdef SLIC3R_SENTRY + initSentryEx(); +#endif +} + +void exitSentry() +{ +#ifdef SLIC3R_SENTRY + exitSentryEx(); +#endif +} +void sentryReportLog(SENTRY_LOG_LEVEL logLevel, + const std::string& logContent, + const std::string& funcModule, + const std::string& logTagKey, + const std::string& logTagValue, + const std::string& logTraceId) +{ +#ifdef SLIC3R_SENTRY + sentryReportLogEx(logLevel, logContent, funcModule, logTagKey, logTagValue, logTraceId); +#endif +} + +} // namespace Slic3r + diff --git a/src/sentry_wrapper/SentryWrapper.hpp b/src/sentry_wrapper/SentryWrapper.hpp new file mode 100644 index 0000000000..32f46f210d --- /dev/null +++ b/src/sentry_wrapper/SentryWrapper.hpp @@ -0,0 +1,30 @@ +#ifndef slic3r_SentryWrapper_hpp_ +#define slic3r_SentryWrapper_hpp_ + +#include + +namespace Slic3r { + + void initSentry(); + + void exitSentry(); + + typedef enum SENTRY_LOG_LEVEL { + SENTRY_LOG_TRACE = -2, + SENTRY_LOG_DEBUG = -1, + SENTRY_LOG_INFO = 0, + SENTRY_LOG_WARNING = 1, + SENTRY_LOG_ERROR = 2, + SENTRY_LOG_FATAL = 3, + }; + + void sentryReportLog(SENTRY_LOG_LEVEL logLevel, + const std::string& logContent, + const std::string& funcModule = "", + const std::string& logTagKey = "", + const std::string& logTagValue = "", + const std::string& logTraceId = ""); + } // namespace Slic3r + +#endif // slic3r_SentryWrapper_hpp_ + diff --git a/src/slic3r/CMakeLists.txt b/src/slic3r/CMakeLists.txt index 5f6584ceaa..44ae2d49a1 100644 --- a/src/slic3r/CMakeLists.txt +++ b/src/slic3r/CMakeLists.txt @@ -737,3 +737,9 @@ endif () # Add a definition so that we can tell we are compiling slic3r. target_compile_definitions(libslic3r_gui PRIVATE SLIC3R_CURRENTLY_COMPILING_GUI_MODULE) + +# Sentry crash reporting integration +if (SLIC3R_SENTRY) + target_compile_definitions(libslic3r_gui PUBLIC SLIC3R_SENTRY) + target_link_libraries(libslic3r_gui sentry::sentry) +endif() \ No newline at end of file diff --git a/src/slic3r/GUI/MainFrame.cpp b/src/slic3r/GUI/MainFrame.cpp index 15b9856903..8a42c4747e 100644 --- a/src/slic3r/GUI/MainFrame.cpp +++ b/src/slic3r/GUI/MainFrame.cpp @@ -72,6 +72,7 @@ #include #include #include +#include "sentry_wrapper/SentryWrapper.hpp" #endif // _WIN32 #include