julia 0.1.0 → 0.2.0

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
- SHA1:
3
- metadata.gz: ffe6273a8591b918cc6e38e68d6f3301e2b14bee
4
- data.tar.gz: 790bd12e87a137f6b57e7926517da57bde91c552
2
+ SHA256:
3
+ metadata.gz: 761658bd92a75b136265135887ffe7ca82a3c42d7e5d15ea5f6f9d8212d23ec1
4
+ data.tar.gz: 0052f5ad9249ff2063eceae0919573fea27039611824cad251b5aa63bdef57e1
5
5
  SHA512:
6
- metadata.gz: e3f48e6edcb0d0ee8d15d4775fd61dcc046824af9d8b6df0f81ed035f84785d70c33371d0ead89ae63f96ce0088602002a287b03dc8e040839304e4103195651
7
- data.tar.gz: 4d0a8208bda0274b58610bc40cf11d937561e471679fbe4bcb7f991e917c51670d772fff62fb889ff5951482e1989a19f70c091311e69fc5b7cbc584a6e2d3a7
6
+ metadata.gz: d6cf4724a9648c91ec03ed60fc1e9f3a337adc11ba1320ac74fedb7a0b6d12bde7fe1f050e9ca4e1d594caf45991977ee8f68ed6620d5beeb9fae79f6ca04c5b
7
+ data.tar.gz: 01d84c23f8c58efa7bd41a241389195e50a6842a6bd0ba0ae7fae77abb5b04bcb135d022b8cfe6a6372b5d4bcfbf18c8a3dd0b4f13f385057e898667c014b120
data/README.md CHANGED
@@ -2,6 +2,20 @@
2
2
 
3
3
  Julia on Ruby.
4
4
 
5
+ ## Supported versions
6
+
7
+ ### Ruby
8
+
9
+ - 2.5
10
+ - 2.4
11
+ - 2.3
12
+
13
+ ### Julia
14
+
15
+ - 1.0
16
+ - 0.7
17
+ - 0.6
18
+
5
19
  ## Installation
6
20
 
7
21
  Add this line to your application's Gemfile:
@@ -23,14 +37,17 @@ Or install it yourself as:
23
37
  ```ruby
24
38
  require 'julia'
25
39
 
26
- Julia.init(ENV['JULIA_HOME'])
27
- Julia.eval_string('print(pi)')
40
+ Julia.eval('print(pi)')
28
41
  ```
29
42
 
30
43
  ## Contributing
31
44
 
32
- Bug reports and pull requests are welcome on GitHub at https://github.com/[USERNAME]/julia.
45
+ Bug reports and pull requests are welcome on GitHub at https://github.com/mrkn/julia.
46
+
47
+ ## Authors
33
48
 
49
+ - Kenta Murata
50
+ - Kenta Tanoue
34
51
 
35
52
  ## License
36
53
 
data/Rakefile CHANGED
@@ -1,6 +1,11 @@
1
- require "bundler/gem_tasks"
2
- require "rspec/core/rake_task"
1
+ require "bundler"
2
+ Bundler::GemHelper.install_tasks
3
+
4
+ require "rake"
3
5
  require "rake/extensiontask"
6
+ require "rspec/core/rake_task"
7
+
8
+ Dir[File.expand_path('../tasks/**/*.rake', __FILE__)].each {|f| load f }
4
9
 
5
10
  Rake::ExtensionTask.new('julia')
6
11
 
@@ -6,9 +6,5 @@ require "julia"
6
6
  # You can add fixtures and/or initialization code here to make experimenting
7
7
  # with your gem easier. You can also use a different console, if you like.
8
8
 
9
- # (If you use this, don't forget to add pry to your Gemfile!)
10
- # require "pry"
11
- # Pry.start
12
-
13
- require "irb"
14
- IRB.start
9
+ require "pry"
10
+ Pry.start
@@ -1,8 +1,3 @@
1
1
  require 'mkmf'
2
2
 
3
- dir_config('julia')
4
- have_header('julia.h')
5
- have_library('julia')
6
- have_func('jl_init')
7
-
8
- create_makefile('julia')
3
+ create_makefile('julia')
@@ -1,30 +1,19 @@
1
- #include <julia.h>
2
- #include <ruby.h>
1
+ #include "julia_internal.h"
3
2
 
4
- VALUE rbjl_mJulia;
3
+ VALUE julia_mJulia;
5
4
 
6
- static VALUE
7
- rbjl_julia_s_init(VALUE mod, VALUE home)
5
+ static void
6
+ init_julia(void)
8
7
  {
9
- SafeStringValue(home);
10
- jl_init(NIL_P(home) ? NULL : StringValueCStr(home));
11
- return mod;
12
- }
13
-
14
- static VALUE
15
- rbjl_julia_s_eval_string(VALUE mod, VALUE str)
16
- {
17
- SafeStringValue(str);
18
- jl_eval_string(StringValueCStr(str));
19
-
20
- return mod;
8
+ JULIA_API(jl_init)();
21
9
  }
22
10
 
23
11
  void
24
12
  Init_julia(void)
25
13
  {
26
- rbjl_mJulia = rb_define_module("Julia");
14
+ julia_mJulia = rb_define_module("Julia");
15
+
16
+ julia_init_libjulia();
27
17
 
28
- rb_define_module_function(rbjl_mJulia, "init", rbjl_julia_s_init, 1);
29
- rb_define_module_function(rbjl_mJulia, "eval_string", rbjl_julia_s_eval_string, 1);
18
+ init_julia();
30
19
  }
