PLATFORMS_DIR = ENV['platforms_dir'] IOS_SDK_VERSIONS = ENV['ios_sdk_versions'].split(',') OSX_SDK_VERSIONS = ENV['osx_sdk_versions'].split(',') verbose(true) NEED_STRIP = !ENV['DEBUG'] task :default => :all task :all => [:vm_files, :bridgesupport_files, :bridgesupport_static_stubs] task :vm_files do strip = File.join(PLATFORMS_DIR, '../Toolchains/XcodeDefault.xctoolchain/usr/bin/strip') OSX_SDK_VERSIONS.each do |sdk_version| sdk = File.join('osx', sdk_version, 'MacOSX') mkdir_p sdk objs = "../vm/MacOSX#{sdk_version}.objs" Dir.glob(File.join(objs, 'kernel-*.bc')).each do |path| install path, sdk end install File.join(objs, 'libmacruby-static.a'), sdk objs = "../vm/MacOSX#{sdk_version}-repl.objs" install File.join(objs, 'libmacruby-repl.dylib'), sdk # remove debug symbols if NEED_STRIP Dir.glob(sdk + '/*.{a,dylib}').each { |x| sh("\"#{strip}\" -S \"#{x}\"") } end end IOS_SDK_VERSIONS.each do |sdk_version| ios = File.join('ios', sdk_version, 'iPhoneOS') mkdir_p ios objs = "../vm/iPhoneOS#{sdk_version}.objs" Dir.glob(File.join(objs, 'kernel-*.bc')).each do |path| install path, ios end install File.join(objs, 'libmacruby-static.a'), ios sim = File.join('ios', sdk_version, 'iPhoneSimulator') mkdir_p sim objs = "../vm/iPhoneSimulator#{sdk_version}.objs" Dir.glob(File.join(objs, 'kernel-*.bc')).each do |path| install path, sim end install File.join(objs, 'libmacruby-static.a'), sim objs = "../vm/iPhoneSimulator#{sdk_version}-repl.objs" install File.join(objs, 'libmacruby-repl.dylib'), sim # remove debug symbols if NEED_STRIP [ios, sim].map { |x| Dir.glob(x + '/*.{a,dylib}') }.flatten.each { |x| sh("\"#{strip}\" -S \"#{x}\"") } end end end def apply_bridgesupport_fixes(bs) rules = [] case File.basename(bs, '.bridgesupport') when 'CoreMIDI', 'AudioToolBox' rules << [/" in base if lines.last.strip != "" io.puts "" end io.print merge.lines.to_a[2..-1].join # skip first "\n" in merge } end EXCLUDED_FRAMEWORKS = ['Kernel', 'System', 'IOKit', 'Carbon', 'Ruby', 'RubyCocoa', 'vecLib'] task :bridgesupport_files do platform_dev_path = "#{PLATFORMS_DIR}/MacOSX.platform/Developer" OSX_SDK_VERSIONS.each do |sdk_version| sdk_path = "#{platform_dev_path}/SDKs/MacOSX#{sdk_version}.sdk" sdk_frameworks = "#{sdk_path}/System/Library/Frameworks" mkdir_p "osx/#{sdk_version}/BridgeSupport" mkdir_p "osx/#{sdk_version}/BridgeSupport/child" Dir.glob('*.bridgesupport').each { |bs| cp bs, "osx/#{sdk_version}/BridgeSupport" } Dir.glob('osx/*.bridgesupport').each { |bs| cp bs, "osx/#{sdk_version}/BridgeSupport" } generate_bridgesupport_file = lambda do |sdk_path, sdk_version, framework_path, is_handle_nested| framework = File.basename(framework_path, '.framework') break if EXCLUDED_FRAMEWORKS.include?(framework) break unless File.exist?(File.join(framework_path, framework)) break unless File.exist?(File.join(framework_path, 'Headers')) dest = "osx/#{sdk_version}/BridgeSupport/#{framework}.bridgesupport" dest = "osx/#{sdk_version}/BridgeSupport/child/#{framework}.bridgesupport" if is_handle_nested unless File.exist?(dest) a = sdk_version.scan(/(\d+)\.(\d+)/)[0] sdk_version_headers = ((a[0].to_i * 10000) + (a[1].to_i * 100)).to_s sh "/usr/bin/gen_bridge_metadata --format complete --cflags \"-isysroot #{sdk_path} -mmacosx-version-min=#{sdk_version} -DTARGET_OS_MAC -D__ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__=#{sdk_version_headers} -framework #{framework}\" --framework #{framework_path} > #{dest}" apply_bridgesupport_fixes(dest) return dest end return dest if is_handle_nested end Dir.glob(File.join(sdk_frameworks, '*.framework')).each do |framework_path| base_bridgesupport_path = generate_bridgesupport_file.call(sdk_path, sdk_version, framework_path, false) if base_bridgesupport_path child_framework_paths = Dir.glob(File.join(framework_path, '/Frameworks/*.framework')) child_framework_paths.delete_if { |x| x.include?("CoreGraphics") } if sdk_version != "10.7" child_framework_paths.each do |child_framework_path| if sdk_version == "10.7" && child_framework_path.include?("CoreGraphics") dest = 'osx/10.7/BridgeSupport/child/CoreGraphics.bridgesupport' sh "/usr/bin/gen_bridge_metadata --format complete --cflags \"-isysroot #{sdk_path} -F#{sdk_path}/System/Library/Frameworks/ApplicationServices.framework/Frameworks -mmacosx-version-min=10.7 -DTARGET_OS_MAC -D__ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__=100700 -framework ApplicationServices\" --framework #{child_framework_path} > #{dest}" apply_bridgesupport_fixes(dest) merge_path = dest else merge_path = generate_bridgesupport_file.call(sdk_path, sdk_version, child_framework_path, true) end merge_bridgesupport(base_bridgesupport_path, merge_path) end end end end platform_dev_path = "#{PLATFORMS_DIR}/iPhoneSimulator.platform/Developer" IOS_SDK_VERSIONS.each do |sdk_version| sdk_path = "#{platform_dev_path}/SDKs/iPhoneSimulator#{sdk_version}.sdk" sdk_frameworks = "#{sdk_path}/System/Library/Frameworks" mkdir_p "ios/#{sdk_version}/BridgeSupport" mkdir_p "ios/#{sdk_version}/BridgeSupport/child" Dir.glob('*.bridgesupport').each { |bs| cp bs, "ios/#{sdk_version}/BridgeSupport" } Dir.glob('ios/*.bridgesupport').each { |bs| cp bs, "ios/#{sdk_version}/BridgeSupport" } generate_bridgesupport_file = lambda do |sdk_path, sdk_version, framework_path, is_handle_nested| framework = File.basename(framework_path, '.framework') break if EXCLUDED_FRAMEWORKS.include?(framework) break unless File.exist?(File.join(framework_path, framework)) break unless File.exist?(File.join(framework_path, 'Headers')) dest = "ios/#{sdk_version}/BridgeSupport/#{framework}.bridgesupport" dest = "ios/#{sdk_version}/BridgeSupport/child/#{framework}.bridgesupport" if is_handle_nested unless File.exist?(dest) a = sdk_version.scan(/(\d+)\.(\d+)/)[0] sdk_version_headers = ((a[0].to_i * 10000) + (a[1].to_i * 100)).to_s extra_flags = (sdk_version >= '7.0') ? '--64-bit' : '--no-64-bit' sh "/usr/bin/gen_bridge_metadata --format complete #{extra_flags} --cflags \"-isysroot #{sdk_path} -miphoneos-version-min=#{sdk_version} -DTARGET_OS_IPHONE -D__ENVIRONMENT_IPHONE_OS_VERSION_MIN_REQUIRED__=#{sdk_version_headers} -framework #{framework}\" --framework #{framework_path} > #{dest}" apply_bridgesupport_fixes(dest) if framework == 'Foundation' and sdk_version >= '7.0' # In iOS 7.0, NSObject is defined in /usr/include/objc/NSObject.h sh "/usr/bin/gen_bridge_metadata --format complete --no-64-bit --cflags \"-isysroot #{sdk_path} -miphoneos-version-min=#{sdk_version} -DTARGET_OS_IPHONE -D__ENVIRONMENT_IPHONE_OS_VERSION_MIN_REQUIRED__=#{sdk_version_headers} -framework #{framework} -I#{sdk_path}/usr/include \" objc/NSObject.h objc/NSObjCRuntime.h > /tmp/NSObject.bridgesupport" merge_bridgesupport dest, '/tmp/NSObject.bridgesupport' end return dest end return dest if is_handle_nested end Dir.glob(File.join(sdk_frameworks, '*.framework')).each do |framework_path| base_bridgesupport_path = generate_bridgesupport_file.call(sdk_path, sdk_version, framework_path, false) if base_bridgesupport_path child_framework_paths = Dir.glob(File.join(framework_path, '/Frameworks/*.framework')) child_framework_paths.each do |child_framework_path| merge_path = generate_bridgesupport_file.call(sdk_path, sdk_version, child_framework_path, true) merge_bridgesupport(base_bridgesupport_path, merge_path) end end end end end def generate_bs_static_stub(file, includes) require 'rubygems' require 'nokogiri' text = '' includes.each { |inc| text << "#import <#{inc}>\n" } doc = Nokogiri::XML(File.read(file)) did_something = false doc.xpath("/signatures/function[@inline=\"true\"]").each do |node| name = node['name'].to_s retval = node.xpath('./retval')[0]['declared_type'].to_s args = node.xpath('./arg').map { |node| node['declared_type'].to_s } proto = "#{retval} __concrete__#{name}(" proto << (0...args.size).to_a.map { |i| "#{args[i]} arg#{i}" }.join(', ') proto << ")" func = '' func << proto func << "\n{\n " func << " return " if retval != 'void' func << name << '(' func << (0...args.size).to_a.map { |i| "arg#{i}" }.join(', ') func << ");\n}\n\n" text << func did_something = true end did_something ? text : nil end task :bridgesupport_static_stubs do OSX_SDK_VERSIONS.each do |sdk_version| Dir.glob("osx/#{sdk_version}/BridgeSupport/*.bridgesupport") do |bs_path| framework = File.basename(bs_path).sub(/\.bridgesupport/, '') case framework when 'GLKit' # TODO next end code = "osx/#{sdk_version}/BridgeSupport/#{framework}_stubs.m" includes = case framework when 'OpenGLES' ['OpenGLES/EAGLDrawable.h'] else ['Cocoa/Cocoa.h', "#{framework}/#{framework}.h"] end unless File.exist?(code) text = generate_bs_static_stub(bs_path, includes) next unless text File.open(code, 'w') { |io| io.puts '#pragma GCC diagnostic ignored "-Wdeprecated-declarations"' io.write(text) } end obj = "osx/#{sdk_version}/MacOSX/#{framework}_stubs.o" next if File.exist?(obj) platform_dev = "#{PLATFORMS_DIR}/MacOSX.platform/Developer" cflags = "-isysroot #{platform_dev}/SDKs/MacOSX#{sdk_version}.sdk" cflags << " -arch i386 -arch x86_64" cflags << " -mmacosx-version-min=#{sdk_version} -Wall -Werror -O3 -fobjc-abi-version=2 -fobjc-legacy-dispatch" sh "/usr/bin/clang #{cflags} #{code} -c -o #{obj}" end end IOS_SDK_VERSIONS.each do |sdk_version| Dir.glob("ios/#{sdk_version}/BridgeSupport/*.bridgesupport") do |bs_path| framework = File.basename(bs_path).sub(/\.bridgesupport/, '') code = "ios/#{sdk_version}/BridgeSupport/#{framework}_stubs.m" includes = case framework when 'OpenGLES' ['OpenGLES/EAGLDrawable.h'] else ['UIKit/UIKit.h', "#{framework}/#{framework}.h"] end unless File.exist?(code) text = generate_bs_static_stub(bs_path, includes) next unless text File.open(code, 'w') { |io| io.write(text) } end device_archs = if sdk_version < '5.0' ['armv6', 'armv7'] elsif sdk_version >= '7.0' ['armv7', 'armv7s', 'arm64'] elsif sdk_version >= '6.0' ['armv7', 'armv7s'] else ['armv7'] end sim_archs = if sdk_version >= '7.0' ['i386', 'x86_64'] else ['i386'] end [['iPhoneOS', *device_archs], ['iPhoneSimulator', *sim_archs]].each do |platform, *archs| obj = "ios/#{sdk_version}/#{platform}/#{framework}_stubs.o" next if File.exist?(obj) platform_dev = "#{PLATFORMS_DIR}/#{platform}.platform/Developer" cflags = "-isysroot #{platform_dev}/SDKs/#{platform}#{sdk_version}.sdk " cflags << archs.map { |a| "-arch #{a}" }.join(' ') cflags << " -miphoneos-version-min=#{sdk_version} -Wall -Werror -O3 -fobjc-abi-version=2 -fobjc-legacy-dispatch" sh "#{PLATFORMS_DIR}/../Toolchains/XcodeDefault.xctoolchain/usr/bin/clang #{cflags} #{code} -c -o #{obj}" end end end end task :clean do IOS_SDK_VERSIONS.each { |path| rm_rf('ios/' + path) } OSX_SDK_VERSIONS.each { |path| rm_rf('osx/' + path) } end