-
Notifications
You must be signed in to change notification settings - Fork 257
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Use new side-by-side mechanism only on ruby-3.4+
It it too heavy to be introduced in stable releases.
- Loading branch information
Showing
6 changed files
with
268 additions
and
156 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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 |
156 changes: 156 additions & 0 deletions
156
recipes/sandbox/60-side-by-side-assembly-ruby-3.4+.rake
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -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 | ||
<dependency> | ||
<dependentAssembly> | ||
<assemblyIdentity version="1.0.0.0" type="win32" name="#{File.basename(so_fname)}-assembly" /> | ||
</dependentAssembly> | ||
</dependency> | ||
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 | ||
<?xml version="1.0" encoding="UTF-8" standalone="yes"?> | ||
<assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0"> | ||
<assemblyIdentity type="win32" name="#{File.basename(so_fname)}-assembly" version="1.0.0.0"></assemblyIdentity> | ||
#{ e_dlls.map{|dll| %Q{<file name="#{File.basename(dll)}"/>} }.join } | ||
</assembly> | ||
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 | ||
<dependency> | ||
<dependentAssembly> | ||
<assemblyIdentity version="1.0.0.0" type="win32" name="ruby_builtin_dlls" /> | ||
</dependentAssembly> | ||
</dependency> | ||
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 | ||
<?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> | ||
#{ core_dlls.map{|dll| %Q{<file name="#{File.basename(dll)}"/>} }.join } | ||
</assembly> | ||
EOT | ||
end | ||
self.sandboxfiles << manifest2 | ||
end |
Oops, something went wrong.