Top Level Namespace
- Extended by:
- Ruby2D::DSL
- Includes:
- Ruby2D
Defined Under Namespace
Modules: Ruby2D Classes: Module, String
Constant Summary collapse
- BUILD_DIR =
Our build output lives in
build/under the current directory, and a build wipes it first. A hidden marker lets a later build (or--clean) tell its own output from an unrelated, pre-existingbuild/— CMake, Meson, and many other tools default to that name — before deleting anything. 'build'- BUILD_MARKER =
File.join(BUILD_DIR, '.ruby2d')
- SDL3_STATIC_LIBS =
Whether all four SDL3 static archives are present in a lib dir
%w[libSDL3.a libSDL3_image.a libSDL3_mixer.a libSDL3_ttf.a].freeze
Constants included from Ruby2D
Ruby2D::Colour, Ruby2D::TextureAtlas, Ruby2D::VERSION
Instance Method Summary collapse
-
#abort_error(msg, spaced: false, indent: 0) ⇒ Object
Print an
Error:line and exit non-zero. -
#add_flags(type, flags) ⇒ Object
Add compiler and linker flags.
-
#add_ld_flags(ld_flags, name, type, dir = nil) ⇒ Object
Add linker flags.
-
#asset_directives(file) ⇒ Object
Collect the asset directories declared inline with
# ruby2d:assets <dir>directives in the app source — the flag-free equivalent of--assets, so an app can carry its own bundling instructions instead of relying on the caller to remember the flag. -
#build(targets, ruby2d_app) ⇒ Object
Build the user's application for one or more targets.
-
#bundled_platform_dir ⇒ Object
The bundled platform dir inside the gem — populated for RELEASE_PLATFORMS.
-
#cache_platform_dir ⇒ Object
The platform dir a
ruby2d setupbuild writes into, outside the gem. -
#cache_stamp_ok?(platform_dir) ⇒ Boolean
A
ruby2d setupcache build is stamped with the ruby2d version that produced it; only reuse it for a matching version (a gem upgrade may pin newer SDL, so stale cache libs must not be linked against this version's headers/sources). -
#check_asset_dir(dir) ⇒ Object
Validate an asset directory (from
--assetsor a# ruby2d:assetsdirective) before it's bundled. -
#clean_up(cmd = nil) ⇒ Object
Clean up the build directory.
-
#cmd_echo(cmd) ⇒ Object
Echo a command under
--debug, abbreviating the gem dir to keep it readable. -
#compile(ruby2d_app) ⇒ Object
Compile Ruby source to mruby bytecode and assemble into a single C file.
-
#compile_native ⇒ Object
Create a native executable using the available C compiler.
-
#compile_web ⇒ Object
Create a WebAssembly executable using Emscripten.
-
#create_macos_bundle ⇒ Object
Build an app bundle for macOS.
-
#deps_include_dir ⇒ Object
The SDL3 + mruby headers matching the resolved libraries (platform/include is a sibling of the per-target lib dir).
-
#deps_platform_dir ⇒ Object
The platform dir holding this target's static libs — bundled first, then a stamped cache build.
- #error(msg, spaced: false, indent: 0) ⇒ Object
-
#find_executable(name) ⇒ Object
Locate an executable on PATH.
-
#find_mrbc ⇒ Object
Find the
mrbcexecutable: prefer bundled assets, then aruby2d setupcache build, then $PATH. -
#launch_native ⇒ Object
Launch a native app, passing its stdio through so console output is visible.
-
#launch_web ⇒ Object
Launch a web app.
-
#native_target ⇒ Object
A friendly label for the host platform the native build targets (e.g. "macOS (arm64)").
- #note(msg, spaced: false, indent: 0) ⇒ Object
-
#refuse_if_foreign_build_dir ⇒ Object
Refuse to wipe
build/when it exists, holds files, and isn't ours — so runningruby2d buildin a project that already usesbuild/for something else can't silently delete it. -
#ruby2d_labeled(label, msg, spaced, indent) ⇒ Object
Compose a labeled line.
- #run_cmd(cmd) ⇒ Object
-
#serve(dir:, port: 8080, path: '') ⇒ Object
Serve a directory over HTTP and open it in the browser.
-
#setup(force: false, clean: false, yes: false) ⇒ Object
Build the native SDL3 + mruby static libraries for the current platform.
-
#setup_clean(yes: false) ⇒ Object
Remove this platform's cache build: the libraries, shared headers, and the regenerable intermediates and downloaded sources.
-
#setup_command?(cmd) ⇒ Boolean
Whether a command is on PATH.
-
#setup_confirm!(yes:) ⇒ Object
Ask before doing the involved work, after printing what it entails.
-
#setup_list_artifacts(dir) ⇒ Object
List the static libraries and binaries a build produced under
dir. -
#setup_pkg_config?(mod) ⇒ Boolean
Whether a pkg-config module's development files are installed.
-
#setup_platform_label ⇒ Object
A friendly label for the platform being built (e.g. "macOS (x86_64)").
-
#setup_preflight! ⇒ Object
Check the host build toolchain up front and, if something's missing, print a platform-specific hint and stop — rather than failing partway through a multi-minute build.
-
#setup_step(title) ⇒ Object
A ruby-red diamond banner, matching the
ruby2dCLI andrakeoutput. -
#setup_tildify(path) ⇒ Object
Abbreviate a home-relative path to
~/…for tidy, portable output. -
#shell_escape(path) ⇒ Object
Shell-escape a path for safe interpolation into a command string, so a gem or asset install location containing spaces (or other shell metacharacters) doesn't break the cc/emcc/mrbc invocations.
-
#skip_build(reason) ⇒ Object
Install without the native extension: write a do-nothing Makefile so
gem installstill completes, surface the recovery guidance, and exit cleanly. - #static_libs_present?(lib_dir) ⇒ Boolean
-
#step(title) ⇒ Object
Print a build-step banner — a ruby-red diamond and a bold title — to match the
ruby2dCLI andrakeoutput. -
#strip_require(file) ⇒ Object
Neutralize
require 'ruby2d'/require 'ruby2d/core'lines — the bundled build already provides Ruby2D. - #warning(msg, spaced: false, indent: 0) ⇒ Object
-
#wrote(path) ⇒ Object
List a file or bundle the build produced, beneath its step banner.
Methods included from Ruby2D::DSL
add_gamepad_mapping, clear, close, elapsed, gamepads, get, off, on, render, request_render, screenshot, set, show, update, window, window=, window?
Methods included from Ruby2D
assets, gem_dir, info, test_audio, test_images, test_media, test_spritesheets, warn
Instance Method Details
#abort_error(msg, spaced: false, indent: 0) ⇒ Object
Print an Error: line and exit non-zero. Writes to stderr rather than stdout,
and never returns — so it also reads correctly as the right-hand side of
system(cmd) || abort_error(...).
38 39 40 |
# File 'lib/ruby2d/cli/messages.rb', line 38 def abort_error(msg, spaced: false, indent: 0) abort ruby2d_labeled('Error:'.error, msg, spaced, indent) end |
#add_flags(type, flags) ⇒ Object
Add compiler and linker flags
9 10 11 12 13 14 |
# File 'ext/ruby2d/extconf.rb', line 9 def add_flags(type, flags) case type when :c then $CFLAGS << " #{flags} " when :ld then $LDFLAGS << " #{flags} " end end |
#add_ld_flags(ld_flags, name, type, dir = nil) ⇒ Object
Add linker flags
178 179 180 181 182 183 184 185 |
# File 'lib/ruby2d/cli/build.rb', line 178 def add_ld_flags(ld_flags, name, type, dir = nil) case type when :archive ld_flags << "#{shell_escape("#{dir}/lib#{name}.a")} " when :framework ld_flags << "-Wl,-framework,#{name} " end end |
#asset_directives(file) ⇒ Object
Collect the asset directories declared inline with # ruby2d:assets <dir>
directives in the app source — the flag-free equivalent of --assets, so an
app can carry its own bundling instructions instead of relying on the caller
to remember the flag. One directory per directive; repeat the line for
several. Paths are relative to the build's working directory, matching
--assets. Returns the directories in source order.
81 82 83 84 85 86 |
# File 'lib/ruby2d/cli/build.rb', line 81 def asset_directives(file) File.foreach(file).filter_map do |line| m = line.match(/\A\s*#\s*ruby2d:assets\s+(\S.*?)\s*\z/) m && m[1] end end |
#build(targets, ruby2d_app) ⇒ Object
Build the user's application for one or more targets
313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 |
# File 'lib/ruby2d/cli/build.rb', line 313 def build(targets, ruby2d_app) targets = [targets] unless targets.is_a?(Array) compile(ruby2d_app) # Asset directories to bundle: the `--assets` flag plus any `# ruby2d:assets # <dir>` directives in the app source. Each is bundled at its own relative # path — mounted into the WebAssembly virtual filesystem for the web build, # copied next to the executable for the native build. Validate once here so a # missing directory fails before either target starts compiling. @asset_dirs = ([@assets_dir] + asset_directives(ruby2d_app)).compact.uniq @asset_dirs.each { |dir| check_asset_dir(dir) } targets.each do |target| case target when :native compile_native when :web compile_web end end # Remove intermediate build files. `--debug` keeps them all — including the # assembled `build/app.c`, for anyone who wants to compile it themselves. unless @debug FileUtils.rm(Dir.glob('build/*.rb')) FileUtils.rm(Dir.glob('build/*.c')) end # Trailing blank line so the output isn't flush against the next shell prompt. puts end |
#bundled_platform_dir ⇒ Object
The bundled platform dir inside the gem — populated for RELEASE_PLATFORMS.
122 123 124 |
# File 'lib/ruby2d/cli/build.rb', line 122 def bundled_platform_dir AssetsTarget.platform_dir(root: Ruby2D.assets) end |
#cache_platform_dir ⇒ Object
The platform dir a ruby2d setup build writes into, outside the gem.
127 128 129 |
# File 'lib/ruby2d/cli/build.rb', line 127 def cache_platform_dir AssetsTarget.platform_dir(root: AssetsTarget.cache_root) end |
#cache_stamp_ok?(platform_dir) ⇒ Boolean
A ruby2d setup cache build is stamped with the ruby2d version that produced
it; only reuse it for a matching version (a gem upgrade may pin newer SDL, so
stale cache libs must not be linked against this version's headers/sources).
134 135 136 137 |
# File 'lib/ruby2d/cli/build.rb', line 134 def cache_stamp_ok?(dir) stamp = File.join(dir, '.ruby2d-version') File.exist?(stamp) && File.read(stamp).strip == Ruby2D::VERSION end |
#check_asset_dir(dir) ⇒ Object
Validate an asset directory (from --assets or a # ruby2d:assets directive)
before it's bundled. A missing dir aborts the build rather than ship an app
that can't find its assets. Both builds bundle the dir at the path given —
the web VFS mounts it there, the native build copies it there next to the
executable — so an absolute dir lands at that same absolute path, which the
relative references apps use won't find; warn rather than silently mislead.
451 452 453 454 455 456 457 458 459 460 |
# File 'lib/ruby2d/cli/build.rb', line 451 def check_asset_dir(dir) unless Dir.exist?(dir) error "asset directory not found: #{dir}" exit 1 end return unless File.absolute_path?(dir) warning "assets dir `#{dir}` is absolute, so it's bundled at that same " \ 'path. Reference it by that absolute path, or use a relative dir (e.g. `media`) instead.' end |
#clean_up(cmd = nil) ⇒ Object
Clean up the build directory
615 616 617 618 619 620 621 622 |
# File 'lib/ruby2d/cli/build.rb', line 615 def clean_up(cmd = nil) if cmd == :all refuse_if_foreign_build_dir step 'Cleaning build directory' FileUtils.rm_rf Dir.glob("#{BUILD_DIR}/*") puts end end |
#cmd_echo(cmd) ⇒ Object
Echo a command under --debug, abbreviating the gem dir to keep it readable.
Substitutes both the escaped and plain gem dir so it works whether or not the
path needed shell-escaping.
34 35 36 37 |
# File 'lib/ruby2d/cli/build.rb', line 34 def cmd_echo(cmd) display_cmd = cmd.gsub(shell_escape(Ruby2D.gem_dir), '$RUBY2D').gsub(Ruby2D.gem_dir, '$RUBY2D') puts " #{"$ #{display_cmd}".dim}\n\n" end |
#compile(ruby2d_app) ⇒ Object
Compile Ruby source to mruby bytecode and assemble into a single C file
213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 |
# File 'lib/ruby2d/cli/build.rb', line 213 def compile(ruby2d_app) # Check if source file provided is good if !ruby2d_app error 'Please provide a Ruby file to build.' exit 1 elsif !File.exist? ruby2d_app error "Can't find file: #{ruby2d_app}" exit 1 end # Add debugging information to produce backtrace debug_flag = @debug ? '-g' : '' # Clear and create build directory, refusing to wipe a foreign `build/` and # marking ours so later builds recognize it. refuse_if_foreign_build_dir FileUtils.rm_rf Dir.glob("#{BUILD_DIR}/*") FileUtils.mkdir_p BUILD_DIR FileUtils.touch BUILD_MARKER # Compiling Ruby to bytecode is a sub-second internal step with no artifact a # user runs — show its banner (and the `mrbc` echoes below) only with `--debug`. step "Compiling #{ruby2d_app}" if @debug # Assemble Ruby 2D library files into one '.rb' file ruby2d_lib_dir = "#{Ruby2D.gem_dir}/lib/ruby2d/" ruby2d_lib = '' @ruby2d_lib_files.each do |f| ruby2d_lib << File.read("#{ruby2d_lib_dir + f}.rb") + "\n\n" end # Make Ruby2D classes and DSL methods available at the top level ruby2d_lib << "include Ruby2D\nextend Ruby2D::DSL\n" File.write('build/ruby2d_lib.rb', ruby2d_lib) # Assemble the Ruby 2D C extension files into one '.c' file ruby2d_ext_dir = "#{Ruby2D.gem_dir}/ext/ruby2d/" ruby2d_ext = "#define MRUBY 1\n\n" c_files = Dir["#{ruby2d_ext_dir}*.c"].sort main_file = c_files.delete("#{ruby2d_ext_dir}ruby2d.c") c_files.unshift(main_file) if main_file c_files.each { |c_file| ruby2d_ext << File.read(c_file) } File.write('build/ruby2d_ext.c', ruby2d_ext) # Find the `mrbc` executable mrbc = find_mrbc unless mrbc error "Can't find `mrbc`, the mruby compiler." puts 'Run `ruby2d setup` to build it, or install mruby so `mrbc` is on your PATH.' exit 1 end # Compile the Ruby 2D lib (`.rb` files) to mruby bytecode. `run_cmd` doesn't # check the result, so do it here — a failure means the assembled bytecode # files won't exist, and the combine step below would crash on a missing file. run_cmd "#{shell_escape(mrbc)} #{debug_flag} -Bruby2d_lib -obuild/ruby2d_lib.c build/ruby2d_lib.rb" unless $?.success? error 'Failed to compile the Ruby 2D library.' exit 1 end # Stage the user's source (requires blanked — see strip_require) and compile it. # `mrbc` reports diagnostics against the path it's given, so capture its output # and rewrite the staging path back to the original filename: a syntax error # then points at `asteroids.rb:LINE`, the file the user wrote, not the internal # copy. Line numbers already line up because strip_require preserves them. staged = 'build/ruby2d_app.rb' File.write(staged, strip_require(ruby2d_app)) app_cmd = "#{shell_escape(mrbc)} #{debug_flag} -Bruby2d_app -obuild/ruby2d_app.c #{staged}" cmd_echo(app_cmd) if @debug app_output = `#{app_cmd} 2>&1` app_result = $? print app_output.gsub(staged) { ruby2d_app } unless app_output.empty? unless app_result.success? error "Failed to compile #{ruby2d_app}." puts 'Check the error above for syntax issues or Ruby features mruby does not support.' exit 1 end # Combine contents of C source files and bytecode into one file File.open('build/app.c', 'w') do |f| ['ruby2d_app', 'ruby2d_lib', 'ruby2d_ext'].each do |c_file| f << File.read("build/#{c_file}.c") << "\n\n" end end # `build/app.c` is an intermediate the native/web steps consume, not something # the user runs — surface it only with `--debug`, where it's also kept. wrote 'build/app.c' if @debug end |
#compile_native ⇒ Object
Create a native executable using the available C compiler
348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 |
# File 'lib/ruby2d/cli/build.rb', line 348 def compile_native # Get include directories incl_dir_ruby2d = "#{Ruby2D.gem_dir}/ext/ruby2d/" incl_dir_deps = deps_include_dir # Set C flags, if any c_flags = '' # Add library search directory ld_flags = '' # Dependent SDL archives before the base `libSDL3.a` so single-pass GNU ld # (MinGW on Windows, and Linux/BSD ld) resolves their symbols; mruby is # independent of SDL. Mirrors the order in ext/ruby2d/extconf.rb. libs = %w[mruby SDL3_image SDL3_mixer SDL3_ttf SDL3] if (platform_dir = deps_platform_dir) # Bundled or `ruby2d setup`-built static archives. macOS's ld64 is order-independent. ld_dir = File.join(platform_dir, 'lib') libs.each { |name| add_ld_flags(ld_flags, name, :archive, ld_dir) } else # No static libs for this target (Linux/BSD aren't in RELEASE_PLATFORMS and # `ruby2d setup` hasn't built them): link system-installed SDL3 + mruby, the # same fallback find_mrbc uses for `mrbc`. libs.each { |name| ld_flags << "-l#{name} " } end # Add compiler flags for each platform case AssetsTarget.host_os when 'macos' %w[AVFoundation AudioToolbox Carbon Cocoa CoreAudio CoreHaptics CoreMedia ForceFeedback GameController IOKit Metal QuartzCore UniformTypeIdentifiers].each do |name| add_ld_flags(ld_flags, name, :framework) end when 'windows' ld_flags << '-lgdi32 -lhid -limm32 -lole32 -loleaut32 -lrpcrt4 -lsetupapi -lusp10 -luuid -lversion -lwinmm -lws2_32' when 'linux', 'bsd' ld_flags << '-lm' end # Check for a C compiler up front so a missing toolchain gives a clear message # instead of a bare `failed` on exit 127 (like the `mrbc` check). A missing C # compiler is a hard error — native can't build without it — whereas a missing # `emcc` only skips the optional web build. Honor $CC if set, else default `cc`. cc = ENV['CC'] || 'cc' if find_executable(cc).nil? error "Can't find `#{cc}`, a C compiler. Install a C toolchain (e.g. Xcode Command Line Tools or build-essential) or set $CC." exit 1 end # Compile the app step 'Building native' puts " #{"for #{native_target}".dim}" FileUtils.mkdir_p 'build/native' run_cmd "#{shell_escape(cc)} #{c_flags} -I#{shell_escape(incl_dir_ruby2d)} -I#{shell_escape(incl_dir_deps)} build/app.c #{ld_flags} -o build/native/app" unless $?.success? error 'Native build failed.' unless deps_platform_dir puts "No bundled libraries for #{AssetsTarget.target_id}. Run `ruby2d setup` to build" puts 'them, or install SDL3 + mruby with your system package manager.' end exit 1 end # Bundle the default font next to the executable so apps using the built-in # font (`Text.new('…')` with no `font:`) resolve it at runtime. The native app # reads `ruby2d/fonts/…` relative to its working directory — which # `ruby2d launch --native` sets to `build/native` — mirroring the WASM preload. fonts_src = "#{Ruby2D.assets}/resources/fonts" if Dir.exist?(fonts_src) fonts_dest = 'build/native/ruby2d/fonts' FileUtils.mkdir_p fonts_dest FileUtils.cp_r "#{fonts_src}/.", fonts_dest end # Bundle each declared asset directory next to the executable — the native # counterpart to the web build's virtual-filesystem preload. The app resolves # them at runtime from its working directory (`build/native`, set by # `ruby2d launch --native`), so a dir mounts at the same relative path it was # given, matching how the app references it (`Image.new('media/x.png')`). @asset_dirs.each do |dir| dest = File.join('build/native', dir) FileUtils.mkdir_p File.dirname(dest) FileUtils.cp_r dir, dest end create_macos_bundle if AssetsTarget.host_os == 'macos' wrote 'build/native/app' wrote 'build/native/App.app' if AssetsTarget.host_os == 'macos' puts " #{'Run `ruby2d launch --native` to view'.dim}" end |
#compile_web ⇒ Object
Create a WebAssembly executable using Emscripten
464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 |
# File 'lib/ruby2d/cli/build.rb', line 464 def compile_web # When Emscripten is missing: skip the web build for a default `ruby2d build` # (so the native app still gets produced), but fail loudly when `--web` was # passed explicitly — the user asked for web specifically, so it shouldn't pass # silently (e.g. in `ruby2d build --web && deploy`). if find_executable('emcc').nil? if @web_explicit error "Can't find `emcc`. Install the Emscripten SDK and source emsdk_env.sh", spaced: true exit 1 end puts "\n #{'Skipping web build — Emscripten (emcc) not found'.dim}" return end step 'Building web' FileUtils.mkdir_p 'build/web' incl_dir_ruby2d = "#{Ruby2D.gem_dir}/ext/ruby2d/" incl_dir_deps = "#{Ruby2D.assets}/platform/include/" wasm_lib_dir = "#{Ruby2D.assets}/platform/wasm/lib" ld_flags = Dir["#{wasm_lib_dir}/*.a"].map { |f| shell_escape(f) }.join(' ') # Always bundle the default font for WASM builds fonts_dir = "#{Ruby2D.assets}/resources/fonts" preload_flag = "--preload-file #{shell_escape("#{fonts_dir}@ruby2d/fonts")}" # Bundle each requested asset directory — from `--assets` and any # `# ruby2d:assets` directive — into the virtual filesystem at its own path # (the `src@dst` map uses the same string for both). Validated in `build`. @asset_dirs.each { |dir| preload_flag += " --preload-file #{shell_escape("#{dir}@#{dir}")}" } # Faster page loads: restrict the JS glue to the browser environment (drops the # Node/worker probing) and, for release builds, minify it with Closure. Closure # is slow, so skip it for --debug (keep iteration fast and the glue readable); # the environment trim is cheap and always applied. web_opt_flags = '-sENVIRONMENT=web' web_opt_flags += ' --closure 1' unless @debug # The vendored wasm libmruby.a is built with MRB_NO_BOXING (floats inline in # mrb_value — the default 32-bit word boxing heap-allocates every Float). # The boxing mode is ABI: app.c includes the mruby headers, so it must define # the same mode or values are read with mismatched layouts at runtime. mruby_abi_flag = '-DMRB_NO_BOXING' # Start the wasm heap at 64MB instead of Emscripten's 16MB default. Growing # is kept as a safety valve, but each mid-game `memory.grow` detaches and # recopies the heap — a visible frame hitch — and reaching 64MB from 16MB # takes ~8 geometric growth steps scattered through early gameplay. Memory # isn't stored in the binary, so this doesn't change the download size; # browsers commit the pages lazily. memory_flags = '-sINITIAL_MEMORY=64MB -sALLOW_MEMORY_GROWTH' if @single_file # A custom template becomes Emscripten's shell file (it must contain the # `{{{ SCRIPT }}}` placeholder); otherwise emcc emits its default shell. shell_flag = @template ? "--shell-file #{shell_escape(@template)} " : '' run_cmd "emcc -O3 #{mruby_abi_flag} -I#{shell_escape(incl_dir_ruby2d)} -I#{shell_escape(incl_dir_deps)} "\ "-sUSE_SDL=0 -sSINGLE_FILE #{memory_flags} #{web_opt_flags} #{shell_flag}"\ "build/app.c #{ld_flags} #{preload_flag} "\ "-o build/web/app.html" unless $?.success? error 'Web build failed.' exit 1 end wrote 'build/web/app.html' else run_cmd "emcc -O3 #{mruby_abi_flag} -I#{shell_escape(incl_dir_ruby2d)} -I#{shell_escape(incl_dir_deps)} "\ "-sUSE_SDL=0 #{memory_flags} #{web_opt_flags} "\ "build/app.c #{ld_flags} #{preload_flag} "\ "-o build/web/app.js" unless $?.success? error 'Web build failed.' exit 1 end # Use the caller's template if given, else the bundled default. Either way # it must load `app.js` (see the bundled `template.html` for the contract). FileUtils.cp(@template || "#{Ruby2D.assets}/resources/web/template.html", 'build/web/app.html') wrote 'build/web/app.html' wrote 'build/web/app.js' wrote 'build/web/app.wasm' wrote 'build/web/app.data' end puts " #{'Run `ruby2d launch --web` to view'.dim}" end |
#create_macos_bundle ⇒ Object
Build an app bundle for macOS
556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 |
# File 'lib/ruby2d/cli/build.rb', line 556 def create_macos_bundle # Property list source for the bundle info_plist = %( <?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd"> <plist version="1.0"> <dict> <key>CFBundleExecutable</key> <string>app</string> <key>CFBundleIconFile</key> <string>app.icns</string> <key>CFBundleInfoDictionaryVersion</key> <string>6.0</string> <key>CFBundlePackageType</key> <string>APPL</string> <key>CFBundleVersion</key> <string>1</string> <key>NSHighResolutionCapable</key> <string>True</string> </dict> </plist> ) # Create directories FileUtils.mkpath 'build/native/App.app/Contents/MacOS' FileUtils.mkpath 'build/native/App.app/Contents/Resources' # Create Info.plist and copy over assets File.open('build/native/App.app/Contents/Info.plist', 'w') { |f| f.write(info_plist) } FileUtils.cp 'build/native/app', 'build/native/App.app/Contents/MacOS/' # Bundle the runtime resources (default font) next to the executable. The app # chdirs to its own directory at startup, so it resolves `ruby2d/fonts/…` # here when launched from Finder (where the working directory is otherwise `/`). if Dir.exist?('build/native/ruby2d') FileUtils.cp_r 'build/native/ruby2d', 'build/native/App.app/Contents/MacOS/' end # Bundle any declared asset directories (copied next to build/native/app # earlier) alongside the executable inside the bundle too, preserving their # relative paths, so a Finder-launched app resolves them the same way. @asset_dirs.each do |dir| src = File.join('build/native', dir) next unless Dir.exist?(src) dest = File.join('build/native/App.app/Contents/MacOS', dir) FileUtils.mkdir_p File.dirname(dest) FileUtils.cp_r src, dest end # Bundle the icon referenced by CFBundleIconFile (the Ruby 2D default), so the # plist's `app.icns` reference resolves instead of dangling. icon = "#{Ruby2D.assets}/resources/icons/icon.icns" FileUtils.cp icon, 'build/native/App.app/Contents/Resources/app.icns' if File.exist?(icon) end |
#deps_include_dir ⇒ Object
The SDL3 + mruby headers matching the resolved libraries (platform/include is a sibling of the per-target lib dir). Falls back to the bundled headers for the system-lib build, where they still describe the pinned API.
155 156 157 158 |
# File 'lib/ruby2d/cli/build.rb', line 155 def deps_include_dir dir = deps_platform_dir dir ? File.join(File.dirname(dir), 'include') : "#{Ruby2D.assets}/platform/include" end |
#deps_platform_dir ⇒ Object
The platform dir holding this target's static libs — bundled first, then a
stamped cache build. nil if neither has them, in which case the native build
links system-installed SDL3 + mruby (Linux/BSD, or before ruby2d setup).
142 143 144 145 146 147 148 149 150 |
# File 'lib/ruby2d/cli/build.rb', line 142 def deps_platform_dir bundled = bundled_platform_dir return bundled if File.exist?(File.join(bundled, 'lib', 'libSDL3.a')) cache = cache_platform_dir return cache if File.exist?(File.join(cache, 'lib', 'libSDL3.a')) && cache_stamp_ok?(cache) nil end |
#error(msg, spaced: false, indent: 0) ⇒ Object
23 24 25 |
# File 'lib/ruby2d/cli/messages.rb', line 23 def error(msg, spaced: false, indent: 0) puts ruby2d_labeled('Error:'.error, msg, spaced, indent) end |
#find_executable(name) ⇒ Object
Locate an executable on PATH. Portable replacement for which, which is
Unix-only (Windows cmd.exe has no which); tries Windows executable
extensions when running there.
92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 |
# File 'lib/ruby2d/cli/build.rb', line 92 def find_executable(name) exts = AssetsTarget.host_os == 'windows' ? ['.exe', '.bat', '.cmd', ''] : [''] # An explicit path (e.g. `CC=/usr/bin/clang`) is used as-is, not searched on # PATH — `File.join(dir, '/usr/bin/clang')` would collapse to a bogus path. if name.include?(File::SEPARATOR) || (File::ALT_SEPARATOR && name.include?(File::ALT_SEPARATOR)) exts.each do |ext| candidate = "#{name}#{ext}" return candidate if File.file?(candidate) && File.executable?(candidate) end return nil end ENV.fetch('PATH', '').split(File::PATH_SEPARATOR).each do |dir| next if dir.empty? exts.each do |ext| candidate = File.join(dir, "#{name}#{ext}") return candidate if File.file?(candidate) && File.executable?(candidate) end end nil end |
#find_mrbc ⇒ Object
Find the mrbc executable: prefer bundled assets, then a ruby2d setup cache
build, then $PATH.
162 163 164 165 166 167 168 169 170 171 172 173 174 |
# File 'lib/ruby2d/cli/build.rb', line 162 def find_mrbc name = AssetsTarget.host_os == 'windows' ? 'mrbc.exe' : 'mrbc' bundled = File.join(bundled_platform_dir, 'bin', name) return bundled if File.exist?(bundled) cache = cache_platform_dir cached_mrbc = File.join(cache, 'bin', name) return cached_mrbc if File.exist?(cached_mrbc) && cache_stamp_ok?(cache) # Fall back to system-installed mrbc find_executable('mrbc') end |
#launch_native ⇒ Object
Launch a native app, passing its stdio through so console output is visible.
16 17 18 19 20 21 22 23 24 25 |
# File 'lib/ruby2d/cli/launch.rb', line 16 def launch_native exe = AssetsTarget.host_os == 'windows' ? 'app.exe' : 'app' unless File.exist?("build/native/#{exe}") error 'No native app found. Run `ruby2d build --native` first.' exit 1 end # Run with the build dir as the working directory so the app resolves its # bundled media by relative path, the way the built app expects. system(File.("build/native/#{exe}"), chdir: 'build/native') end |
#launch_web ⇒ Object
Launch a web app
29 30 31 32 33 34 35 |
# File 'lib/ruby2d/cli/launch.rb', line 29 def launch_web unless File.exist?('build/web/app.html') error 'No web app found. Run `ruby2d build --web` first.' exit 1 end serve(dir: File.('build/web'), port: 8080, path: 'app.html') end |
#native_target ⇒ Object
A friendly label for the host platform the native build targets (e.g.
"macOS (arm64)"). ruby2d build doesn't cross-compile — the executable is for
this machine only — so naming it avoids the "is this a universal binary?" doubt.
57 58 59 60 61 |
# File 'lib/ruby2d/cli/build.rb', line 57 def native_target os = { 'macos' => 'macOS', 'windows' => 'Windows', 'linux' => 'Linux', 'bsd' => 'BSD' }.fetch(AssetsTarget.host_os, AssetsTarget.host_os) "#{os} (#{AssetsTarget.host_arch})" end |
#note(msg, spaced: false, indent: 0) ⇒ Object
31 32 33 |
# File 'lib/ruby2d/cli/messages.rb', line 31 def note(msg, spaced: false, indent: 0) puts ruby2d_labeled('Note:'.bold, msg, spaced, indent) end |
#refuse_if_foreign_build_dir ⇒ Object
Refuse to wipe build/ when it exists, holds files, and isn't ours — so
running ruby2d build in a project that already uses build/ for something
else can't silently delete it. Dir.glob skips the dotfile marker, so the
emptiness check and the delete target stay consistent.
199 200 201 202 203 204 205 206 207 |
# File 'lib/ruby2d/cli/build.rb', line 199 def refuse_if_foreign_build_dir return unless Dir.exist?(BUILD_DIR) return if File.exist?(BUILD_MARKER) return if Dir.glob("#{BUILD_DIR}/*").empty? error "A `#{BUILD_DIR}/` directory already exists here and wasn't created by Ruby 2D." puts 'Refusing to delete its contents. Remove it yourself, or run `ruby2d build` from a different directory.' exit 1 end |
#ruby2d_labeled(label, msg, spaced, indent) ⇒ Object
Compose a labeled line. spaced adds a blank line above, for a message that
interrupts a run of build output; indent matches the nesting of the output
around it (task bodies indent their results by four).
The ruby2d_ prefix keeps this clear of mkmf's own message, which is in
scope while extconf.rb runs.
19 20 21 |
# File 'lib/ruby2d/cli/messages.rb', line 19 def ruby2d_labeled(label, msg, spaced, indent) "#{"\n" if spaced}#{' ' * indent}#{label} #{msg}" end |
#run_cmd(cmd) ⇒ Object
26 27 28 29 |
# File 'lib/ruby2d/cli/build.rb', line 26 def run_cmd(cmd) cmd_echo(cmd) if @debug system cmd end |
#serve(dir:, port: 8080, path: '') ⇒ Object
Serve a directory over HTTP and open it in the browser. Backed by a minimal
socket-based server (no WEBrick dependency) — see static_server.rb.
10 11 12 |
# File 'lib/ruby2d/cli/launch.rb', line 10 def serve(dir:, port: 8080, path: '') Ruby2D::CLI::StaticServer.serve(dir: dir, port: port, path: path) end |
#setup(force: false, clean: false, yes: false) ⇒ Object
Build the native SDL3 + mruby static libraries for the current platform.
160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 |
# File 'lib/ruby2d/cli/setup.rb', line 160 def setup(force: false, clean: false, yes: false) if clean # `--clean` is standalone: it only removes. Say so rather than letting a # combined `--force` look like it did something (matches `build --clean`). note '`--clean` only removes the built libraries; `--force` was ignored.' if force return setup_clean(yes: yes) end target = AssetsTarget.target_id cache = AssetsTarget.cache_root cache_platform = AssetsTarget.platform_dir(root: cache) stamp = File.join(cache_platform, '.ruby2d-version') # Already provided? The gem bundles prebuilt libraries for RELEASE_PLATFORMS. bundled = AssetsTarget.platform_dir(root: Ruby2D.assets) bundled_exists = File.exist?(File.join(bundled, 'lib', 'libSDL3.a')) if !force && bundled_exists setup_step 'Native dependencies ready' puts " #{"#{setup_platform_label} — bundled with the gem".dim}" puts "\n Nothing to build. Run #{'ruby2d build --native <app>.rb'.bold} to build an app.\n\n" return end # Already built for this ruby2d version? Skip unless --force. built = File.exist?(File.join(cache_platform, 'lib', 'libSDL3.a')) && File.exist?(stamp) && File.read(stamp).strip == Ruby2D::VERSION if built && !force setup_step 'Native dependencies ready' puts " #{"#{setup_platform_label} — built at #{setup_tildify(cache_platform)}".dim}" puts "\n Already built. Re-run with #{'--force'.bold} to rebuild, or #{'ruby2d build --native <app>.rb'.bold} to build an app.\n\n" return end setup_preflight! # Header — surface the platform and cache location up front (again at the # end), spell out what the build entails, and confirm before starting: this # downloads sources, compiles for minutes, and rebuilds the installed gem. setup_step 'Set up native dependencies' puts puts " #{'Platform'.dim} #{setup_platform_label} #{"(#{target})".dim}" puts " #{'Location'.dim} #{setup_tildify(cache_platform)}" puts "\n #{'This will:'.bold}" if AssetsTarget.host_os == 'windows' puts ' • Offer to install any missing build tools (git, CMake) via MSYS2' end puts ' • Download the SDL3 and mruby sources with git' puts ' • Compile them into static libraries — this takes several minutes' puts " • Rebuild the Ruby 2D extension with #{'gem pristine ruby2d'.bold}" puts "\n Sources and build files go under the location above; only the last" puts ' step touches anything outside it.' # SDL links a lot of the system's development libraries — windowing, audio, # and more — and the full set is distro-specific and long, so point at SDL's # own list rather than trying to enumerate it. Preflight has already confirmed # the one hard requirement (X11 or Wayland); this covers the rest, whose # absence quietly disables features (e.g. no audio) instead of failing loudly. if AssetsTarget.host_os == 'linux' note "SDL builds against your system's development libraries — windowing,", spaced: true puts ' audio, and more. Install the packages for your distribution before continuing:' puts ' https://wiki.libsdl.org/SDL3/README-linux' end # Only `--force` gets here on a platform the gem already bundles, and a build # resolves bundled libraries first (see cli/build's deps_platform_dir) — so # this build won't be linked against. Worth saying before spending minutes on # it, rather than refusing: rebuilding is still a fair way to check the # pinned sources compile on this machine. if bundled_exists warning "This platform's libraries are bundled with the gem, and a", spaced: true puts " build prefers those — so #{'ruby2d build'.bold} won't link what this produces." end setup_confirm!(yes: yes) setup_step 'Building native dependencies' puts " #{'$ rake sdl mruby'.dim}\n\n" # Redirect sources, intermediates, and output to the cache so nothing is # written into the gem dir. Scope the override to the build subprocess (env # hash) so it doesn't leak into the `gem pristine` below — that step needs the # standard bundled -> cache resolution. The assets Rakefile carries the pinned # versions, the cmake/mruby build steps, and (on Windows) the pacman bootstrap. ok = Dir.chdir(Ruby2D.assets) do system({ 'RUBY2D_ASSETS_ROOT' => cache }, 'rake', 'sdl', 'mruby') end unless ok error 'Failed to build the native dependencies. See the output above.', spaced: true exit 1 end # Stamp the build so `ruby2d build` and extconf only link it against a matching # gem version — a later upgrade may pin newer SDL/mruby. File.write(stamp, Ruby2D::VERSION) setup_step 'Built the native dependencies' puts "\n #{"Native (#{target})".bold}" setup_list_artifacts(cache_platform) puts "\n Built to #{setup_tildify(cache_platform)}" # Build (or rebuild) the CRuby native extension through RubyGems' standard # path now that the libraries exist — extconf resolves this cache build. This # keeps the extension entirely on RubyGems' rails; setup builds no extension # itself. setup_step 'Building the Ruby 2D extension' puts " #{'$ gem pristine ruby2d'.dim}\n\n" if system('gem', 'pristine', 'ruby2d') puts "\n #{'Ready!'.bold} #{"require 'ruby2d'".bold} now works — run #{'ruby2d build --native <app>.rb'.bold} to build an app.\n\n" else warning "Couldn't rebuild the extension automatically.", spaced: true puts " Run #{'gem pristine ruby2d'.bold} yourself to finish.\n\n" end end |
#setup_clean(yes: false) ⇒ Object
Remove this platform's cache build: the libraries, shared headers, and the regenerable intermediates and downloaded sources.
132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 |
# File 'lib/ruby2d/cli/setup.rb', line 132 def setup_clean(yes: false) cache = AssetsTarget.cache_root platform = AssetsTarget.platform_dir(root: cache) # Nothing cached for this platform — say so rather than confirming a no-op. unless Dir.exist?(platform) setup_step 'Nothing to remove' puts " #{"no cached dependencies for #{setup_platform_label}".dim}" puts "\n #{setup_tildify(platform)} doesn't exist.\n\n" return end setup_step 'Remove cached dependencies' puts " #{"for #{setup_platform_label}".dim}" puts "\n This removes #{setup_tildify(platform)} and its build files." puts " Rebuilding them with #{'ruby2d setup'.bold} takes several minutes." setup_confirm!(yes: yes) [platform, AssetsTarget.include_dir(root: cache), AssetsTarget.build_dir(root: cache), AssetsTarget.sources_dir(root: cache)].each { |dir| FileUtils.rm_rf dir } puts "\n Removed #{setup_tildify(platform)}.\n\n" end |
#setup_command?(cmd) ⇒ Boolean
Whether a command is on PATH. Unix only — setup's preflight runs there; on Windows the assets Rakefile bootstraps git/cmake via MSYS2 pacman itself.
45 46 47 |
# File 'lib/ruby2d/cli/setup.rb', line 45 def setup_command?(cmd) system("command -v #{cmd} >/dev/null 2>&1") end |
#setup_confirm!(yes:) ⇒ Object
Ask before doing the involved work, after printing what it entails. Enter
accepts (the user asked for this by typing the command — the prompt is there
to surface the cost, not to second-guess). Skipped by --yes, and when stdin
isn't a TTY (CI, pipelines) where there's nobody to answer.
109 110 111 112 113 114 115 116 117 118 119 120 |
# File 'lib/ruby2d/cli/setup.rb', line 109 def setup_confirm!(yes:) return if yes || !$stdin.tty? print "\n Continue? #{'[Y/n]'.dim} " # A bare Enter accepts; EOF (Ctrl-D) does not — closing the input is a way # out of the prompt, not a way to start a multi-minute build. answer = $stdin.gets return if answer && (answer.strip.empty? || %w[y yes].include?(answer.strip.downcase)) puts "\n Cancelled.\n\n" exit 0 end |
#setup_list_artifacts(dir) ⇒ Object
List the static libraries and binaries a build produced under dir.
124 125 126 127 |
# File 'lib/ruby2d/cli/setup.rb', line 124 def setup_list_artifacts(dir) Dir.glob(File.join(dir, 'lib', '*.a')).map { |f| File.basename(f) }.sort.each { |f| puts " lib/#{f}" } Dir.glob(File.join(dir, 'bin', '*')).map { |f| File.basename(f) }.sort.each { |f| puts " bin/#{f}" } end |
#setup_pkg_config?(mod) ⇒ Boolean
Whether a pkg-config module's development files are installed. Used by the Linux preflight to find missing display libraries before SDL's CMake aborts on them — a wall of text several seconds into the build.
53 54 55 |
# File 'lib/ruby2d/cli/setup.rb', line 53 def setup_pkg_config?(mod) system("pkg-config --exists #{mod} >/dev/null 2>&1") end |
#setup_platform_label ⇒ Object
A friendly label for the platform being built (e.g. "macOS (x86_64)"). Reads the resolved target rather than the host: RUBY2D_ASSETS_OS/ARCH redirect setup at another platform's directory, and naming the host would then describe a build that isn't happening. Any toolchain is left to the target id printed alongside it.
28 29 30 31 32 33 |
# File 'lib/ruby2d/cli/setup.rb', line 28 def setup_platform_label os, arch, = AssetsTarget.resolved_target name = { 'macos' => 'macOS', 'windows' => 'Windows', 'linux' => 'Linux', 'bsd' => 'BSD' }.fetch(os, os) "#{name} (#{arch})" end |
#setup_preflight! ⇒ Object
Check the host build toolchain up front and, if something's missing, print a platform-specific hint and stop — rather than failing partway through a multi-minute build. No-op on Windows, where the assets Rakefile offers to install git/cmake via pacman during its own preflight.
62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 |
# File 'lib/ruby2d/cli/setup.rb', line 62 def setup_preflight! return if AssetsTarget.host_os == 'windows' cc = ENV['CC'] || 'cc' linux = AssetsTarget.host_os == 'linux' missing = [] missing << 'git' unless setup_command?('git') missing << 'cmake' unless setup_command?('cmake') missing << cc unless setup_command?(cc) # SDL's Linux build finds Wayland (and much else) through pkg-config, and the # display-library check below needs it to answer — so require it here. missing << 'pkg-config' if linux && !setup_command?('pkg-config') unless missing.empty? hint = case AssetsTarget.host_os when 'macos' 'Install the Xcode Command Line Tools (`xcode-select --install`) and CMake (`brew install cmake`).' when 'linux' 'Install a C toolchain, CMake, Git, and pkg-config — e.g. `sudo apt install build-essential cmake git pkg-config`.' else 'Install a C toolchain, CMake, and Git with your system package manager (e.g. `pkg install cmake git`).' end error "Missing build tools: #{missing.join(', ')}", spaced: true puts " #{hint}" exit 1 end # SDL won't build a desktop windowing backend without X11 or Wayland # development libraries; its CMake mirrors this exact check, but only after # cloning and configuring — so catch it here with a clean, actionable message # instead of that error's wall of text. pkg-config is guaranteed present # above, so it can answer for both. Linux only: the fix (apt packages, the # SDL wiki) is Debian-shaped, and BSD's expert audience is served by CMake's. if linux && !setup_pkg_config?('x11') && !setup_pkg_config?('wayland-client') error 'SDL needs X11 or Wayland development libraries; neither was found.', spaced: true puts " Install SDL's build dependencies for your distribution, then re-run #{'ruby2d setup'.bold}:" puts ' https://wiki.libsdl.org/SDL3/README-linux' exit 1 end end |
#setup_step(title) ⇒ Object
A ruby-red diamond banner, matching the ruby2d CLI and rake output.
18 19 20 |
# File 'lib/ruby2d/cli/setup.rb', line 18 def setup_step(title) puts "\n #{'◆'.ruby2d_red} #{title.bold}" end |
#setup_tildify(path) ⇒ Object
Abbreviate a home-relative path to ~/… for tidy, portable output.
37 38 39 40 |
# File 'lib/ruby2d/cli/setup.rb', line 37 def setup_tildify(path) home = Dir.home path.start_with?(home) ? path.sub(home, '~') : path end |
#shell_escape(path) ⇒ Object
Shell-escape a path for safe interpolation into a command string, so a gem or asset install location containing spaces (or other shell metacharacters) doesn't break the cc/emcc/mrbc invocations. A no-op for ordinary paths.
22 23 24 |
# File 'lib/ruby2d/cli/build.rb', line 22 def shell_escape(path) Shellwords.escape(path.to_s) end |
#skip_build(reason) ⇒ Object
Install without the native extension: write a do-nothing Makefile so gem install still completes, surface the recovery guidance, and exit cleanly. The
user finishes with ruby2d setup, or a package-manager install + gem pristine ruby2d. Far friendlier than aborting the whole install — and the ruby2d CLI
(including setup) keeps working without the extension.
35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 |
# File 'ext/ruby2d/extconf.rb', line 35 def skip_build(reason) notice = "Ruby 2D: #{reason}\n#{Ruby2D::DepsHelp.notice}" # RubyGems runs extconf via Open3.popen2e and hides the captured stdout/stderr # on a successful (exit-0) install, so a plain `puts` never reaches the user. # Write straight to the controlling terminal — which popen2e leaves attached — # to surface the guidance on an interactive install. Best-effort: with no tty # (CI, piped) it's skipped, and the same guidance still shows at run time via # the LoadError rescue in lib/ruby2d/core.rb. begin File.open('/dev/tty', 'w') { |tty| tty.puts notice } rescue SystemCallError # no controlling terminal — rely on the runtime notice end puts notice # also captured to the build log (visible with `gem install --verbose`) File.write('Makefile', "all:\ninstall:\nclean:\n") exit 0 end |
#static_libs_present?(lib_dir) ⇒ Boolean
18 19 20 |
# File 'ext/ruby2d/extconf.rb', line 18 def static_libs_present?(lib_dir) SDL3_STATIC_LIBS.all? { |lib| File.exist?(File.join(lib_dir, lib)) } end |
#step(title) ⇒ Object
Print a build-step banner — a ruby-red diamond and a bold title — to match
the ruby2d CLI and rake output. Artifact paths are listed beneath it.
42 43 44 |
# File 'lib/ruby2d/cli/build.rb', line 42 def step(title) puts "\n #{'◆'.ruby2d_red} #{title.bold}" end |
#strip_require(file) ⇒ Object
Neutralize require 'ruby2d' / require 'ruby2d/core' lines — the bundled
build already provides Ruby2D. Blank each one out rather than deleting it, so
every following line keeps its original number and an mrbc compile error
still points at the right line in the user's source.
68 69 70 71 72 |
# File 'lib/ruby2d/cli/build.rb', line 68 def strip_require(file) File.foreach(file).map do |line| line.match?(/require ('|")ruby2d(\/core)?('|")/) ? "\n" : line end.join end |
#warning(msg, spaced: false, indent: 0) ⇒ Object
27 28 29 |
# File 'lib/ruby2d/cli/messages.rb', line 27 def warning(msg, spaced: false, indent: 0) puts ruby2d_labeled('Warning:'.warning, msg, spaced, indent) end |
#wrote(path) ⇒ Object
List a file or bundle the build produced, beneath its step banner. The dim
wrote label marks it as an output without competing with the path itself.
49 50 51 |
# File 'lib/ruby2d/cli/build.rb', line 49 def wrote(path) puts " #{'wrote'.dim} #{path}" end |