Class: Inline::C

Inherits:
Object
  • Object
show all
Includes:
ZenTestMapping
Defined in:
lib/inline.rb

Overview

Inline::C is the default builder used and the only one provided by Inline. It can be used as a template to write builders for other languages. It understands type-conversions for the basic types and can be extended as needed using #add_type_converter, #alias_type_converter and #remove_type_converter.

Constant Summary collapse

MAGIC_ARITY_THRESHOLD =
15
MAGIC_ARITY =
-1
TYPE_MAP =

Default C to ruby and ruby to C type map

{
  'char'               => [ 'NUM2CHR',        'CHR2FIX'      ],

  'char *'             => [ 'StringValuePtr', 'rb_str_new2'  ],

  'double'             => [ 'NUM2DBL',        'rb_float_new' ],

  'int'                => [ "FI\X2INT",       'INT2FIX'      ],
  'unsigned int'       => [ 'NUM2UINT',       'UINT2NUM'     ],
  'unsigned'           => [ 'NUM2UINT',       'UINT2NUM'     ],

  'long'               => [ 'NUM2LONG',       'LONG2NUM'     ],
  'unsigned long'      => [ 'NUM2ULONG',      'ULONG2NUM'    ],

  'long long'          => [ 'NUM2LL',         'LL2NUM'       ],
  'unsigned long long' => [ 'NUM2ULL',        'ULL2NUM'      ],

  'off_t'              => [ 'NUM2OFFT',       'OFFT2NUM'     ],

  'VALUE'              => [ '',               ''             ],
  # Can't do these converters because they conflict with the above:
  # ID2SYM(x), SYM2ID(x), F\IX2UINT(x)
}

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(mod) ⇒ C

Returns a new instance of C.

Raises:

  • (ArgumentError)


397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
# File 'lib/inline.rb', line 397

def initialize(mod)
  raise ArgumentError, "Class/Module arg is required" unless Module === mod
  # new (but not on some 1.8s) -> inline -> real_caller|eval
  stack = caller
  meth = stack.shift until meth =~ /in .(inline|test_|setup)/ or stack.empty?
  raise "Couldn't discover caller" if stack.empty?
  real_caller = stack.first
  real_caller = stack[3] if real_caller =~ /\(eval\)/
  real_caller =~ /(.*):(\d+)/
  real_caller = $1
  @rb_file = File.expand_path real_caller

  @mod = mod
  @pre = []
  @src = []
  @inc = []
  @sig = {}
  @flags = []
  @libs = []
  @init_extra = []
  @include_ruby_first = true
  @inherited_methods = {}
  @struct_name = nil

  @type_map = TYPE_MAP.dup
end

Instance Attribute Details

#flagsObject

Returns the value of attribute flags.



389
390
391
# File 'lib/inline.rb', line 389

def flags
  @flags
end

#init_extraObject

Returns the value of attribute init_extra.



389
390
391
# File 'lib/inline.rb', line 389

def init_extra
  @init_extra
end

#libsObject

Returns the value of attribute libs.



389
390
391
# File 'lib/inline.rb', line 389

def libs
  @libs
end

#modObject

Returns the value of attribute mod.



387
388
389
# File 'lib/inline.rb', line 387

def mod
  @mod
end

#preObject

Returns the value of attribute pre.



389
390
391
# File 'lib/inline.rb', line 389

def pre
  @pre
end

#rb_fileObject (readonly)

Returns the value of attribute rb_file.



387
388
389
# File 'lib/inline.rb', line 387

def rb_file
  @rb_file
end

#sigObject

Returns the value of attribute sig.



389
390
391
# File 'lib/inline.rb', line 389

def sig
  @sig
end

#srcObject

Returns the value of attribute src.



389
390
391
# File 'lib/inline.rb', line 389

def src
  @src
end

#struct_nameObject

Sets the name of the C struct for generating accessors. Used with #accessor, #reader, #writer.



395
396
397
# File 'lib/inline.rb', line 395

def struct_name
  @struct_name
end

Instance Method Details

#accessor(method, type, member = method) ⇒ Object

Adds a #reader and #writer for a C struct member wrapped via Data_Wrap_Struct. method is the ruby name to give the accessor, type is the C type. Unless the C member name is overridden with member, the method name is used as the struct member.

