From e8d5b7aedb44a1a75b0d18ac9dc49b6eda350f47 Mon Sep 17 00:00:00 2001 From: dearblue Date: Mon, 18 Sep 2023 21:24:37 +0900 Subject: [PATCH] Added `mrbgems/mruby-bin-utils` --- mrbgems/default.gembox | 3 + mrbgems/mruby-bin-utils/README.md | 29 ++++++++ mrbgems/mruby-bin-utils/bintest/test.rb | 14 ++++ mrbgems/mruby-bin-utils/mrbgem.rake | 84 ++++++++++++++++++++++++ mrbgems/mruby-bin-utils/testdata/test1.c | 9 +++ mrbgems/mruby-bin-utils/testdata/test2.c | 1 + 6 files changed, 140 insertions(+) create mode 100644 mrbgems/mruby-bin-utils/README.md create mode 100644 mrbgems/mruby-bin-utils/bintest/test.rb create mode 100644 mrbgems/mruby-bin-utils/mrbgem.rake create mode 100644 mrbgems/mruby-bin-utils/testdata/test1.c create mode 100644 mrbgems/mruby-bin-utils/testdata/test2.c diff --git a/mrbgems/default.gembox b/mrbgems/default.gembox index 1143b19831..5c43ad4830 100644 --- a/mrbgems/default.gembox +++ b/mrbgems/default.gembox @@ -22,4 +22,7 @@ MRuby::GemBox.new do |conf| # Generate mruby-config command conf.gem :core => "mruby-bin-config" + + # Generate mruby-cc and other commands + conf.gem :core => "mruby-bin-utils" end diff --git a/mrbgems/mruby-bin-utils/README.md b/mrbgems/mruby-bin-utils/README.md new file mode 100644 index 0000000000..544ea1bfec --- /dev/null +++ b/mrbgems/mruby-bin-utils/README.md @@ -0,0 +1,29 @@ +# mruby-bin-utils + +This is a command line program that serves as a wrapper to compile and link source code requiring libmruby. + +The name is a play on GNU Binutils. + +## How to build and use it + +Add this mruby-bin-utils to your build configuration file and build mruby. + +```ruby +# in your build configuration file + +MRuby::Build.new do |conf| + ... + conf.gem core: "mruby-bin-utils" + ... +end +``` + +Then compile and link your code in the generated command line program. + +```console +$ bin/mruby-cc yourcode.c +$ bin/mruby-c++ yourcode.cxx +$ bin/mruby-as yourcode.s +$ bin/mruby-objc yourcode.m +$ bin/mruby-ld ... +``` diff --git a/mrbgems/mruby-bin-utils/bintest/test.rb b/mrbgems/mruby-bin-utils/bintest/test.rb new file mode 100644 index 0000000000..79644f1c09 --- /dev/null +++ b/mrbgems/mruby-bin-utils/bintest/test.rb @@ -0,0 +1,14 @@ +require "pathname" + +cc_command = File.join(ENV["BUILD_DIR"], "bin/mruby-cc") +testdata = Pathname(__dir__).parent + "testdata" + +assert "C compile" do + system *%W(#{cc_command} #{testdata + "test1.c"}) + assert_true $?.success? +end + +assert "C compile (failing)" do + system *%W(#{cc_command} #{testdata + "test2.c"}), err: File::NULL + assert_false $?.success? +end diff --git a/mrbgems/mruby-bin-utils/mrbgem.rake b/mrbgems/mruby-bin-utils/mrbgem.rake new file mode 100644 index 0000000000..8f32bf4159 --- /dev/null +++ b/mrbgems/mruby-bin-utils/mrbgem.rake @@ -0,0 +1,84 @@ +#!ruby + +MRuby::Gem::Specification.new("mruby-bin-utils") do |spec| + spec.summary = "one-shot mruby C/C++ compiler and utilities" + spec.license = "MIT" + spec.author = "mruby developers" + spec.add_dependency "mruby-bin-config", core: "mruby-bin-config" + + if ENV["OS"] =~ /windows/i + msvc = build.toolchains.find { |e| e == "visualcpp" } ? true : false + binext = ".bat" + bingen = ->(bin, cflags, ldflags) { + (cflags, ldflags) = [cflags, ldflags].map { |flags| + flags.map { |f| + varname = %(mrbc_#{f.sub(/^--/, "").gsub(/[^\w]+/, "_")}) + extractor = %(for /f "usebackq delims=" %%i in (`%mrbconfig% #{f}`) do set #{varname}=%%i) + ["%#{varname}%", extractor] + } + } + + withlink = "/link " if msvc && bin != "mruby-ld" + + <<~CODE + @echo off + + if "%1" == "" ( + \techo %~n0: no files given 1>&2 + \texit /b 1 + ) + + set mrbconfig="%~dp0.\\mruby-config.bat" + #{cflags.map { |v, e| e }.join("\n")} + #{ldflags.map { |v, e| e }.join("\n")} + + call #{cflags.map { |v, e| v }.join(" ")} %* #{withlink}#{ldflags.map { |v, e| v }.join(" ")} + CODE + } + else + binext = "" + bingen = ->(bin, cflags, ldflags) { + <<~CODE + #!/bin/sh + + if [ "$#" -lt 1 ] + then + \techo "$(basename "$0"): no files given" 1>&2 + \texit 1 + fi + + mrbconfig="$(dirname "$0")/mruby-config" + + $("$mrbconfig" #{cflags.join(" ")}) "$@" $("$mrbconfig" #{ldflags.join(" ")}) + CODE + } + end + + if spec.build.kind_of?(MRuby::CrossBuild) + destdir = "#{build.build_dir}/host-bin" + addbin = ->(dest) { build.products << dest } + else + destdir = "#{build.build_dir}/bin" + addbin = ->(dest) { build.bins << File.basename(dest) } + end + + [ + ["mruby-cc", %w(--cc --cflags), %w(--ldflags --ldflags-before-libs --libs)], + ["mruby-c++", %w(--cxx --cxxflags), %w(--ldflags --ldflags-before-libs --libs)], + ["mruby-as", %w(--as --asflags), %w(--ldflags --ldflags-before-libs --libs)], + ["mruby-objc", %w(--objc --objcflags), %w(--ldflags --ldflags-before-libs --libs)], + ["mruby-ld", %w(--ld), %w(--ldflags --ldflags-before-libs --libs)], + ].each do |bin, cflags, ldflags| + destpath = File.join(destdir, "#{bin}#{binext}") + + addbin.call(destpath) + + file destpath => __FILE__ do |t| + _pp "GEN", destpath.relative_path + mkdir_p destdir + + # NOTE: No line break code is specified, so text appropriate to the environment is output + File.write(destpath, bingen.call(bin, cflags, ldflags), perm: 0755) + end + end +end diff --git a/mrbgems/mruby-bin-utils/testdata/test1.c b/mrbgems/mruby-bin-utils/testdata/test1.c new file mode 100644 index 0000000000..90c2b040f6 --- /dev/null +++ b/mrbgems/mruby-bin-utils/testdata/test1.c @@ -0,0 +1,9 @@ +#include + +int +main(int argc, char **argv) +{ + mrb_state *mrb = mrb_open(); + mrb_close(mrb); + return 0; +} diff --git a/mrbgems/mruby-bin-utils/testdata/test2.c b/mrbgems/mruby-bin-utils/testdata/test2.c new file mode 100644 index 0000000000..e84eb4a106 --- /dev/null +++ b/mrbgems/mruby-bin-utils/testdata/test2.c @@ -0,0 +1 @@ +#error "INTENTIONAL ERROR FOR FAILING!"