From 124a42e534093a30ae0690cf037e70ee854d7e42 Mon Sep 17 00:00:00 2001 From: Ivan Dlugos Date: Tue, 15 Oct 2024 17:58:46 +0200 Subject: [PATCH 01/10] feat: build sentry-native for linux --- flutter/example/linux/flutter/CMakeLists.txt | 2 +- flutter/lib/src/native/c/sentry_native.dart | 11 +++- flutter/lib/src/native/factory_real.dart | 2 +- flutter/linux/CMakeLists.txt | 29 +++------ .../sentry_flutter/sentry_flutter_plugin.h | 9 +-- flutter/linux/sentry_flutter_plugin.cc | 60 ------------------- flutter/pubspec.yaml | 4 +- flutter/sentry-native/sentry-native.cmake | 10 ++-- .../sentry_native/sentry_native_test.dart | 2 +- .../sentry_native/sentry_native_test_ffi.dart | 26 +++++--- flutter/windows/CMakeLists.txt | 2 +- 11 files changed, 48 insertions(+), 109 deletions(-) rename flutter/linux/{include => }/sentry_flutter/sentry_flutter_plugin.h (62%) delete mode 100644 flutter/linux/sentry_flutter_plugin.cc diff --git a/flutter/example/linux/flutter/CMakeLists.txt b/flutter/example/linux/flutter/CMakeLists.txt index a1da1b9e53..6dc9705582 100644 --- a/flutter/example/linux/flutter/CMakeLists.txt +++ b/flutter/example/linux/flutter/CMakeLists.txt @@ -82,7 +82,7 @@ add_custom_command( COMMAND ${CMAKE_COMMAND} -E env ${FLUTTER_TOOL_ENVIRONMENT} "${FLUTTER_ROOT}/packages/flutter_tools/bin/tool_backend.sh" - linux-x64 ${CMAKE_BUILD_TYPE} + ${FLUTTER_TARGET_PLATFORM} ${CMAKE_BUILD_TYPE} VERBATIM ) add_custom_target(flutter_assemble DEPENDS diff --git a/flutter/lib/src/native/c/sentry_native.dart b/flutter/lib/src/native/c/sentry_native.dart index d3f86df2d7..07f7edea05 100644 --- a/flutter/lib/src/native/c/sentry_native.dart +++ b/flutter/lib/src/native/c/sentry_native.dart @@ -1,5 +1,6 @@ import 'dart:async'; import 'dart:ffi'; +import 'dart:io'; import 'dart:typed_data'; import 'package:ffi/ffi.dart'; @@ -19,7 +20,15 @@ class SentryNative with SentryNativeSafeInvoker implements SentryNativeBinding { final SentryFlutterOptions options; @visibleForTesting - static final native = binding.SentryNative(DynamicLibrary.open('sentry.dll')); + static final native = binding.SentryNative(DynamicLibrary.open( + '$dynamicLibraryDirectory${Platform.isWindows ? 'sentry.dll' : 'libsentry.so'}')); + + /// If the path is just the library name, the loader will look for it in + /// the usual places for shared libraries: + /// - on Linux in /lib and /usr/lib + /// - on Windows in the working directory and System32 + @visibleForTesting + static String? dynamicLibraryDirectory; @visibleForTesting static String? crashpadPath; diff --git a/flutter/lib/src/native/factory_real.dart b/flutter/lib/src/native/factory_real.dart index 92b0f6e545..8824d781bf 100644 --- a/flutter/lib/src/native/factory_real.dart +++ b/flutter/lib/src/native/factory_real.dart @@ -11,7 +11,7 @@ SentryNativeBinding createBinding(SentryFlutterOptions options) { return SentryNativeCocoa(options); } else if (platform.isAndroid) { return SentryNativeJava(options); - } else if (platform.isWindows) { + } else if (platform.isWindows || platform.isLinux) { return SentryNative(options); } else { return SentryNativeChannel(options); diff --git a/flutter/linux/CMakeLists.txt b/flutter/linux/CMakeLists.txt index b63ea90066..2c886a675b 100644 --- a/flutter/linux/CMakeLists.txt +++ b/flutter/linux/CMakeLists.txt @@ -1,25 +1,10 @@ +# The Flutter tooling requires that developers have CMake 3.10 or later +# installed. You should not increase this version, as doing so will cause +# the plugin to fail to compile for some customers of the plugin. cmake_minimum_required(VERSION 3.10) -set(PROJECT_NAME "sentry_flutter") -project(${PROJECT_NAME} LANGUAGES CXX) -# This value is used when generating builds using this plugin, so it must -# not be changed -set(PLUGIN_NAME "sentry_flutter_plugin") +include("${CMAKE_CURRENT_SOURCE_DIR}/../sentry-native/sentry-native.cmake") -add_library(${PLUGIN_NAME} SHARED - "sentry_flutter_plugin.cc" -) -apply_standard_settings(${PLUGIN_NAME}) -set_target_properties(${PLUGIN_NAME} PROPERTIES - CXX_VISIBILITY_PRESET hidden) -target_compile_definitions(${PLUGIN_NAME} PRIVATE FLUTTER_PLUGIN_IMPL) -target_include_directories(${PLUGIN_NAME} INTERFACE - "${CMAKE_CURRENT_SOURCE_DIR}/include") -target_link_libraries(${PLUGIN_NAME} PRIVATE flutter) -target_link_libraries(${PLUGIN_NAME} PRIVATE PkgConfig::GTK) - -# List of absolute paths to libraries that should be bundled with the plugin -set(sentry_flutter_bundled_libraries - "" - PARENT_SCOPE -) +# Even though sentry_flutter doesn't actually provide a useful plugin, we need to accommodate the Flutter tooling. +# sentry_flutter/sentry_flutter_plugin.h is included by the flutter-tool generated plugin registrar: +target_include_directories(sentry INTERFACE ${CMAKE_CURRENT_LIST_DIR}) diff --git a/flutter/linux/include/sentry_flutter/sentry_flutter_plugin.h b/flutter/linux/sentry_flutter/sentry_flutter_plugin.h similarity index 62% rename from flutter/linux/include/sentry_flutter/sentry_flutter_plugin.h rename to flutter/linux/sentry_flutter/sentry_flutter_plugin.h index d0f8df001f..27aabe4deb 100644 --- a/flutter/linux/include/sentry_flutter/sentry_flutter_plugin.h +++ b/flutter/linux/sentry_flutter/sentry_flutter_plugin.h @@ -1,5 +1,4 @@ -#ifndef FLUTTER_PLUGIN_SENTRY_FLUTTER_PLUGIN_H_ -#define FLUTTER_PLUGIN_SENTRY_FLUTTER_PLUGIN_H_ +#pragma once #include @@ -16,11 +15,7 @@ typedef struct { GObjectClass parent_class; } SentryFlutterPluginClass; -FLUTTER_PLUGIN_EXPORT GType sentry_flutter_plugin_get_type(); - FLUTTER_PLUGIN_EXPORT void sentry_flutter_plugin_register_with_registrar( - FlPluginRegistrar* registrar); + FlPluginRegistrar* registrar) {} G_END_DECLS - -#endif // FLUTTER_PLUGIN_SENTRY_FLUTTER_PLUGIN_H_ diff --git a/flutter/linux/sentry_flutter_plugin.cc b/flutter/linux/sentry_flutter_plugin.cc deleted file mode 100644 index c8ac1220c7..0000000000 --- a/flutter/linux/sentry_flutter_plugin.cc +++ /dev/null @@ -1,60 +0,0 @@ -#include "include/sentry_flutter/sentry_flutter_plugin.h" - -#include -#include -#include - -#include - -#define SENTRY_FLUTTER_PLUGIN(obj) \ - (G_TYPE_CHECK_INSTANCE_CAST((obj), sentry_flutter_plugin_get_type(), \ - SentryFlutterPlugin)) - -struct _SentryFlutterPlugin { - GObject parent_instance; -}; - -G_DEFINE_TYPE(SentryFlutterPlugin, sentry_flutter_plugin, g_object_get_type()) - -// Called when a method call is received from Flutter. -static void sentry_flutter_plugin_handle_method_call( - SentryFlutterPlugin* self, - FlMethodCall* method_call) { - g_autoptr(FlMethodResponse) response = nullptr; - - response = FL_METHOD_RESPONSE(fl_method_not_implemented_response_new()); - - fl_method_call_respond(method_call, response, nullptr); -} - -static void sentry_flutter_plugin_dispose(GObject* object) { - G_OBJECT_CLASS(sentry_flutter_plugin_parent_class)->dispose(object); -} - -static void sentry_flutter_plugin_class_init(SentryFlutterPluginClass* klass) { - G_OBJECT_CLASS(klass)->dispose = sentry_flutter_plugin_dispose; -} - -static void sentry_flutter_plugin_init(SentryFlutterPlugin* self) {} - -static void method_call_cb(FlMethodChannel* channel, FlMethodCall* method_call, - gpointer user_data) { - SentryFlutterPlugin* plugin = SENTRY_FLUTTER_PLUGIN(user_data); - sentry_flutter_plugin_handle_method_call(plugin, method_call); -} - -void sentry_flutter_plugin_register_with_registrar(FlPluginRegistrar* registrar) { - SentryFlutterPlugin* plugin = SENTRY_FLUTTER_PLUGIN( - g_object_new(sentry_flutter_plugin_get_type(), nullptr)); - - g_autoptr(FlStandardMethodCodec) codec = fl_standard_method_codec_new(); - g_autoptr(FlMethodChannel) channel = - fl_method_channel_new(fl_plugin_registrar_get_messenger(registrar), - "sentry_flutter", - FL_METHOD_CODEC(codec)); - fl_method_channel_set_method_call_handler(channel, method_call_cb, - g_object_ref(plugin), - g_object_unref); - - g_object_unref(plugin); -} diff --git a/flutter/pubspec.yaml b/flutter/pubspec.yaml index dbc63000d2..6d33508d5e 100644 --- a/flutter/pubspec.yaml +++ b/flutter/pubspec.yaml @@ -58,9 +58,9 @@ flutter: web: pluginClass: SentryFlutterWeb fileName: sentry_flutter_web.dart + # Note, we cannot use `ffiPlugin: true` on Linux and windows because flutter won't add `target_link_libraries()` + # so sentry-native won't even build during the build process (since it doesn't need to). linux: pluginClass: SentryFlutterPlugin windows: - # Note, we cannot use `ffiPlugin: true` because flutter tooling won't add `target_link_libraries()` - # so sentry-native won't even build during the build process (since it doesn't need to). pluginClass: SentryFlutterPlugin diff --git a/flutter/sentry-native/sentry-native.cmake b/flutter/sentry-native/sentry-native.cmake index 0a5fc7884f..258eeb6f8a 100644 --- a/flutter/sentry-native/sentry-native.cmake +++ b/flutter/sentry-native/sentry-native.cmake @@ -18,11 +18,11 @@ FetchContent_MakeAvailable(sentry-native) # List of absolute paths to libraries that should be bundled with the plugin. # This list could contain prebuilt libraries, or libraries created by an # external build triggered from this build file. -set(sentry_flutter_bundled_libraries - $ - $ - PARENT_SCOPE -) +set(sentry_flutter_bundled_libraries $ PARENT_SCOPE) + +if(WIN32) + set(sentry_flutter_bundled_libraries ${sentry_flutter_bundled_libraries} $ PARENT_SCOPE) +endif() # `*_plugin` is the name of the plugin library as expected by flutter. # We don't actually need a plugin here, we just need to get the native library linked diff --git a/flutter/test/sentry_native/sentry_native_test.dart b/flutter/test/sentry_native/sentry_native_test.dart index 3b720df7af..5f168a919d 100644 --- a/flutter/test/sentry_native/sentry_native_test.dart +++ b/flutter/test/sentry_native/sentry_native_test.dart @@ -1,7 +1,7 @@ // We must conditionally import the actual test code, otherwise tests fail on // a browser. @TestOn('vm') doesn't help by itself in this case because imports // are still evaluated, thus causing a compilation failure. -@TestOn('vm && windows') +@TestOn('vm && (windows || linux)') library sentry_native_test; import 'package:flutter_test/flutter_test.dart'; diff --git a/flutter/test/sentry_native/sentry_native_test_ffi.dart b/flutter/test/sentry_native/sentry_native_test_ffi.dart index 75fbf89c96..04de4a225b 100644 --- a/flutter/test/sentry_native/sentry_native_test_ffi.dart +++ b/flutter/test/sentry_native/sentry_native_test_ffi.dart @@ -22,15 +22,14 @@ void main() { ? Directory.current.parent.path : Directory.current.path; - expectedDistFiles = [ - 'sentry.dll', - 'crashpad_handler.exe', - 'crashpad_wer.dll', - ]; + expectedDistFiles = platform.instance.isWindows + ? ['sentry.dll', 'crashpad_handler.exe', 'crashpad_wer.dll'] + : ['libsentry.so', 'crashpad_handler']; setUpAll(() async { Directory.current = await _buildSentryNative('$repoRootDir/temp/native-test'); + SentryNative.dynamicLibraryDirectory = '${Directory.current.path}/'; SentryNative.crashpadPath = '${Directory.current.path}/${expectedDistFiles.firstWhere((f) => f.startsWith('crashpad_handler'))}'; }); @@ -213,9 +212,10 @@ void main() { test('loadDebugImages', () async { final list = await sut.loadDebugImages(SentryStackTrace(frames: [])); expect(list, isNotEmpty); - expect(list![0].type, 'pe'); + expect(list![0].type, platform.instance.isWindows ? 'pe' : 'elf'); expect(list[0].debugId!.length, greaterThan(30)); - expect(list[0].debugFile, isNotEmpty); + expect( + list[0].debugFile, platform.instance.isWindows ? isNotEmpty : isNull); expect(list[0].imageSize, greaterThan(0)); expect(list[0].imageAddr, startsWith('0x')); expect(list[0].imageAddr?.length, greaterThan(2)); @@ -274,7 +274,17 @@ install(FILES "\${PLUGIN_BUNDLED_LIBRARIES}" DESTINATION "${buildOutputDir.repla await _exec('cmake', ['-B', cmakeBuildDir, cmakeConfDir]); await _exec('cmake', ['--build', cmakeBuildDir, '--config', 'Release', '--parallel']); - await _exec('cmake', ['--install', cmakeBuildDir, '--config', 'Release']); + await _exec('cmake', [ + '--install', + cmakeBuildDir, + '--config', + 'Release', + '--component', + 'Runtime' + ]); + if (platform.instance.isLinux) { + await _exec('chmod', ['+x', '$buildOutputDir/crashpad_handler']); + } } return buildOutputDir; } diff --git a/flutter/windows/CMakeLists.txt b/flutter/windows/CMakeLists.txt index f992a75fdb..7926cf0571 100644 --- a/flutter/windows/CMakeLists.txt +++ b/flutter/windows/CMakeLists.txt @@ -6,6 +6,6 @@ cmake_minimum_required(VERSION 3.14) include("${CMAKE_CURRENT_SOURCE_DIR}/../sentry-native/sentry-native.cmake") -# Even though sentry_flutter doesn't actually provide a useful plugin, we need to accomodate the Flutter tooling. +# Even though sentry_flutter doesn't actually provide a useful plugin, we need to accommodate the Flutter tooling. # sentry_flutter/sentry_flutter_plugin.h is included by the flutter-tool generated plugin registrar: target_include_directories(sentry INTERFACE ${CMAKE_CURRENT_LIST_DIR}) From e3245b53d7ddb1f85a4c5b8702542a2dfa758f25 Mon Sep 17 00:00:00 2001 From: Ivan Dlugos Date: Tue, 15 Oct 2024 20:03:03 +0200 Subject: [PATCH 02/10] fix linux native integration --- dart/lib/src/platform_checker.dart | 3 +- flutter/example/linux/my_application.cc | 46 ++++++++++++++++----- flutter/lib/src/native/c/sentry_native.dart | 7 +++- flutter/pubspec.yaml | 1 + flutter/sentry-native/sentry-native.cmake | 8 ++-- 5 files changed, 49 insertions(+), 16 deletions(-) diff --git a/dart/lib/src/platform_checker.dart b/dart/lib/src/platform_checker.dart index 334d73f43f..602f8a6615 100644 --- a/dart/lib/src/platform_checker.dart +++ b/dart/lib/src/platform_checker.dart @@ -47,7 +47,8 @@ class PlatformChecker { return platform.isAndroid || platform.isIOS || platform.isMacOS || - platform.isWindows; + platform.isWindows || + platform.isLinux; } static bool _isWebWithWasmSupport() { diff --git a/flutter/example/linux/my_application.cc b/flutter/example/linux/my_application.cc index c13dff9b7a..6939b619d8 100644 --- a/flutter/example/linux/my_application.cc +++ b/flutter/example/linux/my_application.cc @@ -29,22 +29,21 @@ static void my_application_activate(GApplication* application) { // if future cases occur). gboolean use_header_bar = TRUE; #ifdef GDK_WINDOWING_X11 - GdkScreen *screen = gtk_window_get_screen(window); + GdkScreen* screen = gtk_window_get_screen(window); if (GDK_IS_X11_SCREEN(screen)) { - const gchar* wm_name = gdk_x11_screen_get_window_manager_name(screen); - if (g_strcmp0(wm_name, "GNOME Shell") != 0) { - use_header_bar = FALSE; - } + const gchar* wm_name = gdk_x11_screen_get_window_manager_name(screen); + if (g_strcmp0(wm_name, "GNOME Shell") != 0) { + use_header_bar = FALSE; + } } #endif if (use_header_bar) { - GtkHeaderBar *header_bar = GTK_HEADER_BAR(gtk_header_bar_new()); + GtkHeaderBar* header_bar = GTK_HEADER_BAR(gtk_header_bar_new()); gtk_widget_show(GTK_WIDGET(header_bar)); gtk_header_bar_set_title(header_bar, "sentry_flutter_example"); gtk_header_bar_set_show_close_button(header_bar, TRUE); gtk_window_set_titlebar(window, GTK_WIDGET(header_bar)); - } - else { + } else { gtk_window_set_title(window, "sentry_flutter_example"); } @@ -64,7 +63,7 @@ static void my_application_activate(GApplication* application) { } // Implements GApplication::local_command_line. -static gboolean my_application_local_command_line(GApplication* application, gchar ***arguments, int *exit_status) { +static gboolean my_application_local_command_line(GApplication* application, gchar*** arguments, int* exit_status) { MyApplication* self = MY_APPLICATION(application); // Strip out the first argument as it is the binary name. self->dart_entrypoint_arguments = g_strdupv(*arguments + 1); @@ -82,8 +81,26 @@ static gboolean my_application_local_command_line(GApplication* application, gch return TRUE; } +// Implements GApplication::startup. +static void my_application_startup(GApplication* application) { + //MyApplication* self = MY_APPLICATION(object); + + // Perform any actions required at application startup. + + G_APPLICATION_CLASS(my_application_parent_class)->startup(application); +} + +// Implements GApplication::shutdown. +static void my_application_shutdown(GApplication* application) { + //MyApplication* self = MY_APPLICATION(object); + + // Perform any actions required at application shutdown. + + G_APPLICATION_CLASS(my_application_parent_class)->shutdown(application); +} + // Implements GObject::dispose. -static void my_application_dispose(GObject *object) { +static void my_application_dispose(GObject* object) { MyApplication* self = MY_APPLICATION(object); g_clear_pointer(&self->dart_entrypoint_arguments, g_strfreev); G_OBJECT_CLASS(my_application_parent_class)->dispose(object); @@ -92,13 +109,22 @@ static void my_application_dispose(GObject *object) { static void my_application_class_init(MyApplicationClass* klass) { G_APPLICATION_CLASS(klass)->activate = my_application_activate; G_APPLICATION_CLASS(klass)->local_command_line = my_application_local_command_line; + G_APPLICATION_CLASS(klass)->startup = my_application_startup; + G_APPLICATION_CLASS(klass)->shutdown = my_application_shutdown; G_OBJECT_CLASS(klass)->dispose = my_application_dispose; } static void my_application_init(MyApplication* self) {} MyApplication* my_application_new() { + // Set the program name to the application ID, which helps various systems + // like GTK and desktop environments map this running application to its + // corresponding .desktop file. This ensures better integration by allowing + // the application to be recognized beyond its binary name. + g_set_prgname(APPLICATION_ID); + return MY_APPLICATION(g_object_new(my_application_get_type(), "application-id", APPLICATION_ID, + "flags", G_APPLICATION_NON_UNIQUE, nullptr)); } diff --git a/flutter/lib/src/native/c/sentry_native.dart b/flutter/lib/src/native/c/sentry_native.dart index 07f7edea05..22b2de3fe0 100644 --- a/flutter/lib/src/native/c/sentry_native.dart +++ b/flutter/lib/src/native/c/sentry_native.dart @@ -5,6 +5,7 @@ import 'dart:typed_data'; import 'package:ffi/ffi.dart'; import 'package:meta/meta.dart'; +import 'package:path/path.dart' as path; import '../../../sentry_flutter.dart'; import '../native_app_start.dart'; @@ -28,10 +29,12 @@ class SentryNative with SentryNativeSafeInvoker implements SentryNativeBinding { /// - on Linux in /lib and /usr/lib /// - on Windows in the working directory and System32 @visibleForTesting - static String? dynamicLibraryDirectory; + static String dynamicLibraryDirectory = ''; @visibleForTesting - static String? crashpadPath; + static String? crashpadPath = Platform.isLinux + ? '${path.dirname(Platform.resolvedExecutable)}/bin/crashpad_handler' + : null; SentryNative(this.options); diff --git a/flutter/pubspec.yaml b/flutter/pubspec.yaml index 6d33508d5e..a5bad3997d 100644 --- a/flutter/pubspec.yaml +++ b/flutter/pubspec.yaml @@ -28,6 +28,7 @@ dependencies: meta: ^1.3.0 ffi: ^2.0.0 file: '>=6.1.4' + path: ^1.8.3 dev_dependencies: build_runner: ^2.4.2 diff --git a/flutter/sentry-native/sentry-native.cmake b/flutter/sentry-native/sentry-native.cmake index 258eeb6f8a..8113f51052 100644 --- a/flutter/sentry-native/sentry-native.cmake +++ b/flutter/sentry-native/sentry-native.cmake @@ -18,10 +18,12 @@ FetchContent_MakeAvailable(sentry-native) # List of absolute paths to libraries that should be bundled with the plugin. # This list could contain prebuilt libraries, or libraries created by an # external build triggered from this build file. -set(sentry_flutter_bundled_libraries $ PARENT_SCOPE) - +# On Linux, we don't need to explicitly add crashpad_handler - it's coppied to `bin/crashpad_handler` automatically. if(WIN32) - set(sentry_flutter_bundled_libraries ${sentry_flutter_bundled_libraries} $ PARENT_SCOPE) + set(sentry_flutter_bundled_libraries + $ + $ + PARENT_SCOPE) endif() # `*_plugin` is the name of the plugin library as expected by flutter. From 1674934b806e717598c2f97deacdd8c4f2349ce1 Mon Sep 17 00:00:00 2001 From: Ivan Dlugos Date: Wed, 16 Oct 2024 14:54:06 +0200 Subject: [PATCH 03/10] add linux to run.sh --- flutter/example/run.sh | 3 +++ 1 file changed, 3 insertions(+) diff --git a/flutter/example/run.sh b/flutter/example/run.sh index b329d61be9..11ceb4b764 100755 --- a/flutter/example/run.sh +++ b/flutter/example/run.sh @@ -38,6 +38,9 @@ elif [ "$1" == "macos" ]; then elif [ "$1" == "windows" ]; then flutter build windows --split-debug-info=$symbolsDir --obfuscate launchCmd='./build/windows/x64/runner/Release/sentry_flutter_example.exe' +elif [ "$1" == "linux" ]; then + flutter build linux --split-debug-info=$symbolsDir --obfuscate + launchCmd='./build/linux/x64/release/bundle/sentry_flutter_example' else if [ "$1" == "" ]; then echo -e "[\033[92mrun\033[0m] Pass the platform you'd like to run: android, ios, web" From 8fe0fbaaae0cf56b02b1266beee33ba28fb16f2f Mon Sep 17 00:00:00 2001 From: Ivan Dlugos Date: Thu, 21 Nov 2024 15:05:30 +0100 Subject: [PATCH 04/10] fix tests --- flutter/test/sentry_flutter_test.dart | 8 +++++--- flutter/test/sentry_native/sentry_native_test_ffi.dart | 9 ++++----- 2 files changed, 9 insertions(+), 8 deletions(-) diff --git a/flutter/test/sentry_flutter_test.dart b/flutter/test/sentry_flutter_test.dart index 233f4539bf..6c9daeb4c7 100644 --- a/flutter/test/sentry_flutter_test.dart +++ b/flutter/test/sentry_flutter_test.dart @@ -280,7 +280,9 @@ void main() { Transport transport = MockTransport(); final sentryFlutterOptions = defaultTestOptions(getPlatformChecker(platform: MockPlatform.linux())) - ..methodChannel = native.channel; + ..methodChannel = native.channel + // We need to disable native init because sentry.dll is not available here. + ..autoInitializeNativeSdk = false; await SentryFlutter.init( (options) async { @@ -299,7 +301,7 @@ void main() { ); testScopeObserver( - options: sentryFlutterOptions, expectedHasNativeScopeObserver: false); + options: sentryFlutterOptions, expectedHasNativeScopeObserver: true); testConfiguration( integrations: integrations, @@ -320,7 +322,7 @@ void main() { beforeIntegration: WidgetsFlutterBindingIntegration, afterIntegration: OnErrorIntegration); - expect(SentryFlutter.native, isNull); + expect(SentryFlutter.native, isNotNull); expect(Sentry.currentHub.profilerFactory, isNull); await Sentry.close(); diff --git a/flutter/test/sentry_native/sentry_native_test_ffi.dart b/flutter/test/sentry_native/sentry_native_test_ffi.dart index 04de4a225b..4ccd2e18d8 100644 --- a/flutter/test/sentry_native/sentry_native_test_ffi.dart +++ b/flutter/test/sentry_native/sentry_native_test_ffi.dart @@ -24,14 +24,14 @@ void main() { expectedDistFiles = platform.instance.isWindows ? ['sentry.dll', 'crashpad_handler.exe', 'crashpad_wer.dll'] - : ['libsentry.so', 'crashpad_handler']; + : ['libsentry.so', 'bin/crashpad_handler']; setUpAll(() async { Directory.current = await _buildSentryNative('$repoRootDir/temp/native-test'); SentryNative.dynamicLibraryDirectory = '${Directory.current.path}/'; SentryNative.crashpadPath = - '${Directory.current.path}/${expectedDistFiles.firstWhere((f) => f.startsWith('crashpad_handler'))}'; + '${Directory.current.path}/${expectedDistFiles.firstWhere((f) => f.contains('crashpad_handler'))}'; }); late SentryNative sut; @@ -270,6 +270,7 @@ target_link_libraries(\${CMAKE_PROJECT_NAME} PRIVATE sentry_flutter_plugin) list(APPEND PLUGIN_BUNDLED_LIBRARIES \$) list(APPEND PLUGIN_BUNDLED_LIBRARIES \${sentry_flutter_bundled_libraries}) install(FILES "\${PLUGIN_BUNDLED_LIBRARIES}" DESTINATION "${buildOutputDir.replaceAll('\\', '/')}" COMPONENT Runtime) +set(CMAKE_INSTALL_PREFIX "${buildOutputDir.replaceAll('\\', '/')}") '''); await _exec('cmake', ['-B', cmakeBuildDir, cmakeConfDir]); await _exec('cmake', @@ -279,11 +280,9 @@ install(FILES "\${PLUGIN_BUNDLED_LIBRARIES}" DESTINATION "${buildOutputDir.repla cmakeBuildDir, '--config', 'Release', - '--component', - 'Runtime' ]); if (platform.instance.isLinux) { - await _exec('chmod', ['+x', '$buildOutputDir/crashpad_handler']); + await _exec('chmod', ['+x', '$buildOutputDir/bin/crashpad_handler']); } } return buildOutputDir; From f69794be5a47c0d2f0dc4da3703140b1f9c1240a Mon Sep 17 00:00:00 2001 From: Ivan Dlugos Date: Thu, 21 Nov 2024 15:26:43 +0100 Subject: [PATCH 05/10] minor changes & changelog --- CHANGELOG.md | 1 + flutter/test/sentry_flutter_test.dart | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 324efbc49a..a31620a0b0 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,7 @@ ### Features - Windows native error & obfuscation support ([#2286](https://github.com/getsentry/sentry-dart/pull/2286), [#2426](https://github.com/getsentry/sentry-dart/pull/2426)) +- Linux native error & obfuscation support ([#2431](https://github.com/getsentry/sentry-dart/pull/2431)) - Improve app start measurements by using `addTimingsCallback` instead of `addPostFrameCallback` to determine app start end ([#2405](https://github.com/getsentry/sentry-dart/pull/2405)) - ⚠️ This change may result in reporting of shorter app start durations - Improve frame tracking accuracy ([#2372](https://github.com/getsentry/sentry-dart/pull/2372)) diff --git a/flutter/test/sentry_flutter_test.dart b/flutter/test/sentry_flutter_test.dart index 6c9daeb4c7..40de7407d1 100644 --- a/flutter/test/sentry_flutter_test.dart +++ b/flutter/test/sentry_flutter_test.dart @@ -281,7 +281,7 @@ void main() { final sentryFlutterOptions = defaultTestOptions(getPlatformChecker(platform: MockPlatform.linux())) ..methodChannel = native.channel - // We need to disable native init because sentry.dll is not available here. + // We need to disable native init because libsentry.so is not available here. ..autoInitializeNativeSdk = false; await SentryFlutter.init( From 91650b5d022470e9e4d90c34d1e9a0101ea70e85 Mon Sep 17 00:00:00 2001 From: Ivan Dlugos Date: Thu, 21 Nov 2024 16:02:06 +0100 Subject: [PATCH 06/10] update build deps --- .github/workflows/flutter.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/flutter.yml b/.github/workflows/flutter.yml index b83f616683..2f46d6bc36 100644 --- a/.github/workflows/flutter.yml +++ b/.github/workflows/flutter.yml @@ -67,7 +67,7 @@ jobs: - name: 'Setup Linux' run: | sudo apt update - sudo apt install -y cmake dbus libblkid-dev libgtk-3-dev liblzma-dev ninja-build pkg-config xvfb + sudo apt install -y cmake dbus libblkid-dev libgtk-3-dev liblzma-dev ninja-build pkg-config xvfb libcurl4-openssl-dev sudo apt install -y network-manager upower if: matrix.target == 'linux' From b25bb77ca2a786ac69f1fe45ad84bce923891e1d Mon Sep 17 00:00:00 2001 From: Ivan Dlugos Date: Thu, 21 Nov 2024 19:07:34 +0100 Subject: [PATCH 07/10] tmp --- .github/workflows/flutter.yml | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/.github/workflows/flutter.yml b/.github/workflows/flutter.yml index 2f46d6bc36..69b48dcafc 100644 --- a/.github/workflows/flutter.yml +++ b/.github/workflows/flutter.yml @@ -143,6 +143,13 @@ jobs: ;; esac + - name: Upload temp artifact + uses: actions/upload-artifact@v4 + if: always() + with: + name: native-test-temp + path: flutter/temp + analyze: uses: ./.github/workflows/analyze.yml with: From 9495f3961ca3b5d2a7629f9094659a2cbf8ca4ba Mon Sep 17 00:00:00 2001 From: Ivan Dlugos Date: Thu, 21 Nov 2024 20:35:09 +0100 Subject: [PATCH 08/10] change expected path to the crashpad handler --- .github/workflows/flutter.yml | 7 ------- flutter/lib/src/native/c/sentry_native.dart | 4 +--- flutter/sentry-native/sentry-native.cmake | 8 +++++--- flutter/test/sentry_native/sentry_native_test_ffi.dart | 4 ++-- 4 files changed, 8 insertions(+), 15 deletions(-) diff --git a/.github/workflows/flutter.yml b/.github/workflows/flutter.yml index 69b48dcafc..2f46d6bc36 100644 --- a/.github/workflows/flutter.yml +++ b/.github/workflows/flutter.yml @@ -143,13 +143,6 @@ jobs: ;; esac - - name: Upload temp artifact - uses: actions/upload-artifact@v4 - if: always() - with: - name: native-test-temp - path: flutter/temp - analyze: uses: ./.github/workflows/analyze.yml with: diff --git a/flutter/lib/src/native/c/sentry_native.dart b/flutter/lib/src/native/c/sentry_native.dart index 22b2de3fe0..04cf83afca 100644 --- a/flutter/lib/src/native/c/sentry_native.dart +++ b/flutter/lib/src/native/c/sentry_native.dart @@ -32,9 +32,7 @@ class SentryNative with SentryNativeSafeInvoker implements SentryNativeBinding { static String dynamicLibraryDirectory = ''; @visibleForTesting - static String? crashpadPath = Platform.isLinux - ? '${path.dirname(Platform.resolvedExecutable)}/bin/crashpad_handler' - : null; + static String? crashpadPath; SentryNative(this.options); diff --git a/flutter/sentry-native/sentry-native.cmake b/flutter/sentry-native/sentry-native.cmake index 8113f51052..8e16cb9900 100644 --- a/flutter/sentry-native/sentry-native.cmake +++ b/flutter/sentry-native/sentry-native.cmake @@ -16,14 +16,16 @@ FetchContent_Declare( FetchContent_MakeAvailable(sentry-native) # List of absolute paths to libraries that should be bundled with the plugin. -# This list could contain prebuilt libraries, or libraries created by an -# external build triggered from this build file. -# On Linux, we don't need to explicitly add crashpad_handler - it's coppied to `bin/crashpad_handler` automatically. +# This list could contain prebuilt libraries, or libraries created by an external build triggered from this build file. if(WIN32) set(sentry_flutter_bundled_libraries $ $ PARENT_SCOPE) +else() + set(sentry_flutter_bundled_libraries + $ + PARENT_SCOPE) endif() # `*_plugin` is the name of the plugin library as expected by flutter. diff --git a/flutter/test/sentry_native/sentry_native_test_ffi.dart b/flutter/test/sentry_native/sentry_native_test_ffi.dart index 4ccd2e18d8..9a57e07325 100644 --- a/flutter/test/sentry_native/sentry_native_test_ffi.dart +++ b/flutter/test/sentry_native/sentry_native_test_ffi.dart @@ -24,7 +24,7 @@ void main() { expectedDistFiles = platform.instance.isWindows ? ['sentry.dll', 'crashpad_handler.exe', 'crashpad_wer.dll'] - : ['libsentry.so', 'bin/crashpad_handler']; + : ['libsentry.so', 'crashpad_handler']; setUpAll(() async { Directory.current = @@ -282,7 +282,7 @@ set(CMAKE_INSTALL_PREFIX "${buildOutputDir.replaceAll('\\', '/')}") 'Release', ]); if (platform.instance.isLinux) { - await _exec('chmod', ['+x', '$buildOutputDir/bin/crashpad_handler']); + await _exec('chmod', ['+x', '$buildOutputDir/crashpad_handler']); } } return buildOutputDir; From 7f3abd11cec0935e6256e1eb3e362bd5d3c9b155 Mon Sep 17 00:00:00 2001 From: Ivan Dlugos Date: Thu, 21 Nov 2024 21:07:58 +0100 Subject: [PATCH 09/10] cleanup --- flutter/lib/src/native/c/sentry_native.dart | 1 - flutter/pubspec.yaml | 1 - 2 files changed, 2 deletions(-) diff --git a/flutter/lib/src/native/c/sentry_native.dart b/flutter/lib/src/native/c/sentry_native.dart index 04cf83afca..9e2b8d51f6 100644 --- a/flutter/lib/src/native/c/sentry_native.dart +++ b/flutter/lib/src/native/c/sentry_native.dart @@ -5,7 +5,6 @@ import 'dart:typed_data'; import 'package:ffi/ffi.dart'; import 'package:meta/meta.dart'; -import 'package:path/path.dart' as path; import '../../../sentry_flutter.dart'; import '../native_app_start.dart'; diff --git a/flutter/pubspec.yaml b/flutter/pubspec.yaml index a5bad3997d..6d33508d5e 100644 --- a/flutter/pubspec.yaml +++ b/flutter/pubspec.yaml @@ -28,7 +28,6 @@ dependencies: meta: ^1.3.0 ffi: ^2.0.0 file: '>=6.1.4' - path: ^1.8.3 dev_dependencies: build_runner: ^2.4.2 From 73f91e9b7d70d4f4904d6aafc5c53f8ff094c317 Mon Sep 17 00:00:00 2001 From: Ivan Dlugos <6349682+vaind@users.noreply.github.com> Date: Fri, 22 Nov 2024 09:41:31 +0100 Subject: [PATCH 10/10] Update CHANGELOG.md --- CHANGELOG.md | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 5cddfec11b..1fb1adf24e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,11 +1,16 @@ # Changelog +## Unreleased + +### Features + +- Linux native error & obfuscation support ([#2431](https://github.com/getsentry/sentry-dart/pull/2431)) + ## 8.11.0-beta.1 ### Features - Windows native error & obfuscation support ([#2286](https://github.com/getsentry/sentry-dart/pull/2286), [#2426](https://github.com/getsentry/sentry-dart/pull/2426)) -- Linux native error & obfuscation support ([#2431](https://github.com/getsentry/sentry-dart/pull/2431)) - Improve app start measurements by using `addTimingsCallback` instead of `addPostFrameCallback` to determine app start end ([#2405](https://github.com/getsentry/sentry-dart/pull/2405)) - ⚠️ This change may result in reporting of shorter app start durations - Improve frame tracking accuracy ([#2372](https://github.com/getsentry/sentry-dart/pull/2372))