From ed1da717c7f43a280bf5a87308aee38ac90df950 Mon Sep 17 00:00:00 2001 From: nmburgan <13688219+nmburgan@users.noreply.github.com> Date: Wed, 17 Sep 2025 09:21:18 -0700 Subject: [PATCH 1/7] Use cross-compilation for macos-all-x86_64 Using Rosetta to build the x86_64 agent on arm64 didn't quite work out. Instead, this does real cross-compilation on an arm64 host. --- configs/components/_base-rubygem.rb | 9 ++++++ configs/components/augeas.rb | 6 +--- configs/components/pl-ruby-patch.rb | 6 +--- configs/components/ruby-3.2.rb | 17 +++++----- configs/components/runtime-agent.rb | 2 +- configs/platforms/macos-all-x86_64.rb | 4 ++- configs/projects/_shared-agent-settings.rb | 21 ++++++++---- resources/files/ruby/patch-hostruby.rb | 4 +++ .../patches/ruby_32/target_rbconfig.patch | 32 +++++++++++++++++++ tasks/build.rake | 6 ---- 10 files changed, 73 insertions(+), 34 deletions(-) create mode 100644 resources/patches/ruby_32/target_rbconfig.patch diff --git a/configs/components/_base-rubygem.rb b/configs/components/_base-rubygem.rb index bf1c3133..f9c773a4 100644 --- a/configs/components/_base-rubygem.rb +++ b/configs/components/_base-rubygem.rb @@ -21,6 +21,15 @@ pkg.environment "PATH", "$(shell cygpath -u #{settings[:gcc_bindir]}):$(shell cygpath -u #{settings[:ruby_bindir]}):$(shell cygpath -u #{settings[:bindir]}):/cygdrive/c/Windows/system32:/cygdrive/c/Windows:/cygdrive/c/Windows/System32/WindowsPowerShell/v1.0:$(PATH)" end +if platform.is_macos? + pkg.environment 'CC', settings[:cc] + pkg.environment 'CXX', settings[:cxx] + pkg.environment 'LDFLAGS', settings[:ldflags] + pkg.environment 'CPPFLAGS', settings[:cppflags] + pkg.environment 'CFLAGS', settings[:cflags] + pkg.environment 'MACOSX_DEPLOYMENT_TARGET', settings[:deployment_target] +end + # When cross-compiling, we can't use the rubygems we just built. # Instead we use the host gem installation and override GEM_HOME. Yay? pkg.environment "GEM_HOME", settings[:gem_home] diff --git a/configs/components/augeas.rb b/configs/components/augeas.rb index 9300f7ba..975a00e6 100644 --- a/configs/components/augeas.rb +++ b/configs/components/augeas.rb @@ -128,11 +128,7 @@ # fix libtool linking on big sur if platform.is_macos? - if platform.architecture == 'arm64' - pkg.configure { ["/opt/homebrew/bin/autoreconf --force --install"] } - else - pkg.configure { ["/usr/local/bin/autoreconf --force --install"] } - end + pkg.configure { ["/opt/homebrew/bin/autoreconf --force --install"] } end diff --git a/configs/components/pl-ruby-patch.rb b/configs/components/pl-ruby-patch.rb index 87610181..fb97352c 100644 --- a/configs/components/pl-ruby-patch.rb +++ b/configs/components/pl-ruby-patch.rb @@ -23,11 +23,7 @@ elsif platform.name =~ /solaris-10/ "sparc-solaris" elsif platform.is_macos? - if ruby_version_y.start_with?('2') - "aarch64-darwin" - else - "arm64-darwin" - end + "x86_64-darwin" else "#{platform.architecture}-linux" end diff --git a/configs/components/ruby-3.2.rb b/configs/components/ruby-3.2.rb index 16dec74e..fb5184e3 100644 --- a/configs/components/ruby-3.2.rb +++ b/configs/components/ruby-3.2.rb @@ -27,6 +27,7 @@ if platform.is_cross_compiled? pkg.apply_patch "#{base}/rbinstall_gem_path.patch" + pkg.apply_patch "#{base}/target_rbconfig.patch" end if platform.is_aix? @@ -62,6 +63,7 @@ pkg.environment 'CXX', settings[:cxx] pkg.environment 'MACOSX_DEPLOYMENT_TARGET', settings[:deployment_target] pkg.environment 'PATH', '$(PATH):/opt/homebrew/bin:/usr/local/bin' + pkg.environment 'CROSS_COMPILING', 'true' if platform.is_cross_compiled? elsif platform.is_windows? optflags = cflags + ' -O3' pkg.environment 'optflags', optflags @@ -118,11 +120,6 @@ # This normalizes the build string to something like AIX 7.1.0.0 rather # than AIX 7.1.0.2 or something special_flags += " --build=#{settings[:platform_triple]} " - elsif platform.is_cross_compiled? && platform.is_macos? - # When the target arch is aarch64, ruby incorrectly selects the 'ucontext' coroutine - # implementation instead of 'arm64', so specify 'amd64' explicitly - # https://github.com/ruby/ruby/blob/c9c2245c0a25176072e02db9254f0e0c84c805cd/configure.ac#L2329-L2330 - special_flags += " --with-coroutine=arm64 " elsif platform.is_solaris? && platform.architecture == "sparc" unless platform.is_cross_compiled? # configure seems to enable dtrace because the executable is present, @@ -230,6 +227,7 @@ 'powerpc-ibm-aix7.1.0.0' => 'powerpc-aix7.1.0.0', 'powerpc-ibm-aix7.2.0.0' => 'powerpc-aix7.2.0.0', 'aarch64-redhat-linux' => 'aarch64-linux', + 'x86_64-apple-darwin' => 'x86_64-darwin', 'ppc64-redhat-linux' => 'powerpc64-linux', 'ppc64le-redhat-linux' => 'powerpc64le-linux', 'powerpc64le-suse-linux' => 'powerpc64le-linux', @@ -258,6 +256,9 @@ rbconfig_changes = {} if platform.is_aix? rbconfig_changes["CC"] = "gcc" + elsif platform.is_macos? && platform.is_cross_compiled? + rbconfig_changes["CC"] = settings[:cc] + rbconfig_changes["CXX"] = settings[:cxx] elsif platform.is_cross_compiled? || (platform.is_solaris? && platform.architecture != 'sparc') # REMIND: why are we overriding rbconfig for solaris intel? rbconfig_changes["CC"] = 'gcc' @@ -271,8 +272,6 @@ # the ancient gcc version on sles-12-ppc64le does not understand -fstack-protector-strong, so remove the `strong` part rbconfig_changes["LDFLAGS"] = "-L. -Wl,-rpath=/opt/puppetlabs/puppet/lib -fstack-protector -rdynamic -Wl,-export-dynamic -L/opt/puppetlabs/puppet/lib" end - elsif platform.is_macos? - rbconfig_changes["CC"] = "#{settings[:cc]} #{cflags}" elsif platform.is_windows? if platform.architecture == "x64" rbconfig_changes["CC"] = "x86_64-w64-mingw32-gcc" @@ -302,8 +301,8 @@ pkg.install do [ "#{host_ruby} ../rbconfig-update.rb \"#{rbconfig_changes.to_s.gsub('"', '\"')}\" #{rbconfig_topdir}", - "cp original_rbconfig.rb #{settings[:datadir]}/doc/rbconfig-#{pkg.get_version}-orig.rb", - "cp new_rbconfig.rb #{rbconfig_topdir}/rbconfig.rb", + "cp original_rbconfig.rb #{settings[:datadir]}/doc/rbconfig-3.2-orig.rb", + "sudo cp new_rbconfig.rb #{rbconfig_topdir}/rbconfig.rb", ] end end diff --git a/configs/components/runtime-agent.rb b/configs/components/runtime-agent.rb index 5b08aa5e..cb7ac5e1 100644 --- a/configs/components/runtime-agent.rb +++ b/configs/components/runtime-agent.rb @@ -18,7 +18,7 @@ pkg.install do # These are dependencies of ruby@3.x, remove symlinks from /usr/local # so our build doesn't use the wrong headers - "cd /etc/homebrew && su test -c '#{platform.brew} unlink openssl libyaml'" + "#{platform.brew} unlink openssl libyaml" end end end diff --git a/configs/platforms/macos-all-x86_64.rb b/configs/platforms/macos-all-x86_64.rb index f6994a73..1caa7d53 100644 --- a/configs/platforms/macos-all-x86_64.rb +++ b/configs/platforms/macos-all-x86_64.rb @@ -1,7 +1,9 @@ platform 'macos-all-x86_64' do |plat| plat.inherit_from_default - packages = %w[cmake pkg-config] + plat.brew '/opt/homebrew/bin/brew' + plat.cross_compiled true + packages = %w[cmake pkg-config bison] plat.provision_with "brew install #{packages.join(' ')}" plat.output_dir File.join('macos', 'all', 'x86_64') diff --git a/configs/projects/_shared-agent-settings.rb b/configs/projects/_shared-agent-settings.rb index a242f619..f23cc0a6 100644 --- a/configs/projects/_shared-agent-settings.rb +++ b/configs/projects/_shared-agent-settings.rb @@ -95,7 +95,7 @@ platform_triple = "powerpc64le-suse-linux" if platform.architecture == "ppc64le" && platform.name =~ /^sles-/ platform_triple = "powerpc64le-linux-gnu" if platform.architecture == "ppc64el" platform_triple = "arm-linux-gnueabihf" if platform.architecture == "armhf" -platform_triple = "aarch64-apple-darwin" if platform.is_cross_compiled? && platform.is_macos? +platform_triple = "x86_64-apple-darwin" if platform.is_cross_compiled? && platform.is_macos? # Ruby's build process needs a functional "baseruby". When native compiling, # ruby will build "miniruby" and use that as "baseruby". When cross compiling, @@ -114,8 +114,15 @@ proj.setting(:host_gem, "/opt/pl-build-tools/bin/gem") end elsif platform.is_cross_compiled? && platform.is_macos? - proj.setting(:host_ruby, "/usr/local/opt/ruby@#{ruby_version_y}/bin/ruby") - proj.setting(:host_gem, "/usr/local/opt/ruby@#{ruby_version_y}/bin/gem") + # Running in CI, we use the Ruby set up by the ruby/setup-ruby action and save + # the prefix to an env var. When running locally, we use a Homebrew-installed Ruby. + if ENV['HOST_RUBY_PREFIX'] + proj.setting(:host_ruby, File.join(ENV['HOST_RUBY_PREFIX'], "bin", "ruby")) + proj.setting(:host_gem, File.join(ENV['HOST_RUBY_PREFIX'], "bin", "gem")) + else + proj.setting(:host_ruby, "/opt/homebrew/opt/ruby@#{ruby_version_y}/bin/ruby") + proj.setting(:host_gem, "/opt/homebrew/opt/ruby@#{ruby_version_y}/bin/gem") + end else proj.setting(:host_ruby, File.join(proj.ruby_bindir, "ruby")) proj.setting(:host_gem, File.join(proj.ruby_bindir, "gem")) @@ -124,7 +131,7 @@ if platform.is_cross_compiled_linux? host = "--host #{platform_triple}" elsif platform.is_cross_compiled? && platform.is_macos? - host = "--host aarch64-apple-darwin --build x86_64-apple-darwin --target aarch64-apple-darwin" + host = "--host x86_64-apple-darwin --build aarch64-apple-darwin --target x86_64-apple-darwin" elsif platform.is_solaris? if platform.architecture == 'i386' platform_triple = "#{platform.architecture}-pc-solaris2.#{platform.os_version}" @@ -191,11 +198,11 @@ # that works for all MacOS versions since then, rather than building # separate ones for each version. proj.setting(:deployment_target, '13.0') - targeting_flags = "-target #{platform.architecture}-apple-darwin22 -arch #{platform.architecture} -mmacos-version-min=13.0" + targeting_flags = "-arch #{platform.architecture} -mmacos-version-min=13.0" proj.setting(:cflags, "#{targeting_flags} #{proj.cflags}") proj.setting(:cppflags, "#{targeting_flags} #{proj.cppflags}") - proj.setting(:cc, 'clang') - proj.setting(:cxx, 'clang++') + proj.setting(:cc, "clang -target #{platform.architecture}-apple-darwin") + proj.setting(:cxx, "clang++ -target #{platform.architecture}-apple-darwin") proj.setting(:ldflags, "-L#{proj.libdir}") end diff --git a/resources/files/ruby/patch-hostruby.rb b/resources/files/ruby/patch-hostruby.rb index 0e09dd68..481fc054 100644 --- a/resources/files/ruby/patch-hostruby.rb +++ b/resources/files/ruby/patch-hostruby.rb @@ -99,6 +99,10 @@ def rewrite(file) regexp = /Shellwords\.split\(Gem\.ruby\)/ replace = "\\& << '-r/opt/puppetlabs/puppet/share/doc/rbconfig-#{target_ruby_version}-orig.rb'" builder = 'rubygems/ext/builder.rb' +elsif GEM_VERSION <= Gem::Version.new('3.8') + regexp = /shellsplit\(Gem\.ruby\)/ + replace = "\\& << '-r/opt/puppetlabs/puppet/share/doc/rbconfig-#{target_ruby_version}-orig.rb'" + builder = 'rubygems/ext/builder.rb' else raise "We don't know how to patch rubygems #{GEM_VERSION}" end diff --git a/resources/patches/ruby_32/target_rbconfig.patch b/resources/patches/ruby_32/target_rbconfig.patch new file mode 100644 index 00000000..34977319 --- /dev/null +++ b/resources/patches/ruby_32/target_rbconfig.patch @@ -0,0 +1,32 @@ +From 7cbe54714ca1b9112e278d2d605cd049a065707e Mon Sep 17 00:00:00 2001 +From: Yuta Saito +Date: Tue, 18 Jun 2024 10:19:52 +0900 +Subject: [PATCH] extmk.rb: define Gem.target_rbconfig not to break + `Gem::Platform.local` + +--- + ext/extmk.rb | 8 +++++++- + 1 file changed, 7 insertions(+), 1 deletion(-) + +diff --git a/ext/extmk.rb b/ext/extmk.rb +index 2f76e174d5..8b6b365a99 100755 +--- a/ext/extmk.rb ++++ b/ext/extmk.rb +@@ -2,7 +2,13 @@ + # -*- mode: ruby; coding: us-ascii -*- + # frozen_string_literal: false + +-module Gem; end # only needs Gem::Platform ++module Gem ++ # Used by Gem::Platform.local ++ def self.target_rbconfig ++ RbConfig::CONFIG ++ end ++end ++# only needs Gem::Platform + require 'rubygems/platform' + + # :stopdoc: +-- +2.51.0 + diff --git a/tasks/build.rake b/tasks/build.rake index 813db3ff..6cb0864c 100644 --- a/tasks/build.rake +++ b/tasks/build.rake @@ -11,12 +11,6 @@ namespace :vox do abort 'You must provide a platform.' if args[:platform].nil? || args[:platform].empty? platform = args[:platform] os, _ver, arch = platform.match(/^(\w+)-([\w|\.]+)-(\w+)$/).captures - if os == 'macos' - shell = `uname -m`.chomp - ruby = `ruby -v`.chomp - abort "Detected shell arch: #{shell}. You must run this build from a #{arch} machine or shell. To do this on the current host, run 'arch -#{arch} /bin/bash'" if shell != arch - abort "Detected ruby: #{ruby}. You must run this build with a #{arch} Ruby version. To do this on the current host, install Ruby from an #{arch} shell via 'arch -#{arch} /bin/bash'." unless ruby =~ /#{arch}/ - end engine = platform =~ /^(macos|windows)-/ ? 'local' : 'docker' cmd = "bundle exec build #{project} #{platform} --engine #{engine}" From 186ebfa02fb99db63e4fdc70520265b0e710de53 Mon Sep 17 00:00:00 2001 From: nmburgan <13688219+nmburgan@users.noreply.github.com> Date: Sun, 21 Sep 2025 12:15:05 -0700 Subject: [PATCH 2/7] Cleanup rubygem-ffi The amount of branching logic here was getting out of control, so this cleans it up to make it much easier to follow (hopefully). --- configs/components/rubygem-ffi.rb | 171 +++++++++--------------------- 1 file changed, 51 insertions(+), 120 deletions(-) diff --git a/configs/components/rubygem-ffi.rb b/configs/components/rubygem-ffi.rb index be14b024..650bfb45 100644 --- a/configs/components/rubygem-ffi.rb +++ b/configs/components/rubygem-ffi.rb @@ -6,66 +6,18 @@ # Read the comments in the code below carefully. ##### component "rubygem-ffi" do |pkg, settings, platform| - if platform.is_cross_compiled? && (platform.is_linux? || platform.is_solaris?) - # Installing ffi >= 1.14.0 blows up horribly if we're cross compiling on Linux and Solaris. - # This is because we're using old rubies (2.1 and 2.0) to install gems which do not have - # methods like `append_ldflags`. - # (see https://github.com/ffi/ffi/commit/3aa6b25f5423a64ad4afa7f2a5a5855483bae3c2) - # - # A more long term solution would be to update the host rubies on those - # platforms to something newer (preferably the same API version as the ruby - # we're building for). We can probably avoid this until we start shipping Ruby 3. - pkg.version '1.13.1' - pkg.sha256sum '4e15f52ee45af7c5674d656041855448adbb5022618be252cd602d81b8e2978a' - else - pkg.version '1.17.2' - pkg.sha256sum '297235842e5947cc3036ebe64077584bff583cd7a4e94e9a02fdec399ef46da6' - end + pkg.version '1.17.2' + pkg.sha256sum '297235842e5947cc3036ebe64077584bff583cd7a4e94e9a02fdec399ef46da6' rb_major_minor_version = settings[:ruby_version].to_f - # Windows versions of the FFI gem have custom filenames, so we overwite the - # defaults that _base-rubygem provides here, just for Windows for Ruby < 3.2 if platform.is_windows? && rb_major_minor_version < 3.2 - # Pin this if lower than Ruby 2.7 - pkg.version '1.9.25' if rb_major_minor_version < 2.7 + pkg.sha256sum 'c67b84b1bd54b680bcc23b516e87c96b4585cad3ca9e0afea953c9a9cb90243d' + pkg.url "https://rubygems.org/downloads/ffi-#{pkg.get_version}-x64-mingw32.gem" instance_eval File.read('configs/components/_base-rubygem.rb') - - # Vanagon's `pkg.mirror` is additive, and the _base_rubygem sets the - # non-Windows gem as the first mirror, which is incorrect. We need to unset - # the list of mirrors before adding the Windows-appropriate ones here: - @component.mirrors = [] - # Same for install steps: @component.install = [] - - if platform.architecture == "x64" - # NOTE: make sure to verify the shas for the x64-mingw32 gem! - case pkg.get_version - when '1.9.25' - pkg.sha256sum '5473ac958b78f271f53e9a88197c35cd3e990fbe625d21e525c56d62ae3750da' - when '1.17.2' - pkg.sha256sum 'c67b84b1bd54b680bcc23b516e87c96b4585cad3ca9e0afea953c9a9cb90243d' - end - - pkg.url "https://rubygems.org/downloads/ffi-#{pkg.get_version}-x64-mingw32.gem" - pkg.mirror "#{settings[:buildsources_url]}/ffi-#{pkg.get_version}-x64-mingw32.gem" - else - # Note make sure to verify the shas from the x86-mingw32 gem! - case pkg.get_version - when '1.9.25' - pkg.sha256sum '43d357732a6a0e3e41dc7e28a9c9c5112ac66f4a6ed9e1de40afba9ffcb836c1' - when '1.17.2' - pkg.sha256sum '5052e800045e95acdcd2c404777d5296751e66553c12ff4bf20f29ddcc9e4139' - end - - pkg.url "https://rubygems.org/downloads/ffi-#{pkg.get_version}-x86-mingw32.gem" - pkg.mirror "#{settings[:buildsources_url]}/ffi-#{pkg.get_version}-x86-mingw32.gem" - end - - pkg.install do - "#{settings[:gem_install]} ffi-#{pkg.get_version}-#{platform.architecture}-mingw32.gem" - end + pkg.install { "#{settings[:gem_install]} ffi-#{pkg.get_version}-x64-mingw32.gem" } else # Prior to ruby 3.2, both ruby and the ffi gem vendored a version of libffi. # If libffi happened to be installed in /usr/lib, then the ffi gem preferred @@ -88,78 +40,57 @@ instance_eval File.read('configs/components/_base-rubygem.rb') end - # due to contrib/make_sunver.pl missing on solaris 11 we cannot compile libffi, so we provide the opencsw library - pkg.environment "CPATH", "/opt/csw/lib/libffi-3.2.1/include" if platform.name =~ /solaris-11/ && (platform.is_cross_compiled? || platform.architecture != 'sparc') - pkg.environment "MAKE", platform[:make] if platform.is_solaris? - - if platform.is_cross_compiled_linux? - pkg.environment "PATH", "/opt/pl-build-tools/bin:$(PATH)" - elsif platform.is_solaris? - if settings[:ruby_version] =~ /3\.\d+\.\d+/ - if !platform.is_cross_compiled? && platform.architecture == 'sparc' - pkg.environment "PATH", "#{settings[:ruby_bindir]}:$(PATH)" - else - pkg.environment "PATH", "/opt/csw/bin:/opt/pl-build-tools/bin:$(PATH)" - end - else - pkg.environment "PATH", "/opt/pl-build-tools/bin:/opt/csw/bin:$(PATH)" - end - elsif platform.is_aix? - pkg.environment 'PATH', '/opt/freeware/bin:/opt/pl-build-tools/bin:$(PATH)' - elsif platform.name == 'sles-11-x86_64' - pkg.environment 'PATH', '/opt/pl-build-tools/bin:$(PATH)' - end - - # With Ruby 3.2 on Solaris-11 we install OpenSCW's libffi, no need to copy over the system libffi - if platform.name =~ /solaris-11-i386/ && rb_major_minor_version < 3.2 - pkg.install_file "/usr/lib/libffi.so.5.0.10", "#{settings[:libdir]}/libffi.so" - elsif platform.name =~ /solaris-10-i386/ - # If we ever support Solaris-11 on Ruby 3.2, then we won't want to do this - pkg.install_file "/opt/csw/lib/libffi.so.6", "#{settings[:libdir]}/libffi.so.6" - end - - pkg.environment 'PKG_CONFIG_PATH', '/opt/puppetlabs/puppet/lib/pkgconfig:$(PKG_CONFIG_PATH)' - - if platform.is_cross_compiled? && !platform.is_macos? - base_ruby = case platform.name - when /solaris-10/ - "/opt/csw/lib/ruby/2.0.0" - else - "/opt/pl-build-tools/lib/ruby/2.1.0" - end + if platform.is_solaris? + ver, arch = platform.match(/^\w+-(\d+)-(\w+)$/).captures + cross = platform.is_cross_compiled? - # force compilation without system libffi in order to have a statically linked ffi_c.so - if platform.name =~ /solaris-11-sparc/ - sed_exp = 's|CONFIG\["LDFLAGS"\].*|CONFIG["LDFLAGS"] = "-Wl,-rpath-link,/opt/pl-build-tools/sparc-sun-solaris2.11/sysroot/lib:/opt/pl-build-tools/sparc-sun-solaris2.11/sysroot/usr/lib -L. -Wl,-rpath=/opt/puppetlabs/puppet/lib -fstack-protector"|' + pkg.environment "MAKE", platform[:make] + pkg.environment "PATH", "/opt/pl-build-tools/bin:/opt/csw/bin:$(PATH)" - pkg.configure do - [ - # libtool always uses the system/solaris ld even if we - # configure it to use the GNU ld, causing some flag - # mismatches, so just temporarily move the system ld - # somewhere else - %(mv /usr/bin/ld /usr/bin/ld1), - %(#{platform[:sed]} -i '#{sed_exp}' /opt/puppetlabs/puppet/share/doc/rbconfig-#{settings[:ruby_version]}-orig.rb) - ] - end - - # move ld back after the gem is installed - pkg.install { "mv /usr/bin/ld1 /usr/bin/ld" } - - elsif platform.name =~ /solaris-10-sparc/ - sed_exp = 's|CONFIG\["LDFLAGS"\].*|CONFIG["LDFLAGS"] = "-Wl,-rpath-link,/opt/pl-build-tools/sparc-sun-solaris2.10/sysroot/lib:/opt/pl-build-tools/sparc-sun-solaris2.10/sysroot/usr/lib -L. -Wl,-rpath=/opt/puppetlabs/puppet/lib -fstack-protector"|' - pkg.configure do - [ - %(#{platform[:sed]} -i '#{sed_exp}' /opt/puppetlabs/puppet/share/doc/rbconfig-#{settings[:ruby_version]}-orig.rb) - ] + if rb_major_minor_version >= 3.0 + pkg.environment "PATH", "/opt/csw/bin:/opt/pl-build-tools/bin:$(PATH)" + pkg.environment "PATH", "#{settings[:ruby_bindir]}:$(PATH)" if !cross && arch == 'sparc' + end + + if ver == '11' + # due to contrib/make_sunver.pl missing on solaris 11 we cannot compile libffi, so we provide the opencsw library + pkg.environment "CPATH", "/opt/csw/lib/libffi-3.2.1/include" if cross || arch != 'sparc' + # With Ruby 3.2 on Solaris-11 we install OpenSCW's libffi, no need to copy over the system libffi + pkg.install_file "/usr/lib/libffi.so.5.0.10", "#{settings[:libdir]}/libffi.so" if arch == 'i386' && rb_major_minor_version < 3.2 + base_ruby = '/opt/pl-build-tools/lib/ruby/2.1.0' if cross + if arch == 'sparc' + sed_exp = 's|CONFIG\["LDFLAGS"\].*|CONFIG["LDFLAGS"] = "-Wl,-rpath-link,/opt/pl-build-tools/sparc-sun-solaris2.11/sysroot/lib:/opt/pl-build-tools/sparc-sun-solaris2.11/sysroot/usr/lib -L. -Wl,-rpath=/opt/puppetlabs/puppet/lib -fstack-protector"|' + pkg.configure do + [ + # libtool always uses the system/solaris ld even if we + # configure it to use the GNU ld, causing some flag + # mismatches, so just temporarily move the system ld + # somewhere else + %(mv /usr/bin/ld /usr/bin/ld1), + %(#{platform[:sed]} -i '#{sed_exp}' /opt/puppetlabs/puppet/share/doc/rbconfig-#{settings[:ruby_version]}-orig.rb) + ] + end + # move ld back after the gem is installed + pkg.install { "mv /usr/bin/ld1 /usr/bin/ld" } end end - # FFI 1.13.1 forced the minimum required ruby version to ~> 2.3 - # In order to be able to install the gem using pl-ruby(2.1.9) - # we need to remove the required ruby version check - pkg.configure do - %(#{platform[:sed]} -i '0,/ensure_required_ruby_version_met/b; /ensure_required_ruby_version_met/d' #{base_ruby}/rubygems/installer.rb) + if ver == '10' + pkg.install_file "/opt/csw/lib/libffi.so.6", "#{settings[:libdir]}/libffi.so.6" if arch == 'i386' && rb_major_minor_version < 3.2 + base_ruby = '/opt/csw/lib/ruby/2.0.0' if cross + if arch == 'sparc' + sed_exp = 's|CONFIG\["LDFLAGS"\].*|CONFIG["LDFLAGS"] = "-Wl,-rpath-link,/opt/pl-build-tools/sparc-sun-solaris2.10/sysroot/lib:/opt/pl-build-tools/sparc-sun-solaris2.10/sysroot/usr/lib -L. -Wl,-rpath=/opt/puppetlabs/puppet/lib -fstack-protector"|' + pkg.configure do + [ + %(#{platform[:sed]} -i '#{sed_exp}' /opt/puppetlabs/puppet/share/doc/rbconfig-#{settings[:ruby_version]}-orig.rb) + ] + end + end end end + + pkg.environment 'PATH', '/opt/freeware/bin:/opt/pl-build-tools/bin:$(PATH)' if platform.is_aix? + pkg.environment "PATH", "/opt/pl-build-tools/bin:$(PATH)" if platform.is_cross_compiled_linux? + + pkg.environment 'PKG_CONFIG_PATH', '/opt/puppetlabs/puppet/lib/pkgconfig:$(PKG_CONFIG_PATH)' end From aae142b457bba9cb1a7723959fa5a5afc4c4cde7 Mon Sep 17 00:00:00 2001 From: nmburgan <13688219+nmburgan@users.noreply.github.com> Date: Sun, 21 Sep 2025 12:37:04 -0700 Subject: [PATCH 3/7] [CVE] remove nokogiri and dependencies Originally submitted by @binford2k Nokogiri was used to bump performance on MacOS clients when parsing plist files. Without it, CFPropertyList will fall back to rexml. However, performance testing indicates that the boost is negligible. This just removes it and reduces our security exposure. This also remove the libxslt library from the agent runtime, but doesn't actually delete the component yet because Bolt uses it. --- configs/components/rubygem-mini_portile2.rb | 13 --------- configs/components/rubygem-nokogiri.rb | 30 -------------------- configs/projects/_shared-agent-components.rb | 1 - configs/projects/agent-runtime-main.rb | 6 ---- 4 files changed, 50 deletions(-) delete mode 100644 configs/components/rubygem-mini_portile2.rb delete mode 100644 configs/components/rubygem-nokogiri.rb diff --git a/configs/components/rubygem-mini_portile2.rb b/configs/components/rubygem-mini_portile2.rb deleted file mode 100644 index f3c4d65a..00000000 --- a/configs/components/rubygem-mini_portile2.rb +++ /dev/null @@ -1,13 +0,0 @@ -##### -# Component release information: -# https://rubygems.org/gems/mini_portile2 -# https://github.com/flavorjones/mini_portile/blob/main/CHANGELOG.md -##### -component 'rubygem-mini_portile2' do |pkg, _settings, _platform| - pkg.version '2.8.9' - pkg.sha256sum '0cd7c7f824e010c072e33f68bc02d85a00aeb6fce05bb4819c03dfd3c140c289' - - instance_eval File.read('configs/components/_base-rubygem.rb') - - pkg.environment 'GEM_HOME', settings[:gem_home] -end diff --git a/configs/components/rubygem-nokogiri.rb b/configs/components/rubygem-nokogiri.rb deleted file mode 100644 index 50d2f97e..00000000 --- a/configs/components/rubygem-nokogiri.rb +++ /dev/null @@ -1,30 +0,0 @@ -##### -# Component release information: -# https://rubygems.org/gems/nokogiri -# https://nokogiri.org/CHANGELOG.html -##### -component 'rubygem-nokogiri' do |pkg, settings, _platform| - pkg.version '1.18.9' - pkg.sha256sum 'ac5a7d93fd0e3cef388800b037407890882413feccca79eb0272a2715a82fa33' - - cflags = platform.is_macos? ? settings[:cflags] + '--with-cflags="-Wno-incompatible-function-pointer-types"' : '' - settings["#{pkg.get_name}_gem_install_options".to_sym] = "--platform=ruby -- \ - --use-system-libraries \ - --with-xml2-lib=#{settings[:libdir]} \ - --with-xml2-include=#{settings[:includedir]}/libxml2 \ - --with-xslt-lib=#{settings[:libdir]} \ - --with-xslt-include=#{settings[:includedir]} \ - #{cflags}" - instance_eval File.read('configs/components/_base-rubygem.rb') - pkg.build_requires 'rubygem-mini_portile2' - gem_home = settings[:gem_home] - pkg.environment "GEM_HOME", gem_home - if platform.is_macos? - pkg.environment "PKG_CONFIG_PATH", "#{settings[:libdir]}/pkgconfig" - if platform.is_cross_compiled? - pkg.install do - "rm -r #{gem_home}/gems/nokogiri-#{pkg.get_version}/ext/nokogiri/tmp" - end - end - end -end diff --git a/configs/projects/_shared-agent-components.rb b/configs/projects/_shared-agent-components.rb index ed0ce1ef..b047badd 100644 --- a/configs/projects/_shared-agent-components.rb +++ b/configs/projects/_shared-agent-components.rb @@ -36,7 +36,6 @@ proj.component "readline" if platform.is_macos? proj.component 'augeas' unless platform.is_windows? proj.component 'libxml2' unless platform.is_windows? -proj.component 'libxslt' unless platform.is_windows? proj.component 'ruby-augeas' unless platform.is_windows? proj.component 'ruby-shadow' unless platform.is_aix? || platform.is_windows? diff --git a/configs/projects/agent-runtime-main.rb b/configs/projects/agent-runtime-main.rb index af2210e3..385dc43f 100644 --- a/configs/projects/agent-runtime-main.rb +++ b/configs/projects/agent-runtime-main.rb @@ -67,12 +67,6 @@ proj.component 'rubygem-sys-filesystem' end - # Nokogiri and dependencies to improve macOS performance (PUP-11332) - if platform.is_macos? - proj.component 'rubygem-nokogiri' - proj.component 'rubygem-mini_portile2' - end - # Dependencies for gettext for Ruby >= 3.2 (PA-4815) proj.component 'rubygem-erubi' proj.component 'rubygem-prime' From 3f4dbd3c1fd309a5d0b0fb1a17a3e555fdbb63d7 Mon Sep 17 00:00:00 2001 From: nmburgan <13688219+nmburgan@users.noreply.github.com> Date: Mon, 22 Sep 2025 18:14:00 -0700 Subject: [PATCH 4/7] Add correct runtime dependencies for gems used in the agent We should do this with all of the gems to ensure the 'gem install' during build time does things in the correct order, but this covers the agent gems. --- configs/components/rubygem-CFPropertyList.rb | 4 ++++ configs/components/rubygem-fast_gettext.rb | 3 +++ configs/components/rubygem-gettext.rb | 6 ++++++ configs/components/rubygem-highline.rb | 2 ++ configs/components/rubygem-prime.rb | 2 ++ configs/components/rubygem-sys-filesystem.rb | 2 ++ 6 files changed, 19 insertions(+) diff --git a/configs/components/rubygem-CFPropertyList.rb b/configs/components/rubygem-CFPropertyList.rb index 2306c827..d9513d9c 100644 --- a/configs/components/rubygem-CFPropertyList.rb +++ b/configs/components/rubygem-CFPropertyList.rb @@ -7,11 +7,15 @@ if settings[:ruby_version].to_f >= 3.2 pkg.version '3.0.7' pkg.md5sum 'ed89ce5e7074a6f8e8b8e744eaf014d0' + pkg.build_requires 'base64' else pkg.version '2.3.6' pkg.md5sum 'ae4086185992f293ffab1641b83286a5' end + pkg.build_requires 'rubygem-rexml' + # Also requires nkf, part of the Ruby standard library (ext) as of 3.2 + instance_eval File.read('configs/components/_base-rubygem.rb') pkg.environment "GEM_HOME", settings[:gem_home] end diff --git a/configs/components/rubygem-fast_gettext.rb b/configs/components/rubygem-fast_gettext.rb index 3ea744d6..6db70d82 100644 --- a/configs/components/rubygem-fast_gettext.rb +++ b/configs/components/rubygem-fast_gettext.rb @@ -9,6 +9,9 @@ pkg.version '2.4.0' pkg.sha256sum 'fd26c4c406aa10be34f0fd2847ce3ffdc1e9d9798de87538594757bbb9175fbf' + pkg.build_requires 'rubygem-prime' + # Also requires 'racc', part of the Ruby standard library as of 3.2 + instance_eval File.read('configs/components/_base-rubygem.rb') # Overwrite the base rubygem's default GEM_HOME with the vendor gem directory diff --git a/configs/components/rubygem-gettext.rb b/configs/components/rubygem-gettext.rb index 2c248fa0..e61deb3d 100644 --- a/configs/components/rubygem-gettext.rb +++ b/configs/components/rubygem-gettext.rb @@ -7,6 +7,12 @@ pkg.version '3.5.1' pkg.sha256sum '03ec7f71ea7e2cf1fdcd5e08682e98b81601922fdbee890b7bc6f63b0e1a512a' + pkg.build_requires 'rubygem-erubi' + pkg.build_requires 'rubygem-locale' + pkg.build_requires 'rubygem-prime' + pkg.build_requires 'rubygem-text' + # Also requires 'racc', part of the Ruby standard library as of 3.2 + instance_eval File.read('configs/components/_base-rubygem.rb') # Overwrite the base rubygem's default GEM_HOME with the vendor gem directory diff --git a/configs/components/rubygem-highline.rb b/configs/components/rubygem-highline.rb index 3b8e6409..47ae1f57 100644 --- a/configs/components/rubygem-highline.rb +++ b/configs/components/rubygem-highline.rb @@ -12,6 +12,8 @@ pkg.sha256sum 'd63d7f472f8ffaa143725161ae6fb06895b5cb7527e0b4dac5ad1e4902c80cb9' end + # Requires 'reline', part of the Ruby standard library as of 3.2 + instance_eval File.read('configs/components/_base-rubygem.rb') # Overwrite the base rubygem's default GEM_HOME with the vendor gem directory diff --git a/configs/components/rubygem-prime.rb b/configs/components/rubygem-prime.rb index e9c8e695..fd491964 100644 --- a/configs/components/rubygem-prime.rb +++ b/configs/components/rubygem-prime.rb @@ -7,5 +7,7 @@ pkg.version '0.1.4' pkg.sha256sum '4d755ebf7c2994a6f3a3fee0d072063be3fff2d4042ebff6cd5eebd4747a225e' + # Requires 'forwardable' and 'singleton', both part of the Ruby standard library as of 3.2 + instance_eval File.read('configs/components/_base-rubygem.rb') end diff --git a/configs/components/rubygem-sys-filesystem.rb b/configs/components/rubygem-sys-filesystem.rb index 51d81f86..c1ab96bb 100644 --- a/configs/components/rubygem-sys-filesystem.rb +++ b/configs/components/rubygem-sys-filesystem.rb @@ -12,5 +12,7 @@ pkg.sha256sum '17b561d1be683c34bc53946461ea9d67012d8f395e7297db8c63b9018cb30ece' end + pkg.requires 'rubygem-ffi' + instance_eval File.read('configs/components/_base-rubygem.rb') end From e65251b96036543774c65bcc1719ceb3077972ba Mon Sep 17 00:00:00 2001 From: nmburgan <13688219+nmburgan@users.noreply.github.com> Date: Tue, 23 Sep 2025 09:31:39 -0700 Subject: [PATCH 5/7] Require Ruby in _base-rubygem This should be fairly obvious, but this puts the explicit require before installing any gems, just in case Vanagon decides to switch up the order. --- configs/components/_base-rubygem.rb | 1 + 1 file changed, 1 insertion(+) diff --git a/configs/components/_base-rubygem.rb b/configs/components/_base-rubygem.rb index f9c773a4..eafbbaf5 100644 --- a/configs/components/_base-rubygem.rb +++ b/configs/components/_base-rubygem.rb @@ -15,6 +15,7 @@ end pkg.build_requires "runtime-#{settings[:runtime_project]}" +pkg.build_requires "ruby-#{settings[:ruby_version]}" pkg.build_requires "pl-ruby-patch" if platform.is_cross_compiled? if platform.is_windows? From 8ec48afa76faba3257ada126241d15dbb203cdf9 Mon Sep 17 00:00:00 2001 From: nmburgan <13688219+nmburgan@users.noreply.github.com> Date: Tue, 23 Sep 2025 09:57:58 -0700 Subject: [PATCH 6/7] Fix patch-hostruby for x.y Ruby version --- resources/files/ruby/patch-hostruby.rb | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/resources/files/ruby/patch-hostruby.rb b/resources/files/ruby/patch-hostruby.rb index 481fc054..9b31b273 100644 --- a/resources/files/ruby/patch-hostruby.rb +++ b/resources/files/ruby/patch-hostruby.rb @@ -20,7 +20,11 @@ # target ruby versions (what we're trying to build) target_ruby_version = ARGV[0] target_triple = ARGV[1] -target_api_version = target_ruby_version.gsub(/\.\d*$/, '.0') +target_api_version = if target_ruby_version.match(/\d\.\d\.\d{1,2}/) + target_ruby_version.gsub(/\.\d*$/, '.0') + else + "#{target_ruby_version}.0" + end # host ruby (the ruby we execute to build the target) host_rubylibdir = RbConfig::CONFIG['rubylibdir'] From 5c3edb66bed29b6e8d3aafbcdfe1d93513d794bd Mon Sep 17 00:00:00 2001 From: nmburgan <13688219+nmburgan@users.noreply.github.com> Date: Tue, 23 Sep 2025 09:58:13 -0700 Subject: [PATCH 7/7] Put original versions of modified host Ruby files back --- tasks/build.rake | 17 +++++++++++++++-- 1 file changed, 15 insertions(+), 2 deletions(-) diff --git a/tasks/build.rake b/tasks/build.rake index 6cb0864c..8286f443 100644 --- a/tasks/build.rake +++ b/tasks/build.rake @@ -16,7 +16,20 @@ namespace :vox do cmd = "bundle exec build #{project} #{platform} --engine #{engine}" FileUtils.rm_rf('C:/ProgramFiles64Folder/') if platform =~ /^windows-/ - - run_command(cmd, silent: false, print_command: true, report_status: true) + libdir = `ruby -e "require 'rbconfig'; puts RbConfig::CONFIG['rubylibdir']"`.chomp + begin + run_command(cmd, silent: false, print_command: true, report_status: true) + ensure + # During the build process for macos-all-x86_64, we patch two files in the + # host ruby installation. If we don't revert those changes, subsequent tasks + # like uploading to S3 wil fail. + if platform == 'macos-all-x86_64' + puts 'Reverting changes to host ruby installation...' + ['rubygems/ext/builder.rb', 'rubygems/basic_specification.rb'].each do |f| + FileUtils.rm_f("#{libdir}/#{f}") + FileUtils.mv("#{libdir}/#{f}.orig", "#{libdir}/#{f}") + end + end + end end end