Repository: conan-io/conan-center-index

Issue:
[question] Use only one recipe for sentry-native/crashpad/breakpad
### What is your question?

After talking to the sentry-native developer [here](https://github.com/getsentry/sentry-native/pull/872#issuecomment-1693542784) he advised me that we should have only one recipe instead of three:
- sentry-native
- sentry-crashpad
- sentry-breakpad

I wondered what was the thought of the community and why the recipe had been splited originally.

I ping @madebr who originaly created the sentry-breakpad/crashpad recipe and @paulharris who recently pushed a fix the sentry-crashpad.




Discussion:

Resolving patch:
diff --git a/recipes/sentry-native/all/conanfile.py b/recipes/sentry-native/all/conanfile.py
--- a/recipes/sentry-native/all/conanfile.py
+++ b/recipes/sentry-native/all/conanfile.py
@@ -4,8 +4,7 @@
 from conan.tools.build import check_min_cppstd
 from conan.tools.cmake import CMake, CMakeDeps, CMakeToolchain, cmake_layout
 from conan.tools.env import VirtualBuildEnv
-from conan.tools.files import copy, get, rm, rmdir
-from conan.tools.gnu import PkgConfigDeps
+from conan.tools.files import apply_conandata_patches, copy, export_conandata_patches, get, rm, rmdir
 from conan.tools.microsoft import is_msvc
 from conan.tools.scm import Version
 import os
@@ -34,6 +33,7 @@ class SentryNativeConan(ConanFile):
         "transport": ["none", "curl", "winhttp"],
         "qt": [True, False],
         "with_crashpad": ["google", "sentry"],
+        "crashpad_with_tls": ["openssl", False],
         "with_breakpad": ["google", "sentry"],
         "wer" : [True, False],
     }
@@ -44,6 +44,7 @@ class SentryNativeConan(ConanFile):
         "transport": "curl",  # overwritten in config_options
         "qt": False,
         "with_crashpad": "sentry",
+        "crashpad_with_tls": "openssl",
         "with_breakpad": "sentry",
         "wer": False
     }
@@ -52,18 +53,26 @@ class SentryNativeConan(ConanFile):
     def _min_cppstd(self):
         if is_msvc(self):
             return "17"
+        if self.options.get_safe("backend") == "breakpad" and Version(self.version) >= "0.5.4":
+            return 17
         return "14"
 
     @property
     def _minimum_compilers_version(self):
+        minimum_gcc_version = "5"
+        if self.options.get_safe("backend") == "breakpad":
+            minimum_gcc_version = "7"
         return {
             "Visual Studio": "15",
             "msvc": "191",
-            "gcc": "5",
+            "gcc": minimum_gcc_version,
             "clang": "3.4",
             "apple-clang": "5.1",
         }
 
+    def export_sources(self):
+        export_conandata_patches(self)
+
     def config_options(self):
         if self.settings.os == "Windows":
             del self.options.fPIC
@@ -89,6 +98,8 @@ def config_options(self):
             self.options.backend = "inproc"
         else:
             self.options.backend = "inproc"
+        if self.settings.os not in ("Linux", "Android") or self.options.backend != "crashpad" or self.options.with_crashpad != "sentry":
+            del self.options.crashpad_with_tls
 
     def configure(self):
         if self.options.shared:
@@ -105,13 +116,15 @@ def requirements(self):
         if self.options.transport == "curl":
             self.requires("libcurl/[>=7.78.0 <9]")
         if self.options.backend == "crashpad":
-            if self.options.with_crashpad == "sentry":
-                self.requires(f"sentry-crashpad/{self.version}")
             if self.options.with_crashpad == "google":
                 self.requires("crashpad/cci.20220219")
+            else:
+                self.requires("zlib/[>=1.2.11 <2]")
+                if self.settings.os in ("Linux", "FreeBSD"):
+                    self.requires("libcurl/[>=7.78.0 <9]")
+                if self.options.get_safe("crashpad_with_tls"):
+                    self.requires("openssl/[>=1.1 <4]")
         elif self.options.backend == "breakpad":