@@ -0,0 +1,125 @@
1
+ #ifndef JULIA_INTERNAL_H
2
+ #define JULIA_INTERNAL_H 1
3
+ #define JL_DATA_TYPE
4
+
5
+ #ifdef __cplusplus
6
+ extern "C" {
7
+ #if 0
8
+ } /* satisfy cc-mode */
9
+ #endif
10
+ #endif
11
+
12
+ #include <ruby.h>
13
+
14
+ #if SIZEOF_LONG == SIZEOF_VOIDP
15
+ # define PTR2NUM(x) (LONG2NUM((long)(x)))
16
+ # define NUM2PTR(x) ((void*)(NUM2ULONG(x)))
17
+ #elif SIZEOF_LONG_LONG == SIZEOF_VOIDP
18
+ # define PTR2NUM(x) (LL2NUM((LONG_LONG)(x)))
19
+ # define NUM2PTR(x) ((void*)(NUM2ULL(x)))
20
+ #else
21
+ # error ---->> ruby requires sizeof(void*) == sizeof(long) or sizeof(LONG_LONG) to be compiled. <<----
22
+ #endif
23
+
24
+ typedef struct _jl_value_t jl_value_t;
25
+ typedef struct _jl_taggedvalue_t jl_taggedvalue_t;
26
+
27
+ typedef struct _jl_sym_t {
28
+ JL_DATA_TYPE
29
+ struct _jl_sym_t *left;
30
+ struct _jl_sym_t *right;
31
+ uintptr_t hash;
32
+ } jl_sym_t;
33
+
34
+ typedef struct {
35
+ JL_DATA_TYPE
36
+ size_t length;
37
+ } jl_svec_t;
38
+
39
+ typedef struct {
40
+ uint32_t nfields;
41
+ uint32_t alignment : 9;
42
+ uint32_t haspadding : 1;
43
+ uint32_t npointers : 20;
44
+ uint32_t fielddesc_type : 2;
45
+ } jl_datatype_layout_t;
46
+
47
+ typedef struct {
48
+ JL_DATA_TYPE
49
+ jl_sym_t *name;
50
+ struct _jl_module_t *module;
51
+ jl_svec_t *names;
52
+ jl_value_t *wrapper;
53
+ jl_svec_t *cache;
54
+ jl_svec_t *linearcache;
55
+ intptr_t hash;
56
+ struct _jl_methtable_t *mt;
57
+ } jl_typename_t;
58
+
59
+ typedef struct _jl_datatype_t {
60
+ JL_DATA_TYPE
61
+ jl_typename_t *name;
62
+ struct _jl_datatype_t *super;
63
+ jl_svec_t *parameters;
64
+ jl_svec_t *types;
65
+ jl_svec_t *names;
66
+ jl_value_t *instance;
67
+ const jl_datatype_layout_t *layout;
68
+ int32_t size;
69
+ int32_t ninitialized;
70
+ uint32_t uid;
71
+ uint8_t abstract;
72
+ uint8_t mutabl;
73
+ uint8_t hasfreetypevars;
74
+ uint8_t isconcretetype;
75
+ uint8_t isdispatchtuple;
76
+ uint8_t isbitstype;
77
+ uint8_t zeroinit;
78
+ uint8_t isinlinealloc;
79
+ void *struct_decl;
80
+ void *ditype;
81
+ } jl_datatype_t;
82
+
83
+ struct julia_api_table {
84
+ int (* jl_is_initialized)(void);
85
+ void (* jl_init)(void);
86
+ char const * (* jl_ver_string)(void);
87
+ jl_datatype_t *jl_bool_type;
88
+ jl_datatype_t *jl_char_type;
89
+ jl_datatype_t *jl_string_type;
90
+ jl_datatype_t *jl_int8_type;
91
+ jl_datatype_t *jl_uint8_type;
92
+ jl_datatype_t *jl_int16_type;
93
+ jl_datatype_t *jl_uint16_type;
94
+ jl_datatype_t *jl_int32_type;
95
+ jl_datatype_t *jl_uint32_type;
96
+ jl_datatype_t *jl_int64_type;
97
+ jl_datatype_t *jl_uint64_type;
98
+ jl_datatype_t *jl_float16_type;
99
+ jl_datatype_t *jl_float32_type;
100
+ jl_datatype_t *jl_float64_type;
101
+ jl_value_t * (* jl_eval_string)(const char *str);
102
+ jl_value_t * (* jl_typeof)(jl_value_t *v);
103
+ const char * (* jl_typeof_str)(jl_value_t *v);
104
+ const char * (* jl_string_ptr)(jl_value_t *s);
105
+ int8_t (* jl_unbox_bool)(jl_value_t *v);
106
+ int8_t (* jl_unbox_int8)(jl_value_t *v);
107
+ uint8_t (* jl_unbox_uint8)(jl_value_t *v);
108
+ int16_t (* jl_unbox_int16)(jl_value_t *v);
109
+ uint16_t (* jl_unbox_uint16)(jl_value_t *v);
110
+ int32_t (* jl_unbox_int32)(jl_value_t *v);
111
+ uint32_t (* jl_unbox_uint32)(jl_value_t *v);
112
+ int64_t (* jl_unbox_int64)(jl_value_t *v);
113
+ uint64_t (* jl_unbox_uint64)(jl_value_t *v);
114
+ float (* jl_unbox_float32)(jl_value_t *v);
115
+ double (* jl_unbox_float64)(jl_value_t *v);
116
+ };
117
+
118
+ struct julia_api_table *julia_get_api_table(void);
119
+ #define JULIA_API(name) (julia_get_api_table()->name)
120
+
121
+ void julia_init_libjulia(void);
122
+
123
+ extern VALUE julia_mJulia;
124
+ extern VALUE julia_mLibJulia;
125
+ #endif /* JULIA_INTERNAL_H */
@@ -0,0 +1,253 @@
1
+ #include "julia_internal.h"
2
+
3
+ VALUE julia_mLibJulia;
4
+ VALUE julia_eAPINotFound;
5
+ struct julia_api_table api_table;
6
+ jl_value_t *ans;
7
+ int8_t ans_bool;
8
+
9
+ struct julia_api_table *
10
+ julia_get_api_table(void)
11
+ {
12
+ return &api_table;
13
+ }
14
+
15
+ struct lookup_api_args {
16
+ VALUE handle;
17
+ char const *name;
18
+ };
19
+
20
+ static VALUE
21
+ lookup_libjulia_api_0(struct lookup_api_args *args)
22
+ {
23
+ return rb_funcall(args->handle, rb_intern("sym"), 1, rb_str_new2(args->name));
24
+ }
25
+
26
+ static void *
27
+ lookup_libjulia_api(VALUE handle, char const *name)
28
+ {
29
+ struct lookup_api_args arg;
30
+ VALUE addr;
31
+ int state;
32
+
33
+ arg.handle = handle;
34
+ arg.name = name;
35
+ addr = rb_protect((VALUE (*)(VALUE))lookup_libjulia_api_0, (VALUE)&arg, &state);
36
+ return (state || NIL_P(addr)) ? NULL : NUM2PTR(addr);
37
+ }
38
+
39
+ static void
40
+ init_api_table(VALUE handle)
41
+ {
42
+ #define LOOKUP_API_ENTRY(api_name) lookup_libjulia_api(handle, #api_name)
43
+ #define CHECK_API_ENTRY(api_name) (LOOKUP_API_ENTRY(api_name) != NULL)
44
+ #define INIT_API_TABLE_ENTRY2(member_name, api_name) do { \
45
+ void *fptr = LOOKUP_API_ENTRY(api_name); \
46
+ if (!fptr) { \
47
+ rb_raise(julia_eAPINotFound, "Unable to find the required symbol in libjulia: %s", #api_name); \
48
+ } \
49
+ ((api_table).member_name) = fptr; \
50
+ } while (0)
51
+ #define INIT_API_TABLE_ENTRY(api_name) INIT_API_TABLE_ENTRY2(api_name, api_name)
52
+
53
+ if (CHECK_API_ENTRY(jl_init)) {
54
+ INIT_API_TABLE_ENTRY(jl_init);
55
+ }
56
+ else {
57
+ INIT_API_TABLE_ENTRY2(jl_init, jl_init__threading);
58
+ }
59
+
60
+ INIT_API_TABLE_ENTRY(jl_is_initialized);
61
+ INIT_API_TABLE_ENTRY(jl_ver_string);
62
+
63
+ INIT_API_TABLE_ENTRY(jl_bool_type);
64
+ INIT_API_TABLE_ENTRY(jl_char_type);
65
+ INIT_API_TABLE_ENTRY(jl_string_type);
66
+ INIT_API_TABLE_ENTRY(jl_int8_type);
67
+ INIT_API_TABLE_ENTRY(jl_uint8_type);
68
+ INIT_API_TABLE_ENTRY(jl_int16_type);
69
+ INIT_API_TABLE_ENTRY(jl_uint16_type);
70
+ INIT_API_TABLE_ENTRY(jl_int32_type);
71
+ INIT_API_TABLE_ENTRY(jl_uint32_type);
72
+ INIT_API_TABLE_ENTRY(jl_int64_type);
73
+ INIT_API_TABLE_ENTRY(jl_uint64_type);
74
+ INIT_API_TABLE_ENTRY(jl_float16_type);
75
+ INIT_API_TABLE_ENTRY(jl_float32_type);
76
+ INIT_API_TABLE_ENTRY(jl_float64_type);
77
+ INIT_API_TABLE_ENTRY(jl_eval_string);
78
+ INIT_API_TABLE_ENTRY(jl_typeof);
79
+ INIT_API_TABLE_ENTRY(jl_typeof_str);
80
+ INIT_API_TABLE_ENTRY(jl_string_ptr);
81
+ INIT_API_TABLE_ENTRY(jl_unbox_bool);
82
+ INIT_API_TABLE_ENTRY(jl_unbox_int8);
83
+ INIT_API_TABLE_ENTRY(jl_unbox_uint8);
84
+ INIT_API_TABLE_ENTRY(jl_unbox_int16);
85
+ INIT_API_TABLE_ENTRY(jl_unbox_uint16);
86
+ INIT_API_TABLE_ENTRY(jl_unbox_int32);
87
+ INIT_API_TABLE_ENTRY(jl_unbox_uint32);
88
+ INIT_API_TABLE_ENTRY(jl_unbox_int64);
89
+ INIT_API_TABLE_ENTRY(jl_unbox_uint64);
90
+ INIT_API_TABLE_ENTRY(jl_unbox_float32);
91
+ INIT_API_TABLE_ENTRY(jl_unbox_float64);
92
+ }
93
+
94
+ int
95
+ jl_typeis(jl_value_t *v, jl_datatype_t *t){
96
+ return ((jl_typename_t *)JULIA_API(jl_typeof)(v) == t->name);
97
+ }
98
+
99
+ int
100
+ jl_is_bool(jl_value_t *v)
101
+ {
102
+ return jl_typeis(v, JULIA_API(jl_bool_type));
103
+ }
104
+
105
+ int
106
+ jl_is_char(jl_value_t *v)
107
+ {
108
+ return jl_typeis(v, JULIA_API(jl_char_type));
109
+ }
110
+
111
+ int
112
+ jl_is_string(jl_value_t *v)
113
+ {
114
+ return jl_typeis(v, JULIA_API(jl_string_type));
115
+ }
116
+
117
+ int
118
+ jl_is_int8(jl_value_t *v)
119
+ {
120
+ return jl_typeis(v, JULIA_API(jl_int8_type));
121
+ }
122
+
123
+ int
124
+ jl_is_uint8(jl_value_t *v)
125
+ {
126
+ return jl_typeis(v, JULIA_API(jl_uint8_type));
127
+ }
128
+
129
+ int
130
+ jl_is_int16(jl_value_t *v)
131
+ {
132
+ return jl_typeis(v, JULIA_API(jl_int16_type));
133
+ }
134
+
135
+ int
136
+ jl_is_uint16(jl_value_t *v)
137
+ {
138
+ return jl_typeis(v, JULIA_API(jl_uint16_type));
139
+ }
140
+
141
+ int
142
+ jl_is_int32(jl_value_t *v)
143
+ {
144
+ return jl_typeis(v, JULIA_API(jl_int32_type));
145
+ }
146
+
147
+ int
148
+ jl_is_uint32(jl_value_t *v)
149
+ {
150
+ return jl_typeis(v, JULIA_API(jl_uint32_type));
151
+ }
152
+
153
+ int
154
+ jl_is_int64(jl_value_t *v)
155
+ {
156
+ return jl_typeis(v, JULIA_API(jl_int64_type));
157
+ }
158
+
159
+ int
160
+ jl_is_uint64(jl_value_t *v)
161
+ {
162
+ return jl_typeis(v, JULIA_API(jl_uint64_type));
163
+ }
164
+
165
+ int
166
+ jl_is_float16(jl_value_t *v)
167
+ {
168
+ return jl_typeis(v, JULIA_API(jl_float16_type));
169
+ }
170
+
171
+ int
172
+ jl_is_float32(jl_value_t *v)
173
+ {
174
+ return jl_typeis(v, JULIA_API(jl_float32_type));
175
+ }
176
+
177
+ int
178
+ jl_is_float64(jl_value_t *v)
179
+ {
180
+ return jl_typeis(v, JULIA_API(jl_float64_type));
181
+ }
182
+
183
+ static VALUE
184
+ jl_eval_string(VALUE handle, VALUE arg)
185
+ {
186
+ Check_Type(arg, T_STRING);
187
+ ans = JULIA_API(jl_eval_string)(StringValuePtr(arg));
188
+ if (jl_is_string(ans)) {
189
+ return rb_str_new2(JULIA_API(jl_string_ptr)(ans));
190
+ }
191
+ if (jl_is_bool(ans)) {
192
+ ans_bool = JULIA_API(jl_unbox_bool)(ans);
193
+ if (ans_bool == 1){
194
+ return Qtrue;
195
+ }else{
196
+ return Qfalse;
197
+ }
198
+ }
199
+ if (jl_is_int8(ans)) {
200
+ return INT2NUM(JULIA_API(jl_unbox_int8)(ans));
201
+ }
202
+ if (jl_is_uint8(ans)) {
203
+ return INT2NUM(JULIA_API(jl_unbox_uint8)(ans));
204
+ }
205
+ if (jl_is_int16(ans)) {
206
+ return INT2NUM(JULIA_API(jl_unbox_int16)(ans));
207
+ }
208
+ if (jl_is_uint16(ans)) {
209
+ return INT2NUM(JULIA_API(jl_unbox_uint16)(ans));
210
+ }
211
+ if (jl_is_int32(ans)) {
212
+ return INT2NUM(JULIA_API(jl_unbox_int32)(ans));
213
+ }
214
+ if (jl_is_uint32(ans)) {
215
+ return INT2NUM(JULIA_API(jl_unbox_uint32)(ans));
216
+ }
217
+ if (jl_is_int64(ans)) {
218
+ return INT2NUM(JULIA_API(jl_unbox_int64)(ans));
219
+ }
220
+ if (jl_is_uint64(ans)) {
221
+ return INT2NUM(JULIA_API(jl_unbox_uint64)(ans));
222
+ }
223
+ if (jl_is_float32(ans)) {
224
+ return DBL2NUM(JULIA_API(jl_unbox_float32)(ans));
225
+ }
226
+ if (jl_is_float64(ans)) {
227
+ return DBL2NUM(JULIA_API(jl_unbox_float64)(ans));
228
+ }
229
+ return rb_str_new2(JULIA_API(jl_typeof_str)(ans));
230
+ }
231
+
232
+ static void
233
+ define_JULIA_VERSION(void)
234
+ {
235
+ char const *version = JULIA_API(jl_ver_string)();
236
+ rb_define_const(julia_mLibJulia, "JULIA_VERSION", rb_usascii_str_new_static(version, strlen(version)));
237
+ }
238
+
239
+ void
240
+ julia_init_libjulia(void)
241
+ {
242
+ VALUE handle;
243
+ julia_mLibJulia = rb_const_get_at(julia_mJulia, rb_intern("LibJulia"));
244
+ handle = rb_funcall(julia_mLibJulia, rb_intern("handle"), 0);
245
+ rb_define_module_function(julia_mLibJulia, "jl_eval_string", jl_eval_string, 1);
246
+ init_api_table(handle);
247
+
248
+ if (JULIA_API(jl_is_initialized)() == 0) {
249
+ JULIA_API(jl_init)();
250
+ }
251
+
252
+ define_JULIA_VERSION();
253
+ }
@@ -1,5 +1,5 @@
1
- # coding: utf-8
2
- lib = File.expand_path('../lib', __FILE__)
1
+
2
+ lib = File.expand_path('lib', __dir__)
3
3
  $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
