diff --git a/README.md b/README.md index 16fba0d62..f3a3ffe93 100644 --- a/README.md +++ b/README.md @@ -109,8 +109,9 @@ Check the [wiki on how to use](https://github.com/oneclick/rubyinstaller2/wiki/F | | | | "installer-inno" => executable installer file | | | '------- "msvcrt" => older type of C standard library | | | "ucrt" => new type of C standard library - | | '------- "x86" => 32 bit ruby and MSYS2 version - | | "x64" => 64 bit version + | | '------- "x86" => 32 bit x86 ruby and MSYS2 version + | | "x64" => 64 bit x86_64 version + | | "arm" => ARM64 version | '------ "x.x.x" => ruby version to build | "head" => latest development snapshot of ruby '------ "ri" => RubyInstaller without Devkit diff --git a/lib/ruby_installer/build.rb b/lib/ruby_installer/build.rb index 5430cb229..8679c3029 100644 --- a/lib/ruby_installer/build.rb +++ b/lib/ruby_installer/build.rb @@ -5,6 +5,7 @@ module Build autoload :ComponentsInstaller, 'ruby_installer/build/components_installer' autoload :DllDirectory, 'ruby_installer/build/dll_directory' autoload :ErbCompiler, 'ruby_installer/build/erb_compiler' + autoload :ManifestUpdater, 'ruby_installer/build/manifest_updater' autoload :Msys2Installation, 'ruby_installer/build/msys2_installation' autoload :GEM_VERSION, 'ruby_installer/build/gem_version' autoload :Task, 'ruby_installer/build/task' diff --git a/lib/ruby_installer/build/components/03_dev_tools.rb b/lib/ruby_installer/build/components/03_dev_tools.rb index 57b51c171..9f400694f 100644 --- a/lib/ruby_installer/build/components/03_dev_tools.rb +++ b/lib/ruby_installer/build/components/03_dev_tools.rb @@ -52,6 +52,7 @@ def description 'mingw32' => PACKAGES_MINGW32, 'mingw64' => PACKAGES_MINGW64, 'ucrt64' => PACKAGES_MINGW64, + 'clangarm64' => PACKAGES_MINGW64, } def execute(args) diff --git a/lib/ruby_installer/build/manifest_updater.rb b/lib/ruby_installer/build/manifest_updater.rb new file mode 100644 index 000000000..5668ac8cf --- /dev/null +++ b/lib/ruby_installer/build/manifest_updater.rb @@ -0,0 +1,35 @@ +module RubyInstaller + module Build + class ManifestUpdater + def self.update_file(from_fname, manifest_xml_string, to_fname) + image = File.binread(from_fname) + update_blob(image, manifest_xml_string, filename: from_fname) + File.binwrite(to_fname, image) + end + + def self.update_blob(dll_or_exe_data, manifest_xml_string, filename: nil) + # There are two regular options to add a custom manifest: + # 1. Change a given exe file per Microsofts "mt.exe" after the build + # 2. Specify a the manifest while linking with the MINGW toolchain + # + # Since we don't want to depend on particular Microsoft tools and want to avoid additional patching of the ruby build, we do a nifty trick here. + # We patch the exe file manually. + # Removing unnecessary spaces and comments from the embedded XML manifest gives us enough space to add the above XML elements. + # Then the default MINGW manifest gets replaced by our custom XML content. + # The rest of the available bytes is simply padded with spaces, so that we don't change positions within the EXE image. + success = false + dll_or_exe_data.gsub!(/<\?xml.*?\n/m) do |m| + success = true + newm = m.gsub(/^\s*<\/assembly>\s*$/, manifest_xml_string + "") + .gsub(//m, "") + .gsub(/^ +/, "") + .gsub(/\n+/m, "\n") + + raise "replacement manifest too big #{m.bytesize} < #{newm.bytesize}" if m.bytesize < newm.bytesize + newm + " " * (m.bytesize - newm.bytesize) + end + raise "no manifest found#{ "in #{filename}" if filename}" unless success + end + end + end +end diff --git a/lib/ruby_installer/build/msys2_installation.rb b/lib/ruby_installer/build/msys2_installation.rb index 9868387b0..0bc758438 100644 --- a/lib/ruby_installer/build/msys2_installation.rb +++ b/lib/ruby_installer/build/msys2_installation.rb @@ -26,6 +26,7 @@ def initialize(msys_path: nil, mingwarch: nil, mingw_package_prefix: nil, ruby_b when /x64.*ucrt/ then 'ucrt64' when /x64.*mingw32/ then 'mingw64' when /i386.*mingw32/ then 'mingw32' + when /aarch64-mingw-ucrt/ then 'clangarm64' else raise "unsupported ruby platform #{RUBY_PLATFORM.inspect}" end ) @@ -34,6 +35,7 @@ def initialize(msys_path: nil, mingwarch: nil, mingw_package_prefix: nil, ruby_b when 'mingw32' then "mingw-w64-i686" when 'mingw64' then "mingw-w64-x86_64" when 'ucrt64' then "mingw-w64-ucrt-x86_64" + when 'clangarm64' then "mingw-w64-clang-aarch64" else raise "unknown mingwarch #{@mingwarch.inspect}" end end @@ -128,6 +130,9 @@ def mingw_prefix def enable_dll_search_paths @mingwdir ||= begin DllDirectory.set_defaults + # Add bundled dll directory for libcrypto.dll loading zlib.dll and legacy.dll loading libcrypto.dll + DllDirectory.new(RbConfig::CONFIG["rubyarchdir"]) + # Add MSYS2-MINGW DLL directory for user-installed gems path = mingw_bin_path DllDirectory.new(path) if File.directory?(path) rescue MsysNotFound @@ -182,6 +187,12 @@ def disable_dll_search_paths vars['MSYSTEM_CHOST'] = 'x86_64-w64-mingw32' vars['MINGW_CHOST'] = vars['MSYSTEM_CHOST'] vars['MINGW_PREFIX'] = vars['MSYSTEM_PREFIX'] + when 'clangarm64' + vars['MSYSTEM_PREFIX'] = '/clangarm64' + vars['MSYSTEM_CARCH'] = 'aarch64' + vars['MSYSTEM_CHOST'] = 'aarch64-w64-mingw32' + vars['MINGW_CHOST'] = vars['MSYSTEM_CHOST'] + vars['MINGW_PREFIX'] = vars['MSYSTEM_PREFIX'] else raise "unknown mingwarch #{@mingwarch.inspect}" end diff --git a/packages/ri-msys/Rakefile b/packages/ri-msys/Rakefile index f5e9ab8aa..95148f0c5 100644 --- a/packages/ri-msys/Rakefile +++ b/packages/ri-msys/Rakefile @@ -39,6 +39,14 @@ class RubyPackage < RubyInstaller::Build::Openstruct self.mingwdir = "mingw32" self.packagenamearch = "x86" self.default_instdir = "C:\\Ruby#{rubyver2.gsub(".","")}" + when 'arm-ucrt' + self.pacman_arch = "mingw-w64-clang-aarch64" + self.ruby_arch = "aarch64-mingw-ucrt" + self.msys_arch = "x86_64" + self.msysdir = "msys64" + self.mingwdir = "clangarm64" + self.packagenamearch = "arm" + self.default_instdir = "C:\\Ruby#{rubyver2.gsub(".","")}-arm" else raise "invalid arch #{arch}" end @@ -50,13 +58,13 @@ end ovl_glob('recipes/*/task.rake').each{|f| load(ovl_expand_file(f)) } -ruby_arch_packages = %w[x64-ucrt].map do |arch| +ruby_arch_packages = %w[x64-ucrt x86-msvcrt].map do |arch| %w[3.1.6-1 3.2.6-1 3.3.6-2 3.4.1-1 head].map do |packagever| RubyPackage.new( packagever: packagever, arch: arch, rootdir: __dir__ ).freeze end end -ruby_arch_packages += %w[x86-msvcrt].map do |arch| - %w[3.1.6-1 3.2.6-1 3.3.6-2 3.4.1-1 head].map do |packagever| +ruby_arch_packages += %w[arm-ucrt].map do |arch| + %w[3.4.1-1 head].map do |packagever| RubyPackage.new( packagever: packagever, arch: arch, rootdir: __dir__ ).freeze end end diff --git a/packages/ri/Rakefile b/packages/ri/Rakefile index 73d766c69..7040c512f 100644 --- a/packages/ri/Rakefile +++ b/packages/ri/Rakefile @@ -34,6 +34,12 @@ class RubyPackage < RubyInstaller::Build::Openstruct self.mingwdir = "mingw32" self.default_instdir = "C:\\Ruby#{rubyver2.gsub(".","")}" self.packagenamearch = "x86" + when 'arm-ucrt' + self.pacman_arch = "mingw-w64-clang-aarch64" + self.ruby_arch = "aarch64-mingw-ucrt" + self.mingwdir = "clangarm64" + self.default_instdir = "C:\\Ruby#{rubyver2.gsub(".","")}-arm" + self.packagenamearch = "arm" else raise "invalid arch #{arch}" end @@ -45,13 +51,13 @@ end ovl_glob('recipes/*/task.rake').each{|f| load(ovl_expand_file(f)) } -ruby_arch_packages = %w[x64-ucrt].map do |arch| +ruby_arch_packages = %w[x64-ucrt x86-msvcrt].map do |arch| %w[3.1.6-1 3.2.6-1 3.3.6-2 3.4.1-1 head].map do |packagever| RubyPackage.new( packagever: packagever, arch: arch, rootdir: __dir__ ).freeze end end -ruby_arch_packages += %w[x86-msvcrt].map do |arch| - %w[3.1.6-1 3.2.6-1 3.3.6-2 3.4.1-1 head].map do |packagever| +ruby_arch_packages += %w[arm-ucrt].map do |arch| + %w[3.4.1-1 head].map do |packagever| RubyPackage.new( packagever: packagever, arch: arch, rootdir: __dir__ ).freeze end end diff --git a/recipes/installer-inno/events.iss b/recipes/installer-inno/events.iss index 9c2ce1166..643e04ff3 100644 --- a/recipes/installer-inno/events.iss +++ b/recipes/installer-inno/events.iss @@ -26,7 +26,7 @@ begin ModifyRubyopt(['-Eutf-8']); #endif - if IsComponentSelected('msys2') then + if WizardIsComponentSelected('msys2') then DeleteRubyMsys2Directory(); end else diff --git a/recipes/installer-inno/ri_gui.iss b/recipes/installer-inno/ri_gui.iss index 4085b3247..8f26b7f92 100644 --- a/recipes/installer-inno/ri_gui.iss +++ b/recipes/installer-inno/ri_gui.iss @@ -103,23 +103,23 @@ begin if update then if msysdir <> '' then - if IsComponentSelected('msys2') then + if WizardIsComponentSelected('msys2') then CompLabel.Caption := 'ATTENTION: MSYS2 is already present in ' + msysdir + '. It will be deleted now and then re-installed. Additional installed pacman packages will be removed. Some gems might not work afterwards and must be re-installed.' else CompLabel.Caption := 'Ruby in ' + ExpandConstant('{app}') + ' will be updated. MSYS2 seems to be already present in ' + msysdir + ' . It will kept untouched and will be reused for this Ruby installation. Optionally it can be updated per `ridk install` on the last page of the installer.' else - if IsComponentSelected('msys2') then + if WizardIsComponentSelected('msys2') then CompLabel.Caption := 'Ruby in ' + ExpandConstant('{app}') + ' will be updated and MSYS2 will be installed into ' + ExpandConstant('{app}\{#MsysDir}') + '. Please run `ridk install` on the last installer page to initialize it. It can be updated later per `ridk install` as well.' else CompLabel.Caption := 'Ruby in ' + ExpandConstant('{app}') + ' will be updated. It''s possible to install MSYS2 at the last page of the installer or to reuse an existing MSYS2 installation.' else if msysdir <> '' then - if IsComponentSelected('msys2') then + if WizardIsComponentSelected('msys2') then CompLabel.Caption := 'ATTENTION: MSYS2 is already present in ' + msysdir + '. It will be deleted now and then re-installed. Additional installed pacman packages will be removed. Some gems might not work afterwards and must be re-installed.' else CompLabel.Caption := 'Ruby will be installed into ' + ExpandConstant('{app}') + '. MSYS2 seems to be already present in ' + msysdir + ' . It will kept untouched and will be re-used for this Ruby installation. Optionally it can be updated per `ridk install` on the last page of the installer.' else - if IsComponentSelected('msys2') then + if WizardIsComponentSelected('msys2') then CompLabel.Caption := 'Ruby will be installed into ' + ExpandConstant('{app}') + ' and MSYS2 will be installed into ' + ExpandConstant('{app}\{#MsysDir}') + '. Please run `ridk install` on the last installer page to initialize it. It can be updated later per `ridk install` as well.' else CompLabel.Caption := 'Ruby will be installed into ' + ExpandConstant('{app}') + ' without MSYS2. It''s possible to install MSYS2 at the last page of the installer or to reuse an existing MSYS2 installation.'; @@ -129,9 +129,10 @@ end; procedure EnableMsys2Component(enable: Boolean); begin - {* InnoSetup doesn't provide corresponding setter for IsComponentSelected, so that we alter the ComponentsList directly. *} - if WizardForm.ComponentsList.Items.Count > 2 then - WizardForm.ComponentsList.Checked[2] := enable; + if enable then + WizardSelectComponents('msys2') + else + WizardSelectComponents('!msys2'); end; procedure InitializeGUI; diff --git a/recipes/installer-inno/rubyinstaller.iss.erb b/recipes/installer-inno/rubyinstaller.iss.erb index 2188a31a3..5ea9431aa 100644 --- a/recipes/installer-inno/rubyinstaller.iss.erb +++ b/recipes/installer-inno/rubyinstaller.iss.erb @@ -83,7 +83,7 @@ en.SelectDirDesc= en.SelectDirLabel3=Setup will install [name] into the following folder. Click Install to continue or click Browse to use a different one. en.SelectDirBrowseLabel=Please avoid any folder name that contains spaces (e.g. Program Files). en.DiskSpaceMBLabel=Required free disk space: ~[mb] MB -en.DirExists=The folder:%n%n%1%n%nalready exists. Would you like to install to that folder anyway?%n%nOverwriting a Ruby version with the same major and minor version usually works, but for example Ruby-2.5.0 over 2.4.0 doesn't. +en.DirExists=The folder:%n%n%1%n%nalready exists. Would you like to install to that folder anyway?%n%nOverwriting a Ruby version with the same major and minor version usually works, but for example Ruby-3.4.0 over 3.3.0 doesn't. [CustomMessages] AddPath=Add Ruby executables to your PATH @@ -133,11 +133,16 @@ Root: <%= regroot %>; Subkey: Software\Classes\<%= rubyname %>File\shell\open\co ; So use Innosetup to add described permissions and icacls to disable unwanted inheritance. [Dirs] Name: {app}; Permissions: creatorowner-full users-readexec admins-full +Name: "{app}/<%= package.rubyver2 =~ /^3\.[23]$/ ? "bin/etc" : "lib/ruby/#{ package.rubylibver }/etc" %>" + [Run] +; Set permissions on install directories Filename: "icacls.exe"; Parameters: """{app}"" /inheritancelevel:r "; WorkingDir: "{app}"; StatusMsg: "Changing install Directory Permissions"; Flags: runhidden <% if with_msys %> Filename: "icacls.exe"; Parameters: """{app}\<%= package.msysdir %>\tmp"" /inheritancelevel:r /grant *S-1-5-32-545:(CI)(WD,AD,WEA,WA) /grant *S-1-3-0:(OI)(CI)(IO)(F) /grant *S-1-5-32-544:(OI)(CI)(F) /grant *S-1-5-32-545:(NP)(RX) "; WorkingDir: "{app}"; StatusMsg: "Changing MSYS2 /tmp Directory Permissions"; Flags: runhidden; Components: msys2 <% end %> +; Add link to SSL CA certs so that OpenSSL finds them based on the libssl.dll location +Filename: "{cmd}"; Parameters: "/c mklink /j <%= package.rubyver2 =~ /^3\.[23]$/ ? "bin" : "lib\\ruby\\#{package.rubylibver}" %>\etc\ssl ssl"; WorkingDir: "{app}"; StatusMsg: "Add link to SSL CA certs"; Flags: runhidden [Icons] Name: {autoprograms}\{#InstallerName}\{cm:InteractiveRubyTitle}; Filename: {app}\bin\irb.<%= package.rubyver2 < '3.1' ? "cmd" : "bat" %>; IconFilename: {app}\bin\ruby.exe diff --git a/recipes/sandbox/20-define-import-files.rake b/recipes/sandbox/20-define-import-files.rake index d1ef9d1d6..31f6dddee 100644 --- a/recipes/sandbox/20-define-import-files.rake +++ b/recipes/sandbox/20-define-import-files.rake @@ -10,8 +10,8 @@ self.import_files.merge!({ "resources/files/setrbvars.cmd" => "bin/setrbvars.cmd", "resources/files/operating_system.rb" => "lib/ruby/#{package.rubylibver}/rubygems/defaults/operating_system.rb", "resources/icons/ruby-doc.ico" => "share/doc/ruby/html/images/ruby-doc.ico", - "resources/ssl/cacert.pem" => "#{"bin/etc/" if package.rubyver2 >= "3.2"}ssl/cert.pem", - "resources/ssl/README-SSL.md" => "#{"bin/etc/" if package.rubyver2 >= "3.2"}ssl/README-SSL.md", - "resources/ssl/c_rehash.rb" => "#{"bin/etc/" if package.rubyver2 >= "3.2"}ssl/certs/c_rehash.rb", + "resources/ssl/cacert.pem" => "ssl/cert.pem", + "resources/ssl/README-SSL.md" => "ssl/README-SSL.md", + "resources/ssl/c_rehash.rb" => "ssl/certs/c_rehash.rb", "#{thisdir}/LICENSE.txt" => "LICENSE.txt", }) diff --git a/recipes/sandbox/60-side-by-side-assembly-ruby-3.123.rake b/recipes/sandbox/60-side-by-side-assembly-ruby-3.123.rake new file mode 100644 index 000000000..3d5061d52 --- /dev/null +++ b/recipes/sandbox/60-side-by-side-assembly-ruby-3.123.rake @@ -0,0 +1,88 @@ +# Move bundled RubyInstaller DLLs to a subdirectory. +# This avoids interferences with other apps when ruby.exe is in the PATH. + +if package.rubyver2 < "3.4" + libruby_regex = /(msvcrt|ucrt)-ruby\d+\.dll$/i + bin_dir = File.join(sandboxdir, "bin") + dlls_dir = File.join(sandboxdir, "bin/ruby_builtin_dlls") + directory bin_dir + directory dlls_dir + + # Select the DLLs from "bin/" which shall be moved into "bin/ruby_builtin_dlls/" + dlls = self.sandboxfiles.select do |destpath| + destpath.start_with?(bin_dir+"/") && destpath =~ /\.dll$/i && destpath !~ libruby_regex + end + + dlls.each do |destpath| + # Add tasks to write the DLLs into the sub directory + new_destpath = File.join(File.dirname(destpath), "ruby_builtin_dlls", File.basename(destpath)) + file new_destpath => [destpath.sub(sandboxdir, unpackdirmgw), dlls_dir] do |t| + cp(t.prerequisites.first, t.name) + end + + # Move the DLLs in the dependent files list to the subdirectory + self.sandboxfiles.delete(destpath) + self.sandboxfiles << new_destpath + end + + # Add a custom manifest to both ruby.exe and rubyw.exe, so that they find the DLLs to be moved + self.sandboxfiles.select do |destpath| + destpath =~ /\/rubyw?\.exe$/i + end.each do |destpath| + file destpath => [destpath.sub(sandboxdir, unpackdirmgw), bin_dir] do |t| + puts "patching manifest of #{t.name}" + libruby = File.basename(self.sandboxfiles.find{|a| a=~libruby_regex }) + + image = File.binread(t.prerequisites.first) + # The XML elements we want to add to the default MINGW manifest: + new = <<-EOT + + + true + + + + + + + + + EOT + + # There are two regular options to add a custom manifest: + # 1. Change a given exe file per Microsofts "mt.exe" after the build + # 2. Specify a the manifest while linking with the MINGW toolchain + # + # Since we don't want to depend on particular Microsoft tools and want to avoid additional patching of the ruby build, we do a nifty trick here. + # We patch the exe file manually. + # Removing unnecessary spaces and comments from the embedded XML manifest gives us enough space to add the above XML elements. + # Then the default MINGW manifest gets replaced by our custom XML content. + # The rest of the available bytes is simply padded with spaces, so that we don't change positions within the EXE image. + image.gsub!(/<\?xml.*?\n/m) do |m| + newm = m.gsub(/^\s*<\/assembly>\s*$/, new + "") + .gsub(//m, "") + .gsub(/^ +/, "") + .gsub(/\n+/m, "\n") + + raise "replacement manifest to big #{m.bytesize} < #{newm.bytesize}" if m.bytesize < newm.bytesize + newm + " " * (m.bytesize - newm.bytesize) + end + File.binwrite(t.name, image) + end + end + + # Add a detached manifest file within the sub directory that lists all DLLs in question + manifest2 = File.join(sandboxdir, "bin/ruby_builtin_dlls/ruby_builtin_dlls.manifest") + file manifest2 => [dlls_dir] do |t| + puts "generate #{t.name}" + File.binwrite t.name, <<-EOT + + + + + #{ dlls.map{|dll| %Q{} }.join } + + EOT + end + self.sandboxfiles << manifest2 +end diff --git a/recipes/sandbox/60-side-by-side-assembly-ruby-3.4+.rake b/recipes/sandbox/60-side-by-side-assembly-ruby-3.4+.rake new file mode 100644 index 000000000..f20af19fc --- /dev/null +++ b/recipes/sandbox/60-side-by-side-assembly-ruby-3.4+.rake @@ -0,0 +1,156 @@ +# Move bundled RubyInstaller DLLs to a subdirectory. +# This avoids interferences with other apps when ruby.exe is in the PATH. + +if package.rubyver2 >= "3.4" + libruby_regex = /(msvcrt|ucrt)-ruby\d+\.dll$/i + bin_dir = File.join(sandboxdir, "bin") + dlls_dir = File.join(sandboxdir, "bin/ruby_builtin_dlls") + directory bin_dir + directory dlls_dir + + # Select the DLLs from "bin/" which shall be moved into "bin/ruby_builtin_dlls/" + dlls = self.sandboxfiles.select do |destpath| + destpath.start_with?(bin_dir+"/") && destpath =~ /\.dll$/i && destpath !~ libruby_regex + end + + ext_dll_defs = { + "lib/ruby/#{package.rubylibver}/#{package.ruby_arch}/fiddle.so" => /^libffi-\d.dll$/, + "lib/ruby/#{package.rubylibver}/#{package.ruby_arch}/openssl.so" => /^libssl-[\d_]+(-x64)?.dll$|^libcrypto-[\d_]+(-x64)?.dll$/, + "lib/ruby/#{package.rubylibver}/#{package.ruby_arch}/psych.so" => /^libyaml-[-\d]+.dll$/, + "lib/ruby/#{package.rubylibver}/#{package.ruby_arch}/zlib.so" => /^zlib\d.dll$/, + } + + core_dll_defs = [ + /^libgmp-\d+.dll$/, + /^libwinpthread-\d+.dll$/, + /^libgcc_s_.*.dll$/, + ] + + # create rake tasks to trigger additional processing of so files + ext_dll_defs.keys.each do |so_file| + self.sandboxfiles << File.join(sandboxdir, so_file) + end + + core_dlls, dlls = dlls.partition do |destpath| + core_dll_defs.any? { |re| re =~ File.basename(destpath) } + end + ext_dlls, dlls = dlls.partition do |destpath| + ext_dll_defs.values.any? { |re| re =~ File.basename(destpath) } + end + raise "DLL belonging neither to core nor to exts: #{dlls}" unless dlls.empty? + + + ########################################################################### + # Add manifest to extension.so files pointing to linked MINGW library DLLs + # next to it + ########################################################################### + + # Add tasks to move the DLLs into the extension directory + ext_dlls.each do |destpath| + so_fname, _ = ext_dll_defs.find { |_, re| re =~ File.basename(destpath) } + + new_destpath = File.join(sandboxdir, File.dirname(so_fname), File.basename(destpath)) + file new_destpath => [destpath.sub(sandboxdir, unpackdirmgw), File.dirname(new_destpath)] do |t| + cp(t.prerequisites.first, t.name) + end + + # Move the DLLs in the dependent files list to the subdirectory + self.sandboxfiles.delete(destpath) + self.sandboxfiles << new_destpath + end + + # Add a custom manifest to each extension.so, so that they find the DLLs to be moved + ext_dlls.each do |destpath| + so_fname, _ = ext_dll_defs.find { |_, re| re =~ File.basename(destpath) } + sandbox_so_fname = File.join(sandboxdir, so_fname) + + file sandbox_so_fname => [sandbox_so_fname.sub(sandboxdir, unpackdirmgw), File.dirname(sandbox_so_fname)] do |t| + puts "patching manifest of #{t.name}" + + # The XML elements we want to add to the default MINGW manifest: + new = <<~EOT + + + + + + EOT + + ManifestUpdater.update_file(t.prerequisites.first, new, t.name) + end + end + + # Add a detached manifest file within the ext.so directory that lists all linked DLLs + ext_dll_defs.each do |so_fname, re| + mani_path = File.join(sandboxdir, so_fname + "-assembly.manifest") + e_dlls = ext_dlls.select { |dll| re =~ File.basename(dll) } + + file mani_path => [File.dirname(mani_path)] do |t| + puts "generate #{t.name}" + + File.binwrite t.name, <<~EOT + + + + + #{ e_dlls.map{|dll| %Q{} }.join } + + EOT + end + self.sandboxfiles << mani_path + end + + + ################################################################################# + # Add manifest to ruby.exe, rubyw.exe files pointing to DLLs in ruby_builtin_dlls + ################################################################################# + + core_dlls.each do |destpath| + + # Add tasks to write the DLLs into the sub directory + new_destpath = File.join(File.dirname(destpath), "ruby_builtin_dlls", File.basename(destpath)) + file new_destpath => [destpath.sub(sandboxdir, unpackdirmgw), dlls_dir] do |t| + cp(t.prerequisites.first, t.name) + end + + # Move the DLLs in the dependent files list to the subdirectory + self.sandboxfiles.delete(destpath) + self.sandboxfiles << new_destpath + end + + # Add a custom manifest to ruby.exe, rubyw.exe and libruby, so that they find the DLLs to be moved + self.sandboxfiles.select do |destpath| + destpath =~ libruby_regex + end.each do |destpath| + + file destpath => [destpath.sub(sandboxdir, unpackdirmgw), bin_dir] do |t| + puts "patching manifest of #{t.name}" + + # The XML elements we want to add to the default MINGW manifest: + new = <<~EOT + + + + + + EOT + + ManifestUpdater.update_file(t.prerequisites.first, new, t.name) + end + end + + # Add a detached manifest file within the sub directory that lists all DLLs in question + manifest2 = File.join(sandboxdir, "bin/ruby_builtin_dlls/ruby_builtin_dlls.manifest") + file manifest2 => [dlls_dir] do |t| + puts "generate #{t.name}" + File.binwrite t.name, <<~EOT + + + + + #{ core_dlls.map{|dll| %Q{} }.join } + + EOT + end + self.sandboxfiles << manifest2 +end diff --git a/recipes/sandbox/60-side-by-side-assembly.rake b/recipes/sandbox/60-side-by-side-assembly.rake deleted file mode 100644 index 6439e78ae..000000000 --- a/recipes/sandbox/60-side-by-side-assembly.rake +++ /dev/null @@ -1,86 +0,0 @@ -# Move bundled RubyInstaller DLLs to a subdirectory. -# This avoids interferences with other apps when ruby.exe is in the PATH. - -libruby_regex = /(msvcrt|ucrt)-ruby\d+\.dll$/i -bin_dir = File.join(sandboxdir, "bin") -dlls_dir = File.join(sandboxdir, "bin/ruby_builtin_dlls") -directory bin_dir -directory dlls_dir - -# Select the DLLs from "bin/" which shall be moved into "bin/ruby_builtin_dlls/" -dlls = self.sandboxfiles.select do |destpath| - destpath.start_with?(bin_dir+"/") && destpath =~ /\.dll$/i && destpath !~ libruby_regex -end - -dlls.each do |destpath| - # Add tasks to write the DLLs into the sub directory - new_destpath = File.join(File.dirname(destpath), "ruby_builtin_dlls", File.basename(destpath)) - file new_destpath => [destpath.sub(sandboxdir, unpackdirmgw), dlls_dir] do |t| - cp(t.prerequisites.first, t.name) - end - - # Move the DLLs in the dependent files list to the subdirectory - self.sandboxfiles.delete(destpath) - self.sandboxfiles << new_destpath -end - -# Add a custom manifest to both ruby.exe and rubyw.exe, so that they find the DLLs to be moved -self.sandboxfiles.select do |destpath| - destpath =~ /\/rubyw?\.exe$/i -end.each do |destpath| - file destpath => [destpath.sub(sandboxdir, unpackdirmgw), bin_dir] do |t| - puts "patching manifest of #{t.name}" - libruby = File.basename(self.sandboxfiles.find{|a| a=~libruby_regex }) - - image = File.binread(t.prerequisites.first) - # The XML elements we want to add to the default MINGW manifest: - new = <<-EOT - - - true - - - - - - - - - EOT - - # There are two regular options to add a custom manifest: - # 1. Change a given exe file per Microsofts "mt.exe" after the build - # 2. Specify a the manifest while linking with the MINGW toolchain - # - # Since we don't want to depend on particular Microsoft tools and want to avoid additional patching of the ruby build, we do a nifty trick here. - # We patch the exe file manually. - # Removing unnecessary spaces and comments from the embedded XML manifest gives us enough space to add the above XML elements. - # Then the default MINGW manifest gets replaced by our custom XML content. - # The rest of the available bytes is simply padded with spaces, so that we don't change positions within the EXE image. - image.gsub!(/<\?xml.*?\n/m) do |m| - newm = m.gsub(/^\s*<\/assembly>\s*$/, new + "") - .gsub(//m, "") - .gsub(/^ +/, "") - .gsub(/\n+/m, "\n") - - raise "replacement manifest to big #{m.bytesize} < #{newm.bytesize}" if m.bytesize < newm.bytesize - newm + " " * (m.bytesize - newm.bytesize) - end - File.binwrite(t.name, image) - end -end - -# Add a detached manifest file within the sub directory that lists all DLLs in question -manifest2 = File.join(sandboxdir, "bin/ruby_builtin_dlls/ruby_builtin_dlls.manifest") -file manifest2 => [dlls_dir] do |t| - puts "generate #{t.name}" - File.binwrite t.name, <<-EOT - - - - - #{ dlls.map{|dll| %Q{} }.join } - - EOT -end -self.sandboxfiles << manifest2 diff --git a/recipes/sandbox/70-move-openssl-files-to-bin.rake b/recipes/sandbox/70-move-openssl-files-to-bin-ruby-3.23.rake similarity index 95% rename from recipes/sandbox/70-move-openssl-files-to-bin.rake rename to recipes/sandbox/70-move-openssl-files-to-bin-ruby-3.23.rake index 125ac2325..7119ec5a4 100644 --- a/recipes/sandbox/70-move-openssl-files-to-bin.rake +++ b/recipes/sandbox/70-move-openssl-files-to-bin-ruby-3.23.rake @@ -1,7 +1,7 @@ # Move bundled OpenSSL related files to bin/lib subdirectory. # This is necessary because libcrypt.dll and libssl.dll are located in bin/ruby_builtin_dlls and they search other dlls in ../lib -if package.rubyver2 >= "3.2" +if package.rubyver2 =~ /^3\.[23]$/ osl_files = %w[ lib/engines-3/capi.dll lib/engines-3/loader_attic.dll diff --git a/recipes/sandbox/70-move-openssl-files-to-bin-ruby-3.4+.rake b/recipes/sandbox/70-move-openssl-files-to-bin-ruby-3.4+.rake new file mode 100644 index 000000000..6b1f9eec7 --- /dev/null +++ b/recipes/sandbox/70-move-openssl-files-to-bin-ruby-3.4+.rake @@ -0,0 +1,27 @@ +# Move bundled OpenSSL related files to bin/lib subdirectory. +# This is necessary because libcrypt.dll and libssl.dll are located in bin/ruby_builtin_dlls and they search other dlls in ../lib + +if package.rubyver2 >= "3.4" + osl_files = %w[ + lib/engines-3/capi.dll + lib/engines-3/loader_attic.dll + lib/engines-3/padlock.dll + lib/ossl-modules/legacy.dll + ] + + osl_files.each do |path| + # Add tasks to write the DLLs into the sub directory + + destpath = File.join( + sandboxdir, + "lib/ruby/#{package.rubylibver}", + path + ) + file destpath => [File.join(unpackdirmgw, path), File.dirname(destpath)] do |t| + cp(t.prerequisites.first, t.name) + end + + # Add the DLLs in the dependent files list to the subdirectory + self.sandboxfiles << destpath + end +end diff --git a/recipes/sandbox/80-copy-msys-files.rake b/recipes/sandbox/80-copy-msys-files.rake index b1a287dc8..975107211 100644 --- a/recipes/sandbox/80-copy-msys-files.rake +++ b/recipes/sandbox/80-copy-msys-files.rake @@ -2,7 +2,27 @@ self.sandboxfiles.each do |destpath| directory File.dirname(destpath) unless Rake::Task.task_defined?(destpath) file destpath => [destpath.sub(sandboxdir, unpackdirmgw), File.dirname(destpath)] do |t| - cp_r(t.prerequisites.first, t.name) + # Copy file like cp_r, but excluding files with task definition + # cp_r(t.prerequisites.first, t.name) + + if FileTest.directory?(t.prerequisites.first) + Dir.glob("**/*", base: t.prerequisites.first, flags: File::FNM_DOTMATCH) do |rel| + dst = File.join(t.name, rel) + if Rake::Task.task_defined?(dst) + # invoke task definition and skip cp + Rake::Task[dst].invoke + next + end + src = File.join(t.prerequisites.first, rel) + if FileTest.directory?(src) + mkdir(dst, verbose: false) unless FileTest.directory?(dst) + else + cp(src, dst, verbose: false) + end + end + else + cp(t.prerequisites.first, t.name) + end end end end diff --git a/recipes/sandbox/rubyinstaller-3.4.1-arm-ucrt.files b/recipes/sandbox/rubyinstaller-3.4.1-arm-ucrt.files new file mode 100644 index 000000000..1952c210b --- /dev/null +++ b/recipes/sandbox/rubyinstaller-3.4.1-arm-ucrt.files @@ -0,0 +1,4 @@ +bin/libcrypto-3.dll +bin/libssl-3.dll +bin/aarch64-ucrt-ruby340.dll +lib/libaarch64-ucrt-ruby340.dll.a diff --git a/recipes/sandbox/rubyinstaller-head-arm-ucrt.files b/recipes/sandbox/rubyinstaller-head-arm-ucrt.files new file mode 100644 index 000000000..7558aaf33 --- /dev/null +++ b/recipes/sandbox/rubyinstaller-head-arm-ucrt.files @@ -0,0 +1,4 @@ +bin/libcrypto-3.dll +bin/libssl-3.dll +bin/aarch64-ucrt-ruby350.dll +lib/libaarch64-ucrt-ruby350.dll.a diff --git a/resources/ssl/README-SSL.md b/resources/ssl/README-SSL.md index 13195fe6b..ac045ed1b 100644 --- a/resources/ssl/README-SSL.md +++ b/resources/ssl/README-SSL.md @@ -2,7 +2,7 @@ RubyInstaller2 - SSL/TLS configuration ====================================== RubyInstaller2 is packaged with a predefined list of trusted certificate authorities (CAs). -This list is stored in the file `/bin/etc/ssl/cert.pem` on RubyInstaller-3.2.1 and newer and in `/ssl/cert.pem` on older Rubies with OpenSSL-1.1. +This list is stored in the file `/ssl/cert.pem`. It contains the certificates of the [default list of the Mozilla Foundation](https://wiki.mozilla.org/CA/Included_Certificates) . The file `cert.pem` is loaded when `require "openssl"` is executed. New releases of the RubyInstaller2 update the CA list to the latest version at the release date. @@ -19,11 +19,10 @@ Setting this variable disables the CA list bundled with RubyInstaller2. Addition of certificate to the Ruby default CA list ---------------------------------------------- -Additional certificates shall be stored in `/bin/etc/ssl/certs/.pem` in pem format. -On RubyInstallers before 3.2.1 the path is `/ssl/certs/.pem` . +Additional certificates shall be stored in `/ssl/certs/.pem` in pem format. Each pem file may contain several certificates. The pem files must be activated for CA lookup by using a OpenSSL-hashed filename. -There is a helper script in `/bin/etc/ssl/certs/c_rehash.rb` to generate these hash files. +There is a helper script in `/ssl/certs/c_rehash.rb` to generate these hash files. Just double click `c_rehash.rb` to activate all pem files in the directory. Addition of certificates to the Devkit/MSYS2 CA list diff --git a/test/test_ssl_cacerts.rb b/test/test_ssl_cacerts.rb index bd270b400..75260e5bb 100644 --- a/test/test_ssl_cacerts.rb +++ b/test/test_ssl_cacerts.rb @@ -57,9 +57,9 @@ def test_SSL_CERT_FILE end end - # Can CA certificates added into C:/Ruby32/bin/etc/ssl/certs/.0 ? + # Can CA certificates added into C:/Ruby32/ssl/certs/.0 ? def test_ssl_certs_dir - certfile = "#{RbConfig::TOPDIR}/#{"bin/etc/" if RUBY_VERSION >= "3.2"}ssl/certs/#{pki.ca_cert.subject.hash.to_s(16)}.0" + certfile = "#{RbConfig::TOPDIR}/ssl/certs/#{pki.ca_cert.subject.hash.to_s(16)}.0" File.write(certfile, pki.ca_cert.to_pem) server = TCPServer.new "localhost", 0