Repository: conan-io/conan-center-index

Issue:
[request] andreasbuhr-cppcoro/latest
### Package Name/Version

andreasbuhr-cppcoro/latest

### Changelog

https://github.com/lewissbaker/cppcoro

### Context about the new update

The [version](https://conan.io/center/andreasbuhr-cppcoro) which is on conan.io fails to compile with clang.
For ``` conan install andreasbuhr-cppcoro/cci.20210113@_/_ --profile clang --build=missing ```, it says 
<details> 
<summary> Output </summary>
<br>

```
andreasbuhr-cppcoro/cci.20210113: WARN: Package binary is corrupted, removing: ce7925f094948675ea74d23df83a42941d85bfdd
Installing package: andreasbuhr-cppcoro/cci.20210113
Requirements
andreasbuhr-cppcoro/cci.20210113 from 'conancenter' - Cache
Packages
andreasbuhr-cppcoro/cci.20210113:ce7925f094948675ea74d23df83a42941d85bfdd - Build

Installing (downloading, building) binaries...
andreasbuhr-cppcoro/cci.20210113: WARN: Build folder is dirty, removing it: /home/akshit/.conan/data/andreasbuhr-cppcoro/cci.20210113/_/_/build/ce7925f094948675ea74d23df83a42941d85bfdd
andreasbuhr-cppcoro/cci.20210113: Copying sources to build folder
andreasbuhr-cppcoro/cci.20210113: Building your package in /home/akshit/.conan/data/andreasbuhr-cppcoro/cci.20210113/_/_/build/ce7925f094948675ea74d23df83a42941d85bfdd
andreasbuhr-cppcoro/cci.20210113: Generator cmake created conanbuildinfo.cmake
andreasbuhr-cppcoro/cci.20210113: Aggregating env generators
andreasbuhr-cppcoro/cci.20210113: Calling build()
-- The CXX compiler identification is Clang 15.0.7
-- Detecting CXX compiler ABI info
-- Detecting CXX compiler ABI info - done
-- Check for working CXX compiler: /usr/bin/clang++ - skipped
-- Detecting CXX compile features
-- Detecting CXX compile features - done
-- Conan: called by CMake conan helper
-- Conan: called inside local cache
-- Conan: Adjusting output directories
-- Conan: Using cmake global configuration
-- Conan: Adjusting default RPATHs Conan policies
-- Conan: Adjusting language standard
-- Conan: Adjusting fPIC flag (ON)
-- Conan: Compiler Clang>=8, checking major version 15
-- Conan: Checking correct version: 15
-- Conan: C++ stdlib: libstdc++11
C++ version not set. Defaulting to CMAKE_CXX_STANDARD=20
-- Performing Test _CXX_COROUTINES_SUPPORTS_MS_FLAG
-- Performing Test _CXX_COROUTINES_SUPPORTS_MS_FLAG - Failed
-- Performing Test _CXX_COROUTINES_SUPPORTS_MS_HEAPELIDE_FLAG
-- Performing Test _CXX_COROUTINES_SUPPORTS_MS_HEAPELIDE_FLAG - Failed
-- Performing Test _CXX_COROUTINES_SUPPORTS_TS_FLAG
-- Performing Test _CXX_COROUTINES_SUPPORTS_TS_FLAG - Success
-- Performing Test _CXX_COROUTINES_SUPPORTS_CORO_FLAG
-- Performing Test _CXX_COROUTINES_SUPPORTS_CORO_FLAG - Failed
-- Looking for C++ include coroutine
-- Looking for C++ include coroutine - found
-- Performing Test _CXX_COROUTINES_FINAL_HEADER_COMPILES
-- Performing Test _CXX_COROUTINES_FINAL_HEADER_COMPILES - Success
-- Performing Test CXX_COROUTINES_NO_AWAIT_NEEDED
-- Performing Test CXX_COROUTINES_NO_AWAIT_NEEDED - Success
-- Configuring done
-- Generating done
CMake Warning:
Manually-specified variables were not used by the project:

CMAKE_EXPORT_NO_PACKAGE_REGISTRY
CMAKE_INSTALL_BINDIR
CMAKE_INSTALL_DATAROOTDIR
CMAKE_INSTALL_INCLUDEDIR
CMAKE_INSTALL_LIBDIR
CMAKE_INSTALL_LIBEXECDIR
CMAKE_INSTALL_OLDINCLUDEDIR
CMAKE_INSTALL_SBINDIR


-- Build files have been written to: /home/akshit/.conan/data/andreasbuhr-cppcoro/cci.20210113/_/_/build/ce7925f094948675ea74d23df83a42941d85bfdd
[ 15%] Building CXX object source_subfolder/lib/CMakeFiles/cppcoro.dir/async_mutex.cpp.o
[ 26%] Building CXX object source_subfolder/lib/CMakeFiles/cppcoro.dir/cancellation_token.cpp.o
[ 15%] Building CXX object source_subfolder/lib/CMakeFiles/cppcoro.dir/cancellation_state.cpp.o
[ 26%] Building CXX object source_subfolder/lib/CMakeFiles/cppcoro.dir/async_manual_reset_event.cpp.o
[ 26%] Building CXX object source_subfolder/lib/CMakeFiles/cppcoro.dir/async_auto_reset_event.cpp.o
[ 31%] Building CXX object source_subfolder/lib/CMakeFiles/cppcoro.dir/cancellation_source.cpp.o
[ 36%] Building CXX object source_subfolder/lib/CMakeFiles/cppcoro.dir/cancellation_registration.cpp.o
[ 47%] Building CXX object source_subfolder/lib/CMakeFiles/cppcoro.dir/ip_address.cpp.o
[ 47%] Building CXX object source_subfolder/lib/CMakeFiles/cppcoro.dir/lightweight_manual_reset_event.cpp.o
[ 52%] Building CXX object source_subfolder/lib/CMakeFiles/cppcoro.dir/ipv4_address.cpp.o
[ 57%] Building CXX object source_subfolder/lib/CMakeFiles/cppcoro.dir/ip_endpoint.cpp.o
[ 63%] Building CXX object source_subfolder/lib/CMakeFiles/cppcoro.dir/ipv4_endpoint.cpp.o
[ 68%] Building CXX object source_subfolder/lib/CMakeFiles/cppcoro.dir/ipv6_address.cpp.o
[ 73%] Building CXX object source_subfolder/lib/CMakeFiles/cppcoro.dir/ipv6_endpoint.cpp.o
[ 78%] Building CXX object source_subfolder/lib/CMakeFiles/cppcoro.dir/static_thread_pool.cpp.o
[ 84%] Building CXX object source_subfolder/lib/CMakeFiles/cppcoro.dir/auto_reset_event.cpp.o
[ 89%] Building CXX object source_subfolder/lib/CMakeFiles/cppcoro.dir/spin_wait.cpp.o
[ 94%] Building CXX object source_subfolder/lib/CMakeFiles/cppcoro.dir/spin_mutex.cpp.o
/home/akshit/.conan/data/andreasbuhr-cppcoro/cci.20210113/_/_/build/ce7925f094948675ea74d23df83a42941d85bfdd/source_subfolder/lib/static_thread_pool.cpp:670:23: error: no member named 'exchange' in namespace 'std'; did you mean '__exchange'?
auto* next = std::exchange(tail->m_next, head);
~~~~~^~~~~~~~
__exchange
/usr/bin/../lib/gcc/x86_64-linux-gnu/12/../../../../include/c++/12/bits/move.h:157:5: note: '__exchange' declared here
__exchange(_Tp& __obj, _Up&& __new_val)
^
/home/akshit/.conan/data/andreasbuhr-cppcoro/cci.20210113/_/_/build/ce7925f094948675ea74d23df83a42941d85bfdd/source_subfolder/lib/static_thread_pool.cpp:671:17: error: no member named 'exchange' in namespace 'std'; did you mean '__exchange'?
head = std::exchange(tail, next);
~~~~~^~~~~~~~
__exchange
/usr/bin/../lib/gcc/x86_64-linux-gnu/12/../../../../include/c++/12/bits/move.h:157:5: note: '__exchange' declared here
__exchange(_Tp& __obj, _Up&& __new_val)
^
2 errors generated.
gmake[2]: *** [source_subfolder/lib/CMakeFiles/cppcoro.dir/build.make:272: source_subfolder/lib/CMakeFiles/cppcoro.dir/static_thread_pool.cpp.o] Error 1
gmake[1]: *** [CMakeFiles/Makefile2:113: source_subfolder/lib/CMakeFiles/cppcoro.dir/all] Error 2
gmake: *** [Makefile:136: all] Error 2
andreasbuhr-cppcoro/cci.20210113:
andreasbuhr-cppcoro/cci.20210113: ERROR: Package 'ce7925f094948675ea74d23df83a42941d85bfdd' build failed
andreasbuhr-cppcoro/cci.20210113: WARN: Build folder /home/akshit/.conan/data/andreasbuhr-cppcoro/cci.20210113/_/_/build/ce7925f094948675ea74d23df83a42941d85bfdd
ERROR: andreasbuhr-cppcoro/cci.20210113: Error in build() method, line 82
cmake.build()
ConanException: Error 2 while executing cmake --build '/home/akshit/.conan/data/andreasbuhr-cppcoro/cci.20210113/_/_/build/ce7925f094948675ea74d23df83a42941d85bfdd' '--' '-j12'
```
</details>

<details>
<summary> Configuration: </summary>

```
[settings]
arch=x86_64
arch_build=x86_64
build_type=Release
compiler=clang
compiler.libcxx=libstdc++11
compiler.version=15
os=Linux
os_build=Linux
[options]
[build_requires]
[env]
CC=/usr/bin/clang
CXX=/usr/bin/clang++
```
</details>

This error is [fixed](https://github.com/andreasbuhr/cppcoro/blob/10bbcdbf2be3ad3aa56febcf4c7662d771460a99/lib/static_thread_pool.cpp#L15) in the updated version of the library.

Thanks


Discussion:

Resolving patch:
diff --git a/recipes/andreasbuhr-cppcoro/all/conanfile.py b/recipes/andreasbuhr-cppcoro/all/conanfile.py
--- a/recipes/andreasbuhr-cppcoro/all/conanfile.py
+++ b/recipes/andreasbuhr-cppcoro/all/conanfile.py
@@ -1,21 +1,24 @@
 import os
-from conans import ConanFile, tools, CMake
-from conans.errors import ConanInvalidConfiguration
+from conan import ConanFile
+from conan.tools.build import check_min_cppstd
+from conan.tools.cmake import CMake, CMakeToolchain, cmake_layout
+from conan.tools.files import rmdir, get, copy
+from conan.tools.microsoft import is_msvc
+from conan.tools.scm import Version
+from conan.errors import ConanInvalidConfiguration
 
-required_conan_version = ">=1.33.0"
+required_conan_version = ">=1.53.0"
 
 class AndreasbuhrCppCoroConan(ConanFile):
     name = "andreasbuhr-cppcoro"
     description = "A library of C++ coroutine abstractions for the coroutines TS"
-    topics = ("conan", "cpp", "async", "coroutines")
+    topics = ("cpp", "async", "coroutines")
     url = "https://github.com/conan-io/conan-center-index"
     homepage = "https://github.com/andreasbuhr/cppcoro"
     license = "MIT"
     settings = "os", "compiler", "build_type", "arch"
     provides = "cppcoro"
-
-    exports_sources = "CMakeLists.txt"
-    generators = "cmake"
+    package_type = "library"
 
     options = {
         "shared": [True, False],
@@ -26,87 +29,111 @@ class AndreasbuhrCppCoroConan(ConanFile):
         "fPIC": True,
     }
 
-    _cmake = None
-
-    @property
-    def _source_subfolder(self):
-        return "source_subfolder"
-
     @property
     def _minimum_compilers_version(self):
         return {
             "Visual Studio": "15",
+            "msvc": "191",
             "gcc": "10",
             "clang": "8",
             "apple-clang": "10",
         }
 
+    @property
+    def _min_cppstd(self):
+        # Clang with libstdc++ always requires C++20
+        # Clang 17+ always requires C++20
+        # Otherwise, require C++17
+        compiler = self.settings.compiler
+        requires_cpp20 = compiler == "clang" and ("libstdc++" in compiler.get_safe("libcxx", "") or compiler.version >= Version("17"))
+        return 20 if requires_cpp20 else 17
+
+    def layout(self):
+        cmake_layout(self, src_folder="src")
+
     def config_options(self):
         if self.settings.os == "Windows":
-            del self.options.fPIC
+            self.options.rm_safe("fPIC")
 
     def validate(self):
+        if self.settings.compiler.cppstd:
+            check_min_cppstd(self, self._min_cppstd)
+        
         # We can't simply check for C++20, because clang and MSVC support the coroutine TS despite not having labeled (__cplusplus macro) C++20 support
         min_version = self._minimum_compilers_version.get(str(self.settings.compiler))
         if not min_version:
-            self.output.warn("{} recipe lacks information about the {} compiler support.".format(
-                self.name, self.settings.compiler))
+            self.output.warning(f"{self.name} recipe lacks information about the {self.settings.compiler} compiler support.")
         else:
-            if tools.Version(self.settings.compiler.version) < min_version:
-                raise ConanInvalidConfiguration("{} requires coroutine TS support. The current compiler {} {} does not support it.".format(
-                    self.name, self.settings.compiler, self.settings.compiler.version))
-
-        # Currently clang expects coroutine to be implemented in a certain way (under std::experiemental::), while libstdc++ puts them under std::
-        # There are also other inconsistencies, see https://bugs.llvm.org/show_bug.cgi?id=48172
-        # This should be removed after both gcc and clang implements the final coroutine TS
-        if self.settings.compiler == "clang" and self.settings.compiler.get_safe("libcxx") == "libstdc++":
-            raise ConanInvalidConfiguration("{} does not support clang with libstdc++. Use libc++ instead.".format(self.name))
+            if Version(self.settings.compiler.version) < min_version:
+                raise ConanInvalidConfiguration(
+                    f"{self.name} requires coroutine TS support. The current compiler {self.settings.compiler} {self.settings.compiler.version} does not support it."
+                )
+
+        # Older versions of clang expects coroutine to be put under std::experimental::, while libstdc++ puts them under std::,
+        # See https://bugs.llvm.org/show_bug.cgi?id=48172 for more context.
+        if self.settings.compiler == "clang" and "libstdc++" in self.settings.compiler.get_safe("libcxx", ""):
+            if self.settings.compiler.version < Version("14"):
+                raise ConanInvalidConfiguration("{self.name} does not support clang<14 with libstdc++. Use libc++ or upgrade to clang 14+ instead.")
+            if self.settings.compiler.version == Version("14"):
+                self.output.warning("This build may fail if using libstdc++13 or greater")
 
     def configure(self):
         if self.options.shared:
-            del self.options.fPIC
+            self.options.rm_safe("fPIC")
 
     def source(self):
-        tools.get(**self.conan_data["sources"][self.version], destination=self._source_subfolder, strip_root=True)
+        get(self, **self.conan_data["sources"][self.version], strip_root=True)
 
-    def _configure_cmake(self):
-        if not self._cmake:
-            self._cmake = CMake(self)
-            if self.settings.os == "Windows" and self.options.shared:
-                self._cmake.definitions["CMAKE_WINDOWS_EXPORT_ALL_SYMBOLS"] = "ON"
-            self._cmake.configure()
-        return self._cmake
+    def generate(self):
+        tc = CMakeToolchain(self)
+        tc.variables["CMAKE_WINDOWS_EXPORT_ALL_SYMBOLS"] = "ON"
+        tc.generate()
 
     def build(self):
-        cmake = self._configure_cmake()
+        cmake = CMake(self)
+        cmake.configure()
         cmake.build()
 
     def package(self):
-        self.copy("LICENSE.txt", dst="licenses", src=self._source_subfolder)
-        cmake = self._configure_cmake()
+        copy(self, "LICENSE.txt", dst=os.path.join(self.package_folder, "licenses"), src=self.source_folder)
+        cmake = CMake(self)
         cmake.install()
-        tools.rmdir(os.path.join(self.package_folder, "lib", "cmake"))
+        rmdir(self, os.path.join(self.package_folder, "lib", "cmake"))
 
-    def package_info(self):
-        self.cpp_info.filenames["cmake_find_package"] = "cppcoro"
-        self.cpp_info.filenames["cmake_find_package_multi"] = "cppcoro"
-        self.cpp_info.names["cmake_find_package"] = "cppcoro"
-        self.cpp_info.names["cmake_find_package_multi"] = "cppcoro"
+    @property
+    def _needs_fcoroutines_ts_flag(self):
+        version = Version(self.settings.compiler.version)
+        if self.settings.compiler == "clang":
+            # clang 5: Coroutines support added
+            # somewhere between clang 5 and 11: the requirement to add -fcoroutines-ts was dropped, at least in the context of this recipe.
+            return version < 11
+        elif self.settings.compiler == "apple-clang":
+            # At some point before apple-clang 13, in the context of this recipe, the requirement for this flag was dropped.
+            return version < 13
+        else:
+            return False
 
-        comp = self.cpp_info.components["cppcoro"]
-        comp.names["cmake_find_package"] = "cppcoro"
-        comp.names["cmake_find_package_multi"] = "cppcoro"
-        comp.libs = ["cppcoro"]
+    def package_info(self):
+        self.cpp_info.libs = ["cppcoro"]
 
-        if self.settings.os == "Linux" and self.options.shared:
-            comp.system_libs = ["pthread"]
+        if self.settings.os in ["Linux", "FreeBSD"] and self.options.shared:
+            self.cpp_info.system_libs = ["pthread", "m"]
         if self.settings.os == "Windows":
-            comp.system_libs = ["synchronization"]
+            self.cpp_info.system_libs = ["synchronization", "ws2_32", "mswsock"]
 
-        if self.settings.compiler == "Visual Studio":
-            comp.cxxflags.append("/await")
+        if is_msvc(self):
+            self.cpp_info.cxxflags.append("/await")
         elif self.settings.compiler == "gcc":
-            comp.cxxflags.append("-fcoroutines")
-            comp.defines.append("CPPCORO_COMPILER_SUPPORTS_SYMMETRIC_TRANSFER=1")
-        elif self.settings.compiler == "clang" or self.settings.compiler == "apple-clang":
-            comp.cxxflags.append("-fcoroutines-ts")
+            self.cpp_info.cxxflags.append("-fcoroutines")
+            self.cpp_info.defines.append("CPPCORO_COMPILER_SUPPORTS_SYMMETRIC_TRANSFER=1")
+        elif self._needs_fcoroutines_ts_flag:
+            self.cpp_info.cxxflags.append("-fcoroutines-ts")
+
+        self.cpp_info.set_property("cmake_file_name", "cppcoro")
+        self.cpp_info.set_property("cmake_target_name", "cppcoro::cppcoro")
+
+        # TODO: to remove in conan v2 once cmake_find_package_* generators removed
+        self.cpp_info.filenames["cmake_find_package"] = "cppcoro"
+        self.cpp_info.filenames["cmake_find_package_multi"] = "cppcoro"
+        self.cpp_info.names["cmake_find_package"] = "cppcoro"
+        self.cpp_info.names["cmake_find_package_multi"] = "cppcoro"


Test patch:
diff --git a/recipes/andreasbuhr-cppcoro/all/test_package/CMakeLists.txt b/recipes/andreasbuhr-cppcoro/all/test_package/CMakeLists.txt
--- a/recipes/andreasbuhr-cppcoro/all/test_package/CMakeLists.txt
+++ b/recipes/andreasbuhr-cppcoro/all/test_package/CMakeLists.txt
@@ -1,9 +1,6 @@
-cmake_minimum_required(VERSION 3.1)
+cmake_minimum_required(VERSION 3.15)
 project(test_package)
 
-include(${CMAKE_BINARY_DIR}/conanbuildinfo.cmake)
-conan_basic_setup()
-
 find_package(cppcoro CONFIG REQUIRED)
 
 add_executable(${PROJECT_NAME} test_package.cpp)
diff --git a/recipes/andreasbuhr-cppcoro/all/test_package/conanfile.py b/recipes/andreasbuhr-cppcoro/all/test_package/conanfile.py
--- a/recipes/andreasbuhr-cppcoro/all/test_package/conanfile.py
+++ b/recipes/andreasbuhr-cppcoro/all/test_package/conanfile.py
@@ -1,9 +1,19 @@
+from conan import ConanFile
+from conan.tools.build import can_run
+from conan.tools.cmake import CMake, cmake_layout
 import os
-from conans import ConanFile, CMake, tools
+
 
 class TestPackageConan(ConanFile):
-    settings = "os", "compiler", "build_type", "arch"
-    generators = "cmake", "cmake_find_package_multi"
+    settings = "os", "arch", "compiler", "build_type"
+    generators = "CMakeToolchain", "CMakeDeps", "VirtualRunEnv"
+    test_type = "explicit"
+
+    def layout(self):
+        cmake_layout(self)
+
+    def requirements(self):
+        self.requires(self.tested_reference_str)
 
     def build(self):
         cmake = CMake(self)
@@ -11,6 +21,6 @@ def build(self):
         cmake.build()
 
     def test(self):
-        if not tools.cross_building(self.settings):
-            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")
diff --git a/recipes/andreasbuhr-cppcoro/all/test_v1_package/CMakeLists.txt b/recipes/andreasbuhr-cppcoro/all/test_v1_package/CMakeLists.txt
new file mode 100644
--- /dev/null
+++ b/recipes/andreasbuhr-cppcoro/all/test_v1_package/CMakeLists.txt
@@ -0,0 +1,8 @@
+cmake_minimum_required(VERSION 3.1)
+project(test_package)
+
+include(${CMAKE_BINARY_DIR}/conanbuildinfo.cmake)
+conan_basic_setup(TARGETS)
+
+add_subdirectory(${CMAKE_CURRENT_SOURCE_DIR}/../test_package
+                 ${CMAKE_CURRENT_BINARY_DIR}/test_package)
diff --git a/recipes/andreasbuhr-cppcoro/all/test_v1_package/conanfile.py b/recipes/andreasbuhr-cppcoro/all/test_v1_package/conanfile.py
new file mode 100644
--- /dev/null
+++ b/recipes/andreasbuhr-cppcoro/all/test_v1_package/conanfile.py
@@ -0,0 +1,17 @@
+from conans import ConanFile, CMake, tools
+import os
+
+
+class TestPackageConan(ConanFile):
+    settings = "os", "arch", "compiler", "build_type"
+    generators = "cmake", "cmake_find_package_multi"
+
+    def build(self):
+        cmake = CMake(self)
+        cmake.configure()
+        cmake.build()
+
+    def test(self):
+        if not tools.cross_building(self):
+            bin_path = os.path.join("bin", "test_package")
+            self.run(bin_path, run_environment=True)