4
  require 'julia/version'
5
5
 
@@ -9,8 +9,8 @@ Gem::Specification.new do |spec|
9
9
  spec.authors = ["Kenta Murata"]
10
10
  spec.email = ["mrkn@cookpad.com"]
11
11
 
12
- spec.summary = %q{Julia on Ruby}
13
- spec.description = %q{Julia on Ruby}
12
+ spec.summary = 'Julia on Ruby'
13
+ spec.description = 'Julia on Ruby'
14
14
  spec.homepage = "https://github.com/mrkn/ruby-julia"
15
15
  spec.license = "MIT"
16
16
 
@@ -21,9 +21,11 @@ Gem::Specification.new do |spec|
21
21
  spec.bindir = "exe"
22
22
  spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
23
23
  spec.require_paths = ["lib"]
24
- spec.extensions << 'ext/julia/extconf.rb'
25
24
 
26
25
  spec.add_development_dependency "bundler", "~> 1.10"
26
+ spec.add_development_dependency "pry"
27
+ spec.add_development_dependency "pry-byebug"
27
28
  spec.add_development_dependency "rake", "~> 10.0"
29
+ spec.add_development_dependency "rake-compiler"
28
30
  spec.add_development_dependency "rspec"
29
31
  end
@@ -0,0 +1,12 @@
1
+ module Julia
2
+ require 'julia/version'
3
+ require 'julia/libjulia'
4
+ require 'julia/init'
5
+
6
+ module_function
7
+
8
+ def eval(str)
9
+ Julia.init unless LibJulia.respond_to? :jl_eval_string
10
+ LibJulia.jl_eval_string(str)
11
+ end
12
+ end
@@ -0,0 +1,7 @@
1
+ module Julia
2
+ class Error < StandardError
3
+ end
4
+
5
+ class JuliaNotFound < Error
6
+ end
7
+ end
@@ -0,0 +1,49 @@
1
+ module Julia
2
+ def self.const_missing(name)
3
+ case name
4
+ when :JULIA_VERSION
5
+ Julia.init
6
+ const_get(name)
7
+ else
8
+ super
9
+ end
10
+ end
11
+
12
+ module LibJulia
13
+ def self.const_missing(name)
14
+ case name
15
+ when :JULIA_VERSION
16
+ Julia.init
17
+ const_get(name)
18
+ else
19
+ super
20
+ end
21
+ end
22
+ end
23
+
24
+ def self.init(julia = ENV['JULIA'])
25
+ return false if LibJulia.instance_variable_defined? :@handle
26
+ class << Julia
27
+ remove_method :const_missing
28
+ end
29
+ class << Julia::LibJulia
30
+ remove_method :const_missing
31
+ end
32
+
33
+ LibJulia.instance_variable_set :@handle, LibJulia::Finder.find_libjulia(julia)
34
+ class << LibJulia
35
+ undef_method :handle
36
+ attr_reader :handle
37
+ end
38
+
39
+ begin
40
+ major, minor, _ = RUBY_VERSION.split('.')
41
+ require "#{major}.#{minor}/julia.so"
42
+ rescue LoadError
43
+ require 'julia.so'
44
+ end
45
+
46
+ const_set(:JULIA_VERSION, LibJulia::JULIA_VERSION)
47
+ true
48
+ end
49
+ end
@@ -0,0 +1,18 @@
1
+ module Julia
2
+ module LibJulia
3
+ require 'julia/libjulia/finder'
4
+
5
+ def self.load_lib
6
+ require 'julia/libjulia/finder'
7
+ lib_path = Finder.find_libjulia
8
+ Fiddle::Handle.new(lib_path[0], Fiddle::Handle::RTLD_LAZY | Fiddle::Handle::RTLD_GLOBAL)
9
+ end
10
+
11
+ def self.handle
12
+ # NOTE: Julia.init redefine this method.
13
+ # See julia/init.rb for the detail.
14
+ Julia.init
15
+ handle
16
+ end
17
+ end
18
+ end
@@ -0,0 +1,102 @@
1
+ require 'julia/error'
2
+ require 'fiddle'
3
+
4
+ module Julia
5
+ module LibJulia
6
+ module Finder
7
+ case RUBY_PLATFORM
8
+ when /cygwin/
9
+ libprefix = 'cyg'
10
+ libsuffix = 'dll'
11
+ when /mingw/, /mswin/
12
+ libprefix = ''
13
+ libsuffix = 'dll'
14
+ when /darwin/
15
+ libsuffix = 'dylib'
16
+ end
17
+
18
+ LIBPREFIX = libprefix || 'lib'
19
+ LIBSUFFIX = libsuffix || 'so'
20
+
21
+ class << self
22
+ DEFAULT_JULIA = -'julia'
23
+
24
+ def find_libjulia(julia = nil)
25
+ debug_report "find_libjulia(#{julia.inspect})"
26
+ julia_cmd, julia_config = investigate_julia(julia)
27
+
28
+ libpath = File.join(julia_config[:libdir], "libjulia.#{LIBSUFFIX}")
29
+ if File.file? libpath
30
+ begin
31
+ return dlopen(libpath)
32
+ rescue Fiddle::DLError
33
+ debug_report "#{$!.class}: #{$!.message}"
34
+ else
35
+ debug_report "Success to dlopen #{fullname}"
36
+ end
37
+ else
38
+ debug_report "Unable to find #{fullname}"
39
+ end
40
+
41
+ raise Julia::JuliaNotFound
42
+ end
43
+
44
+ def investigate_julia(julia = nil)
45
+ julia ||= DEFAULT_JULIA
46
+ Array(julia).each do |julia_cmd|
47
+ julia_config = run_julia_investigator(julia_cmd)
48
+ return [julia_cmd, julia_config] unless julia_config.empty?
49
+ end
50
+ rescue
51
+ debug_report "investigate_julia: (#{$!.class}) #{$!.message}"
52
+ raise Julia::JuliaNotFound
53
+ else
54
+ raise Julia::JuliaNotFound
55
+ end
56
+
57
+ def run_julia_investigator(julia_cmd)
58
+ debug_report "run_julia_investigator(#{julia_cmd})"
59
+ IO.popen({}, [julia_cmd, julia_investigator_jl], 'r') do |io|
60
+ {}.tap do |config|
61
+ io.each_line do |line|
62
+ next unless line =~ /: /
63
+ key, value = line.chomp.split(': ', 2)
64
+ case value
65
+ when 'true', 'false'
66
+ value = (value == 'true')
67
+ end
68
+ config[key.to_sym] = value if value != 'nothing'
69
+ end
70
+ end
71
+ end
72
+ rescue Errno::ENOENT
73
+ raise Julia::JuliaNotFound
74
+ end
75
+
76
+ def julia_investigator_jl
77
+ File.expand_path('../investigator.jl', __FILE__)
78
+ end
79
+
80
+ private
81
+
82
+ def dlopen(path)
83
+ # NOTE: libjulia needs to be dlopened with RTLD_GLOBAL.
84
+ # Fiddle.dlopen(path) is same as Fiddle::Handle.new(path),
85
+ # and Fiddle::Handle.new defaultly specifies RTLD_GLOBAL.
86
+ Fiddle.dlopen(path).tap do |handle|
87
+ debug_report "dlopen(#{path.inspect}) = #{handle.inspect}" if handle
88
+ end
89
+ end
90
+
91
+ def debug_report(message)
92
+ return unless debug?
93
+ $stderr.puts "DEBUG(find_libjulia) #{message}"
94
+ end
95
+
96
+ def debug?
97
+ @debug_p ||= (ENV['RUBY_JULIA_DEBUG_FIND_LIBJULIA'] == '1')
98
+ end
99
+ end
100
+ end
101
+ end
102
+ end
@@ -0,0 +1,18 @@
1
+ # See https://github.com/JuliaLang/julia/pull/25102
2
+ if VERSION < v"0.7.0-DEV.3073"
3
+ bindir = JULIA_HOME
4
+ else
5
+ bindir = Sys.BINDIR
6
+ end
7
+
8
+ if VERSION >= v"0.7.0-DEV.3382"
9
+ using Libdl
10
+ end
11
+
12
+ println("VERSION: $(VERSION)")
13
+
14
+ jl_share = abspath(joinpath(bindir, Base.DATAROOTDIR, "julia"))
15
+ println("JL_HOME: $(jl_share)")
16
+
17
+ libdir = abspath(dirname(Libdl.dlpath("libjulia")))
18
+ println("libdir: $(libdir)")
@@ -0,0 +1,59 @@
1
+ function find_library(ruby::AbstractString)
2
+ v = rbexpr(ruby, "RUBY_VERSION", "")
3
+ libs = [ dlprefix*"ruby"*v, dlprefix*"ruby" ]
4
+ lib = rbconfig_expand(ruby, "\$(LIBRUBY_SO)")
5
+ lib != nothing && unshift!(libs, splitext(lib)[1])
6
+ libs = unique(libs)
7
+
8
+ libpaths = [ rbconfig_expand(ruby, "\$(libdir)") ]
9
+ ruby_path = rbexpr(ruby, "RbConfig.ruby")
10
+ if ruby_path != nothing
11
+ if is_windows()
12
+ push!(libpaths, dirname(ruby_path))
13
+ else
14
+ push!(libpaths, joinpath(dirname(dirname(ruby_path)), "lib"))
15
+ end
16
+ end
17
+ if is_apple()
18
+ # TODO: The framework directory of the system ruby should be added in libpaths
19
+ end
20
+
21
+ exec_prefix = rbconfig(ruby, "exec_prefix")
22
+ push!(libpaths, exec_prefix)
23
+ push!(libpaths, joinpath(exec_prefix, "lib"))
24
+
25
+ error_strings = Compat.String[]
26
+
27
+ # find libruby
28
+ for lib in libs
29
+ for libpath in libpaths
30
+ libpath_lib = joinpath(libpath, lib)
31
+ if isfile(libpath_lib*"."*Libdl.dlext)
32
+ try
33
+ return (Libdl.dlopen(libpath_lib,
34
+ Libdl.RTLD_LAZY | Libdl.RTLD_DEEPBIND | Libdl.RTLD_GLOBAL),
35
+ libpath_lib)
36
+ catch e
37
+ push!(error_strings, string("dlopen($libpath_lib) ==> ", e))
38
+ end
39
+ end
40
+ end
41
+ end
42
+
43
+ # find libruby from the system library path
44
+ for lib in libs
45
+ lib = splitext(lib)[1]
46
+ try
47
+ return (Libdl.dlopen(lib, Libdl.RTLD_LAZY | Libdl.RTLD_DEEPBIND | Libdl.RTLD_GLOBAL),
48
+ lib)
49
+ catch e
50
+ push!(error_strings, string("dlopen($lib) ==> ", e))
51
+ end
52
+ end
53
+ end
54
+
55
+ const ruby = "ruby"
56
+
57
+ const (libruby_handle, libruby) = find_library(ruby)
58
+ const programname = rbexpr(ruby, "RbConfig.ruby")
59
+ const ruby_version = convert(VersionNumber, rbexpr(ruby, "RUBY_VERSION"))
@@ -0,0 +1,168 @@
1
+ module Ruby
2
+
3
+ using Compat
4
+
5
+ # startup
6
+ # =======
7
+
8
+ hassym(lib, sym) = Libdl.dlsym_e(lib, sym) != C_NULL
9
+
10
+ function rbexpr(ruby::AbstractString, var::AbstractString)
11
+ val = chomp(readstring(`$ruby -rrbconfig -e "puts $var"`))
12
+ if val == ""
13
+ return nothing
14
+ end
15
+ return val
16
+ end
17
+
18
+ function rbexpr(ruby, var, default)
19
+ val = rbexpr(ruby, var)
20
+ return val == nothing ? default : val
21
+ end
22
+
23
+ function rbconfig(ruby::AbstractString, key::AbstractString)
24
+ return rbexpr(ruby, "RbConfig::CONFIG['$key']")
25
+ end
26
+
27
+ function rbconfig_expand(ruby::AbstractString, make_expr::AbstractString)
28
+ return rbexpr(ruby, "RbConfig.expand('$make_expr')")
29
+ end
30
+
31
+ const dlprefix = is_windows() ? "" : "lib"
32
+
33
+ immutable Dl_info
34
+ dli_fname::Ptr{UInt8}
35
+ dli_fbase::Ptr{Void}
36
+ dli_sname::Ptr{UInt8}
37
+ dli_saddr::Ptr{Void}
38
+ end
39
+
40
+ proc_handle = unsafe_load(@static is_windows() ?
41
+ cglobal(:jl_exe_handle, Ptr{Void}) :
42
+ cglobal(:jl_dl_handle, Ptr{Void}))
43
+
44
+ symbols_present = false
45
+ @static if is_windows()
46
+ EnumProcessModules(hProcess, lphModule, cb, lpcbNeeded) =
47
+ ccall(:K32EnumProcessModules, stdcall, Bool,
48
+ (Ptr{Void}, Ptr{Ptr{Void}}, UInt32, Ptr{UInt32}),
49
+ hProcess, lphModule, cb, lpcbNeeded)
50
+
51
+ lpcbNeeded = Ref{UInt32}()
52
+ handles = Vector{Ptr{Void}}(20)
53
+ if EnumProcessModules(proc_handle, handles, sizeof(handles), lpcbNeeded) == 0
54
+ resize!(handles, div(lpcbNeeded[], sizeof(Ptr{Void})))
55
+ EnumProcessModules(proc_handle, handles, sizeof(handles), lpcbNeeded)
56
+ end
57
+ # Try to find ruby if it's in the current process
58
+ for handle in handles
59
+ sym = ccall(:GetProcAddress, stdcall, Ptr{Void},
60
+ (Ptr{Void}, Ptr{UInt8}), handle, "rb_sysinit")
61
+ sym != C_NULL || continue
62
+ symbols_present = true
63
+ global libruby_handle = handle
64
+ break
65
+ end
66
+ else
67
+ symbols_present = hassym(proc_handle, :rb_sysinit)
68
+ end
69
+
70
+ if !symbols_present
71
+ # Ruby not present. Load libruby here.
72
+ include(joinpath(dirname(@__FILE__), "load_libruby.jl"))
73
+ else
74
+ @static if is_windows()
75
+ pathbuf = Vector{UInt16}(1024)
76
+ ret = ccall(:GetModuleFileNameW, stdcall, UInt32,
77
+ (Ptr{Void}, Ptr{UInt16}, UInt32),
78
+ libruby_handle, pathbuf, length(pathbuf))
79
+ @assert ret != 0
80
+ libname = String(Base.transcode(UInt8, pathbuf[1:findfirst(pathbuf, 0)-1]))
81
+ else
82
+ libruby_handle = proc_handle
83
+ # Now determine the name of the ruby library that these symbols are from
84
+ some_address_in_libruby = Libdl.dlsym(libruby_handle, :rb_sysinit)
85
+ dlinfo = Ref{Dl_info}()
86
+ ccall(:dladdr, Cint, (Ptr{Void}, Ptr{Dl_info}), some_address_in_libruby, dlinfo)
87
+ libname = unsafe_string(dlinfo[].dli_fname)
88
+ end
89
+ if Libdl.dlopen_e(libname) != C_NULL
90
+ const libruby = libname
91
+ else
92
+ const libruby = nothing
93
+ end
94
+ end
95
+
96
+ if libruby == nothing
97
+ macro rbsym(func)
98
+ :($func)
99
+ end
100
+ macro rbglobal(name)
101
+ :(cglobal($name))
102
+ end
103
+ else
104
+ macro rbsym(func)
105
+ :(($func, libruby))
106
+ end
107
+ macro rbglobal(name)
108
+ :(cglobal(($name, libruby)))
109
+ end
110
+ end
111
+
112
+ @static if sizeof(Clong) == sizeof(Ptr{Void})
113
+ typealias VALUE Culong
114
+ typealias ID Culong
115
+ typealias SIGNED_VALUE Clong
116
+ else
117
+ @static if sizeof(Clonglong) == sizeof(Ptr{Void})
118
+ typealias VALUE Culonglong
119
+ typealias ID Culonglong
120
+ typealias SIGNED_VALUE Clonglong
121
+ else
122
+ error("shouldn't be reached here")
123
+ end
124
+ end
125
+
126
+ # definitions
127
+ # -----------
128
+
129
+ # special constants - i.e. non-zero and non-fixnum constants
130
+
131
+ # NOTE: Ruby.jl assumes ruby was built with flonum support.
132
+
133
+ const Qfalse = VALUE(0x00) # ...0000 0000
134
+ const Qtrue = VALUE(0x14) # ...0001 0100
135
+ const Qnil = VALUE(0x08) # ...0000 1000
136
+ const Qundef = VALUE(0x34) # ...0011 0100
137
+
138
+ const IMMEDIATE_MASK = VALUE(0x07)
139
+ const FIXNUM_FLAG = VALUE(0x01) # ...xxxx xxx1
140
+ const FLONUM_MASK = VALUE(0x03)
141
+ const FLONUM_FLAG = VALUE(0x02) # ...xxxx xx10
142
+ const SYMBOL_FLAG = VALUE(0x0c) # ...0000 1100
143
+
144
+ const SPECIAL_SHIFT = VALUE(8)
145
+
146
+ const FIXNUM_MAX = typemax(Clong) >> 1
147
+ const FIXNUM_MIN = typemin(Clong) >> 1
148
+
149
+ LONG2FIX(i::Clong) = ((VALUE(i) << 1) | FIXNUM_FLAG)
150
+
151
+ FIX2LONG(x::VALUE) = Clong(SIGNED_VALUE(x) >> 1)
152
+ FIX2ULONG(x::VALUE) = Culong(FIX2LONG(x))
153
+ FIXNUM_P(f::SIGNED_VALUE) = (f & FIXNUM_FLAG) != 0
154
+ POSFIXABLE(f::Integer) = f < FIXNUM_MAX + 1
155
+ NEGFIXABLE(f::Integer) = f >= FIXNUM_MIN
156
+ FIXABLE(f::Integer) = POSFIXABLE(f) && NEGFIXABLE(f)
157
+
158
+ # initialize
159
+ # ----------
160
+
161
+ function __init__()
162
+ already_initialized = 0 != unsafe_load(Ptr{VALUE}(@rbglobal(:rb_cObject)))
163
+ if !already_initialized
164
+ ccall((@rbsym :ruby_init), Void, ())
165
+ end
166
+ end
167
+
168
+ end # module Ruby
@@ -1,3 +1,3 @@
1
1
  module Julia
2
- VERSION = "0.1.0"
2
+ VERSION = "0.2.0"
3
3
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: julia
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.0
4
+ version: 0.2.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Kenta Murata
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2015-07-13 00:00:00.000000000 Z
11
+ date: 2018-08-29 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bundler
@@ -24,6 +24,34 @@ dependencies:
24
24
  - - "~>"
25
25
  - !ruby/object:Gem::Version
26
26
  version: '1.10'
27
+ - !ruby/object:Gem::Dependency
28
+ name: pry
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - ">="
32
+ - !ruby/object:Gem::Version
33
+ version: '0'
34
+ type: :development
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - ">="
39
+ - !ruby/object:Gem::Version
40
+ version: '0'
41
+ - !ruby/object:Gem::Dependency
42
+ name: pry-byebug
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - ">="
46
+ - !ruby/object:Gem::Version
47
+ version: '0'
48
+ type: :development
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - ">="
53
+ - !ruby/object:Gem::Version
54
+ version: '0'
27
55
  - !ruby/object:Gem::Dependency
28
56
  name: rake
29
57
  requirement: !ruby/object:Gem::Requirement
@@ -38,6 +66,20 @@ dependencies:
38
66
  - - "~>"
39
67
  - !ruby/object:Gem::Version
40
68
  version: '10.0'
