Repository: conan-io/conan-center-index

Issue:
[request] sbepp/1.0.0
### Package Name/Version

sbepp/1.0.0

### Webpage

https://oleksandrkvl.github.io/sbepp/

### Source code

https://github.com/OleksandrKvl/sbepp

### Description of the library/tool

`sbepp` is a [FIX SBE protocol](https://www.fixtrading.org/standards/sbe/) schema compiler. It provides 2 targets:
- `sbepp::sbeppc`, an executable which generates C++ code from XML SBE schema, requires C++17
- `sbepp::sbepp`, a header-only library used by generated code, requires C++11

I'm the author and will provide a recipe in the following PR.


Discussion:

Resolving patch:
diff --git a/recipes/sbepp/all/conanfile.py b/recipes/sbepp/all/conanfile.py
new file mode 100644
--- /dev/null
+++ b/recipes/sbepp/all/conanfile.py
@@ -0,0 +1,124 @@
+from conan import ConanFile
+from conan.errors import ConanInvalidConfiguration
+from conan.tools.microsoft import check_min_vs, is_msvc
+from conan.tools.files import export_conandata_patches, get, copy, rmdir
+from conan.tools.build import check_min_cppstd
+from conan.tools.scm import Version
+from conan.tools.cmake import CMake, CMakeDeps, CMakeToolchain, cmake_layout
+import os
+
+
+required_conan_version = ">=1.53.0"
+
+
+class PackageConan(ConanFile):
+    name = "sbepp"
+    description = "C++ implementation of the FIX Simple Binary Encoding"
+    license = "MIT"
+    url = "https://github.com/conan-io/conan-center-index"
+    homepage = "https://github.com/OleksandrKvl/sbepp"
+    topics = ("trading", "fix", "sbe")
+    settings = "os", "arch", "compiler", "build_type"
+    options = {
+        "with_sbeppc": [True, False]
+    }
+    default_options = {
+        "with_sbeppc": True
+    }
+
+    @property
+    def _min_cppstd(self):
+        if self.options.with_sbeppc:
+            return 17
+        else:
+            return 11
+
+    @property
+    def _compilers_minimum_version(self):
+        if self.options.with_sbeppc:
+            return {
+                "gcc": "9",
+                "clang": "9",
+                "apple-clang": "11"
+            }
+        else:
+            return {
+                "gcc": "4.8.1",
+                "clang": "3.3",
+                "apple-clang": "9.4"
+            }
+
+    def export_sources(self):
+        copy(self, os.path.join("cmake", "sbeppcTargets.cmake"),
+            self.recipe_folder, self.export_sources_folder)
+        export_conandata_patches(self)
+
+    def layout(self):
+        cmake_layout(self, src_folder="src")
+
+    def package_id(self):
+        if not self.info.options.with_sbeppc:
+            self.info.clear()
+        else:
+            del self.info.settings.compiler
+
+    def requirements(self):
+        if self.options.with_sbeppc:
+            self.requires("fmt/9.1.0")
+            self.requires("pugixml/1.12.1")
+
+    def validate(self):
+        if self.settings.compiler.cppstd:
+            check_min_cppstd(self, self._min_cppstd)
+
+        check_min_vs(self, 191)
+        if not is_msvc(self):
+            minimum_version = self._compilers_minimum_version.get(str(self.settings.compiler), False)
+            if minimum_version and Version(self.settings.compiler.version) < minimum_version:
+                raise ConanInvalidConfiguration(
+                    f"{self.ref} requires C++{self._min_cppstd}, which your compiler does not support."
+                )
+
+    def source(self):
+        get(self, **self.conan_data["sources"][self.version], strip_root=True)
+
+    def generate(self):
+        tc = CMakeToolchain(self)
+        if not self.options.with_sbeppc:
+            tc.variables["SBEPP_BUILD_SBEPPC"] = False
+
+        tc.generate()
+
+        if self.options.with_sbeppc:
+            tc = CMakeDeps(self)
+            tc.generate()
+
+    def build(self):
+        cmake = CMake(self)
+        cmake.configure()
+        cmake.build()
+
+    def package(self):
+        copy(self, pattern="LICENSE.md", dst=os.path.join(self.package_folder, "licenses"), src=self.source_folder)
+        cmake = CMake(self)
+        cmake.install()
+        rmdir(self, os.path.join(self.package_folder, "lib", "cmake"))
+        copy(self, "sbeppcTargets.cmake",
+            src=os.path.join(self.source_folder, os.pardir, "cmake"),
+            dst=os.path.join(self.package_folder, self._module_path))
+
+    @property
+    def _module_path(self):
+        return os.path.join("lib", "cmake")
+
+    def package_info(self):
+        # provide sbepp::sbeppc target
+        build_modules = [
+            os.path.join(self._module_path, "sbeppcTargets.cmake")
+        ]
+        self.cpp_info.builddirs.append(self._module_path)
+        self.cpp_info.set_property("cmake_build_modules", build_modules)
+
+        # TODO: to remove in conan v2
+        if self.options.with_sbeppc:
+            self.env_info.PATH.append(os.path.join(self.package_folder, "bin"))


Test patch:
diff --git a/recipes/sbepp/all/test_package/CMakeLists.txt b/recipes/sbepp/all/test_package/CMakeLists.txt
new file mode 100644
--- /dev/null
+++ b/recipes/sbepp/all/test_package/CMakeLists.txt
@@ -0,0 +1,39 @@
+cmake_minimum_required(VERSION 3.15)
+
+project(test_package CXX)
+
+find_package(sbepp REQUIRED CONFIG)
+
+# test `sbepp::sbeppc` executable
+if(TARGET sbepp::sbeppc)
+    set(sbeppc_test_name "test_sbeppc")
+    set(schema "test_schema")
+    set(schema_path "${CMAKE_CURRENT_LIST_DIR}/${schema}.xml")
+    set(output_file "${CMAKE_CURRENT_BINARY_DIR}/${schema}/${schema}.hpp")
+
+    add_custom_command(
+        OUTPUT ${output_file}
+        COMMAND $<TARGET_FILE:sbepp::sbeppc> ${schema_path}
+        DEPENDS ${schema_path}
+    )
+
+    add_custom_target(compile_schema DEPENDS ${output_file})
+
+    add_executable(${sbeppc_test_name})
+    add_dependencies(${sbeppc_test_name} compile_schema)
+    target_sources(${sbeppc_test_name} PRIVATE test_sbeppc.cpp)
+
+    target_include_directories(${sbeppc_test_name}
+        SYSTEM PRIVATE
+        ${CMAKE_CURRENT_BINARY_DIR}
+    )
+
+    target_link_libraries(${sbeppc_test_name} PRIVATE sbepp::sbepp)
+    target_compile_features(${sbeppc_test_name} PRIVATE cxx_std_11)
+endif()
+
+# test `sbepp::sbepp` header-only library
+add_executable(${PROJECT_NAME})
+target_sources(${PROJECT_NAME} PRIVATE test_sbepp.cpp)
+target_link_libraries(${PROJECT_NAME} PRIVATE sbepp::sbepp)
+target_compile_features(${PROJECT_NAME} PRIVATE cxx_std_11)
diff --git a/recipes/sbepp/all/test_package/conanfile.py b/recipes/sbepp/all/test_package/conanfile.py
new file mode 100644
--- /dev/null
+++ b/recipes/sbepp/all/test_package/conanfile.py
@@ -0,0 +1,27 @@
+from conan import ConanFile
+from conan.tools.build import can_run
+from conan.tools.cmake import cmake_layout, CMake
+import os
+
+
+# It will become the standard on Conan 2.x
+class TestPackageConan(ConanFile):
+    settings = "os", "arch", "compiler", "build_type"
+    generators = "CMakeDeps", "CMakeToolchain", "VirtualRunEnv"
+    test_type = "explicit"
+
+    def requirements(self):
+        self.requires(self.tested_reference_str)
+
+    def layout(self):
+        cmake_layout(self)
+
+    def build(self):
+        cmake = CMake(self)
+        cmake.configure()
+        cmake.build()
+
+    def test(self):
+        if can_run(self):
+            bin_path = os.path.join(self.cpp.build.bindirs[0], "test_package")
+            self.run(bin_path, env="conanrun")
diff --git a/recipes/sbepp/all/test_package/test_sbepp.cpp b/recipes/sbepp/all/test_package/test_sbepp.cpp
new file mode 100644
--- /dev/null
+++ b/recipes/sbepp/all/test_package/test_sbepp.cpp
@@ -0,0 +1,16 @@
+#include <sbepp/sbepp.hpp>
+
+#include <cstdlib>
+
+enum class Enum
+{
+    A,
+    B
+};
+
+int main()
+{
+    auto underlying = sbepp::to_underlying(Enum::A);
+
+    return EXIT_SUCCESS;
+}
diff --git a/recipes/sbepp/all/test_package/test_sbeppc.cpp b/recipes/sbepp/all/test_package/test_sbeppc.cpp
new file mode 100644
--- /dev/null
+++ b/recipes/sbepp/all/test_package/test_sbeppc.cpp
@@ -0,0 +1,12 @@
+#include <test_schema/test_schema.hpp>
+
+#include <cstdlib>
+#include <array>
+
+int main(void)
+{
+    std::array<char, 64> buf{};
+    auto msg = sbepp::make_view<test_schema::messages::msg1>(
+        buf.data(), buf.size());
+    return EXIT_SUCCESS;
+}
diff --git a/recipes/sbepp/all/test_package/test_schema.xml b/recipes/sbepp/all/test_package/test_schema.xml
new file mode 100644
--- /dev/null
+++ b/recipes/sbepp/all/test_package/test_schema.xml
@@ -0,0 +1,32 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<sbe:messageSchema xmlns:sbe="http://fixprotocol.io/2016/sbe"
+                   xmlns:xi="http://www.w3.org/2001/XInclude"
+                   package="test_schema"
+                   id="1"
+                   version="0"
+                   semanticVersion="5.2"
+                   description="Example base schema which can be extended."
+                   byteOrder="littleEndian">
+    <types>
+        <composite name="messageHeader">
+            <type name="blockLength" primitiveType="uint16"/>
+            <type name="templateId" primitiveType="uint16"/>
+            <type name="schemaId" primitiveType="uint16"/>
+            <type name="version" primitiveType="uint16"/>
+        </composite>
+
+        <composite name="groupSizeEncoding">
+            <type name="blockLength" primitiveType="uint16"/>
+            <type name="numInGroup" primitiveType="uint16"/>
+        </composite>
+
+        <composite name="varDataEncoding">
+            <type name="length" primitiveType="uint32"/>
+            <type name="varData" primitiveType="uint8" length="0"/>
+        </composite>
+    </types>
+
+    <sbe:message name="msg1" id="1">
+        <field name="field" id="1" type="uint32"/>
+    </sbe:message>
+</sbe:messageSchema>
diff --git a/recipes/sbepp/all/test_v1_package/CMakeLists.txt b/recipes/sbepp/all/test_v1_package/CMakeLists.txt
new file mode 100644
--- /dev/null
+++ b/recipes/sbepp/all/test_v1_package/CMakeLists.txt
@@ -0,0 +1,8 @@
+cmake_minimum_required(VERSION 3.15)
+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/sbepp/all/test_v1_package/conanfile.py b/recipes/sbepp/all/test_v1_package/conanfile.py
new file mode 100644
--- /dev/null
+++ b/recipes/sbepp/all/test_v1_package/conanfile.py
@@ -0,0 +1,19 @@
+from conans import ConanFile, CMake
+from conan.tools.build import cross_building
+import os
+
+
+# legacy validation with Conan 1.x
+class TestPackageV1Conan(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 cross_building(self):
+            bin_path = os.path.join("bin", "test_package")
+            self.run(bin_path, run_environment=True)