Class: Mkrf::Generator

Inherits:
Object
  • Object
show all
Includes:
Rake
Defined in:
lib/mkrf/generator.rb

Overview

Generator is concerned with taking configuration for an extension and writing a Rakefile to the local filesystem which will later be used to build the extension.

You will typically only create one Generator per extconf.rb file, which in turn will generate a Rakefile for building one extension module.

Usage

In the most basic usage, Generator simply takes the name of the library to compile:

require 'mkrf'
Mkrf::Generator.new('libtrivial')

Configuration of the build can be passed to the Generator constructor as a block:

Mkrf::Generator.new('libxml') do |g|
  g.include_library('socket','socket')
  g.include_header('libxml/xmlversion.h',
                   '/opt/include/libxml2',
                   '/usr/local/include/libxml2',
                   '/usr/include/libxml2')
end

It is also possible to specify the library paths in include_library

Mkrf::Generator.new('libxml') do |g|
  g.include_library('socket','socket', '/usr/local/lib/libxml')
end

Constant Summary collapse

CONFIG =
Config::CONFIG

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(extension_name, source_patterns = ["*.c"], availability_options = {}) {|_self| ... } ⇒ Generator

Create a Generator object which writes a Rakefile to the current directory of the local filesystem.

Params:

  • extension_name – the name of the extension

  • source_patterns – an array of patterns describing source files to be compiled. [“*.c”] is the default.

Yields:

  • (_self)

Yield Parameters:



73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
# File 'lib/mkrf/generator.rb', line 73

def initialize(extension_name, source_patterns = ["*.c"], availability_options = {})
  @sources = source_patterns
  @extension_name = extension_name + ".#{CONFIG['DLEXT']}"
  @available = Mkrf::Availability.new(availability_options)
  @defines = []
  if @sources[0] =~ /cpp/
    @cc = 'g++' # should be in CONFIG['C++'] but is not.
    @source_extension = 'cpp'
  else
    @cc = CONFIG['CC']
    @source_extension = 'c'
  end
  
  @objects  = ''
  @ldshared = ''
  @cflags   = "#{CONFIG['CCDLFLAGS']} #{CONFIG['CFLAGS']} #{CONFIG['ARCH_FLAG']}"
  
  yield self if block_given?
  write_rakefile
end

Instance Attribute Details

#additional_codeObject

Any extra code, given as a string, to be appended to the Rakefile.



47
48
49
# File 'lib/mkrf/generator.rb', line 47

def additional_code
  @additional_code
end

#cflagsObject

You may append to these attributes directly in your Generator.new block, for example: g.objects << ' ../common/foo.o ../common/bar.so -lmystuff' or g.cflags << ' -ansi -Wall'

Note the extra space at the beginning of those strings.



54
55
56
# File 'lib/mkrf/generator.rb', line 54

def cflags
  @cflags
end

#ldsharedObject

Any additional options you’d like appended to your system-specific linker command (which is used to build the shared library).



62
63
64
# File 'lib/mkrf/generator.rb', line 62

def ldshared
  @ldshared
end

#objectsObject

objects is for adding additional object files to the link-edit command – outside of the ones that correspond to the source files.



58
59
60
# File 'lib/mkrf/generator.rb', line 58

def objects
  @objects
end

Instance Method Details

#abort!(str, code = 1) ⇒ Object

Logs a fatal error and exits with a non-zero code (defaults to 1)



147
148
149
150
# File 'lib/mkrf/generator.rb', line 147

def abort!(str, code = 1)
  logger.fatal str
  exit code
end

#add_define(defn) ⇒ Object

Add a define to the compile string. Example:

Mkrf::Generator.new('my_library') do |g|    
  g.add_define('HAVE_PTHREADS')
end

Params:

  • defn – string to add to compile time defines



107
108
109
# File 'lib/mkrf/generator.rb', line 107

def add_define(defn)
  @available.defines << defn
end

#defines_compile_stringObject

:nodoc:



159
160
161
# File 'lib/mkrf/generator.rb', line 159

def defines_compile_string # :nodoc:
  @available.defines.collect {|define| "-D#{define}"}.join(' ')
