module Mkmf::Lite
The Lite
module scopes the Mkmf
module to differentiate it from the Mkmf
module in the standard library.
Constants
- MKMF_LITE_VERSION
-
The version of the mkmf-lite library
Public Instance Methods
Source
# File lib/mkmf/lite.rb, line 201 def check_offsetof(struct_type, field, headers = [], *directories) headers = get_header_string(headers) erb = ERB.new(read_template('check_offsetof.erb')) code = erb.result(binding) if directories.empty? options = nil else options = '' directories.each{ |dir| options += "-I#{dir} " } options.rstrip! end try_to_execute(code, options) end
Returns the offset of field
within struct_type
using headers
, or common headers, plus stddef.h, if no headers are specified.
If this method fails an error is raised. This could happen if the field can’t be found and/or the header files do not include the indicated type. It will also fail if the field is a bit field.
Example:
class Foo include Mkmf::Lite utsname = check_offsetof('struct utsname', 'release', 'sys/utsname.h') end
Source
# File lib/mkmf/lite.rb, line 169 def check_sizeof(type, headers = [], *directories) headers = get_header_string(headers) erb = ERB.new(read_template('check_sizeof.erb')) code = erb.result(binding) if directories.empty? options = nil else options = '' directories.each{ |dir| options += "-I#{dir} " } options.rstrip! end try_to_execute(code, options) end
Returns the sizeof type
using headers
, or common headers if no headers are specified.
If this method fails an error is raised. This could happen if the type can’t be found and/or the header files do not include the indicated type.
Example:
class Foo include Mkmf::Lite utsname = check_sizeof('struct utsname', 'sys/utsname.h') end
Source
# File lib/mkmf/lite.rb, line 138 def check_valueof(constant, headers = [], *directories) headers = get_header_string(headers) erb = ERB.new(read_template('check_valueof.erb')) code = erb.result(binding) if directories.empty? options = nil else options = '' directories.each{ |dir| options += "-I#{dir} " } options.rstrip! end try_to_execute(code, options) end
Returns the value of the given constant
(which could also be a macro) using headers
, or common headers if no headers are specified.
If this method fails an error is raised. This could happen if the constant can’t be found and/or the header files do not include the indicated constant.
Source
# File lib/mkmf/lite.rb, line 99 def have_func(function, headers = []) headers = get_header_string(headers) erb_ptr = ERB.new(read_template('have_func_pointer.erb')) erb_std = ERB.new(read_template('have_func.erb')) ptr_code = erb_ptr.result(binding) std_code = erb_std.result(binding) # Check for just the function pointer first. If that fails, then try # to compile with the function declaration. try_to_compile(ptr_code) || try_to_compile(std_code) end
Check for the presence of the given function
in the common header files, or within any headers
that you provide.
Returns true if found, or false if not found.
Source
# File lib/mkmf/lite.rb, line 77 def have_header(header, *directories) erb = ERB.new(read_template('have_header.erb')) code = erb.result(binding) if directories.empty? options = nil else options = '' directories.each{ |dir| options += "-I#{dir} " } options.rstrip! end try_to_compile(code, options) end
Check for the presence of the given header
file. You may optionally provide a list of directories to search.
Returns true if found, or false if not found.
Source
# File lib/mkmf/lite.rb, line 122 def have_struct_member(struct_type, struct_member, headers = []) headers = get_header_string(headers) erb = ERB.new(read_template('have_struct_member.erb')) code = erb.result(binding) try_to_compile(code) end
Checks whether or not the struct of type struct_type
contains the struct_member
. If it does not, or the struct type cannot be found, then false is returned.
An optional list of headers
may be specified, in addition to the common header files that are already searched.
Private Instance Methods
Source
# File lib/mkmf/lite.rb, line 34 def cpp_command command = RbConfig::CONFIG['CC'] || RbConfig::CONFIG['CPP'] || File.which('cc') || File.which('gcc') || File.which('cl') raise 'Compiler not found' unless command command end
rubocop:disable Layout/LineLength
Source
# File lib/mkmf/lite.rb, line 57 def cpp_libraries return if File::ALT_SEPARATOR && RbConfig::CONFIG['CPP'] =~ /^cl/ return if jruby? if cpp_command =~ /clang/i '-Lrt -Ldl -Lcrypt -Lm' else '-lrt -ldl -lcrypt -lm' end end
Source
# File lib/mkmf/lite.rb, line 47 def cpp_out_file if File::ALT_SEPARATOR && RbConfig::CONFIG['CPP'] =~ /^cl/ '/Feconftest.exe' else '-o conftest.exe' end end
Source
# File lib/mkmf/lite.rb, line 230 def get_header_string(headers) headers = [headers] unless headers.is_a?(Array) common_headers = RbConfig::CONFIG['COMMON_HEADERS'] if common_headers.nil? || common_headers.empty? if headers.empty? headers = ['stdio.h', 'stdlib.h'] headers += 'windows.h' if File::ALT_SEPARATOR end else headers += common_headers.split end headers = headers.flatten.uniq headers.map{ |h| "#include <#{h}>" }.join("\n") end
Take an array of header file names (or convert it to an array if it’s a single argument), add the COMMON_HEADERS, flatten it out and remove any duplicates.
Finally, convert the result into a single string of ‘#include’ directives, each separated by a newline.
This string is then to be used at the top of the ERB templates.
Source
# File lib/mkmf/lite.rb, line 351 def get_template_file(file) File.join(File.dirname(__FILE__), 'templates', file) end
Retrieve the path to the template file
name.
Source
# File lib/mkmf/lite.rb, line 27 def jruby? defined?(JRUBY_VERSION) ? true : false end
Source
# File lib/mkmf/lite.rb, line 345 def read_template(file) File.read(get_template_file(file)) end
Slurp the contents of the template file for evaluation later.
Source
# File lib/mkmf/lite.rb, line 311 def try_to_compile(code, command_options = nil) begin boolean = false stderr_orig = $stderr.dup stdout_orig = $stdout.dup Dir.chdir(Dir.tmpdir) do File.write(cpp_source_file, code) if command_options command = "#{cpp_command} #{command_options} #{cpp_libraries} #{cpp_defs} " else command = "#{cpp_command} #{cpp_libraries} #{cpp_defs} " end command += "#{cpp_out_file} " command += cpp_source_file $stderr.reopen(IO::NULL) $stdout.reopen(IO::NULL) boolean = system(command) end ensure FileUtils.rm_f(cpp_source_file) FileUtils.rm_f(cpp_out_file) $stdout.reopen(stdout_orig) $stderr.reopen(stderr_orig) end boolean end
Create a temporary bit of C source code in the temp directory, and try to compile it. If it succeeds, return true. Otherwise, return false.
Note that $stderr is temporarily redirected to the null device because we don’t actually care about the reason for failure.
Source
# File lib/mkmf/lite.rb, line 257 def try_to_execute(code, command_options = nil) begin result = 0 stderr_orig = $stderr.dup stdout_orig = $stdout.dup Dir.chdir(Dir.tmpdir) do File.write(cpp_source_file, code) if command_options command = "#{cpp_command} #{command_options} #{cpp_libraries} #{cpp_defs} " else command = "#{cpp_command} #{cpp_libraries} #{cpp_defs} " end command += "#{cpp_out_file} " command += cpp_source_file # Temporarily close these $stderr.reopen(IO::NULL) $stdout.reopen(IO::NULL) if system(command) $stdout.reopen(stdout_orig) # We need this back for open3 to work. conftest = File::ALT_SEPARATOR ? 'conftest.exe' : './conftest.exe' Open3.popen3(conftest) do |stdin, stdout, stderr| stdin.close stderr.close result = stdout.gets.chomp.to_i end else raise "Failed to compile source code with command '#{command}':\n===\n#{code}===" end end ensure FileUtils.rm_f(cpp_source_file) FileUtils.rm_f(cpp_out_file) $stderr.reopen(stderr_orig) $stdout.reopen(stdout_orig) end result end
Create a temporary bit of C source code in the temp directory, and try to compile it. If it succeeds attempt to run the generated code. The code generated is expected to print a number to STDOUT, which is then grabbed and returned as an integer.
Note that $stderr is temporarily redirected to the null device because we don’t actually care about the reason for failure, though a Ruby error is raised if the compilation step fails.