Skip to content

Commit b30e173

Browse files
committed
Implement dependencies option conflict detection.
Replace expensive and broken dependencies option deduction with conflict detection, following the suggestions given in conan-io/conan#19692
1 parent 36ce8b1 commit b30e173

10 files changed

Lines changed: 89 additions & 64 deletions

File tree

.devcontainer/devcontainer.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@
1414
],
1515
"containerEnv": {
1616
"CONAN_PROFILE": "debug",
17-
"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",
17+
"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",
1818
"CONAN_CONF": "--conf tools.cmake.cmaketoolchain:generator=Ninja",
1919
},
2020
"securityOpt": [

.github/workflows/conan_create.yml

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -66,13 +66,13 @@ jobs:
6666
CC: ${{ matrix.compiler[0] }}
6767
CXX: ${{ matrix.compiler[1] }}
6868
run: |
69-
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
69+
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
7070
- name: Dependency Deduction Test
7171
env:
7272
CC: ${{ matrix.compiler[0] }}
7373
CXX: ${{ matrix.compiler[1] }}
7474
run: |
75-
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
75+
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
7676
- name: Remove Celix
7777
run: |
7878
conan remove -c celix/*
@@ -116,10 +116,10 @@ jobs:
116116
${{ runner.os }}-ccache-Release-
117117
- name: Create Celix
118118
run: |
119-
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
119+
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
120120
- name: Dependency Deduction Test
121121
run: |
122-
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
122+
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
123123
- name: Remove Celix
124124
run: |
125125
conan remove -c celix/*

.github/workflows/containers.yml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,7 @@ jobs:
4242
conan build . -pr:b release -pr:h debug --build=missing \
4343
--options celix/*:build_all=True --options celix/*:enable_address_sanitizer=True \
4444
--options celix/*:enable_testing=True --options celix/*:enable_ccache=True \
45+
-o mosquitto/*:broker=True -o *:shared=True \
4546
--conf:build tools.cmake.cmaketoolchain:generator=Ninja"
4647
- name: Test Celix
4748
run: |

.github/workflows/coverage.yml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,8 @@ jobs:
6262
-o celix/*:enable_code_coverage=True
6363
-o celix/*:enable_testing_on_ci=True
6464
-o celix/*:enable_ccache=True
65+
-o mosquitto/*:broker=True
66+
-o *:shared=True
6567
run: |
6668
conan build . -pr:b release -pr:h default ${CONAN_BUILD_OPTIONS} -b missing
6769
- name: Test with coverage

.github/workflows/fuzzing.yml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,7 @@ jobs:
4141
-o celix/*:enable_address_sanitizer=True
4242
-o celix/*:enable_undefined_sanitizer=True
4343
-o celix/*:celix_err_buffer_size=5120
44+
-o *:shared=True
4445
run: conan build -c tools.cmake.cmaketoolchain:generator=Ninja ${CONAN_BUILD_OPTIONS} -b missing
4546
- name: Set fuzzer run time
4647
id: set-runtime

.github/workflows/macos.yml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,8 @@ jobs:
6363
-o celix/*:enable_testing_on_ci=True
6464
-o celix/*:framework_curlinit=False
6565
-o celix/*:enable_ccache=True
66+
-o mosquitto/*:broker=True
67+
-o *:shared=True
6668
run: |
6769
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
6870
- name: Test

.github/workflows/ubuntu.yml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -81,6 +81,8 @@ jobs:
8181
-o celix/*:enable_testing_on_ci=True
8282
-o celix/*:framework_curlinit=False
8383
-o celix/*:enable_ccache=True
84+
-o mosquitto/*:broker=True
85+
-o *:shared=True
8486
run: |
8587
conan build . -c tools.cmake.cmaketoolchain:generator=Ninja -pr:b release -pr:h default ${CONAN_BUILD_OPTIONS} -b missing
8688
- name: Test

conanfile.py

Lines changed: 62 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -141,6 +141,67 @@ def validate(self):
141141
self.validate_config_option_is_positive_number("celix_properties_optimization_string_buffer_size")
142142
self.validate_config_option_is_positive_number("celix_properties_optimization_entries_buffer_size")
143143

144+
# Helper function to safely get dependency option value
145+
def _get_dependency_option_value(self, dep_name, option_name):
146+
"""Safely get dependency option value, handling get_safe vs direct attribute access"""
147+
if dep_name in self.dependencies:
148+
dep = self.dependencies[dep_name]
149+
# First try get_safe, if that fails try direct attribute access
150+
value = dep.options.get_safe(option_name)
151+
if value is None:
152+
# Try direct attribute access
153+
try:
154+
value = getattr(dep.options, option_name)
155+
except AttributeError:
156+
# Option does not exist
157+
return None
158+
return value
159+
return None
160+
161+
# Validate dependency shared options based on Celix options
162+
# Split OR conditions into individual checks with detailed error messages
163+
from collections import namedtuple
164+
165+
ValidationRule = namedtuple('ValidationRule', ['condition', 'dep_name', 'option_name', 'expected_value', 'condition_desc'])
166+
167+
validation_rules = [
168+
ValidationRule(self.options.build_utils, 'libzip', "shared", True, 'build_utils=True'),
169+
ValidationRule(self.options.build_utils, 'libuv', "shared", True, 'build_utils=True'),
170+
ValidationRule(self.options.build_framework, 'util-linux-libuuid', "shared", True, 'build_framework=True'),
171+
ValidationRule(self.options.build_framework and self.options.framework_curlinit, 'libcurl', "shared", True, 'build_framework=True and framework_curlinit=True'),
172+
ValidationRule(self.options.build_framework and self.options.framework_curlinit, 'openssl', "shared", True, 'build_framework=True and framework_curlinit=True'),
173+
ValidationRule(self.options.build_celix_etcdlib, 'libcurl', "shared", True, 'build_celix_etcdlib=True'),
174+
ValidationRule(self.options.build_celix_etcdlib, 'openssl', "shared", True, 'build_celix_etcdlib=True'),
175+
ValidationRule(self.options.build_rsa_discovery_common, 'libcurl', "shared", True, 'build_rsa_discovery_common=True'),
176+
ValidationRule(self.options.build_rsa_discovery_common, 'openssl', "shared", True, 'build_rsa_discovery_common=True'),
177+
ValidationRule(self.options.build_rsa_remote_service_admin_dfi, 'libcurl', "shared", True, 'build_rsa_remote_service_admin_dfi=True'),
178+
ValidationRule(self.options.build_rsa_remote_service_admin_dfi, 'openssl', "shared", True, 'build_rsa_remote_service_admin_dfi=True'),
179+
ValidationRule(self.options.build_launcher, 'libcurl', "shared", True, 'build_launcher=True'),
180+
ValidationRule(self.options.build_launcher, 'openssl', "shared", True, 'build_launcher=True'),
181+
ValidationRule(self.options.enable_testing, 'gtest', "shared", True, 'enable_testing=True'),
182+
ValidationRule(self.options.enable_benchmarking, 'benchmark', "shared", True, 'enable_benchmarking=True'),
183+
ValidationRule(self.options.build_rsa_discovery_common, 'libxml2', "shared", True, 'build_rsa_discovery_common=True'),
184+
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'),
185+
ValidationRule(self.options.build_http_admin, 'civetweb', "shared", True, 'build_http_admin=True'),
186+
ValidationRule(self.options.build_http_admin, 'openssl', "shared", True, 'build_http_admin=True'),
187+
ValidationRule(self.options.build_rsa_discovery_common, 'civetweb', "shared", True, 'build_rsa_discovery_common=True'),
188+
ValidationRule(self.options.build_rsa_discovery_common, 'openssl', "shared", True, 'build_rsa_discovery_common=True'),
189+
ValidationRule(self.options.build_rsa_remote_service_admin_dfi, 'civetweb', "shared", True, 'build_rsa_remote_service_admin_dfi=True'),
190+
ValidationRule(self.options.build_rsa_remote_service_admin_dfi, 'openssl', "shared", True, 'build_rsa_remote_service_admin_dfi=True'),
191+
ValidationRule(self.options.build_celix_dfi, 'libffi', "shared", True, 'build_celix_dfi=True'),
192+
ValidationRule(self.options.build_utils, 'jansson', "shared", True, 'build_utils=True'),
193+
ValidationRule(self.options.build_celix_dfi, 'jansson', "shared", True, 'build_celix_dfi=True'),
194+
ValidationRule(self.options.build_celix_etcdlib, 'jansson', "shared", True, 'build_celix_etcdlib=True'),
195+
ValidationRule(self.options.build_event_admin_remote_provider_mqtt, 'jansson', "shared", True, 'build_event_admin_remote_provider_mqtt=True'),
196+
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"),
197+
]
198+
199+
for rule in validation_rules:
200+
if rule.condition and rule.dep_name in self.dependencies:
201+
actual_value = _get_dependency_option_value(self, rule.dep_name, rule.option_name)
202+
if actual_value is not None and actual_value != rule.expected_value:
203+
raise ConanInvalidConfiguration(f"Celix configuration `{rule.condition_desc}` requires {rule.dep_name}/*:{rule.option_name}={rule.expected_value}")
204+
144205
def package_id(self):
145206
del self.info.options.build_all
146207
# the followings are not installed
@@ -304,39 +365,6 @@ def configure(self):
304365
setattr(self.options, opt, options[opt])
305366
del options
306367

307-
# Conan 2 does not support set dependency option in requirements()
308-
# https://github.com/conan-io/conan/issues/14528#issuecomment-1685344080
309-
if self.options.build_utils:
310-
self.options['libzip'].shared = True
311-
self.options['libuv'].shared = True
312-
if self.options.build_framework:
313-
self.options['util-linux-libuuid'].shared = True
314-
if ((self.options.build_framework and self.options.framework_curlinit)
315-
or self.options.build_celix_etcdlib
316-
or self.options.build_rsa_discovery_common or self.options.build_rsa_remote_service_admin_dfi
317-
or self.options.build_launcher):
318-
self.options['libcurl'].shared = True
319-
self.options['openssl'].shared = True
320-
if self.options.enable_testing:
321-
self.options['gtest'].shared = True
322-
if self.options.enable_benchmarking:
323-
self.options['benchmark'].shared = True
324-
if (self.options.build_rsa_discovery_common
325-
or (self.options.build_rsa_remote_service_admin_dfi and self.options.enable_testing)):
326-
self.options['libxml2'].shared = True
327-
if self.options.build_http_admin or self.options.build_rsa_discovery_common \
328-
or self.options.build_rsa_remote_service_admin_dfi:
329-
self.options['civetweb'].shared = True
330-
self.options['openssl'].shared = True
331-
if self.options.build_celix_dfi:
332-
self.options['libffi'].shared = True
333-
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:
334-
self.options['jansson'].shared = True
335-
if self.options.build_event_admin_remote_provider_mqtt:
336-
self.options['mosquitto'].shared = True
337-
if self.options.enable_testing:
338-
self.options['mosquitto'].broker = True
339-
340368
def requirements(self):
341369
if self.options.build_utils:
342370
self.requires("libzip/[>=1.7.3 <2.0.0]")
@@ -371,7 +399,7 @@ def requirements(self):
371399
self.requires("zlib/1.3.1", override=True)
372400
if self.options.build_event_admin_remote_provider_mqtt:
373401
self.requires("mosquitto/[>=2.0.3 <3.0.0]")
374-
self.validate()
402+
375403

376404
def layout(self):
377405
cmake_layout(self)

documents/building/README.md

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -86,6 +86,8 @@ conan install . --build=missing --profile:build default --profile:host debug \
8686
-o "celix/*:build_all=True" \
8787
-o "celix/*:enable_testing=True" \
8888
-o "celix/*:enable_ccache=True" \
89+
-o "mosquitto/*:broker=True" \
90+
-o "*:shared=True" \
8991
--conf tools.cmake.cmaketoolchain:generator=Ninja
9092
```
9193

@@ -110,7 +112,8 @@ For example, to only build the framework and utils libraries:
110112
```bash
111113
conan install . --build=missing --profile:build default --profile:host debug \
112114
-o "celix/*:build_framework=True" \
113-
-o "celix/*:build_utils=True"
115+
-o "celix/*:build_utils=True" \
116+
-o "*:shared=True"
114117
cmake --build --preset conan-debug --parallel
115118
```
116119

documents/building/dev_celix_with_clion.md

Lines changed: 10 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ limitations under the License.
2121

2222
# Building and Developing Apache Celix with CLion
2323
Apache Celix can be build for development in CLion with use of the Conan package manager.
24-
Conan will arrange the building of the Apache Celix dependencies and generate Find<package> files for these dependencies.
24+
Conan will arrange the building of the Apache Celix dependencies and generate config package files for these dependencies.
2525

2626
Conan will also generate a `conanrun.sh` and `deactivate_conanrun.sh` script that does the environment (de)setup for the
2727
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
4141
cd celix
4242

4343
#if needed setup conan default and debug profile
44-
conan profile new default --detect
45-
conan profile new debug --detect
46-
conan profile update settings.build_type=Debug debug
44+
conan profile detect -f
45+
conan profile detect -f --name debug
46+
sed -i 's/build_type=Release/build_type=Debug/g' `conan profile path debug`
4747

48-
# Generate and configure cmake-build-debug directory
49-
# If CLion's CMake Preset Integration has been enabled, then CLion will load available CMake profiles
50-
# from the CMakeUserPresets.json file at the project root, which is generated by `conan install`.
51-
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
52-
53-
#optional build
54-
conan build . -bf cmake-build-debug/
48+
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
5549

5650
#optional setup run env and run tests
57-
cd cmake-build-debug
58-
source conanrun.sh
59-
ctest --verbose
60-
source deactivate_conanrun.sh
51+
ctest --preset conan-debug --verbose
6152
```
6253

63-
### Work with Conan 2
64-
65-
The above is for Conan 1.x.
66-
Conan 2 has greatly simplified its integration with CLion.
67-
Issuing the following command will produce a CMakeUserPresets.json at the project root, which CLion will load automatically to set up CMake profiles.
68-
Then Celix can be built within the IDE.
54+
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.
6955

7056
```shell
71-
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
57+
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
7258
```
7359

7460
## Configuring CLion
@@ -78,7 +64,7 @@ This can be done under the menu "Run->Edit Configurations...", then select "Edit
7864
then update the "Google Test" template so that the `conanrun.sh` Conan generated script is sourced in the
7965
"Environment variables" entry.
8066

81-
If the Apache Celix CMake build directory is `home/joe/workspace/celix/cmake-build-debug` then the value for
82-
"Environment variables" should be: `source /home/joe/workspace/celix/cmake-build-debug/conanrun.sh`
67+
If the Apache Celix CMake build directory is `home/joe/workspace/celix/build/Debug` then the value for
68+
"Environment variables" should be: `source /home/joe/workspace/celix/build/Debug/generators/conanrun.sh`
8369

8470
![Configure CLion](media/clion_run_configuration_template.png)

0 commit comments

Comments
 (0)