Skip to content

Instantly share code, notes, and snippets.

@dorentus
Last active August 31, 2020 01:53
Show Gist options
  • Save dorentus/9828754 to your computer and use it in GitHub Desktop.
Save dorentus/9828754 to your computer and use it in GitHub Desktop.
Put build_config.rb into mruby root dir, make, and put build_framework.rb into build dir and run it to get a MRuby.framework, run collect_mrb_gem_archive.rb <gem_name> in build dir to get a seperate <gem_name>.framework
MRuby::Build.new do |conf|
toolchain :clang
conf.gembox 'default'
end
def crossbuild_for(name, platform, sysroot, cc_defines = [])
MRuby::CrossBuild.new(name) do |conf|
toolchain :clang
conf.gembox 'default'
conf.bins = []
conf.cc do |cc|
cc.command = 'xcrun'
cc.defines = cc_defines
cc.flags = %W(-sdk iphoneos clang -miphoneos-version-min=7.0 -arch #{platform} -isysroot #{sysroot} -g -Ofast -Wall -Werror-implicit-function-declaration -fembed-bitcode)
end
conf.linker do |linker|
linker.command = 'xcrun'
linker.flags = %W(-sdk iphoneos clang -miphoneos-version-min=7.0 -arch #{platform} -isysroot #{sysroot})
end
end
end
SIM_SYSROOT = %x[xcrun --sdk iphonesimulator --show-sdk-path].strip
DEVICE_SYSROOT = %x[xcrun --sdk iphoneos --show-sdk-path].strip
crossbuild_for('ios-arm64', 'arm64', DEVICE_SYSROOT, %w(MRB_INT64))
crossbuild_for('ios-armv7', 'armv7', DEVICE_SYSROOT, %w(MRB_INT64))
crossbuild_for('ios-simulator-x86_64', 'x86_64', SIM_SYSROOT, %w(MRB_INT64))
crossbuild_for('ios-simulator-i386', 'i386', SIM_SYSROOT, %w(MRB_INT64))
#!/usr/bin/env ruby
require "FileUtils"
BUILD_PATH = File.dirname(__FILE__)
def build_framework(name, lib_files, header_dir)
path = "#{BUILD_PATH}/#{name}.framework"
FileUtils.rm_rf path
FileUtils.mkdir_p "#{path}/Headers"
FileUtils.cp_r "#{header_dir}/.", "#{path}/Headers"
Dir.glob("#{path}/Headers/**/*.h").each do |file|
replaced = File.read(file).gsub(/^#include "mruby\/(.+)"$/, '#include <Mruby/mruby/\1>')
.gsub(/^#include "mruby\.h"$/, '#include <MRuby/mruby.h>')
File.open(file, "w") { |f| f.puts replaced }
end
File.open "#{path}/Headers/mruby-umbrella.h", "w" do |file|
file.puts '#define MRB_INT64'
file.puts '#include "mruby.h"'
Dir.chdir "#{path}/Headers" do
Dir["mruby/*.h"].each do |f|
next if f == "mruby/debug.h"
next if f =~ /mruby\/boxing/
file.puts "#include \"#{f}\""
end
end
end
Dir.mkdir "#{path}/Modules"
File.open "#{path}/Modules/module.modulemap", "w" do |file|
file.write <<EOF
framework module MRuby {
umbrella header "mruby-umbrella.h"
exclude header "mruby/boxing_nan.h"
exclude header "mruby/boxing_no.h"
exclude header "mruby/boxing_word.h"
exclude header "mruby/debug.h"
export *
module * { export * }
}
EOF
end
system "lipo #{lib_files.join " "} -create -output #{path}/#{name}"
end
lib_files = %w(arm64 armv7 simulator-x86_64 simulator-i386).map do |arch|
"#{BUILD_PATH}/ios-#{arch}/lib/libmruby.a"
end
header_dir = "#{BUILD_PATH}/../include"
build_framework "MRuby", lib_files, header_dir
#!/usr/bin/env ruby
require 'tmpdir'
require 'fileutils'
def collect_gem gem_name, dir, subdir, arch
object_files = Dir.glob("./#{dir}/#{subdir}/mrbgems/#{gem_name}/**/*.o").map do |path|
File.absolute_path path
end
gem_funcname = File.read("./#{dir}/#{subdir}/mrbgems/#{gem_name}/gem_init.c").split("\n").select do |line|
line =~ /GENERATED_TMP_mrb_(.+)_gem_init/
end.first.match(/GENERATED_TMP_mrb_(.+)_gem_init/)[1]
init_func_name = "GENERATED_TMP_mrb_#{gem_funcname}_gem_init"
final_func_name = "GENERATED_TMP_mrb_#{gem_funcname}_gem_final"
header_content = <<-EOF
#include <MRuby/mruby.h>
void mrbgem_load_#{gem_funcname}(mrb_state *mrb);
EOF
source_content = <<-EOF
typedef void (*mrb_atexit_func)(void*);
extern void mrb_state_atexit(void *mrb, mrb_atexit_func func);
extern void #{init_func_name}(void *mrb);
extern void #{final_func_name}(void *mrb);
__attribute__((visibility("default")))
void mrbgem_load_#{gem_funcname}(void *mrb) {
#{init_func_name}(mrb);
mrb_state_atexit(mrb, #{final_func_name});
}
EOF
sdk_path = arch =~ /arm/ ? %x[xcrun --sdk iphoneos --show-sdk-path].strip : %x[xcrun --sdk iphonesimulator --show-sdk-path].strip
dir = Dir.mktmpdir "mrbgem_#{gem_funcname}"
at_exit do
FileUtils.rm_rf dir
end
Dir.chdir dir do
source_file_path = "init.c"
extra_object_file_path = "init.o"
File.open source_file_path, "w" do |f|
f.write source_content
end
system "xcrun", "clang", "-g", "-miphoneos-version-min=7.0", "-fembed-bitcode", "-Os", "-arch", arch, "-isysroot", sdk_path, "-c", source_file_path, "-o", extra_object_file_path
object_files << extra_object_file_path
output_a_file_path = "#{gem_funcname}.a"
system "libtool", "-static", "-syslibroot", sdk_path, *object_files, "-o", output_a_file_path
output_h_file_path = "#{gem_funcname}.h"
File.open output_h_file_path, "w" do |f|
f.write header_content
end
[File.absolute_path(output_a_file_path), File.absolute_path(output_h_file_path)]
end
end
GEM_NAME = ARGV[0] || 'mruby-dispatch'
outputs = [
collect_gem(GEM_NAME, '.', 'ios-arm64', 'arm64'),
collect_gem(GEM_NAME, '.', 'ios-armv7', 'armv7'),
collect_gem(GEM_NAME, '.', 'ios-simulator-x86_64', 'x86_64'),
collect_gem(GEM_NAME, '.', 'ios-simulator-i386', 'i386'),
]
header_file_path = outputs.first.last # header files are all the same
lib_files = outputs.map(&:first)
framework_path = "#{GEM_NAME}.framework"
FileUtils.rm_rf framework_path if Dir.exist? framework_path
FileUtils.mkdir_p "#{framework_path}/Headers"
system "lipo", *lib_files, "-create", "-output", "#{framework_path}/#{GEM_NAME}"
FileUtils.cp header_file_path, "#{framework_path}/Headers/#{GEM_NAME}.h"
puts "-> #{framework_path}"
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment