From f32aa81f6a1fac085fd9038f1262822bcc1ee126 Mon Sep 17 00:00:00 2001 From: Alves Date: Tue, 9 Dec 2025 10:24:15 +0800 Subject: [PATCH] fix win pack lost dlls bug (#53) * feature add sentry for soft catch dmp * feature add cli upload pdb to sentry server * feature add flag for control sentry to use * fix flag not effect on src/makefile * feature unzip for dmp file to upload sentry server * feature remove test code * feature add api for function report log to server * feature update the soft version * feature merge mac sentry to win platform. * fix mac build error bug * feature add sentry config for mac cmake * fix packed the soft and not copy dlls question * fix windows not copy library bug * feature remove test code --- CMakeLists.txt | 33 +++++++++---- build_release_vs2022.bat | 2 +- deps/Sentry/Sentry.cmake | 58 +++++++++++++++++++--- src/CMakeLists.txt | 63 ++++++++++++++++++++--- src/Snapmaker_Orca.cpp | 12 ++++- src/sentry_wrapper/SentryWrapper.cpp | 74 +++++++++++++++++++--------- src/sentry_wrapper/SentryWrapper.hpp | 2 +- 7 files changed, 192 insertions(+), 52 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 13642a8cb2..b1c0ce23c7 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -543,7 +543,12 @@ find_package(TBB REQUIRED) find_package(OpenSSL REQUIRED) find_package(CURL REQUIRED) if (SLIC3R_SENTRY) - find_package(Sentry REQUIRED) + find_package(Sentry QUIET) + if (NOT Sentry_FOUND) + message(WARNING "Sentry SDK not found. SLIC3R_SENTRY will be disabled. " + "Build deps with Sentry support or use -DSLIC3R_SENTRY=OFF") + set(SLIC3R_SENTRY OFF CACHE BOOL "Enable Sentry crash reporting SDK" FORCE) + endif() endif() find_package(Freetype REQUIRED) @@ -569,7 +574,17 @@ if (SLIC3R_SENTRY) else() message(WARNING "sentry.lib not found in ${CMAKE_PREFIX_PATH}/lib. Sentry SDK may not have been built yet.") endif() - endif() + elseif (APPLE AND CMAKE_PREFIX_PATH) + # Try to find libsentry.dylib in the install prefix for macOS + file(GLOB _sentry_lib "${CMAKE_PREFIX_PATH}/lib/libsentry.dylib") + if (_sentry_lib) + target_link_directories(sentry INTERFACE "${CMAKE_PREFIX_PATH}/lib") + target_link_libraries(sentry INTERFACE "sentry") + message(STATUS "Found libsentry.dylib at: ${CMAKE_PREFIX_PATH}/lib") + else() + message(WARNING "libsentry.dylib 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 @@ -793,7 +808,8 @@ function(Snapmaker_Orca_copy_dlls target config postfix output_dlls) ${CMAKE_PREFIX_PATH}/bin/freetype.dll DESTINATION ${_out_dir}) - set(${output_dlls} + # Build the DLL list in a local variable first + set(_dll_list ${_out_dir}/libgmp-10.dll ${_out_dir}/libmpfr-4.dll ${_out_dir}/WebView2Loader.dll @@ -826,20 +842,19 @@ function(Snapmaker_Orca_copy_dlls target config postfix output_dlls) ${_out_dir}/TKXSBase.dll ${_out_dir}/freetype.dll - - PARENT_SCOPE ) - # Add Sentry DLLs to the output list if Sentry is enabled + # Add Sentry DLLs to the list if Sentry is enabled if (SLIC3R_SENTRY) - set(${output_dlls} - ${${output_dlls}} + list(APPEND _dll_list ${_out_dir}/sentry.dll ${_out_dir}/crashpad_handler.exe - PARENT_SCOPE ) endif() + # Set the output variable in parent scope (only once, with complete list) + set(${output_dlls} ${_dll_list} PARENT_SCOPE) + endfunction() diff --git a/build_release_vs2022.bat b/build_release_vs2022.bat index 488f02fe07..2724bf876f 100644 --- a/build_release_vs2022.bat +++ b/build_release_vs2022.bat @@ -47,7 +47,7 @@ if "%1"=="slicer" ( echo "building deps.." echo on -cmake ../ -G "Visual Studio 17 2022" -A x64 -DDESTDIR="%DEPS%" -DCMAKE_BUILD_TYPE=%build_type% -DDEP_DEBUG=%debug% -DORCA_INCLUDE_DEBUG_INFO=%debuginfo% +cmake ../ -G "Visual Studio 17 2022" -A x64 -DDESTDIR="%DEPS%" -DCMAKE_BUILD_TYPE=%build_type% -DDEP_DEBUG=%debug% -DORCA_INCLUDE_DEBUG_INFO=%debuginfo% -DSLIC3R_SENTRY=ON cmake --build . --config %build_type% --target deps -- -m @echo off diff --git a/deps/Sentry/Sentry.cmake b/deps/Sentry/Sentry.cmake index 91e49fc74b..f636281dbe 100644 --- a/deps/Sentry/Sentry.cmake +++ b/deps/Sentry/Sentry.cmake @@ -2,7 +2,7 @@ set(_sentry_platform_flags -DCMAKE_POSITION_INDEPENDENT_CODE=ON -DSENTRY_BUILD_TESTS=OFF -DSENTRY_EXAMPLES=OFF - -DSENTRY_CRASHPAD_BACKEND=ON + -DSENTRY_BACKEND=crashpad -DSENTRY_ENABLE_INSTALL=ON ) @@ -25,16 +25,35 @@ if (WIN32) 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) + # macOS: build shared libs so we get libsentry.dylib + # Note: CURL transport requires OpenSSL, need to link it explicitly + # DESTDIR already contains /usr/local/ suffix, so use it directly set(_sentry_platform_flags ${_sentry_platform_flags} -DSENTRY_TRANSPORT_CURL=ON - -DSENTRY_BUILD_SHARED_LIBS=OFF + -DSENTRY_BUILD_SHARED_LIBS=ON -DCMAKE_BUILD_TYPE:STRING=RelWithDebInfo - -DCMAKE_C_FLAGS:STRING=-g -O2 - -DCMAKE_CXX_FLAGS:STRING=-g -O2 + -DOPENSSL_ROOT_DIR:PATH=${DESTDIR} + -DOPENSSL_USE_STATIC_LIBS:BOOL=ON + -DCMAKE_SHARED_LINKER_FLAGS:STRING=-L${DESTDIR}/lib\ -lssl\ -lcrypto ) set(_sentry_cmake_generator -G "Unix Makefiles") + + # Sentry/crashpad requires macOS 12.0+ due to kIOMainPortDefault API usage + # Force minimum deployment target to 12.0 for Sentry build + set(_sentry_osx_deployment_target "12.0") + if (CMAKE_OSX_DEPLOYMENT_TARGET AND CMAKE_OSX_DEPLOYMENT_TARGET VERSION_GREATER "12.0") + set(_sentry_osx_deployment_target ${CMAKE_OSX_DEPLOYMENT_TARGET}) + endif() + + # Add macOS architecture and deployment target for sentry build + if (CMAKE_OSX_ARCHITECTURES) + set(_sentry_platform_flags ${_sentry_platform_flags} -DCMAKE_OSX_ARCHITECTURES:STRING=${CMAKE_OSX_ARCHITECTURES}) + endif() + set(_sentry_platform_flags ${_sentry_platform_flags} -DCMAKE_OSX_DEPLOYMENT_TARGET:STRING=${_sentry_osx_deployment_target}) + if (CMAKE_OSX_SYSROOT) + set(_sentry_platform_flags ${_sentry_platform_flags} -DCMAKE_OSX_SYSROOT:STRING=${CMAKE_OSX_SYSROOT}) + endif() elseif(CMAKE_SYSTEM_NAME STREQUAL "Linux") # Linux: Use Unix Makefiles set(_sentry_platform_flags @@ -42,22 +61,45 @@ elseif(CMAKE_SYSTEM_NAME STREQUAL "Linux") -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 () +if(WIN32) + set(SENTRY_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 + ) +elseif(APPLE) + set(SENTRY_PATCH_COMMAND + ${GIT_EXECUTABLE} submodule update --init --recursive + ) +else() + set(SENTRY_PATCH_COMMAND + ${GIT_EXECUTABLE} submodule update --init --recursive + ) +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 + PATCH_COMMAND ${SENTRY_PATCH_COMMAND} CMAKE_ARGS ${_sentry_cmake_generator} -DCMAKE_INSTALL_DATADIR:STRING=share ${_sentry_platform_flags} ) +# Sentry depends on CURL which depends on OpenSSL +# Ensure they are built before Sentry +if(APPLE) + if (TARGET dep_CURL) + add_dependencies(dep_Sentry dep_CURL) + endif() + if (TARGET dep_OpenSSL) + add_dependencies(dep_Sentry dep_OpenSSL) + endif() +endif() + if (MSVC) add_debug_dep(dep_Sentry) endif () diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index ca9e209e0c..ee5c2e7cf4 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -117,7 +117,7 @@ configure_file(${CMAKE_CURRENT_SOURCE_DIR}/dev-utils/platform/osx/Info.plist.in 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 sentry_wrapper/SentryWrapper.hpp sentry_wrapper/SentryWrapper.cpp) else () - add_executable(Snapmaker_Orca Snapmaker_Orca.cpp Snapmaker_Orca.hpp) + add_executable(Snapmaker_Orca Snapmaker_Orca.cpp Snapmaker_Orca.hpp sentry_wrapper/SentryWrapper.hpp sentry_wrapper/SentryWrapper.cpp) endif () if (MINGW) @@ -222,20 +222,33 @@ if (WIN32) ) endforeach () - if ("${CMAKE_BUILD_TYPE}" STREQUAL "Debug") - Snapmaker_Orca_copy_dlls(COPY_DLLS "Debug" "d" output_dlls_Debug) - elseif("${CMAKE_BUILD_TYPE}" STREQUAL "RelWithDebInfo") - Snapmaker_Orca_copy_dlls(COPY_DLLS "RelWithDebInfo" "" output_dlls_Release) - else() - Snapmaker_Orca_copy_dlls(COPY_DLLS "Release" "" output_dlls_Release) - endif() + # For multi-config generators (Visual Studio), copy DLLs for all configurations + foreach (CONF ${CMAKE_CONFIGURATION_TYPES}) + if ("${CONF}" STREQUAL "Debug") + Snapmaker_Orca_copy_dlls(COPY_DLLS "${CONF}" "d" output_dlls_Debug) + elseif ("${CONF}" STREQUAL "Release") + Snapmaker_Orca_copy_dlls(COPY_DLLS "${CONF}" "" output_dlls_Release) + elseif ("${CONF}" STREQUAL "RelWithDebInfo") + Snapmaker_Orca_copy_dlls(COPY_DLLS "${CONF}" "" output_dlls_RelWithDebInfo) + else() + # MinSizeRel or other configs + Snapmaker_Orca_copy_dlls(COPY_DLLS "${CONF}" "" _unused_dlls) + endif() + endforeach () else () + # Single-config generators (Ninja, Makefiles) file(TO_NATIVE_PATH "${CMAKE_CURRENT_BINARY_DIR}/resources" WIN_RESOURCES_SYMLINK) add_custom_command(TARGET Snapmaker_Orca POST_BUILD COMMAND if not exist "${WIN_RESOURCES_SYMLINK}" "(" mklink /J "${WIN_RESOURCES_SYMLINK}" "${SLIC3R_RESOURCES_DIR_WIN}" ")" COMMENT "Symlinking the resources directory into the build tree" VERBATIM ) + # Copy DLLs for single-config generators + if ("${CMAKE_BUILD_TYPE}" STREQUAL "Debug") + Snapmaker_Orca_copy_dlls(COPY_DLLS "Debug" "d" output_dlls_Debug) + else() + Snapmaker_Orca_copy_dlls(COPY_DLLS "${CMAKE_BUILD_TYPE}" "" output_dlls_Release) + endif() endif () @@ -246,6 +259,20 @@ else () COMMAND ln -sf Snapmaker_Orca snapmaker-orca WORKING_DIRECTORY "$" VERBATIM) + # Copy Sentry crashpad_handler to executable directory for non-bundle builds (e.g., Xcode debugging) + if (SLIC3R_SENTRY) + add_custom_command(TARGET Snapmaker_Orca POST_BUILD + COMMAND ${CMAKE_COMMAND} -E copy_if_different "${CMAKE_PREFIX_PATH}/bin/crashpad_handler" "$/crashpad_handler" + COMMAND sh -c "codesign --force --sign - '$/crashpad_handler' 2>/dev/null || true" + COMMENT "Copying crashpad_handler for Sentry crash reporting" + VERBATIM) + # Copy libsentry.dylib to executable directory for non-bundle builds + add_custom_command(TARGET Snapmaker_Orca POST_BUILD + COMMAND ${CMAKE_COMMAND} -E copy_if_different "${CMAKE_PREFIX_PATH}/lib/libsentry.dylib" "$/libsentry.dylib" + COMMAND sh -c "codesign --force --sign - '$/libsentry.dylib' 2>/dev/null || true" + COMMENT "Copying libsentry.dylib for Sentry crash reporting" + VERBATIM) + endif() else () add_custom_command(TARGET Snapmaker_Orca POST_BUILD WORKING_DIRECTORY "$" @@ -278,6 +305,26 @@ else () COMMAND ${CMAKE_COMMAND} -E create_symlink "${SLIC3R_RESOURCES_DIR}" "$/../Resources" COMMENT "Symlinking the resources directory into the build tree" VERBATIM) + # Copy Sentry crashpad_handler to MacOS directory (same directory as executable) + if (SLIC3R_SENTRY) + add_custom_command(TARGET Snapmaker_Orca POST_BUILD + COMMAND ${CMAKE_COMMAND} -E copy_if_different "${CMAKE_PREFIX_PATH}/bin/crashpad_handler" "$/crashpad_handler" + COMMAND sh -c "codesign --force --sign - '$/crashpad_handler' 2>/dev/null || true" + COMMENT "Copying and signing crashpad_handler for Sentry crash reporting" + VERBATIM) + # Copy libsentry.dylib to Frameworks directory + add_custom_command(TARGET Snapmaker_Orca POST_BUILD + COMMAND ${CMAKE_COMMAND} -E make_directory "$/../Frameworks" + COMMAND ${CMAKE_COMMAND} -E copy_if_different "${CMAKE_PREFIX_PATH}/lib/libsentry.dylib" "$/../Frameworks/libsentry.dylib" + COMMAND sh -c "codesign --force --sign - '$/../Frameworks/libsentry.dylib' 2>/dev/null || true" + COMMENT "Copying and signing libsentry.dylib for Sentry crash reporting" + VERBATIM) + # Update the rpath for libsentry.dylib + add_custom_command(TARGET Snapmaker_Orca POST_BUILD + COMMAND install_name_tool -change "@rpath/libsentry.dylib" "@executable_path/../Frameworks/libsentry.dylib" "$" || true + COMMENT "Updating rpath for libsentry.dylib" + VERBATIM) + endif() endif() endif () diff --git a/src/Snapmaker_Orca.cpp b/src/Snapmaker_Orca.cpp index 60176d5c3a..5f50d8aca3 100644 --- a/src/Snapmaker_Orca.cpp +++ b/src/Snapmaker_Orca.cpp @@ -33,6 +33,10 @@ using namespace nlohmann; #endif + +#include "sentry_wrapper/SentryWrapper.hpp" + + #include #include #include @@ -6291,6 +6295,12 @@ extern "C" { #else /* _MSC_VER */ int main(int argc, char **argv) { - return CLI().run(argc, argv); + initSentry(); + + auto res = CLI().run(argc, argv); + + exitSentry(); + + return res; } #endif /* _MSC_VER */ diff --git a/src/sentry_wrapper/SentryWrapper.cpp b/src/sentry_wrapper/SentryWrapper.cpp index 1103fbb420..613ca3dda4 100644 --- a/src/sentry_wrapper/SentryWrapper.cpp +++ b/src/sentry_wrapper/SentryWrapper.cpp @@ -10,14 +10,19 @@ #ifdef SLIC3R_SENTRY #include "sentry.h" +#endif #ifdef _WIN32 #include #include #endif +#ifdef __APPLE__ +#include +#include #endif +#include #include namespace Slic3r { @@ -36,41 +41,60 @@ static sentry_value_t on_crash_callback(const sentry_ucontext_t* uctx, sentry_va void initSentryEx() { sentry_options_t* options = sentry_options_new(); + std::string dsn = ""; { -#ifdef WIN32 +#ifdef __APPLE__ + + std::string dsn = std::string("https://ac473187efb8877f36bd31694ffd5dec@o4508125599563776.ingest.us.sentry.io/4510425212059648"); + +#elif _WIN32 std::string dsn = std::string("https://c74b617c2aedc291444d3a238d23e780@o4508125599563776.ingest.us.sentry.io/4510425163956224"); - +#endif sentry_options_set_dsn(options, dsn.c_str()); + std::string handlerDir = ""; + std::string dataBaseDir = ""; +#ifdef __APPLE__ + + char exe_path[PATH_MAX] = {0}; + uint32_t buf_size = PATH_MAX; + + if (_NSGetExecutablePath(exe_path, &buf_size) != 0) { + throw std::runtime_error("Buffer too small for executable path"); + } + + // Get the directory containing the executable, not the executable path itself + boost::filesystem::path exe_dir = boost::filesystem::path(exe_path).parent_path(); + handlerDir = (exe_dir / "crashpad_handler").string(); + + const char* home_env = getenv("HOME"); + + dataBaseDir = home_env; + dataBaseDir = dataBaseDir + "/Library/Application Support/Snapmaker_Orca/SentryData"; +#elif _WIN32 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"; + std::wstring desDir = 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); + handlerDir = wstringTostring(desDir); + wchar_t appDataPath[MAX_PATH] = {0}; auto hr = SHGetFolderPathW(NULL, CSIDL_LOCAL_APPDATA, NULL, SHGFP_TYPE_CURRENT, appDataPath); char* path = new char[MAX_PATH]; @@ -78,13 +102,16 @@ void initSentryEx() 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()); + dataBaseDir = filePath + appName; #endif + + if (!handlerDir.empty()) + sentry_options_set_handler_path(options, handlerDir.c_str()); + + if (!dataBaseDir.empty()) + sentry_options_set_database_path(options, dataBaseDir.c_str()); + std::string softVersion = "snapmaker_orca_2.2.0_beta2"; - // Snapmaker_VERSION sentry_options_set_release(options, softVersion.c_str()); #if defined(_DEBUG) || !defined(NDEBUG) @@ -92,17 +119,16 @@ void initSentryEx() #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_auto_session_tracking(options, 0); + sentry_options_set_symbolize_stacktraces(options, 1); 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_options_set_sample_rate(options, 1.0); + sentry_options_set_traces_sample_rate(options, 1.0); sentry_init(options); sentry_start_session(); diff --git a/src/sentry_wrapper/SentryWrapper.hpp b/src/sentry_wrapper/SentryWrapper.hpp index 32f46f210d..29de368b0e 100644 --- a/src/sentry_wrapper/SentryWrapper.hpp +++ b/src/sentry_wrapper/SentryWrapper.hpp @@ -19,7 +19,7 @@ namespace Slic3r { }; void sentryReportLog(SENTRY_LOG_LEVEL logLevel, - const std::string& logContent, + const std::string& logContent, const std::string& funcModule = "", const std::string& logTagKey = "", const std::string& logTagValue = "",