Class: Rbind::Rbind

Inherits:
Object
  • Object
show all
Defined in:
lib/rbind/rbind.rb

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(name, parser = DefaultParser.new) ⇒ Rbind

Returns a new instance of Rbind.



28
29
30
31
32
33
34
35
36
37
38
39
# File 'lib/rbind/rbind.rb', line 28

def initialize(name,parser = DefaultParser.new)
    @name = GeneratorRuby.name
    @includes = []
    @pkg_config = []
    @rbind_pkgs= []
    @parser = parser

    lib_name = "rbind_#{name.downcase}"
    @generator_c = GeneratorC.new(@parser,name,lib_name)
    @generator_ruby = GeneratorRuby.new(@parser,name,lib_name)
    @generator_extern = GeneratorExtern.new(@parser)
end

Dynamic Method Handling

This class handles dynamic methods through the method_missing method

#method_missing(m, *args) ⇒ Object



205
206
207
208
209
210
211
212
213
# File 'lib/rbind/rbind.rb', line 205

def method_missing(m,*args)
    t = @parser.type(m.to_s,false,false)
    return t if t

    op = @parser.operation(m.to_s,false)
    return op if op

    super
end

Instance Attribute Details

#generator_cObject (readonly)

Returns the value of attribute generator_c.



6
7
8
# File 'lib/rbind/rbind.rb', line 6

def generator_c
  @generator_c
end

#generator_rubyObject (readonly)

Returns the value of attribute generator_ruby.



7
8
9
# File 'lib/rbind/rbind.rb', line 7

def generator_ruby
  @generator_ruby
end

#includesObject

Returns the value of attribute includes.



8
9
10
# File 'lib/rbind/rbind.rb', line 8

def includes
  @includes
end

#nameObject

Returns the value of attribute name.



9
10
11
# File 'lib/rbind/rbind.rb', line 9

def name
  @name
end

#parserObject (readonly)

Returns the value of attribute parser.



5
6
7
# File 'lib/rbind/rbind.rb', line 5

def parser
  @parser
end

#pkg_configObject

Returns the value of attribute pkg_config.



10
11
12
# File 'lib/rbind/rbind.rb', line 10

def pkg_config
  @pkg_config
end

#rbind_pkgsObject

extern rbind pkgs



11
12
13
# File 'lib/rbind/rbind.rb', line 11

def rbind_pkgs
  @rbind_pkgs
end

Class Method Details

.pkg_paths(pkg_name) ⇒ Object



13
14
15
16
17
18
19
20
# File 'lib/rbind/rbind.rb', line 13

def self.pkg_paths(pkg_name)
    out = IO.popen("pkg-config --cflags-only-I #{pkg_name}")
    paths = out.read.split("-I").delete_if(&:empty?).map do |i|
        i.gsub("\n","").gsub(" ","")
    end
    raise "Cannot find pkg paths for #{pkg_name}" if paths.empty?
    paths
end

.rbind_pkg_path(name) ⇒ Object



22
23
24
25
26
# File 'lib/rbind/rbind.rb', line 22

def self.rbind_pkg_path(name)
    files = Gem.find_files("#{name}/rbind/extern.rbind")
    raise "Cannot find paths for rbind package #{name}" if files.empty?
    File.dirname(files.first)
end

Instance Method Details

#add_std_exceptObject



188
189
190
191
192
193
194
195
196
# File 'lib/rbind/rbind.rb', line 188

def add_std_except
    @generator_c.includes << "<stdexcept>"
    exception = RClass.new(RBase.normalize("std::exception"))
    @parser.add_type(exception)

    runtime_error = RClass.new(RBase.normalize("std::runtime_error"))
    runtime_error.add_parent(exception)
    @parser.add_type(runtime_error)
end

#add_std_mapObject



183
184
185
186
# File 'lib/rbind/rbind.rb', line 183

def add_std_map
    @generator_c.includes << "<map>"
    @parser.add_type(StdMap.new("std::map"))
end

#add_std_string(with_c_string = true) ⇒ Object



169
170
171
172
173
174
175
# File 'lib/rbind/rbind.rb', line 169

def add_std_string(with_c_string = true)
    @generator_c.includes << "<string>"
    @generator_c.includes << "<cstring>" if with_c_string
    @parser.add_type(StdString.new("std::string",@parser))
    @parser.type_alias["basic_string"] = @parser.std.string
    self
end

#add_std_typesObject



198
199
200
201
202
203
# File 'lib/rbind/rbind.rb', line 198

def add_std_types
    add_std_vector
    add_std_string
    add_std_map
    add_std_except
end

#add_std_vectorObject



177
178
179
180
181
# File 'lib/rbind/rbind.rb', line 177

def add_std_vector
    @generator_c.includes << "<vector>"
    @parser.add_type(StdVector.new("std::vector"))
    self
end

#buildObject



106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
# File 'lib/rbind/rbind.rb', line 106

