conan-io / conan

Conan - The open-source C and C++ package manager
https://conan.io
MIT License
7.97k stars 952 forks source link

[question] How to use self.dependencies["package"].conf_info in test_v1_package #12674

Closed saukijan closed 1 year ago

saukijan commented 1 year ago

Hello Everyone,

I am working on Package/open62541: bump to v1.3.4 and I am pretty much finished porting the recipe to Conan v2, but I am having a problem with test_v1_package.

Conan v2 migration guide states that, I need to change self.user_info calls into self.conf_info and it works great for the v2 test_package, however test_v1_package can not find the self.conf_info I defined in the recipe.

If I use the following test_v1_package file:

test_v1_package/conanfile.py ```python from conans import ConanFile, CMake from conan.tools.build import cross_building import os # legacy validation with Conan 1.x class TestPackageV1Conan(ConanFile): settings = "os", "compiler", "build_type", "arch" generators = "cmake", "cmake_find_package_multi" def requirements(self): self.requires("ua-nodeset/padim-1.02-2021-07-21") def build(self): cmake = CMake(self) cmake.definitions["open62541_NODESET_DIR"] = self.deps_user_info["ua-nodeset"].nodeset_dir cmake.definitions["open62541_TOOLS_DIR"] = self.deps_user_info["open62541"].tools_dir cmake.configure() cmake.build() def test(self): if not cross_building(self): bin_path = os.path.join("bin", "test_package") self.run(bin_path, run_environment=True) ```

I get the following error:

ERROR: open62541/1.3.4 (test package): Error in build() method, line 17
        cmake.definitions["open62541_TOOLS_DIR"] = self.deps_user_info["open62541"].tools_dir
        AttributeError: 

If I update it into conan v2 format as follows:

test_v1_package/conanfile.py ```python from conans import ConanFile, CMake from conan.tools.build import cross_building import os # legacy validation with Conan 1.x class TestPackageV1Conan(ConanFile): settings = "os", "compiler", "build_type", "arch" generators = "cmake", "cmake_find_package_multi" def requirements(self): self.requires("ua-nodeset/padim-1.02-2021-07-21") def build(self): cmake = CMake(self) cmake.definitions["open62541_NODESET_DIR"] = self.deps_user_info["ua-nodeset"].nodeset_dir cmake.definitions["open62541_TOOLS_DIR"] = self.dependencies["open62541"].conf_info.get( "user.myconf:tools_dir") cmake.configure() cmake.build() def test(self): if not cross_building(self): bin_path = os.path.join("bin", "test_package") self.run(bin_path, run_environment=True) ```

I get the following error:

