r_bridge 0.5.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.gitignore +22 -0
- data/.travis.yml +6 -0
- data/Gemfile +7 -0
- data/LICENSE.txt +674 -0
- data/README.md +365 -0
- data/Rakefile +10 -0
- data/bin/console +14 -0
- data/bin/setup +8 -0
- data/ext/r_bridge/extconf.rb +78 -0
- data/ext/r_bridge/r_bridge.c +5 -0
- data/ext/r_bridge/r_embed.c +26 -0
- data/ext/r_bridge/r_eval.c +29 -0
- data/ext/r_bridge/r_lang.c +62 -0
- data/ext/r_bridge/r_list.c +34 -0
- data/ext/r_bridge/r_mysum.c +89 -0
- data/ext/r_bridge/r_ptr.c +18 -0
- data/ext/r_bridge/r_vec.c +76 -0
- data/ext/r_bridge/win_compat.h +10 -0
- data/lib/r_bridge.rb +10 -0
- data/lib/r_bridge/r_bridge_ffi.rb +480 -0
- data/lib/r_bridge/r_bridge_lazyfunc_ext.rb +202 -0
- data/lib/r_bridge/version.rb +3 -0
- data/r_bridge.gemspec +32 -0
- metadata +91 -0
data/README.md
ADDED
@@ -0,0 +1,365 @@
|
|
1
|
+
# RBridge
|
2
|
+
|
3
|
+
RBridge enables Ruby to access R funtctionality via low level C interface. RBridge constructs R's internal S expression structure, and asks R to evaluate it. RBridge is only intended to control R from Ruby, but is not intended to obtain value from R to Ruby, so RBridge is like a one way bridge from Ruby to R.
|
4
|
+
|
5
|
+
|
6
|
+
* Motivation
|
7
|
+
|
8
|
+
This gem is mainly developed for StatSailr program, which realizes yet another statistics scripting. (StatSailr enables easy access to R functionality using its own StatSailr syntax.)
|
9
|
+
|
10
|
+
|
11
|
+
* For non-Ruby developers
|
12
|
+
|
13
|
+
This repository is a Ruby gem (i.e. Ruby package), and C codes exist under ext/ directory (Ruby codes are under lib/). If you are looking for how to deal with R's C interface, those C files may be useful.
|
14
|
+
|
15
|
+
|
16
|
+
|
17
|
+
## Installation
|
18
|
+
|
19
|
+
|
20
|
+
* For Linux
|
21
|
+
|
22
|
+
Depending on installing via source or binary, necessary settings differ. If you install this gem via source, all the following settings are necessary. Via binary, step 1, 4 and 6 are reqired.
|
23
|
+
|
24
|
+
|
25
|
+
1. Install R (and libR.so)
|
26
|
+
+ For Linux, install package for R program. (The package name is usually something like "r-base" or just "R-core")
|
27
|
+
2. Install R's C header files
|
28
|
+
+ Also, for linux, package for R's C header files is required. ( The package name is usually something like "r-base-dev" or "R-core-devel" )
|
29
|
+
+ Note that most Linux packages does not provide up-to-date version.
|
30
|
+
+ If you need the latest version of R, usually you need to manually modify /etc/apt/sources.list, and add an appropriate repository.
|
31
|
+
3. Make sure that R can be seen from your system.
|
32
|
+
+ In Linux, usually R executable or its symbolic link is installed under the place where system can see it. (e.g. /usr/bin)
|
33
|
+
+ If not, add path for R to 'PATH' environment variable.
|
34
|
+
4. Make sure that libR.so also can be seen from your system.
|
35
|
+
+ You need to add path for libR.so to 'LD_LIBRARY_PATH' system or user variable.
|
36
|
+
+ Usually the path is "/usr/lib/R/lib' or "/usr/lib64/R/lib" or something.
|
37
|
+
+ In ~/.bashrc, add the line like the following.
|
38
|
+
+ (e.g.) export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:/usr/lib64/R/lib
|
39
|
+
+ Alternatively, if you have pkg-config available, adding pkg-config path can conduct path settings.
|
40
|
+
+ (e.g.) export PKG_CONFIG_PATH=$PKG_CONFIG_PATH:/usr/lib64/R/pkgconfig
|
41
|
+
+ This path should have libR.pc file.
|
42
|
+
5. For R to properly work, R_HOME variable is sometimes required. Set it to the root directory that contains R libraries.
|
43
|
+
+ (e.g.) export R_HOME=/usr/lib64/R
|
44
|
+
6. Install 'r_bridge' via gem
|
45
|
+
|
46
|
+
```
|
47
|
+
gem install r_bridge
|
48
|
+
```
|
49
|
+
|
50
|
+
* For Windows
|
51
|
+
|
52
|
+
For windows, there is a known issue. Output from R contains unknown characters, which may relate to UTF16 conversion within Windows.
|
53
|
+
|
54
|
+
|
55
|
+
1. Install R (and R.dll)
|
56
|
+
+ For Windows, download and use R installer.
|
57
|
+
2. Make sure that R.exe and R.dll can be seen from your system.
|
58
|
+
+ For Windows, add path for R.exe (e.g. C:\Program Files\R\R-4.0.2\bin ) to 'Path' system or user variable.
|
59
|
+
+ Also, create 'RUBY_DLL_PATH' system or user variable, which includes path for R.dll (e.g. C:\Program Files\R\R-4.0.2\bin\x64 ).
|
60
|
+
3. Install 'r_bridge' via gem
|
61
|
+
|
62
|
+
```
|
63
|
+
gem install r_bridge
|
64
|
+
```
|
65
|
+
|
66
|
+
|
67
|
+
|
68
|
+
|
69
|
+
## Example
|
70
|
+
|
71
|
+
* Example 1
|
72
|
+
|
73
|
+
```
|
74
|
+
### Example 1: Show current working directory ###
|
75
|
+
|
76
|
+
require("r_bridge")
|
77
|
+
|
78
|
+
# initialize embedded R. This is a must-do.
|
79
|
+
|
80
|
+
RBridge.init_embedded_r()
|
81
|
+
|
82
|
+
# create_function_call is a utility function to create S expression for R function.
|
83
|
+
# In this case, this creates S expression for getwd() without any arguments in R.
|
84
|
+
|
85
|
+
getwd_fun = RBridge.create_function_call("getwd", {} )
|
86
|
+
|
87
|
+
# exec_function() evaluates (executes) R's S expression that should represent function.
|
88
|
+
# If you do not need return value, use exec_function_no_return() instaed.
|
89
|
+
# exec_function_no_return does not track(i.e. does not PROTECT) its return object (at C or Ruby level), which is garbage collected by R automatically.
|
90
|
+
|
91
|
+
path = RBridge.exec_function(getwd_fun) # path must hold a pointer to R's character vector.
|
92
|
+
|
93
|
+
# creates print() function with argument of x, and evaluates (executes) it, and does not track the return object.
|
94
|
+
|
95
|
+
RBridge.exec_function_no_return( RBridge.create_function_call( "print", { "x" => path } ))
|
96
|
+
|
97
|
+
# Conduct garbage collection (UNPROTECT from gc) and end R.
|
98
|
+
|
99
|
+
RBridge.gc_all()
|
100
|
+
RBridge.end_embedded_r()
|
101
|
+
```
|
102
|
+
|
103
|
+
* Example 2
|
104
|
+
|
105
|
+
```
|
106
|
+
### Example2: Calulate mean ###
|
107
|
+
|
108
|
+
require("r_bridge")
|
109
|
+
|
110
|
+
# initialize embedded R. This is a must-do.
|
111
|
+
|
112
|
+
RBridge.init_embedded_r()
|
113
|
+
|
114
|
+
# create_vec() Create vector from Ruby's Array
|
115
|
+
# create R's mean() function with argument of x. Evaluate (execute) it.
|
116
|
+
# create R's print() function with argument of x. Evaluate (execute) it without tracking (i.e. without PROTECTing) the result object.
|
117
|
+
|
118
|
+
vals = RBridge.create_vec([ 12, 13.5, 14.0, 10, 9])
|
119
|
+
mean_val = RBridge.exec_function( RBridge.create_function_call( "mean", { "x" => vals } ))
|
120
|
+
RBridge.exec_function_no_return( RBridge.create_function_call( "print", { "x" => mean_val } ))
|
121
|
+
|
122
|
+
# Conduct garbage collection (UNPROTECT from gc) and end R.
|
123
|
+
|
124
|
+
RBridge.gc_all()
|
125
|
+
RBridge.end_embedded_r()
|
126
|
+
```
|
127
|
+
|
128
|
+
|
129
|
+
## Available Methods
|
130
|
+
|
131
|
+
* Start R and end R
|
132
|
+
|
133
|
+
Before you start to utilize R's functionality, you need to init R with init_embedded_r(). When you end R, you can end R with end_embedded_r().
|
134
|
+
|
135
|
+
Note that once you end R, please do not init R again in the same program. (Maybe it can be possible, but RBridge does not provide such functionality.)
|
136
|
+
|
137
|
+
```
|
138
|
+
RBridge.init_embedded_r()
|
139
|
+
RBridge.end_embedded_r()
|
140
|
+
```
|
141
|
+
|
142
|
+
|
143
|
+
* Garbage collection, PROTECT() and UNPROTECT()
|
144
|
+
|
145
|
+
R objects that are generated via C interface are garbage collected soon. To prevent this, we need to PROTECT those objects using PROTECT(ptr) function at C level. RBridge internally PROTECTs R objects when they are created via RBridge, and counts the number of PROTECTed objects. gc_all() function UNPROTECT those objects by using the count, which results in garbage collection by R.
|
146
|
+
|
147
|
+
```
|
148
|
+
RBridge.gc_all()
|
149
|
+
```
|
150
|
+
|
151
|
+
To be mentioned later, in RBridge there is another functionality called ptr_manager. ptr_manager (RPointerManager) stores pointers to PROTECTed R objects, and UNPROTECT them when the ptr_manger is closed. gc_all() UNPROTECTs all the R objects created before, but ptr_manager can UNPROTECT objects that are created in specific period.
|
152
|
+
|
153
|
+
|
154
|
+
* Create R vector
|
155
|
+
|
156
|
+
create_vec() creates R vectors from Ruby's Array. Created R's vector type is determined by Ruby Array's element type.
|
157
|
+
|
158
|
+
Supported Ruby types are String, Float, Integer and TrueClass/FlaseClass. If the Ruby elements have various types within the same Array, all the elements are dealt as (casted to) the biggest type in the following type order. Type Order: String > Float(Real) > Integer(Int) > true/false(Logical).
|
159
|
+
|
160
|
+
```
|
161
|
+
RBridge.create_vec( ary )
|
162
|
+
|
163
|
+
(e.g.)
|
164
|
+
RBridge.create_vec( [ 1, 2, true, false] ) # integer(1, 2, 1, 0)
|
165
|
+
RBridge.create_vec( [ 1, 2, 3.0, 4] ) # real(1.0, 2.0, 3.0, 4.0)
|
166
|
+
```
|
167
|
+
|
168
|
+
You can also specify which type of R vector to create. In this case, original Ruby's array needs to have unique type for its elements.
|
169
|
+
|
170
|
+
```
|
171
|
+
RBridge.create_strvec( ary ) # Ruby's Array of String => R's Character(String) Vector
|
172
|
+
RBridge.create_intvec( ary ) # Ruby's Array of Integer => R's Integer Vector
|
173
|
+
RBridge.create_realvec( ary ) # Ruby's Array of Float => R's Real Vector
|
174
|
+
RBridge.create_lglvec( ary ) # Ruby's Array of true/false => R's Logical Vector
|
175
|
+
```
|
176
|
+
|
177
|
+
|
178
|
+
* Create R list
|
179
|
+
|
180
|
+
list and data.frame can be created. For column name, specify name using String.
|
181
|
+
|
182
|
+
```
|
183
|
+
RBridge.create_list( hash )
|
184
|
+
RBridge.create_dataframe( hash )
|
185
|
+
|
186
|
+
(e.g.)
|
187
|
+
df = RBridge::create_dataframe( { "y" => [12, 13, 14, 18 , 17, 20, 20 ] , "x" => [ 1, 2, 3, 4, 5, 6, 7]} )
|
188
|
+
```
|
189
|
+
|
190
|
+
* Create R formula
|
191
|
+
|
192
|
+
R has a fomula type, which is used to represent models.
|
193
|
+
|
194
|
+
Make sure to use SymbolR object for elements of this Array.
|
195
|
+
|
196
|
+
```
|
197
|
+
RBridge.create_formula_from_syms( ary )
|
198
|
+
|
199
|
+
(e.g.)
|
200
|
+
ary = [ RBridge::SymbolR.new("y"),
|
201
|
+
RBridge::SymbolR.new("~"),
|
202
|
+
RBridge::SymbolR.new("x")]
|
203
|
+
formula = RBridge::create_formula_from_syms( ary ) # y ~ x
|
204
|
+
```
|
205
|
+
|
206
|
+
|
207
|
+
* Create R function call
|
208
|
+
|
209
|
+
create_function_call creates R's internal S expresion structure for function call.
|
210
|
+
|
211
|
+
Arguments are passed to the second argument as Ruby Hash, and each Hash's value needs to point to R's object. You usually pass R vectors, but you can also pass another function call as an argument.
|
212
|
+
|
213
|
+
```
|
214
|
+
RBridge.create_function_call( fname, hash )
|
215
|
+
|
216
|
+
(e.g.)
|
217
|
+
# pass vector to argument
|
218
|
+
helloworld = RBridge.create_function_call( "print", { "x" => RBridge.create_vec(["Hello", "World"]) } )
|
219
|
+
RBridge.exec_function_no_return(hellowrold)
|
220
|
+
|
221
|
+
# pass another function call to argument
|
222
|
+
getwd = RBridge.create_function_call( "print", { "x" => RBridge.create_function_call( "getwd", {} ) } )
|
223
|
+
RBridge.exec_function_no_return(getwd)
|
224
|
+
```
|
225
|
+
|
226
|
+
The followings are utility functions. assign() and library() are frequently used in R, and easy ways to create them are provided.
|
227
|
+
|
228
|
+
```
|
229
|
+
RBridge.create_assign_function( var_name, r_obj )
|
230
|
+
RBridge.create_library_function( lib_name )
|
231
|
+
```
|
232
|
+
|
233
|
+
|
234
|
+
* Execute (evaluate) R functions
|
235
|
+
|
236
|
+
To evaluate the function call created, use exec_fuction() or exec_function_no_return().
|
237
|
+
|
238
|
+
exec_function returns pointer to R object that is PROTECTed. This means the object needs to be UNPROTECTed when they are no longer used.
|
239
|
+
|
240
|
+
exec_function_no_return does not PROTECT the returned object, and it is soon garbage collected.
|
241
|
+
|
242
|
+
Which one to use does not depend on the original R function, but should depend on whether the returned object will be used later. In other words, exec_function() should be used with assignment operator, but exec_function_no_return() should be called independently.
|
243
|
+
|
244
|
+
```
|
245
|
+
r_return_obj = RBridge.exec_function( func , allow_nil_result: false )
|
246
|
+
RBridge.exec_function_no_return( func )
|
247
|
+
```
|
248
|
+
|
249
|
+
|
250
|
+
* (Internally used) Create R LANGSXP & evaluate it
|
251
|
+
|
252
|
+
To show the relationship between creating function call (LANGSXP) and evaluating (executing) it, here shows how function calls are structured in RBridge.
|
253
|
+
|
254
|
+
LANGSXP is a structure for R's function call object. LANGSXP consists of pairlists, and is constructed using LCONS(). The first element of this overall structure needs to represent the name of function (symbol corresponding to CLOSEXP (function definition)) to be called.
|
255
|
+
|
256
|
+
```
|
257
|
+
(Internally used methods)
|
258
|
+
RBridge.lcons( car, cdr ) # ( car . cdr )
|
259
|
+
RBridge.lcons_gen( car ) # ( car . R_NilValue )
|
260
|
+
RBridge.r_lang_symbol( str )
|
261
|
+
RBridge.set_tag_to_lcons( lcons, tag_name ) # lcons can have tag name, which is used as argument name when evaluation.
|
262
|
+
```
|
263
|
+
|
264
|
+
```
|
265
|
+
(e.g.)
|
266
|
+
require "r_bridge"
|
267
|
+
|
268
|
+
RBridge.init_embedded_r()
|
269
|
+
|
270
|
+
lcons1 = RBridge.lcons_gen( RBridge.create_vec(["Hello", "World"]) )
|
271
|
+
RBridge.set_tag_to_lcons( lcons1, "x")
|
272
|
+
lcons2 = RBridge.lcons(RBridge.r_lang_symbol("print") , lcons1)
|
273
|
+
RBridge.exec_function_no_return(lcons2)
|
274
|
+
|
275
|
+
RBridge.gc_all()
|
276
|
+
RBridge.end_embedded_r()
|
277
|
+
```
|
278
|
+
|
279
|
+
|
280
|
+
* ptr_manager can track PROTECTed R objects, and UNPROTECT them
|
281
|
+
|
282
|
+
ptr_manager (RPointerManager) is another functionality (other than gc_all()) to UNPROTECT R objects. ptr_manager works like a session and ptr_manager_open() starts a new ptr_manager session, ptr_switch() changes to the session that already exists, and ptr_manager_close() closes the specified session. R objects generated via RBridge belong to the ptr_manager that is effective currently (opened or switched most recently). Each ptr_manager has its name (default one is "" (empty string)), and switching and closing can be done by specifying the name.
|
283
|
+
|
284
|
+
```
|
285
|
+
RBridge.ptr_manager_open( ptr_manager_name ) # create new ptr_manager
|
286
|
+
RBridge.ptr_manager_switch( ptr_manager_name ) # change ptr_manager
|
287
|
+
RBridge.ptr_manager_close( ptr_manager_name ) # UNPROTECT added R objects
|
288
|
+
```
|
289
|
+
|
290
|
+
ptr_manager_open() can take block argument. All the R objects generated via RBridge within the block are registered to the ptr_manager opened. They are UNPROTECTed when the block ends. (i.e. ptr_manager_close() is called for the current ptr_manager)
|
291
|
+
|
292
|
+
```
|
293
|
+
RBridge.ptr_manager_open( ptr_manager_name ){
|
294
|
+
...
|
295
|
+
Call RBridge functions.
|
296
|
+
Generated R objects are automatically managed by ptr_manager with <ptr_manager_name> within this block, and become UNPROTECTed after this block.
|
297
|
+
...
|
298
|
+
}
|
299
|
+
```
|
300
|
+
|
301
|
+
* Examples of ptr_manager
|
302
|
+
|
303
|
+
```
|
304
|
+
# Example1: ptr_manager_open()
|
305
|
+
|
306
|
+
require "r_bridge"
|
307
|
+
RBridge.init_embedded_r()
|
308
|
+
|
309
|
+
RBridge.ptr_manager_open("pm1")
|
310
|
+
new_vec = RBridge.create_vec(["Hello", "World"])
|
311
|
+
RBridge.exec_function_no_return( RBridge.create_function_call("print", {"x" => new_vec }))
|
312
|
+
RBridge.ptr_manager_close("pm1")
|
313
|
+
|
314
|
+
RBridge.gc_all() # In this case, not necesary. ( When there are objects that are not managed by ptr_manager, this is necessary.)
|
315
|
+
RBridge.end_embedded_r()
|
316
|
+
```
|
317
|
+
|
318
|
+
```
|
319
|
+
# Example2: ptr_manager_open() with block argument
|
320
|
+
|
321
|
+
require "r_bridge"
|
322
|
+
RBridge.init_embedded_r()
|
323
|
+
|
324
|
+
RBridge.ptr_manager_open("prepare regression analysis"){
|
325
|
+
ary = [ RBridge::SymbolR.new("y"),
|
326
|
+
RBridge::SymbolR.new("~"),
|
327
|
+
RBridge::SymbolR.new("x")]
|
328
|
+
formula = RBridge::create_formula_from_syms( ary )
|
329
|
+
|
330
|
+
df = RBridge::create_dataframe( { "y" => [12, 13, 14, 18 , 17, 20, 20 ] , "x" => [ 1, 2, 3, 4, 5, 6, 7]} )
|
331
|
+
|
332
|
+
RBridge.ptr_manager_open("a little break"){
|
333
|
+
RBridge::exec_function_no_return(RBridge::create_function_call("print", {"x" => RBridge::create_vec( ["(^^)" , "<" , "Hello"] ) }))
|
334
|
+
}
|
335
|
+
|
336
|
+
# assign to R variable
|
337
|
+
reg = RBridge::exec_function( RBridge::create_function_call( "lm" , {"data" => df , "formula" => formula } ) )
|
338
|
+
summary = RBridge::exec_function( RBridge::create_function_call( "summary" , {"object" => reg } ) )
|
339
|
+
RBridge::exec_function_no_return(RBridge::create_function_call( "print" , {"x" => summary }))
|
340
|
+
}
|
341
|
+
|
342
|
+
RBridge.gc_all() # In this case, not necesary. ( When there are objects that are not managed by ptr_manager, this is necessary.)
|
343
|
+
RBridge.end_embedded_r()
|
344
|
+
|
345
|
+
```
|
346
|
+
|
347
|
+
## Additional Features
|
348
|
+
|
349
|
+
* LazyFunc + RParamManager (+ RResultManager): In contrast to create_function_call(), create_lazy_funcion(), which create LazyFunc object, does not need to take existent R objects. It can take RParamName, RResultName and so on, which are not associated with R objects until the function is evaluated.
|
350
|
+
|
351
|
+
These features are being developed for StatSailr, and the API is not stable. They can be accessed but they are not recommended for general usage.
|
352
|
+
|
353
|
+
|
354
|
+
## License
|
355
|
+
|
356
|
+
The gem is available as open source under the terms of the [GPL v3 License](https://www.gnu.org/licenses/gpl-3.0.en.html).
|
357
|
+
|
358
|
+
|
359
|
+
## Contact
|
360
|
+
|
361
|
+
Your feedback is welcome.
|
362
|
+
|
363
|
+
Maintainer: Toshi Umehara toshi@niceume.com
|
364
|
+
|
365
|
+
|
data/Rakefile
ADDED
data/bin/console
ADDED
@@ -0,0 +1,14 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
require "bundler/setup"
|
4
|
+
require "r_bridge"
|
5
|
+
|
6
|
+
# You can add fixtures and/or initialization code here to make experimenting
|
7
|
+
# with your gem easier. You can also use a different console, if you like.
|
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(__FILE__)
|
data/bin/setup
ADDED
@@ -0,0 +1,78 @@
|
|
1
|
+
require "mkmf"
|
2
|
+
require "ffi"
|
3
|
+
|
4
|
+
if FFI::Platform::OS == "windows"
|
5
|
+
p "windows"
|
6
|
+
$CFLAGS << " " << "-D_WIN" << " "
|
7
|
+
end
|
8
|
+
|
9
|
+
|
10
|
+
class RHeaderNotFound < RuntimeError
|
11
|
+
end
|
12
|
+
class RLibraryNotFound < RuntimeError
|
13
|
+
end
|
14
|
+
|
15
|
+
def check_R_header_and_lib( )
|
16
|
+
msg_devel_header = "For UNIX package users, please install R development tools via package (which name should look like r-base-dev or R-devel)."
|
17
|
+
msg_devel_lib = "For UNIX package users, please install R development tools via package (which name should look like r-base-dev or R-devel). If this is a custom build of R, please make sure that It was built with the --enable-R-shlib option. "
|
18
|
+
|
19
|
+
if have_header('R.h')
|
20
|
+
p "header ok"
|
21
|
+
if have_library('R', 'R_tryEval') || have_library('libR', 'R_tryEval')
|
22
|
+
p "library ok"
|
23
|
+
return true
|
24
|
+
else
|
25
|
+
raise RLibraryNotFound.new( "Dynamic (i.e. shared) library of R is not found (R.dll for Windows, libR.so for UNIX)." + msg_devel_lib )
|
26
|
+
end
|
27
|
+
else
|
28
|
+
raise RHeaderNotFound.new( "Header for R is not found." + msg_devel_header )
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
pkg_config_tried = false
|
33
|
+
r_config_tried = false
|
34
|
+
|
35
|
+
dir_config("R")
|
36
|
+
|
37
|
+
begin
|
38
|
+
if check_R_header_and_lib()
|
39
|
+
# Makefile that will build and install extension to lib/r_bridge/librbridge.so
|
40
|
+
create_makefile "r_bridge/librbridge"
|
41
|
+
end
|
42
|
+
rescue RHeaderNotFound, RLibraryNotFound => e
|
43
|
+
if find_executable('pkg-config') && (pkg_config_tried == false)
|
44
|
+
add_cflags = pkg_config("libR", "cflags")
|
45
|
+
add_ldflags = pkg_config("libR", "libs")
|
46
|
+
if ( ! add_cflags.nil? ) && (! add_ldflags.nil?)
|
47
|
+
$CFLAGS << " " << add_cflags
|
48
|
+
$LDFLAGS <<" " << add_ldflags
|
49
|
+
end
|
50
|
+
pkg_config_tried = true
|
51
|
+
retry
|
52
|
+
elsif ! find_executable('R')
|
53
|
+
raise "R program is not found. Please check your PATH setting if you already have R on your machine."
|
54
|
+
elsif find_executable('R') && find_executable('Rscript') && (r_config_tried == false)
|
55
|
+
r_home_path = `Rscript -e "cat(R.home()[1])"`.chomp
|
56
|
+
|
57
|
+
if ! r_home_path.empty?()
|
58
|
+
case FFI::Platform::ARCH
|
59
|
+
when "x86_64"
|
60
|
+
possible_r_header_dirs = [ r_home_path + "/include" ]
|
61
|
+
possible_r_lib_dirs = [ r_home_path + "/bin/x64" , r_home_path + "/bin/i386" ]
|
62
|
+
when "i386"
|
63
|
+
possible_r_header_dirs = [ r_home_path + "/include" ]
|
64
|
+
possible_r_lib_dirs = [ r_home_path + "/bin/i386" ]
|
65
|
+
else
|
66
|
+
raise FFI::Platform::ARCH + ": unkown architecure detected. Please specify R shared library by yourself."
|
67
|
+
end
|
68
|
+
find_header('R.h', *possible_r_header_dirs)
|
69
|
+
find_library('R', 'R_tryEval', *possible_r_lib_dirs)
|
70
|
+
end
|
71
|
+
|
72
|
+
r_config_tried = true
|
73
|
+
retry
|
74
|
+
else
|
75
|
+
raise e
|
76
|
+
end
|
77
|
+
end
|
78
|
+
|