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

Ruby: support conan v2 and expose more configuration options for native extension gems #18338

Closed
wants to merge 31 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
31 commits
Select commit Hold shift + click to select a range
cbef5f3
Ruby: support conan v2 and expose more configuration options for nati…
jmarrec Jul 5, 2023
53d7922
Make changes for 2.0.7
jmarrec Jul 5, 2023
ec79200
Delete option instead of forcing it to false
jmarrec Aug 28, 2023
e551968
Remove pylint: skip-file
jmarrec Dec 18, 2023
367787b
Adjust testing for conan v2
jmarrec Dec 19, 2023
5eed047
Use f-strings per the linter.
jmarrec Dec 19, 2023
f683111
Apply review comments from @valgur
jmarrec Dec 19, 2023
a0a0c43
Improve testing
jmarrec Dec 19, 2023
2798b4f
Fixup removing frameworks dir on mac
jmarrec Dec 19, 2023
80fc1a5
Rename test exe to test_v1_package for clarity
jmarrec Dec 20, 2023
175a786
Find libcrytod (notice the trailing d) on windows debug + zlibstatic …
jmarrec Dec 20, 2023
581ed33
use PkgConfigDeps - fixes an issue present on master branch
jmarrec Dec 20, 2023
a63e33a
Use CMakeToolChain to pass variables to cmake in test_package
jmarrec Dec 21, 2023
44dce48
v1 output contains the command being run, so test with "in" and not e…
jmarrec Dec 21, 2023
5bd4ff0
Adjust to_apple_arch which apparently takes conanfile
jmarrec Dec 21, 2023
63f190c
Try to explicitly depend on autoconf/2.71 for V2 pipeline failure on mac
jmarrec Dec 21, 2023
b35b422
Try with rbs 3.1.0 instead...
jmarrec Dec 22, 2023
cb560ce
try with debug 1.6.3 now...
jmarrec Dec 22, 2023
b50d916
Cross building: pass DESTDIR as arg to make install-local
jmarrec Dec 22, 2023
fe49bed
remove tool_requires
jmarrec Jan 22, 2024
d88e0eb
Windows adjusts: don't try to use conan libffi
jmarrec Jan 23, 2024
6277fba
Escape opt-dir, disable readline, use nmake
jmarrec Jan 23, 2024
f406535
Add patch_description (conan v2)
jmarrec Jan 23, 2024
2576083
Don't link to conan libyaml on msvc, it fails to link
jmarrec Jan 23, 2024
333c63d
Pass DESTDIR to nmake
jmarrec Jan 23, 2024
219f191
quote with-opt-dir only on windows
jmarrec Jan 23, 2024
445df2a
Adjust test_package
jmarrec Jan 23, 2024
ee3a932
nmake extract-extlibs requires a base ruby available, which CI window…
jmarrec Jan 23, 2024
c986810
Actually just assumes that the current libffi bundled in source is up…
jmarrec Jan 23, 2024
0178690
Use fix_apple_shared_install_name to shush KB-H077?
jmarrec Jan 23, 2024
7ddb85e
Backport --add-gmp-dir in an attempt to fix miniruby not loading gmp lib
jmarrec Feb 2, 2024
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
18 changes: 13 additions & 5 deletions recipes/ruby/all/conandata.yml
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,18 @@
patches:
"3.1.0":
- patch_file: "patches/0001-darwin-includedir.patch"
base_path: "source_subfolder"
patch_description: "Remove SDKROOT on macOS"
patch_type: "portability"
- patch_file: "patches/0002-remove-fpic.patch"
base_path: "source_subfolder"
- patch_file: "patches/0003-openssl-ext.patch"
base_path: "source_subfolder"
patch_description: "Remove hardcoded fPIC"
patch_type: "portability"
- patch_file: "patches/0003-openssl-zlib-ext.patch"
patch_description: "Handle naming of zlib and openssl"
patch_type: "conan"
- patch_file: "patches/0004-windows-cflags.patch"
base_path: "source_subfolder"
patch_description: "Define cflags properly on windows"
patch_type: "portability"
- patch_file: "patches/0005-backport-add-with-gmp-dir-3.1.0.patch"
patch_description: "backport add --with-gmp-dir which was added only in 3.2.0"
patch_type: "backport"

Check warning on line 21 in recipes/ruby/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. found arbitrary text in patch_type: backport ^ (line: 21)
patch_source: "https://github.com/ruby/ruby/commit/f512df73986c74e2f4bd65ca642879a0618da213"
277 changes: 180 additions & 97 deletions recipes/ruby/all/conanfile.py
Original file line number Diff line number Diff line change
@@ -1,22 +1,18 @@
import glob
import os
import re

