Skip to content

Commit

Permalink
Migrate to Extension Gem using rake-compiler Part 1
Browse files Browse the repository at this point in the history
  • Loading branch information
ParadoxV5 committed Jan 22, 2024
1 parent 302512d commit 33503a2
Show file tree
Hide file tree
Showing 15 changed files with 68 additions and 181 deletions.
232 changes: 53 additions & 179 deletions Rakefile
Original file line number Diff line number Diff line change
@@ -1,92 +1,8 @@
# frozen_string_literal: true

warn 'only CRuby supported', category: :experimental if 'ruby' != RUBY_ENGINE


# Defines #

# @return `"<architecture>/<platform>"`
# @see RbConfig::CONFIG
OS = File.join(
case target = RbConfig::CONFIG['target_cpu']
when 'x64'
'x86_64'
else
warn "target_cpu `#{target}` not supported", category: :experimental
".#{target}"
end,
case target = RbConfig::CONFIG['target_os']
when 'mingw32'
'windows'
else
warn "target_os `#{target}` not supported", category: :experimental
".#{target}"
end
)

# RubyInstaller has its stuff in its own self-contained folder
# @return [boolish] the `RubyInstaller` module for Windows RubyInstaller, or `nil` for non-RubyInstaller
RubyInstaller ||= nil
warn 'non-RubyInstaller2 not supported', category: :experimental unless RubyInstaller

# C sources directory
# @return `"src"`
SRC = 'src'
# Output root directory
# @return `"build"`
BIN = 'build'
# Output directory
# @return `"build/<architecture>/<platform>/"`
# @see OS
OUT = File.join(BIN, OS, '')

# @return `libruby.so`’s directory: `"/<path>/<to>"`
# @see LIBRUBY_NAME
LIBRUBY_DIR = RbConfig::CONFIG[RubyInstaller ? 'bindir' : 'libdir']
# @return `libruby.so`, the file name (dependant on platform and possibly architecture)
# @see LIBRUBY_DIR
LIBRUBY_NAME = RbConfig::CONFIG['LIBRUBY_SO']
i_h_dir = "-I#{RbConfig::CONFIG['rubyhdrdir']}"
i_arch_h_dir = "-I#{RbConfig::CONFIG['rubyarchhdrdir']}"
l_libruby_dir = "-L#{LIBRUBY_DIR}"
l_libruby_name = "-l:#{LIBRUBY_NAME}"

rubyarchdir = RbConfig::CONFIG['rubyarchdir']
# Assume `rubyarchdir` always starts with `prefix`
directory out_archdir =
File.join(OUT, rubyarchdir[RbConfig::CONFIG['prefix'].size..] || '')
out_enc_dir = File.join(out_archdir, 'enc')
file_create out_enc_dir => out_archdir

# symlinks of `libruby` & dependencies in the output directory and their originals
# @return `{"build/<architecture>/<platform>/<lib.so>" => "/<path>/<to>/<lib.so>", …}`
LIBS = {
File.join(OUT, LIBRUBY_NAME) => File.join(LIBRUBY_DIR, LIBRUBY_NAME),
out_enc_dir => File.join(rubyarchdir, 'enc')
}
if RubyInstaller
%w[libgmp-10.dll].each do|lib|
LIBS[File.join(OUT, lib)] =
File.join(LIBRUBY_DIR, 'ruby_builtin_dlls', lib)
end
end

rake_output_message "<architecture/platform>\t#{OS}"


# C #

src_dir_size = SRC.size
# C sources and file names of their corresponding intermediate `.o`s
# @return `{"src/*.c" => "*.o"}`
# @see SRC
C__O_NAMES = Dir[File.join(SRC, '**', '*.c'), sort: false].to_h {|source| [
source,
source[src_dir_size..].tap { _1[-1] = 'o' }
] }
require 'rake/extensiontask'

# Build modes and their compiler flags
# @return `{'debug' => ["flag", …], 'release' => …}`
# @return `{"debug" => ["flag", …], "release" => …}`
BUILD_FLAGS = {
'debug' => %w[
],
Expand All @@ -95,104 +11,62 @@ BUILD_FLAGS = {
-O2
]
}
BUILD_FLAGS.map do|build, flags|
out = File.join(OUT, "#{build}.lib")
o_dir_name = ".#{build}.o"
directory o_dir = File.join(OUT, o_dir_name)

# Compile Object Binaries (`.o`)
C__O_NAMES.map do|source, o_name|
o0 = File.join(o_dir, o_name)
directory o0_dir = File.dirname(o0)
file o0 => [source, o0_dir] do
sh('gcc',
*flags,
'-c',
"-o#{o0}",
'-fPIC',
'-Iinclude',
i_h_dir,
i_arch_h_dir,
source
)
end
o0
end => o

# Link Shared Library (`.so`)
file out => o do
sh('gcc',
*flags,
'-shared',
'-fPIC',
"-o#{out}",
*o,
l_libruby_dir,
l_libruby_name
)
end
multitask build => [*o, out]