ERROR: open62541/1.3.4 (test package): Error in build() method, line 17
        cmake.definitions["open62541_TOOLS_DIR"] = self.dependencies["open62541"].conf_info.get(
        AttributeError: 'NoneType' object has no attribute 'dependencies'

I could change the recipe so it defines both the v1 self.user_info and the v2 self.conf_inf fields, but I am not sure if that is the correct way to do it.

Does anyone know a better way to define a package variable that will be used CMakeToolchain on the user side?

For reference here is the latest reworked recipe (not yet published)

test_v1_package/conanfile.py ```python from conan import ConanFile from conan.tools.cmake import cmake_layout, CMake, CMakeToolchain, CMakeDeps from conan.tools.env import VirtualBuildEnv from conan.tools.scm import Version from conan.tools.files import apply_conandata_patches, collect_libs, export_conandata_patches, rename, rm, rmdir, mkdir, get from conans.errors import ConanInvalidConfiguration import glob import os import yaml required_conan_version = ">=1.53.0" class Open62541Conan(ConanFile): name = "open62541" license = "MPLv2" homepage = "https://open62541.org/" url = "https://github.com/conan-io/conan-center-index" description = "open62541 is an open source and free implementation of OPC UA " \ "(OPC Unified Architecture) written in the common subset of the " \ "C99 and C++98 languages. The library is usable with all major " \ "compilers and provides the necessary tools to implement dedicated " \ "OPC UA clients and servers, or to integrate OPC UA-based communication " \ "into existing applications. open62541 library is platform independent. " \ "All platform-specific functionality is implemented via exchangeable " \ "plugins. Plugin implementations are provided for the major operating systems." topics = ( "opc ua", "open62541", "sdk", "server/client", "c", "iec-62541", "industrial automation", "tsn", "time sensitive networks", "publish-subscirbe", "pubsub" ) settings = "os", "compiler", "build_type", "arch" options = { "fPIC": [True, False], "shared": [True, False], # False: UA_ENABLE_HISTORIZING=Off # True: UA_ENABLE_HISTORIZING=On # Experimental: UA_ENABLE_HISTORIZING=On and UA_ENABLE_EXPERIMENTAL_HISTORIZING=On "historize": [True, False, "Experimental"], "logging_level": ["Fatal", "Error", "Warning", "Info", "Debug", "Trace"], # False: UA_ENABLE_SUBSCRIPTIONS=Off # True: UA_ENABLE_SUBSCRIPTIONS=On # With Events: deprecated. Use 'events' instead # events: UA_ENABLE_SUBSCRIPTIONS_EVENTS=On # alarms,conditions,events: UA_ENABLE_SUBSCRIPTIONS_EVENTS=On and UA_ENABLE_SUBSCRIPTIONS_ALARMS_CONDITIONS=On "subscription": [True, False, "With Events", "events", "alarms,conditions,events"], # False: UA_ENABLE_METHODCALLS=Off # True: UA_ENABLE_METHODCALLS=Onn "methods": [True, False], # False: UA_ENABLE_NODEMANAGEMENT=Off # True: UA_ENABLE_NODEMANAGEMENT=On "dynamic_nodes": [True, False], # False: UA_ENABLE_AMALGAMATION=Off # True: UA_ENABLE_AMALGAMATION=On "single_header": [True, False], # None: UA_MULTITHREADING=0 # Threadsafe: UA_MULTITHREADING=100 # Internal threads: UA_MULTITHREADING=200 "multithreading": ["None", "Threadsafe", "Internal threads"], # False: UA_ENABLE_IMMUTABLE_NODES=Off # True: UA_ENABLE_IMMUTABLE_NODES=On "imutable_nodes": [True, False], # False: UA_ENABLE_WEBSOCKET_SERVER=Off # True: UA_ENABLE_WEBSOCKET_SERVER=On "web_socket": [True, False], # False: UA_ENABLE_DISCOVERY=Off # True: UA_ENABLE_DISCOVERY=On # With Multicast: Deprecated. Use 'multicast' instead # multicast: UA_ENABLE_DISCOVERY_MULTICAST=On # semaphore: UA_ENABLE_DISCOVERY_SEMAPHORE=On # multicast,semaphore: UA_ENABLE_DISCOVERY_MULTICAST=On and UA_ENABLE_DISCOVERY_SEMAPHORE=On "discovery": [True, False, "With Multicast", "multicast", "semaphore", "multicast,semaphore"], # Deprecated. Use discovery=semaphore instead "discovery_semaphore": [True, False], # False: UA_ENABLE_QUERY=Off # True: UA_ENABLE_QUERY=On "query": [True, False], # False: UA_ENABLE_ENCRYPTION=Off # openssl: UA_ENABLE_ENCRYPTION=On and UA_ENABLE_ENCRYPTION_OPENSSL=On # mbedtls: UA_ENABLE_ENCRYPTION=On # changed in 1.3.1 - UA_ENABLE_ENCRYPTION can be OFF, OPENSSL, MBEDTLS "encryption": [False, "openssl", "mbedtls"], # False: UA_ENABLE_JSON_ENCODING=Off # True: UA_ENABLE_JSON_ENCODING=On "json_support": [True, False], # False: UA_ENABLE_PUBSUB=Off # Simple: UA_ENABLE_PUBSUB=On # Ethernet: UA_ENABLE_PUBSUB=On and UA_ENABLE_PUBSUB_ETH_UADP=On # Ethernet_XDP: UA_ENABLE_PUBSUB=On and UA_ENABLE_PUBSUB_ETH_UADP_XDP=On "pub_sub": [False, "Simple", "Ethernet", "Ethernet_XDP"], # False: UA_ENABLE_PUBSUB_ENCRYPTION=Off # True: UA_ENABLE_PUBSUB_ENCRYPTION=On "pub_sub_encryption": [True, False], # False: UA_ENABLE_DA=Off # True: UA_ENABLE_DA=On "data_access": [True, False], # False: UA_ENABLE_NODESET_COMPILER_DESCRIPTIONS=Off and UA_NAMESPACE_ZERO=options.namespace_zero # True: UA_ENABLE_NODESET_COMPILER_DESCRIPTIONS=On and UA_NAMESPACE_ZERO=Full "compiled_nodeset_descriptions": [True, False], # UA_NAMESPACE_ZERO=option.namespace_zero (only if compiled_nodeset_descriptions=False) "namespace_zero": ["MINIMAL", "REDUCED", "FULL"], # UA_ENABLE_MICRO_EMB_DEV_PROFILE=embedded_profile "embedded_profile": [True, False], # UA_ENABLE_TYPENAMES=typenames "typenames": [True, False], # UA_ENABLE_HARDENING=hardening "hardening": [True, False], # UA_COMPILE_AS_CXX=cpp_compatible "cpp_compatible": [True, False], # UA_ENABLE_STATUSCODE_DESCRIPTIONS=readable_statuscodes "readable_statuscodes": [True, False] } default_options = { "fPIC": True, "shared": False, "historize": False, "logging_level": "Info", "subscription": True, "methods": True, "dynamic_nodes": True, "single_header": False, "multithreading": "None", "imutable_nodes": False, "web_socket": False, "discovery": "semaphore", "discovery_semaphore": True, "query": False, "encryption": False, "json_support": False, "pub_sub": False, "pub_sub_encryption": False, "data_access": True, "compiled_nodeset_descriptions": True, "namespace_zero": "FULL", "embedded_profile": False, "typenames": True, "hardening": True, "cpp_compatible": False, "readable_statuscodes": True } exports_sources = ["CMakeLists.txt", "patches/**"] exports = "submoduledata.yml" short_paths = True def export_sources(self): export_conandata_patches(self) def config_options(self): if self.settings.os == "Windows": del self.options.fPIC if Version(self.version) >= "1.3.1": del self.options.embedded_profile def configure(self): if self.options.shared: self.options.rm_safe("fPIC") if not self.options.cpp_compatible: self.settings.rm_safe("compiler.libcxx") self.settings.rm_safe("compiler.cppstd") # Due to https://github.com/open62541/open62541/issues/4687 we cannot build with 1.2.2 + Windows + shared if Version(self.version) >= "1.2.2" and self.settings.os == "Windows" and self.options.shared: raise ConanInvalidConfiguration("{0} {1} doesn't properly support shared lib on Windows".format(self.name, self.version)) if self.options.subscription == "With Events": self.output.warning("`{name}:subscription=With Events` is deprecated. Use `{name}:subscription=events` instead".format( name=self.name)) # Deprecated in 1.2.2 self.options.subscription = "events" if self.options.web_socket: self.options["libwebsockets"].with_ssl = self.options.encryption def layout(self): cmake_layout(self, src_folder="source") def requirements(self): if self.options.encryption == "mbedtls": self.requires("mbedtls/2.25.0") elif self.options.encryption == "openssl": self.requires("openssl/1.1.1o") if self.options.web_socket: self.requires("libwebsockets/4.2.0") if self.options.discovery == "With Multicast" or "multicast" in str(self.options.discovery): self.requires("pro-mdnsd/0.8.4") def validate(self): if not self.options.subscription: raise ConanInvalidConfiguration( "Open62541 requires subscription option") if not self.options.discovery: if self.options.discovery_semaphore: raise ConanInvalidConfiguration( "Open62541 discovery sempahore option requires discovery option to be enabled") if Version(self.version) < "1.1.0": if self.options.encryption == "openssl": raise ConanInvalidConfiguration( "Lower Open62541 versions than 1.1.0 do not support openssl") if self.options.multithreading != "None": raise ConanInvalidConfiguration( "Lower Open62541 versions than 1.1.0 do not fully support multithreading") if self.options.web_socket: raise ConanInvalidConfiguration( "Lower Open62541 versions than 1.1.0 do not fully support websockets") if self.options.cpp_compatible: raise ConanInvalidConfiguration( "Lower Open62541 versions than 1.1.0 are not cpp compatible due to -fpermisive flags") # FIXME: correct clang versions condition max_clang_version = "8" if Version( self.version) < "1.1.0" else "9" if self.settings.compiler == "clang" and Version(self.settings.compiler.version) > max_clang_version: raise ConanInvalidConfiguration( "Open62541 supports Clang up to {} compiler version".format(max_clang_version)) if self.settings.compiler == "clang": if Version(self.settings.compiler.version) < "5": raise ConanInvalidConfiguration( "Older clang compiler version than 5.0 are not supported") if self.options.pub_sub != False and self.settings.os != "Linux": raise ConanInvalidConfiguration( "PubSub over Ethernet is not supported for your OS!") if self.options.web_socket: if self.options["libwebsockets"].with_ssl != self.options.encryption: raise ConanInvalidConfiguration( "When web_socket is enabled, libwebsockets:with_ssl must have the value of open62541:encryption") def source(self): get(self, **self.conan_data["sources"][self.version], destination=self.source_folder, strip_root=True) submodule_filename = os.path.join( self.recipe_folder, 'submoduledata.yml') with open(submodule_filename, 'r') as submodule_stream: submodules_data = yaml.safe_load(submodule_stream) for path, submodule in submodules_data["submodules"][self.version].items(): filename = os.path.basename(submodule["url"]) archive_name = submodule["archive_pattern"].format( version=os.path.splitext(filename.replace('v', ''))[0]) submodule_data = { "url": submodule["url"], "sha256": submodule["sha256"] } get(self, **submodule_data) submodule_source = os.path.join(self.source_folder, path) rmdir(self, submodule_source) rename(self, archive_name, submodule_source) def _get_log_level(self): return { "Fatal": "600", "Error": "500", "Warning": "400", "Info": "300", "Debug": "200", "Trace": "100", "PackageOption": "300" }.get(str(self.options.logging_level), "300") def _get_multithreading_option(self): return { "None": "0", "Threadsafe": "100", "Internal threads": "200" }.get(str(self.options.multithreading), "0") def generate(self): tc = CMakeToolchain(self) version = Version(self.version) tc.variables["OPEN62541_VER_MAJOR"] = version.major tc.variables["OPEN62541_VER_MINOR"] = version.minor tc.variables["OPEN62541_VER_PATCH"] = version.patch tc.variables["UA_LOGLEVEL"] = self._get_log_level() tc.variables["UA_ENABLE_SUBSCRIPTIONS"] = self.options.subscription != False if self.options.subscription != False: if "events" in str(self.options.subscription): tc.variables["UA_ENABLE_SUBSCRIPTIONS_EVENTS"] = True if "alarms" in str(self.options.subscription) and "conditions" in str(self.options.subscription): tc.variables["UA_ENABLE_SUBSCRIPTIONS_ALARMS_CONDITIONS"] = True tc.variables["UA_ENABLE_METHODCALLS"] = self.options.methods tc.variables["UA_ENABLE_NODEMANAGEMENT"] = self.options.dynamic_nodes tc.variables["UA_ENABLE_AMALGAMATION"] = self.options.single_header if version >= "1.1.3": tc.variables["UA_MULTITHREADING"] = self._get_multithreading_option() tc.variables["UA_ENABLE_IMMUTABLE_NODES"] = self.options.imutable_nodes tc.variables["UA_ENABLE_WEBSOCKET_SERVER"] = self.options.web_socket tc.variables["UA_ENABLE_HISTORIZING"] = self.options.historize != False if self.options.historize != False: if self.options.historize == "Experimental": tc.variables["UA_ENABLE_EXPERIMENTAL_HISTORIZING"] = True tc.variables["UA_ENABLE_DISCOVERY"] = self.options.discovery != False if self.options.discovery != False: tc.variables["UA_ENABLE_DISCOVERY_MULTICAST"] = \ self.options.discovery == "With Multicast" or "multicast" in str( self.options.discovery) tc.variables["UA_ENABLE_DISCOVERY_SEMAPHORE"] = \ self.options.discovery_semaphore or "semaphore" in str( self.options.discovery) tc.variables["UA_ENABLE_QUERY"] = self.options.query if Version(self.version) >= "1.3.1": if self.options.encryption == "openssl": tc.variables["UA_ENABLE_ENCRYPTION"] = "OPENSSL" elif self.options.encryption == "mbedtls": tc.variables["UA_ENABLE_ENCRYPTION"] = "MBEDTLS" else: tc.variables["UA_ENABLE_ENCRYPTION"] = "OFF" else: tc.variables["UA_ENABLE_ENCRYPTION"] = self.options.encryption != False if self.options.encryption != False: if self.options.encryption == "openssl": tc.variables["UA_ENABLE_ENCRYPTION_OPENSSL"] = True tc.variables["UA_ENABLE_JSON_ENCODING"] = self.options.json_support tc.variables["UA_ENABLE_PUBSUB"] = self.options.pub_sub != False tc.variables["UA_ENABLE_PUBSUB_ENCRYPTION"] = self.options.pub_sub_encryption != False if self.options.pub_sub != False: if self.settings.os == "Linux" and self.options.pub_sub == "Ethernet": tc.variables["UA_ENABLE_PUBSUB_ETH_UADP"] = True elif self.settings.os == "Linux" and self.options.pub_sub == "Ethernet_XDP": tc.variables["UA_ENABLE_PUBSUB_ETH_UADP_XDP"] = True tc.variables["UA_ENABLE_DA"] = self.options.data_access if self.options.compiled_nodeset_descriptions == True: tc.variables["UA_ENABLE_NODESET_COMPILER_DESCRIPTIONS"] = self.options.compiled_nodeset_descriptions tc.variables["UA_NAMESPACE_ZERO"] = "FULL" else: tc.variables["UA_NAMESPACE_ZERO"] = self.options.namespace_zero if Version(self.version) < "1.3.1": tc.variables["UA_ENABLE_MICRO_EMB_DEV_PROFILE"] = self.options.embedded_profile tc.variables["UA_ENABLE_TYPENAMES"] = self.options.typenames tc.variables["UA_ENABLE_STATUSCODE_DESCRIPTIONS"] = self.options.readable_statuscodes tc.variables["UA_ENABLE_HARDENING"] = self.options.hardening if self.settings.compiler == "Visual Studio" and self.options.shared == True: tc.variables["UA_MSVC_FORCE_STATIC_CRT"] = True tc.variables["UA_COMPILE_AS_CXX"] = self.options.cpp_compatible tc.generate() tc = CMakeDeps(self) tc.generate() tc = VirtualBuildEnv(self) tc.generate(scope="build") def _patch_sources(self): apply_conandata_patches(self) if Version(self.version) >= "1.3.1": os.unlink(os.path.join(self.source_folder, "tools", "cmake", "FindPython3.cmake")) def build(self): self._patch_sources() cmake = CMake(self) cmake.configure() cmake.build() @property def _tools_subfolder(self): return os.path.join(self.source_folder, "tools") @property def _module_subfolder(self): return os.path.join("lib", "cmake", "open62541") @property def _module_file_rel_path(self): return os.path.join(self._module_subfolder, "open62541Macros.cmake") def package(self): self.copy("LICENSE", dst="licenses", src=self.source_folder) self.copy("LICENSE-CC0", dst="licenses", src=self.source_folder) cmake = CMake(self) cmake.install() rm(self, '*.pdb', os.path.join(self.package_folder, "bin")) rm(self, '*.pdb', os.path.join(self.package_folder, "lib")) for cmake_file in glob.glob(os.path.join(self.package_folder, self._module_subfolder, "*")): if not cmake_file.endswith(self._module_file_rel_path): os.remove(cmake_file) rmdir(self, os.path.join(self.package_folder, "lib", "pkgconfig")) rmdir(self, os.path.join(self.package_folder, "share")) self.copy("generate_*.py", src=self._tools_subfolder, dst=os.path.join("res", "tools")) self.copy("nodeset_compiler/*", src=self._tools_subfolder, dst=os.path.join("res", "tools")) @staticmethod def _chmod_plus_x(filename): if os.name == 'posix': os.chmod(filename, os.stat(filename).st_mode | 0o111) def package_info(self): self.cpp_info.names["cmake_find_package"] = "open62541" self.cpp_info.names["cmake_find_package_multi"] = "open62541" self.cpp_info.names["pkg_config"] = "open62541" self.cpp_info.libs = collect_libs(self) self.cpp_info.includedirs = [ "include", os.path.join("include", "open62541", "plugin") ] # required for creating custom servers from ua-nodeset self.conf_info.define("user.myconf:tools_dir", os.path.join( self.package_folder, "res", "tools")) self._chmod_plus_x(os.path.join(self.package_folder, "res", "tools", "generate_nodeid_header.py")) if self.options.single_header: self.cpp_info.defines.append("UA_ENABLE_AMALGAMATION") if self.settings.os == "Windows": self.cpp_info.system_libs.append("ws2_32") self.cpp_info.includedirs.append( os.path.join("include", "open62541", "win32")) else: self.cpp_info.includedirs.append( os.path.join("include", "open62541", "posix")) if self.settings.os in ("Linux", "FreeBSD"): self.cpp_info.system_libs.extend(["pthread", "m", "rt"]) self.cpp_info.builddirs = [self._module_subfolder] self.cpp_info.set_property("cmake_build_modules", [ self._module_file_rel_path]) ```
memsharded commented 1 year ago

Hi @saukijan

From a quick view I think it is good to keep both definitions in place. You can keep defining user_info for v1-legacy, and use conf_info for v2-compatible. Have you considered and tried that?

saukijan commented 1 year ago

Well, I tested both versions separately, and just finished testing using both v1 and v2 definitions, but that causes a problem with auto included open62541Macros.cmake module.

If I use the following recipie:

conanfile.py ```python from conan import ConanFile from conan.tools.cmake import cmake_layout, CMake, CMakeToolchain, CMakeDeps from conan.tools.env import VirtualBuildEnv from conan.tools.scm import Version from conan.tools.files import apply_conandata_patches, collect_libs, export_conandata_patches, rename, rm, rmdir, mkdir, get from conans.errors import ConanInvalidConfiguration import glob import os import yaml required_conan_version = ">=1.53.0" class Open62541Conan(ConanFile): name = "open62541" license = "MPLv2" homepage = "https://open62541.org/" url = "https://github.com/conan-io/conan-center-index" description = "open62541 is an open source and free implementation of OPC UA " \ "(OPC Unified Architecture) written in the common subset of the " \ "C99 and C++98 languages. The library is usable with all major " \ "compilers and provides the necessary tools to implement dedicated " \ "OPC UA clients and servers, or to integrate OPC UA-based communication " \ "into existing applications. open62541 library is platform independent. " \ "All platform-specific functionality is implemented via exchangeable " \ "plugins. Plugin implementations are provided for the major operating systems." topics = ( "opc ua", "open62541", "sdk", "server/client", "c", "iec-62541", "industrial automation", "tsn", "time sensitive networks", "publish-subscirbe", "pubsub" ) settings = "os", "compiler", "build_type", "arch" options = { "fPIC": [True, False], "shared": [True, False], # False: UA_ENABLE_HISTORIZING=Off # True: UA_ENABLE_HISTORIZING=On # Experimental: UA_ENABLE_HISTORIZING=On and UA_ENABLE_EXPERIMENTAL_HISTORIZING=On "historize": [True, False, "Experimental"], "logging_level": ["Fatal", "Error", "Warning", "Info", "Debug", "Trace"], # False: UA_ENABLE_SUBSCRIPTIONS=Off # True: UA_ENABLE_SUBSCRIPTIONS=On # With Events: deprecated. Use 'events' instead # events: UA_ENABLE_SUBSCRIPTIONS_EVENTS=On # alarms,conditions,events: UA_ENABLE_SUBSCRIPTIONS_EVENTS=On and UA_ENABLE_SUBSCRIPTIONS_ALARMS_CONDITIONS=On "subscription": [True, False, "With Events", "events", "alarms,conditions,events"], # False: UA_ENABLE_METHODCALLS=Off # True: UA_ENABLE_METHODCALLS=Onn "methods": [True, False], # False: UA_ENABLE_NODEMANAGEMENT=Off # True: UA_ENABLE_NODEMANAGEMENT=On "dynamic_nodes": [True, False], # False: UA_ENABLE_AMALGAMATION=Off # True: UA_ENABLE_AMALGAMATION=On "single_header": [True, False], # None: UA_MULTITHREADING=0 # Threadsafe: UA_MULTITHREADING=100 # Internal threads: UA_MULTITHREADING=200 "multithreading": ["None", "Threadsafe", "Internal threads"], # False: UA_ENABLE_IMMUTABLE_NODES=Off # True: UA_ENABLE_IMMUTABLE_NODES=On "imutable_nodes": [True, False], # False: UA_ENABLE_WEBSOCKET_SERVER=Off # True: UA_ENABLE_WEBSOCKET_SERVER=On "web_socket": [True, False], # False: UA_ENABLE_DISCOVERY=Off # True: UA_ENABLE_DISCOVERY=On # With Multicast: Deprecated. Use 'multicast' instead # multicast: UA_ENABLE_DISCOVERY_MULTICAST=On # semaphore: UA_ENABLE_DISCOVERY_SEMAPHORE=On # multicast,semaphore: UA_ENABLE_DISCOVERY_MULTICAST=On and UA_ENABLE_DISCOVERY_SEMAPHORE=On "discovery": [True, False, "With Multicast", "multicast", "semaphore", "multicast,semaphore"], # Deprecated. Use discovery=semaphore instead "discovery_semaphore": [True, False], # False: UA_ENABLE_QUERY=Off # True: UA_ENABLE_QUERY=On "query": [True, False], # False: UA_ENABLE_ENCRYPTION=Off # openssl: UA_ENABLE_ENCRYPTION=On and UA_ENABLE_ENCRYPTION_OPENSSL=On # mbedtls: UA_ENABLE_ENCRYPTION=On # changed in 1.3.1 - UA_ENABLE_ENCRYPTION can be OFF, OPENSSL, MBEDTLS "encryption": [False, "openssl", "mbedtls"], # False: UA_ENABLE_JSON_ENCODING=Off # True: UA_ENABLE_JSON_ENCODING=On "json_support": [True, False], # False: UA_ENABLE_PUBSUB=Off # Simple: UA_ENABLE_PUBSUB=On # Ethernet: UA_ENABLE_PUBSUB=On and UA_ENABLE_PUBSUB_ETH_UADP=On # Ethernet_XDP: UA_ENABLE_PUBSUB=On and UA_ENABLE_PUBSUB_ETH_UADP_XDP=On "pub_sub": [False, "Simple", "Ethernet", "Ethernet_XDP"], # False: UA_ENABLE_PUBSUB_ENCRYPTION=Off # True: UA_ENABLE_PUBSUB_ENCRYPTION=On "pub_sub_encryption": [True, False], # False: UA_ENABLE_DA=Off # True: UA_ENABLE_DA=On "data_access": [True, False], # False: UA_ENABLE_NODESET_COMPILER_DESCRIPTIONS=Off and UA_NAMESPACE_ZERO=options.namespace_zero # True: UA_ENABLE_NODESET_COMPILER_DESCRIPTIONS=On and UA_NAMESPACE_ZERO=Full "compiled_nodeset_descriptions": [True, False], # UA_NAMESPACE_ZERO=option.namespace_zero (only if compiled_nodeset_descriptions=False) "namespace_zero": ["MINIMAL", "REDUCED", "FULL"], # UA_ENABLE_MICRO_EMB_DEV_PROFILE=embedded_profile "embedded_profile": [True, False], # UA_ENABLE_TYPENAMES=typenames "typenames": [True, False], # UA_ENABLE_HARDENING=hardening "hardening": [True, False], # UA_COMPILE_AS_CXX=cpp_compatible "cpp_compatible": [True, False], # UA_ENABLE_STATUSCODE_DESCRIPTIONS=readable_statuscodes "readable_statuscodes": [True, False] } default_options = { "fPIC": True, "shared": False, "historize": False, "logging_level": "Info", "subscription": True, "methods": True, "dynamic_nodes": True, "single_header": False, "multithreading": "None", "imutable_nodes": False, "web_socket": False, "discovery": "semaphore", "discovery_semaphore": True, "query": False, "encryption": False, "json_support": False, "pub_sub": False, "pub_sub_encryption": False, "data_access": True, "compiled_nodeset_descriptions": True, "namespace_zero": "FULL", "embedded_profile": False, "typenames": True, "hardening": True, "cpp_compatible": False, "readable_statuscodes": True } exports_sources = ["CMakeLists.txt", "patches/**"] exports = "submoduledata.yml" short_paths = True def export_sources(self): export_conandata_patches(self) def config_options(self): if self.settings.os == "Windows": del self.options.fPIC if Version(self.version) >= "1.3.1": del self.options.embedded_profile def configure(self): if self.options.shared: self.options.rm_safe("fPIC") if not self.options.cpp_compatible: self.settings.rm_safe("compiler.libcxx") self.settings.rm_safe("compiler.cppstd") # Due to https://github.com/open62541/open62541/issues/4687 we cannot build with 1.2.2 + Windows + shared if Version(self.version) >= "1.2.2" and self.settings.os == "Windows" and self.options.shared: raise ConanInvalidConfiguration("{0} {1} doesn't properly support shared lib on Windows".format(self.name, self.version)) if self.options.subscription == "With Events": self.output.warning("`{name}:subscription=With Events` is deprecated. Use `{name}:subscription=events` instead".format( name=self.name)) # Deprecated in 1.2.2 self.options.subscription = "events" if self.options.web_socket: self.options["libwebsockets"].with_ssl = self.options.encryption def layout(self): cmake_layout(self, src_folder="source") def requirements(self): if self.options.encryption == "mbedtls": self.requires("mbedtls/2.25.0") elif self.options.encryption == "openssl": self.requires("openssl/1.1.1o") if self.options.web_socket: self.requires("libwebsockets/4.2.0") if self.options.discovery == "With Multicast" or "multicast" in str(self.options.discovery): self.requires("pro-mdnsd/0.8.4") def validate(self): if not self.options.subscription: raise ConanInvalidConfiguration( "Open62541 requires subscription option") if not self.options.discovery: if self.options.discovery_semaphore: raise ConanInvalidConfiguration( "Open62541 discovery sempahore option requires discovery option to be enabled") if Version(self.version) < "1.1.0": if self.options.encryption == "openssl": raise ConanInvalidConfiguration( "Lower Open62541 versions than 1.1.0 do not support openssl") if self.options.multithreading != "None": raise ConanInvalidConfiguration( "Lower Open62541 versions than 1.1.0 do not fully support multithreading") if self.options.web_socket: raise ConanInvalidConfiguration( "Lower Open62541 versions than 1.1.0 do not fully support websockets") if self.options.cpp_compatible: raise ConanInvalidConfiguration( "Lower Open62541 versions than 1.1.0 are not cpp compatible due to -fpermisive flags") # FIXME: correct clang versions condition max_clang_version = "8" if Version( self.version) < "1.1.0" else "9" if self.settings.compiler == "clang" and Version(self.settings.compiler.version) > max_clang_version: raise ConanInvalidConfiguration( "Open62541 supports Clang up to {} compiler version".format(max_clang_version)) if self.settings.compiler == "clang": if Version(self.settings.compiler.version) < "5": raise ConanInvalidConfiguration( "Older clang compiler version than 5.0 are not supported") if self.options.pub_sub != False and self.settings.os != "Linux": raise ConanInvalidConfiguration( "PubSub over Ethernet is not supported for your OS!") if self.options.web_socket: if self.options["libwebsockets"].with_ssl != self.options.encryption: raise ConanInvalidConfiguration( "When web_socket is enabled, libwebsockets:with_ssl must have the value of open62541:encryption") def source(self): get(self, **self.conan_data["sources"][self.version], destination=self.source_folder, strip_root=True) submodule_filename = os.path.join( self.recipe_folder, 'submoduledata.yml') with open(submodule_filename, 'r') as submodule_stream: submodules_data = yaml.safe_load(submodule_stream) for path, submodule in submodules_data["submodules"][self.version].items(): filename = os.path.basename(submodule["url"]) archive_name = submodule["archive_pattern"].format( version=os.path.splitext(filename.replace('v', ''))[0]) submodule_data = { "url": submodule["url"], "sha256": submodule["sha256"] } get(self, **submodule_data) submodule_source = os.path.join(self.source_folder, path) rmdir(self, submodule_source) rename(self, archive_name, submodule_source) def _get_log_level(self): return { "Fatal": "600", "Error": "500", "Warning": "400", "Info": "300", "Debug": "200", "Trace": "100", "PackageOption": "300" }.get(str(self.options.logging_level), "300") def _get_multithreading_option(self): return { "None": "0", "Threadsafe": "100", "Internal threads": "200" }.get(str(self.options.multithreading), "0") def generate(self): tc = CMakeToolchain(self) version = Version(self.version) tc.variables["OPEN62541_VER_MAJOR"] = version.major tc.variables["OPEN62541_VER_MINOR"] = version.minor tc.variables["OPEN62541_VER_PATCH"] = version.patch tc.variables["UA_LOGLEVEL"] = self._get_log_level() tc.variables["UA_ENABLE_SUBSCRIPTIONS"] = self.options.subscription != False if self.options.subscription != False: if "events" in str(self.options.subscription): tc.variables["UA_ENABLE_SUBSCRIPTIONS_EVENTS"] = True if "alarms" in str(self.options.subscription) and "conditions" in str(self.options.subscription): tc.variables["UA_ENABLE_SUBSCRIPTIONS_ALARMS_CONDITIONS"] = True tc.variables["UA_ENABLE_METHODCALLS"] = self.options.methods tc.variables["UA_ENABLE_NODEMANAGEMENT"] = self.options.dynamic_nodes tc.variables["UA_ENABLE_AMALGAMATION"] = self.options.single_header if version >= "1.1.3": tc.variables["UA_MULTITHREADING"] = self._get_multithreading_option() tc.variables["UA_ENABLE_IMMUTABLE_NODES"] = self.options.imutable_nodes tc.variables["UA_ENABLE_WEBSOCKET_SERVER"] = self.options.web_socket tc.variables["UA_ENABLE_HISTORIZING"] = self.options.historize != False if self.options.historize != False: if self.options.historize == "Experimental": tc.variables["UA_ENABLE_EXPERIMENTAL_HISTORIZING"] = True tc.variables["UA_ENABLE_DISCOVERY"] = self.options.discovery != False if self.options.discovery != False: tc.variables["UA_ENABLE_DISCOVERY_MULTICAST"] = \ self.options.discovery == "With Multicast" or "multicast" in str( self.options.discovery) tc.variables["UA_ENABLE_DISCOVERY_SEMAPHORE"] = \ self.options.discovery_semaphore or "semaphore" in str( self.options.discovery) tc.variables["UA_ENABLE_QUERY"] = self.options.query if Version(self.version) >= "1.3.1": if self.options.encryption == "openssl": tc.variables["UA_ENABLE_ENCRYPTION"] = "OPENSSL" elif self.options.encryption == "mbedtls": tc.variables["UA_ENABLE_ENCRYPTION"] = "MBEDTLS" else: tc.variables["UA_ENABLE_ENCRYPTION"] = "OFF" else: tc.variables["UA_ENABLE_ENCRYPTION"] = self.options.encryption != False if self.options.encryption != False: if self.options.encryption == "openssl": tc.variables["UA_ENABLE_ENCRYPTION_OPENSSL"] = True tc.variables["UA_ENABLE_JSON_ENCODING"] = self.options.json_support tc.variables["UA_ENABLE_PUBSUB"] = self.options.pub_sub != False tc.variables["UA_ENABLE_PUBSUB_ENCRYPTION"] = self.options.pub_sub_encryption != False if self.options.pub_sub != False: if self.settings.os == "Linux" and self.options.pub_sub == "Ethernet": tc.variables["UA_ENABLE_PUBSUB_ETH_UADP"] = True elif self.settings.os == "Linux" and self.options.pub_sub == "Ethernet_XDP": tc.variables["UA_ENABLE_PUBSUB_ETH_UADP_XDP"] = True tc.variables["UA_ENABLE_DA"] = self.options.data_access if self.options.compiled_nodeset_descriptions == True: tc.variables["UA_ENABLE_NODESET_COMPILER_DESCRIPTIONS"] = self.options.compiled_nodeset_descriptions tc.variables["UA_NAMESPACE_ZERO"] = "FULL" else: tc.variables["UA_NAMESPACE_ZERO"] = self.options.namespace_zero if Version(self.version) < "1.3.1": tc.variables["UA_ENABLE_MICRO_EMB_DEV_PROFILE"] = self.options.embedded_profile tc.variables["UA_ENABLE_TYPENAMES"] = self.options.typenames tc.variables["UA_ENABLE_STATUSCODE_DESCRIPTIONS"] = self.options.readable_statuscodes tc.variables["UA_ENABLE_HARDENING"] = self.options.hardening if self.settings.compiler == "Visual Studio" and self.options.shared == True: tc.variables["UA_MSVC_FORCE_STATIC_CRT"] = True tc.variables["UA_COMPILE_AS_CXX"] = self.options.cpp_compatible tc.generate() tc = CMakeDeps(self) tc.generate() tc = VirtualBuildEnv(self) tc.generate(scope="build") def _patch_sources(self): apply_conandata_patches(self) if Version(self.version) >= "1.3.1": os.unlink(os.path.join(self.source_folder, "tools", "cmake", "FindPython3.cmake")) def build(self): self._patch_sources() cmake = CMake(self) cmake.configure() cmake.build() @property def _tools_subfolder(self): return os.path.join(self.source_folder, "tools") @property def _module_subfolder(self): return os.path.join("lib", "cmake", "open62541") @property def _module_file_rel_path(self): return os.path.join(self._module_subfolder, "open62541Macros.cmake") def package(self): self.copy("LICENSE", dst="licenses", src=self.source_folder) self.copy("LICENSE-CC0", dst="licenses", src=self.source_folder) cmake = CMake(self) cmake.install() rm(self, '*.pdb', os.path.join(self.package_folder, "bin")) rm(self, '*.pdb', os.path.join(self.package_folder, "lib")) for cmake_file in glob.glob(os.path.join(self.package_folder, self._module_subfolder, "*")): if not cmake_file.endswith(self._module_file_rel_path): os.remove(cmake_file) rmdir(self, os.path.join(self.package_folder, "lib", "pkgconfig")) rmdir(self, os.path.join(self.package_folder, "share")) self.copy("generate_*.py", src=self._tools_subfolder, dst=os.path.join("res", "tools")) self.copy("nodeset_compiler/*", src=self._tools_subfolder, dst=os.path.join("res", "tools")) @staticmethod def _chmod_plus_x(filename): if os.name == 'posix': os.chmod(filename, os.stat(filename).st_mode | 0o111) def package_info(self): self.cpp_info.names["cmake_find_package"] = "open62541" self.cpp_info.names["cmake_find_package_multi"] = "open62541" self.cpp_info.names["pkg_config"] = "open62541" self.cpp_info.libs = collect_libs(self) self.cpp_info.includedirs = [ "include", os.path.join("include", "open62541", "plugin") ] # required for creating custom servers from ua-nodeset self.conf_info.define("user.myconf:tools_dir", os.path.join( self.package_folder, "res", "tools")) # v1 legacy support self.user_info.tools_dir = os.path.join( self.package_folder, "res", "tools") self._chmod_plus_x(os.path.join(self.package_folder, "res", "tools", "generate_nodeid_header.py")) if self.options.single_header: self.cpp_info.defines.append("UA_ENABLE_AMALGAMATION") if self.settings.os == "Windows": self.cpp_info.system_libs.append("ws2_32") self.cpp_info.includedirs.append( os.path.join("include", "open62541", "win32")) else: self.cpp_info.includedirs.append( os.path.join("include", "open62541", "posix")) if self.settings.os in ("Linux", "FreeBSD"): self.cpp_info.system_libs.extend(["pthread", "m", "rt"]) self.cpp_info.builddirs = [self._module_subfolder] self.cpp_info.set_property("cmake_build_modules", [ self._module_file_rel_path]) ```

I will get an error:

CMake Error at CMakeLists.txt:17 (ua_generate_nodeset_and_datatypes):
  Unknown CMake command "ua_generate_nodeset_and_datatypes".

-- Configuring incomplete, errors occurred!
See also "/home/dg1024/Documents/projects/conan-center-index/recipes/open62541/all/test_v1_package/build/8130ca333cc035689d4db02db920b56a5f995fbb/CMakeFiles/CMakeOutput.log".
See also "/home/dg1024/Documents/projects/conan-center-index/recipes/open62541/all/test_v1_package/build/8130ca333cc035689d4db02db920b56a5f995fbb/CMakeFiles/CMakeError.log".
ERROR: open62541/1.3.4 (test package): Error in build() method, line 20
        cmake.configure()
        ConanException: Error 1 while executing cd '/home/dg1024/Documents/projects/conan-center-index/recipes/open62541/all/test_v1_package/build/8130ca333cc035689d4db02db920b56a5f995fbb' && cmake -G "Unix Makefiles" -DCMAKE_BUILD_TYPE="Release" -DCONAN_IN_LOCAL_CACHE="OFF" -DCONAN_COMPILER="gcc" -DCONAN_COMPILER_VERSION="10" -DCONAN_CXX_FLAGS="-m64" -DCONAN_SHARED_LINKER_FLAGS="-m64" -DCONAN_C_FLAGS="-m64" -DCONAN_LIBCXX="libstdc++11" -DCMAKE_INSTALL_PREFIX="/home/dg1024/Documents/projects/conan-center-index/recipes/open62541/all/test_v1_package/build/8130ca333cc035689d4db02db920b56a5f995fbb/package" -DCMAKE_INSTALL_BINDIR="bin" -DCMAKE_INSTALL_SBINDIR="bin" -DCMAKE_INSTALL_LIBEXECDIR="bin" -DCMAKE_INSTALL_LIBDIR="lib" -DCMAKE_INSTALL_INCLUDEDIR="include" -DCMAKE_INSTALL_OLDINCLUDEDIR="include" -DCMAKE_INSTALL_DATAROOTDIR="share" -DCMAKE_PREFIX_PATH="/home/dg1024/Documents/projects/conan-center-index/recipes/open62541/all/test_v1_package/build/8130ca333cc035689d4db02db920b56a5f995fbb" -DCMAKE_MODULE_PATH="/home/dg1024/Documents/projects/conan-center-index/recipes/open62541/all/test_v1_package/build/8130ca333cc035689d4db02db920b56a5f995fbb" -DCMAKE_EXPORT_NO_PACKAGE_REGISTRY="ON" -DCONAN_EXPORTED="1" -Dopen62541_NODESET_DIR="/home/dg1024/.conan/data/ua-nodeset/padim-1.02-2021-07-21/_/_/package/5ab84d6acfe1f23c4fae0ab88f26e3a396351ac9/res" -Dopen62541_TOOLS_DIR="/home/dg1024/.conan/data/open62541/1.3.4/_/_/package/22bc0e9ebfa1897cc2ab76ac0a8efd194cffa549/res/tools" -Wno-dev '/home/dg1024/Documents/projects/conan-center-index/recipes/open62541/all/test_v1_package'

Which is caused by the missing open62541Macros.cmake module, I can fix it by adding self.cpp_info.build_modules = [self._module_file_rel_path] in v2 recipe, but then I will get a CMAKE FILE NOT IN BUILD FOLDERS (KB-H019 warning on the github pipeline, which causes the entire pipeline to fail.

conanfile.py ```python from conan import ConanFile from conan.tools.cmake import cmake_layout, CMake, CMakeToolchain, CMakeDeps from conan.tools.env import VirtualBuildEnv from conan.tools.scm import Version from conan.tools.files import apply_conandata_patches, collect_libs, export_conandata_patches, rename, rm, rmdir, mkdir, get from conans.errors import ConanInvalidConfiguration import glob import os import yaml required_conan_version = ">=1.53.0" class Open62541Conan(ConanFile): name = "open62541" license = "MPLv2" homepage = "https://open62541.org/" url = "https://github.com/conan-io/conan-center-index" description = "open62541 is an open source and free implementation of OPC UA " \ "(OPC Unified Architecture) written in the common subset of the " \ "C99 and C++98 languages. The library is usable with all major " \ "compilers and provides the necessary tools to implement dedicated " \ "OPC UA clients and servers, or to integrate OPC UA-based communication " \ "into existing applications. open62541 library is platform independent. " \ "All platform-specific functionality is implemented via exchangeable " \ "plugins. Plugin implementations are provided for the major operating systems." topics = ( "opc ua", "open62541", "sdk", "server/client", "c", "iec-62541", "industrial automation", "tsn", "time sensitive networks", "publish-subscirbe", "pubsub" ) settings = "os", "compiler", "build_type", "arch" options = { "fPIC": [True, False], "shared": [True, False], # False: UA_ENABLE_HISTORIZING=Off # True: UA_ENABLE_HISTORIZING=On # Experimental: UA_ENABLE_HISTORIZING=On and UA_ENABLE_EXPERIMENTAL_HISTORIZING=On "historize": [True, False, "Experimental"], "logging_level": ["Fatal", "Error", "Warning", "Info", "Debug", "Trace"], # False: UA_ENABLE_SUBSCRIPTIONS=Off # True: UA_ENABLE_SUBSCRIPTIONS=On # With Events: deprecated. Use 'events' instead # events: UA_ENABLE_SUBSCRIPTIONS_EVENTS=On # alarms,conditions,events: UA_ENABLE_SUBSCRIPTIONS_EVENTS=On and UA_ENABLE_SUBSCRIPTIONS_ALARMS_CONDITIONS=On "subscription": [True, False, "With Events", "events", "alarms,conditions,events"], # False: UA_ENABLE_METHODCALLS=Off # True: UA_ENABLE_METHODCALLS=Onn "methods": [True, False], # False: UA_ENABLE_NODEMANAGEMENT=Off # True: UA_ENABLE_NODEMANAGEMENT=On "dynamic_nodes": [True, False], # False: UA_ENABLE_AMALGAMATION=Off # True: UA_ENABLE_AMALGAMATION=On "single_header": [True, False], # None: UA_MULTITHREADING=0 # Threadsafe: UA_MULTITHREADING=100 # Internal threads: UA_MULTITHREADING=200 "multithreading": ["None", "Threadsafe", "Internal threads"], # False: UA_ENABLE_IMMUTABLE_NODES=Off # True: UA_ENABLE_IMMUTABLE_NODES=On "imutable_nodes": [True, False], # False: UA_ENABLE_WEBSOCKET_SERVER=Off # True: UA_ENABLE_WEBSOCKET_SERVER=On "web_socket": [True, False], # False: UA_ENABLE_DISCOVERY=Off # True: UA_ENABLE_DISCOVERY=On # With Multicast: Deprecated. Use 'multicast' instead # multicast: UA_ENABLE_DISCOVERY_MULTICAST=On # semaphore: UA_ENABLE_DISCOVERY_SEMAPHORE=On # multicast,semaphore: UA_ENABLE_DISCOVERY_MULTICAST=On and UA_ENABLE_DISCOVERY_SEMAPHORE=On "discovery": [True, False, "With Multicast", "multicast", "semaphore", "multicast,semaphore"], # Deprecated. Use discovery=semaphore instead "discovery_semaphore": [True, False], # False: UA_ENABLE_QUERY=Off # True: UA_ENABLE_QUERY=On "query": [True, False], # False: UA_ENABLE_ENCRYPTION=Off # openssl: UA_ENABLE_ENCRYPTION=On and UA_ENABLE_ENCRYPTION_OPENSSL=On # mbedtls: UA_ENABLE_ENCRYPTION=On # changed in 1.3.1 - UA_ENABLE_ENCRYPTION can be OFF, OPENSSL, MBEDTLS "encryption": [False, "openssl", "mbedtls"], # False: UA_ENABLE_JSON_ENCODING=Off # True: UA_ENABLE_JSON_ENCODING=On "json_support": [True, False], # False: UA_ENABLE_PUBSUB=Off # Simple: UA_ENABLE_PUBSUB=On # Ethernet: UA_ENABLE_PUBSUB=On and UA_ENABLE_PUBSUB_ETH_UADP=On # Ethernet_XDP: UA_ENABLE_PUBSUB=On and UA_ENABLE_PUBSUB_ETH_UADP_XDP=On "pub_sub": [False, "Simple", "Ethernet", "Ethernet_XDP"], # False: UA_ENABLE_PUBSUB_ENCRYPTION=Off # True: UA_ENABLE_PUBSUB_ENCRYPTION=On "pub_sub_encryption": [True, False], # False: UA_ENABLE_DA=Off # True: UA_ENABLE_DA=On "data_access": [True, False], # False: UA_ENABLE_NODESET_COMPILER_DESCRIPTIONS=Off and UA_NAMESPACE_ZERO=options.namespace_zero # True: UA_ENABLE_NODESET_COMPILER_DESCRIPTIONS=On and UA_NAMESPACE_ZERO=Full "compiled_nodeset_descriptions": [True, False], # UA_NAMESPACE_ZERO=option.namespace_zero (only if compiled_nodeset_descriptions=False) "namespace_zero": ["MINIMAL", "REDUCED", "FULL"], # UA_ENABLE_MICRO_EMB_DEV_PROFILE=embedded_profile "embedded_profile": [True, False], # UA_ENABLE_TYPENAMES=typenames "typenames": [True, False], # UA_ENABLE_HARDENING=hardening "hardening": [True, False], # UA_COMPILE_AS_CXX=cpp_compatible "cpp_compatible": [True, False], # UA_ENABLE_STATUSCODE_DESCRIPTIONS=readable_statuscodes "readable_statuscodes": [True, False] } default_options = { "fPIC": True, "shared": False, "historize": False, "logging_level": "Info", "subscription": True, "methods": True, "dynamic_nodes": True, "single_header": False, "multithreading": "None", "imutable_nodes": False, "web_socket": False, "discovery": "semaphore", "discovery_semaphore": True, "query": False, "encryption": False, "json_support": False, "pub_sub": False, "pub_sub_encryption": False, "data_access": True, "compiled_nodeset_descriptions": True, "namespace_zero": "FULL", "embedded_profile": False, "typenames": True, "hardening": True, "cpp_compatible": False, "readable_statuscodes": True } exports_sources = ["CMakeLists.txt", "patches/**"] exports = "submoduledata.yml" short_paths = True def export_sources(self): export_conandata_patches(self) def config_options(self): if self.settings.os == "Windows": del self.options.fPIC if Version(self.version) >= "1.3.1": del self.options.embedded_profile def configure(self): if self.options.shared: self.options.rm_safe("fPIC") if not self.options.cpp_compatible: self.settings.rm_safe("compiler.libcxx") self.settings.rm_safe("compiler.cppstd") # Due to https://github.com/open62541/open62541/issues/4687 we cannot build with 1.2.2 + Windows + shared if Version(self.version) >= "1.2.2" and self.settings.os == "Windows" and self.options.shared: raise ConanInvalidConfiguration("{0} {1} doesn't properly support shared lib on Windows".format(self.name, self.version)) if self.options.subscription == "With Events": self.output.warning("`{name}:subscription=With Events` is deprecated. Use `{name}:subscription=events` instead".format( name=self.name)) # Deprecated in 1.2.2 self.options.subscription = "events" if self.options.web_socket: self.options["libwebsockets"].with_ssl = self.options.encryption def layout(self): cmake_layout(self, src_folder="source") def requirements(self): if self.options.encryption == "mbedtls": self.requires("mbedtls/2.25.0") elif self.options.encryption == "openssl": self.requires("openssl/1.1.1o") if self.options.web_socket: self.requires("libwebsockets/4.2.0") if self.options.discovery == "With Multicast" or "multicast" in str(self.options.discovery): self.requires("pro-mdnsd/0.8.4") def validate(self): if not self.options.subscription: raise ConanInvalidConfiguration( "Open62541 requires subscription option") if not self.options.discovery: if self.options.discovery_semaphore: raise ConanInvalidConfiguration( "Open62541 discovery sempahore option requires discovery option to be enabled") if Version(self.version) < "1.1.0": if self.options.encryption == "openssl": raise ConanInvalidConfiguration( "Lower Open62541 versions than 1.1.0 do not support openssl") if self.options.multithreading != "None": raise ConanInvalidConfiguration( "Lower Open62541 versions than 1.1.0 do not fully support multithreading") if self.options.web_socket: raise ConanInvalidConfiguration( "Lower Open62541 versions than 1.1.0 do not fully support websockets") if self.options.cpp_compatible: raise ConanInvalidConfiguration( "Lower Open62541 versions than 1.1.0 are not cpp compatible due to -fpermisive flags") # FIXME: correct clang versions condition max_clang_version = "8" if Version( self.version) < "1.1.0" else "9" if self.settings.compiler == "clang" and Version(self.settings.compiler.version) > max_clang_version: raise ConanInvalidConfiguration( "Open62541 supports Clang up to {} compiler version".format(max_clang_version)) if self.settings.compiler == "clang": if Version(self.settings.compiler.version) < "5": raise ConanInvalidConfiguration( "Older clang compiler version than 5.0 are not supported") if self.options.pub_sub != False and self.settings.os != "Linux": raise ConanInvalidConfiguration( "PubSub over Ethernet is not supported for your OS!") if self.options.web_socket: if self.options["libwebsockets"].with_ssl != self.options.encryption: raise ConanInvalidConfiguration( "When web_socket is enabled, libwebsockets:with_ssl must have the value of open62541:encryption") def source(self): get(self, **self.conan_data["sources"][self.version], destination=self.source_folder, strip_root=True) submodule_filename = os.path.join( self.recipe_folder, 'submoduledata.yml') with open(submodule_filename, 'r') as submodule_stream: submodules_data = yaml.safe_load(submodule_stream) for path, submodule in submodules_data["submodules"][self.version].items(): filename = os.path.basename(submodule["url"]) archive_name = submodule["archive_pattern"].format( version=os.path.splitext(filename.replace('v', ''))[0]) submodule_data = { "url": submodule["url"], "sha256": submodule["sha256"] } get(self, **submodule_data) submodule_source = os.path.join(self.source_folder, path) rmdir(self, submodule_source) rename(self, archive_name, submodule_source) def _get_log_level(self): return { "Fatal": "600", "Error": "500", "Warning": "400", "Info": "300", "Debug": "200", "Trace": "100", "PackageOption": "300" }.get(str(self.options.logging_level), "300") def _get_multithreading_option(self): return { "None": "0", "Threadsafe": "100", "Internal threads": "200" }.get(str(self.options.multithreading), "0") def generate(self): tc = CMakeToolchain(self) version = Version(self.version) tc.variables["OPEN62541_VER_MAJOR"] = version.major tc.variables["OPEN62541_VER_MINOR"] = version.minor tc.variables["OPEN62541_VER_PATCH"] = version.patch tc.variables["UA_LOGLEVEL"] = self._get_log_level() tc.variables["UA_ENABLE_SUBSCRIPTIONS"] = self.options.subscription != False if self.options.subscription != False: if "events" in str(self.options.subscription): tc.variables["UA_ENABLE_SUBSCRIPTIONS_EVENTS"] = True if "alarms" in str(self.options.subscription) and "conditions" in str(self.options.subscription): tc.variables["UA_ENABLE_SUBSCRIPTIONS_ALARMS_CONDITIONS"] = True tc.variables["UA_ENABLE_METHODCALLS"] = self.options.methods tc.variables["UA_ENABLE_NODEMANAGEMENT"] = self.options.dynamic_nodes tc.variables["UA_ENABLE_AMALGAMATION"] = self.options.single_header if version >= "1.1.3": tc.variables["UA_MULTITHREADING"] = self._get_multithreading_option() tc.variables["UA_ENABLE_IMMUTABLE_NODES"] = self.options.imutable_nodes tc.variables["UA_ENABLE_WEBSOCKET_SERVER"] = self.options.web_socket tc.variables["UA_ENABLE_HISTORIZING"] = self.options.historize != False if self.options.historize != False: if self.options.historize == "Experimental": tc.variables["UA_ENABLE_EXPERIMENTAL_HISTORIZING"] = True tc.variables["UA_ENABLE_DISCOVERY"] = self.options.discovery != False if self.options.discovery != False: tc.variables["UA_ENABLE_DISCOVERY_MULTICAST"] = \ self.options.discovery == "With Multicast" or "multicast" in str( self.options.discovery) tc.variables["UA_ENABLE_DISCOVERY_SEMAPHORE"] = \ self.options.discovery_semaphore or "semaphore" in str( self.options.discovery) tc.variables["UA_ENABLE_QUERY"] = self.options.query if Version(self.version) >= "1.3.1": if self.options.encryption == "openssl": tc.variables["UA_ENABLE_ENCRYPTION"] = "OPENSSL" elif self.options.encryption == "mbedtls": tc.variables["UA_ENABLE_ENCRYPTION"] = "MBEDTLS" else: tc.variables["UA_ENABLE_ENCRYPTION"] = "OFF" else: tc.variables["UA_ENABLE_ENCRYPTION"] = self.options.encryption != False if self.options.encryption != False: if self.options.encryption == "openssl": tc.variables["UA_ENABLE_ENCRYPTION_OPENSSL"] = True tc.variables["UA_ENABLE_JSON_ENCODING"] = self.options.json_support tc.variables["UA_ENABLE_PUBSUB"] = self.options.pub_sub != False tc.variables["UA_ENABLE_PUBSUB_ENCRYPTION"] = self.options.pub_sub_encryption != False if self.options.pub_sub != False: if self.settings.os == "Linux" and self.options.pub_sub == "Ethernet": tc.variables["UA_ENABLE_PUBSUB_ETH_UADP"] = True elif self.settings.os == "Linux" and self.options.pub_sub == "Ethernet_XDP": tc.variables["UA_ENABLE_PUBSUB_ETH_UADP_XDP"] = True tc.variables["UA_ENABLE_DA"] = self.options.data_access if self.options.compiled_nodeset_descriptions == True: tc.variables["UA_ENABLE_NODESET_COMPILER_DESCRIPTIONS"] = self.options.compiled_nodeset_descriptions tc.variables["UA_NAMESPACE_ZERO"] = "FULL" else: tc.variables["UA_NAMESPACE_ZERO"] = self.options.namespace_zero if Version(self.version) < "1.3.1": tc.variables["UA_ENABLE_MICRO_EMB_DEV_PROFILE"] = self.options.embedded_profile tc.variables["UA_ENABLE_TYPENAMES"] = self.options.typenames tc.variables["UA_ENABLE_STATUSCODE_DESCRIPTIONS"] = self.options.readable_statuscodes tc.variables["UA_ENABLE_HARDENING"] = self.options.hardening if self.settings.compiler == "Visual Studio" and self.options.shared == True: tc.variables["UA_MSVC_FORCE_STATIC_CRT"] = True tc.variables["UA_COMPILE_AS_CXX"] = self.options.cpp_compatible tc.generate() tc = CMakeDeps(self) tc.generate() tc = VirtualBuildEnv(self) tc.generate(scope="build") def _patch_sources(self): apply_conandata_patches(self) if Version(self.version) >= "1.3.1": os.unlink(os.path.join(self.source_folder, "tools", "cmake", "FindPython3.cmake")) def build(self): self._patch_sources() cmake = CMake(self) cmake.configure() cmake.build() @property def _tools_subfolder(self): return os.path.join(self.source_folder, "tools") @property def _module_subfolder(self): return os.path.join("lib", "cmake", "open62541") @property def _module_file_rel_path(self): return os.path.join(self._module_subfolder, "open62541Macros.cmake") def package(self): self.copy("LICENSE", dst="licenses", src=self.source_folder) self.copy("LICENSE-CC0", dst="licenses", src=self.source_folder) cmake = CMake(self) cmake.install() rm(self, '*.pdb', os.path.join(self.package_folder, "bin")) rm(self, '*.pdb', os.path.join(self.package_folder, "lib")) for cmake_file in glob.glob(os.path.join(self.package_folder, self._module_subfolder, "*")): if not cmake_file.endswith(self._module_file_rel_path): os.remove(cmake_file) rmdir(self, os.path.join(self.package_folder, "lib", "pkgconfig")) rmdir(self, os.path.join(self.package_folder, "share")) self.copy("generate_*.py", src=self._tools_subfolder, dst=os.path.join("res", "tools")) self.copy("nodeset_compiler/*", src=self._tools_subfolder, dst=os.path.join("res", "tools")) @staticmethod def _chmod_plus_x(filename): if os.name == 'posix': os.chmod(filename, os.stat(filename).st_mode | 0o111) def package_info(self): self.cpp_info.names["cmake_find_package"] = "open62541" self.cpp_info.names["cmake_find_package_multi"] = "open62541" self.cpp_info.names["pkg_config"] = "open62541" self.cpp_info.libs = collect_libs(self) self.cpp_info.includedirs = [ "include", os.path.join("include", "open62541", "plugin") ] # required for creating custom servers from ua-nodeset self.conf_info.define("user.myconf:tools_dir", os.path.join( self.package_folder, "res", "tools")) # v1 legacy support self.user_info.tools_dir = os.path.join( self.package_folder, "res", "tools") self._chmod_plus_x(os.path.join(self.package_folder, "res", "tools", "generate_nodeid_header.py")) if self.options.single_header: self.cpp_info.defines.append("UA_ENABLE_AMALGAMATION") if self.settings.os == "Windows": self.cpp_info.system_libs.append("ws2_32") self.cpp_info.includedirs.append( os.path.join("include", "open62541", "win32")) else: self.cpp_info.includedirs.append( os.path.join("include", "open62541", "posix")) if self.settings.os in ("Linux", "FreeBSD"): self.cpp_info.system_libs.extend(["pthread", "m", "rt"]) self.cpp_info.builddirs = [self._module_subfolder] self.cpp_info.build_modules = [self._module_file_rel_path] self.cpp_info.set_property("cmake_build_modules", [ self._module_file_rel_path]) ```

I will push the latest changes, and double check if this still causes the pipeline to fail, but I have a sneaking suspicion that it will

SpaceIm commented 1 year ago

you should append to self.cpp_info.builddirs, otherwise it can break few things in conan v1.

saukijan commented 1 year ago

you should append to self.cpp_info.builddirs, otherwise it can break few things in conan v1.

Will do! Thanks for the tip @SpaceIm !

saukijan commented 1 year ago

as I suspected, @memsharded, pipeline fails due to post_package_info(): WARN: [CMAKE FILE NOT IN BUILD FOLDERS (KB-H019)] cpp_info.build_modules is not a dictionary hook.

memsharded commented 1 year ago

quick tip: Avoid naming user.myconf:tools_dir generic name. It should be something like user.open62541:tools_dir instead

saukijan commented 1 year ago

@memsharded your suggestion seems to be working, the post_package_info(): WARN: [CMAKE FILE NOT IN BUILD FOLDERS (KB-H019)] cpp_info.build_modules is not a dictionary issue was probably being caused by using self.cpp_info.build_modules = [self._module_file_rel_path] instead of self.cpp_info.build_modules["cmake_find_package"] = [self._module_file_rel_path]

You can close this issue if this solution is satisfactory

saukijan commented 1 year ago

quick tip: Avoid naming user.myconf:tools_dir generic name. It should be something like user.open62541:tools_dir instead

Thanks for the tip @memsharded, @SpaceIm mentioned that there was a guideline for that, but I could not find it in conan-center-index contribution guide

memsharded commented 1 year ago

Good, closing the issue then, thanks for following up!