Skip to content

[boost] Conan 2.x cleanup #27602

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Draft
wants to merge 20 commits into
base: master
Choose a base branch
from
Draft
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
133 changes: 35 additions & 98 deletions recipes/boost/all/conanfile.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@
import sys
import yaml

required_conan_version = ">=1.53.0"
required_conan_version = ">=2.2"

# When adding (or removing) an option, also add this option to the list in
# `rebuild-dependencies.yml` and re-run that script.
Expand Down Expand Up @@ -71,7 +71,7 @@ class BoostConan(ConanFile):
homepage = "https://www.boost.org"
license = "BSL-1.0"
topics = ("libraries", "cpp")

package_type = "library"
settings = "os", "arch", "compiler", "build_type"
options = {
"shared": [True, False],
Expand All @@ -97,10 +97,9 @@ class BoostConan(ConanFile):
"lzma": [True, False],
"zstd": [True, False],
"segmented_stacks": [True, False],
"debug_level": list(range(0, 14)),
"debug_level": list(range(0, 14)) + ["deprecated"],
"pch": [True, False],
"extra_b2_flags": [None, "ANY"], # custom b2 flags
"i18n_backend": ["iconv", "icu", None, "deprecated"],
"i18n_backend_iconv": ["libc", "libiconv", "off"],
"i18n_backend_icu": [True, False],
"visibility": ["global", "protected", "hidden"],
Expand Down Expand Up @@ -136,10 +135,9 @@ class BoostConan(ConanFile):
"lzma": False,
"zstd": False,
"segmented_stacks": False,
"debug_level": 0,
"debug_level": "deprecated", # deprecated, use Conan conf tools.build:verbosity
"pch": True,
"extra_b2_flags": None,
"i18n_backend": "deprecated",
"i18n_backend_iconv": "libc",
"i18n_backend_icu": False,
"visibility": "hidden",
Expand All @@ -152,7 +150,6 @@ class BoostConan(ConanFile):
default_options.update({f"without_{_name}": False for _name in CONFIGURE_OPTIONS})
default_options.update({f"without_{_name}": True for _name in ("graph_parallel", "mpi", "python")})

short_paths = True
no_copy_source = True
_cached_dependencies = None

Expand Down Expand Up @@ -372,10 +369,6 @@ def _all_super_modules(self, name):
def _bcp_dir(self):
return "custom-boost"

@property
def _settings_build(self):
return getattr(self, "settings_build", self.settings)

@property
def _is_clang_cl(self):
return self.settings.os == "Windows" and self.settings.compiler == "clang"
Expand Down Expand Up @@ -634,17 +627,6 @@ def configure(self):
elif self.options.shared:
self.options.rm_safe("fPIC")

if self.options.i18n_backend != "deprecated":
self.output.warning("i18n_backend option is deprecated, do not use anymore.")
if self.options.i18n_backend == "iconv":
self.options.i18n_backend_iconv = "libiconv"
self.options.i18n_backend_icu = False
if self.options.i18n_backend == "icu":
self.options.i18n_backend_iconv = "off"
self.options.i18n_backend_icu = True
if self.options.i18n_backend == "None":
self.options.i18n_backend_iconv = "off"
self.options.i18n_backend_icu = False
if self.options.without_locale:
self.options.rm_safe("i18n_backend_iconv")
self.options.rm_safe("i18n_backend_icu")
Expand All @@ -665,11 +647,6 @@ def configure(self):
if self.options.without_fiber:
self.options.rm_safe("numa")

# Use verbosity from [conf] if specified
verbosity = self.conf.get("tools.build:verbosity", default="quiet")
if verbosity == "verbose" and int(self.options.debug_level) < 2:
self.options.debug_level.value = 2

def layout(self):
basic_layout(self, src_folder="src")

Expand Down Expand Up @@ -771,6 +748,9 @@ def validate(self):
if Version(self.version) == "1.86.0" and is_msvc(self) and self.options.get_safe("shared") and self.options.get_safe("without_process", None) == False:
raise ConanInvalidConfiguration(f"{self.ref} Boost.Process will fail to be consumed as shared library on MSVC. See https://github.com/boostorg/process/issues/408.")

if str(self.options.debug_level) != "deprecated":
self.output.warning("The option debug_level is deprecated. Use Conan conf tools.build:verbosity instead.")

def _with_dependency(self, dependency):
"""
Return true when dependency is required according to the dependencies-x.y.z.yml file
Expand Down Expand Up @@ -827,8 +807,6 @@ def requirements(self):
self.requires("libiconv/1.17")

def package_id(self):
del self.info.options.i18n_backend

if self.info.options.header_only:
self.info.clear()
else:
Expand Down Expand Up @@ -987,7 +965,7 @@ def _python_includes(self):
if os.path.isfile(python_h):
self.output.info(f"found Python.h: {python_h}")
return candidate.replace("\\", "/")
raise Exception("couldn't locate Python.h - make sure you have installed python development files")
raise ConanException("Could not locate Python.h - make sure you have installed python development files.")

@property
def _python_library_dir(self):
Expand All @@ -1004,7 +982,7 @@ def _python_library_dir(self):
if libdir and multiarch and masd and not libdir.endswith(masd):
if masd.startswith(os.sep):
masd = masd[len(os.sep):]
self.output.warning(f"Python libdir candidate thingy: {libdir}")
self.output.info(f"Python libdir candidate thingy: {libdir}")
libdir = os.path.join(libdir, masd)

if not libdir:
Expand Down Expand Up @@ -1049,7 +1027,7 @@ def _clean(self):
]
for d in clean_dirs:
if os.path.isdir(d):
self.output.warning(f"removing '{d}'")
self.output.info(f"removing '{d}'")
shutil.rmtree(d)

@property
Expand All @@ -1069,12 +1047,18 @@ def _use_bcp(self):
def _boost_build_dir(self):
return os.path.join(self.source_folder, "tools", "build")

@property
def _debug_flag(self):
verbosity = self.conf.get("tools.build:verbosity", default="quiet", check_type=str)
debug_level = {"quiet": 0, "verbose": 2}.get(verbosity)
return f"-d{debug_level}"

def _build_bcp(self):
folder = os.path.join(self.source_folder, "tools", "bcp")
with chdir(self, folder):
command = f"{self._b2_exe} -j{build_jobs(self)} --abbreviate-paths toolset={self._toolset}"
command += f" -d{self.options.debug_level}"
self.output.warning(command)
command += f" {self._debug_flag}"
self.output.info(command)
self.run(command)

def _run_bcp(self):
Expand All @@ -1092,55 +1076,41 @@ def _run_bcp(self):
libraries.add(d)
libraries = " ".join(libraries)
command = f"{self._bcp_exe} {namespace} {alias} {boostdir} {libraries} {self._bcp_dir}"
self.output.warning(command)
self.output.info(command)
self.run(command)

def build(self):
def _patch_sources(self):
stacktrace_jamfile = os.path.join(self.source_folder, "libs", "stacktrace", "build", "Jamfile.v2")
if cross_building(self, skip_x64_x86=True):
# When cross building, do not attempt to run the test-executable (assume they work)
replace_in_file(self, stacktrace_jamfile, "$(>) > $(<)", "echo \"\" > $(<)", strict=False)
if self._with_stacktrace_backtrace and self.settings.os != "Windows" and not cross_building(self):
# When libbacktrace is shared, give extra help to the test-executable
linker_var = "DYLD_LIBRARY_PATH" if self.settings.os == "Macos" else "LD_LIBRARY_PATH"
libbacktrace_libdir = self.dependencies["libbacktrace"].cpp_info.aggregated_components().libdirs[0]
patched_run_rule = f"{linker_var}={libbacktrace_libdir} $(>) > $(<)"
replace_in_file(self, stacktrace_jamfile, "$(>) > $(<)", patched_run_rule, strict=False)
replace_in_file(self, stacktrace_jamfile, "$(>) > $(<)", patched_run_rule)
if self.dependencies["libbacktrace"].options.shared:
replace_in_file(self, stacktrace_jamfile, "<link>static", "<link>shared", strict=False)
replace_in_file(self, stacktrace_jamfile, "<link>static", "<link>shared")

# Older clang releases require a thread_local variable to be initialized by a constant value
replace_in_file(self, os.path.join(self.source_folder, "boost", "stacktrace", "detail", "libbacktrace_impls.hpp"),
"/* thread_local */", "thread_local", strict=False)
replace_in_file(self, os.path.join(self.source_folder, "boost", "stacktrace", "detail", "libbacktrace_impls.hpp"),
"/* static __thread */", "static __thread", strict=False)
if self.settings.compiler == "apple-clang" or (self.settings.compiler == "clang" and Version(self.settings.compiler.version) < 6):
replace_in_file(self, os.path.join(self.source_folder, "boost", "stacktrace", "detail", "libbacktrace_impls.hpp"),
"thread_local", "/* thread_local */")
replace_in_file(self, os.path.join(self.source_folder, "boost", "stacktrace", "detail", "libbacktrace_impls.hpp"),
"static __thread", "/* static __thread */")
replace_in_file(self, os.path.join(self.source_folder, "tools", "build", "src", "tools", "gcc.jam"),
"local generic-os = [ set.difference $(all-os) : aix darwin vxworks solaris osf hpux ] ;",
"local generic-os = [ set.difference $(all-os) : aix darwin vxworks solaris osf hpux iphone appletv ] ;",
strict=False)
replace_in_file(self, os.path.join(self.source_folder, "tools", "build", "src", "tools", "gcc.jam"),
"local no-threading = android beos haiku sgi darwin vxworks ;",
"local no-threading = android beos haiku sgi darwin vxworks iphone appletv ;",
strict=False)
"static __thread", "/* static __thread */")
replace_in_file(self, os.path.join(self.source_folder, "libs", "fiber", "build", "Jamfile.v2"),
" <conditional>@numa",
" <link>shared:<library>.//boost_fiber : <conditional>@numa",
strict=False)
if self.settings.os == "Android":
)
if self.settings.os == "Android" and Version(self.version) < "1.83.0":
# force versionless soname from boostorg/boost#206
# this can be applied to all versions and it's easier with a replace
replace_in_file(self, os.path.join(self.source_folder, "boostcpp.jam"),
"! [ $(property-set).get <target-os> ] in windows cygwin darwin aix &&",
"! [ $(property-set).get <target-os> ] in windows cygwin darwin aix android &&",
strict=False)
)

def build(self):
self._patch_sources()
if self.options.header_only:
self.output.warning("Header only package, skipping build")
self.output.info("Header only package, skipping build")
return

self._clean()
Expand All @@ -1157,7 +1127,7 @@ def build(self):
# -d2 is to print more debug info and avoid travis timing out without output
sources = os.path.join(self.source_folder, self._bcp_dir) if self._use_bcp else self.source_folder
full_command += f' --debug-configuration --build-dir="{self.build_folder}"'
self.output.warning(full_command)
self.output.info(full_command)

# If sending a user-specified toolset to B2, setting the vcvars
# interferes with the compiler selection.
Expand Down Expand Up @@ -1241,14 +1211,8 @@ def _gnu_cxx11_abi(self):
_GLIBCXX_USE_CXX11_ABI= . Returns None if C++ library cannot be
determined.
"""
try:
if str(self.settings.compiler.libcxx) == "libstdc++":
return "0"
if str(self.settings.compiler.libcxx) == "libstdc++11":
return "1"
except ConanException:
pass
return None
libcxx = self.settings.get_safe("compiler.libcxx", default=None)
return {"libstdc++11": 1, "libstdc++": 0}.get(libcxx, None)

@property
def _build_flags(self):
Expand Down Expand Up @@ -1451,7 +1415,7 @@ def add_defines(library):
f"--prefix={self.package_folder}",
f"-j{build_jobs(self)}",
"--abbreviate-paths",
f"-d{self.options.debug_level}",
self._debug_flag,
])
return flags

Expand Down Expand Up @@ -1515,7 +1479,7 @@ def _cxx(self):
return ""

def _create_user_config_jam(self, folder):
self.output.warning("Patching user-config.jam")
self.output.info("Patching user-config.jam")

def create_library_config(deps_name, name):
aggregated_cpp_info = self.dependencies[deps_name].cpp_info.aggregated_components()
Expand Down Expand Up @@ -1607,7 +1571,7 @@ def create_library_config(deps_name, name):

contents += " ;"

self.output.warning(contents)
self.output.info(contents)
filename = f"{folder}/user-config.jam"
save(self, filename, contents)

Expand Down Expand Up @@ -1655,10 +1619,8 @@ def _toolset_tag(self):
# clang | 12 | Macos | clang-darwin12 |
# gcc | 11 | Linux | gcc8 |
# gcc | 8 | Windows | mgw8 |
# Visual Studio | 17 | Windows | vc142 | depends on compiler.toolset
compiler = {
"apple-clang": "",
"Visual Studio": "vc",
"msvc": "vc",
}.get(str(self.settings.compiler), str(self.settings.compiler))
if (self.settings.compiler, self.settings.os) == ("gcc", "Windows"):
Expand Down Expand Up @@ -1735,23 +1697,14 @@ def _option_to_conan_requirement(name):
}.get(name, name)

def package_info(self):
self.env_info.BOOST_ROOT = self.package_folder

self.cpp_info.set_property("cmake_file_name", "Boost")
self.cpp_info.filenames["cmake_find_package"] = "Boost"
self.cpp_info.filenames["cmake_find_package_multi"] = "Boost"
self.cpp_info.names["cmake_find_package"] = "Boost"
self.cpp_info.names["cmake_find_package_multi"] = "Boost"

# - Use 'headers' component for all includes + defines
# - Use '_libboost' component to attach extra system_libs, ...

self.cpp_info.components["headers"].libs = []
self.cpp_info.components["headers"].libdirs = []
self.cpp_info.components["headers"].set_property("cmake_target_name", "Boost::headers")
self.cpp_info.components["headers"].names["cmake_find_package"] = "headers"
self.cpp_info.components["headers"].names["cmake_find_package_multi"] = "headers"
self.cpp_info.components["headers"].names["pkg_config"] = "boost"

if self.options.system_no_deprecated:
self.cpp_info.components["headers"].defines.append("BOOST_SYSTEM_NO_DEPRECATED")
Expand Down Expand Up @@ -1792,8 +1745,6 @@ def package_info(self):
# Boost::boost is an alias of Boost::headers
self.cpp_info.components["_boost_cmake"].requires = ["headers"]
self.cpp_info.components["_boost_cmake"].set_property("cmake_target_name", "Boost::boost")
self.cpp_info.components["_boost_cmake"].names["cmake_find_package"] = "boost"
self.cpp_info.components["_boost_cmake"].names["cmake_find_package_multi"] = "boost"
if self.options.header_only:
self.cpp_info.components["_boost_cmake"].libdirs = []

