from conans import ConanFile, CMake, tools
from conans.errors import ConanInvalidConfiguration
import os


class BackwardCppConan(ConanFile):
    name = "backward-cpp"
    description = "A beautiful stack trace pretty printer for C++"
    homepage = "https://github.com/bombela/backward-cpp"
    url = "https://github.com/conan-io/conan-center-index"
    topics = ("conan", "backward-cpp", "stack-trace")
    license = "MIT"
    exports_sources = [ "CMakeLists.txt", "patches/backward-cpp-*.patch" ]
    generators = "cmake"

    settings = "os", "arch", "compiler", "build_type"
    options = {
       "stack_walking" : ["unwind", "backtrace"],
       "stack_details" : ["dw", "bfd", "dwarf", "backtrace_symbol"],
       "shared": [True, False],
       "fPIC": [True, False]
    }
    default_options = {
       "stack_walking": "unwind",
       "stack_details": "dwarf",
       "shared": True,
       "fPIC": True
    }

    _source_subfolder = "source_subfolder"
    _build_subfolder = "build_subfolder"

    def _has_stack_walking(self, type):
        return self.options.stack_walking == type

    def _has_stack_details(self, type):
        return self.options.stack_details == type
    
    def configure(self):
        if self.settings.os not in ["Linux", "Macos", "Android"]:
            raise ConanInvalidConfiguration("upstream backward-cpp v{0} is not \
                supported in {1}.".format(self.version, self.settings.os))
        # windows implementation only available in upstream master branch

        if self.settings.os == "Macos" and \
           not self._has_stack_details("backtrace_symbol"):
            raise ConanInvalidConfiguration("only stack_details=backtrace_symbol"
                                            " is supported on Macos")
        
    def requirements(self):
        if self.settings.os in ["Linux", "Android"] and \
           self._has_stack_details("dwarf"):
            self.requires("libdwarf/20191104")
    
    def system_requirements(self):
        required_package = None
        if self.settings.os == "Linux":
            if self._has_stack_details("dw"):
                if tools.os_info.linux_distro in ["ubuntu", "debian"]:
                    required_package = "libdw-dev"
                elif tools.os_info.linux_distro in ["fedora", "centos"]:
                    required_package = "elfutils-libs"
                elif tools.os_info.linux_distro == "opensuse":
                    required_package = "libdw-devel"
                elif tools.os_info.linux_distro == "arch":
                    required_package = "libelf"

            if self._has_stack_details("bfd"):
                if tools.os_info.linux_distro in ["ubuntu", "debian"]:
                    required_package = "binutils-dev"
                elif tools.os_info.linux_distro in ["fedora", "centos", "opensuse"]:
                    required_package = "binutils-devel"
                elif tools.os_info.linux_distro == "arch":
                    required_package = "binutils"
                elif tools.os_info.is_freebsd:
                    required_package = "libbfd"
        
        if required_package != None:
            installer = tools.SystemPackageTool()
            if not installer.installed(required_package):
                raise ConanInvalidConfiguration("backward-cpp requires {}.".format(required_package))

    def source(self):
        tools.get(**self.conan_data["sources"][self.version])
        extracted_dir = self.name + "-" + self.version
        os.rename(extracted_dir, self._source_subfolder)

    def _configure_cmake(self):
        cmake = CMake(self)
        cmake.definitions['STACK_WALKING_UNWIND'] = self._has_stack_walking("unwind")
        cmake.definitions['STACK_WALKING_BACKTRACE'] = self._has_stack_walking("backtrace")
        cmake.definitions['STACK_DETAILS_AUTO_DETECT'] = False
        cmake.definitions['STACK_DETAILS_BACKTRACE_SYMBOL'] = self._has_stack_details("backtrace_symbol")
        cmake.definitions['STACK_DETAILS_DW'] = self._has_stack_details("dw")
        cmake.definitions['STACK_DETAILS_BFD'] = self._has_stack_details("bfd")
        cmake.definitions['STACK_DETAILS_DWARF'] = self._has_stack_details("dwarf")
        cmake.definitions['BACKWARD_SHARED'] = self.options.shared
        cmake.configure(build_folder=self._build_subfolder)
        return cmake

    def build(self):
        for patch in self.conan_data["patches"][self.version]:
            tools.patch(**patch)
        cmake = self._configure_cmake()
        cmake.build()

    def package(self):
        cmake = self._configure_cmake()
        cmake.install()
        self.copy(pattern="LICENSE*", dst="licenses", src=self._source_subfolder)
        os.remove(os.path.join(self.package_folder, "lib", "backward", "BackwardConfig.cmake"))

    def package_info(self):
        self.cpp_info.names["cmake"] = "Backward"
        self.cpp_info.names["cmake_find_package"] = "Backward"
        self.cpp_info.names["cmake_find_package_multi"] = "Backward"

        self.cpp_info.defines.append('BACKWARD_HAS_UNWIND={}'.format(int(self._has_stack_walking("unwind"))))
        self.cpp_info.defines.append('BACKWARD_HAS_BACKTRACE={}'.format(int(self._has_stack_walking("backtrace"))))
        
        self.cpp_info.defines.append('BACKWARD_HAS_BACKTRACE_SYMBOL={}'.format(int(self._has_stack_details("backtrace_symbol"))))
        self.cpp_info.defines.append('BACKWARD_HAS_DW={}'.format(int(self._has_stack_details("dw"))))
        self.cpp_info.defines.append('BACKWARD_HAS_BFD={}'.format(int(self._has_stack_details("bfd"))))
        self.cpp_info.defines.append('BACKWARD_HAS_DWARF={}'.format(int(self._has_stack_details("dwarf"))))

        self.cpp_info.libs = tools.collect_libs(self)
        if self.settings.os == "Linux":
            self.cpp_info.system_libs.extend(["dl"])
            if self._has_stack_details("dw"):
                self.cpp_info.system_libs.extend(["dw"])           
            if self._has_stack_details("bfd"):
                self.cpp_info.system_libs.extend(["bfd"])


        

