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

libidn2: migrate to Conan v2, add shared MSVC build #18642

Merged
merged 12 commits into from
Apr 17, 2024
1 change: 0 additions & 1 deletion recipes/libidn2/all/conandata.yml
Original file line number Diff line number Diff line change
Expand Up @@ -5,4 +5,3 @@ sources:
patches:
"2.3.0":
- patch_file: "patches/0001-no-versioning-of-symbols.patch"
base_path: "source_subfolder"
154 changes: 80 additions & 74 deletions recipes/libidn2/all/conanfile.py
Original file line number Diff line number Diff line change
@@ -1,18 +1,30 @@
from conans import AutoToolsBuildEnvironment, ConanFile, tools
from conans.errors import ConanInvalidConfiguration
from contextlib import contextmanager
import os

required_conan_version = ">=1.33.0"
from conan import ConanFile
from conan.errors import ConanInvalidConfiguration
from conan.tools.build import cross_building
from conan.tools.env import Environment, VirtualBuildEnv, VirtualRunEnv
from conan.tools.files import apply_conandata_patches, chdir, copy, export_conandata_patches, get, rmdir
from conan.tools.gnu import Autotools, AutotoolsDeps, AutotoolsToolchain
from conan.tools.layout import basic_layout
from conan.tools.microsoft import is_msvc, unix_path

required_conan_version = ">=1.53.0"


class LibIdn(ConanFile):
name = "libidn2"
description = "GNU Libidn is a fully documented implementation of the Stringprep, Punycode and IDNA 2003 specifications."
homepage = "https://www.gnu.org/software/libidn/"
topics = ("libidn", "encode", "decode", "internationalized", "domain", "name")
description = (
"GNU Libidn is a fully documented implementation of the Stringprep, Punycode and IDNA 2003"
" specifications."
)
license = "GPL-3.0-or-later"
url = "https://github.com/conan-io/conan-center-index"
homepage = "https://www.gnu.org/software/libidn/"
topics = ("libidn", "encode", "decode", "internationalized", "domain", "name")

package_type = "library"
settings = "os", "arch", "compiler", "build_type"
options = {
"shared": [True, False],
"fPIC": [True, False],
Expand All @@ -21,111 +33,105 @@ class LibIdn(ConanFile):
"shared": False,
"fPIC": True,
}
settings = "os", "arch", "compiler", "build_type"

_autotools = None

@property
def _source_subfolder(self):
return "source_subfolder"
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":
del self.options.fPIC

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.16")
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")

@property
def _settings_build(self):
return getattr(self, "settings_build", self.settings)
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.4")
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):
tools.get(**self.conan_data["sources"][self.version],
destination=self._source_subfolder, strip_root=True)

@contextmanager
def _build_context(self):
if self.settings.compiler == "Visual Studio":
with tools.vcvars(self.settings):
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

def _configure_autotools(self):
if self._autotools:
return self._autotools
self._autotools = AutoToolsBuildEnvironment(self, win_bash=tools.os_info.is_windows)
self._autotools.libs = []
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")
tc = AutotoolsToolchain(self)
if not self.options.shared:
self._autotools.defines.append("IDN2_STATIC")
if self.settings.compiler == "Visual Studio":
if tools.Version(self.settings.compiler.version) >= "12":
self._autotools.flags.append("-FS")
self._autotools.link_flags.extend("-L{}".format(p.replace("\\", "/")) for p in self.deps_cpp_info.lib_paths)
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)),
"--with-libiconv-prefix={}".format(tools.unix_path(self.deps_cpp_info["libiconv"].rootpath)),
tc.extra_defines.append("IDN2_STATIC")
if is_msvc(self):
tc.extra_cxxflags.append("-FS")
tc.configure_args += [
f"--with-libiconv-prefix={unix_path(self, self.dependencies['libiconv'].package_folder)}",
"--disable-nls",
"--disable-rpath",
]
self._autotools.configure(args=conf_args, configure_dir=self._source_subfolder)
return self._autotools
tc.generate()
tc = AutotoolsDeps(self)
tc.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))
env.define("CC", f"{compile_wrapper} cl -nologo")
env.define("CXX", f"{compile_wrapper} cl -nologo")
env.define("LD", "link -nologo")
env.define("AR", f'{ar_wrapper} "lib -nologo"')
env.define("NM", "dumpbin -symbols")
env.define("OBJDUMP", ":")
env.define("RANLIB", ":")
env.define("STRIP", ":")
env.vars(self).save_script("conanbuild_msvc")