from conan import ConanFile
from conan.tools.apple.apple import is_apple_os, to_apple_arch
from conan.errors import ConanInvalidConfiguration
from conan.tools.apple import is_apple_os, fix_apple_shared_install_name, to_apple_arch
from conan.tools.build import cross_building
from conan.tools.env import VirtualBuildEnv
from conan.tools.files import apply_conandata_patches, collect_libs, copy, export_conandata_patches, get, replace_in_file, rm, rmdir
from conan.tools.gnu import Autotools, PkgConfigDeps, AutotoolsToolchain
from conan.tools.layout import basic_layout
from conan.tools.microsoft import check_min_vs, is_msvc, is_msvc_static_runtime, msvc_runtime_flag, unix_path, VCVars
from conan.tools.scm import Version

try:
from conan.tools.cross_building import cross_building
except ImportError:
from conan.tools.build.cross_building import cross_building

from conan.tools.files import apply_conandata_patches
from conan.tools.gnu import Autotools, AutotoolsDeps, AutotoolsToolchain
from conan.tools.microsoft import msvc_runtime_flag, is_msvc
from conans import tools
from conans.errors import ConanInvalidConfiguration
import glob
import os

required_conan_version = ">=1.43.0"
required_conan_version = ">=1.53"


class RubyConan(ConanFile):
Expand All @@ -27,22 +23,32 @@ class RubyConan(ConanFile):
homepage = "https://www.ruby-lang.org"
url = "https://github.com/conan-io/conan-center-index"
settings = "os", "arch", "compiler", "build_type"
exports_sources = "patches/**"
options = {
"shared": [True, False],
"fPIC": [True, False],
"with_openssl": [True, False]
"with_openssl": [True, False],

"with_static_linked_ext": [True, False],
"with_enable_load_relative": [True, False],
"with_libyaml": [True, False],
"with_libffi": [True, False],
"with_readline": [True, False],
"with_gmp": [True, False],
}
default_options = {
"shared": False,
"fPIC": True,
"with_openssl": True
"with_openssl": True,

"with_static_linked_ext": True,
"with_enable_load_relative": True,
"with_libyaml": True,
"with_libffi": True,
"with_readline": True,
"with_gmp": True,
}
short_paths = True

@property
def _source_subfolder(self):
return "source_subfolder"
short_paths = True

@property
def _settings_build(self):
Expand All @@ -54,51 +60,79 @@ def _windows_system_libs(self):

@property
def _msvc_optflag(self):
if self.settings.compiler == "Visual Studio" and tools.Version(self.settings.compiler.version) < "14":
return "-O2b2xg-"
else:
if check_min_vs(self, "190", raise_invalid=False):
return "-O2sy-"
else: # MSVC < 14
return "-O2b2xg-"

def requirements(self):
self.requires("zlib/1.2.12")
self.requires("gmp/6.1.2")
if self.options.with_openssl:
self.requires("openssl/1.1.1o")
def export_sources(self):
export_conandata_patches(self)

def build_requirements(self):
if self.settings.os != "Windows":
self.tool_requires("autoconf/2.71")
if not self.conf.get("tools.gnu:pkg_config", check_type=str):
self.tool_requires("pkgconf/2.1.0")

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.options.with_static_linked_ext

self.settings.rm_safe("compiler.libcxx")
self.settings.rm_safe("compiler.cppstd")

if self.settings.os == "Windows":
# readline isn't supported on Windows
del self.options.with_readline

if is_msvc(self):
# conan libffi will not allow linking right now with MSVC
del self.options.with_libffi
# conan LibYAML will not link properly right now with MSVC, so using built-in Psych provided libYAML
del self.options.with_libyaml

def requirements(self):
self.requires("zlib/1.2.12")

if self.options.with_openssl:
self.requires("openssl/1.1.1q")

if self.options.get_safe("with_libyaml"):
self.requires("libyaml/0.2.5")

if self.options.get_safe("with_libffi"):
self.requires("libffi/3.4.2")

if self.options.get_safe("with_readline"):
self.requires("readline/8.1.2")

if self.options.with_gmp:
self.requires("gmp/6.2.1")

def validate(self):
if is_msvc(self) and msvc_runtime_flag(self).startswith('MT'):
if is_msvc(self) and is_msvc_static_runtime(self):
# see https://github.com/conan-io/conan-center-index/pull/8644#issuecomment-1068974098
raise ConanInvalidConfiguration("VS static runtime is not supported")

def configure(self):
if self.options.shared:
del self.options.fPIC
del self.settings.compiler.libcxx
del self.settings.compiler.cppstd
def layout(self):
basic_layout(self, src_folder="src")

def source(self):
tools.get(**self.conan_data["sources"][self.version], destination=self._source_subfolder, strip_root=True)
get(self, **self.conan_data["sources"][self.version], strip_root=True)