def build
    ::Rbind.log.info "build c wrappers"
    path = File.join(generator_c.output_path,"build")
    FileUtils.mkdir_p(path) if path && !File.directory?(path)
    Dir.chdir(path) do
        if !system("cmake -C ..")
            raise "CMake Configure Error"
        end
        if !system("make")
            raise "Make Build Error"
        end
    end
    if !system("cp #{File.join(path,"lib*.*")} #{generator_ruby.output_path}")
        raise "cannot copy library to #{generator_ruby.output_path}"
    end
    ::Rbind.log.info "all done !"
end

#check_pythonObject



48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
# File 'lib/rbind/rbind.rb', line 48

def check_python
    out = IO.popen("which python")
    if(out.read.empty?)
        raise 'Cannot find python interpreter needed for parsing header files'
    end
    in_,out,err = Open3.popen3("python --version")
    str = err.read
    str = if str.empty?
              out.read
          else
              str
          end
    if(str =~ /[a-zA-Z]* (.*)/)
        if $1.to_f < 2.7
            raise "Wrong python version #{$1}. At least python 2.7 is needed for parsing header files"
        end
    else
        raise 'Cannot determine python version needed for parsing header files'
    end
end

#generate(c_path = "src", ruby_path = "ruby/lib/#{name.downcase}") ⇒ Object



124
125
126
127
128
# File 'lib/rbind/rbind.rb', line 124

def generate(c_path = "src",ruby_path = "ruby/lib/#{name.downcase}")
    generate_c c_path,ruby_path
    generate_extern ruby_path,c_path
    generate_ruby ruby_path
end

#generate_c(path, ruby_path) ⇒ Object



136
137
138
139
140
141
142
# File 'lib/rbind/rbind.rb', line 136

def generate_c(path,ruby_path)
    ::Rbind.log.info "generate c wrappers"
    @generator_c.includes += includes
    @generator_c.includes.uniq!
    @generator_c.pkg_config = pkg_config
    @generator_c.generate(path,ruby_path)
end

#generate_extern(path, cpath) ⇒ Object



144
145
146
# File 'lib/rbind/rbind.rb', line 144

def generate_extern(path,cpath)
    @generator_extern.generate(File.join(path,"rbind"),@generator_ruby.module_name,@generator_ruby.file_prefix,cpath)
end

#generate_ruby(path) ⇒ Object



130
131
132
133
134
# File 'lib/rbind/rbind.rb', line 130

def generate_ruby(path)
    ::Rbind.log.info "generate ruby ffi wrappers"
    @generator_ruby.required_module_names = rbind_pkgs
    @generator_ruby.generate(path)
end

#libsObject



165
166
167
# File 'lib/rbind/rbind.rb', line 165

def libs
    @generator_c.libs
end

#on_type_not_found(&block) ⇒ Object



161
162
163
# File 'lib/rbind/rbind.rb', line 161

def on_type_not_found(&block)
    @parser.on_type_not_found(&block)
end

#parse(*files) ⇒ Object



41
42
43
44
45
46
# File 'lib/rbind/rbind.rb', line 41

def parse(*files)
    files.flatten.each do |path|
        raise ArgumentError, "File '#{path}' does not exist" if not File.exists?(path)
        parser.parse File.new(path).read
    end
end

#parse_externObject

parses other rbind packages



70
71
72
73
74
75
76
77
78
79
80
81
# File 'lib/rbind/rbind.rb', line 70

def parse_extern
    # extern package are always paresed with the default parser 
    local_parser = DefaultParser.new(parser)
    @rbind_pkgs.each do |pkg|
        path = Rbind.rbind_pkg_path(pkg)
        config = YAML.load(File.open(File.join(path,"config.rbind")).read)
        path = File.join(path,"extern.rbind")
        ::Rbind.log.info "parsing extern rbind file #{path}"
        local_parser.parse(File.open(path).read,config.ruby_module_name)
    end
    self
end

#parse_header(header) ⇒ Object



102
103
104
# File 'lib/rbind/rbind.rb', line 102

def parse_header(header)
    parser.parse parse_headers_dry(header)
end

#parse_headers(*headers) ⇒ Object



98
99
100
# File 'lib/rbind/rbind.rb', line 98

def parse_headers(*headers)
    parser.parse parse_headers_dry(*headers)
end

#parse_headers_dry(*headers) ⇒ Object



83
84
85
86
87
88
89
90
91
92
93
94
95
96
# File 'lib/rbind/rbind.rb', line 83

def parse_headers_dry(*headers)
    check_python
    headers = if headers.empty?
                  includes
              else
                  headers
              end
    headers = headers.map do |h|
        "\"#{h}\""
    end
    path = File.join(File.dirname(__FILE__),'tools','hdr_parser.py')
    out = IO.popen("python #{path} #{headers.join(" ")}")
    out.read
end

#type(*args) ⇒ Object



157
158
159
# File 'lib/rbind/rbind.rb', line 157

def type(*args)
    parser.type(*args)
end

#use_namespace(name) ⇒ Object



148
149
150
151
152
153
154
155
# File 'lib/rbind/rbind.rb', line 148

def use_namespace(name)
    t = if name.is_a? String
            parser.type(name)
        else
            name
        end
    parser.use_namespace t
end