-
Notifications
You must be signed in to change notification settings - Fork 1.8k
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
[spdlog] Add support for Conan v2 #11981
Changes from 23 commits
b4672c5
78185de
f95f5d7
f0b7712
db0d70c
2f68d6e
d56969b
314370f
8c8e4ff
200448b
0a2dca2
390c8a8
76c3288
40361e7
8c124f0
0683847
b20a7fc
5bc9b33
edd94c1
be8523c
4b7b71f
997a1e6
e78f2ea
73aa32c
aa5de1d
5c213a0
72df1ad
ae4569f
aa09a82
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
This file was deleted.
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,18 +1,26 @@ | ||
from conans import CMake, ConanFile, tools | ||
from conans.errors import ConanInvalidConfiguration | ||
from conan import ConanFile | ||
from conan.tools.cmake import CMake, CMakeToolchain, CMakeDeps, cmake_layout | ||
from conan.tools.files import get, copy, rmdir, replace_in_file | ||
from conan.tools.scm import Version | ||
from conan.tools.microsoft import is_msvc_static_runtime | ||
from conan.errors import ConanInvalidConfiguration | ||
# TODO: Need to be ported for Conan 2.0 | ||
from conans import __version__ as conan_version | ||
# TODO: Update after Conan 1.50 | ||
from conans import tools as tools_legacy | ||
import os | ||
|
||
required_conan_version = ">=1.43.0" | ||
|
||
required_conan_version = ">=1.49.0" | ||
|
||
|
||
class SpdlogConan(ConanFile): | ||
name = "spdlog" | ||
description = "Fast C++ logging library" | ||
url = "https://github.com/conan-io/conan-center-index" | ||
homepage = "https://github.com/gabime/spdlog" | ||
topics = ("spdlog", "logging", "header-only") | ||
topics = ("logging", "log-filtering", "header-only") | ||
license = "MIT" | ||
|
||
settings = "os", "arch", "compiler", "build_type" | ||
options = { | ||
"shared": [True, False], | ||
|
@@ -31,14 +39,6 @@ class SpdlogConan(ConanFile): | |
"no_exceptions": False, | ||
} | ||
|
||
exports_sources = "CMakeLists.txt" | ||
generators = "cmake", "cmake_find_package", "cmake_find_package_multi" | ||
_cmake = None | ||
|
||
@property | ||
def _source_subfolder(self): | ||
return "source_subfolder" | ||
|
||
def config_options(self): | ||
if self.settings.os == "Windows": | ||
del self.options.fPIC | ||
|
@@ -51,99 +51,108 @@ def configure(self): | |
del self.options.fPIC | ||
|
||
def requirements(self): | ||
if tools.Version(self.version) >= "1.10.0": | ||
self.requires("fmt/8.1.1") | ||
elif tools.Version(self.version) >= "1.9.0": | ||
self.requires("fmt/8.0.1") | ||
elif tools.Version(self.version) >= "1.7.0": | ||
self.requires("fmt/7.1.3") | ||
elif tools.Version(self.version) >= "1.5.0": | ||
self.requires("fmt/6.2.1") | ||
# TODO: Remove in Conan 2.0 - 1.x self.requires does not support transitive_headers | ||
requires = lambda ref: self.requires(ref, transitive_headers=True) if Version(conan_version) >= "2.0.0-beta" else self.requires(ref) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. What does There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Indeed, I needed to ask Conan devs to understand. The fmt header is required in a public spglog header, but on the test package, fmt headers are not available by default, so to avoid the failure, we need trasitive_headers. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. We'll be working on the docs more and more. My understanding is it should be the "same" as CMake's at least in concept 🤞 There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. conan 1.52 will allow these arguments in There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. That pr is directly from this work #11981 (comment) Which is why this migration is super important Once 1.52 is available we cam clean this one up 👍 |
||
if Version(self.version) >= "1.10.0": | ||
requires("fmt/8.1.1") | ||
elif Version(self.version) >= "1.9.0": | ||
requires("fmt/8.0.1") | ||
elif Version(self.version) >= "1.7.0": | ||
requires("fmt/7.1.3") | ||
elif Version(self.version) >= "1.5.0": | ||
requires("fmt/6.2.1") | ||
else: | ||
self.requires("fmt/6.0.0") | ||
requires("fmt/6.0.0") | ||
|
||
def validate(self): | ||
def validate_build(self): | ||
if self.settings.compiler.cppstd: | ||
tools_legacy.check_min_cppstd(self, 11) | ||
if self.settings.os != "Windows" and (self.options.wchar_support or self.options.wchar_filenames): | ||
raise ConanInvalidConfiguration("wchar is only supported under windows") | ||
if self.options.get_safe("shared", False): | ||
if self.settings.os == "Windows" and tools.Version(self.version) < "1.6.0": | ||
raise ConanInvalidConfiguration("spdlog shared lib is not yet supported under windows") | ||
if self.settings.compiler == "Visual Studio" and "MT" in self.settings.compiler.runtime: | ||
raise ConanInvalidConfiguration("Visual Studio build for shared library with MT runtime is not supported") | ||
if self.options.get_safe("shared", False) and is_msvc_static_runtime(self): | ||
raise ConanInvalidConfiguration("Visual Studio build for shared library with MT runtime is not supported") | ||
|
||
def package_id(self): | ||
if self.options.header_only: | ||
self.info.header_only() | ||
if self.info.options.header_only: | ||
self.info.clear() | ||
|
||
def source(self): | ||
tools.get(**self.conan_data["sources"][self.version], | ||
destination=self._source_subfolder, strip_root=True) | ||
|
||
def _configure_cmake(self): | ||
if self._cmake: | ||
return self._cmake | ||
self._cmake = CMake(self) | ||
self._cmake.definitions["SPDLOG_BUILD_EXAMPLE"] = False | ||
self._cmake.definitions["SPDLOG_BUILD_EXAMPLE_HO"] = False | ||
self._cmake.definitions["SPDLOG_BUILD_TESTS"] = False | ||
self._cmake.definitions["SPDLOG_BUILD_TESTS_HO"] = False | ||
self._cmake.definitions["SPDLOG_BUILD_BENCH"] = False | ||
self._cmake.definitions["SPDLOG_FMT_EXTERNAL"] = True | ||
self._cmake.definitions["SPDLOG_FMT_EXTERNAL_HO"] = self.options["fmt"].header_only | ||
self._cmake.definitions["SPDLOG_BUILD_SHARED"] = not self.options.header_only and self.options.shared | ||
self._cmake.definitions["SPDLOG_WCHAR_SUPPORT"] = self.options.wchar_support | ||
self._cmake.definitions["SPDLOG_WCHAR_FILENAMES"] = self.options.wchar_filenames | ||
self._cmake.definitions["SPDLOG_INSTALL"] = True | ||
self._cmake.definitions["SPDLOG_NO_EXCEPTIONS"] = self.options.no_exceptions | ||
if self.settings.os in ("iOS", "tvOS", "watchOS"): | ||
self._cmake.definitions["SPDLOG_NO_TLS"] = True | ||
if tools.cross_building(self): | ||
# Workaround to find CMake config files in some cross-build scenario | ||
# TODO: to remove if something like https://github.com/conan-io/conan/issues/9427#issuecomment-993685376 | ||
# is implemented | ||
self._cmake.definitions["CMAKE_FIND_ROOT_PATH_MODE_PACKAGE"] = "BOTH" | ||
self._cmake.configure() | ||
return self._cmake | ||
get(self, **self.conan_data["sources"][self.version], strip_root=True) | ||
|
||
def generate(self): | ||
if not self.options.header_only: | ||
fmt = self.dependencies["fmt"] | ||
tc = CMakeToolchain(self) | ||
tc.variables["SPDLOG_BUILD_EXAMPLE"] = False | ||
tc.variables["SPDLOG_BUILD_EXAMPLE_HO"] = False | ||
tc.variables["SPDLOG_BUILD_TESTS"] = False | ||
tc.variables["SPDLOG_BUILD_TESTS_HO"] = False | ||
tc.variables["SPDLOG_BUILD_BENCH"] = False | ||
tc.variables["SPDLOG_FMT_EXTERNAL"] = True | ||
tc.variables["SPDLOG_FMT_EXTERNAL_HO"] = fmt.options.header_only | ||
tc.variables["SPDLOG_BUILD_SHARED"] = not self.options.header_only and self.options.shared | ||
tc.variables["SPDLOG_WCHAR_SUPPORT"] = self.options.wchar_support | ||
tc.variables["SPDLOG_WCHAR_FILENAMES"] = self.options.wchar_filenames | ||
tc.variables["SPDLOG_INSTALL"] = True | ||
tc.variables["SPDLOG_NO_EXCEPTIONS"] = self.options.no_exceptions | ||
if self.settings.os in ("iOS", "tvOS", "watchOS"): | ||
tc.variables["SPDLOG_NO_TLS"] = True | ||
tc.variables["CMAKE_POLICY_DEFAULT_CMP0091"] = "NEW" | ||
tc.generate() | ||
cmake_deps = CMakeDeps(self) | ||
cmake_deps.generate() | ||
Comment on lines
+112
to
+113
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. CMakeDeps not needed if header_only There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. True! |
||
|
||
def layout(self): | ||
cmake_layout(self) | ||
|
||
def _disable_werror(self): | ||
tools.replace_in_file(os.path.join(self._source_subfolder, "cmake", "utils.cmake"), "/WX", "") | ||
replace_in_file(self, os.path.join(self.source_folder, "cmake", "utils.cmake"), "/WX", "") | ||
|
||
def build(self): | ||
if tools.Version(self.version) < "1.7" and tools.Version(self.deps_cpp_info["fmt"].version) >= "7": | ||
raise ConanInvalidConfiguration("The project {}/{} requires fmt < 7.x".format(self.name, self.version)) | ||
|
||
self._disable_werror() | ||
if not self.options.header_only: | ||
cmake = self._configure_cmake() | ||
cmake = CMake(self) | ||
cmake.configure() | ||
cmake.build() | ||
|
||
def package(self): | ||
self.copy("LICENSE", dst="licenses", src=self._source_subfolder) | ||
copy(self, "LICENSE", dst=os.path.join(self.package_folder, "licenses"), src=self.source_folder) | ||
if self.options.header_only: | ||
self.copy(pattern="*.h", dst="include", src=os.path.join(self._source_subfolder, "include")) | ||
copy(self, pattern="*.h", dst=os.path.join(self.package_folder, "include"), src=os.path.join(self.source_folder, "include")) | ||
else: | ||
cmake = self._configure_cmake() | ||
cmake = CMake(self) | ||
cmake.install() | ||
tools.rmdir(os.path.join(self.package_folder, "lib", "cmake")) | ||
tools.rmdir(os.path.join(self.package_folder, "lib", "pkgconfig")) | ||
tools.rmdir(os.path.join(self.package_folder, "lib", "spdlog", "cmake")) | ||
rmdir(self, os.path.join(self.package_folder, "lib", "cmake")) | ||
rmdir(self, os.path.join(self.package_folder, "lib", "pkgconfig")) | ||
rmdir(self, os.path.join(self.package_folder, "lib", "spdlog", "cmake")) | ||
|
||
def package_info(self): | ||
# TODO: to remove in conan v2 once cmake_find_package* generators removed | ||
self.cpp_info.names["cmake_find_package"] = "spdlog" | ||
self.cpp_info.names["cmake_find_package_multi"] = "spdlog" | ||
|
||
target = "spdlog_header_only" if self.options.header_only else "spdlog" | ||
self.cpp_info.set_property("cmake_file_name", "spdlog") | ||
self.cpp_info.set_property("cmake_target_name", "spdlog::{}".format(target)) | ||
self.cpp_info.set_property("cmake_target_name", f"spdlog::{target}") | ||
self.cpp_info.set_property("pkg_config_name", "spdlog") | ||
|
||
self.cpp_info.names["cmake_find_package"] = "spdlog" | ||
self.cpp_info.names["cmake_find_package_multi"] = "spdlog" | ||
# TODO: to remove in conan v2 once cmake_find_package* generators removed | ||
self.cpp_info.components["libspdlog"].names["cmake_find_package"] = target | ||
self.cpp_info.components["libspdlog"].names["cmake_find_package_multi"] = target | ||
|
||
self.cpp_info.components["libspdlog"].set_property("cmake_target_name", f"spdlog::{target}") | ||
|
||
self.cpp_info.components["libspdlog"].defines.append("SPDLOG_FMT_EXTERNAL") | ||
self.cpp_info.components["libspdlog"].requires = ["fmt::fmt"] | ||
|
||
self.cpp_info.components["libspdlog"].includedirs = ["include"] | ||
if not self.options.header_only: | ||
self.cpp_info.components["libspdlog"].libs = tools.collect_libs(self) | ||
suffix = "d" if self.settings.build_type == "Debug" else "" | ||
self.cpp_info.components["libspdlog"].libs = [f"spdlog{suffix}"] | ||
self.cpp_info.components["libspdlog"].defines.append("SPDLOG_COMPILED_LIB") | ||
else: | ||
self.cpp_info.components["libspdlog"].libdirs = [] | ||
self.cpp_info.components["libspdlog"].bindirs = [] | ||
if self.options.wchar_support: | ||
self.cpp_info.components["libspdlog"].defines.append("SPDLOG_WCHAR_TO_UTF8_SUPPORT") | ||
if self.options.wchar_filenames: | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,15 +1,14 @@ | ||
cmake_minimum_required(VERSION 3.1) | ||
project(test_package) | ||
|
||
include(${CMAKE_BINARY_DIR}/conanbuildinfo.cmake) | ||
conan_basic_setup(TARGETS) | ||
cmake_minimum_required(VERSION 3.15) | ||
project(test_package CXX) | ||
|
||
find_package(spdlog REQUIRED CONFIG) | ||
|
||
add_executable(${PROJECT_NAME} test_package.cpp) | ||
if(TARGET spdlog::spdlog_header_only) | ||
target_link_libraries(${PROJECT_NAME} spdlog::spdlog_header_only) | ||
if(SPDLOG_HEADER_ONLY) | ||
target_link_libraries(${PROJECT_NAME} PUBLIC spdlog::spdlog_header_only) | ||
else() | ||
target_link_libraries(${PROJECT_NAME} spdlog::spdlog) | ||
target_link_libraries(${PROJECT_NAME} PUBLIC spdlog::spdlog) | ||
endif() | ||
set_property(TARGET ${PROJECT_NAME} PROPERTY CXX_STANDARD 11) | ||
set_target_properties(${PROJECT_NAME} PROPERTIES | ||
CXX_STANDARD 11 | ||
CMAKE_POLICY_DEFAULT_CMP0091 NEW) |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,18 +1,33 @@ | ||
from conans import ConanFile, CMake, tools | ||
# pylint: skip-file | ||
import os | ||
from conan import ConanFile | ||
from conan.tools.cmake import CMake, CMakeToolchain | ||
from conan.tools.build import can_run | ||
from conan.tools.cmake import cmake_layout | ||
|
||
|
||
class TestPackageConan(ConanFile): | ||
settings = "os", "arch", "compiler", "build_type" | ||
generators = "cmake", "cmake_find_package_multi" | ||
settings = "os", "compiler", "build_type", "arch" | ||
generators = "CMakeDeps", "VirtualBuildEnv", "VirtualRunEnv" | ||
test_type = "explicit" | ||
|
||
def requirements(self): | ||
self.requires(self.tested_reference_str) | ||
|
||
def generate(self): | ||
tc = CMakeToolchain(self) | ||
tc.variables["SPDLOG_HEADER_ONLY"] = self.dependencies["spdlog"].options.header_only | ||
tc.generate() | ||
|
||
def layout(self): | ||
cmake_layout(self) | ||
|
||
def build(self): | ||
cmake = CMake(self) | ||
cmake.configure() | ||
cmake.build() | ||
|
||
def test(self): | ||
if not tools.cross_building(self): | ||
tools.mkdir("logs/") | ||
bin_path = os.path.join("bin", "test_package") | ||
self.run(bin_path, run_environment=True) | ||
if can_run(self): | ||
bin_path = os.path.join(self.cpp.build.bindirs[0], "test_package") | ||
self.run(bin_path, env="conanrun") |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
fmt can be compiled 🤔 the should probably depend on
conan-center-index/recipes/fmt/all/conanfile.py
Line 31 in e442496
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Indeed spdlog needs fmt, but the main problem is, spdlog includes fmt/core.h in a public and exported header, so when you consume spdlog.h, it will ask for fmt directly too. That's why it need to be transitive. I talked with Carlos about this topic, he said it's a rare case. Indeed it should be, because we usually don't expose external dependencies as a good practice. Do you have another suggestion related to the package ID?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
To be more clear about the dependency chain: https://github.com/gabime/spdlog/blob/v1.10.0/include/spdlog/spdlog.h#L12 -> https://github.com/gabime/spdlog/blob/v1.10.0/include/spdlog/common.h#L45 -> https://github.com/gabime/spdlog/blob/v1.10.0/include/spdlog/fmt/fmt.h#L27
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
No, that's perfect!
I was confused by #11981 (comment)
I think it's fairly common for a compiled library to have external includes exposed so we will need this trick more often.
The goal of 2.0 is to be more explicit so this is much better :)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
BTW I commented about the case with Conan team here: conan-io/conan#11760