from conans import ConanFile
from conans import tools
import platform, os, sys
class BoostConan(ConanFile):
name = "Boost"
version = "1.62.0"
settings = "os", "arch", "compiler", "build_type"
FOLDER_NAME = "boost_%s" % version.replace(".", "_")
# The current python option requires the package to be built locally, to find default Python implementation
options = {
"shared": [True, False],
"header_only": [True, False],
"fPIC": [True, False],
"python": [True, False], # Note: this variable does not have the 'without_' prefix to keep the old shas
"without_atomic": [True, False],
"without_chrono": [True, False],
"without_container": [True, False],
"without_context": [True, False],
"without_coroutine": [True, False],
"without_coroutine2": [True, False],
"without_date_time": [True, False],
"without_exception": [True, False],
"without_filesystem": [True, False],
"without_graph": [True, False],
"without_graph_parallel": [True, False],
"without_iostreams": [True, False],
"without_locale": [True, False],
"without_log": [True, False],
"without_math": [True, False],
"without_mpi": [True, False],
"without_program_options": [True, False],
"without_random": [True, False],
"without_regex": [True, False],
"without_serialization": [True, False],
"without_signals": [True, False],
"without_system": [True, False],
"without_test": [True, False],
"without_thread": [True, False],
"without_timer": [True, False],
"without_type_erasure": [True, False],
"without_wave": [True, False]
}
default_options = "shared=False", \
"header_only=False", \
"fPIC=False", \
"python=False", \
"without_atomic=False", \
"without_chrono=False", \
"without_container=False", \
"without_context=False", \
"without_coroutine=False", \
"without_coroutine2=False", \
"without_date_time=False", \
"without_exception=False", \
"without_filesystem=False", \
"without_graph=False", \
"without_graph_parallel=False", \
"without_iostreams=False", \
"without_locale=False", \
"without_log=False", \
"without_math=False", \
"without_mpi=False", \
"without_program_options=False", \
"without_random=False", \
"without_regex=False", \
"without_serialization=False", \
"without_signals=False", \
"without_system=False", \
"without_test=False", \
"without_thread=False", \
"without_timer=False", \
"without_type_erasure=False", \
"without_wave=False"
url="https://github.com/lasote/conan-boost"
exports = ["FindBoost.cmake", "OriginalFindBoost*"]
license="Boost Software License - Version 1.0. http://www.boost.org/LICENSE_1_0.txt"
short_paths = True
def config_options(self):
""" First configuration step. Only settings are defined. Options can be removed
according to these settings
"""
if self.settings.compiler == "Visual Studio":
self.options.remove("fPIC")
def configure(self):
""" Second configuration step. Both settings and options have values, in this case
we can force static library if MT was specified as runtime
"""
if self.settings.compiler == "Visual Studio" and \
self.options.shared and "MT" in str(self.settings.compiler.runtime):
self.options.shared = False
if self.options.header_only:
# Should be doable in conan_info() but the UX is not ready
self.options.remove("shared")
self.options.remove("fPIC")
self.options.remove("python")
if not self.options.without_iostreams:
if self.settings.os == "Linux" or self.settings.os == "Macos":
self.requires("bzip2/1.0.6@lasote/stable")
if not self.options.header_only:
self.options["bzip2/1.0.6"].shared = self.options.shared
self.requires("zlib/1.2.8@lasote/stable")
if not self.options.header_only:
self.options["zlib"].shared = self.options.shared
def conan_info(self):
""" if it is header only, the requirements, settings and options do not affect the package ID
so they should be removed, so just 1 package for header only is generated, not one for each
different compiler and option. This is the last step, after build, and package
"""
if self.options.header_only:
self.info.requires.clear()
self.info.settings.clear()
def source(self):
zip_name = "%s.zip" % self.FOLDER_NAME if sys.platform == "win32" else "%s.tar.gz" % self.FOLDER_NAME
url = "http://sourceforge.net/projects/boost/files/boost/%s/%s/download" % (self.version, zip_name)
self.output.info("Downloading %s..." % url)
tools.download(url, zip_name)
tools.unzip(zip_name, ".")
os.unlink(zip_name)
def build(self):
if self.options.header_only:
self.output.warn("Header only package, skipping build")
return
command = "bootstrap" if self.settings.os == "Windows" else "./bootstrap.sh"
flags = []
if self.settings.os == "Windows" and self.settings.compiler == "gcc":
command += " mingw"
flags.append("--layout=system")
try:
self.run("cd %s && %s" % (self.FOLDER_NAME, command))
except:
self.run("cd %s && type bootstrap.log" % self.FOLDER_NAME
if self.settings.os == "Windows"
else "cd %s && cat bootstrap.log" % self.FOLDER_NAME)
raise
if self.settings.compiler == "Visual Studio":
flags.append("toolset=msvc-%s.0" % self.settings.compiler.version)
elif str(self.settings.compiler) in ["clang", "gcc"]:
flags.append("toolset=%s"% self.settings.compiler)
flags.append("link=%s" % ("static" if not self.options.shared else "shared"))
if self.settings.compiler == "Visual Studio" and self.settings.compiler.runtime:
flags.append("runtime-link=%s" % ("static" if "MT" in str(self.settings.compiler.runtime) else "shared"))
flags.append("variant=%s" % str(self.settings.build_type).lower())
flags.append("address-model=%s" % ("32" if self.settings.arch == "x86" else "64"))
option_names = {
"--without-atomic": self.options.without_atomic,
"--without-chrono": self.options.without_chrono,
"--without-container": self.options.without_container,
"--without-coroutine": self.options.without_coroutine,
"--without-coroutine2": self.options.without_coroutine2,
"--without-date_time": self.options.without_date_time,
"--without-exception": self.options.without_exception,
"--without-filesystem": self.options.without_filesystem,
"--without-graph": self.options.without_graph,
"--without-graph_parallel": self.options.without_graph_parallel,
"--without-iostreams": self.options.without_iostreams,
"--without-locale": self.options.without_locale,
"--without-log": self.options.without_log,
"--without-math": self.options.without_math,
"--without-mpi": self.options.without_mpi,
"--without-program_options": self.options.without_program_options,
"--without-random": self.options.without_random,
"--without-regex": self.options.without_regex,
"--without-serialization": self.options.without_serialization,
"--without-signals": self.options.without_signals,
"--without-system": self.options.without_system,
"--without-test": self.options.without_test,
"--without-thread": self.options.without_thread,
"--without-timer": self.options.without_timer,
"--without-type_erasure": self.options.without_type_erasure,
"--without-wave": self.options.without_wave
}
for option_name, activated in option_names.items():
if activated:
flags.append(option_name)
cxx_flags = []
# fPIC DEFINITION
if self.settings.compiler != "Visual Studio":
if self.options.fPIC:
cxx_flags.append("-fPIC")
# LIBCXX DEFINITION FOR BOOST B2
try:
if str(self.settings.compiler.libcxx) == "libstdc++":
flags.append("define=_GLIBCXX_USE_CXX11_ABI=0")
elif str(self.settings.compiler.libcxx) == "libstdc++11":
flags.append("define=_GLIBCXX_USE_CXX11_ABI=1")
if "clang" in str(self.settings.compiler):
if str(self.settings.compiler.libcxx) == "libc++":
cxx_flags.append("-stdlib=libc++")
cxx_flags.append("-std=c++11")
flags.append('linkflags="-stdlib=libc++"')
else:
cxx_flags.append("-stdlib=libstdc++")
cxx_flags.append("-std=c++11")
except:
pass
cxx_flags = 'cxxflags="%s"' % " ".join(cxx_flags) if cxx_flags else ""
flags.append(cxx_flags)
# JOIN ALL FLAGS
b2_flags = " ".join(flags)
command = "b2" if self.settings.os == "Windows" else "./b2"
without_python = "--without-python" if not self.options.python else ""
full_command = "cd %s && %s %s -j%s --abbreviate-paths %s" % (
self.FOLDER_NAME,
command,
b2_flags,
tools.cpu_count(),
without_python)
self.output.warn(full_command)
envs = self.prepare_deps_options_env()
with tools.environment_append(envs):
self.run(full_command)#, output=False)
def prepare_deps_options_env(self):
ret = {}
# if self.settings.os == "Linux" and "bzip2" in self.requires:
# include_path = self.deps_cpp_info["bzip2"].include_paths[0]
# lib_path = self.deps_cpp_info["bzip2"].lib_paths[0]
# lib_name = self.deps_cpp_info["bzip2"].libs[0]
# ret["BZIP2_BINARY"] = lib_name
# ret["BZIP2_INCLUDE"] = include_path
# ret["BZIP2_LIBPATH"] = lib_path
return ret
def package(self):
# Copy findZLIB.cmake to package
self.copy("FindBoost.cmake", ".", ".")
self.copy("OriginalFindBoost*", ".", ".")
self.copy(pattern="*", dst="include/boost", src="%s/boost" % self.FOLDER_NAME)
self.copy(pattern="*.a", dst="lib", src="%s/stage/lib" % self.FOLDER_NAME)
self.copy(pattern="*.so", dst="lib", src="%s/stage/lib" % self.FOLDER_NAME)
self.copy(pattern="*.so.*", dst="lib", src="%s/stage/lib" % self.FOLDER_NAME)
self.copy(pattern="*.dylib*", dst="lib", src="%s/stage/lib" % self.FOLDER_NAME)
self.copy(pattern="*.lib", dst="lib", src="%s/stage/lib" % self.FOLDER_NAME)
self.copy(pattern="*.dll", dst="bin", src="%s/stage/lib" % self.FOLDER_NAME)
def package_info(self):
if not self.options.header_only and self.options.shared:
self.cpp_info.defines.append("BOOST_ALL_DYN_LINK")
else:
self.cpp_info.defines.append("BOOST_USE_STATIC_LIBS")
if self.options.header_only:
return
libs = ("wave unit_test_framework prg_exec_monitor test_exec_monitor container exception "
"graph iostreams locale log log_setup math_c99 math_c99f math_c99l math_tr1 "
"math_tr1f math_tr1l program_options random regex wserialization serialization "
"signals coroutine context timer thread chrono date_time atomic filesystem system").split()
if self.options.python:
libs.append("python")
if not self.options.shared:
self.cpp_info.defines.append("BOOST_PYTHON_STATIC_LIB")
# Remove excluded libraries
for option in self.options.fields:
if option.startswith('without_'):
lib_name = option[8:]
if getattr(self.options, option) and lib_name in libs:
libs.remove(lib_name)
if self.settings.compiler != "Visual Studio":
self.cpp_info.libs.extend(["boost_%s" % lib for lib in libs])
else:
win_libs = []
# http://www.boost.org/doc/libs/1_55_0/more/getting_started/windows.html
visual_version = int(str(self.settings.compiler.version)) * 10
runtime = "mt" # str(self.settings.compiler.runtime).lower()
abi_tags = []
if self.settings.compiler.runtime in ("MTd", "MT"):
abi_tags.append("s")
if self.settings.build_type == "Debug":
abi_tags.append("gd")
abi_tags = ("-%s" % "".join(abi_tags)) if abi_tags else ""
version = "_".join(self.version.split(".")[0:2])
suffix = "vc%d-%s%s-%s" % (visual_version, runtime, abi_tags, version)
prefix = "lib" if not self.options.shared else ""
win_libs.extend(["%sboost_%s-%s" % (prefix, lib, suffix) for lib in libs if lib not in ["exception", "test_exec_monitor"]])
win_libs.extend(["libboost_exception-%s" % suffix, "libboost_test_exec_monitor-%s" % suffix])
#self.output.warn("EXPORTED BOOST LIBRARIES: %s" % win_libs)
self.cpp_info.libs.extend(win_libs)
self.cpp_info.defines.extend(["BOOST_ALL_NO_LIB"]) # DISABLES AUTO LINKING! NO SMART AND MAGIC DECISIONS THANKS!