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

libidn: migrate to Conan v2, add shared MSVC build support #18641

Merged
merged 7 commits into from
Apr 19, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
1 change: 0 additions & 1 deletion recipes/libidn/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/libidn-1.36.tar.gz"
sha256: "14b67108344d81ba844631640df77c9071d9fb0659b080326ff5424e86b14038"
patches:
"1.36":
- patch_file: "patches/0001-unconditional-system-stdint-h.patch"

Check warning on line 7 in recipes/libidn/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-unc ... ^ (line: 7)
base_path: "source_subfolder"
180 changes: 103 additions & 77 deletions recipes/libidn/all/conanfile.py
Original file line number Diff line number Diff line change
@@ -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):
Expand All @@ -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],
Expand All @@ -29,117 +32,140 @@ 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":
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.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"]
if self.settings.os == "Windows":
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)

7 changes: 3 additions & 4 deletions recipes/libidn/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(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)
24 changes: 17 additions & 7 deletions recipes/libidn/all/test_package/conanfile.py
Original file line number Diff line number Diff line change
@@ -1,19 +1,29 @@
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)
cmake.configure()
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")
8 changes: 8 additions & 0 deletions recipes/libidn/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/)
19 changes: 19 additions & 0 deletions recipes/libidn/all/test_v1_package/conanfile.py
Original file line number Diff line number Diff line change
@@ -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)