summaryrefslogtreecommitdiffhomepage
path: root/build_config
diff options
context:
space:
mode:
authorChris Reuter <[email protected]>2021-10-21 21:33:17 -0400
committerChris Reuter <[email protected]>2021-10-21 21:58:45 -0400
commit5c4273f944b538bc24ed98c52991ea8bf9044654 (patch)
tree2d65523aa60dff53a4cedd95e92abf25b0755a39 /build_config
parentb6b4ac8270fcef135291cbde60d18f1c8a4c98e4 (diff)
downloadmruby-5c4273f944b538bc24ed98c52991ea8bf9044654.tar.gz
mruby-5c4273f944b538bc24ed98c52991ea8bf9044654.zip
Added testing support for cross-MinGW builds.
This adds a build_config that will cross-build a Windows executable using the MinGW cross-compiler and will also run the unit (i.e. 'rake test') using Wine. For this to work, I made some modifications to the underlying test scripts as well as some minor changes to a couple of the tests themselves.
Diffstat (limited to 'build_config')
-rw-r--r--build_config/cross-mingw-winetest.rb91
-rwxr-xr-xbuild_config/helpers/wine_runner.rb71
2 files changed, 162 insertions, 0 deletions
diff --git a/build_config/cross-mingw-winetest.rb b/build_config/cross-mingw-winetest.rb
new file mode 100644
index 000000000..fad06b265
--- /dev/null
+++ b/build_config/cross-mingw-winetest.rb
@@ -0,0 +1,91 @@
+
+# Cross-compile using MinGW and test using Wine.
+#
+# Steps:
+#
+# 1. Install MinGW; 64-bit target seems to work best.
+#
+# 2. Install Wine.
+#
+# 3. Run command:
+#
+# wine cmd /c echo "Hello world"'
+#
+# This will confirm that Wine works and will trigger standard
+# Wine setup, which is slow.
+#
+# 4. Confirm that drive 'z:' is mapped to your root filesystem.
+# (This is supposed to be a default but it helps to
+# double-check.) To confirm, run:
+#
+# wine cmd /c dir 'z:\\'
+#
+# This should give you a DOS-style equivalent of 'ls /'. If not,
+# you'll need to fix that with winecfg or by adding a symlink to
+# '~/.wine/dosdevices'.
+#
+# 5. You will likely need to tweak the settings below to work with
+# your configuration unless it is exactly like one of the platforms
+# I've tested on (Ubuntu 20.04 or macOS using brew.)
+#
+# 6. Run the build command:
+#
+# MRUBY_CONFIG=build_config/cross-mingw-winetest.rb rake test
+#
+# If all goes well, you should now have Windows executables and a
+# set of passing tests.
+#
+#
+# Caveats:
+#
+# 1. This works by using a helper script that rewrites test output
+# to make it look *nix-like and then handing it back to the test
+# cases. Some of the existing tests were (slightly) modified to
+# make this easier but only for the 'full-core' gembox. Other
+# gems' bintests may or may not work with the helper script and
+# may or may not be fixable by extending the script.
+#
+# 2. MinGW and Wine are both complex and not very consistent so you
+# will likely need to do some fiddling to get things to work.
+#
+# 3. This script assumes you are running it on a *nix-style OS.
+#
+# 4. I recommend building 64-bit targets only. Building a 32-bit
+# Windows binary with i686-w64-mingw32 seems to work (at least,
+# it did for me) but the resulting executable failed a number of
+# unit tests due to small errors in some floating point
+# operations. It's unclear if this indicates more serious problems.
+#
+
+
+MRuby::CrossBuild.new("cross-mingw-winetest") do |conf|
+ conf.toolchain :gcc
+
+ conf.host_target = "x86_64-w64-mingw32"
+
+ # Ubuntu 20
+ conf.cc.command = "#{conf.host_target}-gcc-posix"
+
+ # macOS+Wine from brew
+ #conf.cc.command = "#{conf.host_target}-gcc"
+
+ conf.linker.command = conf.cc.command
+ conf.archiver.command = "#{conf.host_target}-gcc-ar"
+ conf.exts.executable = ".exe"
+
+ # By default, we compile as static as possible to remove runtime
+ # MinGW dependencies; they are probably fixable but it gets
+ # complicated.
+ conf.cc.flags = ['-static']
+ conf.linker.flags += ['-static']
+
+ conf.test_runner do |t|
+ thisdir = File.absolute_path( File.dirname(__FILE__) )
+ t.command = File.join(thisdir, * %w{ helpers wine_runner.rb})
+ end
+
+ conf.gembox "full-core"
+
+ conf.enable_bintest
+ conf.enable_test
+end
diff --git a/build_config/helpers/wine_runner.rb b/build_config/helpers/wine_runner.rb
new file mode 100755
index 000000000..9a7eb46b0
--- /dev/null
+++ b/build_config/helpers/wine_runner.rb
@@ -0,0 +1,71 @@
+#!/usr/bin/env ruby
+
+# Wrapper for running tests for cross-compiled Windows builds in Wine.
+
+require 'open3'
+
+DOSROOT = 'z:'
+
+# Rewrite test output to replace DOS-isms with Unix-isms.
+def clean(output, stderr = false)
+ ends_with_newline = !!(output =~ /\n$/)
+ executable = ARGV[0].gsub(/\.exe\z/i, '')
+
+ # Fix line-ends
+ output = output.gsub(/\r\n/, "\n")
+
+ # Strip out Wine messages
+
+
+ results = output.split(/\n/).map do |line|
+ # Fix file paths
+ if line =~ /#{DOSROOT}\\/i
+ line.gsub!(/#{DOSROOT}([^:]*)/i) { |path|
+ path.gsub!(/^#{DOSROOT}/i, '')
+ path.gsub!(%r{\\}, '/')
+ path
+ }
+ end
+
+ # strip '.exe' off the end of the executable's name if needed
+ line.gsub!(/(#{Regexp.escape executable})\.exe/i, '\1')
+
+ line
+ end
+
+ result_text = results.join("\n")
+ result_text += "\n" if ends_with_newline
+ return result_text
+end
+
+
+def main
+ if ARGV.empty? || ARGV[0] =~ /^- (-?) (\?|help|h) $/x
+ puts "#{$0} <command-line>"
+ exit 0
+ end
+
+ # For simplicity, just read all of stdin into memory and pass that
+ # as an argument when invoking wine. (Skipped if STDIN was not
+ # redirected.)
+ if !STDIN.tty?
+ input = STDIN.read
+ else
+ input = ""
+ end
+
+ # Disable all Wine messages so they don't interfere with the output
+ ENV['WINEDEBUG'] = 'err-all,warn-all,fixme-all,trace-all'
+
+ # Run the program in wine and capture the output
+ output, errormsg, status = Open3.capture3('wine', *ARGV, :stdin_data => input)
+
+ # Clean and print the results.
+ STDOUT.write clean(output)
+ STDERR.write clean(errormsg)
+
+ exit(status.exitstatus)
+end
+
+
+main()