-            if self.options.with_breakpad == "sentry":
-                self.requires(f"sentry-breakpad/{self.version}")
             if self.options.with_breakpad == "google":
                 self.requires("breakpad/cci.20210521")
         if self.options.get_safe("qt"):
@@ -135,9 +148,6 @@ def validate(self):
     def build_requirements(self):
         if self.settings.os == "Windows":
             self.tool_requires("cmake/[>=3.16.4 <4]")
-        if self.options.backend == "breakpad":
-            if not self.conf.get("tools.gnu:pkg_config", check_type=str):
-                self.tool_requires("pkgconf/2.0.3")
 
     def source(self):
         get(self, **self.conan_data["sources"][self.version])
@@ -146,8 +156,10 @@ def generate(self):
         VirtualBuildEnv(self).generate()
         tc = CMakeToolchain(self)
         tc.variables["SENTRY_BACKEND"] = self.options.backend
-        tc.variables["SENTRY_CRASHPAD_SYSTEM"] = True
-        tc.variables["SENTRY_BREAKPAD_SYSTEM"] = True
+        if self.options.backend == "crashpad":
+            tc.variables["SENTRY_CRASHPAD_SYSTEM"] = self.options.with_crashpad == "google"
+        if self.options.backend == "breakpad":
+            tc.variables["SENTRY_BREAKPAD_SYSTEM"] = self.options.with_breakpad == "google"
         tc.variables["SENTRY_ENABLE_INSTALL"] = True
         tc.variables["SENTRY_TRANSPORT"] = self.options.transport
         tc.variables["SENTRY_PIC"] = self.options.get_safe("fPIC", True)
@@ -158,10 +170,9 @@ def generate(self):
             tc.variables["CRASHPAD_WER_ENABLED"] = True
         tc.generate()
         CMakeDeps(self).generate()
-        if self.options.backend == "breakpad":
-            PkgConfigDeps(self).generate()
 
     def build(self):
+        apply_conandata_patches(self)
         cmake = CMake(self)
         cmake.configure()
         cmake.build()
@@ -175,24 +186,148 @@ def package(self):
 
     def package_info(self):
         self.cpp_info.set_property("cmake_file_name", "sentry")
-        self.cpp_info.set_property("cmake_target_name", "sentry::sentry")
-        self.cpp_info.libs = ["sentry"]
+
+        self.cpp_info.components["sentry"].set_property("cmake_target_name", "sentry::sentry")
+        self.cpp_info.components["sentry"].libs = ["sentry"]
+
         if self.settings.os in ("Android", "FreeBSD", "Linux"):
-            self.cpp_info.exelinkflags = ["-Wl,-E,--build-id=sha1"]
-            self.cpp_info.sharedlinkflags = ["-Wl,-E,--build-id=sha1"]
+            self.cpp_info.components["sentry"].exelinkflags = ["-Wl,-E,--build-id=sha1"]
+            self.cpp_info.components["sentry"].sharedlinkflags = ["-Wl,-E,--build-id=sha1"]
         if self.settings.os in ("FreeBSD", "Linux"):
-            self.cpp_info.system_libs = ["pthread", "dl"]
+            self.cpp_info.components["sentry"].system_libs = ["pthread", "dl"]
         elif is_apple_os(self):
-            self.cpp_info.frameworks = ["CoreGraphics", "CoreText"]
+            self.cpp_info.components["sentry"].frameworks = ["CoreGraphics", "CoreText"]
         elif self.settings.os == "Android":
-            self.cpp_info.system_libs = ["dl", "log"]
+            self.cpp_info.components["sentry"].system_libs = ["dl", "log"]
         elif self.settings.os == "Windows":
-            self.cpp_info.system_libs = ["shlwapi", "dbghelp", "version"]
+            self.cpp_info.components["sentry"].system_libs = ["shlwapi", "dbghelp", "version"]
             if self.options.transport == "winhttp":
-                self.cpp_info.system_libs.append("winhttp")
+                self.cpp_info.components["sentry"].system_libs.append("winhttp")
+        if self.options.transport == "curl":
+            self.cpp_info.components["sentry"].requires.extend(["libcurl::libcurl"])
+        if self.options.get_safe("qt"):
+            self.cpp_info.components["sentry"].requires.extend(["qt::qt", "openssl::openssl"])
 
         if not self.options.shared:
