rutie 0.0.4 → 0.0.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/lib/rutie/rake_task.rb +58 -0
- data/lib/rutie.rb +62 -8
- data/rutie.gemspec +6 -2
- metadata +19 -7
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 1b64238b8adf58283d6b5f5af059aa5c55fc639b511d028cfe1acbf1ec60f34d
|
|
4
|
+
data.tar.gz: baa343484d7ee30aa776bd1b964c9da48f3be00bd3087e92616d9cdab81ab88b
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: b39f0e34b4481f8465dac15e91560f91a1911eaeb296755197eb1d21cd2410e5e536bccaf656773961ecfb1213d11894674440fca36eb87de967995a59c754cc
|
|
7
|
+
data.tar.gz: d2697285b96743651f9298346fe20766be9cb1715d61b34d835d607684e2f029046995273e8bf4f0f3eb99574a8da51d68aaf2e271636ff420ef36c864c6bc82
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
require 'rake'
|
|
2
|
+
require 'rbconfig'
|
|
3
|
+
|
|
4
|
+
class Rutie
|
|
5
|
+
# Rake tasks that build a Rutie extension so `ruby` can load it:
|
|
6
|
+
#
|
|
7
|
+
# # Rakefile
|
|
8
|
+
# require 'rutie/rake_task'
|
|
9
|
+
# Rutie::RakeTask.new
|
|
10
|
+
#
|
|
11
|
+
# Rake::TestTask.new(test: 'rutie:build') { |t| ... }
|
|
12
|
+
#
|
|
13
|
+
# `rutie:build` runs `cargo build --release`. On macOS it builds with
|
|
14
|
+
# `NO_LINK_RUTIE=1` and `-undefined dynamic_lookup` instead, so the extension
|
|
15
|
+
# uses the libruby of the `ruby` process loading it rather than linking its
|
|
16
|
+
# own (with a static Ruby that would be a second VM that never booted).
|
|
17
|
+
# `rutie:clean` runs `cargo clean`.
|
|
18
|
+
class RakeTask
|
|
19
|
+
include Rake::DSL
|
|
20
|
+
|
|
21
|
+
# `release: false` builds the debug profile, for `Rutie.new(..., release: 'debug')`.
|
|
22
|
+
# `cargo_args` are extra arguments for cargo, such as `%w[--features foo]`.
|
|
23
|
+
def initialize(release: true, cargo_args: [], os: nil)
|
|
24
|
+
@release = release
|
|
25
|
+
@cargo_args = cargo_args
|
|
26
|
+
@os = os # for testing purposes
|
|
27
|
+
|
|
28
|
+
define_tasks
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
# The environment and command `rutie:build` runs.
|
|
32
|
+
def build_command
|
|
33
|
+
profile = @release ? ['--release'] : []
|
|
34
|
+
|
|
35
|
+
if macos?
|
|
36
|
+
[{ 'NO_LINK_RUTIE' => '1' },
|
|
37
|
+
'cargo', 'rustc', *profile, *@cargo_args, '--', '-C', 'link-args=-Wl,-undefined,dynamic_lookup']
|
|
38
|
+
else
|
|
39
|
+
[{}, 'cargo', 'build', *profile, *@cargo_args]
|
|
40
|
+
end
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
private
|
|
44
|
+
def define_tasks
|
|
45
|
+
namespace :rutie do
|
|
46
|
+
desc 'Build the Rust extension'
|
|
47
|
+
task(:build) { sh(*build_command) }
|
|
48
|
+
|
|
49
|
+
desc 'Remove the Rust build output (cargo clean)'
|
|
50
|
+
task(:clean) { sh 'cargo', 'clean' }
|
|
51
|
+
end
|
|
52
|
+
end
|
|
53
|
+
|
|
54
|
+
def macos?
|
|
55
|
+
(@os || RbConfig::CONFIG['host_os']) =~ /darwin|mac os/
|
|
56
|
+
end
|
|
57
|
+
end
|
|
58
|
+
end
|
data/lib/rutie.rb
CHANGED
|
@@ -1,4 +1,11 @@
|
|
|
1
1
|
class Rutie
|
|
2
|
+
# Raised by #init when the compiled Rust library is not where Rutie looks for
|
|
3
|
+
# it. A LoadError, so code that rescues LoadError keeps working.
|
|
4
|
+
class LibraryNotFound < LoadError; end
|
|
5
|
+
|
|
6
|
+
# Raised by #init when the library has no function with the init name.
|
|
7
|
+
class InitFunctionNotFound < LoadError; end
|
|
8
|
+
|
|
2
9
|
def initialize(project_name, **opts)
|
|
3
10
|
@os = opts.fetch(:os) { nil } # for testing purposes
|
|
4
11
|
|
|
@@ -9,23 +16,68 @@ class Rutie
|
|
|
9
16
|
@full_lib_path = opts.fetch(:lib_path) { nil }
|
|
10
17
|
end
|
|
11
18
|
|
|
19
|
+
# The path of the compiled library. With no `lib_path` option, Rutie looks in
|
|
20
|
+
# `$CARGO_TARGET_DIR/<release>` when that variable is set, then in
|
|
21
|
+
# `../target/<release>` relative to `dir`, and returns the first that holds
|
|
22
|
+
# the library (or the first candidate when none does).
|
|
12
23
|
def ffi_library(dir)
|
|
13
|
-
|
|
24
|
+
candidates = library_candidates(dir)
|
|
14
25
|
|
|
15
|
-
File.
|
|
26
|
+
candidates.find { |path| File.exist?(path) } || candidates.first
|
|
16
27
|
end
|
|
17
28
|
|
|
18
|
-
|
|
29
|
+
# Loads the compiled Rust library and calls its init function, which defaults
|
|
30
|
+
# to `Init_<project_name>`:
|
|
31
|
+
#
|
|
32
|
+
# Rutie.new(:my_ext).init __dir__
|
|
33
|
+
# Rutie.new(:my_ext).init 'Init_my_ext', __dir__
|
|
34
|
+
def init(c_init_method_name = "Init_#{@project_name}", dir)
|
|
35
|
+
library = ffi_library(dir)
|
|
36
|
+
raise LibraryNotFound, library_not_found_message(dir) unless File.exist?(library)
|
|
37
|
+
|
|
19
38
|
require 'fiddle'
|
|
20
39
|
|
|
21
|
-
Fiddle
|
|
40
|
+
handle = Fiddle.dlopen(library)
|
|
41
|
+
function =
|
|
42
|
+
begin
|
|
43
|
+
handle[c_init_method_name]
|
|
44
|
+
rescue Fiddle::DLError
|
|
45
|
+
raise InitFunctionNotFound, init_not_found_message(library, c_init_method_name)
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
Fiddle::Function.new(function, [], Fiddle::TYPE_VOIDP).call
|
|
22
49
|
end
|
|
23
50
|
|
|
24
51
|
private
|
|
25
|
-
def
|
|
26
|
-
|
|
52
|
+
def library_file
|
|
53
|
+
[ @lib_prefix, @project_name, '.', @lib_suffix ].join
|
|
54
|
+
end
|
|
55
|
+
|
|
56
|
+
def library_candidates(dir)
|
|
57
|
+
file = library_file
|
|
58
|
+
|
|
59
|
+
return [File.join(File.expand_path(@full_lib_path, dir), file)] if @full_lib_path
|
|
60
|
+
|
|
61
|
+
candidates = []
|
|
62
|
+
target_dir = ENV['CARGO_TARGET_DIR']
|
|
63
|
+
# Cargo resolves a relative CARGO_TARGET_DIR against the working directory.
|
|
64
|
+
candidates << File.join(File.expand_path(@release, target_dir), file) unless target_dir.nil? || target_dir.empty?
|
|
65
|
+
candidates << File.join(File.expand_path("../target/#{@release}", dir), file)
|
|
66
|
+
candidates.uniq
|
|
67
|
+
end
|
|
68
|
+
|
|
69
|
+
def library_not_found_message(dir)
|
|
70
|
+
profile = @release == 'release' ? ' --release' : ''
|
|
71
|
+
|
|
72
|
+
"Rutie could not find the compiled library for #{@project_name}. " \
|
|
73
|
+
"Looked for: #{library_candidates(dir).join(', ')}. " \
|
|
74
|
+
"Build it with `cargo build#{profile}` (see Rutie::RakeTask), " \
|
|
75
|
+
"or pass `lib_path:` to Rutie.new."
|
|
76
|
+
end
|
|
27
77
|
|
|
28
|
-
|
|
78
|
+
def init_not_found_message(library, name)
|
|
79
|
+
"#{library} has no function #{name}. Define it in Rust as " \
|
|
80
|
+
"`#[no_mangle] pub extern \"C\" fn #{name}()`, or pass its name to Rutie#init."
|
|
29
81
|
end
|
|
30
82
|
|
|
31
83
|
def set_prefix
|
|
@@ -66,10 +118,12 @@ class Rutie
|
|
|
66
118
|
def to_str
|
|
67
119
|
@name
|
|
68
120
|
end
|
|
121
|
+
alias to_s to_str
|
|
69
122
|
|
|
70
123
|
private
|
|
124
|
+
# A Cargo library name: snake_case, and digits after the first character.
|
|
71
125
|
def valid_name?(project)
|
|
72
|
-
project.
|
|
126
|
+
project.match?(/\A[a-z_][a-z0-9_]*\z/)
|
|
73
127
|
end
|
|
74
128
|
|
|
75
129
|
class InvalidProjectName < StandardError
|
data/rutie.gemspec
CHANGED
|
@@ -4,7 +4,7 @@ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
|
|
4
4
|
|
|
5
5
|
Gem::Specification.new do |spec|
|
|
6
6
|
spec.name = 'rutie'
|
|
7
|
-
spec.version = '0.0.
|
|
7
|
+
spec.version = '0.0.5'
|
|
8
8
|
spec.authors = ['Daniel P. Clark']
|
|
9
9
|
spec.email = ['6ftdan@gmail.com']
|
|
10
10
|
spec.summary = 'Rutie helper methods.'
|
|
@@ -12,5 +12,9 @@ Gem::Specification.new do |spec|
|
|
|
12
12
|
spec.homepage = 'https://github.com/danielpclark/rutie'
|
|
13
13
|
spec.license = 'MIT'
|
|
14
14
|
|
|
15
|
-
spec.files = %w[rutie.gemspec lib/rutie.rb LICENSE]
|
|
15
|
+
spec.files = %w[rutie.gemspec lib/rutie.rb lib/rutie/rake_task.rb LICENSE]
|
|
16
|
+
|
|
17
|
+
# Rutie#init loads the extension with Fiddle, a bundled gem rather than a
|
|
18
|
+
# default gem since Ruby 4.0, so Bundler needs it declared.
|
|
19
|
+
spec.add_dependency 'fiddle'
|
|
16
20
|
end
|
metadata
CHANGED
|
@@ -1,15 +1,28 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: rutie
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.0.
|
|
4
|
+
version: 0.0.5
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Daniel P. Clark
|
|
8
|
-
autorequire:
|
|
9
8
|
bindir: bin
|
|
10
9
|
cert_chain: []
|
|
11
|
-
date:
|
|
12
|
-
dependencies:
|
|
10
|
+
date: 1980-01-02 00:00:00.000000000 Z
|
|
11
|
+
dependencies:
|
|
12
|
+
- !ruby/object:Gem::Dependency
|
|
13
|
+
name: fiddle
|
|
14
|
+
requirement: !ruby/object:Gem::Requirement
|
|
15
|
+
requirements:
|
|
16
|
+
- - ">="
|
|
17
|
+
- !ruby/object:Gem::Version
|
|
18
|
+
version: '0'
|
|
19
|
+
type: :runtime
|
|
20
|
+
prerelease: false
|
|
21
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
22
|
+
requirements:
|
|
23
|
+
- - ">="
|
|
24
|
+
- !ruby/object:Gem::Version
|
|
25
|
+
version: '0'
|
|
13
26
|
description: Rutie — The Tie Between Ruby and Rust. Helper methods gem for Rutie.
|
|
14
27
|
email:
|
|
15
28
|
- 6ftdan@gmail.com
|
|
@@ -19,12 +32,12 @@ extra_rdoc_files: []
|
|
|
19
32
|
files:
|
|
20
33
|
- LICENSE
|
|
21
34
|
- lib/rutie.rb
|
|
35
|
+
- lib/rutie/rake_task.rb
|
|
22
36
|
- rutie.gemspec
|
|
23
37
|
homepage: https://github.com/danielpclark/rutie
|
|
24
38
|
licenses:
|
|
25
39
|
- MIT
|
|
26
40
|
metadata: {}
|
|
27
|
-
post_install_message:
|
|
28
41
|
rdoc_options: []
|
|
29
42
|
require_paths:
|
|
30
43
|
- lib
|
|
@@ -39,8 +52,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
|
39
52
|
- !ruby/object:Gem::Version
|
|
40
53
|
version: '0'
|
|
41
54
|
requirements: []
|
|
42
|
-
rubygems_version:
|
|
43
|
-
signing_key:
|
|
55
|
+
rubygems_version: 4.0.20
|
|
44
56
|
specification_version: 4
|
|
45
57
|
summary: Rutie helper methods.
|
|
46
58
|
test_files: []
|