Skip to content

Commit

Permalink
Merge pull request #399 from oneclick/arm64
Browse files Browse the repository at this point in the history
Add arm64 architecture
  • Loading branch information
larskanis authored Jan 14, 2025
2 parents 7a72381 + ff96dd3 commit a790d77
Show file tree
Hide file tree
Showing 21 changed files with 395 additions and 114 deletions.
5 changes: 3 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
1 change: 1 addition & 0 deletions lib/ruby_installer/build.rb
Original file line number Diff line number Diff line change
Expand Up @@ -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'
Expand Down
1 change: 1 addition & 0 deletions lib/ruby_installer/build/components/03_dev_tools.rb
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,7 @@ def description
'mingw32' => PACKAGES_MINGW32,
'mingw64' => PACKAGES_MINGW64,
'ucrt64' => PACKAGES_MINGW64,
'clangarm64' => PACKAGES_MINGW64,
}

def execute(args)
Expand Down
35 changes: 35 additions & 0 deletions lib/ruby_installer/build/manifest_updater.rb
Original file line number Diff line number Diff line change
@@ -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.*?<assembly.*?<\/assembly>\n/m) do |m|
success = true
newm = m.gsub(/^\s*<\/assembly>\s*$/, manifest_xml_string + "</assembly>")
.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
11 changes: 11 additions & 0 deletions lib/ruby_installer/build/msys2_installation.rb
Original file line number Diff line number Diff line change
Expand Up @@ -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
)
Expand All @@ -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
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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

Expand Down
14 changes: 11 additions & 3 deletions packages/ri-msys/Rakefile
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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
Expand Down
12 changes: 9 additions & 3 deletions packages/ri/Rakefile
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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
Expand Down
2 changes: 1 addition & 1 deletion recipes/installer-inno/events.iss
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ begin
ModifyRubyopt(['-Eutf-8']);
#endif

if IsComponentSelected('msys2') then
if WizardIsComponentSelected('msys2') then
DeleteRubyMsys2Directory();

end else
Expand Down
15 changes: 8 additions & 7 deletions recipes/installer-inno/ri_gui.iss
Original file line number Diff line number Diff line change
Expand Up @@ -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.';
Expand All @@ -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;
Expand Down
7 changes: 6 additions & 1 deletion recipes/installer-inno/rubyinstaller.iss.erb
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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
Expand Down
6 changes: 3 additions & 3 deletions recipes/sandbox/20-define-import-files.rake
Original file line number Diff line number Diff line change
Expand Up @@ -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",
})
88 changes: 88 additions & 0 deletions recipes/sandbox/60-side-by-side-assembly-ruby-3.123.rake
Original file line number Diff line number Diff line change
@@ -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
<application xmlns="urn:schemas-microsoft-com:asm.v3">
<windowsSettings xmlns:ws2="http://schemas.microsoft.com/SMI/2016/WindowsSettings">
<ws2:longPathAware>true</ws2:longPathAware>
</windowsSettings>
</application>
<dependency>
<dependentAssembly>
<assemblyIdentity version="1.0.0.0" type="win32" name="ruby_builtin_dlls" />
</dependentAssembly>
</dependency>
<file name="#{ libruby }"/>
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.*?<assembly.*?<\/assembly>\n/m) do |m|
newm = m.gsub(/^\s*<\/assembly>\s*$/, new + "</assembly>")
.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
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0">
<assemblyIdentity type="win32" name="ruby_builtin_dlls" version="1.0.0.0"></assemblyIdentity>
#{ dlls.map{|dll| %Q{<file name="#{File.basename(dll)}"/>} }.join }
</assembly>
EOT
end
self.sandboxfiles << manifest2
end
Loading

0 comments on commit a790d77

Please sign in to comment.