recipes/backward-cpp/all/conanfile.py
from conans import ConanFile, CMake, tools
from conans.errors import ConanInvalidConfiguration
import os


class BackwardCppConan(ConanFile):
    name = "backward-cpp"
    description = "A beautiful stack trace pretty printer for C++"
    homepage = "https://github.com/bombela/backward-cpp"
    url = "https://github.com/conan-io/conan-center-index"
    topics = ("conan", "backward-cpp", "stack-trace")
    license = "MIT"
    exports_sources = [ "CMakeLists.txt", "patches/backward-cpp-*.patch" ]
    generators = "cmake"

    settings = "os", "arch", "compiler", "build_type"
    options = {
       "stack_walking" : ["unwind", "backtrace"],
       "stack_details" : ["dw", "bfd", "dwarf", "backtrace_symbol"],
       "shared": [True, False],
       "fPIC": [True, False]
    }
    default_options = {
       "stack_walking": "unwind",
       "stack_details": "dwarf",
       "shared": True,
       "fPIC": True
    }

    _source_subfolder = "source_subfolder"
    _build_subfolder = "build_subfolder"

    def _has_stack_walking(self, type):
        return self.options.stack_walking == type

    def _has_stack_details(self, type):
        return self.options.stack_details == type
    
    def configure(self):
        if self.settings.os not in ["Linux", "Macos", "Android"]:
            raise ConanInvalidConfiguration("upstream backward-cpp v{0} is not \
                supported in {1}.".format(self.version, self.settings.os))
        # windows implementation only available in upstream master branch

        if self.settings.os == "Macos" and \
           not self._has_stack_details("backtrace_symbol"):
            raise ConanInvalidConfiguration("only stack_details=backtrace_symbol"
                                            " is supported on Macos")
        
    def requirements(self):
        if self.settings.os in ["Linux", "Android"] and \
           self._has_stack_details("dwarf"):
            self.requires("libdwarf/20191104")
    
    def system_requirements(self):
        required_package = None
        if self.settings.os == "Linux":
            if self._has_stack_details("dw"):
                if tools.os_info.linux_distro in ["ubuntu", "debian"]:
                    required_package = "libdw-dev"
                elif tools.os_info.linux_distro in ["fedora", "centos"]:
                    required_package = "elfutils-libs"
                elif tools.os_info.linux_distro == "opensuse":
                    required_package = "libdw-devel"
                elif tools.os_info.linux_distro == "arch":
                    required_package = "libelf"

            if self._has_stack_details("bfd"):
                if tools.os_info.linux_distro in ["ubuntu", "debian"]:
                    required_package = "binutils-dev"
                elif tools.os_info.linux_distro in ["fedora", "centos", "opensuse"]:
                    required_package = "binutils-devel"
                elif tools.os_info.linux_distro == "arch":
                    required_package = "binutils"
                elif tools.os_info.is_freebsd:
                    required_package = "libbfd"
        
        if required_package != None:
            installer = tools.SystemPackageTool()
            if not installer.installed(required_package):
                raise ConanInvalidConfiguration("backward-cpp requires {}.".format(required_package))

    def source(self):
        tools.get(**self.conan_data["sources"][self.version])
        extracted_dir = self.name + "-" + self.version
        os.rename(extracted_dir, self._source_subfolder)

    def _configure_cmake(self):
        cmake = CMake(self)
        cmake.definitions['STACK_WALKING_UNWIND'] = self._has_stack_walking("unwind")
        cmake.definitions['STACK_WALKING_BACKTRACE'] = self._has_stack_walking("backtrace")
        cmake.definitions['STACK_DETAILS_AUTO_DETECT'] = False
        cmake.definitions['STACK_DETAILS_BACKTRACE_SYMBOL'] = self._has_stack_details("backtrace_symbol")
        cmake.definitions['STACK_DETAILS_DW'] = self._has_stack_details("dw")
        cmake.definitions['STACK_DETAILS_BFD'] = self._has_stack_details("bfd")
        cmake.definitions['STACK_DETAILS_DWARF'] = self._has_stack_details("dwarf")
        cmake.definitions['BACKWARD_SHARED'] = self.options.shared
        cmake.configure(build_folder=self._build_subfolder)
        return cmake

    def build(self):
        for patch in self.conan_data["patches"][self.version]:
            tools.patch(**patch)
        cmake = self._configure_cmake()
        cmake.build()

    def package(self):
        cmake = self._configure_cmake()
        cmake.install()
        self.copy(pattern="LICENSE*", dst="licenses", src=self._source_subfolder)
        os.remove(os.path.join(self.package_folder, "lib", "backward", "BackwardConfig.cmake"))

    def package_info(self):
        self.cpp_info.names["cmake_find_package"] = "Backward"
        self.cpp_info.names["cmake_find_package_multi"] = "Backward"

        self.cpp_info.defines.append('BACKWARD_HAS_UNWIND={}'.format(int(self._has_stack_walking("unwind"))))
        self.cpp_info.defines.append('BACKWARD_HAS_BACKTRACE={}'.format(int(self._has_stack_walking("backtrace"))))
        
        self.cpp_info.defines.append('BACKWARD_HAS_BACKTRACE_SYMBOL={}'.format(int(self._has_stack_details("backtrace_symbol"))))
        self.cpp_info.defines.append('BACKWARD_HAS_DW={}'.format(int(self._has_stack_details("dw"))))
        self.cpp_info.defines.append('BACKWARD_HAS_BFD={}'.format(int(self._has_stack_details("bfd"))))
        self.cpp_info.defines.append('BACKWARD_HAS_DWARF={}'.format(int(self._has_stack_details("dwarf"))))

        self.cpp_info.libs = tools.collect_libs(self)
        if self.settings.os == "Linux":
            self.cpp_info.system_libs.extend(["dl"])
            if self._has_stack_details("dw"):
                self.cpp_info.system_libs.extend(["dw"])           
            if self._has_stack_details("bfd"):
                self.cpp_info.system_libs.extend(["bfd"])


        

