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
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
# File lib/mkmf/lite.rb, line 161 def check_sizeof(type, headers = []) headers = get_header_string(headers) erb = ERB.new(read_template('check_sizeof.erb')) code = erb.result(binding) try_to_execute(code) 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.
# File lib/mkmf/lite.rb, line 138 def check_valueof(constant, headers = []) headers = get_header_string(headers) erb = ERB.new(read_template('check_valueof.erb')) code = erb.result(binding) try_to_execute(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.
# 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 header
file. You may optionally provide a list of directories to search.
Returns true if found, or false if not found.
# 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
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.
# 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
Private Instance Methods
rubocop:disable Layout/LineLength
# 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
# File lib/mkmf/lite.rb, line 23 def cpp_defs RbConfig::CONFIG['DEFS'] end
# 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
# 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
# File lib/mkmf/lite.rb, line 43 def cpp_source_file 'conftest.c' 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.
# File lib/mkmf/lite.rb, line 182 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
Retrieve the path to the template file
name.
# File lib/mkmf/lite.rb, line 298 def get_template_file(file) File.join(File.dirname(__FILE__), 'templates', file) end
# File lib/mkmf/lite.rb, line 27 def jruby? defined?(JRUBY_VERSION) ? true : false end
Slurp the contents of the template file for evaluation later.
# File lib/mkmf/lite.rb, line 292 def read_template(file) File.read(get_template_file(file)) 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.
# File lib/mkmf/lite.rb, line 258 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 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.
# File lib/mkmf/lite.rb, line 209 def try_to_execute(code) begin result = 0 stderr_orig = $stderr.dup stdout_orig = $stdout.dup Dir.chdir(Dir.tmpdir) do File.write(cpp_source_file, code) command = "#{cpp_command} #{cpp_libraries} #{cpp_defs} " 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