-            self.cpp_info.defines = ["SENTRY_BUILD_STATIC"]
+            self.cpp_info.components["sentry"].defines = ["SENTRY_BUILD_STATIC"]
+
+        if self.options.backend == "breakpad" and self.options.with_breakpad == "sentry":
+            self.cpp_info.components["breakpad"].set_property("cmake_target_name", "breakpad_client")
+            self.cpp_info.components["breakpad"].libs = [] if self.options.shared else ["breakpad_client"]
+            if is_apple_os(self):
+                self.cpp_info.components["breakpad"].frameworks.append("CoreFoundation")
+            if self.settings.os in ["Linux", "FreeBSD"]:
+                self.cpp_info.components["breakpad"].system_libs.append("pthread")
+
+            self.cpp_info.components["sentry"].requires.append("breakpad")
+
+        if self.options.backend == "crashpad" and self.options.with_crashpad == "sentry":
+            # mini_chromium
+            self.cpp_info.components["crashpad_mini_chromium"].set_property("cmake_target_name", "crashpad::mini_chromium")
+            self.cpp_info.components["crashpad_mini_chromium"].libs = [] if self.options.shared else ["mini_chromium"]
+            if self.settings.os in ("Linux", "FreeBSD"):
+                self.cpp_info.components["crashpad_mini_chromium"].system_libs.append("pthread")
+            elif is_apple_os(self):
+                self.cpp_info.components["crashpad_mini_chromium"].frameworks = ["CoreFoundation", "Foundation", "Security"]
+                if self.settings.os == "Macos":
+                    self.cpp_info.components["crashpad_mini_chromium"].frameworks.extend(["ApplicationServices", "IOKit"])
+                else:  # iOS
+                    self.cpp_info.components["crashpad_mini_chromium"].frameworks.extend(["CoreGraphics", "CoreText"])
+
+            # compat
+            self.cpp_info.components["crashpad_compat"].set_property("cmake_target_name", "crashpad::compat")
+            # On Apple crashpad_compat is an interface library
+            if not is_apple_os(self):
+                self.cpp_info.components["crashpad_compat"].libs = [] if self.options.shared else ["crashpad_compat"]
+            if self.settings.os in ("Linux", "FreeBSD"):
+                self.cpp_info.components["crashpad_compat"].system_libs.append("dl")
+
+            # util
+            self.cpp_info.components["crashpad_util"].set_property("cmake_target_name", "crashpad::util")
+            self.cpp_info.components["crashpad_util"].libs = [] if self.options.shared else ["crashpad_util"]
+            self.cpp_info.components["crashpad_util"].requires = ["crashpad_compat", "crashpad_mini_chromium", "zlib::zlib"]
+            if self.settings.os in ("Linux", "FreeBSD"):
+                self.cpp_info.components["crashpad_util"].system_libs.extend(["pthread", "rt"])
+                # Requires libcurl https://github.com/getsentry/crashpad/blob/2237d97ee2c38c930c07001e660be57324f69a37/util/CMakeLists.txt#L256
+                self.cpp_info.components["crashpad_util"].requires.extend(["libcurl::libcurl"])
+            elif self.settings.os == "Windows":
+                self.cpp_info.components["crashpad_util"].system_libs.append("winhttp")
+            elif self.settings.os == "Macos":
+                self.cpp_info.components["crashpad_util"].frameworks.extend(["CoreFoundation", "Foundation", "IOKit"])
+                self.cpp_info.components["crashpad_util"].system_libs.append("bsm")
+            if self.options.get_safe("crashpad_with_tls") == "openssl":
+                self.cpp_info.components["crashpad_util"].requires.append("openssl::openssl")
+
+            # client
+            self.cpp_info.components["crashpad_client"].set_property("cmake_target_name", "crashpad::client")
+            self.cpp_info.components["crashpad_client"].libs = [] if self.options.shared else ["crashpad_client"]
+            self.cpp_info.components["crashpad_client"].requires = ["crashpad_util", "crashpad_mini_chromium"]
+
+            self.cpp_info.components["sentry"].requires.append("crashpad_client")
+
+            # snapshot
+            self.cpp_info.components["crashpad_snapshot"].set_property("cmake_target_name", "crashpad::snapshot")
+            self.cpp_info.components["crashpad_snapshot"].libs = [] if self.options.shared else ["crashpad_snapshot"]
+            self.cpp_info.components["crashpad_snapshot"].requires = [
+                "crashpad_client", "crashpad_compat",
+                "crashpad_util", "crashpad_mini_chromium",
+            ]
+            if self.settings.os == "Windows":
+                self.cpp_info.components["snapshot"].system_libs.append("powrprof")
+
+            # minidump
+            self.cpp_info.components["crashpad_minidump"].set_property("cmake_target_name", "crashpad::minidump")
+            self.cpp_info.components["crashpad_minidump"].libs = [] if self.options.shared else ["crashpad_minidump"]
+            self.cpp_info.components["crashpad_minidump"].requires = [
+                "crashpad_compat", "crashpad_snapshot",
+                "crashpad_util", "crashpad_mini_chromium",
+            ]
+
+            if self.settings.os == "Windows":
+                # getopt
+                self.cpp_info.components["crashpad_getopt"].set_property("cmake_target_name", "crashpad::getopt")
+                self.cpp_info.components["crashpad_getopt"].libs = [] if self.options.shared else ["crashpad_getopt"]
+
+            # handler
+            self.cpp_info.components["crashpad_handler"].set_property("cmake_target_name", "crashpad::handler")
+            self.cpp_info.components["crashpad_handler"].libs = [] if self.options.shared else ["crashpad_handler_lib"]
+            self.cpp_info.components["crashpad_handler"].requires = [
+                "crashpad_compat", "crashpad_minidump", "crashpad_snapshot",
+                "crashpad_util", "crashpad_mini_chromium",
+            ]
+            if self.settings.os == "Windows":
+                self.cpp_info.components["crashpad_handler"].requires.append("crashpad_getopt")
+
+            # tools
+            self.cpp_info.components["crashpad_tools"].set_property("cmake_target_name", "crashpad::tools")
+            self.cpp_info.components["crashpad_tools"].libs = [] if self.options.shared else ["crashpad_tools"]
+
+            bin_path = os.path.join(self.package_folder, "bin")
+            self.output.info(f"Appending PATH environment variable: {bin_path}")
+            self.env_info.PATH.append(bin_path)
+
+            # TODO: to remove in conan v2 once cmake_find_package* generators removed
+            self.cpp_info.names["cmake_find_package"] = "crashpad"
+            self.cpp_info.names["cmake_find_package_multi"] = "crashpad"
+            self.cpp_info.components["crashpad_mini_chromium"].names["cmake_find_package"] = "mini_chromium"
+            self.cpp_info.components["crashpad_mini_chromium"].names["cmake_find_package_multi"] = "mini_chromium"
+            self.cpp_info.components["crashpad_compat"].names["cmake_find_package"] = "compat"
+            self.cpp_info.components["crashpad_compat"].names["cmake_find_package_multi"] = "compat"
+            self.cpp_info.components["crashpad_util"].names["cmake_find_package"] = "util"
+            self.cpp_info.components["crashpad_util"].names["cmake_find_package_multi"] = "util"
+            self.cpp_info.components["crashpad_client"].names["cmake_find_package"] = "client"
+            self.cpp_info.components["crashpad_client"].names["cmake_find_package_multi"] = "client"
+            self.cpp_info.components["crashpad_snapshot"].names["cmake_find_package"] = "snapshot"
+            self.cpp_info.components["crashpad_snapshot"].names["cmake_find_package_multi"] = "snapshot"
+            self.cpp_info.components["crashpad_minidump"].names["cmake_find_package"] = "minidump"
+            self.cpp_info.components["crashpad_minidump"].names["cmake_find_package_multi"] = "minidump"
+            if self.settings.os == "Windows":
+                self.cpp_info.components["crashpad_getopt"].names["cmake_find_package"] = "getopt"
+                self.cpp_info.components["crashpad_getopt"].names["cmake_find_package_multi"] = "getopt"
+            self.cpp_info.components["crashpad_handler"].names["cmake_find_package"] = "handler"
+            self.cpp_info.components["crashpad_handler"].names["cmake_find_package_multi"] = "handler"
+            self.cpp_info.components["crashpad_tools"].names["cmake_find_package"] = "tools"
+            self.cpp_info.components["crashpad_tools"].names["cmake_find_package_multi"] = "tools"
 
         # TODO: to remove in conan v2 once cmake_find_package* generators removed
         self.cpp_info.names["cmake_find_package"] = "sentry"