Expand All @@ -1802,9 +1753,6 @@ def package_info(self):

self.cpp_info.components["diagnostic_definitions"].libs = []
self.cpp_info.components["diagnostic_definitions"].set_property("cmake_target_name", "Boost::diagnostic_definitions")
self.cpp_info.components["diagnostic_definitions"].names["cmake_find_package"] = "diagnostic_definitions"
self.cpp_info.components["diagnostic_definitions"].names["cmake_find_package_multi"] = "diagnostic_definitions"
self.cpp_info.components["diagnostic_definitions"].names["pkg_config"] = "boost_diagnostic_definitions" # FIXME: disable on pkg_config
# I would assume headers also need the define BOOST_LIB_DIAGNOSTIC, as a header can trigger an autolink,
# and this definition triggers a print out of the library selected. See notes below on autolink and headers.
self.cpp_info.components["headers"].requires.append("diagnostic_definitions")
Expand All @@ -1813,9 +1761,6 @@ def package_info(self):

self.cpp_info.components["disable_autolinking"].libs = []
self.cpp_info.components["disable_autolinking"].set_property("cmake_target_name", "Boost::disable_autolinking")
self.cpp_info.components["disable_autolinking"].names["cmake_find_package"] = "disable_autolinking"
self.cpp_info.components["disable_autolinking"].names["cmake_find_package_multi"] = "disable_autolinking"
self.cpp_info.components["disable_autolinking"].names["pkg_config"] = "boost_disable_autolinking" # FIXME: disable on pkg_config

# Even headers needs to know the flags for disabling autolinking ...
# magic_autolink is an option in the recipe, so if a consumer wants this version of boost,
Expand Down Expand Up @@ -1851,9 +1796,6 @@ def package_info(self):

self.cpp_info.components["dynamic_linking"].libs = []
self.cpp_info.components["dynamic_linking"].set_property("cmake_target_name", "Boost::dynamic_linking")
self.cpp_info.components["dynamic_linking"].names["cmake_find_package"] = "dynamic_linking"
self.cpp_info.components["dynamic_linking"].names["cmake_find_package_multi"] = "dynamic_linking"
self.cpp_info.components["dynamic_linking"].names["pkg_config"] = "boost_dynamic_linking" # FIXME: disable on pkg_config
# A library that only links to Boost::headers can be linked into another library that links a Boost::library,
# so for this reasons, the header-only library should know the BOOST_ALL_DYN_LINK definition as it will likely
# change some important part of the boost code and cause linking errors downstream.
Expand Down Expand Up @@ -1978,9 +1920,6 @@ def filter_transform_module_libraries(names):

self.cpp_info.components[module].requires = self._dependencies["dependencies"][module] + ["_libboost"]
self.cpp_info.components[module].set_property("cmake_target_name", "Boost::" + module)
self.cpp_info.components[module].names["cmake_find_package"] = module
self.cpp_info.components[module].names["cmake_find_package_multi"] = module
self.cpp_info.components[module].names["pkg_config"] = f"boost_{module}"

# extract list of names of direct host dependencies to check for dependencies
# of components that exist in other packages
Expand Down Expand Up @@ -2089,6 +2028,4 @@ def filter_transform_module_libraries(names):
(self.settings.compiler == "gcc" and Version(self.settings.compiler.version) == "10"):
self.cpp_info.components["cobalt"].cxxflags.append("-fcoroutines")

#TODO: remove in the future, user_info deprecated in conan2, but kept for compatibility while recipe is cross-compatible.
self.user_info.stacktrace_addr2line_available = self._stacktrace_addr2line_available
self.conf_info.define("user.boost:stacktrace_addr2line_available", self._stacktrace_addr2line_available)