diff --git a/.github/workflows/build-develop.yml b/.github/workflows/build-develop.yml index 423779d1b..666bfe9d0 100644 --- a/.github/workflows/build-develop.yml +++ b/.github/workflows/build-develop.yml @@ -49,10 +49,16 @@ jobs: - name: Detect Conan Profile run: conan profile detect -f + - name: Bootstrap local Corrade recipe + run: conan create ${{github.workspace}}/recipes/corrade/all --version cci.20250327 --build=missing + + - name: Bootstrap local pcapplusplus recipe + run: conan create ${{github.workspace}}/recipes/pcapplusplus/cmake --version 23.09 --build=missing + - name: Configure CMake shell: bash working-directory: ${{github.workspace}}/build - run: PKG_CONFIG_PATH=${{github.workspace}}/local/lib/pkgconfig cmake $GITHUB_WORKSPACE -DCMAKE_BUILD_TYPE=$BUILD_TYPE -DCMAKE_PROJECT_TOP_LEVEL_INCLUDES=./cmake/conan_provider.cmake -DCONAN_INSTALL_ARGS="--build=missing;-c=corrade/*:tools.build:cxxflags=['-include','vector']" + run: PKG_CONFIG_PATH=${{github.workspace}}/local/lib/pkgconfig cmake $GITHUB_WORKSPACE -DCMAKE_BUILD_TYPE=$BUILD_TYPE -DCMAKE_PROJECT_TOP_LEVEL_INCLUDES=./cmake/conan_provider.cmake -DCONAN_INSTALL_ARGS="--build=missing" - name: Build working-directory: ${{github.workspace}}/build @@ -86,6 +92,9 @@ jobs: key: conan-${{ runner.os }}-amd64-${{ hashFiles('conanfile.py', '*/conanfile.py') }} restore-keys: conan-${{ runner.os }}-amd64- + - name: Bootstrap local Corrade recipe + run: conan create ${{github.workspace}}/recipes/corrade/all --version cci.20250327 --build=missing + - name: Configure CMake shell: bash working-directory: ${{github.workspace}}/build diff --git a/.github/workflows/build-release.yml b/.github/workflows/build-release.yml index 44aa5e498..1ce13b19b 100644 --- a/.github/workflows/build-release.yml +++ b/.github/workflows/build-release.yml @@ -39,6 +39,9 @@ jobs: key: conan-${{ runner.os }}-${{ hashFiles('conanfile.py', '*/conanfile.py') }} restore-keys: conan-${{ runner.os }}- + - name: Bootstrap local Corrade recipe + run: conan create ${{github.workspace}}/recipes/corrade/all --version cci.20250327 --build=missing + - name: Configure CMake shell: bash working-directory: ${{github.workspace}}/build diff --git a/.github/workflows/build_cross.yml b/.github/workflows/build_cross.yml index b85c8619a..b26d53a07 100644 --- a/.github/workflows/build_cross.yml +++ b/.github/workflows/build_cross.yml @@ -122,6 +122,10 @@ jobs: key: conan-${{ runner.os }}-${{matrix.arch}}-${{ hashFiles('**/conanfile.py') }} restore-keys: conan-${{ runner.os }}-${{matrix.arch}}- + - name: Bootstrap local Corrade recipe + working-directory: ${{github.workspace}}/src + run: conan create recipes/corrade/all --version cci.20250327 -pr:b=default --build=missing + - name: Install dependencies working-directory: ${{github.workspace}}/src run: | diff --git a/.github/workflows/build_debug.yml b/.github/workflows/build_debug.yml index b09c77a4e..5f8914f0b 100644 --- a/.github/workflows/build_debug.yml +++ b/.github/workflows/build_debug.yml @@ -31,6 +31,9 @@ jobs: key: conan-${{ runner.os }}-amd64-${{ hashFiles('conanfile.py', '*/conanfile.py') }} restore-keys: conan-${{ runner.os }}-amd64- + - name: Bootstrap local Corrade recipe + run: conan create ${{github.workspace}}/recipes/corrade/all --version cci.20250327 --build=missing + - name: linux package install run: | sudo apt-get update diff --git a/cmake/conan_provider.cmake b/cmake/conan_provider.cmake index 5f71be451..5d89097f1 100644 --- a/cmake/conan_provider.cmake +++ b/cmake/conan_provider.cmake @@ -135,10 +135,14 @@ function(detect_arch arch) endfunction() -function(detect_cxx_standard cxx_standard) +function(detect_cxx_standard compiler cxx_standard) set(${cxx_standard} ${CMAKE_CXX_STANDARD} PARENT_SCOPE) if(CMAKE_CXX_EXTENSIONS) - set(${cxx_standard} "gnu${CMAKE_CXX_STANDARD}" PARENT_SCOPE) + if(compiler STREQUAL "msvc") + set(${cxx_standard} "${CMAKE_CXX_STANDARD}" PARENT_SCOPE) + else() + set(${cxx_standard} "gnu${CMAKE_CXX_STANDARD}" PARENT_SCOPE) + endif() endif() endfunction() @@ -356,8 +360,10 @@ macro(append_compiler_executables_configuration) # Not necessary to warn if RC not defined endif() if(NOT "x${_conan_compilers_list}" STREQUAL "x") - string(REPLACE ";" "," _conan_compilers_list "${_conan_compilers_list}") - string(APPEND profile "tools.build:compiler_executables={${_conan_compilers_list}}\n") + if (NOT CMAKE_CXX_COMPILER_ID STREQUAL "MSVC") + string(REPLACE ";" "," _conan_compilers_list "${_conan_compilers_list}") + string(APPEND profile "tools.build:compiler_executables={${_conan_compilers_list}}\n") + endif() endif() unset(_conan_c_compiler) unset(_conan_cpp_compiler) @@ -370,7 +376,7 @@ function(detect_host_profile output_file) detect_os(os os_api_level os_sdk os_subsystem os_version) detect_arch(arch) detect_compiler(compiler compiler_version compiler_runtime compiler_runtime_type) - detect_cxx_standard(compiler_cppstd) + detect_cxx_standard(${compiler} compiler_cppstd) detect_lib_cxx(compiler_libcxx) detect_build_type(build_type) @@ -461,10 +467,9 @@ endfunction() function(conan_install) - cmake_parse_arguments(ARGS conan_args ${ARGN}) set(conan_output_folder ${CMAKE_BINARY_DIR}/conan) # Invoke "conan install" with the provided arguments - set(conan_args ${conan_args} -of=${conan_output_folder}) + set(conan_args -of=${conan_output_folder}) message(STATUS "CMake-Conan: conan install ${CMAKE_SOURCE_DIR} ${conan_args} ${ARGN}") @@ -567,7 +572,7 @@ macro(conan_provide_dependency method package_name) get_property(_conan_install_success GLOBAL PROPERTY CONAN_INSTALL_SUCCESS) if(NOT _conan_install_success) find_program(CONAN_COMMAND "conan" REQUIRED) - conan_get_version(${CONAN_COMMAND} CONAN_CURRENT_VERSION) + conan_get_version("${CONAN_COMMAND}" CONAN_CURRENT_VERSION) conan_version_check(MINIMUM ${CONAN_MINIMUM_VERSION} CURRENT ${CONAN_CURRENT_VERSION}) message(STATUS "CMake-Conan: first find_package() found. Installing dependencies with Conan") if("default" IN_LIST CONAN_HOST_PROFILE OR "default" IN_LIST CONAN_BUILD_PROFILE) @@ -580,30 +585,59 @@ macro(conan_provide_dependency method package_name) construct_profile_argument(_build_profile_flags CONAN_BUILD_PROFILE) if(EXISTS "${CMAKE_SOURCE_DIR}/conanfile.py") file(READ "${CMAKE_SOURCE_DIR}/conanfile.py" outfile) - if(NOT "${outfile}" MATCHES ".*CMakeDeps.*") - message(WARNING "Cmake-conan: CMakeDeps generator was not defined in the conanfile") + if(NOT "${outfile}" MATCHES ".*CMakeConfigDeps.*") + message(WARNING "Cmake-conan: CMakeConfigDeps generator was not defined in the conanfile") endif() - set(generator "") elseif (EXISTS "${CMAKE_SOURCE_DIR}/conanfile.txt") file(READ "${CMAKE_SOURCE_DIR}/conanfile.txt" outfile) - if(NOT "${outfile}" MATCHES ".*CMakeDeps.*") - message(WARNING "Cmake-conan: CMakeDeps generator was not defined in the conanfile. " - "Please define the generator as it will be mandatory in the future") + if(NOT "${outfile}" MATCHES ".*CMakeConfigDeps.*") + message(WARNING "Cmake-conan: CMakeConfigDeps generator was not defined in the conanfile") endif() - set(generator "-g;CMakeDeps") endif() + get_property(_multiconfig_generator GLOBAL PROPERTY GENERATOR_IS_MULTI_CONFIG) - if(NOT _multiconfig_generator) - message(STATUS "CMake-Conan: Installing single configuration ${CMAKE_BUILD_TYPE}") - conan_install(${_host_profile_flags} ${_build_profile_flags} ${CONAN_INSTALL_ARGS} ${generator}) + + if(DEFINED CONAN_INSTALL_BUILD_CONFIGURATIONS) + # Configurations are specified by the project or user + set(_build_configs "${CONAN_INSTALL_BUILD_CONFIGURATIONS}") + list(LENGTH _build_configs _build_configs_length) + if(NOT _multiconfig_generator AND _build_configs_length GREATER 1) + message(FATAL_ERROR "cmake-conan: when using a single-config CMake generator, " + "please only specify a single configuration in CONAN_INSTALL_BUILD_CONFIGURATIONS") + endif() + unset(_build_configs_length) else() - message(STATUS "CMake-Conan: Installing both Debug and Release") - conan_install(${_host_profile_flags} ${_build_profile_flags} -s build_type=Release ${CONAN_INSTALL_ARGS} ${generator}) - conan_install(${_host_profile_flags} ${_build_profile_flags} -s build_type=Debug ${CONAN_INSTALL_ARGS} ${generator}) + # No configuration overrides, provide sensible defaults + if(_multiconfig_generator) + set(_build_configs Release Debug) + else() + set(_build_configs ${CMAKE_BUILD_TYPE}) + endif() + endif() + + list(JOIN _build_configs ", " _build_configs_msg) + message(STATUS "CMake-Conan: Installing configuration(s): ${_build_configs_msg}") + foreach(_build_config IN LISTS _build_configs) + set(_self_build_config "") + if(NOT _multiconfig_generator AND NOT _build_config STREQUAL "${CMAKE_BUILD_TYPE}") + set(_self_build_config -s &:build_type=${CMAKE_BUILD_TYPE}) + endif() + conan_install(${_host_profile_flags} ${_build_profile_flags} -s build_type=${_build_config} ${_self_build_config} ${CONAN_INSTALL_ARGS}) + endforeach() + + get_property(_conan_generators_folder GLOBAL PROPERTY CONAN_GENERATORS_FOLDER) + if(EXISTS "${_conan_generators_folder}/conan_cmakedeps_paths.cmake") + message(STATUS "CMake-Conan: Loading conan_cmakedeps_paths.cmake file") + include(${_conan_generators_folder}/conan_cmakedeps_paths.cmake) + endif() + + unset(_self_build_config) + unset(_multiconfig_generator) + unset(_build_configs) + unset(_build_configs_msg) unset(_host_profile_flags) unset(_build_profile_flags) - unset(_multiconfig_generator) unset(_conan_install_success) else() message(STATUS "CMake-Conan: find_package(${ARGV1}) found, 'conan install' already ran") diff --git a/conanfile.py b/conanfile.py index 2a01b519a..1181eee32 100644 --- a/conanfile.py +++ b/conanfile.py @@ -8,7 +8,7 @@ class Pktvisor(ConanFile): def requirements(self): self.requires("catch2/3.8.0") - self.requires("corrade/2020.06") + self.requires("corrade/cci.20250327") self.requires("cpp-httplib/0.18.3") self.requires("docopt.cpp/0.6.3") self.requires("fast-cpp-csv-parser/cci.20240102") @@ -20,7 +20,7 @@ def requirements(self): self.requires("libpcap/1.10.5", force=True) else: self.requires("npcap/1.70") - self.requires("opentelemetry-cpp/1.17.0") + self.requires("opentelemetry-cpp/1.24.0") self.requires("pcapplusplus/23.09") self.requires("protobuf/5.27.0") self.requires("sigslot/1.2.2") @@ -37,7 +37,7 @@ def requirements(self): self.requires("sentry-crashpad/0.6.5") def build_requirements(self): - self.tool_requires("corrade/2020.06") + self.tool_requires("corrade/cci.20250327") self.tool_requires("protobuf/5.27.0") def layout(self): diff --git a/docs/superpowers/plans/2026-03-27-corrade-local-conan-recipe.md b/docs/superpowers/plans/2026-03-27-corrade-local-conan-recipe.md new file mode 100644 index 000000000..a5fa94d33 --- /dev/null +++ b/docs/superpowers/plans/2026-03-27-corrade-local-conan-recipe.md @@ -0,0 +1,655 @@ +# Corrade Local Conan Recipe Implementation Plan + +> **For agentic workers:** REQUIRED SUB-SKILL: Use superpowers:subagent-driven-development (recommended) or superpowers:executing-plans to implement this plan task-by-task. Steps use checkbox (`- [ ]`) syntax for tracking. + +**Goal:** Replace the frozen `corrade/2020.06` Conan Center package with a local recipe that builds Corrade from commit `22e7ffc6fcdeaa0df96e0d8b3d482ad6abe7dc36`, fixing GCC 11+/Clang 14+ compilation failures. + +**Architecture:** A `recipes/corrade/` directory is added to the repo containing a Conan recipe adapted from the official CCI recipe. The recipe fetches Corrade from a GitHub commit tarball instead of the `v2020.06` tag tarball. A `conan create` bootstrap step is added to all CI workflows before the cmake/conan-install phase. + +**Tech Stack:** Conan 2.x, CMake 3.24+, C++17, GitHub Actions + +**Working branch:** `chore/replace-corrade-conan-recipe` + +--- + +## File Map + +| Action | Path | Purpose | +|---|---|---| +| Create | `recipes/corrade/config.yml` | Declares version `cci.20250327` | +| Create | `recipes/corrade/all/conandata.yml` | Source URL + SHA256 for commit tarball | +| Create | `recipes/corrade/all/conanfile.py` | Conan recipe (adapted from CCI, patches removed) | +| Create | `recipes/corrade/all/cmake/conan-corrade-vars.cmake` | CMake helper (verbatim from CCI) | +| Modify | `conanfile.py` | Bump version `2020.06` → `cci.20250327` | +| Modify | `.github/workflows/build-develop.yml` | Add `conan create` before cmake (mac + linux jobs); remove mac workaround cxxflag | +| Modify | `.github/workflows/build-release.yml` | Add `conan create` before cmake | +| Modify | `.github/workflows/build_debug.yml` | Add `conan create` before cmake | +| Modify | `.github/workflows/build_cross.yml` | Add `conan create` before `conan install` | + +--- + +## Task 1: Compute commit tarball SHA256 + +**Files:** +- Read: nothing (run command) + +- [ ] **Step 1: Download the commit tarball and compute SHA256** + +```bash +curl -sL https://github.com/mosra/corrade/archive/22e7ffc6fcdeaa0df96e0d8b3d482ad6abe7dc36.tar.gz | sha256sum +``` + +Expected output format: ` -` + +- [ ] **Step 2: Record the hash** + +Copy the 64-character hex hash. You will use it in Task 2, Step 2. Do not proceed until you have it. + +--- + +## Task 2: Create the local Conan recipe files + +**Files:** +- Create: `recipes/corrade/config.yml` +- Create: `recipes/corrade/all/conandata.yml` +- Create: `recipes/corrade/all/conanfile.py` +- Create: `recipes/corrade/all/cmake/conan-corrade-vars.cmake` + +- [ ] **Step 1: Create `recipes/corrade/config.yml`** + +```yaml +versions: + "cci.20250327": + folder: all +``` + +- [ ] **Step 2: Create `recipes/corrade/all/conandata.yml`** + +Replace `` with the hash you computed in Task 1. + +```yaml +sources: + "cci.20250327": + url: "https://github.com/mosra/corrade/archive/22e7ffc6fcdeaa0df96e0d8b3d482ad6abe7dc36.tar.gz" + sha256: "" +``` + +- [ ] **Step 3: Create `recipes/corrade/all/conanfile.py`** + +This is the CCI recipe with two lines removed: `export_conandata_patches` (from `export_sources`) and `apply_conandata_patches` (from `build`). No patches are needed for this master commit — the fixes are already in the source. + +```python +import os + +from conan import ConanFile +from conan.errors import ConanInvalidConfiguration +from conan.tools.build import cross_building +from conan.tools.cmake import CMake, CMakeDeps, CMakeToolchain, cmake_layout +from conan.tools.files import copy, get, rmdir +from conan.tools.microsoft import is_msvc, check_min_vs + +required_conan_version = ">=1.52.0" + + +class CorradeConan(ConanFile): + name = "corrade" + description = "Corrade is a multiplatform utility library written in C++11/C++14." + license = "MIT" + url = "https://github.com/conan-io/conan-center-index" + homepage = "https://magnum.graphics/corrade" + topics = ("magnum", "filesystem", "console", "environment", "os") + + package_type = "library" + settings = "os", "arch", "compiler", "build_type" + options = { + "shared": [True, False], + "fPIC": [True, False], + "build_deprecated": [True, False], + "with_interconnect": [True, False], + "with_main": [True, False], + "with_pluginmanager": [True, False], + "with_testsuite": [True, False], + "with_utility": [True, False], + } + default_options = { + "shared": False, + "fPIC": True, + "build_deprecated": True, + "with_interconnect": True, + "with_main": True, + "with_pluginmanager": True, + "with_testsuite": True, + "with_utility": True, + } + + def export_sources(self): + copy(self, "cmake/*", src=self.recipe_folder, dst=self.export_sources_folder) + + def config_options(self): + if self.settings.os == "Windows": + del self.options.fPIC + + def configure(self): + if self.options.shared: + self.options.rm_safe("fPIC") + + def layout(self): + cmake_layout(self, src_folder="src") + + def validate(self): + check_min_vs(self, 190) + if not self.options.with_utility and ( + self.options.with_testsuite or self.options.with_interconnect or self.options.with_pluginmanager + ): + raise ConanInvalidConfiguration( + "Component 'utility' is required for 'test_suite', 'interconnect' and 'plugin_manager'" + ) + + def build_requirements(self): + if hasattr(self, "settings_build") and cross_building(self, skip_x64_x86=True): + self.tool_requires(f"corrade/{self.version}") + + def source(self): + get(self, **self.conan_data["sources"][self.version], strip_root=True) + + def generate(self): + tc = CMakeToolchain(self) + tc.variables["BUILD_STATIC"] = not self.options.shared + tc.variables["BUILD_STATIC_PIC"] = self.options.get_safe("fPIC", False) + + tc.variables["BUILD_DEPRECATED"] = self.options.build_deprecated + tc.variables["WITH_INTERCONNECT"] = self.options.with_interconnect + tc.variables["WITH_MAIN"] = self.options.with_main + tc.variables["WITH_PLUGINMANAGER"] = self.options.with_pluginmanager + tc.variables["WITH_TESTSUITE"] = self.options.with_testsuite + tc.variables["WITH_UTILITY"] = self.options.with_utility + tc.variables["WITH_RC"] = self.options.with_utility + + tc.variables["LIB_SUFFIX"] = "" + + if is_msvc(self): + if check_min_vs(self, 193, raise_invalid=False): + tc.variables["MSVC2019_COMPATIBILITY"] = True + elif check_min_vs(self, 192, raise_invalid=False): + tc.variables["MSVC2017_COMPATIBILITY"] = True + elif check_min_vs(self, 191, raise_invalid=False): + tc.variables["MSVC2015_COMPATIBILITY"] = True + + tc.generate() + tc = CMakeDeps(self) + tc.generate() + + def build(self): + cmake = CMake(self) + cmake.configure() + cmake.build() + + def package(self): + copy(self, "COPYING", dst=os.path.join(self.package_folder, "licenses"), src=self.source_folder) + cmake = CMake(self) + cmake.install() + share_cmake = os.path.join(self.package_folder, "share", "cmake", "Corrade") + copy(self, "UseCorrade.cmake", + src=share_cmake, + dst=os.path.join(self.package_folder, "lib", "cmake")) + copy(self, "CorradeLibSuffix.cmake", + src=share_cmake, + dst=os.path.join(self.package_folder, "lib", "cmake")) + copy(self, "*.cmake", + src=os.path.join(self.export_sources_folder, "cmake"), + dst=os.path.join(self.package_folder, "lib", "cmake")) + rmdir(self, os.path.join(self.package_folder, "share")) + + def package_info(self): + self.cpp_info.set_property("cmake_find_mode", "both") + self.cpp_info.set_property("cmake_file_name", "Corrade") + self.cpp_info.set_property("cmake_target_name", "Corrade::Corrade") + + suffix = "-d" if self.settings.build_type == "Debug" else "" + + cmake_modules = [ + os.path.join("lib", "cmake", "conan-corrade-vars.cmake"), + os.path.join("lib", "cmake", "CorradeLibSuffix.cmake"), + os.path.join("lib", "cmake", "UseCorrade.cmake"), + ] + self.cpp_info.set_property("cmake_build_modules", cmake_modules) + self.cpp_info.components["_corrade"].build_modules["cmake_find_package"] = cmake_modules + self.cpp_info.components["_corrade"].build_modules["cmake_find_package_multi"] = cmake_modules + + if self.options.with_main: + self.cpp_info.components["main"].set_property("cmake_target_name", "Corrade::Main") + self.cpp_info.components["main"].names["cmake_find_package"] = "Main" + self.cpp_info.components["main"].names["cmake_find_package_multi"] = "Main" + if self.settings.os == "Windows": + self.cpp_info.components["main"].libs = ["CorradeMain" + suffix] + self.cpp_info.components["main"].requires = ["_corrade"] + + if self.options.with_utility: + self.cpp_info.components["utility"].set_property("cmake_target_name", "Corrade::Utility") + self.cpp_info.components["utility"].names["cmake_find_package"] = "Utility" + self.cpp_info.components["utility"].names["cmake_find_package_multi"] = "Utility" + self.cpp_info.components["utility"].libs = ["CorradeUtility" + suffix] + if self.settings.os in ["Linux", "FreeBSD"]: + self.cpp_info.components["utility"].system_libs = ["m", "dl"] + self.cpp_info.components["utility"].requires = ["_corrade"] + + if self.options.with_interconnect: + self.cpp_info.components["interconnect"].set_property("cmake_target_name", "Corrade::Interconnect") + self.cpp_info.components["interconnect"].names["cmake_find_package"] = "Interconnect" + self.cpp_info.components["interconnect"].names["cmake_find_package_multi"] = "Interconnect" + self.cpp_info.components["interconnect"].libs = ["CorradeInterconnect" + suffix] + self.cpp_info.components["interconnect"].requires = ["utility"] + + if self.options.with_pluginmanager: + self.cpp_info.components["plugin_manager"].set_property("cmake_target_name", "Corrade::PluginManager") + self.cpp_info.components["plugin_manager"].names["cmake_find_package"] = "PluginManager" + self.cpp_info.components["plugin_manager"].names["cmake_find_package_multi"] = "PluginManager" + self.cpp_info.components["plugin_manager"].libs = ["CorradePluginManager" + suffix] + self.cpp_info.components["plugin_manager"].requires = ["utility"] + + if self.options.with_testsuite: + self.cpp_info.components["test_suite"].set_property("cmake_target_name", "Corrade::TestSuite") + self.cpp_info.components["test_suite"].names["cmake_find_package"] = "TestSuite" + self.cpp_info.components["test_suite"].names["cmake_find_package_multi"] = "TestSuite" + self.cpp_info.components["test_suite"].libs = ["CorradeTestSuite" + suffix] + self.cpp_info.components["test_suite"].requires = ["utility"] + + if self.options.with_utility: + bindir = os.path.join(self.package_folder, "bin") + self.output.info(f"Appending PATH environment variable: {bindir}") + self.env_info.PATH.append(bindir) + + for key, component in self.cpp_info.components.items(): + component.set_property("pkg_config_name", f"{self.name}_{key}") + + self.cpp_info.names["cmake_find_package"] = "Corrade" + self.cpp_info.names["cmake_find_package_multi"] = "Corrade" +``` + +- [ ] **Step 4: Create `recipes/corrade/all/cmake/conan-corrade-vars.cmake`** + +Verbatim copy of the CCI helper file: + +```cmake +# Here we are reproducing the variables and call performed by the FindCorrade.cmake provided by the library + +# Read flags from configuration +file(READ "${CMAKE_CURRENT_LIST_DIR}/../../include/Corrade/configure.h" _corradeConfigure) +string(REGEX REPLACE ";" "\\\\;" _corradeConfigure "${_corradeConfigure}") +string(REGEX REPLACE "\n" ";" _corradeConfigure "${_corradeConfigure}") +set(_corradeFlags + MSVC2015_COMPATIBILITY + MSVC2017_COMPATIBILITY + MSVC2019_COMPATIBILITY + BUILD_DEPRECATED + BUILD_STATIC + BUILD_STATIC_UNIQUE_GLOBALS + BUILD_MULTITHREADED + TARGET_UNIX + TARGET_APPLE + TARGET_IOS + TARGET_IOS_SIMULATOR + TARGET_WINDOWS + TARGET_WINDOWS_RT + TARGET_EMSCRIPTEN + TARGET_ANDROID + # TARGET_X86 etc and TARGET_LIBCXX are not exposed to CMake as the meaning + # is unclear on platforms with multi-arch binaries or when mixing different + # STL implementations. TARGET_GCC etc are figured out via UseCorrade.cmake, + # as the compiler can be different when compiling the lib & when using it. + PLUGINMANAGER_NO_DYNAMIC_PLUGIN_SUPPORT + TESTSUITE_TARGET_XCTEST + UTILITY_USE_ANSI_COLORS) +foreach(_corradeFlag ${_corradeFlags}) + list(FIND _corradeConfigure "#define CORRADE_${_corradeFlag}" _corrade_${_corradeFlag}) + if(NOT _corrade_${_corradeFlag} EQUAL -1) + set(CORRADE_${_corradeFlag} 1) + endif() +endforeach() + + +# Corrade::rc, a target with just an executable +if(NOT TARGET Corrade::rc) + if(CMAKE_CROSSCOMPILING) + find_program(CORRADE_RC_PROGRAM + NAMES corrade-rc + PATHS ENV + PATH NO_DEFAULT_PATH) + else() + find_program(CORRADE_RC_PROGRAM + NAMES corrade-rc + PATHS "${CMAKE_CURRENT_LIST_DIR}/../../bin/" + NO_DEFAULT_PATH) + endif() + + get_filename_component(CORRADE_RC_PROGRAM "${CORRADE_RC_PROGRAM}" ABSOLUTE) + + add_executable(Corrade::rc IMPORTED) + set_property(TARGET Corrade::rc PROPERTY IMPORTED_LOCATION ${CORRADE_RC_PROGRAM}) +endif() + +# Include and declare other build modules +include("${CMAKE_CURRENT_LIST_DIR}/UseCorrade.cmake") +set(CORRADE_LIB_SUFFIX_MODULE "${CMAKE_CURRENT_LIST_DIR}/CorradeLibSuffix.cmake") +``` + +- [ ] **Step 5: Verify directory structure** + +```bash +find recipes/corrade -type f | sort +``` + +Expected output: +``` +recipes/corrade/all/cmake/conan-corrade-vars.cmake +recipes/corrade/all/conandata.yml +recipes/corrade/all/conanfile.py +recipes/corrade/config.yml +``` + +- [ ] **Step 6: Commit** + +```bash +git add recipes/corrade/ +git commit -m "chore: add local Corrade Conan recipe at commit 22e7ffc6 + +Builds Corrade from master commit 22e7ffc6 which contains GCC 11+ +and Clang 14+ fixes not in the frozen corrade/2020.06 CCI package. + +Co-Authored-By: Claude Sonnet 4.6 " +``` + +--- + +## Task 3: Verify recipe builds locally + +**Files:** +- Read: `recipes/corrade/all/conanfile.py` (just created) + +- [ ] **Step 1: Detect Conan profile (if not already done)** + +```bash +conan profile detect -f +``` + +Expected: profile written to `~/.conan2/profiles/default` (or existing profile updated) + +- [ ] **Step 2: Run `conan create` for the local recipe** + +```bash +conan create recipes/corrade/all --version cci.20250327 --build=missing +``` + +Expected: output ends with something like: +``` +corrade/cci.20250327: Package '...' created +``` + +If it fails with a SHA256 mismatch, the hash in `conandata.yml` is wrong — recompute it: +```bash +curl -sL https://github.com/mosra/corrade/archive/22e7ffc6fcdeaa0df96e0d8b3d482ad6abe7dc36.tar.gz | sha256sum +``` +Then update `recipes/corrade/all/conandata.yml` with the correct value and retry. + +- [ ] **Step 3: Confirm package is in local cache** + +```bash +conan list "corrade/cci.20250327" +``` + +Expected output includes `corrade/cci.20250327`. + +--- + +## Task 4: Update main conanfile.py + +**Files:** +- Modify: `conanfile.py` (lines 11 and 40) + +- [ ] **Step 1: Update `requirements()`** + +In `conanfile.py`, change line 11: +```python +# Before +self.requires("corrade/2020.06") +# After +self.requires("corrade/cci.20250327") +``` + +- [ ] **Step 2: Update `build_requirements()`** + +In `conanfile.py`, change line 40: +```python +# Before +self.tool_requires("corrade/2020.06") +# After +self.tool_requires("corrade/cci.20250327") +``` + +- [ ] **Step 3: Verify the full conanfile looks correct** + +```bash +grep corrade conanfile.py +``` + +Expected output: +``` + self.requires("corrade/cci.20250327") + self.tool_requires("corrade/cci.20250327") +``` + +No other lines should reference `corrade`. + +- [ ] **Step 4: Verify local build resolves correctly** + +From a clean build directory: +```bash +mkdir -p build_test && cd build_test +cmake .. -DCMAKE_BUILD_TYPE=Release -DCMAKE_PROJECT_TOP_LEVEL_INCLUDES=./cmake/conan_provider.cmake +``` + +Expected: cmake configure completes without Corrade-related errors. If Conan reports `corrade/cci.20250327 not found`, re-run Task 3. + +- [ ] **Step 5: Commit** + +```bash +git add conanfile.py +git commit -m "chore: bump Corrade to local recipe cci.20250327 + +Replaces the frozen corrade/2020.06 CCI package with a local recipe +that builds from master commit 22e7ffc6 to fix GCC 11+/Clang 14+ failures. + +Co-Authored-By: Claude Sonnet 4.6 " +``` + +--- + +## Task 5: Update CI — build-develop.yml + +**Files:** +- Modify: `.github/workflows/build-develop.yml` + +There are **two jobs** in this file: `unit-tests-mac` (line 22) and `unit-tests-linux` (line 67). Both need a `conan create` step. The mac job also has a Corrade-specific cxxflag workaround (`-c=corrade/*:tools.build:cxxflags=['-include','vector']`) that should be removed since the root cause is fixed on master. + +- [ ] **Step 1: Add `conan create` step to `unit-tests-mac` job** + +After the `Detect Conan Profile` step (line ~50) and before the `Configure CMake` step (line ~52), insert: + +```yaml + - name: Bootstrap local Corrade recipe + run: conan create ${{github.workspace}}/recipes/corrade/all --version cci.20250327 --build=missing +``` + +- [ ] **Step 2: Remove the mac-specific Corrade cxxflag workaround** + +In the `Configure CMake` step of `unit-tests-mac`, the current run line is: +```yaml + run: PKG_CONFIG_PATH=${{github.workspace}}/local/lib/pkgconfig cmake $GITHUB_WORKSPACE -DCMAKE_BUILD_TYPE=$BUILD_TYPE -DCMAKE_PROJECT_TOP_LEVEL_INCLUDES=./cmake/conan_provider.cmake -DCONAN_INSTALL_ARGS="--build=missing;-c=corrade/*:tools.build:cxxflags=['-include','vector']" +``` + +Change it to: +```yaml + run: PKG_CONFIG_PATH=${{github.workspace}}/local/lib/pkgconfig cmake $GITHUB_WORKSPACE -DCMAKE_BUILD_TYPE=$BUILD_TYPE -DCMAKE_PROJECT_TOP_LEVEL_INCLUDES=./cmake/conan_provider.cmake -DCONAN_INSTALL_ARGS="--build=missing" +``` + +- [ ] **Step 3: Add `conan create` step to `unit-tests-linux` job** + +After the `Detect Conan Profile` step (or after the `Setup Conan Cache` step if there's no profile detection step in this job) and before the `Configure CMake` step (line ~89), insert: + +```yaml + - name: Bootstrap local Corrade recipe + run: conan create ${{github.workspace}}/recipes/corrade/all --version cci.20250327 --build=missing +``` + +- [ ] **Step 4: Commit** + +```bash +git add .github/workflows/build-develop.yml +git commit -m "ci: add Corrade recipe bootstrap step to build-develop workflow + +Co-Authored-By: Claude Sonnet 4.6 " +``` + +--- + +## Task 6: Update CI — build-release.yml + +**Files:** +- Modify: `.github/workflows/build-release.yml` + +- [ ] **Step 1: Add `conan create` step to `unit-tests` job** + +After the `Setup Conan Cache` step (line ~38) and before the `Configure CMake` step (line ~42), insert: + +```yaml + - name: Bootstrap local Corrade recipe + run: conan create ${{github.workspace}}/recipes/corrade/all --version cci.20250327 --build=missing +``` + +- [ ] **Step 2: Commit** + +```bash +git add .github/workflows/build-release.yml +git commit -m "ci: add Corrade recipe bootstrap step to build-release workflow + +Co-Authored-By: Claude Sonnet 4.6 " +``` + +--- + +## Task 7: Update CI — build_debug.yml + +**Files:** +- Modify: `.github/workflows/build_debug.yml` + +- [ ] **Step 1: Add `conan create` step to `code-coverage` job** + +After the `Setup Conan Cache` step (line ~30) and before the `Configure CMake` step (line ~39), insert: + +```yaml + - name: Bootstrap local Corrade recipe + run: conan create ${{github.workspace}}/recipes/corrade/all --version cci.20250327 --build=missing +``` + +- [ ] **Step 2: Commit** + +```bash +git add .github/workflows/build_debug.yml +git commit -m "ci: add Corrade recipe bootstrap step to build_debug workflow + +Co-Authored-By: Claude Sonnet 4.6 " +``` + +--- + +## Task 8: Update CI — build_cross.yml + +**Files:** +- Modify: `.github/workflows/build_cross.yml` + +The cross-compile workflow is different: `conan install` runs explicitly (line 128) before cmake. The `conan create` must run before that `conan install` step. The `conan create` here needs to use the default (build host) profile since the recipe will be consumed as a `tool_requires`. + +- [ ] **Step 1: Add `conan create` step before `Install dependencies`** + +After the `Setup Conan Cache` step (line ~118) and before the `Install dependencies` step (line ~125), insert: + +```yaml + - name: Bootstrap local Corrade recipe + working-directory: ${{github.workspace}}/src + run: conan create recipes/corrade/all --version cci.20250327 -pr:b=default --build=missing +``` + +Note: `-pr:b=default` is explicit here because the cross-compile context has both host and build profiles. The Corrade recipe will be used as `tool_requires` (build profile) so we create it with the build profile. + +- [ ] **Step 2: Commit** + +```bash +git add .github/workflows/build_cross.yml +git commit -m "ci: add Corrade recipe bootstrap step to build_cross workflow + +Co-Authored-By: Claude Sonnet 4.6 " +``` + +--- + +## Task 9: Final verification + +- [ ] **Step 1: Check all workflow files reference the bootstrap step** + +```bash +grep -l "Bootstrap local Corrade" .github/workflows/*.yml +``` + +Expected output (4 files): +``` +.github/workflows/build-develop.yml +.github/workflows/build-release.yml +.github/workflows/build_debug.yml +.github/workflows/build_cross.yml +``` + +- [ ] **Step 2: Confirm no remaining references to `corrade/2020.06`** + +```bash +grep -r "corrade/2020.06" . +``` + +Expected: no output. + +- [ ] **Step 3: Confirm local build passes tests (optional but recommended)** + +```bash +mkdir -p build_verify && cd build_verify +cmake .. -DCMAKE_BUILD_TYPE=Release -DCMAKE_PROJECT_TOP_LEVEL_INCLUDES=./cmake/conan_provider.cmake +cmake --build . -- -j4 +ctest --output-on-failure +``` + +Expected: all tests pass. + +- [ ] **Step 4: Final commit (if Step 3 required any fixes)** + +Only needed if Step 3 revealed issues that required fixes. + +```bash +git add -A +git commit -m "chore: fix post-verification issues with Corrade recipe + +Co-Authored-By: Claude Sonnet 4.6 " +``` + +--- + +## Notes for Future Maintainers + +**When Corrade `2025.0a` lands in Conan Center:** +1. Delete `recipes/corrade/` +2. In `conanfile.py`: change `cci.20250327` → `2025.0a` in both `requires` and `build_requirements` +3. In all 4 CI workflow files: remove the `Bootstrap local Corrade recipe` step +4. Commit and PR + +**If the commit `22e7ffc6` needs to be updated to a newer master commit:** +1. Compute new SHA256: `curl -sL https://github.com/mosra/corrade/archive/.tar.gz | sha256sum` +2. Update `recipes/corrade/all/conandata.yml`: change both the URL commit hash and the sha256 +3. Update the version name in `config.yml`, `conandata.yml`, `conanfile.py` (root), and all 4 CI workflow files +4. Re-run `conan create recipes/corrade/all --version --build=missing` locally to verify diff --git a/docs/superpowers/specs/2026-03-27-corrade-local-conan-recipe-design.md b/docs/superpowers/specs/2026-03-27-corrade-local-conan-recipe-design.md new file mode 100644 index 000000000..ae34a3d4e --- /dev/null +++ b/docs/superpowers/specs/2026-03-27-corrade-local-conan-recipe-design.md @@ -0,0 +1,166 @@ +# Design: Replace Conan `corrade/2020.06` with Local Recipe at Git Commit `22e7ffc6` + +**Date:** 2026-03-27 +**Status:** Approved + +--- + +## Problem + +pktvisor's build depends on `corrade/2020.06` from Conan Center Index (CCI). This version is from June 2020 and fails to compile with GCC 11/12 and Clang 14+ due to known upstream issues (#136, #164). No newer Corrade version exists in CCI (only `2020.06` and `2019.10` are published; the `2025.0a` release is ~81% complete upstream but not yet tagged). + +## Goal + +Fix the build on modern compilers with zero C++ source changes and zero CMakeLists.txt changes, while keeping Conan as the sole dependency manager. + +## Solution: A1 — Local Conan Recipe at Specific Git Commit + +Store a minimal Conan recipe inside the pktvisor repo that builds Corrade from a known-good commit on the `master` branch (`22e7ffc6fcdeaa0df96e0d8b3d482ad6abe7dc36`). This commit contains all GCC 11/12/13 and Clang 14/15/16 fixes that were merged after the 2020.06 release but never formally tagged. + +### Why this commit? + +Commit `22e7ffc6` on the Corrade `master` branch post-dates the fixes for: +- **Issue #136**: `constexpr` lambda failure with GCC 11/12 and Clang 11–14 +- **Issue #164**: `strerror_r` type mismatch on Clang 14 / FreeBSD + +No patches are needed — the fixes are baked into the source at this commit. + +### Future migration path + +When Corrade `2025.0a` is tagged and appears in Conan Center: +1. Delete `recipes/corrade/` +2. Bump the version string in `conanfile.py` from `cci.20250327` to `2025.0a` +3. Remove the `conan create` bootstrap step from CI + +--- + +## Repository Changes + +### New directory structure + +``` +recipes/corrade/ +├── all/ +│ ├── conanfile.py # Adapted from CCI (patches removed) +│ ├── conandata.yml # Points to commit tarball +│ └── cmake/ +│ └── conan-corrade-vars.cmake # Copied verbatim from CCI +└── config.yml # Declares version cci.20250327 +``` + +### `recipes/corrade/config.yml` + +```yaml +versions: + "cci.20250327": + folder: all +``` + +### `recipes/corrade/all/conandata.yml` + +```yaml +sources: + "cci.20250327": + url: "https://github.com/mosra/corrade/archive/22e7ffc6fcdeaa0df96e0d8b3d482ad6abe7dc36.tar.gz" + sha256: "" +``` + +The SHA256 must be computed during implementation by downloading the tarball once: +```bash +curl -L https://github.com/mosra/corrade/archive/22e7ffc6fcdeaa0df96e0d8b3d482ad6abe7dc36.tar.gz | sha256sum +``` + +### `recipes/corrade/all/conanfile.py` + +Based verbatim on the CCI recipe with two modifications: +1. Remove `export_conandata_patches` from `export_sources()` +2. Remove `apply_conandata_patches` from `build()` + +All other recipe logic (options, CMake variables, `package_info()` components, `UseCorrade.cmake` installation) remains identical to the CCI recipe. + +### `recipes/corrade/all/cmake/conan-corrade-vars.cmake` + +Copied verbatim from CCI. This file reads `configure.h` to extract Corrade feature flags and sets up the `Corrade::rc` imported executable target. + +--- + +## Main `conanfile.py` changes (pktvisor root) + +```python +# requirements(): +# Before: self.requires("corrade/2020.06") +self.requires("corrade/cci.20250327") + +# build_requirements(): +# Before: self.tool_requires("corrade/2020.06") +self.tool_requires("corrade/cci.20250327") +``` + +--- + +## Build Workflow + +A one-time bootstrap step must run before `conan install` in any clean environment: + +```bash +conan create recipes/corrade/all --version cci.20250327 --build=missing +``` + +After this, the normal build is unchanged: + +```bash +conan install . --build=missing -s build_type=Release +cmake -B build -DCMAKE_TOOLCHAIN_FILE=build/Release/generators/conan_toolchain.cmake +cmake --build build +``` + +The bootstrapped package is cached in `~/.conan2/` and does not need to be re-created on subsequent builds unless the cache is cleared. + +### CI changes + +Add one line before the existing `conan install` step in all CI pipeline definitions: + +```yaml +# Before conan install: +- run: conan create recipes/corrade/all --version cci.20250327 --build=missing +``` + +### Local developer setup + +Add the bootstrap command to the project's developer setup documentation (README or CONTRIBUTING). + +--- + +## What Does NOT Change + +| Artifact | Change | +|---|---| +| All `.cpp` / `.h` files | None | +| All `CMakeLists.txt` files | None | +| All plugin `.conf` files | None | +| `find_package(Corrade REQUIRED)` in root CMakeLists.txt | None | +| All `corrade_add_static_plugin()` calls | None | +| All `CORRADE_PLUGIN_REGISTER` macros | None | +| All other Conan dependencies | None | + +--- + +## Risk Assessment + +| Risk | Likelihood | Mitigation | +|---|---|---| +| `conan-corrade-vars.cmake` cmake helper incompatible with master source | Low | The file reads from `configure.h` which exists on master; same logic applies | +| GitHub commit tarball URL changes | Very low | GitHub commit-based archives are permanent | +| Master-branch Corrade API incompatible with pktvisor source | Very low | API is backward-compatible; master only adds fixes and new features | +| Cross-compilation (`tool_requires`) needs separate create step | Medium | The CCI recipe handles this via `cross_building()` check; same logic preserved | + +--- + +## Files Touched + +1. `conanfile.py` — 2 line changes (version bump in `requires` and `tool_requires`) +2. `recipes/corrade/config.yml` — new file +3. `recipes/corrade/all/conandata.yml` — new file +4. `recipes/corrade/all/conanfile.py` — new file (adapted from CCI) +5. `recipes/corrade/all/cmake/conan-corrade-vars.cmake` — new file (verbatim from CCI) +6. CI pipeline file(s) — add `conan create` bootstrap step diff --git a/recipes/corrade/all/cmake/conan-corrade-vars.cmake b/recipes/corrade/all/cmake/conan-corrade-vars.cmake new file mode 100644 index 000000000..cc7a73f98 --- /dev/null +++ b/recipes/corrade/all/cmake/conan-corrade-vars.cmake @@ -0,0 +1,60 @@ +# Here we are reproducing the variables and call performed by the FindCorrade.cmake provided by the library + +# Read flags from configuration +file(READ "${CMAKE_CURRENT_LIST_DIR}/../../include/Corrade/configure.h" _corradeConfigure) +string(REGEX REPLACE ";" "\\\\;" _corradeConfigure "${_corradeConfigure}") +string(REGEX REPLACE "\n" ";" _corradeConfigure "${_corradeConfigure}") +set(_corradeFlags + MSVC2015_COMPATIBILITY + MSVC2017_COMPATIBILITY + MSVC2019_COMPATIBILITY + BUILD_DEPRECATED + BUILD_STATIC + BUILD_STATIC_UNIQUE_GLOBALS + BUILD_MULTITHREADED + TARGET_UNIX + TARGET_APPLE + TARGET_IOS + TARGET_IOS_SIMULATOR + TARGET_WINDOWS + TARGET_WINDOWS_RT + TARGET_EMSCRIPTEN + TARGET_ANDROID + # TARGET_X86 etc and TARGET_LIBCXX are not exposed to CMake as the meaning + # is unclear on platforms with multi-arch binaries or when mixing different + # STL implementations. TARGET_GCC etc are figured out via UseCorrade.cmake, + # as the compiler can be different when compiling the lib & when using it. + PLUGINMANAGER_NO_DYNAMIC_PLUGIN_SUPPORT + TESTSUITE_TARGET_XCTEST + UTILITY_USE_ANSI_COLORS) +foreach(_corradeFlag ${_corradeFlags}) + list(FIND _corradeConfigure "#define CORRADE_${_corradeFlag}" _corrade_${_corradeFlag}) + if(NOT _corrade_${_corradeFlag} EQUAL -1) + set(CORRADE_${_corradeFlag} 1) + endif() +endforeach() + + +# Corrade::rc, a target with just an executable +if(NOT TARGET Corrade::rc) + if(CMAKE_CROSSCOMPILING) + find_program(CORRADE_RC_PROGRAM + NAMES corrade-rc + PATHS ENV + PATH NO_DEFAULT_PATH) + else() + find_program(CORRADE_RC_PROGRAM + NAMES corrade-rc + PATHS "${CMAKE_CURRENT_LIST_DIR}/../../bin/" + NO_DEFAULT_PATH) + endif() + + get_filename_component(CORRADE_RC_PROGRAM "${CORRADE_RC_PROGRAM}" ABSOLUTE) + + add_executable(Corrade::rc IMPORTED) + set_property(TARGET Corrade::rc PROPERTY IMPORTED_LOCATION ${CORRADE_RC_PROGRAM}) +endif() + +# Include and declare other build modules +include("${CMAKE_CURRENT_LIST_DIR}/UseCorrade.cmake") +set(CORRADE_LIB_SUFFIX_MODULE "${CMAKE_CURRENT_LIST_DIR}/CorradeLibSuffix.cmake") diff --git a/recipes/corrade/all/conandata.yml b/recipes/corrade/all/conandata.yml new file mode 100644 index 000000000..36bf3ad3b --- /dev/null +++ b/recipes/corrade/all/conandata.yml @@ -0,0 +1,4 @@ +sources: + "cci.20250327": + url: "https://github.com/mosra/corrade/archive/22e7ffc6fcdeaa0df96e0d8b3d482ad6abe7dc36.tar.gz" + sha256: "d8f30e9a857172003b6b02304783f40e8038c36e4127a0cfec7fe14f41c13fd4" diff --git a/recipes/corrade/all/conanfile.py b/recipes/corrade/all/conanfile.py new file mode 100644 index 000000000..1832c52b4 --- /dev/null +++ b/recipes/corrade/all/conanfile.py @@ -0,0 +1,185 @@ +import os + +from conan import ConanFile +from conan.errors import ConanInvalidConfiguration +from conan.tools.build import cross_building +from conan.tools.cmake import CMake, CMakeDeps, CMakeToolchain, cmake_layout +from conan.tools.files import copy, get, rmdir +from conan.tools.microsoft import is_msvc, check_min_vs + +required_conan_version = ">=1.52.0" + + +class CorradeConan(ConanFile): + name = "corrade" + description = "Corrade is a multiplatform utility library written in C++11/C++14." + license = "MIT" + url = "https://github.com/netboxlabs/pktvisor" + homepage = "https://magnum.graphics/corrade" + topics = ("magnum", "filesystem", "console", "environment", "os") + + package_type = "library" + settings = "os", "arch", "compiler", "build_type" + options = { + "shared": [True, False], + "fPIC": [True, False], + "build_deprecated": [True, False], + "with_interconnect": [True, False], + "with_main": [True, False], + "with_pluginmanager": [True, False], + "with_testsuite": [True, False], + "with_utility": [True, False], + } + default_options = { + "shared": False, + "fPIC": True, + "build_deprecated": True, + "with_interconnect": True, + "with_main": True, + "with_pluginmanager": True, + "with_testsuite": True, + "with_utility": True, + } + + def export_sources(self): + copy(self, "cmake/*", src=self.recipe_folder, dst=self.export_sources_folder) + + def config_options(self): + if self.settings.os == "Windows": + del self.options.fPIC + + def configure(self): + if self.options.shared: + self.options.rm_safe("fPIC") + + def layout(self): + cmake_layout(self, src_folder="src") + + def validate(self): + check_min_vs(self, 190) + if not self.options.with_utility and ( + self.options.with_testsuite or self.options.with_interconnect or self.options.with_pluginmanager + ): + raise ConanInvalidConfiguration( + "Component 'utility' is required for 'test_suite', 'interconnect' and 'plugin_manager'" + ) + + def build_requirements(self): + if hasattr(self, "settings_build") and cross_building(self, skip_x64_x86=True): + self.tool_requires(f"corrade/{self.version}") + + def source(self): + get(self, **self.conan_data["sources"][self.version], strip_root=True) + + def generate(self): + tc = CMakeToolchain(self) + tc.variables["BUILD_STATIC"] = not self.options.shared + tc.variables["BUILD_STATIC_PIC"] = self.options.get_safe("fPIC", False) + + tc.variables["BUILD_DEPRECATED"] = self.options.build_deprecated + tc.variables["WITH_INTERCONNECT"] = self.options.with_interconnect + tc.variables["WITH_MAIN"] = self.options.with_main + tc.variables["WITH_PLUGINMANAGER"] = self.options.with_pluginmanager + tc.variables["WITH_TESTSUITE"] = self.options.with_testsuite + tc.variables["WITH_UTILITY"] = self.options.with_utility + tc.variables["WITH_RC"] = self.options.with_utility + + tc.variables["LIB_SUFFIX"] = "" + + if is_msvc(self): + if check_min_vs(self, 193, raise_invalid=False): + tc.variables["MSVC2019_COMPATIBILITY"] = True + elif check_min_vs(self, 192, raise_invalid=False): + tc.variables["MSVC2017_COMPATIBILITY"] = True + elif check_min_vs(self, 191, raise_invalid=False): + tc.variables["MSVC2015_COMPATIBILITY"] = True + + tc.generate() + tc = CMakeDeps(self) + tc.generate() + + def build(self): + cmake = CMake(self) + cmake.configure() + cmake.build() + + def package(self): + copy(self, "COPYING", dst=os.path.join(self.package_folder, "licenses"), src=self.source_folder) + cmake = CMake(self) + cmake.install() + share_cmake = os.path.join(self.package_folder, "share", "cmake", "Corrade") + copy(self, "UseCorrade.cmake", + src=share_cmake, + dst=os.path.join(self.package_folder, "lib", "cmake")) + copy(self, "CorradeLibSuffix.cmake", + src=share_cmake, + dst=os.path.join(self.package_folder, "lib", "cmake")) + copy(self, "*.cmake", + src=os.path.join(self.export_sources_folder, "cmake"), + dst=os.path.join(self.package_folder, "lib", "cmake")) + rmdir(self, os.path.join(self.package_folder, "share")) + + def package_info(self): + self.cpp_info.set_property("cmake_find_mode", "both") + self.cpp_info.set_property("cmake_file_name", "Corrade") + self.cpp_info.set_property("cmake_target_name", "Corrade::Corrade") + + suffix = "-d" if self.settings.build_type == "Debug" else "" + + cmake_modules = [ + os.path.join("lib", "cmake", "conan-corrade-vars.cmake"), + os.path.join("lib", "cmake", "CorradeLibSuffix.cmake"), + os.path.join("lib", "cmake", "UseCorrade.cmake"), + ] + self.cpp_info.set_property("cmake_build_modules", cmake_modules) + self.cpp_info.components["_corrade"].build_modules["cmake_find_package"] = cmake_modules + self.cpp_info.components["_corrade"].build_modules["cmake_find_package_multi"] = cmake_modules + + if self.options.with_main: + self.cpp_info.components["main"].set_property("cmake_target_name", "Corrade::Main") + self.cpp_info.components["main"].names["cmake_find_package"] = "Main" + self.cpp_info.components["main"].names["cmake_find_package_multi"] = "Main" + if self.settings.os == "Windows": + self.cpp_info.components["main"].libs = ["CorradeMain" + suffix] + self.cpp_info.components["main"].requires = ["_corrade"] + + if self.options.with_utility: + self.cpp_info.components["utility"].set_property("cmake_target_name", "Corrade::Utility") + self.cpp_info.components["utility"].names["cmake_find_package"] = "Utility" + self.cpp_info.components["utility"].names["cmake_find_package_multi"] = "Utility" + self.cpp_info.components["utility"].libs = ["CorradeUtility" + suffix] + if self.settings.os in ["Linux", "FreeBSD"]: + self.cpp_info.components["utility"].system_libs = ["m", "dl"] + self.cpp_info.components["utility"].requires = ["_corrade"] + + if self.options.with_interconnect: + self.cpp_info.components["interconnect"].set_property("cmake_target_name", "Corrade::Interconnect") + self.cpp_info.components["interconnect"].names["cmake_find_package"] = "Interconnect" + self.cpp_info.components["interconnect"].names["cmake_find_package_multi"] = "Interconnect" + self.cpp_info.components["interconnect"].libs = ["CorradeInterconnect" + suffix] + self.cpp_info.components["interconnect"].requires = ["utility"] + + if self.options.with_pluginmanager: + self.cpp_info.components["plugin_manager"].set_property("cmake_target_name", "Corrade::PluginManager") + self.cpp_info.components["plugin_manager"].names["cmake_find_package"] = "PluginManager" + self.cpp_info.components["plugin_manager"].names["cmake_find_package_multi"] = "PluginManager" + self.cpp_info.components["plugin_manager"].libs = ["CorradePluginManager" + suffix] + self.cpp_info.components["plugin_manager"].requires = ["utility"] + + if self.options.with_testsuite: + self.cpp_info.components["test_suite"].set_property("cmake_target_name", "Corrade::TestSuite") + self.cpp_info.components["test_suite"].names["cmake_find_package"] = "TestSuite" + self.cpp_info.components["test_suite"].names["cmake_find_package_multi"] = "TestSuite" + self.cpp_info.components["test_suite"].libs = ["CorradeTestSuite" + suffix] + self.cpp_info.components["test_suite"].requires = ["utility"] + + if self.options.with_utility: + bindir = os.path.join(self.package_folder, "bin") + self.output.info(f"Appending PATH environment variable: {bindir}") + self.env_info.PATH.append(bindir) + + for key, component in self.cpp_info.components.items(): + component.set_property("pkg_config_name", f"{self.name}_{key}") + + self.cpp_info.names["cmake_find_package"] = "Corrade" + self.cpp_info.names["cmake_find_package_multi"] = "Corrade" diff --git a/recipes/corrade/config.yml b/recipes/corrade/config.yml new file mode 100644 index 000000000..397b32480 --- /dev/null +++ b/recipes/corrade/config.yml @@ -0,0 +1,3 @@ +versions: + "cci.20250327": + folder: all diff --git a/recipes/pcapplusplus/cmake/conandata.yml b/recipes/pcapplusplus/cmake/conandata.yml new file mode 100644 index 000000000..26ff7631c --- /dev/null +++ b/recipes/pcapplusplus/cmake/conandata.yml @@ -0,0 +1,4 @@ +sources: + "23.09": + url: "https://github.com/seladb/PcapPlusPlus/archive/v23.09.tar.gz" + sha256: "608292f7d2a2e1b7af26adf89347597a6131547eea4e513194bc4f584a40fe74" diff --git a/recipes/pcapplusplus/cmake/conanfile.py b/recipes/pcapplusplus/cmake/conanfile.py new file mode 100644 index 000000000..f5591a560 --- /dev/null +++ b/recipes/pcapplusplus/cmake/conanfile.py @@ -0,0 +1,124 @@ +import os +from conan import ConanFile +from conan.tools.build import check_min_cppstd +from conan.tools.cmake import CMakeToolchain, CMake, cmake_layout, CMakeDeps +from conan.tools.files import copy, get, rmdir, replace_in_file +from conan.tools.scm import Version +from conan.errors import ConanInvalidConfiguration + + +required_conan_version = ">=2" + + +class PcapplusplusConan(ConanFile): + name = "pcapplusplus" + license = "Unlicense" + description = "PcapPlusPlus is a multiplatform C++ library for capturing, parsing and crafting of network packets" + topics = ("pcap", "network", "security", "packet") + url = "https://github.com/netboxlabs/pktvisor" + homepage = "https://github.com/seladb/PcapPlusPlus" + settings = "os", "arch", "build_type", "compiler" + package_type = "library" + options = { + "fPIC": [True, False], + "shared": [True, False], + "immediate_mode": [True, False], + } + default_options = { + "fPIC": True, + "shared": False, + "immediate_mode": False, + } + + implements = ["auto_shared_fpic"] + + def requirements(self): + if self.settings.os == "Windows": + self.requires("npcap/1.70") + else: + self.requires("libpcap/1.10.1") + + def validate(self): + if Version(self.version) <= "25.05" and self.options.shared and self.settings.os == "Windows": + raise ConanInvalidConfiguration(f"{self.ref} does not support Windows shared builds for now") + check_min_cppstd(self, 11) + if self.settings.os not in ("FreeBSD", "Linux", "Macos", "Windows"): + raise ConanInvalidConfiguration(f"{self.settings.os} is not supported") + + def validate_build(self): + compiler_version = Version(self.settings.compiler.version) + if self.settings.compiler == "gcc" and compiler_version < "5.1": + raise ConanInvalidConfiguration("PcapPlusPlus requires GCC >= 5.1") + + def source(self): + get(self, **self.conan_data["sources"][self.version], strip_root=True) + self._patch_sources() + + def generate(self): + deps = CMakeDeps(self) + deps.generate() + tc = CMakeToolchain(self) + tc.cache_variables["PCAPPP_BUILD_TESTS"] = False + tc.cache_variables["PCAPPP_BUILD_EXAMPLES"] = False + tc.cache_variables["BUILD_SHARED_LIBS"] = self.options.shared + tc.generate() + + def layout(self): + cmake_layout(self, src_folder="src") + + def _patch_sources(self): + replace_in_file(self, os.path.join(self.source_folder, "CMakeLists.txt"), + "set(CMAKE_CXX_STANDARD 11)", + "") + # Fix VLA in PcapLiveDevice.cpp for Clang 17+ (macOS/FreeBSD) + # uint8_t buf[len] is a VLA which is an error in standard C++ + pcap_live = os.path.join(self.source_folder, "Pcap++", "src", "PcapLiveDevice.cpp") + replace_in_file(self, pcap_live, + '#include "IpUtils.h"', + '#include "IpUtils.h"\n#include ') + replace_in_file(self, pcap_live, + "uint8_t buf[len];", + "std::vector buf(len);") + replace_in_file(self, pcap_live, + "if (sysctl(mib, 6, buf, &len, nullptr, 0) < 0)", + "if (sysctl(mib, 6, buf.data(), &len, nullptr, 0) < 0)") + replace_in_file(self, pcap_live, + "struct if_msghdr*ifm = (struct if_msghdr *)buf;", + "struct if_msghdr*ifm = (struct if_msghdr *)buf.data();") + + def build(self): + cmake = CMake(self) + cmake.configure() + cmake.build() + + def package(self): + copy(self, "LICENSE", src=self.source_folder, dst=os.path.join(self.package_folder, "licenses"), keep_path=False) + cmake = CMake(self) + cmake.install() + rmdir(self, os.path.join(self.package_folder, "lib", "cmake")) + rmdir(self, os.path.join(self.package_folder, "lib", "pkgconfig")) + + def package_info(self): + self.cpp_info.set_property("cmake_file_name", "PcapPlusPlus") + self.cpp_info.set_property("cmake_target_name", "PcapPlusPlus::PcapPlusPlus") + + self.cpp_info.components["common"].libs = ["Common++"] + if self.settings.os == "Windows": + self.cpp_info.components["common"].system_libs = ["ws2_32", "iphlpapi"] + + self.cpp_info.components["packet"].libs = ["Packet++"] + self.cpp_info.components["packet"].requires = ["common"] + + self.cpp_info.components["pcap"].libs = ["Pcap++"] + self.cpp_info.components["pcap"].requires = ["common", "packet"] + if self.settings.os == "Windows": + self.cpp_info.components["pcap"].requires.append("npcap::npcap") + self.cpp_info.components["pcap"].system_libs = ["ws2_32", "iphlpapi"] + self.cpp_info.components["pcap"].defines = ["WPCAP", "HAVE_REMOTE"] + else: + self.cpp_info.components["pcap"].requires.append("libpcap::libpcap") + + if self.settings.os == "Macos": + self.cpp_info.components["pcap"].frameworks = ["CoreFoundation", "SystemConfiguration"] + elif self.settings.os in ("Linux", "FreeBSD"): + self.cpp_info.components["pcap"].system_libs = ["pthread"] diff --git a/recipes/pcapplusplus/config.yml b/recipes/pcapplusplus/config.yml new file mode 100644 index 000000000..768eb5242 --- /dev/null +++ b/recipes/pcapplusplus/config.yml @@ -0,0 +1,3 @@ +versions: + "23.09": + folder: cmake diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index e1d8db50d..4ca6003d8 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -45,7 +45,7 @@ target_link_libraries(visor-core datasketches rng timer - opentelemetry-cpp::opentelemetry_proto + opentelemetry-cpp::proto protobuf::libprotobuf maxminddb::maxminddb Corrade::Corrade @@ -89,4 +89,4 @@ target_link_libraries(unit-tests-visor-core add_test(NAME unit-tests-visor-core WORKING_DIRECTORY ${PROJECT_SOURCE_DIR}/src - COMMAND unit-tests-visor-core) \ No newline at end of file + COMMAND unit-tests-visor-core)