end

#has_function?(function) ⇒ Boolean

Returns true if the function is able to be called based on libraries and headers currently loaded. Returns false otherwise.

Params:

  • function – the function to check for

Returns:

  • (Boolean)


132
133
134
# File 'lib/mkrf/generator.rb', line 132

def has_function?(function)
  @available.has_function? function
end

#include_header(*args) ⇒ Object

Include a header in the compile. Returns false if the header is not available, returns non-false otherwise. As a side effect, a compile time define occurs as HAVE_ appended with the name of the header in upper and scored case. Parameters are the same as Mkrf::Availability#include_header



123
124
125
# File 'lib/mkrf/generator.rb', line 123

def include_header(*args)
  @available.include_header(*args)
end

#include_library(*args) ⇒ Object

Include a library in the compile. Returns false if the library is not available. Returns non-false otherwise. Parameters are the same as Mkrf::Availability#include_library



114
115
116
# File 'lib/mkrf/generator.rb', line 114

def include_library(*args)
  @available.include_library(*args)
end

#library_path(path) ⇒ Object

:nodoc:



163
164
165
166
167
168
169
# File 'lib/mkrf/generator.rb', line 163

def library_path(path) # :nodoc:
  if RUBY_PLATFORM =~ /mswin/
    "-libpath:#{path}"
  else
    "-L#{path}"
  end
end

#loggerObject

Returns mkrf’s logger instance. You can use this to set logging levels.

Mkrf::Generator.new('libsomethin') do |g|
  g.logger.level = Logger::WARN
end


142
143
144
# File 'lib/mkrf/generator.rb', line 142

def logger
  @available.logger
end

#rakefile_contentsObject

:nodoc:



171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
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
# File 'lib/mkrf/generator.rb', line 171

def rakefile_contents # :nodoc:
  objext = CONFIG['OBJEXT']

  <<-END_RAKEFILE
# Generated by mkrf
require 'rake/clean'

CLEAN.include('*.#{objext}')
CLOBBER.include('#{@extension_name}', 'mkrf.log')

SRC = FileList[#{sources.join(',')}]
OBJ = SRC.ext('#{objext}')
CC = '#{@cc}'

ADDITIONAL_OBJECTS = '#{objects}'

LDSHARED = "#{@available.ldshared_string} #{ldshared}"

LIBPATH =  "#{library_path(CONFIG['libdir'])} #{@available.library_paths_compile_string}"

INCLUDES = "#{@available.includes_compile_string}"

LIBS = "#{@available.library_compile_string}"

CFLAGS = "#{cflags} #{defines_compile_string}"

RUBYARCHDIR = "\#{ENV["RUBYARCHDIR"]}"
LIBRUBYARG_SHARED = "#{CONFIG['LIBRUBYARG_SHARED']}"

task :default => ['#{@extension_name}']

rule '.#{objext}' => '.#{@source_extension}' do |t|
  sh "\#{CC} \#{CFLAGS} \#{INCLUDES} -c \#{t.source}"
end

desc "Build this extension"
file '#{@extension_name}' => OBJ do
  sh "\#{LDSHARED} \#{LIBPATH} #{@available.ld_outfile(@extension_name)} \#{OBJ} \#{ADDITIONAL_OBJECTS} \#{LIBS} \#{LIBRUBYARG_SHARED}"
end

desc "Install this extension"
task :install => '#{@extension_name}' do
  makedirs "\#{RUBYARCHDIR}"
  install "#{@extension_name}", "\#{RUBYARCHDIR}"
end

#{additional_code}
  END_RAKEFILE
end

#sourcesObject

An array of the source patterns as single quoted strings



95
96
97
# File 'lib/mkrf/generator.rb', line 95

def sources
  @sources.collect {|s| "'#{s}'"}
end

#write_rakefile(filename = "Rakefile") ⇒ Object

:nodoc:



152
153
154
155
156
157
# File 'lib/mkrf/generator.rb', line 152

def write_rakefile(filename = "Rakefile") # :nodoc:
  File.open(filename, "w+") do |f|
    f.puts rakefile_contents
  end
  logger.info "Rakefile written"
end