builder.struct_name = 'MyStruct'
builder.accessor :title,        'char *'
builder.accessor :stream_index, 'int',   :index

The latter accesses MyStruct->index via the stream_index method.



436
437
438
439
# File 'lib/inline.rb', line 436

def accessor(method, type, member = method)
  reader method, type, member
  writer method, type, member
end

#add_compile_flags(*flags) ⇒ Object

Adds compiler options to the compiler command line. No preprocessing is done, so you must have all your dashes and everything.



669
670
671
# File 'lib/inline.rb', line 669

def add_compile_flags(*flags)
  @flags.push(*flags)
end

#add_id(name) ⇒ Object

Registers a static id_name for the symbol :name.



676
677
678
# File 'lib/inline.rb', line 676

def add_id name
  self.add_static "id_#{name}", "rb_intern(\"#{name}\")"
end

Adds linker flags to the link command line. No preprocessing is done, so you must have all your dashes and everything.



684
685
686
# File 'lib/inline.rb', line 684

def add_link_flags(*flags)
  @libs.push(*flags)
end

#add_static(name, init, type = "VALUE") ⇒ Object

Create a static variable and initialize it to a value.



691
692
693
694
# File 'lib/inline.rb', line 691

def add_static name, init, type = "VALUE"
  prefix      "static #{type} #{name};"
  add_to_init "#{name} = #{init};"
end

#add_to_init(*src) ⇒ Object

Adds custom content to the end of the init function.



699
700
701
# File 'lib/inline.rb', line 699

def add_to_init(*src)
  @init_extra.push(*src)
end

#add_type_converter(type, r2c, c2r) ⇒ Object

Registers C type-casts r2c and c2r for type.



706
707
708
709
# File 'lib/inline.rb', line 706

def add_type_converter(type, r2c, c2r)
  warn "WAR\NING: overridding #{type} on #{caller[0]}" if @type_map.has_key? type
  @type_map[type] = [r2c, c2r]
end

#alias_type_converter(existing_type, alias_type) ⇒ Object

Registers C type alias_type as an alias of existing_type



714
715
716
717
718
719
# File 'lib/inline.rb', line 714

def alias_type_converter(existing_type, alias_type)
  warn "WAR\NING: overridding #{type} on #{caller[0]}" if
    @type_map.has_key? alias_type

  @type_map[alias_type] = @type_map[existing_type]
end

#buildObject

Builds the source file, if needed, and attempts to compile it.



527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
# File 'lib/inline.rb', line 527

