Repository: conan-io/conan-center-index

Issue:
[package] libidn/1.36: conan install reports "libidn/1.36 seems broken"
### Description

when I attempt to install libidn/1.36 conan reports 

> Recipe 'libidn/1.36' seems broken.
> It is possible that this recipe is not Conan 2.0 ready
> If the recipe comes from ConanCenter check: https://conan.io/cci-v2.html
> If it is your recipe, check if it is updated to 2.0

Hence I am unable to use podofo/0.9.7 for now.

### Package and Environment Details

* Package Name/Version: **libidn/1.36**
* Operating System+version: **Manjaro Linux**
* Compiler+version: **GCC 12.2.1**
* Conan version: **conan 2.0.2**
* Python version: **Python 3.10.9**


### Conan profile

[settings]
arch=x86_64
build_type=Debug
compiler=gcc
compiler.cppstd=gnu17
compiler.libcxx=libstdc++11
compiler.version=12
os=Linux


### Steps to reproduce

conan install --requires=libidn/1.36 -of temp

### Logs


======== Input profiles ========
Profile host:
[settings]
arch=x86_64
build_type=Debug
compiler=gcc
compiler.cppstd=gnu17
compiler.libcxx=libstdc++11
compiler.version=12
os=Linux

Profile build:
[settings]
arch=x86_64
build_type=Debug
compiler=gcc
compiler.cppstd=gnu17
compiler.libcxx=libstdc++11
compiler.version=12
os=Linux


======== Computing dependency graph ========
Graph root
    cli
*********************************************************
Recipe 'libidn/1.36' seems broken.
It is possible that this recipe is not Conan 2.0 ready
If the recipe comes from ConanCenter check: https://conan.io/cci-v2.html
If it is your recipe, check if it is updated to 2.0
*********************************************************

ERROR: Package 'libidn/1.36' not resolved: libidn/1.36: Cannot load recipe.
Error loading conanfile at '/home/volker/.conan2/p/libidad27bc2fdd138/e/conanfile.py': Unable to load conanfile in /home/volker/.conan2/p/libidad27bc2fdd138/e/conanfile.py
  File "<frozen importlib._bootstrap_external>", line 883, in exec_module
  File "<frozen importlib._bootstrap>", line 241, in _call_with_frames_removed
  File "/home/volker/.conan2/p/libidad27bc2fdd138/e/conanfile.py", line 1, in <module>
    from conans import AutoToolsBuildEnvironment, ConanFile, tools
ImportError: cannot import name 'AutoToolsBuildEnvironment' from 'conans' (/home/volker/.local/lib/python3.10/site-packages/conans/__init__.py)




Discussion:

Resolving patch:
diff --git a/recipes/libidn/all/conanfile.py b/recipes/libidn/all/conanfile.py
--- a/recipes/libidn/all/conanfile.py
+++ b/recipes/libidn/all/conanfile.py
@@ -1,13 +1,14 @@
-from conan import ConanFile
-from conan.errors import ConanInvalidConfiguration
-from conan.tools.files import get, rmdir
-from conan.tools.scm import Version
-from conans import AutoToolsBuildEnvironment, tools
-import contextlib
-import functools
 import os
 
-required_conan_version = ">=1.33.0"
+from conan import ConanFile
+from conan.tools.build import cross_building
+from conan.tools.env import VirtualBuildEnv, VirtualRunEnv, Environment
+from conan.tools.files import get, rmdir, export_conandata_patches, apply_conandata_patches, copy, replace_in_file, rm, save
+from conan.tools.gnu import AutotoolsToolchain, Autotools, AutotoolsDeps
+from conan.tools.layout import basic_layout
+from conan.tools.microsoft import unix_path, is_msvc
+
+required_conan_version = ">=1.53.0"
 
 
 class LibIdnConan(ConanFile):
@@ -17,6 +18,8 @@ class LibIdnConan(ConanFile):
     topics = ("libidn", "encode", "decode", "internationalized", "domain", "name")
     license = "GPL-3.0-or-later"
     url = "https://github.com/conan-io/conan-center-index"
+
+    package_type = "library"
     settings = "os", "arch", "compiler", "build_type"
     options = {
         "shared": [True, False],
@@ -29,17 +32,12 @@ class LibIdnConan(ConanFile):
         "threads": True,
     }
 