def generate(self):
td = AutotoolsDeps(self)
# remove non-existing frameworks dirs, otherwise clang complains
for m in re.finditer("-F (\S+)", td.vars().get("LDFLAGS")):
if not os.path.exists(m[1]):
td.environment.remove("LDFLAGS", f"-F {m[1]}")
if self.settings.os == "Windows":
if is_msvc(self):
td.environment.append("LIBS", [f"{lib}.lib" for lib in self._windows_system_libs])
else:
td.environment.append("LDFLAGS", [f"-l{lib}" for lib in self._windows_system_libs])
td.generate()
venv = VirtualBuildEnv(self)
venv.generate()

deps = PkgConfigDeps(self)
deps.generate()

tc = AutotoolsToolchain(self)
# TODO: removed in conan 1.49
tc.default_configure_install_args = True

tc.configure_args.append("--disable-install-doc")
if self.options.shared and not is_msvc(self):
Expand All @@ -107,8 +141,33 @@ def generate(self):
if "--enable-shared" not in tc.configure_args:
tc.configure_args.append("--enable-shared")

if cross_building(self) and is_apple_os(self.settings.os):
apple_arch = to_apple_arch(self.settings.arch)
if not self.options.shared and self.options.with_static_linked_ext:
tc.configure_args.append("--with-static-linked-ext")

if self.options.with_enable_load_relative:
tc.configure_args.append("--enable-load-relative")

# Ruby doesn't respect the --with-gmp-dir for eg. After removal of libgmp-dev on conanio/gcc10 build failed
opt_dirs = []

# zlib always True
tc.configure_args.append(f'--with-zlib-dir={self.dependencies["zlib"].package_path.as_posix()}')
for dep in ["zlib", "openssl", "libffi", "libyaml", "readline", "gmp"]:
if self.options.get_safe(f"with_{dep}"):
root_path = self.dependencies[dep].package_path.as_posix()
tc.configure_args.append(f"--with-{dep}-dir={root_path}")
opt_dirs.append(root_path)

if opt_dirs:
if self.settings.os == "Windows":
sep = ";"
tc.configure_args.append(f'--with-opt-dir="{sep.join(opt_dirs)}"')
else:
sep = ":"
tc.configure_args.append(f'--with-opt-dir={sep.join(opt_dirs)}')

if cross_building(self) and is_apple_os(self):
apple_arch = to_apple_arch(self)
if apple_arch:
tc.configure_args.append(f"--with-arch={apple_arch}")
if is_msvc(self):
Expand All @@ -120,77 +179,101 @@ def generate(self):
tc.ldflags.append("-debug")
tc.build_type_flags = [f if f != "-O2" else self._msvc_optflag for f in tc.build_type_flags]

tc.configure_args.append("--without-ext=+,dbm,gdbm,readline")
if Version(self.version) < "3.2.0":
tc.configure_args.append("--enable-bundled-libffi")
tc.generate()

def build(self):
if is_msvc(self):
vc = VCVars(self)
vc.generate()

def _patch_sources(self):
apply_conandata_patches(self)
replace_in_file(self, os.path.join(self.source_folder, "gems", "bundled_gems"), "rbs 2.0.0", "rbs 3.1.0")
replace_in_file(self, os.path.join(self.source_folder, "gems", "bundled_gems"), "debug 1.4.0", "debug 1.6.3")

at = Autotools(self)
def build(self):
self._patch_sources()

build_script_folder = self._source_subfolder
autotools = Autotools(self)

build_script_folder = self.source_folder
if is_msvc(self):
self.conf["tools.gnu:make_program"] = "nmake"
# self.conf["tools.gnu:make_program"] = "nmake"
# self.conf_info.define("tools.gnu:make_program", "nmake")
build_script_folder = os.path.join(build_script_folder, "win32")

if "TMP" in os.environ: # workaround for TMP in CCI containing both forward and back slashes
os.environ["TMP"] = os.environ["TMP"].replace("/", "\\")

with tools.vcvars(self):
at.configure(build_script_folder=build_script_folder)
at.make()
autotools.configure(build_script_folder=build_script_folder)
if is_msvc(self):
self.run("nmake incs")
self.run("nmake")
else:
autotools.make()

def package(self):
for file in ["COPYING", "BSDL"]:
self.copy(file, dst="licenses", src=self._source_subfolder)
copy(self, pattern=file, src=self.source_folder, dst=os.path.join(self.package_folder, "licenses"))

at = Autotools(self)
with tools.vcvars(self):
if cross_building(self):
at.make(target="install-local")
at.make(target="install-arch")
else:
at.install()
autotools = Autotools(self)
if is_msvc(self):
self.run(f"nmake install-nodoc DESTDIR={self.package_folder}")
elif cross_building(self):
autotools.make(target="install-local", args=[f"DESTDIR={unix_path(self, self.package_folder)}"])
autotools.make(target="install-arch", args=[f"DESTDIR={unix_path(self, self.package_folder)}"])
else:
autotools.install()