69
+ - !ruby/object:Gem::Dependency
70
+ name: rake-compiler
71
+ requirement: !ruby/object:Gem::Requirement
72
+ requirements:
73
+ - - ">="
74
+ - !ruby/object:Gem::Version
75
+ version: '0'
76
+ type: :development
77
+ prerelease: false
78
+ version_requirements: !ruby/object:Gem::Requirement
79
+ requirements:
80
+ - - ">="
81
+ - !ruby/object:Gem::Version
82
+ version: '0'
41
83
  - !ruby/object:Gem::Dependency
42
84
  name: rspec
43
85
  requirement: !ruby/object:Gem::Requirement
@@ -56,8 +98,7 @@ description: Julia on Ruby
56
98
  email:
57
99
  - mrkn@cookpad.com
58
100
  executables: []
59
- extensions:
60
- - ext/julia/extconf.rb
101
+ extensions: []
61
102
  extra_rdoc_files: []
62
103
  files:
63
104
  - ".gitignore"
@@ -72,7 +113,17 @@ files:
72
113
  - examples/pkg_status.rb
73
114
  - ext/julia/extconf.rb
74
115
  - ext/julia/julia.c
116
+ - ext/julia/julia_internal.h
117
+ - ext/julia/libjulia.c
75
118
  - julia.gemspec
119
+ - lib/julia.rb
120
+ - lib/julia/error.rb
121
+ - lib/julia/init.rb
122
+ - lib/julia/libjulia.rb
123
+ - lib/julia/libjulia/finder.rb
124
+ - lib/julia/libjulia/investigator.jl
125
+ - lib/julia/load_libruby.jl
126
+ - lib/julia/ruby.jl
76
127
  - lib/julia/version.rb
77
128
  homepage: https://github.com/mrkn/ruby-julia
78
129
  licenses:
@@ -94,9 +145,8 @@ required_rubygems_version: !ruby/object:Gem::Requirement
94
145
  version: '0'
95
146
  requirements: []
96
147
  rubyforge_project:
97
- rubygems_version: 2.4.5
148
+ rubygems_version: 2.7.6
98
149
  signing_key:
99
150
  specification_version: 4
100
151
  summary: Julia on Ruby
101
152
  test_files: []
102
- has_rdoc: