This is an automated email from the ASF dual-hosted git repository.

pengzheng pushed a commit to branch feature/option-conflict-detection
in repository https://gitbox.apache.org/repos/asf/celix.git

commit b30e173db9e3136d99f3b4dba6c192a17abf4337
Author: PengZheng <[email protected]>
AuthorDate: Fri Mar 13 16:31:24 2026 +0800

    Implement dependencies option conflict detection.
    
    Replace expensive and broken dependencies option deduction with conflict 
detection, following the suggestions given in 
https://github.com/conan-io/conan/issues/19692
---
 .devcontainer/devcontainer.json            |  2 +-
 .github/workflows/conan_create.yml         |  8 +--
 .github/workflows/containers.yml           |  1 +
 .github/workflows/coverage.yml             |  2 +
 .github/workflows/fuzzing.yml              |  1 +
 .github/workflows/macos.yml                |  2 +
 .github/workflows/ubuntu.yml               |  2 +
 conanfile.py                               | 96 +++++++++++++++++++-----------
 documents/building/README.md               |  5 +-
 documents/building/dev_celix_with_clion.md | 34 ++++-------
 10 files changed, 89 insertions(+), 64 deletions(-)

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/*: [...]
       - 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=Tru [...]
+          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=Tru [...]
       - 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..0216a54f2 100644
--- a/conanfile.py
+++ b/conanfile.py
@@ -141,6 +141,67 @@ class CelixConan(ConanFile):
         
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 @@ class CelixConan(ConanFile):
             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 @@ class CelixConan(ConanFile):
         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)
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<package> 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)

Reply via email to