rmdir(self, os.path.join(self.package_folder, "share"))
rmdir(self, os.path.join(self.package_folder, "lib", "pkgconfig"))
rm(self, pattern="*.pdb", folder=os.path.join(self.package_folder, "lib"))
fix_apple_shared_install_name(self)

tools.rmdir(os.path.join(self.package_folder, "share"))
tools.rmdir(os.path.join(self.package_folder, "lib", "pkgconfig"))
tools.remove_files_by_mask(os.path.join(self.package_folder, "lib"), "*.pdb")
# install the enc/*.a / ext/*.a libraries
if not self.options.shared and self.options.with_static_linked_ext:
for dirname in ["ext", "enc"]:
dst = os.path.join("lib", dirname)
copy(self, "*.a", src=dirname, dst=os.path.join(self.package_folder, dst), keep_path=True)
copy(self, "*.lib", src=dirname, dst=os.path.join(self.package_folder, dst), keep_path=True)

def package_info(self):
binpath = os.path.join(self.package_folder, "bin")
self.output.info(f"Adding to PATH: {binpath}")
self.env_info.PATH.append(binpath)
version = Version(self.version)
self.cpp_info.set_property("cmake_find_mode", "both")
self.cpp_info.set_property("cmake_file_name", "Ruby")
self.cpp_info.set_property("cmake_target_name", "Ruby::Ruby")
self.cpp_info.set_property("pkg_config_name", "ruby")
self.cpp_info.set_property("pkg_config_aliases", [f"ruby-{version.major}.{version.minor}"])

version = tools.Version(self.version)
rubylib = self.cpp_info.components["rubylib"]
config_file = glob.glob(os.path.join(self.package_folder, "include", "**", "ruby", "config.h"), recursive=True)[0]
rubylib.includedirs = [
config_file = glob.glob(os.path.join(self.package_folder, "include", "**", "ruby", "config.h"), recursive=True)[
0
]
self.cpp_info.includedirs = [
os.path.join(self.package_folder, "include", f"ruby-{version}"),
os.path.dirname(os.path.dirname(config_file))
os.path.dirname(os.path.dirname(config_file)),
]
rubylib.libs = tools.collect_libs(self)
self.cpp_info.libs = collect_libs(self)
if is_msvc(self):
if self.options.shared:
rubylib.libs = list(filter(lambda l: not l.endswith("-static"), rubylib.libs))
self.cpp_info.libs = list(filter(lambda l: not l.endswith("-static"), self.cpp_info.libs))
else:
rubylib.libs = list(filter(lambda l: l.endswith("-static"), rubylib.libs))
rubylib.requires.extend(["zlib::zlib", "gmp::gmp"])
if self.options.with_openssl:
rubylib.requires.append("openssl::openssl")
self.cpp_info.libs = list(filter(lambda l: l.endswith("-static"), self.cpp_info.libs))

if self.settings.os in ("FreeBSD", "Linux"):
rubylib.system_libs = ["dl", "pthread", "rt", "m", "crypt"]
self.cpp_info.system_libs = ["dl", "pthread", "rt", "m", "crypt", "util"]
elif self.settings.os == "Windows":
rubylib.system_libs = self._windows_system_libs
self.cpp_info.system_libs = self._windows_system_libs
if str(self.settings.compiler) in ("clang", "apple-clang"):
rubylib.cflags = ["-fdeclspec"]
rubylib.cxxflags = ["-fdeclspec"]
if tools.is_apple_os(self.settings.os):
rubylib.frameworks = ["CoreFoundation"]

self.cpp_info.filenames["cmake_find_package"] = "Ruby"
self.cpp_info.filenames["cmake_find_package_multi"] = "Ruby"
self.cpp_info.set_property("cmake_file_name", "Ruby")
self.cpp_info.cflags = ["-fdeclspec"]
self.cpp_info.cxxflags = ["-fdeclspec"]
if is_apple_os(self):
self.cpp_info.frameworks = ["CoreFoundation"]

# TODO: to remove in conan v2
self.cpp_info.names["cmake_find_package"] = "Ruby"
self.cpp_info.names["cmake_find_package_multi"] = "Ruby"
self.cpp_info.set_property("cmake_target_name", "Ruby::Ruby")
self.cpp_info.set_property("pkg_config_aliases", [f"ruby-{version.major}.{version.minor}"])
binpath = os.path.join(self.package_folder, "bin")
self.env_info.PATH.append(binpath)
self.runenv_info.prepend_path("PATH", os.path.join(self.package_folder, "bin"))
Loading
Loading