Test patch:
diff --git a/recipes/sentry-native/all/test_package/conanfile.py b/recipes/sentry-native/all/test_package/conanfile.py
--- a/recipes/sentry-native/all/test_package/conanfile.py
+++ b/recipes/sentry-native/all/test_package/conanfile.py
@@ -1,12 +1,13 @@
 from conan import ConanFile
 from conan.tools.build import can_run
-from conan.tools.cmake import CMake, cmake_layout
+from conan.tools.files import mkdir, save, load
+from conan.tools.cmake import cmake_layout, CMake, CMakeToolchain
 import os
 
 
 class TestPackageConan(ConanFile):
     settings = "os", "arch", "compiler", "build_type"
-    generators = "CMakeToolchain", "CMakeDeps", "VirtualRunEnv"
+    generators = "CMakeDeps", "VirtualRunEnv"
     test_type = "explicit"
 
     def layout(self):
@@ -15,6 +16,13 @@ def layout(self):
     def requirements(self):
         self.requires(self.tested_reference_str)
 
+    def generate(self):
+        tc = CMakeToolchain(self)
+        tc.generate()
+        handler_exe = "crashpad_handler.exe" if self.settings.os == "Windows" else "crashpad_handler"
+        handler_bin_path = os.path.join(self.dependencies[self.tested_reference_str].package_folder, "bin", handler_exe)
+        save(self, os.path.join(self.build_folder, "handler_bin_path"), handler_bin_path)
+
     def build(self):
         cmake = CMake(self)
         cmake.configure()