o_dir
end => o_dirs # ["…/.debug.o", …]`


# Ruby #
# sh('gcc',
# *flags,
# …
# )

hash_files = %w[core editor].to_h do|api_type|
tsv = File.join BIN, "#{api_type}.hashes.tsv"
# Each task executes at most once
file tsv => :extension_api
[api_type, tsv]
# C
Rake::ExtensionTask.new 'godot_rb' do|ext|
# ext.config_options << '--with-foo'
ext.source_pattern = '**/*.c'
ext.no_native = true
end

extension_api = File.join 'include', 'godot', 'extension_api.json'
# Database of method hashes
# ```
# Class
# method␉12345
# ```
task :extension_api => [BIN, extension_api] do
require 'json'
json = JSON.load_file extension_api
files = hash_files.transform_values do|tsv|
File.open tsv, 'w'
rescue => e
warn e.full_message
end
begin
json['classes'].each do|klass_data|
files[klass_data['api_type']]&.then do|tsv|
tsv.puts klass_data['name']
klass_data['methods']&.each do|method_data|
method_data['hash']&.then { tsv.puts "#{method_data['name']}\t#{_1}" }
end
end
end
ensure
files.each_value { _1&.close }
end
end
# # Ruby #
#
# hash_files = %w[core editor].to_h do|api_type|
# tsv = File.join BIN, "#{api_type}.hashes.tsv"
# # Each task executes at most once
# file tsv => :extension_api
# [api_type, tsv]
# end
#
# extension_api = File.join 'include', 'godot', 'extension_api.json'
# # Database of method hashes
# # ```
# # Class
# # method␉12345
# # ```
# task :extension_api => [BIN, extension_api] do
# require 'json'
# json = JSON.load_file extension_api
# files = hash_files.transform_values do|tsv|
# File.open tsv, 'w'
# rescue => e
# warn e.full_message
# end
# begin
# json['classes'].each do|klass_data|
# files[klass_data['api_type']]&.then do|tsv|
# tsv.puts klass_data['name']
# klass_data['methods']&.each do|method_data|
# method_data['hash']&.then { tsv.puts "#{method_data['name']}\t#{_1}" }
# end
# end
# end
# ensure
# files.each_value { _1&.close }
# end
# end


# Tasks #

desc 'build Godot.rb for debug builds'
task default: [BUILD_FLAGS.each_key.first, :additional_files]
desc 'build Godot.rb for all build types'
task all: (BUILD_FLAGS.keys << 'additional_files')

LIBS.each {|symlink, lib| file_create symlink => OUT do
ln_sf lib, symlink
end }
multitask additional_files: ( LIBS.keys.push *hash_files.values )


desc "delete the intermediate directories such as `#{o_dirs.first}`"
task :mostlyclean do
rm_rf o_dirs
end
desc "delete the output directory `#{OUT}`"
task :clean do
rm_rf OUT
end
# desc 'build Godot.rb for debug builds'
# task default: [BUILD_FLAGS.each_key.first, :additional_files]
# desc 'build Godot.rb for all build types'
# task all: (BUILD_FLAGS.keys << 'additional_files')
#
# multitask additional_files: hash_files.values
2 changes: 1 addition & 1 deletion ext/godot_rb/cleanup.c
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
#include "ruby/variants.h"
#include "variants.h"

static void core(void) {
if RB_UNLIKELY(ruby_cleanup(EXIT_SUCCESS))
Expand Down
11 changes: 11 additions & 0 deletions ext/godot_rb/extconf.rb
Original file line number Diff line number Diff line change
@@ -1,2 +1,13 @@
require 'mkmf'

# Detect (Windows) stand-alone MinGW without MSYS2 (AKA DevKit)
unless CROSS_COMPILING or RbConfig::CONFIG['build_os'] != 'mingw32' or find_executable 'msys2'
# Monkeypatch {MakeMakefile#find_header} to prevent translation to MSYS `/C/some/path/`
def mkintpath(path) = path
end

include = File.expand_path '../../include/', __FILE__
find_header 'godot_rb.h', include
find_header 'godot/gdextension_interface.h', include

create_makefile 'godot_rb'
2 changes: 2 additions & 0 deletions ext/godot_rb/godot_rb.c
Original file line number Diff line number Diff line change
Expand Up @@ -112,3 +112,5 @@ bool godot_rb_protect(void (* function)(va_list* args), ...) {
}
return true;
}

void Init_godot_rb() {}
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
2 changes: 1 addition & 1 deletion ext/godot_rb/setup.c
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
#include "setup.h"
#include "ruby/variants.h"
#include "variants.h"

/**
Ruby keeps a copy of the argc/v pointers’ contents, though it seems to only use `argv[0]` occasionally.
Expand Down
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.

0 comments on commit 33503a2

Please sign in to comment.