-    @property
-    def _source_subfolder(self):
-        return "source_subfolder"
-
     @property
     def _settings_build(self):
         return getattr(self, "settings_build", self.settings)
 
     def export_sources(self):
-        for patch in self.conan_data.get("patches", {}).get(self.version, []):
-            self.copy(patch["patch_file"])
+        export_conandata_patches(self)
 
     def config_options(self):
         if self.settings.os == "Windows":
@@ -47,91 +45,120 @@ def config_options(self):
 
     def configure(self):
         if self.options.shared:
-            del self.options.fPIC
-        del self.settings.compiler.libcxx
-        del self.settings.compiler.cppstd
+            self.options.rm_safe("fPIC")
+        self.settings.rm_safe("compiler.libcxx")
+        self.settings.rm_safe("compiler.cppstd")
+
+    def layout(self):
+        basic_layout(self, src_folder="src")
 
     def requirements(self):
         self.requires("libiconv/1.17")
 
-    def validate(self):
-        if self.settings.os == "Windows" and self.options.shared:
-            raise ConanInvalidConfiguration("Shared libraries are not supported on Windows due to libtool limitation")
-
     def build_requirements(self):
-        if self._settings_build.os == "Windows" and not tools.get_env("CONAN_BASH_PATH"):
-            self.build_requires("msys2/cci.latest")
-        if self.settings.compiler == "Visual Studio":
-            self.build_requires("automake/1.16.5")
+        if self._settings_build.os == "Windows":
+            self.win_bash = True
+            if not self.conf.get("tools.microsoft.bash:path", check_type=str):
+                self.tool_requires("msys2/cci.latest")
+        if is_msvc(self):
+            self.tool_requires("automake/1.16.5")
 
     def source(self):
-        get(self, **self.conan_data["sources"][self.version],
-                  destination=self._source_subfolder, strip_root=True)
-
-    @contextlib.contextmanager
-    def _build_context(self):
-        if self.settings.compiler == "Visual Studio":
-            with tools.vcvars(self):
-                env = {
-                    "CC": "{} cl -nologo".format(tools.unix_path(self.deps_user_info["automake"].compile)),
-                    "CXX": "{} cl -nologo".format(tools.unix_path(self.deps_user_info["automake"].compile)),
-                    "LD": "{} link -nologo".format(tools.unix_path(self.deps_user_info["automake"].compile)),
-                    "AR": "{} lib".format(tools.unix_path(self.deps_user_info["automake"].ar_lib)),
-                }
-                with tools.environment_append(env):
-                    yield
-        else:
-            yield
+        get(self, **self.conan_data["sources"][self.version], strip_root=True)
+
+    def generate(self):
+        env = VirtualBuildEnv(self)
+        env.generate()
+
+        if not cross_building(self):
+            env = VirtualRunEnv(self)
+            env.generate(scope="build")
 
-    @functools.lru_cache(1)
-    def _configure_autotools(self):
-        autotools = AutoToolsBuildEnvironment(self, win_bash=tools.os_info.is_windows)
-        autotools.libs = []
+        tc = AutotoolsToolchain(self)
         if not self.options.shared:
-            autotools.defines.append("LIBIDN_STATIC")
-        if self.settings.compiler == "Visual Studio":
-            if Version(self.settings.compiler.version) >= "12":
-                autotools.flags.append("-FS")
-            autotools.link_flags.extend("-L{}".format(p.replace("\\", "/")) for p in self.deps_cpp_info.lib_paths)
+            tc.extra_defines.append("LIBIDN_STATIC")
         yes_no = lambda v: "yes" if v else "no"