@@ -22,5 +30,8 @@ def build(self):
 
     def test(self):
         if can_run(self):
+            test_env_dir = "test_env"
+            mkdir(self, test_env_dir)
             bin_path = os.path.join(self.cpp.build.bindirs[0], "test_package")
-            self.run(bin_path, env="conanrun")
+            handler_bin_path = load(self, os.path.join(self.build_folder, "handler_bin_path"))
+            self.run(f"{bin_path} {test_env_dir} {handler_bin_path}", env="conanrun")
diff --git a/recipes/sentry-native/all/test_v1_package/CMakeLists.txt b/recipes/sentry-native/all/test_v1_package/CMakeLists.txt
deleted file mode 100644
--- a/recipes/sentry-native/all/test_v1_package/CMakeLists.txt
+++ /dev/null
@@ -1,8 +0,0 @@
-cmake_minimum_required(VERSION 3.1)
-project(test_package)
-
-include(${CMAKE_BINARY_DIR}/conanbuildinfo.cmake)
-conan_basic_setup(TARGETS)
-
-add_subdirectory(${CMAKE_CURRENT_SOURCE_DIR}/../test_package
-                 ${CMAKE_CURRENT_BINARY_DIR}/test_package)
diff --git a/recipes/sentry-native/all/test_v1_package/conanfile.py b/recipes/sentry-native/all/test_v1_package/conanfile.py
deleted file mode 100644
--- a/recipes/sentry-native/all/test_v1_package/conanfile.py
+++ /dev/null
@@ -1,17 +0,0 @@
-from conans import ConanFile, CMake, tools
-import os
-
-
-class TestPackageConan(ConanFile):
-    settings = "os", "arch", "compiler", "build_type"
-    generators = "cmake", "cmake_find_package_multi"
-
-    def build(self):
-        cmake = CMake(self)
-        cmake.configure()
-        cmake.build()
-
-    def test(self):
-        if not tools.cross_building(self):
-            bin_path = os.path.join("bin", "test_package")
-            self.run(bin_path, run_environment=True)