Skip to content

Commit 39cf098

Browse files
valgurfranramirez688
authored andcommitted
(conan-io#18641) libidn: migrate to Conan v2, add shared MSVC build support
* libidn: migrate to Conan v2 * libidn: fix MSVC build * libidn: --disable-csharp * libidn: fix shared lib not being found in v1 * libidn: fix MSVC build, add shared MSVC build support * libidn: tc.extra_cflags.append("-FS")
1 parent ea2470a commit 39cf098

File tree

6 files changed

+150
-89
lines changed

6 files changed

+150
-89
lines changed

recipes/libidn/all/conandata.yml

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,4 +5,3 @@ sources:
55
patches:
66
"1.36":
77
- patch_file: "patches/0001-unconditional-system-stdint-h.patch"
8-
base_path: "source_subfolder"

recipes/libidn/all/conanfile.py

Lines changed: 103 additions & 77 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,14 @@
1-
from conan import ConanFile
2-
from conan.errors import ConanInvalidConfiguration
3-
from conan.tools.files import get, rmdir
4-
from conan.tools.scm import Version
5-
from conans import AutoToolsBuildEnvironment, tools
6-
import contextlib
7-
import functools
81
import os
92

10-
required_conan_version = ">=1.33.0"
3+
from conan import ConanFile
4+
from conan.tools.build import cross_building
5+
from conan.tools.env import VirtualBuildEnv, VirtualRunEnv, Environment
6+
from conan.tools.files import get, rmdir, export_conandata_patches, apply_conandata_patches, copy, replace_in_file, rm, save
7+
from conan.tools.gnu import AutotoolsToolchain, Autotools, AutotoolsDeps
8+
from conan.tools.layout import basic_layout
9+
from conan.tools.microsoft import unix_path, is_msvc
10+
11+
required_conan_version = ">=1.53.0"
1112

1213

1314
class LibIdnConan(ConanFile):
@@ -17,6 +18,8 @@ class LibIdnConan(ConanFile):
1718
topics = ("libidn", "encode", "decode", "internationalized", "domain", "name")
1819
license = "GPL-3.0-or-later"
1920
url = "https://github.com/conan-io/conan-center-index"
21+
22+
package_type = "library"
2023
settings = "os", "arch", "compiler", "build_type"
2124
options = {
2225
"shared": [True, False],
@@ -29,117 +32,140 @@ class LibIdnConan(ConanFile):
2932
"threads": True,
3033
}
3134

32-
@property
33-
def _source_subfolder(self):
34-
return "source_subfolder"
35-
3635
@property
3736
def _settings_build(self):
3837
return getattr(self, "settings_build", self.settings)
3938

4039
def export_sources(self):
41-
for patch in self.conan_data.get("patches", {}).get(self.version, []):
42-
self.copy(patch["patch_file"])
40+
export_conandata_patches(self)
4341

4442
def config_options(self):
4543
if self.settings.os == "Windows":
4644
del self.options.fPIC
4745

4846
def configure(self):
4947
if self.options.shared:
50-
del self.options.fPIC
51-
del self.settings.compiler.libcxx
52-
del self.settings.compiler.cppstd
48+
self.options.rm_safe("fPIC")
49+
self.settings.rm_safe("compiler.libcxx")
50+
self.settings.rm_safe("compiler.cppstd")
51+
52+
def layout(self):
53+
basic_layout(self, src_folder="src")
5354

5455
def requirements(self):
5556
self.requires("libiconv/1.17")
5657

57-
def validate(self):
58-
if self.settings.os == "Windows" and self.options.shared:
59-
raise ConanInvalidConfiguration("Shared libraries are not supported on Windows due to libtool limitation")
60-
6158
def build_requirements(self):
62-
if self._settings_build.os == "Windows" and not tools.get_env("CONAN_BASH_PATH"):
63-
self.build_requires("msys2/cci.latest")
64-
if self.settings.compiler == "Visual Studio":
65-
self.build_requires("automake/1.16.5")
59+
if self._settings_build.os == "Windows":
60+
self.win_bash = True
61+
if not self.conf.get("tools.microsoft.bash:path", check_type=str):
62+
self.tool_requires("msys2/cci.latest")
63+
if is_msvc(self):
64+
self.tool_requires("automake/1.16.5")
6665

6766
def source(self):
68-
get(self, **self.conan_data["sources"][self.version],
69-
destination=self._source_subfolder, strip_root=True)
70-
71-
@contextlib.contextmanager
72-
def _build_context(self):
73-
if self.settings.compiler == "Visual Studio":
74-
with tools.vcvars(self):
75-
env = {
76-
"CC": "{} cl -nologo".format(tools.unix_path(self.deps_user_info["automake"].compile)),
77-
"CXX": "{} cl -nologo".format(tools.unix_path(self.deps_user_info["automake"].compile)),
78-
"LD": "{} link -nologo".format(tools.unix_path(self.deps_user_info["automake"].compile)),
79-
"AR": "{} lib".format(tools.unix_path(self.deps_user_info["automake"].ar_lib)),
80-
}
81-
with tools.environment_append(env):
82-
yield
83-
else:
84-
yield
67+
get(self, **self.conan_data["sources"][self.version], strip_root=True)
68+
69+
def generate(self):
70+
env = VirtualBuildEnv(self)
71+
env.generate()
72+
73+
if not cross_building(self):
74+
env = VirtualRunEnv(self)
75+
env.generate(scope="build")
8576

86-
@functools.lru_cache(1)
87-
def _configure_autotools(self):
88-
autotools = AutoToolsBuildEnvironment(self, win_bash=tools.os_info.is_windows)
89-
autotools.libs = []
77+
tc = AutotoolsToolchain(self)
9078
if not self.options.shared:
91-
autotools.defines.append("LIBIDN_STATIC")
92-
if self.settings.compiler == "Visual Studio":
93-
if Version(self.settings.compiler.version) >= "12":
94-
autotools.flags.append("-FS")
95-
autotools.link_flags.extend("-L{}".format(p.replace("\\", "/")) for p in self.deps_cpp_info.lib_paths)
79+
tc.extra_defines.append("LIBIDN_STATIC")
9680
yes_no = lambda v: "yes" if v else "no"
97-
conf_args = [
98-
"--enable-shared={}".format(yes_no(self.options.shared)),
99-
"--enable-static={}".format(yes_no(not self.options.shared)),
81+
tc.configure_args += [
10082
"--enable-threads={}".format(yes_no(self.options.threads)),
101-
"--with-libiconv-prefix={}".format(tools.unix_path(self.deps_cpp_info["libiconv"].rootpath)),
83+
"--with-libiconv-prefix={}".format(unix_path(self, self.dependencies["libiconv"].package_folder)),
84+
"--disable-csharp",
10285
"--disable-nls",
10386
"--disable-rpath",
10487
]
105-
autotools.configure(args=conf_args, configure_dir=self._source_subfolder)
106-
return autotools
107-
108-
def build(self):
109-
for patch in self.conan_data.get("patches", {}).get(self.version, []):
110-
tools.patch(**patch)
111-
if self.settings.compiler == "Visual Studio":
88+
if is_msvc(self):
89+
tc.extra_cflags.append("-FS")
90+
tc.extra_cxxflags.append("-FS")
91+
tc.generate()
92+
93+
if is_msvc(self):
94+
env = Environment()
95+
dep_info = self.dependencies["libiconv"].cpp_info.aggregated_components()
96+
env.append("CPPFLAGS", [f"-I{unix_path(self, p)}" for p in dep_info.includedirs] + [f"-D{d}" for d in dep_info.defines])
97+
env.append("_LINK_", [lib if lib.endswith(".lib") else f"{lib}.lib" for lib in (dep_info.libs + dep_info.system_libs)])
98+
env.append("LDFLAGS", [f"-L{unix_path(self, p)}" for p in dep_info.libdirs] + dep_info.sharedlinkflags + dep_info.exelinkflags)
99+
env.append("CFLAGS", dep_info.cflags)
100+
env.vars(self).save_script("conanautotoolsdeps_cl_workaround")
101+
else:
102+
deps = AutotoolsDeps(self)
103+
deps.generate()
104+
105+
if is_msvc(self):
106+
env = Environment()
107+
automake_conf = self.dependencies.build["automake"].conf_info
108+
compile_wrapper = unix_path(self, automake_conf.get("user.automake:compile-wrapper", check_type=str))
109+
ar_wrapper = unix_path(self, automake_conf.get("user.automake:lib-wrapper", check_type=str))
110+
# Workaround for iconv.lib not being found due to linker flag order
111+
libiconv_libdir = unix_path(self, self.dependencies["libiconv"].cpp_info.aggregated_components().libdir)
112+
env.define("CC", f"{compile_wrapper} cl -nologo -L{libiconv_libdir}")
113+
env.define("CXX", f"{compile_wrapper} cl -nologo")
114+
env.define("LD", "link -nologo")
115+
env.define("AR", f'{ar_wrapper} lib')
116+
env.vars(self).save_script("conanbuild_msvc")
117+
118+
def _patch_sources(self):
119+
apply_conandata_patches(self)
120+
# Disable examples and tests
121+
for subdir in ["examples", "tests", "fuzz", "gltests", os.path.join("lib", "gltests"), "doc"]:
122+
save(self, os.path.join(self.source_folder, subdir, "Makefile.in"), "all:\ninstall:\n")
123+
124+
if is_msvc(self):
112125
if self.settings.arch in ("x86_64", "armv8", "armv8.3"):
113126
ssize = "signed long long int"
114127
else:
115128
ssize = "signed long int"
116-
tools.replace_in_file(os.path.join(self._source_subfolder, "lib", "stringprep.h"),
117-
"ssize_t", ssize)
118-
with self._build_context():
119-
autotools = self._configure_autotools()
120-
autotools.make(args=["V=1"])
129+
replace_in_file(self, os.path.join(self.source_folder, "lib", "stringprep.h"), "ssize_t", ssize)
121130

122-
def package(self):
123-
self.copy("COPYING", src=self._source_subfolder, dst="licenses")
124-
with self._build_context():
125-
autotools = self._configure_autotools()
126-
autotools.install()
131+
if self.settings.os == "Windows":
132+
# Otherwise tries to create a symlink from GNUmakefile to itself, which fails on Windows
133+
replace_in_file(self, os.path.join(self.source_folder, "configure"),
134+
'"$GNUmakefile") CONFIG_LINKS="$CONFIG_LINKS $GNUmakefile:$GNUmakefile" ;;', "")
135+
replace_in_file(self, os.path.join(self.source_folder, "configure"),
136+
'ac_config_links="$ac_config_links $GNUmakefile:$GNUmakefile"', "")
127137

138+
def build(self):
139+
self._patch_sources()
140+
autotools = Autotools(self)
141+
autotools.configure()
142+
autotools.make()
143+
144+
def package(self):
145+
copy(self, "COPYING", self.source_folder, os.path.join(self.package_folder, "licenses"))
146+
autotools = Autotools(self)
147+
autotools.install()
128148
rmdir(self, os.path.join(self.package_folder, "lib", "pkgconfig"))
129149
rmdir(self, os.path.join(self.package_folder, "share"))
130-
tools.remove_files_by_mask(os.path.join(self.package_folder, "lib"), "*.la")
150+
rm(self, "*.la", os.path.join(self.package_folder, "lib"), recursive=True)
151+
152+
if is_msvc(self) and self.options.shared:
153+
os.rename(os.path.join(self.package_folder, "lib", "idn.dll.lib"),
154+
os.path.join(self.package_folder, "lib", "idn-12.lib"))
131155

132156
def package_info(self):
133-
self.cpp_info.libs = ["idn"]
134-
self.cpp_info.names["pkg_config"] = "libidn"
157+
if is_msvc(self) and self.options.shared:
158+
self.cpp_info.libs = ["idn-12"]
159+
else:
160+
self.cpp_info.libs = ["idn"]
161+
self.cpp_info.set_property("pkg_config_name", "libidn")
135162
if self.settings.os in ["Linux", "FreeBSD"]:
136163
if self.options.threads:
137164
self.cpp_info.system_libs = ["pthread"]
138165
if self.settings.os == "Windows":
139166
if not self.options.shared:
140167
self.cpp_info.defines = ["LIBIDN_STATIC"]
141168

169+
# TODO: to remove in conan v2
142170
bin_path = os.path.join(self.package_folder, "bin")
143-
self.output.info("Appending PATH environment variable: {}".format(bin_path))
144171
self.env_info.PATH.append(bin_path)
145-
Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,7 @@
1-
cmake_minimum_required(VERSION 3.1)
1+
cmake_minimum_required(VERSION 3.15)
22
project(test_package C)
33

4-
include(${CMAKE_BINARY_DIR}/conanbuildinfo.cmake)
5-
conan_basic_setup()
4+
find_package(libidn REQUIRED CONFIG)
65

76
add_executable(${PROJECT_NAME} test_package.c)
8-
target_link_libraries(${PROJECT_NAME} ${CONAN_LIBS})
7+
target_link_libraries(${PROJECT_NAME} PRIVATE libidn::libidn)
Lines changed: 17 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,19 +1,29 @@
1-
from conans import ConanFile, CMake, tools
21
import os
32

3+
from conan import ConanFile
4+
from conan.tools.build import can_run
5+
from conan.tools.cmake import cmake_layout, CMake
6+
47

58
class TestPackageConan(ConanFile):
6-
settings = "os", "compiler", "build_type", "arch"
7-
generators = "cmake"
9+
settings = "os", "arch", "compiler", "build_type"
10+
generators = "CMakeDeps", "CMakeToolchain", "VirtualRunEnv"
11+
test_type = "explicit"
12+
13+
def requirements(self):
14+
self.requires(self.tested_reference_str, run=True)
15+
16+
def layout(self):
17+
cmake_layout(self)
818

919
def build(self):
1020
cmake = CMake(self)
1121
cmake.configure()
1222
cmake.build()
1323

1424
def test(self):
15-
if not tools.cross_building(self):
16-
self.run("idn --help", run_environment=True)
25+
if can_run(self):
26+
self.run("idn --help", env="conanrun")
1727

18-
bin_path = os.path.join("bin", "test_package")
19-
self.run(bin_path, run_environment=True)
28+
bin_path = os.path.join(self.cpp.build.bindir, "test_package")
29+
self.run(bin_path, env="conanrun")
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
cmake_minimum_required(VERSION 3.15)
2+
project(test_package)
3+
4+
include(${CMAKE_BINARY_DIR}/conanbuildinfo.cmake)
5+
conan_basic_setup(TARGETS)
6+
7+
add_subdirectory(${CMAKE_CURRENT_SOURCE_DIR}/../test_package/
8+
${CMAKE_CURRENT_BINARY_DIR}/test_package/)
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
from conans import ConanFile, CMake, tools
2+
import os
3+
4+
5+
class TestPackageConan(ConanFile):
6+
settings = "os", "compiler", "build_type", "arch"
7+
generators = "cmake", "cmake_find_package_multi"
8+
9+
def build(self):
10+
cmake = CMake(self)
11+
cmake.configure()
12+
cmake.build()
13+
14+
def test(self):
15+
if not tools.cross_building(self):
16+
self.run("idn --help", run_environment=True)
17+
18+
bin_path = os.path.join("bin", "test_package")
19+
self.run(bin_path, run_environment=True)

0 commit comments

Comments
 (0)