-        conf_args = [
-            "--enable-shared={}".format(yes_no(self.options.shared)),
-            "--enable-static={}".format(yes_no(not self.options.shared)),
+        tc.configure_args += [
             "--enable-threads={}".format(yes_no(self.options.threads)),
-            "--with-libiconv-prefix={}".format(tools.unix_path(self.deps_cpp_info["libiconv"].rootpath)),
+            "--with-libiconv-prefix={}".format(unix_path(self, self.dependencies["libiconv"].package_folder)),
+            "--disable-csharp",
             "--disable-nls",
             "--disable-rpath",
         ]
-        autotools.configure(args=conf_args, configure_dir=self._source_subfolder)
-        return autotools
-
-    def build(self):
-        for patch in self.conan_data.get("patches", {}).get(self.version, []):
-            tools.patch(**patch)
-        if self.settings.compiler == "Visual Studio":
+        if is_msvc(self):
+            tc.extra_cflags.append("-FS")
+            tc.extra_cxxflags.append("-FS")
+        tc.generate()
+
+        if is_msvc(self):
+            env = Environment()
+            dep_info = self.dependencies["libiconv"].cpp_info.aggregated_components()
+            env.append("CPPFLAGS", [f"-I{unix_path(self, p)}" for p in dep_info.includedirs] + [f"-D{d}" for d in dep_info.defines])
+            env.append("_LINK_", [lib if lib.endswith(".lib") else f"{lib}.lib" for lib in (dep_info.libs + dep_info.system_libs)])
+            env.append("LDFLAGS", [f"-L{unix_path(self, p)}" for p in dep_info.libdirs] + dep_info.sharedlinkflags + dep_info.exelinkflags)
+            env.append("CFLAGS", dep_info.cflags)
+            env.vars(self).save_script("conanautotoolsdeps_cl_workaround")
+        else:
+            deps = AutotoolsDeps(self)
+            deps.generate()
+
+        if is_msvc(self):
+            env = Environment()
+            automake_conf = self.dependencies.build["automake"].conf_info
+            compile_wrapper = unix_path(self, automake_conf.get("user.automake:compile-wrapper", check_type=str))
+            ar_wrapper = unix_path(self, automake_conf.get("user.automake:lib-wrapper", check_type=str))
+            # Workaround for iconv.lib not being found due to linker flag order
+            libiconv_libdir = unix_path(self, self.dependencies["libiconv"].cpp_info.aggregated_components().libdir)
+            env.define("CC", f"{compile_wrapper} cl -nologo -L{libiconv_libdir}")
+            env.define("CXX", f"{compile_wrapper} cl -nologo")
+            env.define("LD", "link -nologo")
+            env.define("AR", f'{ar_wrapper} lib')
+            env.vars(self).save_script("conanbuild_msvc")
+
+    def _patch_sources(self):
+        apply_conandata_patches(self)
+        # Disable examples and tests
+        for subdir in ["examples", "tests", "fuzz", "gltests", os.path.join("lib", "gltests"), "doc"]:
+            save(self, os.path.join(self.source_folder, subdir, "Makefile.in"), "all:\ninstall:\n")
+
+        if is_msvc(self):
             if self.settings.arch in ("x86_64", "armv8", "armv8.3"):
                 ssize = "signed long long int"
             else:
                 ssize = "signed long int"
-            tools.replace_in_file(os.path.join(self._source_subfolder, "lib", "stringprep.h"),
-                                  "ssize_t", ssize)
-        with self._build_context():
-            autotools = self._configure_autotools()
-            autotools.make(args=["V=1"])
+            replace_in_file(self, os.path.join(self.source_folder, "lib", "stringprep.h"), "ssize_t", ssize)
 
-    def package(self):
-        self.copy("COPYING", src=self._source_subfolder, dst="licenses")
-        with self._build_context():
-            autotools = self._configure_autotools()
-            autotools.install()
+        if self.settings.os == "Windows":
+            # Otherwise tries to create a symlink from GNUmakefile to itself, which fails on Windows
+            replace_in_file(self, os.path.join(self.source_folder, "configure"),
+                            '"$GNUmakefile") CONFIG_LINKS="$CONFIG_LINKS $GNUmakefile:$GNUmakefile" ;;', "")
+            replace_in_file(self, os.path.join(self.source_folder, "configure"),
+                            'ac_config_links="$ac_config_links $GNUmakefile:$GNUmakefile"', "")
 
+    def build(self):
+        self._patch_sources()
+        autotools = Autotools(self)
+        autotools.configure()
+        autotools.make()
+
+    def package(self):
+        copy(self, "COPYING", self.source_folder, os.path.join(self.package_folder, "licenses"))
+        autotools = Autotools(self)
+        autotools.install()
         rmdir(self, os.path.join(self.package_folder, "lib", "pkgconfig"))
         rmdir(self, os.path.join(self.package_folder, "share"))
-        tools.remove_files_by_mask(os.path.join(self.package_folder, "lib"), "*.la")
+        rm(self, "*.la", os.path.join(self.package_folder, "lib"), recursive=True)
+
+        if is_msvc(self) and self.options.shared:
+            os.rename(os.path.join(self.package_folder, "lib", "idn.dll.lib"),
+                      os.path.join(self.package_folder, "lib", "idn-12.lib"))
 
     def package_info(self):
-        self.cpp_info.libs = ["idn"]
-        self.cpp_info.names["pkg_config"] = "libidn"
+        if is_msvc(self) and self.options.shared:
+            self.cpp_info.libs = ["idn-12"]
+        else:
+            self.cpp_info.libs = ["idn"]
+        self.cpp_info.set_property("pkg_config_name", "libidn")
         if self.settings.os in ["Linux", "FreeBSD"]:
             if self.options.threads:
                 self.cpp_info.system_libs = ["pthread"]
@@ -139,7 +166,6 @@ def package_info(self):
             if not self.options.shared:
                 self.cpp_info.defines = ["LIBIDN_STATIC"]
 
+        # TODO: to remove in conan v2
         bin_path = os.path.join(self.package_folder, "bin")
-        self.output.info("Appending PATH environment variable: {}".format(bin_path))
         self.env_info.PATH.append(bin_path)
-


Test patch:
diff --git a/recipes/libidn/all/test_package/CMakeLists.txt b/recipes/libidn/all/test_package/CMakeLists.txt
--- a/recipes/libidn/all/test_package/CMakeLists.txt
+++ b/recipes/libidn/all/test_package/CMakeLists.txt
@@ -1,8 +1,7 @@
-cmake_minimum_required(VERSION 3.1)
+cmake_minimum_required(VERSION 3.15)
 project(test_package C)
 
-include(${CMAKE_BINARY_DIR}/conanbuildinfo.cmake)
-conan_basic_setup()
+find_package(libidn REQUIRED CONFIG)
 
 add_executable(${PROJECT_NAME} test_package.c)
-target_link_libraries(${PROJECT_NAME} ${CONAN_LIBS})
+target_link_libraries(${PROJECT_NAME} PRIVATE libidn::libidn)
diff --git a/recipes/libidn/all/test_package/conanfile.py b/recipes/libidn/all/test_package/conanfile.py
--- a/recipes/libidn/all/test_package/conanfile.py
+++ b/recipes/libidn/all/test_package/conanfile.py
@@ -1,10 +1,20 @@
-from conans import ConanFile, CMake, tools
 import os
 
+from conan import ConanFile
+from conan.tools.build import can_run
+from conan.tools.cmake import cmake_layout, CMake
+
 
 class TestPackageConan(ConanFile):
-    settings = "os", "compiler", "build_type", "arch"
-    generators = "cmake"
+    settings = "os", "arch", "compiler", "build_type"
+    generators = "CMakeDeps", "CMakeToolchain", "VirtualRunEnv"
+    test_type = "explicit"
+
+    def requirements(self):
+        self.requires(self.tested_reference_str, run=True)
+
+    def layout(self):
+        cmake_layout(self)
 
     def build(self):
         cmake = CMake(self)
@@ -12,8 +22,8 @@ def build(self):
         cmake.build()
 
     def test(self):
-        if not tools.cross_building(self):
-            self.run("idn --help", run_environment=True)
+        if can_run(self):
+            self.run("idn --help", env="conanrun")
 
-            bin_path = os.path.join("bin", "test_package")
-            self.run(bin_path, run_environment=True)
+            bin_path = os.path.join(self.cpp.build.bindir, "test_package")
+            self.run(bin_path, env="conanrun")
diff --git a/recipes/libidn/all/test_v1_package/CMakeLists.txt b/recipes/libidn/all/test_v1_package/CMakeLists.txt
new file mode 100644
--- /dev/null
+++ b/recipes/libidn/all/test_v1_package/CMakeLists.txt
@@ -0,0 +1,8 @@
+cmake_minimum_required(VERSION 3.15)
+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/libidn/all/test_v1_package/conanfile.py b/recipes/libidn/all/test_v1_package/conanfile.py
new file mode 100644
--- /dev/null
+++ b/recipes/libidn/all/test_v1_package/conanfile.py
@@ -0,0 +1,19 @@
+from conans import ConanFile, CMake, tools
+import os
+
+
+class TestPackageConan(ConanFile):
+    settings = "os", "compiler", "build_type", "arch"
+    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):
+            self.run("idn --help", run_environment=True)
+
+            bin_path = os.path.join("bin", "test_package")
+            self.run(bin_path, run_environment=True)