Skip to content
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

Merged
merged 29 commits into from
Aug 25, 2022
Merged
Show file tree
Hide file tree
Changes from 23 commits
Commits
Show all changes
29 commits
Select commit Hold shift + click to select a range
b4672c5
Remove old versions
uilianries Jul 30, 2022
78185de
Revert "Remove old versions"
uilianries Jul 30, 2022
f95f5d7
Remove pwdold versions
uilianries Jul 30, 2022
f0b7712
spdlog prepared for Conan 2.0
uilianries Jul 30, 2022
db0d70c
Add test package
uilianries Jul 30, 2022
2f68d6e
Reduce test package
uilianries Jul 30, 2022
d56969b
Update recipes/spdlog/all/conanfile.py
uilianries Aug 2, 2022
314370f
remove dulicated generators
uilianries Aug 2, 2022
8c8e4ff
Fix cmake target name
uilianries Aug 2, 2022
200448b
minimal test
uilianries Aug 2, 2022
0a2dca2
transitive headers
uilianries Aug 2, 2022
390c8a8
It's alive
uilianries Aug 2, 2022
76c3288
Update recipes/spdlog/all/test_package/CMakeLists.txt
uilianries Aug 3, 2022
40361e7
Use old check_min_cppstd
uilianries Aug 4, 2022
8c124f0
Allow conan 1.49.0
uilianries Aug 4, 2022
0683847
skip test package for linter
uilianries Aug 4, 2022
b20a7fc
fix license folder path
uilianries Aug 4, 2022
5bc9b33
manage header only package id
uilianries Aug 4, 2022
edd94c1
manage header only package id
uilianries Aug 4, 2022
be8523c
Skip old versions
uilianries Aug 4, 2022
4b7b71f
Skip old versions
uilianries Aug 4, 2022
997a1e6
Use again self.info.clear
uilianries Aug 4, 2022
e78f2ea
Try to dribble the linter
uilianries Aug 4, 2022
73aa32c
Import check_min_cppstd
uilianries Aug 5, 2022
aa5de1d
Re-use test_package.cpp
uilianries Aug 5, 2022
5c213a0
lint test_package
uilianries Aug 5, 2022
72df1ad
Use validate
uilianries Aug 5, 2022
ae4569f
Validate accoring client version
uilianries Aug 5, 2022
aa09a82
Cache cmake policy
uilianries Aug 5, 2022
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
7 changes: 0 additions & 7 deletions recipes/spdlog/all/CMakeLists.txt

This file was deleted.

30 changes: 0 additions & 30 deletions recipes/spdlog/all/conandata.yml
Original file line number Diff line number Diff line change
Expand Up @@ -5,36 +5,6 @@ sources:
"1.9.2":
url: "https://github.com/gabime/spdlog/archive/v1.9.2.tar.gz"
sha256: "6fff9215f5cb81760be4cc16d033526d1080427d236e86d70bb02994f85e3d38"
"1.9.1":
url: "https://github.com/gabime/spdlog/archive/v1.9.1.tar.gz"
sha256: "9a452cfa24408baccc9b2bc2d421d68172a7630c99e9504a14754be840d31a62"
"1.9.0":
url: "https://github.com/gabime/spdlog/archive/v1.9.0.tar.gz"
sha256: "9ad181d75aaedbf47c8881e7b947a47cac3d306997e39de24dba60db633e70a7"
"1.8.5":
url: "https://github.com/gabime/spdlog/archive/v1.8.5.tar.gz"
sha256: "944d0bd7c763ac721398dca2bb0f3b5ed16f67cef36810ede5061f35a543b4b8"
"1.8.2":
url: "https://github.com/gabime/spdlog/archive/v1.8.2.tar.gz"
sha256: "e20e6bd8f57e866eaf25a5417f0a38a116e537f1a77ac7b5409ca2b180cec0d5"
"1.8.1":
url: "https://github.com/gabime/spdlog/archive/v1.8.1.tar.gz"
sha256: "5197b3147cfcfaa67dd564db7b878e4a4b3d9f3443801722b3915cdeced656cb"
"1.8.0":
url: "https://github.com/gabime/spdlog/archive/v1.8.0.tar.gz"
sha256: "1e68e9b40cf63bb022a4b18cdc1c9d88eb5d97e4fd64fa981950a9cacf57a4bf"
"1.7.0":
url: "https://github.com/gabime/spdlog/archive/v1.7.0.tar.gz"
sha256: "f0114a4d3c88be9e696762f37a7c379619443ce9d668546c61b21d41affe5b62"
"1.6.1":
url: "https://github.com/gabime/spdlog/archive/v1.6.1.tar.gz"
sha256: "378a040d91f787aec96d269b0c39189f58a6b852e4cbf9150ccfacbe85ebbbfc"
"1.6.0":
url: "https://github.com/gabime/spdlog/archive/v1.6.0.tar.gz"
sha256: "0421667c9f2fc78e6548d44f7bc5921be0f03e612df384294c16cedb93d967f8"
"1.5.0":
url: "https://github.com/gabime/spdlog/archive/v1.5.0.tar.gz"
sha256: "b38e0bbef7faac2b82fed550a0c19b0d4e7f6737d5321d4fd8f216b80f8aee8a"
"1.4.2":
url: "https://github.com/gabime/spdlog/archive/v1.4.2.tar.gz"
sha256: "821c85b120ad15d87ca2bc44185fa9091409777c756029125a02f81354072157"
155 changes: 82 additions & 73 deletions recipes/spdlog/all/conanfile.py
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],
Expand All @@ -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
Expand All @@ -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)
Copy link
Contributor

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

"header_only": False,

Copy link
Member Author

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?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copy link
Contributor

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 :)

Copy link
Member Author

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

Copy link
Contributor

@SpaceIm SpaceIm Aug 25, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What does transitive_headers=True mean? Ok: https://docs.conan.io/en/2.0/reference/conanfile/methods.html?highlight=transitive_headers#transitive-headers, some sort of PRIVATE vs INTERFACE. It's not clear in the documentation what is the default value, nor if it's as smart as PRIVATE/PUBLIC/INTERFACE CMake properties.

Copy link
Member Author

Choose a reason for hiding this comment

The 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.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We'll be working on the docs more and more.
Best reference as of know I think is this talk https://www.youtube.com/watch?v=kKGglzm5ous&t=2025

My understanding is it should be the "same" as CMake's at least in concept 🤞

Copy link
Contributor

@SpaceIm SpaceIm Aug 28, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

conan 1.52 will allow these arguments in self.requires (see conan-io/conan#11934), but my understanding is that it will be a no-op in conan v1 mode (everything is always public), it's just a way to ease the migration of recipes to conan v2, since the default value of transitive_* arguments is False.

Copy link
Contributor

Choose a reason for hiding this comment

The 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
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

CMakeDeps not needed if header_only

Copy link
Member Author

Choose a reason for hiding this comment

The 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:
Expand Down
17 changes: 8 additions & 9 deletions recipes/spdlog/all/test_package/CMakeLists.txt
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)
29 changes: 22 additions & 7 deletions recipes/spdlog/all/test_package/conanfile.py
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")
Loading