def build
  so_name = self.so_name
  so_exists = File.file? so_name
  unless so_exists and File.mtime(rb_file) < File.mtime(so_name) then

    unless File.directory? Inline.directory then
      warn "NOTE: creating #{Inline.directory} for RubyInline" if $DEBUG
      FileUtils.mkdir_p Inline.directory, :mode => 0700
    end

    src_name = "#{Inline.directory}/#{module_name}.c"
    old_src_name = File.write_with_backup src_name, generate_ext

    # recompile only if the files are different
    recompile = true
    if so_exists and old_src_name and
        FileUtils.compare_file(old_src_name, src_name) then
      recompile = false

      # Updates the timestamps on all the generated/compiled files.
      # Prevents us from entering this conditional unless the source
      # file changes again.
      t = Time.now
      File.utime(t, t, src_name, old_src_name, so_name)
    end

    if recompile then
      unless RbConfig::CONFIG["ENABLE_SHARED"] == "yes" then
        raise "this ruby isn't configured for dynamic linking"
      end

      hdrdir = %w(srcdir includedir archdir rubyhdrdir).map { |name|
        RbConfig::CONFIG[name]
      }.find { |dir|
        dir and File.exist? File.join(dir, "ruby.h")
      } or abort "ERROR: Can't find header dir for ruby. Exiting..."

      flags = @flags.join(' ')

      @libs << RbConfig::CONFIG['LIBRUBYARG_SHARED']

      libs  = @libs.join(' ')

      config_hdrdir = if RbConfig::CONFIG['rubyarchhdrdir'] then
                        "-I #{RbConfig::CONFIG['rubyarchhdrdir']}"
                      elsif RUBY_VERSION > '1.9' then
                        "-I #{File.join hdrdir, RbConfig::CONFIG['arch']}"
                      else
                        nil
                      end

      windoze = WINDOZE and RUBY_PLATFORM =~ /mswin/
      sane = ! windoze
      cmd = [ RbConfig::CONFIG['LDSHARED'],
              flags,
              (RbConfig::CONFIG['DLDFLAGS']         if sane),
              (RbConfig::CONFIG['CCDLFLAGS']        if sane),
              RbConfig::CONFIG['CFLAGS'],
              (RbConfig::CONFIG['LDFLAGS']          if sane),
              '-I', hdrdir,
              config_hdrdir,
              '-I', RbConfig::CONFIG['includedir'],
              ("-L#{RbConfig::CONFIG['libdir']}"    if sane),
              (['-o', so_name.inspect]              if sane),
              File.expand_path(src_name).inspect,
              libs,
              crap_for_windoze,
              (RbConfig::CONFIG['LDFLAGS']          if windoze),
              (RbConfig::CONFIG['CCDLFLAGS']        if windoze),
            ].compact.join(' ')

      # odd compilation error on clang + freebsd 10. Ruby built w/ rbenv.
      cmd = cmd.gsub(/-Wl,-soname,\$@/, "-Wl,-soname,#{File.basename so_name}")

      # strip off some makefile macros for mingw 1.9
      cmd = cmd.gsub(/\$\(.*\)/, '') if RUBY_PLATFORM =~ /mingw/

      cmd += " 2> #{DEV_NULL}" if $TESTING and not $DEBUG

      warn "Building #{so_name} with '#{cmd}'" if $DEBUG

      result = if WINDOZE
                 Dir.chdir(Inline.directory) { `#{cmd}` }
               else
                 `#{cmd}`
               end

      warn "Output:\n#{result}" if $DEBUG

      if $? != 0 then
        bad_src_name = src_name + ".bad"
        File.rename src_name, bad_src_name
        raise CompilationError, "error executing #{cmd.inspect}: #{$?}\nRenamed #{src_name} to #{bad_src_name}"
      end

      # NOTE: manifest embedding is only required when using VC8 ruby
      # build or compiler.
      # Errors from this point should be ignored if RbConfig::CONFIG['arch']
      # (RUBY_PLATFORM) matches 'i386-mswin32_80'
      if WINDOZE and RUBY_PLATFORM =~ /_80$/ then
        Dir.chdir Inline.directory do
          cmd = "mt /manifest lib.so.manifest /outputresource:so.dll;#2"
          warn "Embedding manifest with '#{cmd}'" if $DEBUG
          result = `#{cmd}`
          warn "Output:\n#{result}" if $DEBUG
          if $? != 0 then
            raise CompilationError, "error executing #{cmd}: #{$?}"
          end
        end
      end

      warn "Built successfully" if $DEBUG
    end

  else
    warn "#{so_name} is up to date" if $DEBUG
  end # unless (file is out of date)
end

#c(src, options = {}) ⇒ Object

Adds a C function to the source, including performing automatic type conversion to arguments and the return value. The Ruby method name can be overridden by providing method_name. Unknown type conversions can be extended by using add_type_converter.



784
785
786
787
788
789
# File 'lib/inline.rb', line 784

def c src, options = {}
  options = {
    :expand_types => true,
  }.merge options
  self.generate src, options
end

#c2ruby(type) ⇒ Object

Converts C type type to a ruby type

Raises:

  • (ArgumentError)


496
497
498
499
# File 'lib/inline.rb', line 496

def c2ruby(type)
  raise ArgumentError, "Unknown type #{type.inspect}" unless @type_map.has_key? type
  @type_map[type].last
end

#c_raw(src, options = {}) ⇒ Object

Adds a raw C function to the source. This version does not perform any type conversion and must conform to the ruby/C coding conventions. The Ruby method name can be overridden by providing method_name.



808
809
810
# File 'lib/inline.rb', line 808

def c_raw src, options = {}
  self.generate src, options
end

#c_raw_singleton(src, options = {}) ⇒ Object

Same as c_raw, but adds a class function.



815
816
817
818
819
820
# File 'lib/inline.rb', line 815

def c_raw_singleton src, options = {}
  options = {
    :singleton => true,
  }.merge options
  self.generate src, options
