Repository: conan-io/conan-center-index

Issue:
[cryptopp] cryptopp/8.2.0: missing PEM Pack
The PEM pack allow you to read and write keys and parameters in PEM format.  
It is not part of the cryptopp github repo but can be found here: https://github.com/noloader/cryptopp-pem  
"To compile the source files drop them in your cryptopp directory and run make. The makefile will automatically pick them up. ".  
See also https://www.cryptopp.com/wiki/PEM_Pack.



Discussion:

Resolving patch:
diff --git a/recipes/cryptopp-pem/all/conanfile.py b/recipes/cryptopp-pem/all/conanfile.py
new file mode 100644
--- /dev/null
+++ b/recipes/cryptopp-pem/all/conanfile.py
@@ -0,0 +1,161 @@
+from conans import ConanFile, CMake, tools
+from conans.errors import ConanInvalidConfiguration
+import os
+import shutil
+import textwrap
+
+required_conan_version = ">=1.43.0"
+
+
+class CryptoPPPEMConan(ConanFile):
+    name = "cryptopp-pem"
+    url = "https://github.com/conan-io/conan-center-index"
+    homepage = "https://www.cryptopp.com/wiki/PEM_Pack"
+    license = "Unlicense"
+    description = "The PEM Pack is a partial implementation of message encryption which allows you to read and write PEM encoded keys and parameters, including encrypted private keys."
+    topics = ("cryptopp", "crypto", "cryptographic", "security", "PEM")
+
+    settings = "os", "arch", "compiler", "build_type"
+    options = {
+        "shared": [True, False],
+        "fPIC": [True, False],
+    }
+    default_options = {
+        "shared": False,
+        "fPIC": True,
+    }
+
+    generators = "cmake", "cmake_find_package"
+    _cmake = None
+
+    @property
+    def _source_subfolder(self):
+        return "source_subfolder"
+
+    @property
+    def _build_subfolder(self):
+        return "build_subfolder"
+
+    def export_sources(self):
+        self.copy("CMakeLists.txt")
+        for patch in self.conan_data.get("patches", {}).get(self.version, []):
+            self.copy(patch["patch_file"])
+
+    def config_options(self):
+        if self.settings.os == "Windows":
+            del self.options.fPIC
+
+    def configure(self):
+        if self.options.shared:
+            del self.options.fPIC
+
+    def source(self):
+        suffix = "CRYPTOPP_{}".format(self.version.replace(".", "_"))
+
+        # Get sources
+        tools.get(**self.conan_data["sources"][self.version]["source"],
+                  strip_root=True, destination=self._source_subfolder)
+
+        # Get CMakeLists
+        tools.get(**self.conan_data["sources"][self.version]["cmake"])
+        src_folder = os.path.join(self.source_folder, "cryptopp-cmake-" + suffix)
+        dst_folder = os.path.join(self.source_folder, self._source_subfolder)
+        shutil.move(os.path.join(src_folder, "CMakeLists.txt"), os.path.join(dst_folder, "CMakeLists.txt"))
+        shutil.move(os.path.join(src_folder, "cryptopp-config.cmake"), os.path.join(dst_folder, "cryptopp-config.cmake"))
+        tools.rmdir(src_folder)
+        
+        # Get license
+        tools.download("https://unlicense.org/UNLICENSE", "UNLICENSE", sha256="7e12e5df4bae12cb21581ba157ced20e1986a0508dd10d0e8a4ab9a4cf94e85c")
+
+    def _patch_sources(self):
+        if self.settings.os == "Android" and "ANDROID_NDK_HOME" in os.environ:
+            shutil.copyfile(os.path.join(tools.get_env("ANDROID_NDK_HOME"), "sources", "android", "cpufeatures", "cpu-features.h"),
+                            os.path.join(self._source_subfolder, "cpu-features.h"))
+        for patch in self.conan_data.get("patches", {}).get(self.version, []):
+            tools.patch(**patch)
+        # Honor fPIC option
+        tools.replace_in_file(os.path.join(self._source_subfolder, "CMakeLists.txt"),
+                              "SET(CMAKE_POSITION_INDEPENDENT_CODE 1)", "")
+
+    def _configure_cmake(self):
+        if self._cmake:
+            return self._cmake
+        self._cmake = CMake(self)
+        self._cmake.definitions["BUILD_STATIC"] = not self.options.shared
+        self._cmake.definitions["BUILD_SHARED"] = self.options.shared
+        self._cmake.definitions["BUILD_TESTING"] = False
+        self._cmake.definitions["BUILD_DOCUMENTATION"] = False
+        self._cmake.definitions["USE_INTERMEDIATE_OBJECTS_TARGET"] = False
+        self._cmake.definitions["DISABLE_ASM"] = True
+        if self.settings.os == "Android":
+            self._cmake.definitions["CRYPTOPP_NATIVE_ARCH"] = True
+        if self.settings.os == "Macos" and self.settings.arch == "armv8" and tools.Version(self.version) <= "8.4.0":
+            self._cmake.definitions["CMAKE_CXX_FLAGS"] = "-march=armv8-a"
+        self._cmake.configure(build_folder=self._build_subfolder)
+        return self._cmake
+
+    def requirements(self):
+        self.requires("cryptopp/" + self.version)
+
+    def build(self):                      
+        self._patch_sources()
+        cmake = self._configure_cmake()
+        cmake.build()
+
+    def package(self):
+        self.copy(pattern="UNLICENSE", dst="licenses")
+        cmake = self._configure_cmake()
+        cmake.install()
+        tools.rmdir(os.path.join(self.package_folder, "lib", "cmake"))
+        # TODO: to remove in conan v2 once cmake_find_package* generators removed
+        self._create_cmake_module_alias_targets(
+            os.path.join(self.package_folder, self._module_file_rel_path),
+            {
+                "cryptopp-pem-shared": "cryptopp-pem::cryptopp-pem-shared",
+                "cryptopp-pem-static": "cryptopp-pem::cryptopp-pem-static"
+            }
+        )
+
+    @staticmethod
+    def _create_cmake_module_alias_targets(module_file, targets):
+        content = ""
+        for alias, aliased in targets.items():
+            content += textwrap.dedent("""\
+                if(TARGET {aliased} AND NOT TARGET {alias})
+                    add_library({alias} INTERFACE IMPORTED)
+                    set_property(TARGET {alias} PROPERTY INTERFACE_LINK_LIBRARIES {aliased})
+                endif()
+            """.format(alias=alias, aliased=aliased))
+        tools.save(module_file, content)
+
+    @property
+    def _module_file_rel_path(self):
+        return os.path.join("lib", "cmake", "conan-official-{}-targets.cmake".format(self.name))
+
+    def package_info(self):
+        cmake_target = "cryptopp-pem-shared" if self.options.shared else "cryptopp-pem-static"
+        self.cpp_info.set_property("cmake_file_name", "cryptopp-pem")
+        self.cpp_info.set_property("cmake_target_name", cmake_target)
+        self.cpp_info.set_property("pkg_config_name", "libcryptopp-pem")
+
+        # TODO: back to global scope once cmake_find_package* generators removed
+        self.cpp_info.components["libcryptopp-pem"].libs = tools.collect_libs(self)
+        if self.settings.os in ["Linux", "FreeBSD"]:
+            self.cpp_info.components["libcryptopp-pem"].system_libs = ["pthread", "m"]
+        elif self.settings.os == "SunOS":
+            self.cpp_info.components["libcryptopp-pem"].system_libs = ["nsl", "socket"]
+        elif self.settings.os == "Windows":
+            self.cpp_info.components["libcryptopp-pem"].system_libs = ["ws2_32"]
+
+        # TODO: to remove in conan v2 once cmake_find_package* & pkg_config generators removed
+        self.cpp_info.names["pkg_config"] = "libcryptopp-pem"
+        self.cpp_info.components["libcryptopp-pem"].names["cmake_find_package"] = cmake_target
+        self.cpp_info.components["libcryptopp-pem"].names["cmake_find_package_multi"] = cmake_target
+        self.cpp_info.components["libcryptopp-pem"].build_modules["cmake_find_package"] = [self._module_file_rel_path]
+        self.cpp_info.components["libcryptopp-pem"].build_modules["cmake_find_package_multi"] = [self._module_file_rel_path]
+        self.cpp_info.components["libcryptopp-pem"].set_property("cmake_target_name", cmake_target)
+        self.cpp_info.components["libcryptopp-pem"].set_property("pkg_config_name", "libcryptopp-pem")
+
+        self.cpp_info.components["libcryptopp-pem"].requires = [
+            "cryptopp::cryptopp",
+        ]


Test patch:
diff --git a/recipes/cryptopp-pem/all/test_package/CMakeLists.txt b/recipes/cryptopp-pem/all/test_package/CMakeLists.txt
new file mode 100644
--- /dev/null
+++ b/recipes/cryptopp-pem/all/test_package/CMakeLists.txt
@@ -0,0 +1,10 @@
+cmake_minimum_required(VERSION 3.1)
+project(test_package)
+
+include(${CMAKE_BINARY_DIR}/conanbuildinfo.cmake)
+conan_basic_setup(TARGETS)
+
+find_package(cryptopp-pem)
+
+add_executable(${PROJECT_NAME} test_package.cpp)
+target_link_libraries(${PROJECT_NAME} cryptopp-pem::cryptopp-pem)
diff --git a/recipes/cryptopp-pem/all/test_package/conanfile.py b/recipes/cryptopp-pem/all/test_package/conanfile.py
new file mode 100644
--- /dev/null
+++ b/recipes/cryptopp-pem/all/test_package/conanfile.py
@@ -0,0 +1,17 @@
+from conans import ConanFile, CMake, tools
+import os
+
+
+class TestPackageConan(ConanFile):
+    settings = "os", "arch", "compiler", "build_type"
+    generators = "cmake", "cmake_find_package"
+
+    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)
diff --git a/recipes/cryptopp-pem/all/test_package/test_package.cpp b/recipes/cryptopp-pem/all/test_package/test_package.cpp
new file mode 100644
--- /dev/null
+++ b/recipes/cryptopp-pem/all/test_package/test_package.cpp
@@ -0,0 +1,27 @@
+#include <cryptopp/pem.h>
+
+#include <iostream>
+#include <string>
+
+int main()
+{
+    try
+    {
+        CryptoPP::RSA::PublicKey publicKey;
+        std::string key = "-----BEGIN PUBLIC KEY-----\n"
+            "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDWEDeqk749sYZAt2adT2m1Vo8N\n"
+            "h86GzAs/ZWvlQDUyiedDuAvOhrVwllp4GuAXP7tZwGoeJ+Un6Nkl45IIQ2U9NMWQ\n"
+            "aru76CD9kVUdThnKVOaeeqZysM1Bz6iJF5piSUzVKZdEk6rIUZjrwpNaYdBBq4a/\n"
+            "cNETdvolooljIRB8ywIDAQAB\n"
+            "-----END PUBLIC KEY-----";
+        CryptoPP::StringSource source_str(key, true);
+        CryptoPP::PEM_Load(source_str, publicKey);
+
+        return 0;
+    }
+    catch(const std::exception& e)
+    {
+        std::cout << e.what() << std::endl;
+        return 1;
+    }
+}