From c261ee6da21b7a08cd05d82e15cd896ff375c940 Mon Sep 17 00:00:00 2001 From: Largo Date: Wed, 28 Oct 2026 11:22:14 +0100 Subject: [PATCH 1/6] Call the interpreter ironruby, as JRuby's is jruby; ir stays its short name RbConfig's ruby_install_name was "ir", so the binstubs RubyGems, Bundler and Rails write started `#!/usr/bin/env ir`. Ruby runs a #! line only when it says "ruby", so bin/rails needed a special case to run at all; "jruby" and "truffleruby" never did. "iruby" is taken: it is the Jupyter kernel's command. - The launchers are ironruby and ironruby.cmd now, with what ir.sh and ir.cmd had; ir.sh and ir.cmd forward to them. igem, iirb, irb and irubyc call ironruby directly. - ruby_install_name is "ironruby". The build puts an ironruby(.exe) copy of the apphost beside ir(.exe) - it starts the same ir.dll - so RbConfig.ruby is a file, as libraries that spawn it need. - Gem.ruby prefers the ironruby launcher, then ir.sh / ir.cmd. - ShebangNamesIronRuby stays, for binstubs written with ir. - Release archives ship both launchers; CI and the release check run both. --- .github/workflows/ci.yml | 17 +++- Docs/rails-on-windows.md | 4 +- README.md | 21 ++--- Src/Console/Ruby.Console.csproj | 13 ++++ Src/Ruby/Runtime/RubyUtils.cs | 5 +- Src/StdLib/ironruby/rbconfig.rb | 9 ++- .../ruby/4.0/rubygems/defaults/ironruby.rb | 21 ++--- Util/package-release.sh | 8 +- igem.cmd | 4 +- igem.sh | 4 +- iirb.cmd | 4 +- iirb.sh | 2 +- ir.cmd | 50 +----------- ir.sh | 75 +----------------- irb.cmd | 4 +- irb.sh | 4 +- ironruby | 77 +++++++++++++++++++ ironruby.cmd | 47 +++++++++++ irubyc.cmd | 4 +- irubyc.sh | 4 +- 20 files changed, 211 insertions(+), 166 deletions(-) create mode 100755 ironruby create mode 100644 ironruby.cmd diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 54e6fea15..d6c054025 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -190,11 +190,22 @@ jobs: require "rake" puts "rexml #{REXML::VERSION}, csv #{CSV::VERSION}, rake #{Rake::VERSION}" RUBY + # ironruby is the launcher, as jruby is JRuby's; RbConfig.ruby has to be a file, + # since libraries spawn it, and ir is the short name, which has to keep working. + cat > names.rb <<'RUBY' + abort "ruby_install_name: #{RbConfig::CONFIG["ruby_install_name"]}" unless RbConfig::CONFIG["ruby_install_name"] == "ironruby" + abort "no #{RbConfig.ruby}" unless File.file?(RbConfig.ruby) + puts "#{RbConfig.ruby} exists" + RUBY if [ "$RUNNER_OS" = Windows ]; then - cmd //c ir.cmd smoke.rb - cmd //c ir.cmd Util/windows-desktop-check.rb + cmd //c ironruby.cmd smoke.rb + cmd //c ironruby.cmd names.rb + cmd //c ir.cmd -e "puts RUBY_ENGINE" + cmd //c ironruby.cmd Util/windows-desktop-check.rb else - ./ir.sh smoke.rb + ./ironruby smoke.rb + ./ironruby names.rb + ./ir.sh -e 'puts RUBY_ENGINE' fi # IO#write_nonblock on a socket claims only what the kernel took (#14). On Linux the diff --git a/Docs/rails-on-windows.md b/Docs/rails-on-windows.md index 4b024dc00..d40907d47 100644 --- a/Docs/rails-on-windows.md +++ b/Docs/rails-on-windows.md @@ -43,7 +43,9 @@ CRuby, the CSRF meta tags are there, and a POST without a token is refused with `ruby_install_name`, which is `ir`, so they start `#!/usr/bin/env ir.exe"`; like MRI, the command line and prism skip a `#!` line without "ruby" in it. A `#!` line naming IronRuby's own launcher now counts as Ruby. `RubyUtils.ShebangNamesIronRuby`, `RubyCommandLine.cs`, - `PrismAstBridge.cs`. + `PrismAstBridge.cs`. Since then the launcher is called `ironruby`, as JRuby's is `jruby`, + and so is `ruby_install_name`: new binstubs say `#!/usr/bin/env ironruby` and need no + special case; this one keeps those written with `ir` running. 5. **`TZInfo::DataSourceNotFound` in the first initializer.** Windows has no zoneinfo, so the Gemfile has `gem "tzinfo-data", platforms: %i[windows jruby]`; Bundler filters such gems by the *generic* platform, and IronRuby's `universal-dotnet` is generic `ruby`. For the dotnet diff --git a/README.md b/README.md index 68dd06745..83528109f 100644 --- a/README.md +++ b/README.md @@ -90,15 +90,18 @@ IronRuby. `io/console` is a C extension in CRuby, so IronRuby implements it over Scripts run the same way, and gems install with real TLS: ```console -$ ./ir.sh script.rb # prism front end, vendored stdlib, JIT and OSR on -$ ./igem.sh install rack # or: ./ir.sh -S gem install rack -$ ./ir.sh -S bundle install +$ ./ironruby script.rb # prism front end, vendored stdlib, JIT and OSR on +$ ./igem.sh install rack # or: ./ironruby -S gem install rack +$ ./ironruby -S bundle install ``` -`ir` / `igem` / `iirb` / `irubyc` are the i-prefixed names IronRuby has used since 1.x, so -they can sit on `PATH` beside CRuby's `ruby` and `gem` — the same reason JRuby ships -`jruby`, `jgem`, `jirb` and `jrubyc`. The unprefixed `gem`, `irb`, `bundle`, `bundler` and -`irubyc` live in `Src/StdLib/bin` and are what `ir -S ` finds. +The interpreter is `ironruby` (`ironruby.cmd` on Windows), as JRuby's is `jruby`: it is +RbConfig's `ruby_install_name`, so the binstubs RubyGems, Bundler and Rails write start +`#!/usr/bin/env ironruby` - a `#!` line with "ruby" in it, which Ruby runs as Ruby. `ir.sh` +and `ir.cmd` are its short name, the one IronRuby has used since 1.x, and run the same thing. +`igem` / `iirb` / `irubyc` keep the i-prefix so they can sit on `PATH` beside CRuby's `gem` +and `irb`, as JRuby's `jgem`, `jirb` and `jrubyc` do. The unprefixed `gem`, `irb`, `bundle`, +`bundler` and `irubyc` live in `Src/StdLib/bin` and are what `ironruby -S ` finds. ```ruby # all of this runs today @@ -497,12 +500,12 @@ one and run the launchers in it: ```console $ tar xzf ironruby-4.0.1-linux-x64.tar.gz && cd ironruby-4.0.1-linux-x64 -$ ./ir.sh -e 'puts RUBY_DESCRIPTION' +$ ./ironruby -e 'puts RUBY_DESCRIPTION' $ ./irb.sh $ ./igem.sh install rack ``` -On Windows, unzip it and use `ir.cmd`, `irb.cmd` and `igem.cmd`, or double-click +On Windows, unzip it and use `ironruby.cmd`, `irb.cmd` and `igem.cmd`, or double-click `Samples\Notepad\notepad.cmd`. The archive has the same layout as a checkout, with the Release build in `Src/Console/bin/Release/net8.0`, so everything above applies to it unchanged. `irubyc` works too, but it still needs the .NET SDK to compile the application. diff --git a/Src/Console/Ruby.Console.csproj b/Src/Console/Ruby.Console.csproj index 250d2d750..3da18b55b 100644 --- a/Src/Console/Ruby.Console.csproj +++ b/Src/Console/Ruby.Console.csproj @@ -32,6 +32,19 @@ file this process has LOCK_EX'd. Turn the emulation off. --> + + + + + + + diff --git a/Src/Ruby/Runtime/RubyUtils.cs b/Src/Ruby/Runtime/RubyUtils.cs index 1255c24f6..ab7af1649 100644 --- a/Src/Ruby/Runtime/RubyUtils.cs +++ b/Src/Ruby/Runtime/RubyUtils.cs @@ -1971,8 +1971,9 @@ public static bool IsRubyThreadExit(Exception e) { /// Whether the first line of a script is a #! line that runs IronRuby's own launcher. MRI /// and prism take a #! line without "ruby" in it as the start of some other program and /// look further down for the Ruby one; but RubyGems and Rails write binstubs from - /// RbConfig's ruby_install_name, which is "ir", so `rails new` starts bin/rails with - /// "#!/usr/bin/env ir.exe" - a Ruby script that does not say "ruby". + /// RbConfig's ruby_install_name, which was "ir", so `rails new` started bin/rails with + /// "#!/usr/bin/env ir.exe" - a Ruby script that does not say "ruby". It is "ironruby" + /// now, which does; this keeps the binstubs written before that running. /// public static bool ShebangNamesIronRuby(string/*!*/ code) { if (code == null || !code.StartsWith("#!", StringComparison.Ordinal)) { diff --git a/Src/StdLib/ironruby/rbconfig.rb b/Src/StdLib/ironruby/rbconfig.rb index ca1cf5fc1..0a1414ce8 100644 --- a/Src/StdLib/ironruby/rbconfig.rb +++ b/Src/StdLib/ironruby/rbconfig.rb @@ -39,9 +39,12 @@ module RbConfig CONFIG["RUBY_PROGRAM_VERSION"] = RUBY_VERSION.dup CONFIG["RUBY_API_VERSION"] = "#{CONFIG["MAJOR"]}.#{CONFIG["MINOR"]}" CONFIG["EXEEXT"] = windows ? ".exe" : "" - # This value is used by libraries to spawn new processes to run Ruby scripts. Hence it needs to match the ir.exe name - CONFIG["ruby_install_name"] = "ir" - CONFIG["RUBY_INSTALL_NAME"] = "ir" + # Libraries spawn RbConfig.ruby to run Ruby scripts, so this has to be a file in bindir: + # the build puts an ironruby apphost beside ir (Ruby.Console.csproj). And RubyGems and + # Bundler write it into binstubs as `#!/usr/bin/env ironruby`, which the ironruby + # launcher answers - a #! line with "ruby" in it, as JRuby's "jruby" is. + CONFIG["ruby_install_name"] = "ironruby" + CONFIG["RUBY_INSTALL_NAME"] = "ironruby" CONFIG["RUBY_SO_NAME"] = "IronRuby" CONFIG["PATH_SEPARATOR"] = File::PATH_SEPARATOR.dup diff --git a/Src/StdLib/ruby/4.0/rubygems/defaults/ironruby.rb b/Src/StdLib/ruby/4.0/rubygems/defaults/ironruby.rb index de29bea5b..7c9fd80c1 100644 --- a/Src/StdLib/ruby/4.0/rubygems/defaults/ironruby.rb +++ b/Src/StdLib/ruby/4.0/rubygems/defaults/ironruby.rb @@ -227,11 +227,12 @@ def self.path end ## - # RbConfig.ruby names the `ir` apphost, which starts without the -X:StdLib + # RbConfig.ruby names the `ironruby` apphost, which starts without the -X:StdLib # argument that gives it Ruby 4's standard library. RubyGems and # Bundler shell out to Gem.ruby to run binstubs and extconf.rb, so point it - # at the ir.sh (ir.cmd on Windows) wrapper next to the source tree when there - # is one. + # at the ironruby (ironruby.cmd on Windows) launcher next to the source tree + # when there is one - or at ir.sh (ir.cmd), its short name, in a tree from + # before the launcher was called ironruby. def self.ruby @ruby ||= begin @@ -239,9 +240,8 @@ def self.ruby begin # /Src/StdLib/ruby/4.0/rubygems/defaults/ironruby.rb -> root = File.expand_path("../../../../../..", __dir__) - name = Gem.win_platform? ? "ir.cmd" : "ir.sh" - candidate = File.join(root, name) - wrapper = candidate if File.file?(candidate) + names = Gem.win_platform? ? %w[ironruby.cmd ir.cmd] : %w[ironruby ir.sh] + wrapper = names.map { |name| File.join(root, name) }.find { |candidate| File.file?(candidate) } rescue StandardError wrapper = nil end @@ -254,10 +254,11 @@ def self.ruby ## # A binstub RubyGems writes gets `#!/usr/bin/env ` by - # default, and RbConfig's ruby_install_name here is "ir" - the apphost, which - # is not on PATH and which would start without the arguments that make it a - # Ruby 4 interpreter anyway. Turn the env shebang off for every install, so - # the line becomes `#!`, the ir.sh wrapper. That also makes + # default, and RbConfig's ruby_install_name here is "ironruby" - which is the + # launcher only where its directory is on PATH, and otherwise the apphost, + # which would start without the arguments that make it a Ruby 4 interpreter. + # Turn the env shebang off for every install, so the line becomes + # `#!`, the ironruby launcher. That also makes # Bundler's CLI::Exec#ruby_shebang? recognise the binstub - it matches # "#!#{Gem.ruby}" - so `bundle exec ` loads it in this process # instead of exec'ing it into whatever `ruby` is on PATH. diff --git a/Util/package-release.sh b/Util/package-release.sh index e897ff80e..6708ae3d5 100755 --- a/Util/package-release.sh +++ b/Util/package-release.sh @@ -37,8 +37,8 @@ dotnet publish "$IR_ROOT/Src/Console/Ruby.Console.csproj" \ rm -f "$STAGE/Src/Console/bin/Release/$IR_TFM"/*.pdb case "$RID" in - win-*) launchers=(ir.cmd irb.cmd igem.cmd iirb.cmd irubyc.cmd) ;; - *) launchers=(ir.sh irb.sh igem.sh iirb.sh irubyc.sh) ;; + win-*) launchers=(ironruby.cmd ir.cmd irb.cmd igem.cmd iirb.cmd irubyc.cmd) ;; + *) launchers=(ironruby ir.sh irb.sh igem.sh iirb.sh irubyc.sh) ;; esac for f in "${launchers[@]}" README.md; do cp "$IR_ROOT/$f" "$STAGE/" @@ -112,9 +112,9 @@ esac # that Windows Forms and WPF load from it, which a missing framework reference breaks # without breaking anything else. case "$RID" in - win-*) (cd "$STAGE" && cmd //c ir.cmd -e 'puts RUBY_DESCRIPTION' && + win-*) (cd "$STAGE" && cmd //c ironruby.cmd -e 'puts RUBY_DESCRIPTION' && cmd //c ir.cmd -e 'puts RUBY_ENGINE' && cmd //c ir.cmd "$(cygpath -w "$IR_ROOT/Util/windows-desktop-check.rb")") ;; - *) "$STAGE/ir.sh" -e 'puts RUBY_DESCRIPTION' ;; + *) "$STAGE/ironruby" -e 'puts RUBY_DESCRIPTION' && "$STAGE/ir.sh" -e 'puts RUBY_ENGINE' ;; esac cd "$OUT" diff --git a/igem.cmd b/igem.cmd index 70c2049ec..341bfe741 100644 --- a/igem.cmd +++ b/igem.cmd @@ -1,3 +1,3 @@ @echo off -rem IronRuby's gem on Windows. The same thing as `ir.cmd -S gem`. -"%~dp0ir.cmd" -S gem %* +rem IronRuby's gem on Windows. The same thing as `ironruby.cmd -S gem`. +"%~dp0ironruby.cmd" -S gem %* diff --git a/igem.sh b/igem.sh index 4af817ff1..fc56efed0 100755 --- a/igem.sh +++ b/igem.sh @@ -1,7 +1,7 @@ #!/bin/sh -# IronRuby's gem. The same thing as `./ir.sh -S gem`, under the i-prefixed name +# IronRuby's gem. The same thing as `./ironruby -S gem`, under the i-prefixed name # IronRuby has used since 1.x -- the point of the prefix is co-installation: when # CRuby is also on PATH, plain `gem` is ambiguous. (JRuby ships jgem for the same # reason, alongside its unprefixed bin/gem.) IR_ROOT="$(dirname "$(readlink -f "$0")")" -exec "$IR_ROOT/ir.sh" -S gem "$@" +exec "$IR_ROOT/ironruby" -S gem "$@" diff --git a/iirb.cmd b/iirb.cmd index c843085a9..55dc7c6c8 100644 --- a/iirb.cmd +++ b/iirb.cmd @@ -1,3 +1,3 @@ @echo off -rem IronRuby's irb on Windows, i-prefixed. Same as irb.cmd / `ir.cmd -S irb`. -"%~dp0ir.cmd" -S irb %* +rem IronRuby's irb on Windows, i-prefixed. Same as irb.cmd / `ironruby.cmd -S irb`. +"%~dp0ironruby.cmd" -S irb %* diff --git a/iirb.sh b/iirb.sh index 15e82bc44..464ad8844 100755 --- a/iirb.sh +++ b/iirb.sh @@ -2,4 +2,4 @@ # IronRuby's irb under the i-prefixed name (IronRuby 1.x shipped iirb.bat; JRuby # ships jirb). irb.sh is the same thing under the plainer name. IR_ROOT="$(dirname "$(readlink -f "$0")")" -exec "$IR_ROOT/ir.sh" -S irb "$@" +exec "$IR_ROOT/ironruby" -S irb "$@" diff --git a/ir.cmd b/ir.cmd index fe51087d0..b3724ceee 100644 --- a/ir.cmd +++ b/ir.cmd @@ -1,46 +1,4 @@ -@echo off -rem Runs the built ir with the prism front end and the bundled standard library. -rem The Windows twin of ir.sh; see it for why each switch is here. -rem -rem ir.cmd -e "puts RUBY_DESCRIPTION" -rem set RUBY_EXE=%CD%\ir.cmd -rem -setlocal -set "IR_ROOT=%~dp0" -if "%IR_ROOT:~-1%"=="\" set "IR_ROOT=%IR_ROOT:~0,-1%" - -rem IR_CONFIG=Release runs the optimized build instead. Debug stays the default, -rem exactly as in ir.sh. -rem A binary release (Util/package-release.sh) ships only the Release build: when -rem IR_CONFIG is not set and there is no Debug build, run that one. -if "%IR_CONFIG%"=="" if not exist "%IR_ROOT%\Src\Console\bin\Debug\" if exist "%IR_ROOT%\Src\Console\bin\Release\" set "IR_CONFIG=Release" -if "%IR_CONFIG%"=="" set "IR_CONFIG=Debug" - -rem IR_TFM picks the target framework out of the multi-targeted build (net8.0;net10.0), -rem exactly as in ir.sh. net8.0 stays the default. -if "%IR_TFM%"=="" set "IR_TFM=net8.0" - -rem A tree built on Windows puts ir.exe straight in %IR_TFM%; one cross-published from -rem Linux with -r win-x64 puts it in %IR_TFM%\win-x64. Take whichever exists. -set "IR_BIN=%IR_ROOT%\Src\Console\bin\%IR_CONFIG%\%IR_TFM%\win-x64\ir.exe" -if not exist "%IR_BIN%" set "IR_BIN=%IR_ROOT%\Src\Console\bin\%IR_CONFIG%\%IR_TFM%\ir.exe" -if not exist "%IR_BIN%" ( - echo ir.cmd: no %IR_CONFIG% build at %IR_BIN% 1>&2 - echo ir.cmd: build it with: dotnet build Src\Console\Ruby.Console.csproj -c %IR_CONFIG% -r win-x64 --self-contained false 1>&2 - exit /b 127 -) - -set "S=%IR_ROOT%\Src\StdLib" - -rem -S searches RUBYPATH before PATH, so `ir.cmd -S irb` runs the irb shipped here. -rem The directory ir.exe is in comes next: it is RubyGems' bindir (RbConfig's bindir), -rem where `igem install` writes the binstubs of installed gems, so `ir.cmd -S ` finds the one written for IronRuby before a host Ruby's - as in ir.sh. -for %%I in ("%IR_BIN%") do set "IR_BINDIR=%%~dpI" -set "IR_BINDIR=%IR_BINDIR:~0,-1%" -if "%RUBYPATH%"=="" (set "RUBYPATH=%S%\bin;%IR_BINDIR%") else (set "RUBYPATH=%S%\bin;%IR_BINDIR%;%RUBYPATH%") - -rem -X:StdLib is split on Path.PathSeparator, which is ';' on Windows - a ':' list would -rem be cut apart at every drive letter. -"%IR_BIN%" "-X:StdLib=%S%\ironruby;%S%\ruby\4.0" %* -exit /b %ERRORLEVEL% +@echo off +rem The short name for ironruby.cmd, which it runs with the same arguments. Not `call`: +rem that would double every ^ in them. +"%~dp0ironruby.cmd" %* diff --git a/ir.sh b/ir.sh index 1ab7f70f6..01edfbaf8 100755 --- a/ir.sh +++ b/ir.sh @@ -1,74 +1,3 @@ #!/bin/sh -# Runs the built ir with the prism front end and the bundled standard library. -# Used as RUBY_EXE when running ruby/spec: -# -# RUBY_EXE=./ir.sh ./ir.sh -Imspec/lib mspec/bin/mspec-run spec/language -# -IR_ROOT="$(dirname "$(readlink -f "$0")")" - -# apphost needs DOTNET_ROOT when the SDK isn't on the default search path -if [ -z "$DOTNET_ROOT" ] && [ -x /usr/local/dotnet/dotnet ]; then - DOTNET_ROOT=/usr/local/dotnet - export DOTNET_ROOT -fi - -# IronRuby's own library (the core prelude and what MRI implements as C -# extensions) comes first, then Ruby 4.0's standard library. -X:StdLib puts them -# on $LOAD_PATH after -I, RUBYOPT's -I and RUBYLIB, where MRI keeps its own -# library directories. -S="$IR_ROOT/Src/StdLib" -# IR_CONFIG=Release runs the optimized build instead (build it with -# `dotnet build Src/Console/Ruby.Console.csproj -c Release ...`). It is about 1.8x -# faster across Util/bench - the Debug build is compiled with optimizations off, which -# marks the assemblies non-optimizable, so the JIT leaves the whole runtime unoptimized -# too - and it passes the same specs and the same IronRuby.Tests. Util/run-tests.sh and -# regen-initializers.sh read IR_CONFIG as well, so one export covers a whole session. -# Debug stays the default because every worktree and every agent script builds it. -# A binary release (Util/package-release.sh) ships only the Release build: when -# IR_CONFIG is not set and there is no Debug build, run that one. -if [ -z "$IR_CONFIG" ]; then - IR_CONFIG=Debug - if [ ! -x "$IR_ROOT/Src/Console/bin/Debug/${IR_TFM:-net8.0}/ir" ] && - [ -x "$IR_ROOT/Src/Console/bin/Release/${IR_TFM:-net8.0}/ir" ]; then - IR_CONFIG=Release - fi -fi - -# IR_TFM picks the target framework, the same way IR_CONFIG picks the configuration. The -# tree multi-targets net8.0;net10.0 (Directory.Build.props), so one `dotnet build` leaves -# both side by side and IR_TFM=net10.0 runs the same IL on the .NET 10 runtime. net8.0 -# stays the default: it is what every worktree, agent script and baseline was taken on. -: "${IR_TFM:=net8.0}" - -IR_BIN="$IR_ROOT/Src/Console/bin/$IR_CONFIG/$IR_TFM/ir" -# Say which configuration is missing rather than let the shell's "not found" - which a -# filtered spec log swallows - be the only clue. Getting IR_CONFIG=Release past a tree -# that has only ever been built Debug is the whole reason this check is here. -if [ ! -x "$IR_BIN" ]; then - echo "ir.sh: no $IR_CONFIG build at $IR_BIN" >&2 - if [ "$IR_CONFIG" = "R2R" ]; then - # Not a build configuration: a ReadyToRun publish, which starts about 0.45s - # faster than Release because IronRuby's own assemblies are already native. - echo "ir.sh: build it with: IR_TFM=$IR_TFM Util/publish-r2r.sh" >&2 - else - echo "ir.sh: build it with: dotnet build Src/Console/Ruby.Console.csproj -c $IR_CONFIG -p:DlrSourceDir=..." >&2 - echo "ir.sh: (that builds every framework in IronRubyTargetFrameworks, including $IR_TFM)" >&2 - fi - exit 127 -fi - -# -S searches RUBYPATH before PATH; Src/StdLib/bin holds the executables the -# bundled library ships (irb), so `./ir.sh -S irb` runs IronRuby's own rather -# than whatever binstub happens to be on PATH. The directory ir itself is in -# is RubyGems' bindir here (RbConfig's bindir), where `igem install` writes the -# binstubs of installed gems; it comes next, so `./ir.sh -S ` -# finds the binstub written for IronRuby before a host Ruby's version of the -# same command - or a version manager's shim, which is a native executable and -# not a script at all. An existing RUBYPATH is searched after both - IronRuby's -# own commands come first, as they always have for Src/StdLib/bin - and still -# beats PATH for anything not found here. ir.cmd uses the same order. -RUBYPATH="$S/bin:$(dirname "$IR_BIN")${RUBYPATH:+:$RUBYPATH}" -export RUBYPATH - -exec "$IR_BIN" \ - "-X:StdLib=$S/ironruby:$S/ruby/4.0" "$@" +# The short name for ./ironruby, which it runs with the same arguments. +exec "$(dirname "$(readlink -f "$0")")/ironruby" "$@" diff --git a/irb.cmd b/irb.cmd index 7a017b887..06b6ac600 100644 --- a/irb.cmd +++ b/irb.cmd @@ -1,3 +1,3 @@ @echo off -rem IronRuby's irb on Windows. The same thing as `ir.cmd -S irb`. -"%~dp0ir.cmd" -S irb %* +rem IronRuby's irb on Windows. The same thing as `ironruby.cmd -S irb`. +"%~dp0ironruby.cmd" -S irb %* diff --git a/irb.sh b/irb.sh index 8a299c80d..763f35571 100755 --- a/irb.sh +++ b/irb.sh @@ -1,5 +1,5 @@ #!/bin/sh -# IronRuby's irb. The same thing as `./ir.sh -S irb`, which also works; this is +# IronRuby's irb. The same thing as `./ironruby -S irb`, which also works; this is # here so that starting a REPL does not need to know about -S. IR_ROOT="$(dirname "$(readlink -f "$0")")" -exec "$IR_ROOT/ir.sh" -S irb "$@" +exec "$IR_ROOT/ironruby" -S irb "$@" diff --git a/ironruby b/ironruby new file mode 100755 index 000000000..ddaa1bae4 --- /dev/null +++ b/ironruby @@ -0,0 +1,77 @@ +#!/bin/sh +# Runs the built ir with the prism front end and the bundled standard library. +# It is called ironruby as JRuby's is called jruby: RbConfig's ruby_install_name, and so +# the `#!/usr/bin/env ironruby` of every binstub RubyGems and Bundler write, names it, and +# a #! line with "ruby" in it is one Ruby runs. ir.sh is the short name for it. +# Used as RUBY_EXE when running ruby/spec: +# +# RUBY_EXE=./ironruby ./ironruby -Imspec/lib mspec/bin/mspec-run spec/language +# +IR_ROOT="$(dirname "$(readlink -f "$0")")" + +# apphost needs DOTNET_ROOT when the SDK isn't on the default search path +if [ -z "$DOTNET_ROOT" ] && [ -x /usr/local/dotnet/dotnet ]; then + DOTNET_ROOT=/usr/local/dotnet + export DOTNET_ROOT +fi + +# IronRuby's own library (the core prelude and what MRI implements as C +# extensions) comes first, then Ruby 4.0's standard library. -X:StdLib puts them +# on $LOAD_PATH after -I, RUBYOPT's -I and RUBYLIB, where MRI keeps its own +# library directories. +S="$IR_ROOT/Src/StdLib" +# IR_CONFIG=Release runs the optimized build instead (build it with +# `dotnet build Src/Console/Ruby.Console.csproj -c Release ...`). It is about 1.8x +# faster across Util/bench - the Debug build is compiled with optimizations off, which +# marks the assemblies non-optimizable, so the JIT leaves the whole runtime unoptimized +# too - and it passes the same specs and the same IronRuby.Tests. Util/run-tests.sh and +# regen-initializers.sh read IR_CONFIG as well, so one export covers a whole session. +# Debug stays the default because every worktree and every agent script builds it. +# A binary release (Util/package-release.sh) ships only the Release build: when +# IR_CONFIG is not set and there is no Debug build, run that one. +if [ -z "$IR_CONFIG" ]; then + IR_CONFIG=Debug + if [ ! -x "$IR_ROOT/Src/Console/bin/Debug/${IR_TFM:-net8.0}/ir" ] && + [ -x "$IR_ROOT/Src/Console/bin/Release/${IR_TFM:-net8.0}/ir" ]; then + IR_CONFIG=Release + fi +fi + +# IR_TFM picks the target framework, the same way IR_CONFIG picks the configuration. The +# tree multi-targets net8.0;net10.0 (Directory.Build.props), so one `dotnet build` leaves +# both side by side and IR_TFM=net10.0 runs the same IL on the .NET 10 runtime. net8.0 +# stays the default: it is what every worktree, agent script and baseline was taken on. +: "${IR_TFM:=net8.0}" + +IR_BIN="$IR_ROOT/Src/Console/bin/$IR_CONFIG/$IR_TFM/ir" +# Say which configuration is missing rather than let the shell's "not found" - which a +# filtered spec log swallows - be the only clue. Getting IR_CONFIG=Release past a tree +# that has only ever been built Debug is the whole reason this check is here. +if [ ! -x "$IR_BIN" ]; then + echo "ironruby: no $IR_CONFIG build at $IR_BIN" >&2 + if [ "$IR_CONFIG" = "R2R" ]; then + # Not a build configuration: a ReadyToRun publish, which starts about 0.45s + # faster than Release because IronRuby's own assemblies are already native. + echo "ironruby: build it with: IR_TFM=$IR_TFM Util/publish-r2r.sh" >&2 + else + echo "ironruby: build it with: dotnet build Src/Console/Ruby.Console.csproj -c $IR_CONFIG -p:DlrSourceDir=..." >&2 + echo "ironruby: (that builds every framework in IronRubyTargetFrameworks, including $IR_TFM)" >&2 + fi + exit 127 +fi + +# -S searches RUBYPATH before PATH; Src/StdLib/bin holds the executables the +# bundled library ships (irb), so `./ironruby -S irb` runs IronRuby's own rather +# than whatever binstub happens to be on PATH. The directory ir itself is in +# is RubyGems' bindir here (RbConfig's bindir), where `igem install` writes the +# binstubs of installed gems; it comes next, so `./ironruby -S ` +# finds the binstub written for IronRuby before a host Ruby's version of the +# same command - or a version manager's shim, which is a native executable and +# not a script at all. An existing RUBYPATH is searched after both - IronRuby's +# own commands come first, as they always have for Src/StdLib/bin - and still +# beats PATH for anything not found here. ironruby.cmd uses the same order. +RUBYPATH="$S/bin:$(dirname "$IR_BIN")${RUBYPATH:+:$RUBYPATH}" +export RUBYPATH + +exec "$IR_BIN" \ + "-X:StdLib=$S/ironruby:$S/ruby/4.0" "$@" diff --git a/ironruby.cmd b/ironruby.cmd new file mode 100644 index 000000000..207132afd --- /dev/null +++ b/ironruby.cmd @@ -0,0 +1,47 @@ +@echo off +rem Runs the built ir with the prism front end and the bundled standard library. +rem The Windows twin of ironruby; see it for why each switch is here, and for the name. +rem ir.cmd is the short name for it. +rem +rem ironruby.cmd -e "puts RUBY_DESCRIPTION" +rem set RUBY_EXE=%CD%\ironruby.cmd +rem +setlocal +set "IR_ROOT=%~dp0" +if "%IR_ROOT:~-1%"=="\" set "IR_ROOT=%IR_ROOT:~0,-1%" + +rem IR_CONFIG=Release runs the optimized build instead. Debug stays the default, +rem exactly as in ironruby. +rem A binary release (Util/package-release.sh) ships only the Release build: when +rem IR_CONFIG is not set and there is no Debug build, run that one. +if "%IR_CONFIG%"=="" if not exist "%IR_ROOT%\Src\Console\bin\Debug\" if exist "%IR_ROOT%\Src\Console\bin\Release\" set "IR_CONFIG=Release" +if "%IR_CONFIG%"=="" set "IR_CONFIG=Debug" + +rem IR_TFM picks the target framework out of the multi-targeted build (net8.0;net10.0), +rem exactly as in ironruby. net8.0 stays the default. +if "%IR_TFM%"=="" set "IR_TFM=net8.0" + +rem A tree built on Windows puts ir.exe straight in %IR_TFM%; one cross-published from +rem Linux with -r win-x64 puts it in %IR_TFM%\win-x64. Take whichever exists. +set "IR_BIN=%IR_ROOT%\Src\Console\bin\%IR_CONFIG%\%IR_TFM%\win-x64\ir.exe" +if not exist "%IR_BIN%" set "IR_BIN=%IR_ROOT%\Src\Console\bin\%IR_CONFIG%\%IR_TFM%\ir.exe" +if not exist "%IR_BIN%" ( + echo ironruby.cmd: no %IR_CONFIG% build at %IR_BIN% 1>&2 + echo ironruby.cmd: build it with: dotnet build Src\Console\Ruby.Console.csproj -c %IR_CONFIG% -r win-x64 --self-contained false 1>&2 + exit /b 127 +) + +set "S=%IR_ROOT%\Src\StdLib" + +rem -S searches RUBYPATH before PATH, so `ironruby.cmd -S irb` runs the irb shipped here. +rem The directory ir.exe is in comes next: it is RubyGems' bindir (RbConfig's bindir), +rem where `igem install` writes the binstubs of installed gems, so `ironruby.cmd -S ` finds the one written for IronRuby before a host Ruby's - as in ironruby. +for %%I in ("%IR_BIN%") do set "IR_BINDIR=%%~dpI" +set "IR_BINDIR=%IR_BINDIR:~0,-1%" +if "%RUBYPATH%"=="" (set "RUBYPATH=%S%\bin;%IR_BINDIR%") else (set "RUBYPATH=%S%\bin;%IR_BINDIR%;%RUBYPATH%") + +rem -X:StdLib is split on Path.PathSeparator, which is ';' on Windows - a ':' list would +rem be cut apart at every drive letter. +"%IR_BIN%" "-X:StdLib=%S%\ironruby;%S%\ruby\4.0" %* +exit /b %ERRORLEVEL% diff --git a/irubyc.cmd b/irubyc.cmd index 4ac7df5e1..5cea92574 100644 --- a/irubyc.cmd +++ b/irubyc.cmd @@ -1,4 +1,4 @@ @echo off -rem IronRuby's ahead-of-time compiler on Windows. The same thing as `ir.cmd -S irubyc`. +rem IronRuby's ahead-of-time compiler on Windows. The same thing as `ironruby.cmd -S irubyc`. rem Needs the .NET SDK; see irubyc.sh and `irubyc --help`. -"%~dp0ir.cmd" -S irubyc %* +"%~dp0ironruby.cmd" -S irubyc %* diff --git a/irubyc.sh b/irubyc.sh index 74c8461bd..2d9386692 100755 --- a/irubyc.sh +++ b/irubyc.sh @@ -1,6 +1,6 @@ #!/bin/sh # IronRuby's ahead-of-time compiler, the analogue of JRuby's jrubyc. The same -# thing as `./ir.sh -S irubyc`, under the i-prefixed name IronRuby has used +# thing as `./ironruby -S irubyc`, under the i-prefixed name IronRuby has used # since 1.x (see igem.sh for why the prefix is there). # # ./irubyc.sh -t /tmp/out app.rb lib/ @@ -10,4 +10,4 @@ # Ruby sources in the resulting assembly. The Ruby itself is still compiled by # IronRuby at startup -- irubyc does not emit IL for it. See --help. IR_ROOT="$(dirname "$(readlink -f "$0")")" -exec "$IR_ROOT/ir.sh" -S irubyc "$@" +exec "$IR_ROOT/ironruby" -S irubyc "$@" From ccb5fbfd27062b094154250c80b21422697353ed Mon Sep 17 00:00:00 2001 From: Largo Date: Wed, 28 Oct 2026 11:34:20 +0100 Subject: [PATCH 2/6] Release: render the launch video only when asked for It rendered on every release tag and on every pull request that touched the packaging - about 7 minutes each, for a video that rarely changes. Now only a run by hand renders it: render_video keeps it as an artifact, and video_for renders it and puts it, with its SHA256SUMS line, on a release - which also adds it to one published without. A release publishes the archives alone, and a change to media/launch no longer starts the workflow. --- .github/workflows/release.yml | 25 ++++++++++++++++--------- 1 file changed, 16 insertions(+), 9 deletions(-) diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index eb2fb1ebd..0fd995761 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -1,12 +1,14 @@ name: Release # Binary builds: a self-contained IronRuby for each platform, made by -# Util/package-release.sh, and the launch video, rendered from media/launch. Pushing a -# tag v* publishes them as a GitHub release (a pre-release while the version has a -# suffix such as -preview1), with Docs/releases/.md as the notes when there is one; -# running the workflow by hand, or a pull request that changes the packaging or the -# video, only keeps them as workflow artifacts. Run by hand with video_for set to a tag, -# it renders only the video and replaces it, and its SHA256SUMS line, on that release. +# Util/package-release.sh. Pushing a tag v* publishes them as a GitHub release (a +# pre-release while the version has a suffix such as -preview1), with +# Docs/releases/.md as the notes when there is one; running the workflow by hand, or +# a pull request that changes the packaging, only keeps them as workflow artifacts. +# The launch video, rendered from media/launch, is only rendered when asked for by hand - +# it takes about 7 minutes of every run otherwise: with render_video it is kept as an +# artifact, and with video_for set to a tag it alone is rendered and replaces the video, +# and its SHA256SUMS line, on that release (or adds them to one published without). on: push: tags: ['v*'] @@ -14,9 +16,13 @@ on: paths: - .github/workflows/release.yml - Util/package-release.sh - - media/launch/** workflow_dispatch: inputs: + render_video: + description: Render the launch video as well, as a workflow artifact + type: boolean + required: false + default: false video_for: description: Render only the launch video and replace it on this release (a tag, such as v4.0.0) required: false @@ -157,6 +163,7 @@ jobs: # does not render does not hold the archives back. video: name: launch video + if: github.event_name == 'workflow_dispatch' && (inputs.render_video || inputs.video_for != '') runs-on: ubuntu-latest continue-on-error: true # A render takes about 7 minutes; a failed one can leave hyperframes waiting. @@ -208,7 +215,7 @@ jobs: release: name: GitHub release if: github.ref_type == 'tag' - needs: [package, video] + needs: package runs-on: ubuntu-latest permissions: contents: write @@ -217,7 +224,7 @@ jobs: with: sparse-checkout: Docs/releases - # ironruby-* only: the archives and the video, not the review stills. + # ironruby-* only: the archives, not the review stills (the video is not rendered here). - uses: actions/download-artifact@v8 with: path: dist From 970e223db2422c10ecabc31b01c8bd6dca67cab8 Mon Sep 17 00:00:00 2001 From: Largo Date: Wed, 28 Oct 2026 11:43:36 +0100 Subject: [PATCH 3/6] ironruby with no script reads the program from stdin, as ruby does With neither -e nor a script, ruby reads the program from stdin until EOF, at a terminal as well, and $0 is "-"; JRuby does the same. IronRuby started the DLR's interactive console at a terminal instead - not irb, with Microsoft's banner and an (ir) prompt - and left $0 nil when it read stdin. The options parser now gives "-" in that case, as if it had been typed, so RubyCommandLine's existing "-" path reads stdin and $0 is "-". irb is `irb` / `iirb`. irw, which has no console to read from, still shows its help; it does not build on master either (Microsoft.Build.Utilities.v4.0). --- Src/Ruby/Hosting/RubyCommandLine.cs | 10 +++++----- Src/Ruby/Hosting/RubyOptionsParser.cs | 15 +++++++++++++++ Src/WinConsole/Program.cs | 3 ++- 3 files changed, 22 insertions(+), 6 deletions(-) diff --git a/Src/Ruby/Hosting/RubyCommandLine.cs b/Src/Ruby/Hosting/RubyCommandLine.cs index 54a264ebc..2f9ef5ba7 100644 --- a/Src/Ruby/Hosting/RubyCommandLine.cs +++ b/Src/Ruby/Hosting/RubyCommandLine.cs @@ -82,11 +82,11 @@ protected override int Run() { } } - // `ruby` with no -e and no script argument reads the program from stdin when - // stdin is redirected. Only a real terminal gets the interactive loop — and - // the banner that goes with it. A script argument of "-" says to read stdin - // outright, whether or not it is redirected, and is how the CRuby test suite - // runs a program in a child process; ARGV is what follows it. + // A script argument of "-" says to read the program from stdin, and is how the CRuby + // test suite runs a program in a child process; ARGV is what follows it. The options + // parser gives "-" when there is neither -e nor a script, so `ironruby` alone reads + // stdin as `ruby` does - at a terminal too, until EOF. A host that skips the parser + // and gives neither still gets stdin when it is redirected. if (Options.Command == null && (Options.FileName == "-" || (Options.FileName == null && System.Console.IsInputRedirected))) { // The program is read as bytes: a magic comment may say they are not UTF-8, and diff --git a/Src/Ruby/Hosting/RubyOptionsParser.cs b/Src/Ruby/Hosting/RubyOptionsParser.cs index b9dee8f11..38240c6cc 100644 --- a/Src/Ruby/Hosting/RubyOptionsParser.cs +++ b/Src/Ruby/Hosting/RubyOptionsParser.cs @@ -30,6 +30,12 @@ namespace IronRuby.Hosting { public sealed class RubyConsoleOptions : ConsoleOptions { public string ChangeDirectory; public bool DisplayVersion; + + /// + /// Neither -e nor a script was given, so the program is read from stdin, as if "-" had + /// been (FileName is "-"). A host without a console - irw - shows its help instead. + /// + public bool ProgramFromStdinByDefault; } public sealed class RubyOptionsParser : OptionsParser { @@ -842,6 +848,15 @@ protected override void AfterParse() { ConsoleOptions.PrintVersion = true; ConsoleOptions.Exit = true; } + + // `ruby` with neither -e nor a script reads the program from stdin until EOF - at a + // terminal too - as if "-" had been given, and $0 is "-" (MRI, JRuby). IronRuby used to + // start the DLR's interactive console there; irb is `irb` / `iirb`. + if (!ConsoleOptions.Exit && ConsoleOptions.Command == null && ConsoleOptions.FileName == null) { + ConsoleOptions.FileName = "-"; + ConsoleOptions.ProgramFromStdinByDefault = true; + LanguageSetup.Options["MainFile"] = "-"; + } } /// diff --git a/Src/WinConsole/Program.cs b/Src/WinConsole/Program.cs index 20d918e86..c6a2d4695 100644 --- a/Src/WinConsole/Program.cs +++ b/Src/WinConsole/Program.cs @@ -31,7 +31,8 @@ protected override ConsoleOptions ParseOptions(string/*!*/[]/*!*/ args, ScriptRu Environment.CurrentDirectory = rubyOptions.ChangeDirectory; } - if (rubyOptions.Introspection || rubyOptions.Command == null && rubyOptions.FileName == null) { + // without a script there is no console to read one from + if (rubyOptions.Introspection || rubyOptions.Command == null && (rubyOptions.FileName == null || rubyOptions.ProgramFromStdinByDefault)) { PrintHelp(); return null; } From db5b32c09383a33e407164123930c60479d26a4e Mon Sep 17 00:00:00 2001 From: Largo Date: Wed, 28 Oct 2026 11:53:30 +0100 Subject: [PATCH 4/6] ironrubyw.exe, as rubyw.exe and jrubyw.exe; remove the dead irw project ironrubyw.exe is the same ir.dll behind an apphost marked as a Windows GUI program, so Windows gives it no console window - for Windows Forms and WPF programs. The build makes it with the SDK's own CreateAppHost, as for a WinExe project, and publish puts it beside ir.exe, so the Windows archive ships it. Without a script it reads nothing from stdin and exits, as rubyw does. Samples/Notepad/notepad.cmd starts it, and needs the "start /b" workaround only for a build from before it. Src/WinConsole (irw.exe, irw64.exe) is gone: it had not built since the move to .NET (Microsoft.Build.Utilities.v4.0), nothing built or shipped it, and ironrubyw is what it was for. Ruby.sln no longer lists it. CI checks that ironrubyw.exe has the GUI subsystem and runs, and the release check that the Windows archive has it. --- .github/workflows/ci.yml | 10 + README.md | 3 + Ruby.sln | 24 --- Samples/Notepad/notepad.cmd | 19 +- Samples/Notepad/notepad.rb | 9 +- Src/Console/Ruby.Console.csproj | 16 ++ Src/Ruby/Hosting/RubyOptionsParser.cs | 10 +- Src/WinConsole/Program.cs | 56 ------ Src/WinConsole/Properties/AssemblyInfo.cs | 47 ----- Src/WinConsole/Ruby.WinConsole.csproj | 58 ------ Src/WinConsole/Ruby.WinConsole.ruleset | 213 ---------------------- Src/WinConsole/Ruby.WinConsoleAny.csproj | 56 ------ Util/package-release.sh | 3 +- 13 files changed, 50 insertions(+), 474 deletions(-) delete mode 100644 Src/WinConsole/Program.cs delete mode 100644 Src/WinConsole/Properties/AssemblyInfo.cs delete mode 100644 Src/WinConsole/Ruby.WinConsole.csproj delete mode 100644 Src/WinConsole/Ruby.WinConsole.ruleset delete mode 100644 Src/WinConsole/Ruby.WinConsoleAny.csproj diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index d6c054025..ebf14dc30 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -202,6 +202,16 @@ jobs: cmd //c ironruby.cmd names.rb cmd //c ir.cmd -e "puts RUBY_ENGINE" cmd //c ironruby.cmd Util/windows-desktop-check.rb + # ironrubyw.exe, as rubyw.exe: the same interpreter as a Windows GUI program (PE + # subsystem 2), so it gets no console window. It still writes to a pipe it is given. + cat > subsystem.rb <<'RUBY' + data = File.binread(ARGV[0], 4096) + subsystem = data[data[0x3c, 4].unpack1("V") + 24 + 68, 2].unpack1("v") + abort "#{ARGV[0]}: subsystem #{subsystem}" unless subsystem == 2 + RUBY + rubyw="Src/Console/bin/Debug/$TFM/ironrubyw.exe" + ruby subsystem.rb "$rubyw" + "$rubyw" -e 'require "set"; puts "ironrubyw: #{RUBY_ENGINE}"' | grep -x "ironrubyw: ironruby" else ./ironruby smoke.rb ./ironruby names.rb diff --git a/README.md b/README.md index 83528109f..ebb463106 100644 --- a/README.md +++ b/README.md @@ -102,6 +102,9 @@ and `ir.cmd` are its short name, the one IronRuby has used since 1.x, and run th `igem` / `iirb` / `irubyc` keep the i-prefix so they can sit on `PATH` beside CRuby's `gem` and `irb`, as JRuby's `jgem`, `jirb` and `jrubyc` do. The unprefixed `gem`, `irb`, `bundle`, `bundler` and `irubyc` live in `Src/StdLib/bin` and are what `ironruby -S ` finds. +On Windows the build also has `ironrubyw.exe` next to `ir.exe`, as CRuby has `rubyw.exe` and +JRuby `jrubyw.exe`: the same interpreter as a Windows GUI program, which gets no console +window - for Windows Forms and WPF programs; `Samples\Notepad\notepad.cmd` starts it. ```ruby # all of this runs today diff --git a/Ruby.sln b/Ruby.sln index 008a21e08..38b51d358 100644 --- a/Ruby.sln +++ b/Ruby.sln @@ -22,10 +22,6 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Ruby.ConsoleAny", "Src\Console\Ruby.ConsoleAny.csproj", "{6EE7A428-D803-41BC-8248-1297C3ACE369}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Ruby.WinConsole", "Src\WinConsole\Ruby.WinConsole.csproj", "{B17FEFC8-EA7C-4CFA-B46E-B9003CE1F329}" -EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Ruby.WinConsoleAny", "Src\WinConsole\Ruby.WinConsoleAny.csproj", "{F231EB3F-75E7-499F-B1F2-C26E56601E1B}" -EndProject Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Build", "Build", "{BBF4E796-17F9-4B55-A144-5CE412991105}" ProjectSection(SolutionItems) = preProject Build\After.targets = Build\After.targets @@ -126,26 +122,6 @@ Global {6EE7A428-D803-41BC-8248-1297C3ACE369}.v2Debug|Any CPU.Build.0 = v2Debug|Any CPU {6EE7A428-D803-41BC-8248-1297C3ACE369}.v2Release|Any CPU.ActiveCfg = v2Release|Any CPU {6EE7A428-D803-41BC-8248-1297C3ACE369}.v2Release|Any CPU.Build.0 = v2Release|Any CPU - {B17FEFC8-EA7C-4CFA-B46E-B9003CE1F329}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {B17FEFC8-EA7C-4CFA-B46E-B9003CE1F329}.Debug|Any CPU.Build.0 = Debug|Any CPU - {B17FEFC8-EA7C-4CFA-B46E-B9003CE1F329}.FxCop|Any CPU.ActiveCfg = FxCop|Any CPU - {B17FEFC8-EA7C-4CFA-B46E-B9003CE1F329}.FxCop|Any CPU.Build.0 = FxCop|Any CPU - {B17FEFC8-EA7C-4CFA-B46E-B9003CE1F329}.Release|Any CPU.ActiveCfg = Release|Any CPU - {B17FEFC8-EA7C-4CFA-B46E-B9003CE1F329}.Release|Any CPU.Build.0 = Release|Any CPU - {B17FEFC8-EA7C-4CFA-B46E-B9003CE1F329}.v2Debug|Any CPU.ActiveCfg = v2Debug|Any CPU - {B17FEFC8-EA7C-4CFA-B46E-B9003CE1F329}.v2Debug|Any CPU.Build.0 = v2Debug|Any CPU - {B17FEFC8-EA7C-4CFA-B46E-B9003CE1F329}.v2Release|Any CPU.ActiveCfg = v2Release|Any CPU - {B17FEFC8-EA7C-4CFA-B46E-B9003CE1F329}.v2Release|Any CPU.Build.0 = v2Release|Any CPU - {F231EB3F-75E7-499F-B1F2-C26E56601E1B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {F231EB3F-75E7-499F-B1F2-C26E56601E1B}.Debug|Any CPU.Build.0 = Debug|Any CPU - {F231EB3F-75E7-499F-B1F2-C26E56601E1B}.FxCop|Any CPU.ActiveCfg = FxCop|Any CPU - {F231EB3F-75E7-499F-B1F2-C26E56601E1B}.FxCop|Any CPU.Build.0 = FxCop|Any CPU - {F231EB3F-75E7-499F-B1F2-C26E56601E1B}.Release|Any CPU.ActiveCfg = Release|Any CPU - {F231EB3F-75E7-499F-B1F2-C26E56601E1B}.Release|Any CPU.Build.0 = Release|Any CPU - {F231EB3F-75E7-499F-B1F2-C26E56601E1B}.v2Debug|Any CPU.ActiveCfg = v2Debug|Any CPU - {F231EB3F-75E7-499F-B1F2-C26E56601E1B}.v2Debug|Any CPU.Build.0 = v2Debug|Any CPU - {F231EB3F-75E7-499F-B1F2-C26E56601E1B}.v2Release|Any CPU.ActiveCfg = v2Release|Any CPU - {F231EB3F-75E7-499F-B1F2-C26E56601E1B}.v2Release|Any CPU.Build.0 = v2Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE diff --git a/Samples/Notepad/notepad.cmd b/Samples/Notepad/notepad.cmd index 2ea5459c6..6665df23b 100644 --- a/Samples/Notepad/notepad.cmd +++ b/Samples/Notepad/notepad.cmd @@ -1,16 +1,21 @@ @echo off rem IronRuby Notepad. Double-click it, drop a file on it, or run: notepad.cmd file.txt rem -rem ir.exe is a console program, so Windows gives it a console window. "start /b" leaves -rem that console to ir.exe alone once this batch file has ended, and notepad.rb then -rem lets go of it, which closes the window. To keep the console for Ruby's output, run -rem ..\..\ir.cmd notepad.rb instead. The build is chosen as ir.cmd chooses it. +rem ironrubyw.exe is ironruby without a console window, as rubyw.exe is ruby's: a Windows +rem Forms program has no use for one. To keep a console for Ruby's output, run +rem ..\..\ironruby.cmd notepad.rb instead. The build is chosen as ironruby.cmd chooses it. +rem +rem A build from before ironrubyw has only ir.exe, a console program, which Windows gives +rem a console window: "start /b" leaves that console to ir.exe alone once this batch file +rem has ended, and notepad.rb then lets go of it, which closes the window. (Single-line +rem ifs: a dropped file name with a ")" in it would end a parenthesized block.) setlocal set "IR_ROOT=%~dp0..\.." if "%IR_CONFIG%"=="" if not exist "%IR_ROOT%\Src\Console\bin\Debug\" if exist "%IR_ROOT%\Src\Console\bin\Release\" set "IR_CONFIG=Release" if "%IR_CONFIG%"=="" set "IR_CONFIG=Debug" if "%IR_TFM%"=="" set "IR_TFM=net8.0" -set "IR_BIN=%IR_ROOT%\Src\Console\bin\%IR_CONFIG%\%IR_TFM%\win-x64\ir.exe" -if not exist "%IR_BIN%" set "IR_BIN=%IR_ROOT%\Src\Console\bin\%IR_CONFIG%\%IR_TFM%\ir.exe" +set "IR_DIR=%IR_ROOT%\Src\Console\bin\%IR_CONFIG%\%IR_TFM%\win-x64" +if not exist "%IR_DIR%\ir.exe" set "IR_DIR=%IR_ROOT%\Src\Console\bin\%IR_CONFIG%\%IR_TFM%" set "S=%IR_ROOT%\Src\StdLib" -start "" /b "%IR_BIN%" "-X:StdLib=%S%\ironruby;%S%\ruby\4.0" "%~dp0notepad.rb" %* +if exist "%IR_DIR%\ironrubyw.exe" start "" "%IR_DIR%\ironrubyw.exe" "-X:StdLib=%S%\ironruby;%S%\ruby\4.0" "%~dp0notepad.rb" %* +if not exist "%IR_DIR%\ironrubyw.exe" start "" /b "%IR_DIR%\ir.exe" "-X:StdLib=%S%\ironruby;%S%\ruby\4.0" "%~dp0notepad.rb" %* diff --git a/Samples/Notepad/notepad.rb b/Samples/Notepad/notepad.rb index 2a3b3b20f..3da5da63d 100644 --- a/Samples/Notepad/notepad.rb +++ b/Samples/Notepad/notepad.rb @@ -1,7 +1,7 @@ # IronRuby Notepad: Windows Notepad, written in Ruby, on IronRuby and Windows Forms. # -# notepad.cmd [file] double-click it, drop a file on it, or run it -# ..\..\ir.cmd notepad.rb [file] the same, keeping the console for Ruby's output +# notepad.cmd [file] double-click it, drop a file on it, or run it +# ..\..\ironruby.cmd notepad.rb [file] the same, keeping the console for Ruby's output # # What Notepad does, this does: New, New Window, Open, Save, Save As, Page Setup and # Print with a header and page numbers; Undo and Redo, Cut, Copy, Paste, Delete, Find, @@ -50,8 +50,9 @@ def self.caret_position D::Point.new(*point[0, 8].unpack("l2")) end - # ir.exe is a console program, so started from Explorer it gets a console window of - # its own. When nobody else is attached to it, let go of it: that closes the window. + # ir.exe and ironruby.exe are console programs, so started from Explorer they get a + # console window of their own. When nobody else is attached to it, let go of it: that + # closes the window. Under ironrubyw.exe, which notepad.cmd uses, there is none. def self.detach_console_if_alone list = Fiddle::Pointer.malloc(64) return unless CONSOLE_PROCESSES.call(list, 16) == 1 diff --git a/Src/Console/Ruby.Console.csproj b/Src/Console/Ruby.Console.csproj index 3da18b55b..05f7ff153 100644 --- a/Src/Console/Ruby.Console.csproj +++ b/Src/Console/Ruby.Console.csproj @@ -45,6 +45,22 @@ DestinationFiles="$(PublishDir)ironruby$(_NativeExecutableExtension)" Condition="Exists('$(PublishDir)$(AssemblyName)$(_NativeExecutableExtension)')" SkipUnchangedFiles="true" /> + + + + + + + diff --git a/Src/Ruby/Hosting/RubyOptionsParser.cs b/Src/Ruby/Hosting/RubyOptionsParser.cs index 38240c6cc..ffe713fcf 100644 --- a/Src/Ruby/Hosting/RubyOptionsParser.cs +++ b/Src/Ruby/Hosting/RubyOptionsParser.cs @@ -30,12 +30,6 @@ namespace IronRuby.Hosting { public sealed class RubyConsoleOptions : ConsoleOptions { public string ChangeDirectory; public bool DisplayVersion; - - /// - /// Neither -e nor a script was given, so the program is read from stdin, as if "-" had - /// been (FileName is "-"). A host without a console - irw - shows its help instead. - /// - public bool ProgramFromStdinByDefault; } public sealed class RubyOptionsParser : OptionsParser { @@ -851,10 +845,10 @@ protected override void AfterParse() { // `ruby` with neither -e nor a script reads the program from stdin until EOF - at a // terminal too - as if "-" had been given, and $0 is "-" (MRI, JRuby). IronRuby used to - // start the DLR's interactive console there; irb is `irb` / `iirb`. + // start the DLR's interactive console there; irb is `irb` / `iirb`. ironrubyw, which has + // no console, then reads nothing and exits, as rubyw does. if (!ConsoleOptions.Exit && ConsoleOptions.Command == null && ConsoleOptions.FileName == null) { ConsoleOptions.FileName = "-"; - ConsoleOptions.ProgramFromStdinByDefault = true; LanguageSetup.Options["MainFile"] = "-"; } } diff --git a/Src/WinConsole/Program.cs b/Src/WinConsole/Program.cs deleted file mode 100644 index c6a2d4695..000000000 --- a/Src/WinConsole/Program.cs +++ /dev/null @@ -1,56 +0,0 @@ -/* **************************************************************************** - * - * Copyright (c) Microsoft Corporation. - * - * This source code is subject to terms and conditions of the Apache License, Version 2.0. A - * copy of the license can be found in the License.html file at the root of this distribution. If - * you cannot locate the Apache License, Version 2.0, please send an email to - * ironruby@microsoft.com. By using this source code in any fashion, you are agreeing to be bound - * by the terms of the Apache License, Version 2.0. - * - * You must not remove this notice, or any other, from this software. - * - * - * ***************************************************************************/ - -using System; -using IronRuby.Hosting; -using IronRuby.Runtime; -using System.Windows.Forms; -using Microsoft.Scripting.Hosting.Shell; -using Microsoft.Scripting.Hosting; - -internal sealed class Host : RubyConsoleHost { - protected override ConsoleOptions ParseOptions(string/*!*/[]/*!*/ args, ScriptRuntimeSetup/*!*/ runtimeSetup, LanguageSetup/*!*/ languageSetup) { - var rubyOptions = (RubyConsoleOptions)base.ParseOptions(args, runtimeSetup, languageSetup); - if (rubyOptions == null) { - return null; - } - - if (rubyOptions.ChangeDirectory != null) { - Environment.CurrentDirectory = rubyOptions.ChangeDirectory; - } - - // without a script there is no console to read one from - if (rubyOptions.Introspection || rubyOptions.Command == null && (rubyOptions.FileName == null || rubyOptions.ProgramFromStdinByDefault)) { - PrintHelp(); - return null; - } - - return rubyOptions; - } - - protected override void ReportInvalidOption(InvalidOptionException e) { - MessageBox.Show(e.Message); - } - - [STAThread] - [RubyStackTraceHidden] - static int Main(string[] args) { - return new Host().Run(args); - } - - protected override void PrintHelp() { - MessageBox.Show(GetHelp(), "IronRuby Window Console Help"); - } -} \ No newline at end of file diff --git a/Src/WinConsole/Properties/AssemblyInfo.cs b/Src/WinConsole/Properties/AssemblyInfo.cs deleted file mode 100644 index b06e9f6a1..000000000 --- a/Src/WinConsole/Properties/AssemblyInfo.cs +++ /dev/null @@ -1,47 +0,0 @@ -/* **************************************************************************** - * - * Copyright (c) Microsoft Corporation. - * - * This source code is subject to terms and conditions of the Apache License, Version 2.0. A - * copy of the license can be found in the License.html file at the root of this distribution. If - * you cannot locate the Apache License, Version 2.0, please send an email to - * ironruby@microsoft.com. By using this source code in any fashion, you are agreeing to be bound - * by the terms of the Apache License, Version 2.0. - * - * You must not remove this notice, or any other, from this software. - * - * - * ***************************************************************************/ - -using System.Reflection; -using System.Runtime.CompilerServices; -using System.Runtime.InteropServices; -using IronRuby.Runtime; - -// General Information about an assembly is controlled through the following -// set of attributes. Change these attribute values to modify the information -// associated with an assembly. -[assembly: AssemblyTitle("RubyConsole")] -[assembly: AssemblyDescription("")] -[assembly: AssemblyConfiguration("")] -[assembly: AssemblyProduct("RubyConsole")] -[assembly: AssemblyTrademark("")] -[assembly: AssemblyCulture("")] - -// Setting ComVisible to false makes the types in this assembly not visible -// to COM components. If you need to access a type in this assembly from -// COM, set the ComVisible attribute to true on that type. -[assembly: ComVisible(false)] - -// The following GUID is for the ID of the typelib if this project is exposed to COM -[assembly: Guid("4fcc9697-d2dd-48a1-be74-41db600df98d")] - -// Version information for an assembly consists of the following four values: -// -// Major Version -// Minor Version -// Build Number -// Revision -// -//[assembly: AssemblyVersion(RubyContext.IronRubyVersionString)] -//[assembly: AssemblyFileVersion(RubyContext.IronRubyVersionString)] diff --git a/Src/WinConsole/Ruby.WinConsole.csproj b/Src/WinConsole/Ruby.WinConsole.csproj deleted file mode 100644 index d3fa9c3ce..000000000 --- a/Src/WinConsole/Ruby.WinConsole.csproj +++ /dev/null @@ -1,58 +0,0 @@ - - - - - 2.0 - {B17FEFC8-EA7C-4CFA-B46E-B9003CE1F329} - WinExe - Properties - IronRuby - irw - x86 - Ruby.WinConsole.ruleset - - - - - - - - - - - - - - - - - {77323B06-15A2-4CF4-8A7A-86EAA2B66498} - IronRuby.Libraries - - - {7F6984B4-EE6D-4E6F-ABB1-E210D7DC4FDD} - Ruby - - - - - - - Properties\AssemblyVersion.cs - - - - - - App.Debug.config - - - App.Release.config - - - - - - - - \ No newline at end of file diff --git a/Src/WinConsole/Ruby.WinConsole.ruleset b/Src/WinConsole/Ruby.WinConsole.ruleset deleted file mode 100644 index 9a2c075e1..000000000 --- a/Src/WinConsole/Ruby.WinConsole.ruleset +++ /dev/null @@ -1,213 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/Src/WinConsole/Ruby.WinConsoleAny.csproj b/Src/WinConsole/Ruby.WinConsoleAny.csproj deleted file mode 100644 index 779eb8887..000000000 --- a/Src/WinConsole/Ruby.WinConsoleAny.csproj +++ /dev/null @@ -1,56 +0,0 @@ - - - - - 2.0 - {F231EB3F-75E7-499F-B1F2-C26E56601E1B} - WinExe - Properties - IronRuby - irw64 - - - - - - - - - - - - - - - - - {77323B06-15A2-4CF4-8A7A-86EAA2B66498} - IronRuby.Libraries - - - {7F6984B4-EE6D-4E6F-ABB1-E210D7DC4FDD} - Ruby - - - - - - - Properties\AssemblyVersion.cs - - - - - - App.Debug.config - - - App.Release.config - - - - - - - - \ No newline at end of file diff --git a/Util/package-release.sh b/Util/package-release.sh index 6708ae3d5..23a5bb71b 100755 --- a/Util/package-release.sh +++ b/Util/package-release.sh @@ -112,7 +112,8 @@ esac # that Windows Forms and WPF load from it, which a missing framework reference breaks # without breaking anything else. case "$RID" in - win-*) (cd "$STAGE" && cmd //c ironruby.cmd -e 'puts RUBY_DESCRIPTION' && cmd //c ir.cmd -e 'puts RUBY_ENGINE' && + win-*) test -f "$STAGE/Src/Console/bin/Release/$IR_TFM/ironrubyw.exe" && + (cd "$STAGE" && cmd //c ironruby.cmd -e 'puts RUBY_DESCRIPTION' && cmd //c ir.cmd -e 'puts RUBY_ENGINE' && cmd //c ir.cmd "$(cygpath -w "$IR_ROOT/Util/windows-desktop-check.rb")") ;; *) "$STAGE/ironruby" -e 'puts RUBY_DESCRIPTION' && "$STAGE/ir.sh" -e 'puts RUBY_ENGINE' ;; esac From e4c9411ce8b09a6e61e62b617130aeda87611bec Mon Sep 17 00:00:00 2001 From: Largo Date: Wed, 28 Oct 2026 12:02:27 +0100 Subject: [PATCH 5/6] CI: move the subsystem check out of the if, where its heredoc never ended A heredoc ends at a line that is its delimiter alone, and inside the if the YAML block left that line indented, so bash read to the end of the script and every smoke test failed with "unexpected end of file". The script now writes subsystem.rb before the if, as it does names.rb. --- .github/workflows/ci.yml | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index ebf14dc30..312b4e241 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -197,18 +197,19 @@ jobs: abort "no #{RbConfig.ruby}" unless File.file?(RbConfig.ruby) puts "#{RbConfig.ruby} exists" RUBY + # ironrubyw.exe, as rubyw.exe: the same interpreter as a Windows GUI program (PE + # subsystem 2), so it gets no console window. It still writes to a pipe it is given. + # (A heredoc's end has to start its line, so this one is not inside the if.) + cat > subsystem.rb <<'RUBY' + data = File.binread(ARGV[0], 4096) + subsystem = data[data[0x3c, 4].unpack1("V") + 24 + 68, 2].unpack1("v") + abort "#{ARGV[0]}: subsystem #{subsystem}" unless subsystem == 2 + RUBY if [ "$RUNNER_OS" = Windows ]; then cmd //c ironruby.cmd smoke.rb cmd //c ironruby.cmd names.rb cmd //c ir.cmd -e "puts RUBY_ENGINE" cmd //c ironruby.cmd Util/windows-desktop-check.rb - # ironrubyw.exe, as rubyw.exe: the same interpreter as a Windows GUI program (PE - # subsystem 2), so it gets no console window. It still writes to a pipe it is given. - cat > subsystem.rb <<'RUBY' - data = File.binread(ARGV[0], 4096) - subsystem = data[data[0x3c, 4].unpack1("V") + 24 + 68, 2].unpack1("v") - abort "#{ARGV[0]}: subsystem #{subsystem}" unless subsystem == 2 - RUBY rubyw="Src/Console/bin/Debug/$TFM/ironrubyw.exe" ruby subsystem.rb "$rubyw" "$rubyw" -e 'require "set"; puts "ironrubyw: #{RUBY_ENGINE}"' | grep -x "ironrubyw: ironruby" From 836ef6afda41c6c73cc08bff9d3ed5cdd5072bce Mon Sep 17 00:00:00 2001 From: Largo Date: Wed, 28 Oct 2026 12:08:31 +0100 Subject: [PATCH 6/6] Address review: release check stops, ironrubyw incremental, docs - Util/package-release.sh: one check per line. set -e does not stop at a failure on the left of && (nor at a case whose last list failed that way), so a Windows archive without ironrubyw.exe, or a tree whose launcher did not start, was archived anyway. - release.yml: only a pushed tag publishes a release; a run by hand on a tag keeps its archives as artifacts, as the header says. - Ruby.Console.csproj: CreateIronRubyWAppHost has the SDK's Inputs and Outputs, so a build no longer rewrites ironrubyw.exe - which fails while Notepad runs under it. - ironruby.cmd: the missing-build message quotes the path, which a ")" (as in "Program Files (x86)") would otherwise end the block at. - README, rbconfig.rb, ironruby: Bundler and Rails write `#!/usr/bin/env ironruby`; RubyGems' own binstubs name the launcher by its path. The 4.0.1 instructions use ir.sh / ir.cmd, which that archive has. - media/launch/README.md: the film is rendered only by hand now. --- .github/workflows/release.yml | 3 ++- README.md | 14 +++++++++----- Src/Console/Ruby.Console.csproj | 3 +++ Src/StdLib/ironruby/rbconfig.rb | 7 ++++--- Util/package-release.sh | 17 +++++++++++++---- ironruby | 5 +++-- ironruby.cmd | 3 ++- media/launch/README.md | 9 +++++---- 8 files changed, 41 insertions(+), 20 deletions(-) diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 0fd995761..f4e9d44e4 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -214,7 +214,8 @@ jobs: release: name: GitHub release - if: github.ref_type == 'tag' + # A pushed tag only: a run by hand keeps its archives as artifacts, even on a tag. + if: github.event_name == 'push' && github.ref_type == 'tag' needs: package runs-on: ubuntu-latest permissions: diff --git a/README.md b/README.md index ebb463106..e88d31260 100644 --- a/README.md +++ b/README.md @@ -96,9 +96,11 @@ $ ./ironruby -S bundle install ``` The interpreter is `ironruby` (`ironruby.cmd` on Windows), as JRuby's is `jruby`: it is -RbConfig's `ruby_install_name`, so the binstubs RubyGems, Bundler and Rails write start -`#!/usr/bin/env ironruby` - a `#!` line with "ruby" in it, which Ruby runs as Ruby. `ir.sh` -and `ir.cmd` are its short name, the one IronRuby has used since 1.x, and run the same thing. +RbConfig's `ruby_install_name`, so the binstubs Bundler and Rails write start +`#!/usr/bin/env ironruby` - a `#!` line with "ruby" in it, which Ruby runs as Ruby. (Those +RubyGems writes for an installed gem name the launcher by its path instead, `#!/ironruby`, +so they only work where that path still does.) `ir.sh` and `ir.cmd` are its short name, the +one IronRuby has used since 1.x, and run the same thing. `igem` / `iirb` / `irubyc` keep the i-prefix so they can sit on `PATH` beside CRuby's `gem` and `irb`, as JRuby's `jgem`, `jirb` and `jrubyc` do. The unprefixed `gem`, `irb`, `bundle`, `bundler` and `irubyc` live in `Src/StdLib/bin` and are what `ironruby -S ` finds. @@ -503,12 +505,14 @@ one and run the launchers in it: ```console $ tar xzf ironruby-4.0.1-linux-x64.tar.gz && cd ironruby-4.0.1-linux-x64 -$ ./ironruby -e 'puts RUBY_DESCRIPTION' +$ ./ir.sh -e 'puts RUBY_DESCRIPTION' $ ./irb.sh $ ./igem.sh install rack ``` -On Windows, unzip it and use `ironruby.cmd`, `irb.cmd` and `igem.cmd`, or double-click +4.0.1 has `ir.sh` and `ir.cmd`; releases after it also have `ironruby` and `ironruby.cmd` +(see above), and `ir.sh` / `ir.cmd` keep working there. +On Windows, unzip it and use `ir.cmd`, `irb.cmd` and `igem.cmd`, or double-click `Samples\Notepad\notepad.cmd`. The archive has the same layout as a checkout, with the Release build in `Src/Console/bin/Release/net8.0`, so everything above applies to it unchanged. `irubyc` works too, but it still needs the .NET SDK to compile the application. diff --git a/Src/Console/Ruby.Console.csproj b/Src/Console/Ruby.Console.csproj index 05f7ff153..da74b56f5 100644 --- a/Src/Console/Ruby.Console.csproj +++ b/Src/Console/Ruby.Console.csproj @@ -49,7 +49,10 @@ apphost marked as a Windows GUI program, so Windows gives it no console window - for Windows Forms and WPF programs such as Samples/Notepad. It is the SDK's own CreateAppHost, as for a WinExe project. Only a Windows apphost has the flag. --> + &2 + echo ironruby.cmd: no %IR_CONFIG% build at "%IR_BIN%" 1>&2 echo ironruby.cmd: build it with: dotnet build Src\Console\Ruby.Console.csproj -c %IR_CONFIG% -r win-x64 --self-contained false 1>&2 exit /b 127 ) diff --git a/media/launch/README.md b/media/launch/README.md index d6009e108..fffd8c9de 100644 --- a/media/launch/README.md +++ b/media/launch/README.md @@ -47,7 +47,8 @@ npm run render # renders/ironruby-4-launch.mp4, 60 fps npm run preview # the HyperFrames studio, to scrub and edit ``` -`.github/workflows/release.yml` does the same on Ubuntu for every `v*` tag (and for pull -requests that touch this folder) and attaches the MP4 to the release. Run by hand with -`video_for: v4.0.0`, it renders only the film and replaces it on that release, along with -its line in `SHA256SUMS`. +`.github/workflows/release.yml` does the same on Ubuntu, but only when it is run by hand - +neither a `v*` tag nor a pull request renders the film. With `render_video` ticked it keeps +the MP4 as a workflow artifact; with `video_for: v4.0.0` it renders only the film and puts +it on that release, along with its line in `SHA256SUMS` (replacing the one there, or adding +both to a release published without it).