def build(self):
for patch in self.conan_data.get("patches", {}).get(self.version, []):
tools.patch(**patch)
with self._build_context():
autotools = self._configure_autotools()
apply_conandata_patches(self)
with chdir(self, self.source_folder):
autotools = Autotools(self)
autotools.configure()
autotools.make()

def package(self):
self.copy("COPYING", src=self._source_subfolder, dst="licenses")
with self._build_context():
autotools = self._configure_autotools()
copy(self, "COPYING", src=self.source_folder, dst=os.path.join(self.package_folder, "licenses"))
with chdir(self, self.source_folder):
autotools = Autotools(self)
autotools.install()

os.unlink(os.path.join(self.package_folder, "lib", "libidn2.la"))

tools.rmdir(os.path.join(self.package_folder, "lib", "pkgconfig"))
tools.rmdir(os.path.join(self.package_folder, "share"))
rmdir(self, os.path.join(self.package_folder, "lib", "pkgconfig"))
rmdir(self, os.path.join(self.package_folder, "share"))

def package_info(self):
self.cpp_info.libs = ["idn2"]
self.cpp_info.names["pkg_config"] = "libidn2"
self.cpp_info.set_property("pkg_config_name", "libidn2")
if self.settings.os == "Windows":
if not self.options.shared:
self.cpp_info.defines = ["IDN2_STATIC"]

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)
7 changes: 3 additions & 4 deletions recipes/libidn2/all/test_package/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -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(libidn2 REQUIRED CONFIG)

add_executable(${PROJECT_NAME} test_package.c)
target_link_libraries(${PROJECT_NAME} ${CONAN_LIBS})
target_link_libraries(${PROJECT_NAME} PRIVATE libidn2::libidn2)
30 changes: 22 additions & 8 deletions recipes/libidn2/all/test_package/conanfile.py
Original file line number Diff line number Diff line change
@@ -1,20 +1,34 @@
from conans import ConanFile, CMake, tools
from conan import ConanFile
from conan.tools.build import can_run
from conan.tools.cmake import cmake_layout, CMake
import os

from conan.tools.env import VirtualRunEnv


class TestPackageConan(ConanFile):
settings = "os", "compiler", "build_type", "arch"
generators = "cmake"
settings = "os", "arch", "compiler", "build_type"
generators = "CMakeDeps", "CMakeToolchain"
test_type = "explicit"

def requirements(self):
self.requires(self.tested_reference_str, run=True)

def layout(self):
cmake_layout(self)

def generate(self):
VirtualRunEnv(self).generate(scope="run")
VirtualRunEnv(self).generate(scope="build")

def build(self):
cmake = CMake(self)
cmake.configure()
cmake.build()

def test(self):
if not tools.cross_building(self.settings):
self.run("idn2 --help", run_environment=True)

bin_path = os.path.join("bin", "test_package")
self.run(bin_path, run_environment=True)
if can_run(self):
self.run("idn2 --help")

bin_path = os.path.join(self.cpp.build.bindir, "test_package")
self.run(bin_path, env="conanrun")
8 changes: 8 additions & 0 deletions recipes/libidn2/all/test_v1_package/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -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/)
20 changes: 20 additions & 0 deletions recipes/libidn2/all/test_v1_package/conanfile.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
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.settings):
self.run("idn2 --help", run_environment=True)

bin_path = os.path.join("bin", "test_package")
self.run(bin_path, run_environment=True)