diff --git a/.devcontainer/devcontainer.json b/.devcontainer/devcontainer.json index b8dd32653..080c352da 100644 --- a/.devcontainer/devcontainer.json +++ b/.devcontainer/devcontainer.json @@ -14,7 +14,7 @@ ], "containerEnv": { "CONAN_PROFILE": "debug", - "CONAN_OPTS": "--options celix/*:build_all=True -o celix/*:enable_address_sanitizer=True -o celix/*:enable_testing=True -o celix/*:enable_ccache=True -o celix/*:enable_code_coverage=True", + "CONAN_OPTS": "--options celix/*:build_all=True -o celix/*:enable_address_sanitizer=True -o celix/*:enable_testing=True -o celix/*:enable_ccache=True -o celix/*:enable_code_coverage=True -o mosquitto/*:broker=True -o *:shared=True", "CONAN_CONF": "--conf tools.cmake.cmaketoolchain:generator=Ninja", }, "securityOpt": [ diff --git a/.github/workflows/conan_create.yml b/.github/workflows/conan_create.yml index 308e35b67..9e4ec651c 100644 --- a/.github/workflows/conan_create.yml +++ b/.github/workflows/conan_create.yml @@ -66,13 +66,13 @@ jobs: CC: ${{ matrix.compiler[0] }} CXX: ${{ matrix.compiler[1] }} run: | - conan create . -c tools.cmake.cmaketoolchain:generator=Ninja -b missing -o celix/*:build_all=True -o celix/*:enable_ccache=True -pr:b default -pr:h default -s:h build_type=${{ matrix.type }} -o celix/*:celix_cxx17=True -o celix/*:celix_install_deprecated_api=True + conan create . -c tools.cmake.cmaketoolchain:generator=Ninja -b missing -o celix/*:build_all=True -o celix/*:enable_ccache=True -pr:b default -pr:h default -s:h build_type=${{ matrix.type }} -o celix/*:celix_cxx17=True -o celix/*:celix_install_deprecated_api=True -o mosquitto/*:broker=True -o *:shared=True - name: Dependency Deduction Test env: CC: ${{ matrix.compiler[0] }} CXX: ${{ matrix.compiler[1] }} run: | - conan inspect . | awk 'BEGIN { FS="[\t:]+"; output=0 } /build/ && !/build_all/ { if(output) print $1} /^options/ {output=1} /^options_definitions/ {output=0}' | while read option; do conan build . -c tools.cmake.cmaketoolchain:generator=Ninja -b missing -o celix/*:${option}=True -pr:b default -pr:h default -s:h build_type=${{ matrix.type }} -of ${option}_dir -o celix/*:celix_cxx17=True -o celix/*:enable_ccache=True -o celix/*:celix_install_deprecated_api=True || exit 1; done + conan inspect . | awk 'BEGIN { FS="[\t:]+"; output=0 } /build/ && !/build_all/ { if(output) print $1} /^options/ {output=1} /^options_definitions/ {output=0}' | while read option; do conan build . -c tools.cmake.cmaketoolchain:generator=Ninja -b missing -o celix/*:${option}=True -pr:b default -pr:h default -s:h build_type=${{ matrix.type }} -of ${option}_dir -o celix/*:celix_cxx17=True -o celix/*:enable_ccache=True -o celix/*:celix_install_deprecated_api=True -o mosquitto/*:broker=True -o *:shared=True || exit 1; done - name: Remove Celix run: | conan remove -c celix/* @@ -116,10 +116,10 @@ jobs: ${{ runner.os }}-ccache-Release- - name: Create Celix run: | - conan create . -c tools.cmake.cmaketoolchain:generator=Ninja -b missing -o celix/*:build_all=True -o celix/*:enable_ccache=True -pr:b default -pr:h default -s:b build_type=Release -s:h build_type=Release -o celix/*:celix_cxx17=True -o celix/*:celix_install_deprecated_api=True -o celix/*:enable_address_sanitizer=True + conan create . -c tools.cmake.cmaketoolchain:generator=Ninja -b missing -o celix/*:build_all=True -o celix/*:enable_ccache=True -pr:b default -pr:h default -s:b build_type=Release -s:h build_type=Release -o celix/*:celix_cxx17=True -o celix/*:celix_install_deprecated_api=True -o celix/*:enable_address_sanitizer=True -o mosquitto/*:broker=True -o *:shared=True - name: Dependency Deduction Test run: | - conan inspect . | awk 'BEGIN { FS="[\t:]+"; output=0 } /build/ && !/build_all/ && !/build_rsa_remote_service_admin_shm_v2/ && !/build_rsa_discovery_zeroconf/ { if(output) print $1} /^options/ {output=1} /^options_definitions/ {output=0}' | while read option; do conan build . -c tools.cmake.cmaketoolchain:generator=Ninja -b missing -o celix/*:${option}=True -pr:b default -pr:h default -s:b build_type=Release -s:h build_type=Release -of ${option}_dir -o celix/*:celix_cxx17=True -o celix/*:enable_ccache=True -o celix/*:celix_install_deprecated_api=True || exit 1; done + conan inspect . | awk 'BEGIN { FS="[\t:]+"; output=0 } /build/ && !/build_all/ && !/build_rsa_remote_service_admin_shm_v2/ && !/build_rsa_discovery_zeroconf/ { if(output) print $1} /^options/ {output=1} /^options_definitions/ {output=0}' | while read option; do conan build . -c tools.cmake.cmaketoolchain:generator=Ninja -b missing -o celix/*:${option}=True -pr:b default -pr:h default -s:b build_type=Release -s:h build_type=Release -of ${option}_dir -o celix/*:celix_cxx17=True -o celix/*:enable_ccache=True -o celix/*:celix_install_deprecated_api=True -o mosquitto/*:broker=True -o *:shared=True || exit 1; done - name: Remove Celix run: | conan remove -c celix/* diff --git a/.github/workflows/containers.yml b/.github/workflows/containers.yml index c59fd9a9e..a4c4adae8 100644 --- a/.github/workflows/containers.yml +++ b/.github/workflows/containers.yml @@ -42,6 +42,7 @@ jobs: conan build . -pr:b release -pr:h debug --build=missing \ --options celix/*:build_all=True --options celix/*:enable_address_sanitizer=True \ --options celix/*:enable_testing=True --options celix/*:enable_ccache=True \ + -o mosquitto/*:broker=True -o *:shared=True \ --conf:build tools.cmake.cmaketoolchain:generator=Ninja" - name: Test Celix run: | diff --git a/.github/workflows/coverage.yml b/.github/workflows/coverage.yml index 1813ec9bc..831df12ca 100644 --- a/.github/workflows/coverage.yml +++ b/.github/workflows/coverage.yml @@ -62,6 +62,8 @@ jobs: -o celix/*:enable_code_coverage=True -o celix/*:enable_testing_on_ci=True -o celix/*:enable_ccache=True + -o mosquitto/*:broker=True + -o *:shared=True run: | conan build . -pr:b release -pr:h default ${CONAN_BUILD_OPTIONS} -b missing - name: Test with coverage diff --git a/.github/workflows/fuzzing.yml b/.github/workflows/fuzzing.yml index f78916085..3cce6f245 100644 --- a/.github/workflows/fuzzing.yml +++ b/.github/workflows/fuzzing.yml @@ -41,6 +41,7 @@ jobs: -o celix/*:enable_address_sanitizer=True -o celix/*:enable_undefined_sanitizer=True -o celix/*:celix_err_buffer_size=5120 + -o *:shared=True run: conan build -c tools.cmake.cmaketoolchain:generator=Ninja ${CONAN_BUILD_OPTIONS} -b missing - name: Set fuzzer run time id: set-runtime diff --git a/.github/workflows/macos.yml b/.github/workflows/macos.yml index 806ee35bd..cf4420b50 100644 --- a/.github/workflows/macos.yml +++ b/.github/workflows/macos.yml @@ -63,6 +63,8 @@ jobs: -o celix/*:enable_testing_on_ci=True -o celix/*:framework_curlinit=False -o celix/*:enable_ccache=True + -o mosquitto/*:broker=True + -o *:shared=True run: | conan build . -c tools.cmake.cmaketoolchain:generator=Ninja -pr:b default -pr:h default -s:b build_type=Release -s:h build_type=Release ${CONAN_BUILD_OPTIONS} -b missing - name: Test diff --git a/.github/workflows/ubuntu.yml b/.github/workflows/ubuntu.yml index 184c830b8..42282a7d8 100644 --- a/.github/workflows/ubuntu.yml +++ b/.github/workflows/ubuntu.yml @@ -81,6 +81,8 @@ jobs: -o celix/*:enable_testing_on_ci=True -o celix/*:framework_curlinit=False -o celix/*:enable_ccache=True + -o mosquitto/*:broker=True + -o *:shared=True run: | conan build . -c tools.cmake.cmaketoolchain:generator=Ninja -pr:b release -pr:h default ${CONAN_BUILD_OPTIONS} -b missing - name: Test diff --git a/conanfile.py b/conanfile.py index 7a12b5a57..711b96199 100644 --- a/conanfile.py +++ b/conanfile.py @@ -141,6 +141,67 @@ def validate(self): self.validate_config_option_is_positive_number("celix_properties_optimization_string_buffer_size") self.validate_config_option_is_positive_number("celix_properties_optimization_entries_buffer_size") + # Helper function to safely get dependency option value + def _get_dependency_option_value(self, dep_name, option_name): + """Safely get dependency option value, handling get_safe vs direct attribute access""" + if dep_name in self.dependencies: + dep = self.dependencies[dep_name] + # First try get_safe, if that fails try direct attribute access + value = dep.options.get_safe(option_name) + if value is None: + # Try direct attribute access + try: + value = getattr(dep.options, option_name) + except AttributeError: + # Option does not exist + return None + return value + return None + + # Validate dependency shared options based on Celix options + # Split OR conditions into individual checks with detailed error messages + from collections import namedtuple + + ValidationRule = namedtuple('ValidationRule', ['condition', 'dep_name', 'option_name', 'expected_value', 'condition_desc']) + + validation_rules = [ + ValidationRule(self.options.build_utils, 'libzip', "shared", True, 'build_utils=True'), + ValidationRule(self.options.build_utils, 'libuv', "shared", True, 'build_utils=True'), + ValidationRule(self.options.build_framework, 'util-linux-libuuid', "shared", True, 'build_framework=True'), + ValidationRule(self.options.build_framework and self.options.framework_curlinit, 'libcurl', "shared", True, 'build_framework=True and framework_curlinit=True'), + ValidationRule(self.options.build_framework and self.options.framework_curlinit, 'openssl', "shared", True, 'build_framework=True and framework_curlinit=True'), + ValidationRule(self.options.build_celix_etcdlib, 'libcurl', "shared", True, 'build_celix_etcdlib=True'), + ValidationRule(self.options.build_celix_etcdlib, 'openssl', "shared", True, 'build_celix_etcdlib=True'), + ValidationRule(self.options.build_rsa_discovery_common, 'libcurl', "shared", True, 'build_rsa_discovery_common=True'), + ValidationRule(self.options.build_rsa_discovery_common, 'openssl', "shared", True, 'build_rsa_discovery_common=True'), + ValidationRule(self.options.build_rsa_remote_service_admin_dfi, 'libcurl', "shared", True, 'build_rsa_remote_service_admin_dfi=True'), + ValidationRule(self.options.build_rsa_remote_service_admin_dfi, 'openssl', "shared", True, 'build_rsa_remote_service_admin_dfi=True'), + ValidationRule(self.options.build_launcher, 'libcurl', "shared", True, 'build_launcher=True'), + ValidationRule(self.options.build_launcher, 'openssl', "shared", True, 'build_launcher=True'), + ValidationRule(self.options.enable_testing, 'gtest', "shared", True, 'enable_testing=True'), + ValidationRule(self.options.enable_benchmarking, 'benchmark', "shared", True, 'enable_benchmarking=True'), + ValidationRule(self.options.build_rsa_discovery_common, 'libxml2', "shared", True, 'build_rsa_discovery_common=True'), + ValidationRule(self.options.build_rsa_remote_service_admin_dfi and self.options.enable_testing, 'libxml2', "shared", True, 'build_rsa_remote_service_admin_dfi=True and enable_testing=True'), + ValidationRule(self.options.build_http_admin, 'civetweb', "shared", True, 'build_http_admin=True'), + ValidationRule(self.options.build_http_admin, 'openssl', "shared", True, 'build_http_admin=True'), + ValidationRule(self.options.build_rsa_discovery_common, 'civetweb', "shared", True, 'build_rsa_discovery_common=True'), + ValidationRule(self.options.build_rsa_discovery_common, 'openssl', "shared", True, 'build_rsa_discovery_common=True'), + ValidationRule(self.options.build_rsa_remote_service_admin_dfi, 'civetweb', "shared", True, 'build_rsa_remote_service_admin_dfi=True'), + ValidationRule(self.options.build_rsa_remote_service_admin_dfi, 'openssl', "shared", True, 'build_rsa_remote_service_admin_dfi=True'), + ValidationRule(self.options.build_celix_dfi, 'libffi', "shared", True, 'build_celix_dfi=True'), + ValidationRule(self.options.build_utils, 'jansson', "shared", True, 'build_utils=True'), + ValidationRule(self.options.build_celix_dfi, 'jansson', "shared", True, 'build_celix_dfi=True'), + ValidationRule(self.options.build_celix_etcdlib, 'jansson', "shared", True, 'build_celix_etcdlib=True'), + ValidationRule(self.options.build_event_admin_remote_provider_mqtt, 'jansson', "shared", True, 'build_event_admin_remote_provider_mqtt=True'), + ValidationRule(self.options.build_event_admin_remote_provider_mqtt and self.options.enable_testing, "mosquitto", "broker", True, "build_event_admin_remote_provider_mqtt=True and enable_testing=True"), + ] + + for rule in validation_rules: + if rule.condition and rule.dep_name in self.dependencies: + actual_value = _get_dependency_option_value(self, rule.dep_name, rule.option_name) + if actual_value is not None and actual_value != rule.expected_value: + raise ConanInvalidConfiguration(f"Celix configuration `{rule.condition_desc}` requires {rule.dep_name}/*:{rule.option_name}={rule.expected_value}") + def package_id(self): del self.info.options.build_all # the followings are not installed @@ -304,39 +365,6 @@ def configure(self): setattr(self.options, opt, options[opt]) del options - # Conan 2 does not support set dependency option in requirements() - # https://github.com/conan-io/conan/issues/14528#issuecomment-1685344080 - if self.options.build_utils: - self.options['libzip'].shared = True - self.options['libuv'].shared = True - if self.options.build_framework: - self.options['util-linux-libuuid'].shared = True - if ((self.options.build_framework and self.options.framework_curlinit) - or self.options.build_celix_etcdlib - or self.options.build_rsa_discovery_common or self.options.build_rsa_remote_service_admin_dfi - or self.options.build_launcher): - self.options['libcurl'].shared = True - self.options['openssl'].shared = True - if self.options.enable_testing: - self.options['gtest'].shared = True - if self.options.enable_benchmarking: - self.options['benchmark'].shared = True - if (self.options.build_rsa_discovery_common - or (self.options.build_rsa_remote_service_admin_dfi and self.options.enable_testing)): - self.options['libxml2'].shared = True - if self.options.build_http_admin or self.options.build_rsa_discovery_common \ - or self.options.build_rsa_remote_service_admin_dfi: - self.options['civetweb'].shared = True - self.options['openssl'].shared = True - if self.options.build_celix_dfi: - self.options['libffi'].shared = True - if self.options.build_utils or self.options.build_celix_dfi or self.options.build_celix_etcdlib or self.options.build_event_admin_remote_provider_mqtt: - self.options['jansson'].shared = True - if self.options.build_event_admin_remote_provider_mqtt: - self.options['mosquitto'].shared = True - if self.options.enable_testing: - self.options['mosquitto'].broker = True - def requirements(self): if self.options.build_utils: self.requires("libzip/[>=1.7.3 <2.0.0]") @@ -371,7 +399,7 @@ def requirements(self): self.requires("zlib/1.3.1", override=True) if self.options.build_event_admin_remote_provider_mqtt: self.requires("mosquitto/[>=2.0.3 <3.0.0]") - self.validate() + def layout(self): cmake_layout(self) @@ -425,7 +453,5 @@ def package_info(self): # enable imports() of conanfile.py to collect bundles from the local cache using @bindirs # check https://docs.conan.io/en/latest/reference/conanfile/methods.html#imports self.cpp_info.bindirs = ["bin", os.path.join("share", self.name, "bundles")] - self.cpp_info.build_modules["cmake"].append(os.path.join("lib", "cmake", "Celix", "CelixConfig.cmake")) - self.cpp_info.build_modules["cmake_find_package"].append(os.path.join("lib", "cmake", - "Celix", "CelixConfig.cmake")) - self.cpp_info.set_property("cmake_build_modules", [os.path.join("lib", "cmake", "Celix", "CelixConfig.cmake")]) + self.cpp_info.builddirs.append(os.path.join("lib", "cmake", "Celix")) + self.cpp_info.set_property("cmake_find_mode", "none") diff --git a/documents/building/README.md b/documents/building/README.md index 7e27d2a95..16391b8ac 100644 --- a/documents/building/README.md +++ b/documents/building/README.md @@ -86,6 +86,8 @@ conan install . --build=missing --profile:build default --profile:host debug \ -o "celix/*:build_all=True" \ -o "celix/*:enable_testing=True" \ -o "celix/*:enable_ccache=True" \ + -o "mosquitto/*:broker=True" \ + -o "*:shared=True" \ --conf tools.cmake.cmaketoolchain:generator=Ninja ``` @@ -110,7 +112,8 @@ For example, to only build the framework and utils libraries: ```bash conan install . --build=missing --profile:build default --profile:host debug \ -o "celix/*:build_framework=True" \ - -o "celix/*:build_utils=True" + -o "celix/*:build_utils=True" \ + -o "*:shared=True" cmake --build --preset conan-debug --parallel ``` diff --git a/documents/building/dev_celix_with_clion.md b/documents/building/dev_celix_with_clion.md index 3b0273805..cab8666be 100644 --- a/documents/building/dev_celix_with_clion.md +++ b/documents/building/dev_celix_with_clion.md @@ -21,7 +21,7 @@ limitations under the License. # Building and Developing Apache Celix with CLion Apache Celix can be build for development in CLion with use of the Conan package manager. -Conan will arrange the building of the Apache Celix dependencies and generate Find files for these dependencies. +Conan will arrange the building of the Apache Celix dependencies and generate config package files for these dependencies. Conan will also generate a `conanrun.sh` and `deactivate_conanrun.sh` script that does the environment (de)setup for the binary locations of the build dependencies (i.e. configures `PATH` and `LD_LIBRARY_PATH`/`DYLD_LIBRARY_PATH`). @@ -41,34 +41,20 @@ git clone https://github.com/apache/celix.git cd celix #if needed setup conan default and debug profile -conan profile new default --detect -conan profile new debug --detect -conan profile update settings.build_type=Debug debug +conan profile detect -f +conan profile detect -f --name debug +sed -i 's/build_type=Release/build_type=Debug/g' `conan profile path debug` -# Generate and configure cmake-build-debug directory -# If CLion's CMake Preset Integration has been enabled, then CLion will load available CMake profiles -# from the CMakeUserPresets.json file at the project root, which is generated by `conan install`. -conan install . celix/2.3.0 -pr:b default -pr:h debug -if cmake-build-debug/ -o celix:enable_testing=True -o celix:enable_address_sanitizer=True -o celix:build_all=True -b missing - -#optional build -conan build . -bf cmake-build-debug/ +conan build . -pr:b default -pr:h debug -o celix/*:enable_testing=True -o celix/*:enable_address_sanitizer=True -o celix/*:build_all=True -o mosquitto/*:broker=True -o *:shared=True -b missing #optional setup run env and run tests -cd cmake-build-debug -source conanrun.sh -ctest --verbose -source deactivate_conanrun.sh +ctest --preset conan-debug --verbose ``` -### Work with Conan 2 - -The above is for Conan 1.x. -Conan 2 has greatly simplified its integration with CLion. -Issuing the following command will produce a CMakeUserPresets.json at the project root, which CLion will load automatically to set up CMake profiles. -Then Celix can be built within the IDE. +Alternatively, issuing the following command will produce a CMakeUserPresets.json at the project root, which CLion will load automatically to set up CMake profiles, without actually building the project. Then Celix can be built within the IDE. ```shell -conan install . -pr:b default -pr:h default -s:h build_type=Debug -o celix/*:build_all=True -o celix/*:celix_cxx17=True -o celix/*:enable_testing=True -b missing -o celix/*:enable_address_sanitizer=True -of cmake-build-debug +conan install . -pr:b default -pr:h default -s:h build_type=Debug -o celix/*:build_all=True -o celix/*:celix_cxx17=True -o celix/*:enable_testing=True -b missing -o celix/*:enable_address_sanitizer=True -o mosquitto/*:broker=True -o *:shared=True ``` ## Configuring CLion @@ -78,7 +64,7 @@ This can be done under the menu "Run->Edit Configurations...", then select "Edit then update the "Google Test" template so that the `conanrun.sh` Conan generated script is sourced in the "Environment variables" entry. -If the Apache Celix CMake build directory is `home/joe/workspace/celix/cmake-build-debug` then the value for -"Environment variables" should be: `source /home/joe/workspace/celix/cmake-build-debug/conanrun.sh` +If the Apache Celix CMake build directory is `home/joe/workspace/celix/build/Debug` then the value for +"Environment variables" should be: `source /home/joe/workspace/celix/build/Debug/generators/conanrun.sh` ![Configure CLion](media/clion_run_configuration_template.png)