diff --git a/recipes/boost/all/conandata.yml b/recipes/boost/all/conandata.yml index 8a97c3892858f..765b415990da3 100644 --- a/recipes/boost/all/conandata.yml +++ b/recipes/boost/all/conandata.yml @@ -34,6 +34,12 @@ sources: "https://sourceforge.net/projects/boost/files/boost/1.74.0/boost_1_74_0.tar.bz2" ] sha256: "83bfc1507731a0906e387fc28b7ef5417d591429e51e788417fe9ff025e116b1" + 1.75.0: + url: [ + "https://dl.bintray.com/boostorg/release/1.75.0/source/boost_1_75_0.tar.bz2", + "https://sourceforge.net/projects/boost/files/boost/1.75.0/boost_1_75_0.tar.bz2" + ] + sha256: "953db31e016db7bb207f11432bef7df100516eeb746843fa0486a222e3fd49cb" patches: 1.69.0: - patch_file: "patches/boost_build_asmflags.patch" @@ -93,3 +99,8 @@ patches: base_path: "source_subfolder" - patch_file: "patches/python_base_prefix_since_1_74.patch" base_path: "source_subfolder" + 1.75.0: + - patch_file: "patches/boost_build_qcc_fix_debug_build_parameter_since_1_74.patch" + base_path: "source_subfolder" + - patch_file: "patches/python_base_prefix_since_1_74.patch" + base_path: "source_subfolder" diff --git a/recipes/boost/all/conanfile.py b/recipes/boost/all/conanfile.py index 7bc414ea540cf..1782b8315fcfe 100644 --- a/recipes/boost/all/conanfile.py +++ b/recipes/boost/all/conanfile.py @@ -4,6 +4,7 @@ from conans.errors import ConanException from conans.errors import ConanInvalidConfiguration +import glob import os import sys import shlex @@ -34,10 +35,12 @@ "graph", "graph_parallel", "iostreams", + "json", "locale", "log", "math", "mpi", + "nowide", "program_options", "python", "random", @@ -64,7 +67,6 @@ class BoostConan(ConanFile): _options = None - options = { "shared": [True, False], "header_only": [True, False], @@ -129,6 +131,26 @@ class BoostConan(ConanFile): def export(self): self.copy(self._dependency_filename, src="dependencies", dst="dependencies") + @property + def _min_compiler_version_default_cxx11(self): + # Minimum compiler version having c++ standard >= 11 + return { + "gcc": 6, + "clang": 6, + "apple-clang": 12, # guess + "Visual Studio": 14, # guess + }.get(str(self.settings.compiler)) + + @property + def _min_compiler_version_nowide(self): + # Nowide needs c++11 + swappable std::fstream + return { + "gcc": 5, + "clang": 5, + "apple-clang": 12, # guess + "Visual Studio": 14, # guess + }.get(str(self.settings.compiler)) + @property def _dependency_filename(self): return "dependencies-{}.yml".format(self.version) @@ -140,15 +162,18 @@ def _dependencies(self): raise ConanException("Cannot find {}".format(dependencies_filepath)) return yaml.load(open(dependencies_filepath)) - def _iter_modules(self): - tree = {k: v[:] for k, v in self._dependencies["dependencies"].items()} - while tree: - nodeps = set(k for k, v in tree.items() if not v) - if not nodeps: - raise ConanException("cyclic dependency tree detected") - for nodep in nodeps: - yield nodep - tree = {k: [d for d in v if d not in nodeps] for k, v in tree.items() if k not in nodeps} + def _all_dependent_modules(self, name): + dependencies = {name} + while True: + new_dependencies = set() + for dependency in dependencies: + new_dependencies.update(set(self._dependencies["dependencies"][dependency])) + new_dependencies.update(dependencies) + if len(new_dependencies) > len(dependencies): + dependencies = new_dependencies + else: + break + return dependencies @property def _source_subfolder(self): @@ -188,6 +213,21 @@ def config_options(self): if "without_{}".format(opt_name) not in self.options: raise ConanException("{} has the configure options {} which is not available in conanfile.py".format(self._dependency_filename, opt_name)) + # nowide requires a c++11-able compiler + movable std::fstream: change default to not build on compiler with too old default c++ standard or too low compiler.cppstd + # json requires a c++11-able compiler: change default to not build on compiler with too old default c++ standard or too low compiler.cppstd + if self.settings.compiler.cppstd: + if not tools.valid_min_cppstd(self, 11): + self.options.without_fiber = True + self.options.without_nowide = True + self.options.without_json = True + else: + version_cxx11_standard_json = self._min_compiler_version_default_cxx11 + if version_cxx11_standard_json: + if tools.Version(self.settings.compiler.version) < version_cxx11_standard_json: + self.options.without_fiber = True + self.options.without_json = True + self.options.without_nowide = True + # Remove options not supported by this version of boost for dep_name in CONFIGURE_OPTIONS: if dep_name not in self._configure_options: @@ -198,8 +238,11 @@ def _configure_options(self): return self._dependencies["configure_options"] def configure(self): - if not self.options.i18n_backend and not self.options.without_locale: - raise ConanInvalidConfiguration("Boost 'locale' library requires a i18n_backend, either 'icu' or 'iconv'") + if self.options.without_locale: + self.options.i18n_backend = None + else: + if not self.options.i18n_backend: + raise ConanInvalidConfiguration("Boost.locale library requires a i18n_backend (either 'icu' or 'iconv')") if not self.options.multithreading: # * For the reason 'thread' is deactivate look at https://stackoverflow.com/a/20991533 @@ -225,6 +268,44 @@ def configure(self): self.options.python_version = self._detect_python_version() self.options.python_executable = self._python_executable + if not self.options.get_safe("without_nowide", True): + # nowide require a c++11-able compiler with movable std::fstream + mincompiler_version = self._min_compiler_version_nowide + if mincompiler_version: + if tools.Version(self.settings.compiler.version) < mincompiler_version: + raise ConanInvalidConfiguration("This compiler is too old to build Boost.nowide.") + + if self.settings.compiler.cppstd: + tools.check_min_cppstd(self, 11) + else: + version_cxx11_standard = self._min_compiler_version_default_cxx11 + if version_cxx11_standard: + if tools.Version(self.settings.compiler.version) < version_cxx11_standard: + raise ConanInvalidConfiguration("Boost.{fiber,json} require a c++11 compiler (please set compiler.cppstd or use a newer compiler)") + else: + self.output.warn("I don't know what the default c++ standard of this compiler is. I suppose it supports c++11 by default.\n" + "This might cause some boost libraries not being built and conan components to fail.") + + # FIXME: check this + shouldn't default be on self._is_msvc? + # if self.options.layout == "b2-default": + # self.options.layout = "versioned" if self.settings.os == "Windows" else "system" + + if not all((self.options.without_fiber, self.options.get_safe("without_json", True))): + # fiber/json require a c++11-able compiler. + if self.settings.compiler.cppstd: + tools.check_min_cppstd(self, 11) + else: + version_cxx11_standard = self._min_compiler_version_default_cxx11 + if version_cxx11_standard: + if tools.Version(self.settings.compiler.version) < version_cxx11_standard: + raise ConanInvalidConfiguration("Boost.{fiber,json} requires a c++11 compiler (please set compiler.cppstd or use a newer compiler)") + else: + self.output.warn("I don't know what the default c++ standard of this compiler is. I suppose it supports c++11 by default.\n" + "This might cause some boost libraries not being built and conan components to fail.") + + if self.options.layout == "b2-default": + self.options.layout = "versioned" if self.settings.os == "Windows" else "system" + def build_requirements(self): if not self.options.header_only: self.build_requires("b2/4.2.0") @@ -584,7 +665,7 @@ def _b2_os(self): @property def _b2_address_model(self): - if str(self.settings.arch) in ["x86_64", "ppc64", "ppc64le", "mips64", "armv8", "sparcv9"]: + if self.settings.arch in ("x86_64", "ppc64", "ppc64le", "mips64", "armv8", "armv8.3", "sparcv9"): return "64" else: return "32" @@ -651,6 +732,9 @@ def _gnu_cxx11_abi(self): def _build_flags(self): flags = self._build_cross_flags + # Stop at the first error. No need to continue building. + flags.append("-q") + # https://www.boost.org/doc/libs/1_70_0/libs/context/doc/html/context/architectures.html if self._b2_os: flags.append("target-os=%s" % self._b2_os) @@ -663,8 +747,7 @@ def _build_flags(self): if self._b2_abi: flags.append("abi=%s" % self._b2_abi) - if self.options.layout is not "b2-default": - flags.append("--layout=%s" % self.options.layout) + flags.append("--layout=%s" % self.options.layout) flags.append("--user-config=%s" % os.path.join(self._boost_build_dir, 'user-config.jam')) flags.append("-sNO_ZLIB=%s" % ("0" if self._with_zlib else "1")) flags.append("-sNO_BZIP2=%s" % ("0" if self._with_bzip2 else "1")) @@ -707,14 +790,17 @@ def add_defines(library): flags.append("variant=release") for libname in self._configure_options: - if getattr(self.options, "without_%s" % libname): - flags.append("--without-%s" % libname) + if not getattr(self.options, "without_%s" % libname): + flags.append("--with-%s" % libname) flags.append("toolset=%s" % self._toolset) if self.settings.get_safe("compiler.cppstd"): flags.append("cxxflags=%s" % cppstd_flag(self.settings)) + # LDFLAGS + link_flags = [] + # CXX FLAGS cxx_flags = [] # fPIC DEFINITION @@ -727,18 +813,19 @@ def add_defines(library): elif self.settings.compiler == "Visual Studio": cxx_flags.append("/Z7") + # Standalone toolchain fails when declare the std lib - if self.settings.os != "Android" and self.settings.os != "Emscripten": + if self.settings.os not in ("Android", "Emscripten"): try: if self._gnu_cxx11_abi: flags.append("define=_GLIBCXX_USE_CXX11_ABI=%s" % self._gnu_cxx11_abi) - if "clang" in str(self.settings.compiler): - if str(self.settings.compiler.libcxx) == "libc++": - cxx_flags.append("-stdlib=libc++") - flags.append('linkflags="-stdlib=libc++"') - else: - cxx_flags.append("-stdlib=libstdc++") + if self.settings.compiler in ("clang", "apple-clang"): + libcxx = { + "libstdc++11": "libstdc++", + }.get(str(self.settings.compiler.libcxx), str(self.settings.compiler.libcxx)) + cxx_flags.append("-stdlib={}".format(libcxx)) + link_flags.append("-stdlib={}".format(libcxx)) except: pass @@ -770,6 +857,21 @@ def add_defines(library): cxx_flags.append("-fvisibility-inlines-hidden") cxx_flags.append("-fembed-bitcode") + if self._with_iconv: + flags.append("-sICONV_PATH={}".format(self.deps_cpp_info["libiconv"].rootpath)) + if self._with_icu: + flags.append("-sICU_PATH={}".format(self.deps_cpp_info["icu"].rootpath)) + if not self.options["icu"].shared: + # Using ICU_OPTS to pass ICU system libraries is not possible due to Boost.Regex disallowing it. + if self.settings.compiler == "Visual Studio": + icu_ldflags = " ".join("{}.lib".format(l) for l in self.deps_cpp_info["icu"].system_libs) + else: + icu_ldflags = " ".join("-l{}".format(l) for l in self.deps_cpp_info["icu"].system_libs) + link_flags.append(icu_ldflags) + + link_flags = 'linkflags="%s"' % " ".join(link_flags) if link_flags else "" + flags.append(link_flags) + cxx_flags = 'cxxflags="%s"' % " ".join(cxx_flags) if cxx_flags else "" flags.append(cxx_flags) @@ -982,6 +1084,15 @@ def package(self): self.output.info("Unlinking static duplicate library: {}".format(os.path.join(self.package_folder, "lib", "lib{}.lib".format(common_lib)))) os.unlink(os.path.join(self.package_folder, "lib", "lib{}.lib".format(common_lib))) + dll_pdbs = glob.glob(os.path.join(self.package_folder, "lib", "*.dll")) + \ + glob.glob(os.path.join(self.package_folder, "lib", "*.pdb")) + if dll_pdbs: + tools.mkdir(os.path.join(self.package_folder, "bin")) + for bin_file in dll_pdbs: + os.rename(bin_file, os.path.join(self.package_folder, "bin", os.path.basename(bin_file))) + + tools.remove_files_by_mask(os.path.join(self.package_folder, "bin"), "*.pdb") + def _create_emscripten_libs(self): # Boost Build doesn't create the libraries, but it gets close, # leaving .bc files where the libraries would be. @@ -998,11 +1109,6 @@ def _create_emscripten_libs(self): self.output.info(cmd) self.run(cmd) - @property - def _is_versioned_layout(self): - layout = self.options.get_safe("layout") - return layout == "versioned" or (layout == "b2-default" and os.name == 'nt') - @staticmethod def _option_to_conan_requirement(name): return { @@ -1042,7 +1148,7 @@ def package_info(self): if self.options.error_code_header_only: self.cpp_info.components["headers"].defines.append("BOOST_ERROR_CODE_HEADER_ONLY") - if self._is_versioned_layout: + if self.options.layout == "versioned": version = tools.Version(self.version) self.cpp_info.components["headers"].includedirs.append(os.path.join("include", "boost-{}_{}".format(version.major, version.minor))) @@ -1053,7 +1159,6 @@ def package_info(self): if not self.options.header_only: self.cpp_info.components["_libboost"].requires = ["headers"] - self.cpp_info.components["_libboost"].bindirs.append("lib") self.cpp_info.components["diagnostic_definitions"].libs = [] self.cpp_info.components["diagnostic_definitions"].names["cmake_find_package"] = "diagnostic_definitions" @@ -1086,34 +1191,45 @@ def package_info(self): # A Boost::dynamic_linking cmake target does only make sense for a shared boost package self.cpp_info.components["dynamic_linking"].defines = ["BOOST_ALL_DYN_LINK"] - libsuffix = "" - if self._is_versioned_layout: - # https://www.boost.org/doc/libs/1_73_0/more/getting_started/windows.html#library-naming - toolset_tag = "-{}".format(self._toolset_tag) - threading_tag = "-mt" if self.options.multithreading else "" - abi_tag = "" - if self._is_msvc: - # FIXME: add 'y' when using cpython cci package and when python is built in debug mode - static_runtime_key = "s" if "MT" in str(self.settings.compiler.runtime) else "" - debug_runtime_key = "g" if "d" in str(self.settings.compiler.runtime) else "" - debug_key = "d" if self.settings.build_type == "Debug" else "" - abi = static_runtime_key + debug_runtime_key + debug_key - if abi: - abi_tag = "-{}".format(abi) - else: - debug_tag = "d" if self.settings.build_type == "Debug" else "" - abi = debug_tag - if abi: - abi_tag = "-{}".format(abi) - - arch_tag = "-{}{}".format(self._b2_architecture[0], self._b2_address_model) - version = tools.Version(self.version) - if not version.patch or version.patch == "0": - version_tag = "-{}_{}".format(version.major, version.minor) - else: - version_tag = "-{}_{}_{}".format(version.major, version.minor, version.patch) - libsuffix = toolset_tag + threading_tag + abi_tag + arch_tag + version_tag - self.output.info("Versioning library suffix: {}".format(libsuffix)) + # https://www.boost.org/doc/libs/1_73_0/more/getting_started/windows.html#library-naming + # libsuffix for MSVC: + # - system: "" + # - versioned: "-vc142-mt-d-x64-1_74" + # - tagged: "-mt-d-x64" + libsuffix_lut = { + "system": "", + "versioned": "{toolset}{threading}{abi}{arch}{version}", + "tagged": "{threading}{abi}{arch}", + } + libsuffix_data = { + "toolset": "-{}".format(self._toolset_tag), + "threading": "-mt" if self.options.multithreading else "", + "abi": "", + "ach": "", + "version": "", + } + if self._is_msvc: # FIXME: mingw? + # FIXME: add 'y' when using cpython cci package and when python is built in debug mode + static_runtime_key = "s" if "MT" in str(self.settings.compiler.runtime) else "" + debug_runtime_key = "g" if "d" in str(self.settings.compiler.runtime) else "" + debug_key = "d" if self.settings.build_type == "Debug" else "" + abi = static_runtime_key + debug_runtime_key + debug_key + if abi: + libsuffix_data["abi"] = "-{}".format(abi) + else: + debug_tag = "d" if self.settings.build_type == "Debug" else "" + abi = debug_tag + if abi: + libsuffix_data["abi"] = "-{}".format(abi) + + libsuffix_data["arch"] = "-{}{}".format(self._b2_architecture[0], self._b2_address_model) + version = tools.Version(self.version) + if not version.patch or version.patch == "0": + libsuffix_data["version"] = "-{}_{}".format(version.major, version.minor) + else: + libsuffix_data["version"] = "-{}_{}_{}".format(version.major, version.minor, version.patch) + libsuffix = libsuffix_lut[str(self.options.layout)].format(**libsuffix_data) + self.output.info("Library layout suffix: {}".format(repr(libsuffix))) libformatdata = {} if not self.options.without_python: @@ -1131,14 +1247,16 @@ def add_libprefix(n): modules_seen = set() detected_libraries = set(tools.collect_libs(self)) used_libraries = set() - for module in self._iter_modules(): - if self.options.get_safe("without_{}".format(module), False) or not all(d in modules_seen for d in self._dependencies["dependencies"][module]): + + for module in self._dependencies["dependencies"].keys(): + missing_depmodules = list(depmodule for depmodule in self._all_dependent_modules(module) if self.options.get_safe("without_{}".format(depmodule), False)) + if missing_depmodules: continue module_libraries = [add_libprefix(lib.format(**libformatdata)) + libsuffix for lib in self._dependencies["libs"][module]] if all(l in detected_libraries for l in module_libraries): modules_seen.add(module) - used_libraries = used_libraries.union(module_libraries) + used_libraries.update(module_libraries) self.cpp_info.components[module].libs = module_libraries self.cpp_info.components[module].requires = self._dependencies["dependencies"][module] + ["_libboost"] @@ -1152,10 +1270,10 @@ def add_libprefix(n): if self.options.get_safe(requirement, None) == False: continue conan_requirement = self._option_to_conan_requirement(requirement) - if not conan_requirement: + if conan_requirement not in self.requires: continue - if conan_requirement in ("icu", "iconv"): - if conan_requirement != self.options.get_safe("i18n_backend"): + if module == "locale" and requirement in ("icu", "iconv"): + if requirement != self.options.i18n_backend: continue self.cpp_info.components[module].requires.append("{0}::{0}".format(conan_requirement)) @@ -1194,3 +1312,10 @@ def add_libprefix(n): self.cpp_info.components["_libboost"].cxxflags.append("-pthread") self.cpp_info.components["_libboost"].sharedlinkflags.extend(["-pthread","--shared-memory"]) self.cpp_info.components["_libboost"].exelinkflags.extend(["-pthread","--shared-memory"]) + elif self.settings.os == "iOS": + if self.options.multithreading: + # https://github.com/conan-io/conan-center-index/issues/3867 + # runtime crashes occur when using the default platform-specific reference counter/atomic + self.cpp_info.components["headers"].defines.extend(["BOOST_AC_USE_PTHREADS", "BOOST_SP_USE_PTHREADS"]) + else: + self.cpp_info.components["headers"].defines.extend(["BOOST_AC_DISABLE_THREADS", "BOOST_SP_DISABLE_THREADS"]) diff --git a/recipes/boost/all/dependencies/dependencies-1.73.0.yml b/recipes/boost/all/dependencies/dependencies-1.73.0.yml index 40a02246bb246..d26d67c9c338d 100644 --- a/recipes/boost/all/dependencies/dependencies-1.73.0.yml +++ b/recipes/boost/all/dependencies/dependencies-1.73.0.yml @@ -16,6 +16,7 @@ configure_options: - log - math - mpi +- nowide - program_options - python - random diff --git a/recipes/boost/all/dependencies/dependencies-1.74.0.yml b/recipes/boost/all/dependencies/dependencies-1.74.0.yml index ae0c9b3c4736f..679e8d616f324 100644 --- a/recipes/boost/all/dependencies/dependencies-1.74.0.yml +++ b/recipes/boost/all/dependencies/dependencies-1.74.0.yml @@ -16,6 +16,7 @@ configure_options: - log - math - mpi +- nowide - program_options - python - random diff --git a/recipes/boost/all/dependencies/dependencies-1.75.0.yml b/recipes/boost/all/dependencies/dependencies-1.75.0.yml new file mode 100644 index 0000000000000..4d24ca98d6337 --- /dev/null +++ b/recipes/boost/all/dependencies/dependencies-1.75.0.yml @@ -0,0 +1,280 @@ +configure_options: +- atomic +- chrono +- container +- context +- contract +- coroutine +- date_time +- exception +- fiber +- filesystem +- graph +- graph_parallel +- iostreams +- json +- locale +- log +- math +- mpi +- nowide +- program_options +- python +- random +- regex +- serialization +- stacktrace +- system +- test +- thread +- timer +- type_erasure +- wave +dependencies: + atomic: [] + chrono: + - system + container: [] + context: + - thread + contract: + - exception + - thread + coroutine: + - context + - exception + - system + - thread + date_time: [] + exception: [] + fiber: + - context + - filesystem + fiber_numa: + - fiber + filesystem: + - system + graph: + - math + - random + - regex + - serialization + graph_parallel: + - filesystem + - graph + - mpi + - random + - serialization + iostreams: + - random + - regex + json: + - container + - exception + - system + locale: + - thread + log: + - atomic + - container + - date_time + - exception + - filesystem + - locale + - random + - regex + - system + - thread + log_setup: + - log + math: + - atomic + math_c99: + - math + math_c99f: + - math + math_c99l: + - math + math_tr1: + - math + math_tr1f: + - math + math_tr1l: + - math + mpi: + - graph + - serialization + mpi_python: + - mpi + - python + nowide: + - filesystem + numpy: + - python + prg_exec_monitor: + - test + program_options: [] + python: [] + random: + - math + - system + regex: [] + serialization: [] + stacktrace: [] + stacktrace_addr2line: + - stacktrace + stacktrace_backtrace: + - stacktrace + stacktrace_basic: + - stacktrace + stacktrace_noop: + - stacktrace + stacktrace_windbg: + - stacktrace + stacktrace_windbg_cached: + - stacktrace + system: [] + test: + - exception + test_exec_monitor: + - test + thread: + - atomic + - chrono + - container + - date_time + - exception + - system + timer: + - chrono + - system + type_erasure: + - thread + unit_test_framework: + - prg_exec_monitor + - test + - test_exec_monitor + wave: + - filesystem + - serialization + wserialization: + - serialization +libs: + atomic: + - boost_atomic + chrono: + - boost_chrono + container: + - boost_container + context: + - boost_context + contract: + - boost_contract + coroutine: + - boost_coroutine + date_time: + - boost_date_time + exception: + - boost_exception + fiber: + - boost_fiber + fiber_numa: + - boost_fiber_numa + filesystem: + - boost_filesystem + graph: + - boost_graph + graph_parallel: + - boost_graph_parallel + iostreams: + - boost_iostreams + json: + - boost_json + locale: + - boost_locale + log: + - boost_log + log_setup: + - boost_log_setup + math: [] + math_c99: + - boost_math_c99 + math_c99f: + - boost_math_c99f + math_c99l: + - boost_math_c99l + math_tr1: + - boost_math_tr1 + math_tr1f: + - boost_math_tr1f + math_tr1l: + - boost_math_tr1l + mpi: + - boost_mpi + mpi_python: + - boost_mpi_python + nowide: + - boost_nowide + numpy: + - boost_numpy{py_major}{py_minor} + prg_exec_monitor: + - boost_prg_exec_monitor + program_options: + - boost_program_options + python: + - boost_python{py_major}{py_minor} + random: + - boost_random + regex: + - boost_regex + serialization: + - boost_serialization + stacktrace: [] + stacktrace_addr2line: + - boost_stacktrace_addr2line + stacktrace_backtrace: + - boost_stacktrace_backtrace + stacktrace_basic: + - boost_stacktrace_basic + stacktrace_noop: + - boost_stacktrace_noop + stacktrace_windbg: + - boost_stacktrace_windbg + stacktrace_windbg_cached: + - boost_stacktrace_windbg_cached + system: + - boost_system + test: [] + test_exec_monitor: + - boost_test_exec_monitor + thread: + - boost_thread + timer: + - boost_timer + type_erasure: + - boost_type_erasure + unit_test_framework: + - boost_unit_test_framework + wave: + - boost_wave + wserialization: + - boost_wserialization +requirements: + iostreams: + - bzip2 + - lzma + - zlib + - zstd + locale: + - iconv + - icu + python: + - python + regex: + - icu + stacktrace: + - backtrace +static_only: +- boost_exception +- boost_test_exec_monitor +version: 1.75.0 diff --git a/recipes/boost/all/rebuild-dependencies.py b/recipes/boost/all/rebuild-dependencies.py index 5fa3f1689ead6..1afb1db22509e 100755 --- a/recipes/boost/all/rebuild-dependencies.py +++ b/recipes/boost/all/rebuild-dependencies.py @@ -38,10 +38,12 @@ "graph", "graph_parallel", "iostreams", + "json", "locale", "log", "math", "mpi", + "nowide", "program_options", "python", "random", @@ -149,6 +151,9 @@ def do_git_submodule_update(self): print("Re-init git submodules") subprocess.check_call(["git", "submodule", "update", "--init"]) + print("Removing unknown files/directories") + subprocess.check_call(["git", "clean", "-d", "-f"]) + def do_install_boostdep(self): with tools.chdir(str(self.boost_path)): print("Installing boostdep/{}".format(self.boostdep_version)) @@ -224,8 +229,8 @@ def _sort_requirements(self, requirements: List[str]) -> Tuple[List[str], Dict[s def do_boostdep_collect(self) -> BoostDependencies: with tools.chdir(str(self.boost_path)): with tools.environment_append({"PATH": self._bin_paths}): - buildables = subprocess.check_output(["boostdep", "--list-buildable"]) - buildables = buildables.decode().splitlines() + buildables = subprocess.check_output(["boostdep", "--list-buildable"], text=True) + buildables = buildables.splitlines() log.debug("`boostdep --list--buildable` returned these buildables: %s", buildables) # modules = subprocess.check_output(["boostdep", "--list-modules"]) @@ -234,10 +239,18 @@ def do_boostdep_collect(self) -> BoostDependencies: dep_modules = buildables dependency_tree = {} - for module in dep_modules: - module_ts_output = subprocess.check_output(["boostdep", "--track-sources", module]) - mod_deps = re.findall("\n([A-Za-z_-]+):\n", module_ts_output.decode()) - dependency_tree[module] = mod_deps + buildable_dependencies = subprocess.check_output(["boostdep", "--list-buildable-dependencies"], text=True) + log.debug("boosdep --list-buildable-dependencies returnes: %s", buildable_dependencies) + for line in buildable_dependencies.splitlines(): + if re.match(r"^[\s]*#.*", line): + continue + match = re.match(r"([\S]+)\s*=\s*([^;]+)\s*;\s*", line) + if not match: + continue + master = match.group(1) + dependencies = re.split(r"\s+", match.group(2).strip()) + dependency_tree[master] = dependencies + log.debug("Using `boostdep --track-sources`, the following dependency tree was calculated:") log.debug(pprint.pformat(dependency_tree)) @@ -308,6 +321,12 @@ def _fix_dependencies(self, deptree: Dict[str, List[str]]) -> Dict[str, List[str if "mpi_python" in deptree and "python" not in deptree["mpi_python"]: deptree["mpi_python"].append("python") + # Break random/math dependency cycle + try: + deptree["math"].remove("random") + except ValueError: + pass + remaining_tree = self.detect_cycles(deptree) if remaining_tree: raise Exception("Dependency cycle detected. Remaining tree: {}".format(remaining_tree)) @@ -389,7 +408,6 @@ def _sort_item(cls, item): elif isinstance(item, list): return list(cls._sort_item(e) for e in sorted(item)) else: - print("UNKNOWN", type(item), item) return item def do_create_dependency_file(self) -> None: @@ -413,7 +431,7 @@ def main(args=None) -> int: parser = argparse.ArgumentParser() parser.add_argument("--verbose", dest="verbose", action="store_true", help="verbose output") parser.add_argument("-t", dest="tmppath", help="temporary folder where to clone boost (default is system temporary folder)") - parser.add_argument("-d", dest="boostdep_version", default="1.74.0", type=str, help="boostdep version") + parser.add_argument("-d", dest="boostdep_version", default="1.75.0", type=str, help="boostdep version") parser.add_argument("-u", dest="git_url", default=BOOST_GIT_URL, help="boost git url") parser.add_argument("-U", dest="git_update", action="store_true", help="update the git repo") parser.add_argument("-o", dest="outputdir", default=None, type=Path, help="output dependency dir") @@ -438,7 +456,6 @@ def main(args=None) -> int: ns.outputdir.mkdir(exist_ok=True) git_update_done = False - boostdep_installed = False if ns.boost_version is None: conan_data = yaml.safe_load(Path("conandata.yml").open()) @@ -467,9 +484,7 @@ def main(args=None) -> int: boost_collector.do_git_submodule_update() - if not boostdep_installed: - boost_collector.do_install_boostdep() - boostdep_installed = True + boost_collector.do_install_boostdep() boost_collector.do_create_dependency_file() return 0 diff --git a/recipes/boost/all/test_package/CMakeLists.txt b/recipes/boost/all/test_package/CMakeLists.txt index e99576d69f05f..79479af9467a7 100644 --- a/recipes/boost/all/test_package/CMakeLists.txt +++ b/recipes/boost/all/test_package/CMakeLists.txt @@ -35,6 +35,30 @@ if(NOT HEADER_ONLY) target_link_libraries(chrono_exe PRIVATE Boost::chrono) endif() + if(WITH_FIBER) + find_package(Boost COMPONENTS fiber REQUIRED) + add_executable(fiber_exe fiber.cpp) + target_link_libraries(fiber_exe PRIVATE Boost::fiber) + endif() + + if(WITH_JSON) + find_package(Boost COMPONENTS json REQUIRED) + add_executable(json_exe json.cpp) + target_link_libraries(json_exe PRIVATE Boost::json) + endif() + + if(WITH_NOWIDE) + find_package(Boost COMPONENTS nowide REQUIRED) + add_executable(nowide_exe nowide.cpp) + target_link_libraries(nowide_exe PRIVATE Boost::nowide) + endif() + + if(WITH_LOCALE) + find_package(Boost COMPONENTS locale REQUIRED) + add_executable(locale_exe locale.cpp) + target_link_libraries(locale_exe PRIVATE Boost::locale) + endif() + if(WITH_PYTHON) find_package(Boost COMPONENTS python REQUIRED) add_library(hello_ext MODULE python.cpp) diff --git a/recipes/boost/all/test_package/conanfile.py b/recipes/boost/all/test_package/conanfile.py index 77d0bf284bdcf..a77bbd9e621eb 100644 --- a/recipes/boost/all/test_package/conanfile.py +++ b/recipes/boost/all/test_package/conanfile.py @@ -1,12 +1,18 @@ from conans import ConanFile, CMake, tools +from conans.errors import ConanException import os -import sys class TestPackageConan(ConanFile): settings = "os", "compiler", "arch", "build_type" generators = "cmake", "cmake_find_package" + def _boost_option(self, name, default): + try: + return getattr(self.options["boost"], name, default) + except (AttributeError, ConanException): + return default + def build(self): # FIXME: tools.vcvars added for clang-cl. Remove once conan supports clang-cl properly. (https://github.com/conan-io/conan-center-index/pull/1453) with tools.vcvars(self.settings) if (self.settings.os == "Windows" and self.settings.compiler == "clang") else tools.no_op(): @@ -24,6 +30,10 @@ def build(self): cmake.definitions["WITH_TEST"] = not self.options["boost"].without_test cmake.definitions["WITH_COROUTINE"] = not self.options["boost"].without_coroutine cmake.definitions["WITH_CHRONO"] = not self.options["boost"].without_chrono + cmake.definitions["WITH_FIBER"] = not self.options["boost"].without_fiber + cmake.definitions["WITH_LOCALE"] = not self.options["boost"].without_locale + cmake.definitions["WITH_NOWIDE"] = not self._boost_option("without_nowide", True) + cmake.definitions["WITH_JSON"] = not self._boost_option("without_json", True) cmake.configure() cmake.build() @@ -43,6 +53,14 @@ def test(self): self.run(os.path.join("bin", "coroutine_exe"), run_environment=True) if not self.options["boost"].without_chrono: self.run(os.path.join("bin", "chrono_exe"), run_environment=True) + if not self.options["boost"].without_fiber: + self.run(os.path.join("bin", "fiber_exe"), run_environment=True) + if not self.options["boost"].without_locale: + self.run(os.path.join("bin", "locale_exe"), run_environment=True) + if not self._boost_option("without_nowide", True): + self.run("{} {}".format(os.path.join("bin", "nowide_exe"), os.path.join(self.source_folder, "conanfile.py")), run_environment=True) + if not self._boost_option("without_json", True): + self.run(os.path.join("bin", "json_exe"), run_environment=True) if not self.options["boost"].without_python: with tools.environment_append({"PYTHONPATH": "{}:{}".format("bin", "lib")}): self.run("{} {}".format(self.options["boost"].python_executable, os.path.join(self.source_folder, "python.py")), run_environment=True) diff --git a/recipes/boost/all/test_package/fiber.cpp b/recipes/boost/all/test_package/fiber.cpp new file mode 100644 index 0000000000000..5d9c5e402e4a2 --- /dev/null +++ b/recipes/boost/all/test_package/fiber.cpp @@ -0,0 +1,130 @@ +// Copyright Nat Goodspeed + Oliver Kowalke 2015. +// Distributed under the Boost Software License, Version 1.0. +// (See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include + +#include + +static std::size_t fiber_count{ 0 }; +static std::mutex mtx_count{}; +static boost::fibers::condition_variable_any cnd_count{}; +typedef std::unique_lock< std::mutex > lock_type; + +/***************************************************************************** + * example fiber function + *****************************************************************************/ +//[fiber_fn_ws +void whatevah( char me) { + try { + std::thread::id my_thread = std::this_thread::get_id(); /**< get ID of initial thread >*/ + { + std::ostringstream buffer; + buffer << "fiber " << me << " started on thread " << my_thread << '\n'; + std::cout << buffer.str() << std::flush; + } + for ( unsigned i = 0; i < 10; ++i) { /**< loop ten times >*/ + boost::this_fiber::yield(); /**< yield to other fibers >*/ + std::thread::id new_thread = std::this_thread::get_id(); /**< get ID of current thread >*/ + if ( new_thread != my_thread) { /**< test if fiber was migrated to another thread >*/ + my_thread = new_thread; + std::ostringstream buffer; + buffer << "fiber " << me << " switched to thread " << my_thread << '\n'; + std::cout << buffer.str() << std::flush; + } + } + } catch ( ... ) { + } + lock_type lk( mtx_count); + if ( 0 == --fiber_count) { /**< Decrement fiber counter for each completed fiber. >*/ + lk.unlock(); + cnd_count.notify_all(); /**< Notify all fibers waiting on `cnd_count`. >*/ + } +} +//] + +/***************************************************************************** + * example thread function + *****************************************************************************/ +//[thread_fn_ws +void thread( boost::fibers::detail::thread_barrier * b) { + std::ostringstream buffer; + buffer << "thread started " << std::this_thread::get_id() << std::endl; + std::cout << buffer.str() << std::flush; + boost::fibers::use_scheduling_algorithm< boost::fibers::algo::shared_work >(); /**< + Install the scheduling algorithm `boost::fibers::algo::shared_work` in order to + join the work sharing. + >*/ + b->wait(); /**< sync with other threads: allow them to start processing >*/ + lock_type lk( mtx_count); + cnd_count.wait( lk, [](){ return 0 == fiber_count; } ); /**< + Suspend main fiber and resume worker fibers in the meanwhile. + Main fiber gets resumed (e.g returns from `condition_variable_any::wait()`) + if all worker fibers are complete. + >*/ + BOOST_ASSERT( 0 == fiber_count); +} +//] + +/***************************************************************************** + * main() + *****************************************************************************/ +int main( int argc, char *argv[]) { + std::cout << "main thread started " << std::this_thread::get_id() << std::endl; + //[main_ws + boost::fibers::use_scheduling_algorithm< boost::fibers::algo::shared_work >(); /*< + Install the scheduling algorithm `boost::fibers::algo::shared_work` in the main thread + too, so each new fiber gets launched into the shared pool. + >*/ + + for ( char c : std::string("abcdefghijklmnopqrstuvwxyz")) { /*< + Launch a number of worker fibers; each worker fiber picks up a character + that is passed as parameter to fiber-function `whatevah`. + Each worker fiber gets detached. + >*/ + boost::fibers::fiber([c](){ whatevah( c); }).detach(); + ++fiber_count; /*< Increment fiber counter for each new fiber. >*/ + } + boost::fibers::detail::thread_barrier b( 4); + std::thread threads[] = { /*< + Launch a couple of threads that join the work sharing. + >*/ + std::thread( thread, & b), + std::thread( thread, & b), + std::thread( thread, & b) + }; + b.wait(); /*< sync with other threads: allow them to start processing >*/ + { + lock_type/*< `lock_type` is typedef'ed as __unique_lock__< [@http://en.cppreference.com/w/cpp/thread/mutex `std::mutex`] > >*/ lk( mtx_count); + cnd_count.wait( lk, [](){ return 0 == fiber_count; } ); /*< + Suspend main fiber and resume worker fibers in the meanwhile. + Main fiber gets resumed (e.g returns from `condition_variable_any::wait()`) + if all worker fibers are complete. + >*/ + } /*< + Releasing lock of mtx_count is required before joining the threads, otherwise + the other threads would be blocked inside condition_variable::wait() and + would never return (deadlock). + >*/ + BOOST_ASSERT( 0 == fiber_count); + for ( std::thread & t : threads) { /*< wait for threads to terminate >*/ + t.join(); + } + //] + std::cout << "done." << std::endl; + return EXIT_SUCCESS; +} diff --git a/recipes/boost/all/test_package/json.cpp b/recipes/boost/all/test_package/json.cpp new file mode 100644 index 0000000000000..f74f69c4168e7 --- /dev/null +++ b/recipes/boost/all/test_package/json.cpp @@ -0,0 +1,18 @@ +#include +using namespace boost::json; + +#include +#include + +int main() { + object obj; + obj[ "pi" ] = 3.141; + obj[ "happy" ] = true; + obj[ "name" ] = "Boost"; + obj[ "nothing" ] = nullptr; + obj[ "answer" ].emplace_object()["everything"] = 42; + obj[ "list" ] = { 1, 0, 2 }; + obj[ "object" ] = { {"currency", "USD"}, {"value", 42.99} }; + std::string s = serialize(obj); + std::cout << s << '\n'; +} diff --git a/recipes/boost/all/test_package/locale.cpp b/recipes/boost/all/test_package/locale.cpp new file mode 100644 index 0000000000000..4722b7025b8e0 --- /dev/null +++ b/recipes/boost/all/test_package/locale.cpp @@ -0,0 +1,56 @@ +// +// Copyright (c) 2009-2011 Artyom Beilis (Tonkikh) +// +// Distributed under the Boost Software License, Version 1.0. (See +// accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) +// +#include +#include +#include +#include +int main() +{ + using namespace boost::locale; + generator gen; + std::locale::global(gen("")); + std::cout.imbue(std::locale()); + // Setup environment + boost::locale::date_time now; + date_time start=now; + // Set the first day of the first month of this year + start.set(period::month(),now.minimum(period::month())); + start.set(period::day(),start.minimum(period::day())); + int current_year = period::year(now); + // Display current year + std::cout << format("{1,ftime='%Y'}") % now << std::endl; + // + // Run forward untill current year is the date + // + for(now=start; period::year(now) == current_year;) { + // Print heading of month + if(calendar().is_gregorian()) + std::cout << format("{1,ftime='%B'}") % now <>' +#include + +#include +#include +#include +int main(int argc,char **argv) +{ + boost::nowide::args a(argc,argv); // Fix arguments - make them UTF-8 + if(argc!=2) { + boost::nowide::cerr << "Usage: file_name" << std::endl; // Unicode aware console + return 1; + } + boost::nowide::ifstream f(argv[1]); // argv[1] - is UTF-8 + if(!f) { + // the console can display UTF-8 + boost::nowide::cerr << "Can't open " << argv[1] << std::endl; + return 1; + } + int total_lines = 0; + while(f) { + if(f.get() == '\n') + total_lines++; + } + f.close(); + // the console can display UTF-8 + boost::nowide::cout << "File " << argv[1] << " has " << total_lines << " lines" << std::endl; + return 0; +} diff --git a/recipes/boost/config.yml b/recipes/boost/config.yml index 7bc5a0694451a..5d607bcb67b96 100644 --- a/recipes/boost/config.yml +++ b/recipes/boost/config.yml @@ -11,3 +11,5 @@ versions: folder: all 1.74.0: folder: all + 1.75.0: + folder: all