end

#c_singleton(src, options = {}) ⇒ Object

Same as c, but adds a class function.



794
795
796
797
798
799
800
# File 'lib/inline.rb', line 794

def c_singleton src, options = {}
  options = {
    :expand_types => true,
    :singleton    => true,
  }.merge options
  self.generate src, options
end

#crap_for_windozeObject

Returns extra compilation flags for windoze platforms. Ugh.



649
650
651
652
653
654
655
656
657
658
659
660
661
662
# File 'lib/inline.rb', line 649

def crap_for_windoze
  # gawd windoze land sucks
  case RUBY_PLATFORM
  when /mswin32/ then
    " -link /OUT:\"#{self.so_name}\" /LIBPATH:\"#{RbConfig::CONFIG['libdir']}\" /DEFAULTLIB:\"#{RbConfig::CONFIG['LIBRUBY']}\" /INCREMENTAL:no /EXPORT:Init_#{module_name}"
  when /mingw32/ then
    c = RbConfig::CONFIG
    " -Wl,--enable-auto-import -L#{c['libdir']} -l#{c['RUBY_SO_NAME']} -o #{so_name.inspect}"
  when /i386-cygwin/ then
    ' -L/usr/local/lib -lruby.dll'
  else
    ''
  end
end

#generate(src, options = {}) ⇒ Object

def parse_signature

Raises:

  • (ArgumentError)


237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
# File 'lib/inline.rb', line 237

def generate(src, options={})
  options = {:expand_types=>options} unless Hash === options

  expand_types = options[:expand_types]
  singleton = options[:singleton]
  result = self.strip_comments(src)

  signature = parse_signature(src, !expand_types)
  function_name = signature['name']
  method_name = options[:method_name]
  method_name ||= test_to_normal function_name
  return_type = signature['return']
  arity = options[:arity] || signature['arity']

  raise ArgumentError, "too many arguments" if arity > MAGIC_ARITY_THRESHOLD

  if expand_types then
    prefix = "static VALUE #{function_name}("
    if arity <= MAGIC_ARITY then
      prefix += "int argc, VALUE *argv, VALUE self"
    else
      prefix += "VALUE self"
      prefix += signature['args'].map { |arg, type| ", VALUE _#{arg}"}.join
    end
    prefix += ") {\n"
    prefix += signature['args'].map { |arg, type|
      "  #{type} #{arg} = #{ruby2c(type)}(_#{arg});\n"
    }.join

    # replace the function signature (hopefully) with new sig (prefix)
    result.sub!(/[^;\/\"\>]+#{function_name}\s*\([^\{]+\{/, "\n" + prefix)
    result.sub!(/\A\n/, '') # strip off the \n in front in case we added it
    unless return_type == "void" then
      raise SyntaxError, "Couldn't find return statement for #{function_name}" unless
        result =~ /return/
      result.gsub!(/return\s+([^\;\}]+)/) do
        "return #{c2ruby(return_type)}(#{$1})"
      end
    else
      result.sub!(/\s*\}\s*\Z/, "\nreturn Qnil;\n}")
    end
  else
    prefix = "static #{return_type} #{function_name}("
    result.sub!(/[^;\/\"\>]+#{function_name}\s*\(/, prefix)
    result.sub!(/\A\n/, '') # strip off the \n in front in case we added it
  end

  delta = if result =~ /\A(static.*?\{)/m then
            $1.split(/\n/).size
          else
            msg = "WAR\NING: Can't find signature in #{result.inspect}\n"
            warn msg unless $TESTING
            0
          end

  file, line = $1, $2 if caller[1] =~ /(.*?):(\d+)/

  result = "# line #{line.to_i + delta} \"#{file}\"\n" + result unless
    $DEBUG and not $TESTING

  @src << result
  @sig[function_name] = [arity,singleton,method_name]

  return result if $TESTING
end

#generate_extObject

Builds a complete C extension suitable for writing to a file and compiling.



307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
# File 'lib/inline.rb', line 307

def generate_ext
  ext = []

  if @include_ruby_first
    @inc.unshift "#include \"ruby.h\""
  else
    @inc.push "#include \"ruby.h\""
  end

  ext << @inc
  ext << nil
  unless @pre.empty? then
    ext << @pre.join("\n\n")
    ext << nil
  end
  ext << @src.join("\n\n")
  ext << nil
  ext << nil
  ext << "#ifdef __cplusplus"
  ext << "extern \"C\" {"
  ext << "#endif"
  ext << "  __declspec(dllexport)" if WINDOZE
  ext << "  void Init_#{module_name}(void) {"
  ext << "    VALUE c = rb_cObject;"

  # TODO: use rb_class2path
  # ext << "    VALUE c = rb_path2class(#{@mod.name.inspect});"
  ext << @mod.name.split("::").map { |n|
    "    c = rb_const_get(c, rb_intern(\"#{n}\"));"
  }.join("\n")

  ext << nil

  @sig.keys.sort.each do |name|
    method = []
    arity, singleton, method_name = @sig[name]
    if singleton then
      if method_name == 'allocate' then
        raise "#{@mod}::allocate must have an arity of zero" if arity > 0
        ext << "    rb_define_alloc_func(c, (VALUE(*)(VALUE))#{name});"
        next
      end
      method << "    rb_define_singleton_method(c, \"#{method_name}\", "
    else
      method << "    rb_define_method(c, \"#{method_name}\", "
    end
    method << "(VALUE(*)(ANYARGS))#{name}, #{arity});"
    ext << method.join
  end

  ext << @init_extra.join("\n") unless @init_extra.empty?

  ext << nil
  ext << "  }"
  ext << "#ifdef __cplusplus"
  ext << "}"
  ext << "#endif"
  ext << nil

  ext.join "\n"
end

#include(header) ⇒ Object

Adds an include to the top of the file. Don’t forget to use quotes or angle brackets.



759
760
761
# File 'lib/inline.rb', line 759

def include(header)
  @inc << "#include #{header}"
end

#include_ruby_lastObject

Specifies that the the ruby.h header should be included after custom header(s) instead of before them.



767
768
769
# File 'lib/inline.rb', line 767

def include_ruby_last
  @include_ruby_first = false
end

#loadObject

Loads the generated code back into ruby



520
521
522
# File 'lib/inline.rb', line 520

def load
  require "#{so_name}" or raise LoadError, "require on #{so_name} failed"
end

#load_cacheObject

Attempts to load pre-generated code returning true if it succeeds.



504
505
506
507
508
509
510
511
512
513
514
515
# File 'lib/inline.rb', line 504

def load_cache
  begin
    file = File.join("inline", File.basename(so_name))
    if require file then
      dir = Inline.directory
      warn "WAR\NING: #{dir} exists but is not being used" if test ?d, dir and $VERBOSE
      return true
    end
  rescue LoadError
  end
  return false
end

#map_c_const(names_and_types) ⇒ Object

Maps a C constant to ruby. names_and_types is a hash that maps the name of the constant to its C type.

builder.map_c_const :C_NAME => :int

If you wish to give the constant a different ruby name:

builder.map_c_const :C_NAME => [:int, :RUBY_NAME]


748
749
750
751
752
753
# File 'lib/inline.rb', line 748

def map_c_const(names_and_types)
  names_and_types.each do |name, typ|
    typ, ruby_name = Array === typ ? typ : [typ, name]
    self.add_to_init "    rb_define_const(c, #{ruby_name.to_s.inspect}, #{c2ruby(typ.to_s)}(#{name}));"
  end
end

#map_ruby_const(*names) ⇒ Object

Maps RubyConstants to cRubyConstants.



731
732
733
734
735
736
# File 'lib/inline.rb', line 731

def map_ruby_const(*names)
  names.each do |name|
    self.prefix "static VALUE c#{name};"
    self.add_to_init "    c#{name} = rb_const_get(c, rb_intern(#{name.to_s.inspect}));"
  end
end

#module_nameObject



369
370
371
372
373
374
375
376
377
378
# File 'lib/inline.rb', line 369

def module_name
  unless defined? @module_name then
    module_name = @mod.name.gsub('::','__')
    md5 = Digest::MD5.new
    @pre.each { |m| md5 << m.to_s }
    @sig.keys.sort_by { |x| x.to_s }.each { |m| md5 << m.to_s }
    @module_name = "Inline_#{module_name}_#{md5}"
  end
  @module_name
end

#parse_signature(src, raw = false) ⇒ Object

Raises:

  • (SyntaxError)


194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
# File 'lib/inline.rb', line 194

def parse_signature(src, raw=false)

  sig = self.strip_comments(src)
  # strip preprocessor directives
  sig.gsub!(/^\s*\#.*(\\\n.*)*/, '')
  # strip {}s
  sig.gsub!(/\{[^\}]*\}/, '{ }')
  # clean and collapse whitespace
  sig.gsub!(/\s+/, ' ')

  unless defined? @types then
    @types = 'void|' + @type_map.keys.map{|x| Regexp.escape(x)}.join('|')
  end

  if /(#{@types})\s*(\w+)\s*\(([^)]*)\)/ =~ sig then
    return_type, function_name, arg_string = $1, $2, $3
    args = []
    arg_string.split(',').each do |arg|

      # helps normalize into 'char * varname' form
      arg = arg.gsub(/\s*\*\s*/, ' * ').strip

      if /(((#{@types})\s*\*?)+)\s+(\w+)\s*$/ =~ arg then
        args.push([$4, $1])
      elsif arg != "void" then
        warn "WAR\NING: '#{arg}' not understood"
      end
    end

    arity = args.size
    arity = MAGIC_ARITY if raw

    return {
      'return' => return_type,
      'name'   => function_name,
      'args'   => args,
      'arity'  => arity
    }
  end

  raise SyntaxError, "Can't parse signature: #{sig}"
end

#prefix(code) ⇒ Object

Adds any amount of text/code to the source



774
775
776
# File 'lib/inline.rb', line 774

def prefix(code)
  @pre << code
end

#reader(method, type, member = method) ⇒ Object

Adds a reader for a C struct member wrapped via Data_Wrap_Struct. method is the ruby name to give the reader, type is the C type. Unless the C member name is overridden with member, the method name is used as the struct member. See #accessor for an example.



447
448
449
450
451
452
453
454
455
456
457
458
459
460
# File 'lib/inline.rb', line 447

def reader(method, type, member = method)
  raise "struct name not set for reader #{method} #{type}" unless
    @struct_name

  c <<-C
VALUE #{method}(void) {
  #{@struct_name} *pointer;

  Data_Get_Struct(self, #{@struct_name}, pointer);

  return #{c2ruby type}(pointer->#{member});
}
  C
end

#remove_type_converter(type) ⇒ Object

Unregisters C type-casts for type.



724
725
726
# File 'lib/inline.rb', line 724

def remove_type_converter(type)
  @type_map.delete type
end

#ruby2c(type) ⇒ Object

Converts ruby type type to a C type

Raises:

  • (ArgumentError)


488
489
490
491
# File 'lib/inline.rb', line 488

def ruby2c(type)
  raise ArgumentError, "Unknown type #{type.inspect}" unless @type_map.has_key? type
  @type_map[type].first
end

#so_nameObject



380
381
382
383
384
385
# File 'lib/inline.rb', line 380

def so_name
  unless defined? @so_name then
    @so_name = "#{Inline.directory}/#{module_name}.#{RbConfig::CONFIG["DLEXT"]}"
  end
  @so_name
end

#strip_comments(src) ⇒ Object



185
186
187
188
189
190
191
192
# File 'lib/inline.rb', line 185

def strip_comments(src)
  # strip c-comments
  src = src.gsub(%r%\s*/\*.*?\*/%m, '')
  # strip cpp-comments
  src = src.gsub(%r%^\s*//.*?\n%, '')
  src = src.gsub(%r%[ \t]*//[^\n]*%, '')
  src
end

#writer(method, type, member = method) ⇒ Object

Adds a writer for a C struct member wrapped via Data_Get_Struct. method is the ruby name to give the writer, type is the C type. Unless the C member name is overridden with member, the method name is used as the struct member. See #accessor for an example.



468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
# File 'lib/inline.rb', line 468

def writer(method, type, member = method)
  raise "struct name not set for writer #{method} #{type}" unless
    @struct_name

  c <<-C
VALUE #{method}_equals(VALUE value) {
  #{@struct_name} *pointer;

  Data_Get_Struct(self, #{@struct_name}, pointer);

  pointer->#{member} = #{ruby2c type}(value);

  return value;
}
  C
end