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 @@ -3,6 +3,5 @@
url: "https://ftp.gnu.org/gnu/libidn/libidn2-2.3.0.tar.gz"
sha256: "e1cb1db3d2e249a6a3eb6f0946777c2e892d5c5dc7bd91c74394fc3a01cab8b5"
patches:
"2.3.0":
- patch_file: "patches/0001-no-versioning-of-symbols.patch"

Check warning on line 7 in recipes/libidn2/all/conandata.yml

View workflow job for this annotation

GitHub Actions / Lint changed files (YAML files)

conandata.yml schema warning

Schema outlined in https://github.com/conan-io/conan-center-index/blob/master/docs/adding_packages/conandata_yml_format.md#patches-fields is not followed. required key(s) 'patch_description', 'patch_type' not found in - patch_file: patches/0001-no- ... ^ (line: 7)
base_path: "source_subfolder"
175 changes: 97 additions & 78 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.tools.apple import fix_apple_shared_install_name
from conan.tools.build import cross_building
from conan.tools.env import Environment, VirtualBuildEnv, VirtualRunEnv
from conan.tools.files import apply_conandata_patches, 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,118 @@
"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 requirements(self):
self.requires("libiconv/1.16")

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 layout(self):
basic_layout(self, src_folder="src")

@property
def _settings_build(self):
return getattr(self, "settings_build", self.settings)
def requirements(self):
self.requires("libiconv/1.17")

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

def _configure_autotools(self):
if self._autotools:
return self._autotools
self._autotools = AutoToolsBuildEnvironment(self, win_bash=tools.os_info.is_windows)
self._autotools.libs = []
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_cflags.append("-FS")
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()

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))
dumpbin_nm = unix_path(self, os.path.join(self.source_folder, "dumpbin_nm.py"))

Check warning on line 109 in recipes/libidn2/all/conanfile.py

View workflow job for this annotation

GitHub Actions / Lint changed conanfile.py (v2 migration)

Unused variable 'dumpbin_nm'
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')
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()
autotools.make()
apply_conandata_patches(self)
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()
autotools.install()
copy(self, "COPYING", src=self.source_folder, dst=os.path.join(self.package_folder, "licenses"))
autotools = Autotools(self)
autotools.install()

os.unlink(os.path.join(self.package_folder, "lib", "libidn2.la"))
rmdir(self, os.path.join(self.package_folder, "lib", "pkgconfig"))
rmdir(self, os.path.join(self.package_folder, "share"))
fix_apple_shared_install_name(self)

tools.rmdir(os.path.join(self.package_folder, "lib", "pkgconfig"))
tools.rmdir(os.path.join(self.package_folder, "share"))
if is_msvc(self) and self.options.shared:
os.rename(os.path.join(self.package_folder, "lib", "idn2.dll.lib"),
os.path.join(self.package_folder, "lib", "idn2-0.lib"))
copy(self, "idn2.exe",
os.path.join(self.build_folder, "src", ".libs"),
os.path.join(self.package_folder, "bin"))

def package_info(self):
self.cpp_info.libs = ["idn2"]
self.cpp_info.names["pkg_config"] = "libidn2"
if is_msvc(self) and self.options.shared:
self.cpp_info.libs = ["idn2-0"]
else:
self.cpp_info.libs = ["idn2"]
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)
24 changes: 16 additions & 8 deletions recipes/libidn2/all/test_package/conanfile.py
Original file line number Diff line number Diff line change
@@ -1,20 +1,28 @@
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


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)
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", env="conanrun")

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)