recipes/backward-cpp/all/conanfile.py
diff --git a/recipes/backward-cpp/all/conanfile.py b/recipes/backward-cpp/all/conanfile.py
index 4fddde8f6a781..d96d1bc4063bc 100644
--- a/recipes/backward-cpp/all/conanfile.py
+++ b/recipes/backward-cpp/all/conanfile.py
@@ -111,7 +111,6 @@ def package(self):
         os.remove(os.path.join(self.package_folder, "lib", "backward", "BackwardConfig.cmake"))
 
     def package_info(self):
-        self.cpp_info.names["cmake"] = "Backward"
         self.cpp_info.names["cmake_find_package"] = "Backward"
         self.cpp_info.names["cmake_find_package_multi"] = "Backward"
 

[question] Consistency in package and generator names
After the discussion in https://github.com/conan-io/conan/issues/6269#issuecomment-570182130, most packages got normalized to use the format discussed in this comment (https://github.com/conan-io/conan-center-index/pull/690 and related).

If I understand the intention correctly, in CMake the package should always be added with `CONAN_PKG::{name}` (for example  `openssl`) and conan will then expand the correct `Find*`-macro using `self.cpp_info.names["cmake_find_package"]` or `self.cpp_info.names["cmake_find_package_multi"]` (in this case `OpenSSL`).

Some recipes now use an additonal `self.cpp_info.names['cmake']` (a cursory search found [libcurl](https://github.com/conan-io/conan-center-index/blob/ee20546/recipes/libcurl/all/conanfile.py#L374) and [backward-cpp](https://github.com/conan-io/conan-center-index/blob/ee20546/recipes/backward-cpp/all/conanfile.py#L114)).

This leads to strange behavior:
- the `cmake` generator expects `CONAN_PKG::CURL` and will fail with `CONAN_PKG::libcurl`
- the `cmake_multi` works the opposite way, working with `CONAN_PKG::libcurl` and failing with uppercase `CURL`

In terms of consistency, I tend to say that the behavior of `cmake_multi` is the correct one, but either way, both CMake-variants should at least behave the same way.

I'm not sure if there are any side effects in removing the offending lines.

I didn't check if other generators have a similar behavior for different packages.

It might be a good idea to double-check all occurrences of superfluous or missing `cpp_info.names`, ([tcl](https://github.com/conan-io/conan-center-index/blob/ee20546/recipes/tcl/8.6.10/conanfile.py#L198), for example is missing the _multi_ entry). Is there a specific reason to split `cmake` and `cmake_multi` in this case (maybe a question to move to the main conan repo)?
