123456789_123456789_123456789_123456789_123456789_

Module: MakeMakefile

Relationships & Source Files
Namespace Children
Modules:
Defined in: lib/mkmf.rb

Overview

mkmf.rb is used by Ruby C extensions to generate a Makefile which will correctly compile and link the C extension to Ruby and a third-party library.

Constant Summary

Class Method Summary

Instance Attribute Summary

Instance Method Summary

Class Method Details

.[](name) (private)

[ GitHub ]

  
# File 'lib/mkmf.rb', line 2787

def self.[](name)
  @lang.fetch(name)
end

.[]=(name, mod) (private)

[ GitHub ]

  
# File 'lib/mkmf.rb', line 2791

def self.[]=(name, mod)
  @lang[name] = mod
end

.config_string(key, config = CONFIG) (mod_func)

This method is for internal use only.
[ GitHub ]

  
# File 'lib/mkmf.rb', line 148

def config_string(key, config = CONFIG)
  s = config[key] and !s.empty? and block_given? ? yield(s) : s
end

.dir_re(dir) (mod_func)

This method is for internal use only.
[ GitHub ]

  
# File 'lib/mkmf.rb', line 153

def dir_re(dir)
  Regexp.new('\$(?:\('dir'\)|\{'dir'\})(?:\$(?:\(target_prefix\)|\{target_prefix\}))?')
end

.rm_f(*files) (mod_func)

This method is for internal use only.
[ GitHub ]

  
# File 'lib/mkmf.rb', line 266

def rm_f(*files)
  opt = (Hash === files.last ? [files.pop] : [])
  FileUtils.rm_f(Dir[*files.flatten], *opt)
end

.rm_rf(*files) (mod_func)

This method is for internal use only.
[ GitHub ]

  
# File 'lib/mkmf.rb', line 272

def rm_rf(*files)
  opt = (Hash === files.last ? [files.pop] : [])
  FileUtils.rm_rf(Dir[*files.flatten], *opt)
end

Instance Attribute Details

#have_devel?Boolean (readonly)

This method is for internal use only.
[ GitHub ]

  
# File 'lib/mkmf.rb', line 461

def have_devel?
  unless defined? $have_devel
    $have_devel = true
    $have_devel = try_link(MAIN_DOES_NOTHING)
  end
  $have_devel
end

#have_typeof?Boolean (readonly)

This method is for internal use only.

Used internally by the what_type? method to check if the typeof GCC extension is available.

[ GitHub ]

  
# File 'lib/mkmf.rb', line 1489

def have_typeof?
  return $typeof if defined?($typeof)
  $typeof = %w[__typeof__ typeof].find do |t|
    try_compile(<<SRC)
int rbcv_foo;
#{t}(rbcv_foo) rbcv_bar;
SRC
  end
end

Instance Method Details

#_libdir_basename (private)

This method is for internal use only.
[ GitHub ]

  
# File 'lib/mkmf.rb', line 2621

def _libdir_basename
  @libdir_basename ||= config_string("libdir") {|name| name[/\A\$\(exec_prefix\)\/(.*)/, 1]} || "lib"
end

#append_cflags(flags, *opts)

This method is for internal use only.
[ GitHub ]

  
# File 'lib/mkmf.rb', line 664

def append_cflags(flags, *opts)
  Array(flags).each do |flag|
    if checking_for("whether #{flag} is accepted as CFLAGS") {
         try_cflags(flag, *opts)
       }
      $CFLAGS << " " << flag
    end
  end
end

#append_cppflags(flags, *opts)

This method is for internal use only.
[ GitHub ]

  
# File 'lib/mkmf.rb', line 642

def append_cppflags(flags, *opts)
  Array(flags).each do |flag|
    if checking_for("whether #{flag} is accepted as CPPFLAGS") {
         try_cppflags(flag, *opts)
       }
      $CPPFLAGS << " " << flag
    end
  end
end

#append_ldflags(flags, *opts)

This method is for internal use only.
[ GitHub ]

  
# File 'lib/mkmf.rb', line 687

def append_ldflags(flags, *opts)
  Array(flags).each do |flag|
    if checking_for("whether #{flag} is accepted as LDFLAGS") {
         try_ldflags(flag, *opts)
       }
      $LDFLAGS << " " << flag
    end
  end
end

#append_library(libs, lib)

This method is for internal use only.

:no-doc:

[ GitHub ]

  
# File 'lib/mkmf.rb', line 949

def append_library(libs, lib) # :no-doc:
  format(LIBARG, lib) + " " + libs
end

#arg_config(config, default = nil, &block)

This method is for internal use only.
[ GitHub ]

  
# File 'lib/mkmf.rb', line 1615

def arg_config(config, default=nil, &block)
  $arg_config << [config, default]
  defaults = []
  if default
    defaults << default
  elsif !block
    defaults << nil
  end
  $configure_args.fetch(config.tr('_', '-'), *defaults, &block)
end

#cc_command(opt = "")

This method is for internal use only.
[ GitHub ]

  
# File 'lib/mkmf.rb', line 513

def cc_command(opt="")
  conf = cc_config(opt)
  RbConfig::expand("$(CC) #$INCFLAGS #$CPPFLAGS #$CFLAGS #$ARCH_FLAG #{opt} -c #{CONFTEST_C}",
                   conf)
end

#cc_config(opt = "")

This method is for internal use only.
[ GitHub ]

  
# File 'lib/mkmf.rb', line 506

def cc_config(opt="")
  conf = RbConfig::CONFIG.merge('hdrdir' => $hdrdir.quote, 'srcdir' => $srcdir.quote,
                                'arch_hdrdir' => $arch_hdrdir.quote,
                                'top_srcdir' => $top_srcdir.quote)
  conf
end

#check_signedness(type, headers = nil, opts = nil, &b)

Returns the signedness of the given type. You may optionally specify additional headers to search in for the type.

If the type is found and is a numeric type, a macro is passed as a preprocessor constant to the compiler using the type name, in uppercase, prepended with SIGNEDNESS_OF_, followed by the type name, followed by =X where “X” is positive integer if the type is unsigned and a negative integer if the type is signed.

For example, if size_t is defined as unsigned, then check_signedness('size_t') would return +1 and the SIGNEDNESS_OF_SIZE_T=1</code> preprocessor macro would be passed to the compiler. The SIGNEDNESS_OF_INT=-1 macro would be set for check_signedness('int')

[ GitHub ]

  
# File 'lib/mkmf.rb', line 1388

def check_signedness(type, headers = nil, opts = nil, &b)
  typedef, member, prelude = typedef_expr(type, headers)
  signed = nil
  checking_for("signedness of #{type}", STRING_OR_FAILED_FORMAT) do
    signed = try_signedness(typedef, member, [prelude], opts, &b) or next nil
    $defs.push("-DSIGNEDNESS_OF_%s=%+d" % [type.tr_cpp, signed])
    signed < 0 ? "signed" : "unsigned"
  end
  signed
end

#check_sizeof(type, headers = nil, opts = "", &b)

Returns the size of the given type. You may optionally specify additional headers to search in for the type.

If found, a macro is passed as a preprocessor constant to the compiler using the type name, in uppercase, prepended with SIZEOF_, followed by the type name, followed by =X where “X” is the actual size.

For example, if check_sizeof('mystruct') returned 12, then the SIZEOF_MYSTRUCT=12 preprocessor macro would be passed to the compiler.

[ GitHub ]

  
# File 'lib/mkmf.rb', line 1359

def check_sizeof(type, headers = nil, opts = "", &b)
  typedef, member, prelude = typedef_expr(type, headers)
  prelude << "#{typedef} *rbcv_ptr_;\n"
  prelude = [prelude]
  expr = "sizeof((*rbcv_ptr_)#{"." << member if member})"
  fmt = STRING_OR_FAILED_FORMAT
  checking_for checking_message("size of #{type}", headers), fmt do
    if size = try_constant(expr, prelude, opts, &b)
      $defs.push(format("-DSIZEOF_%s=%s", type.tr_cpp, size))
      size
    end
  end
end

#checking_for(m, fmt = nil)

This method is for internal use only.

This emits a string to stdout that allows users to see the results of the various have* and find* methods as they are tested.

Internal use only.

[ GitHub ]

  
# File 'lib/mkmf.rb', line 965

def checking_for(m, fmt = nil)
  f = caller[0][/in `([^<].*)'$/, 1] and f << ": " #` for vim #'
  m = "checking #{/\Acheck/ =~ f ? '' : 'for '}#{m}... "
  message "%s", m
  a = r = nil
  Logging::postpone do
    r = yield
    a = (fmt ? "#{fmt % r}" : r ? "yes" : "no")
    "#{f}#{m}-------------------- #{a}\n\n"
  end
  message "%s\n", a
  Logging::message "--------------------\n\n"
  r
end

#checking_message(target, place = nil, opt = nil)

This method is for internal use only.
[ GitHub ]

  
# File 'lib/mkmf.rb', line 980

def checking_message(target, place = nil, opt = nil)
  [["in", place], ["with", opt]].inject("#{target}") do |msg, (pre, noun)|
    if noun
      [[:to_str], [:join, ","], [:to_s]].each do |meth, *args|
        if noun.respond_to?(meth)
          break noun = noun.__send__(meth, *args)
        end
      end
      unless noun.empty?
        msg << " #{pre} " unless msg.empty?
        msg << noun
      end
    end
    msg
  end
end

#configuration(srcdir)

This method is for internal use only.
[ GitHub ]

  
# File 'lib/mkmf.rb', line 1925

def configuration(srcdir)
  mk = []
  vpath = $VPATH.dup
  CONFIG["hdrdir"] ||= $hdrdir
  mk << %{
SHELL = /bin/sh

# V=0 quiet, V=1 verbose.  other values don't work.
V = 0
Q1 = $(V:1=)
Q = $(Q1:0=@)
ECHO1 = $(V:1=@ #{CONFIG['NULLCMD']})
ECHO = $(ECHO1:0=@ echo)
NULLCMD = #{CONFIG['NULLCMD']}

#### Start of system configuration section. ####
#{"top_srcdir = " + $top_srcdir.sub(%r"\A#{Regexp.quote($topdir)}/", "$(topdir)/") if $extmk}
srcdir = #{srcdir.gsub(/\$\((srcdir)\)|\$\{(srcdir)\}/) {mkintpath(CONFIG[$1||$2]).unspace}}
topdir = #{mkintpath(topdir = $extmk ? CONFIG["topdir"] : $topdir).unspace}
hdrdir = #{(hdrdir = CONFIG["hdrdir"]) == topdir ? "$(topdir)" : mkintpath(hdrdir).unspace}
arch_hdrdir = #{mkintpath($arch_hdrdir).unspace}
PATH_SEPARATOR = #{CONFIG['PATH_SEPARATOR']}
VPATH = #{vpath.join(CONFIG['PATH_SEPARATOR'])}
}
  if $extmk
    mk << "RUBYLIB =\n""RUBYOPT = -\n"
  end
  prefix = mkintpath(CONFIG["prefix"])
  if destdir = prefix[$dest_prefix_pattern, 1]
    mk << "\nDESTDIR = #{destdir}\n"
    prefix = prefix[destdir.size..-1]
  end
  mk << "prefix = #{with_destdir(prefix).unspace}\n"
  CONFIG.each do |key, var|
    mk << "#{key} = #{with_destdir(mkintpath(var)).unspace}\n" if /.prefix$/ =~ key
  end
  CONFIG.each do |key, var|
    next if /^abs_/ =~ key
    next if /^(?:src|top(?:_src)?|build|hdr)dir$/ =~ key
    next unless /dir$/ =~ key
    mk << "#{key} = #{with_destdir(var)}\n"
  end
  if !$extmk and !$configure_args.has_key?('--ruby') and
      sep = config_string('BUILD_FILE_SEPARATOR')
    sep = ":/=#{sep}"
  else
    sep = ""
  end
  possible_command = (proc {|s| s if /top_srcdir|tooldir/ !~ s} unless $extmk)
  extconf_h = $extconf_h ? "-DRUBY_EXTCONF_H=\\\"$(RUBY_EXTCONF_H)\\\" " : $defs.join(" ") << " "
  headers = %w[
    $(hdrdir)/ruby.h
    $(hdrdir)/ruby/backward.h
    $(hdrdir)/ruby/ruby.h
    $(hdrdir)/ruby/defines.h
    $(hdrdir)/ruby/missing.h
    $(hdrdir)/ruby/intern.h
    $(hdrdir)/ruby/st.h
    $(hdrdir)/ruby/subst.h
  ]
  headers += $headers
  if RULE_SUBST
    headers.each {|h| h.sub!(/.*/, &RULE_SUBST.method(:%))}
  end
  headers << $config_h
  headers << '$(RUBY_EXTCONF_H)' if $extconf_h
  mk << %{

CC_WRAPPER = #{CONFIG['CC_WRAPPER']}
CC = #{CONFIG['CC']}
CXX = #{CONFIG['CXX']}
LIBRUBY = #{CONFIG['LIBRUBY']}
LIBRUBY_A = #{CONFIG['LIBRUBY_A']}
LIBRUBYARG_SHARED = #$LIBRUBYARG_SHARED
LIBRUBYARG_STATIC = #$LIBRUBYARG_STATIC
empty =
OUTFLAG = #{OUTFLAG}$(empty)
COUTFLAG = #{COUTFLAG}$(empty)
CSRCFLAG = #{CSRCFLAG}$(empty)

RUBY_EXTCONF_H = #{$extconf_h}
cflags   = #{CONFIG['cflags']}
cxxflags = #{CONFIG['cxxflags']}
optflags = #{CONFIG['optflags']}
debugflags = #{CONFIG['debugflags']}
warnflags = #{$warnflags}
cppflags = #{CONFIG['cppflags']}
CCDLFLAGS = #{$static ? '' : CONFIG['CCDLFLAGS']}
CFLAGS   = $(CCDLFLAGS) #$CFLAGS $(ARCH_FLAG)
INCFLAGS = -I. #$INCFLAGS
DEFS     = #{CONFIG['DEFS']}
CPPFLAGS = #{extconf_h}#{$CPPFLAGS}
CXXFLAGS = $(CCDLFLAGS) #$CXXFLAGS $(ARCH_FLAG)
ldflags  = #{$LDFLAGS}
dldflags = #{$DLDFLAGS} #{CONFIG['EXTDLDFLAGS']}
ARCH_FLAG = #{$ARCH_FLAG}
DLDFLAGS = $(ldflags) $(dldflags) $(ARCH_FLAG)
LDSHARED = #{CONFIG['LDSHARED']}
LDSHAREDXX = #{config_string('LDSHAREDXX') || '$(LDSHARED)'}
AR = #{CONFIG['AR']}
EXEEXT = #{CONFIG['EXEEXT']}

}
  CONFIG.each do |key, val|
    mk << "#{key} = #{val}\n" if /^RUBY.*NAME/ =~ key
  end
  mk << %{
arch = #{CONFIG['arch']}
sitearch = #{CONFIG['sitearch']}
ruby_version = #{RbConfig::CONFIG['ruby_version']}
ruby = #{$ruby.sub(%r[\A#{Regexp.quote(RbConfig::CONFIG['bindir'])}(?=/|\z)]) {'$(bindir)'}}
RUBY = $(ruby#{sep})
BUILTRUBY = #{if defined?($builtruby) && $builtruby
  $builtruby
else
  File.join('$(bindir)', CONFIG["RUBY_INSTALL_NAME"] + CONFIG['EXEEXT'])
end}
ruby_headers = #{headers.join(' ')}

RM = #{config_string('RM', &possible_command) || '$(RUBY) -run -e rm -- -f'}
RM_RF = #{'$(RUBY) -run -e rm -- -rf'}
RMDIRS = #{config_string('RMDIRS', &possible_command) || '$(RUBY) -run -e rmdir -- -p'}
MAKEDIRS = #{config_string('MAKEDIRS', &possible_command) || '@$(RUBY) -run -e mkdir -- -p'}
INSTALL = #{config_string('INSTALL', &possible_command) || '@$(RUBY) -run -e install -- -vp'}
INSTALL_PROG = #{config_string('INSTALL_PROG') || '$(INSTALL) -m 0755'}
INSTALL_DATA = #{config_string('INSTALL_DATA') || '$(INSTALL) -m 0644'}
COPY = #{config_string('CP', &possible_command) || '@$(RUBY) -run -e cp -- -v'}
TOUCH = exit >

#### End of system configuration section. ####

preload = #{defined?($preload) && $preload ? $preload.join(' ') : ''}
}
  mk
end

#conftest_source

This method is for internal use only.
[ GitHub ]

  
# File 'lib/mkmf.rb', line 437

def conftest_source
  CONFTEST_C
end

#convertible_int(type, headers = nil, opts = nil, &b)

Returns the convertible integer type of the given type. You may optionally specify additional headers to search in for the type. convertible means actually the same type, or typedef’d from the same type.

If the type is an integer type and the convertible type is found, the following macros are passed as preprocessor constants to the compiler using the type name, in uppercase.

  • TYPEOF_, followed by the type name, followed by =X where “X” is the found convertible type name.

  • TYP2NUM and NUM2TYP, where TYP is the type name in uppercase with replacing an _t suffix with “T”, followed by =X where “X” is the macro name to convert type to an Integer object, and vice versa.

For example, if foobar_t is defined as unsigned long, then convertible_int("foobar_t") would return “unsigned long”, and define these macros:

#define TYPEOF_FOOBAR_T unsigned long
#define FOOBART2NUM ULONG2NUM
#define NUM2FOOBART NUM2ULONG
[ GitHub ]

  
# File 'lib/mkmf.rb', line 1423

def convertible_int(type, headers = nil, opts = nil, &b)
  type, macname = *type
  checking_for("convertible type of #{type}", STRING_OR_FAILED_FORMAT) do
    if UNIVERSAL_INTS.include?(type)
      type
    else
      typedef, member, prelude = typedef_expr(type, headers, &b)
      if member
        prelude << "static rbcv_typedef_ rbcv_var;"
        compat = UNIVERSAL_INTS.find {|t|
          try_static_assert("sizeof(rbcv_var.#{member}) == sizeof(#{t})", [prelude], opts, &b)
        }
      else
        next unless signed = try_signedness(typedef, member, [prelude])
        u = "unsigned " if signed > 0
        prelude << "extern rbcv_typedef_ foo();"
        compat = UNIVERSAL_INTS.find {|t|
          try_compile([prelude, "extern #{u}#{t} foo();"].join("\n"), opts, :werror=>true, &b)
        }
      end
      if compat
        macname ||= type.sub(/_(?=t\z)/, '').tr_cpp
        conv = (compat == "long long" ? "LL" : compat.upcase)
        compat = "#{u}#{compat}"
        typename = type.tr_cpp
        $defs.push(format("-DSIZEOF_%s=SIZEOF_%s", typename, compat.tr_cpp))
        $defs.push(format("-DTYPEOF_%s=%s", typename, compat.quote))
        $defs.push(format("-DPRI_%s_PREFIX=PRI_%s_PREFIX", macname, conv))
        conv = (u ? "U" : "") + conv
        $defs.push(format("-D%s2NUM=%s2NUM", macname, conv))
        $defs.push(format("-DNUM2%s=NUM2%s", macname, conv))
        compat
      end
    end
  end
end

#cpp_command(outfile, opt = "")

This method is for internal use only.
[ GitHub ]

  
# File 'lib/mkmf.rb', line 519

def cpp_command(outfile, opt="")
  conf = cc_config(opt)
  if $universal and (arch_flag = conf['ARCH_FLAG']) and !arch_flag.empty?
    conf['ARCH_FLAG'] = arch_flag.gsub(/(?:\G|\s)-arch\s\S/, '')
  end
  RbConfig::expand("$(CPP) #$INCFLAGS #$CPPFLAGS #$CFLAGS #{opt} #{CONFTEST_C} #{outfile}",
                   conf)
end

#cpp_include(header)

This method is for internal use only.
[ GitHub ]

  
# File 'lib/mkmf.rb', line 621

def cpp_include(header)
  if header
    header = [header] unless header.kind_of? Array
    header.map {|h| String === h ? "#include <#{h}>\n" : h}.join
  else
    ""
  end
end

#create_header(header = "extconf.h")

Generates a header file consisting of the various macro definitions generated by other methods such as have_func and have_header. These are then wrapped in a custom #ifndef based on the header file name, which defaults to “extconf.h”.

For example:

# extconf.rb
require 'mkmf'
have_func('realpath')
have_header('sys/utime.h')
create_header
create_makefile('foo')

The above script would generate the following extconf.h file:

#ifndef EXTCONF_H
#define EXTCONF_H
#define HAVE_REALPATH 1
#define HAVE_SYS_UTIME_H 1
#endif

Given that the create_header method generates a file based on definitions set earlier in your extconf.rb file, you will probably want to make this one of the last methods you call in your script.

[ GitHub ]

  
# File 'lib/mkmf.rb', line 1715

def create_header(header = "extconf.h")
  message "creating %s\n", header
  sym = header.tr_cpp
  hdr = ["#ifndef #{sym}\n#define #{sym}\n"]
  for line in $defs
    case line
    when /^-D([^=]+)(?:=(.*))?/
      hdr << "#define #$1 #{$2 ? Shellwords.shellwords($2)[0].gsub(/(?=\t+)/, "\\\n") : 1}\n"
    when /^-U(.*)/
      hdr << "#undef #$1\n"
    end
  end
  hdr << "#endif\n"
  hdr = hdr.join("")
  log_src(hdr, "#{header} is")
  unless (IO.read(header) == hdr rescue false)
    open(header, "wb") do |hfile|
      hfile.write(hdr)
    end
  end
  $extconf_h = header
end

#create_makefile(target, srcprefix = nil)

Generates the Makefile for your extension, passing along any options and preprocessor constants that you may have generated through other methods.

The target name should correspond the name of the global function name defined within your C extension, minus the Init_. For example, if your C extension is defined as Init_foo, then your target would simply be “foo”.

If any “/” characters are present in the target name, only the last name is interpreted as the target name, and the rest are considered toplevel directory names, and the generated Makefile will be altered accordingly to follow that directory structure.

For example, if you pass “test/foo” as a target name, your extension will be installed under the “test” directory. This means that in order to load the file within a Ruby program later, that directory structure will have to be followed, e.g. require 'test/foo'.

The srcprefix should be used when your source files are not in the same directory as your build script. This will not only eliminate the need for you to manually copy the source files into the same directory as your build script, but it also sets the proper target_prefix in the generated Makefile.

Setting the target_prefix will, in turn, install the generated binary in a directory under your RbConfig::CONFIG['sitearchdir'] that mimics your local filesystem when you run make install.

For example, given the following file tree:

ext/
  extconf.rb
  test/
    foo.c

And given the following code:

create_makefile('test/foo', 'test')

That will set the target_prefix in the generated Makefile to “test”. That, in turn, will create the following file tree when installed via the make install command:

/path/to/ruby/sitearchdir/test/foo.so

It is recommended that you use this approach to generate your makefiles, instead of copying files around manually, because some third party libraries may depend on the target_prefix being set properly.

The srcprefix argument can be used to override the default source directory, i.e. the current directory. It is included as part of the VPATH and added to the list of INCFLAGS.

[ GitHub ]

  
# File 'lib/mkmf.rb', line 2224

def create_makefile(target, srcprefix = nil)
  $target = target
  libpath = $DEFLIBPATH|$LIBPATH
  message "creating Makefile\n"
  MakeMakefile.rm_f "#{CONFTEST}*"
  if CONFIG["DLEXT"] == $OBJEXT
    for lib in libs = $libs.split(' ')
      lib.sub!(/-l(.*)/, %%"lib\\1.#{$LIBEXT}"%)
    end
    $defs.push(format("-DEXTLIB='%s'", libs.join(",")))
  end

  if target.include?('/')
    target_prefix, target = File.split(target)
    target_prefix[0,0] = '/'
  else
    target_prefix = ""
  end

  srcprefix ||= "$(srcdir)/#{srcprefix}".chomp('/')
  RbConfig.expand(srcdir = srcprefix.dup)

  ext = ".#{$OBJEXT}"
  orig_srcs = Dir[File.join(srcdir, "*.{#{SRC_EXT.join(%q{,})}}")].sort
  if not $objs
    srcs = $srcs || orig_srcs
    $objs = []
    objs = srcs.inject(Hash.new {[]}) {|h, f|
      h.key?(o = File.basename(f, ".*") << ext) or $objs << o
      h[o] <<= f
      h
    }
    unless objs.delete_if {|b, f| f.size == 1}.empty?
      dups = objs.sort.map {|b, f|
        "#{b[/.*\./]}{#{f.collect {|n| n[/([^.]+)\z/]}.join(',')}}"
      }
      abort "source files duplication - #{dups.join(", ")}"
    end
  else
    $objs.collect! {|o| File.basename(o, ".*") << ext} unless $OBJEXT == "o"
    srcs = $srcs || $objs.collect {|o| o.chomp(ext) << ".c"}
  end
  $srcs = srcs

  hdrs = Dir[File.join(srcdir, "*.{#{HDR_EXT.join(%q{,})}}")]

  target = nil if $objs.empty?

  if target and EXPORT_PREFIX
    if File.exist?(File.join(srcdir, target + '.def'))
      deffile = "$(srcdir)/$(TARGET).def"
      unless EXPORT_PREFIX.empty?
        makedef = %{$(RUBY) -pe "$$_.sub!(/^(?=\\w)/,'#{EXPORT_PREFIX}') unless 1../^EXPORTS$/i" #{deffile}}
      end
    else
      makedef = %{(echo EXPORTS && echo $(TARGET_ENTRY))}
    end
    if makedef
      $cleanfiles << '$(DEFFILE)'
      origdef = deffile
      deffile = "$(TARGET)-$(arch).def"
    end
  end
  origdef ||= ''

  if $extout and $INSTALLFILES
    $cleanfiles.concat($INSTALLFILES.collect {|files, dir|File.join(dir, files.delete_prefix('./'))})
    $distcleandirs.concat($INSTALLFILES.collect {|files, dir| dir})
  end

  if $extmk and $static
    $defs << "-DRUBY_EXPORT=1"
  end

  if $extmk and not $extconf_h
    create_header
  end

  libpath = libpathflag(libpath)

  dllib = target ? "$(TARGET).#{CONFIG['DLEXT']}" : ""
  staticlib = target ? "$(TARGET).#$LIBEXT" : ""
  conf = configuration(srcprefix)
  conf << "\
libpath = #{($DEFLIBPATH|$LIBPATH).join(" ")}
LIBPATH = #{libpath}
DEFFILE = #{deffile}

CLEANFILES = #{$cleanfiles.join(' ')}
DISTCLEANFILES = #{$distcleanfiles.join(' ')}
DISTCLEANDIRS = #{$distcleandirs.join(' ')}

extout = #{$extout && $extout.quote}
extout_prefix = #{$extout_prefix}
target_prefix = #{target_prefix}
LOCAL_LIBS = #{$LOCAL_LIBS}
LIBS = #{$LIBRUBYARG} #{$libs} #{$LIBS}
ORIG_SRCS = #{orig_srcs.collect(&File.method(:basename)).join(' ')}
SRCS = $(ORIG_SRCS) #{(srcs - orig_srcs).collect(&File.method(:basename)).join(' ')}
OBJS = #{$objs.join(" ")}
HDRS = #{hdrs.map{|h| '$(srcdir)/' + File.basename(h)}.join(' ')}
LOCAL_HDRS = #{$headers.join(' ')}
TARGET = #{target}
TARGET_NAME = #{target && target[/\A\w+/]}
TARGET_ENTRY = #{EXPORT_PREFIX || ''}Init_$(TARGET_NAME)
DLLIB = #{dllib}
EXTSTATIC = #{$static || ""}
STATIC_LIB = #{staticlib unless $static.nil?}
#{!$extout && defined?($installed_list) ? "INSTALLED_LIST = #{$installed_list}\n" : ""}
TIMESTAMP_DIR = #{$extout && $extmk ? '$(extout)/.timestamp' : '.'}
" #"
  # TODO: fixme
  install_dirs.each {|d| conf << ("%-14s= %s\n" % d) if /^[[:upper:]]/ =~ d[0]}
  sodir = $extout ? '$(TARGET_SO_DIR)' : '$(RUBYARCHDIR)'
  n = '$(TARGET_SO_DIR)$(TARGET)'
  conf << "\
TARGET_SO_DIR =#{$extout ? " $(RUBYARCHDIR)/" : ''}
TARGET_SO     = $(TARGET_SO_DIR)$(DLLIB)
CLEANLIBS     = #{'$(TARGET_SO) ' if target}#{config_string('cleanlibs') {|t| t.gsub(/\$\*/) {n}}}
CLEANOBJS     = *.#{$OBJEXT} #{config_string('cleanobjs') {|t| t.gsub(/\$\*/, "$(TARGET)#{deffile ? '-$(arch)': ''}")} if target} *.bak
" #"

  conf = yield(conf) if block_given?
  mfile = open("Makefile", "wb")
  mfile.puts(conf)
  mfile.print "
all:    #{$extout ? "install" : target ? "$(DLLIB)" : "Makefile"}
static: #{$extmk && !$static ? "all" : "$(STATIC_LIB)#{$extout ? " install-rb" : ""}"}
.PHONY: all install static install-so install-rb
.PHONY: clean clean-so clean-static clean-rb
" #"
  mfile.print CLEANINGS
  fsep = config_string('BUILD_FILE_SEPARATOR') {|s| s unless s == "/"}
  if fsep
    sep = ":/=#{fsep}"
    fseprepl = proc {|s|
      s = s.gsub("/", fsep)
      s = s.gsub(/(\$\(\w+)(\))/) {$1sep$2}
      s.gsub(/(\$\{\w+)(\})/) {$1sep$2}
    }
    rsep = ":#{fsep}=/"
  else
    fseprepl = proc {|s| s}
    sep = ""
    rsep = ""
  end
  dirs = []
  mfile.print "install: install-so install-rb\n\n"
  dir = sodir.dup
  mfile.print("install-so: ")
  if target
    f = "$(DLLIB)"
    dest = "$(TARGET_SO)"
    stamp = timestamp_file(dir, target_prefix)
    if $extout
      mfile.puts dest
      mfile.print "clean-so::\n"
      mfile.print "\t-$(Q)$(RM) #{fseprepl[dest]} #{fseprepl[stamp]}\n"
      mfile.print "\t-$(Q)$(RMDIRS) #{fseprepl[dir]}#{$ignore_error}\n"
    else
      mfile.print "#{f} #{stamp}\n"
      mfile.print "\t$(INSTALL_PROG) #{fseprepl[f]} #{dir}\n"
      if defined?($installed_list)
        mfile.print "\t@echo #{dir}/#{File.basename(f)}>>$(INSTALLED_LIST)\n"
      end
    end
    mfile.print "clean-static::\n"
    mfile.print "\t-$(Q)$(RM) $(STATIC_LIB)\n"
  else
    mfile.puts "Makefile"
  end
  mfile.print("install-rb: pre-install-rb do-install-rb install-rb-default\n")
  mfile.print("install-rb-default: pre-install-rb-default do-install-rb-default\n")
  mfile.print("pre-install-rb: Makefile\n")
  mfile.print("pre-install-rb-default: Makefile\n")
  mfile.print("do-install-rb:\n")
  mfile.print("do-install-rb-default:\n")
  for sfx, i in [["-default", [["lib/**/*.rb", "$(RUBYLIBDIR)", "lib"]]], ["", $INSTALLFILES]]
    files = install_files(mfile, i, nil, srcprefix) or next
    for dir, *files in files
      unless dirs.include?(dir)
        dirs << dir
        mfile.print "pre-install-rb#{sfx}: #{timestamp_file(dir, target_prefix)}\n"
      end
      for f in files
        dest = "#{dir}/#{File.basename(f)}"
        mfile.print("do-install-rb#{sfx}: #{dest}\n")
        mfile.print("#{dest}: #{f} #{timestamp_file(dir, target_prefix)}\n")
        mfile.print("\t$(Q) $(#{$extout ? 'COPY' : 'INSTALL_DATA'}) #{f} $(@D)\n")
        if defined?($installed_list) and !$extout
          mfile.print("\t@echo #{dest}>>$(INSTALLED_LIST)\n")
        end
        if $extout
          mfile.print("clean-rb#{sfx}::\n")
          mfile.print("\t-$(Q)$(RM) #{fseprepl[dest]}\n")
        end
      end
    end
    mfile.print "pre-install-rb#{sfx}:\n"
    if files.empty?
      mfile.print("\t@$(NULLCMD)\n")
    else
      q = "$(MAKE) -q do-install-rb#{sfx}"
      if $nmake
        mfile.print "!if \"$(Q)\" == \"@\"\n\t@#{q} || \\\n!endif\n\t"
      else
        mfile.print "\t$(Q1:0=@#{q} || )"
      end
      mfile.print "$(ECHO1:0=echo) installing#{sfx.sub(/^-/, " ")} #{target} libraries\n"
    end
    if $extout
      dirs.uniq!
      unless dirs.empty?
        mfile.print("clean-rb#{sfx}::\n")
        for dir in dirs.sort_by {|d| -d.count('/')}
          stamp = timestamp_file(dir, target_prefix)
          mfile.print("\t-$(Q)$(RM) #{fseprepl[stamp]}\n")
          mfile.print("\t-$(Q)$(RMDIRS) #{fseprepl[dir]}#{$ignore_error}\n")
        end
      end
    end
  end
  dirs.unshift(sodir) if target and !dirs.include?(sodir)
  dirs.each do |d|
    t = timestamp_file(d, target_prefix)
    mfile.print "#{t}:\n\t$(Q) $(MAKEDIRS) $(@D) #{d}\n\t$(Q) $(TOUCH) $@\n"
  end

  mfile.print <<-SITEINSTALL

site-install: site-install-so site-install-rb
site-install-so: install-so
site-install-rb: install-rb

  SITEINSTALL

  return unless target

  mfile.print ".SUFFIXES: .#{(SRC_EXT + [$OBJEXT, $ASMEXT]).compact.join(' .')}\n"
  mfile.print "\n"

  compile_command = "\n\t$(ECHO) compiling $(<#{rsep})\n\t$(Q) %s\n\n"
  command = compile_command % COMPILE_CXX
  asm_command = compile_command.sub(/compiling/, 'translating') % ASSEMBLE_CXX
  CXX_EXT.each do |e|
    each_compile_rules do |rule|
      mfile.printf(rule, e, $OBJEXT)
      mfile.print(command)
      mfile.printf(rule, e, $ASMEXT)
      mfile.print(asm_command)
    end
  end
  command = compile_command % COMPILE_C
  asm_command = compile_command.sub(/compiling/, 'translating') % ASSEMBLE_C
  C_EXT.each do |e|
    each_compile_rules do |rule|
      mfile.printf(rule, e, $OBJEXT)
      mfile.print(command)
      mfile.printf(rule, e, $ASMEXT)
      mfile.print(asm_command)
    end
  end

  mfile.print "$(TARGET_SO): "
  mfile.print "$(DEFFILE) " if makedef
  mfile.print "$(OBJS) Makefile"
  mfile.print " #{timestamp_file(sodir, target_prefix)}" if $extout
  mfile.print "\n"
  mfile.print "\t$(ECHO) linking shared-object #{target_prefix.sub(/\A\/(.*)/, '\1/')}$(DLLIB)\n"
  mfile.print "\t-$(Q)$(RM) $(@#{sep})\n"
  link_so = LINK_SO.gsub(/^/, "\t$(Q) ")
  if srcs.any?(&%r"\.(?:#{CXX_EXT.join('|')})\z".method(:===))
    link_so = link_so.sub(/\bLDSHARED\b/, '\&XX')
  end
  mfile.print link_so, "\n\n"
  unless $static.nil?
    mfile.print "$(STATIC_LIB): $(OBJS)\n\t-$(Q)$(RM) $(@#{sep})\n\t"
    mfile.print "$(ECHO) linking static-library $(@#{rsep})\n\t$(Q) "
    mfile.print "$(AR) #{config_string('ARFLAGS') || 'cru '}$@ $(OBJS)"
    config_string('RANLIB') do |ranlib|
      mfile.print "\n\t-$(Q)#{ranlib} $(@) 2> /dev/null || true"
    end
  end
  mfile.print "\n\n"
  if makedef
    mfile.print "$(DEFFILE): #{origdef}\n"
    mfile.print "\t$(ECHO) generating $(@#{rsep})\n"
    mfile.print "\t$(Q) #{makedef} > $@\n\n"
  end

  depend = File.join(srcdir, "depend")
  if File.exist?(depend)
    mfile.print("###\n", *depend_rules(File.read(depend)))
  else
    mfile.print "$(OBJS): $(HDRS) $(ruby_headers)\n"
  end

  $makefile_created = true
ensure
  mfile.close if mfile
end

#create_tmpsrc(src)

This method is for internal use only.
[ GitHub ]

  
# File 'lib/mkmf.rb', line 441

def create_tmpsrc(src)
  src = "#{COMMON_HEADERS}\n#{src}"
  src = yield(src) if block_given?
  src.gsub!(/[ \t]+$/, '')
  src.gsub!(/\A\n|^\n$/, '')
  src.sub!(/[^\n]\z/, "\\&\n")
  count = 0
  begin
    open(conftest_source, "wb") do |cfile|
      cfile.print src
    end
  rescue Errno::EACCES
    if (count += 1) < 5
      sleep 0.2
      retry
    end
  end
  src
end

#depend_rules(depend)

Processes the data contents of the “depend” file. Each line of this file is expected to be a file name.

Returns the output of findings, in Makefile format.

[ GitHub ]

  
# File 'lib/mkmf.rb', line 2109

def depend_rules(depend)
  suffixes = []
  depout = []
  cont = implicit = nil
  impconv = proc do
    each_compile_rules {|rule| depout << (rule % implicit[0]) << implicit[1]}
    implicit = nil
  end
  ruleconv = proc do |line|
    if implicit
      if /\A\t/ =~ line
        implicit[1] << line
        next
      else
        impconv[]
      end
    end
    if m = /\A\.(\w)\.(\w)(?:\s*:)/.match(line)
      suffixes << m[1] << m[2]
      implicit = [[m[1], m[2]], [m.post_match]]
      next
    elsif RULE_SUBST and /\A(?!\s*\w+\s*=)[$\w][^#]*:/ =~ line
      line.sub!(/\s*\#.*$/, '')
      comment = $&
      line.gsub!(%r"(\s)(?!\.)([^$(){}=:\s\\,])(?=\s|\z)") {$1 + RULE_SUBST % $2}
      line = line.chomp + comment + "\n" if comment
    end
    depout << line
  end
  depend.each_line do |line|
    line.gsub!(/\.o\b/, ".#{$OBJEXT}")
    line.gsub!(/\{\$\(VPATH\)\}/, "") unless $nmake
    line.gsub!(/\$\((?:hdr|top)dir\)\/config.h/, $config_h)
    if $nmake && /\A\s*\$\(RM|COPY\)/ =~ line
      line.gsub!(%r"[-\w\./]{2,}"){$&.tr("/", "\\")}
      line.gsub!(/(\$\((?!RM|COPY)[^:)]+)(?=\))/, '\1:/=\\')
    end
    if /(?:^|[^\\])(?:\\\\)*\\$/ =~ line
      (cont ||= []) << line
      next
    elsif cont
      line = (cont << line).join
      cont = nil
    end
    ruleconv.call(line)
  end
  if cont
    ruleconv.call(cont.join)
  elsif implicit
    impconv.call
  end
  unless suffixes.empty?
    depout.unshift(".SUFFIXES: ." + suffixes.uniq.join(" .") + "\n\n")
  end
  if $extconf_h
    depout.unshift("$(OBJS): $(RUBY_EXTCONF_H)\n\n")
    depout.unshift("$(OBJS): $(hdrdir)/ruby/win32.h\n\n") if $mswin or $mingw
  end
  depout.flatten!
  depout
end

#dir_config(target) #dir_config(target, prefix) #dir_config(target, idefault, ldefault)

Sets a target name that the user can then use to configure various “with” options with on the command line by using that name. For example, if the target is set to “foo”, then the user could use the --with-foo-dir=prefix, --with-foo-include=dir and --with-foo-lib=dir command line options to tell where to search for header/library files.

You may pass along additional parameters to specify default values. If one is given it is taken as default prefix, and if two are given they are taken as “include” and “lib” defaults in that order.

In any case, the return value will be an array of determined “include” and “lib” directories, either of which can be nil if no corresponding command line option is given when no default value is specified.

Note that dir_config only adds to the list of places to search for libraries and include files. It does not link the libraries into your application.

[ GitHub ]

  
# File 'lib/mkmf.rb', line 1765

def dir_config(target, idefault=nil, ldefault=nil)
  if conf = $config_dirs[target]
    return conf
  end

  if dir = with_config(target + "-dir", (idefault unless ldefault))
    defaults = Array === dir ? dir : dir.split(File::PATH_SEPARATOR)
    idefault = ldefault = nil
  end

  idir = with_config(target + "-include", idefault)
  $arg_config.last[1] ||= "${#{target}-dir}/include"
  ldir = with_config(target + "-lib", ldefault)
  $arg_config.last[1] ||= "${#{target}-dir}/#{_libdir_basename}"

  idirs = idir ? Array === idir ? idir.dup : idir.split(File::PATH_SEPARATOR) : []
  if defaults
    idirs.concat(defaults.collect {|d| d + "/include"})
    idir = ([idir] + idirs).compact.join(File::PATH_SEPARATOR)
  end
  unless idirs.empty?
    idirs.collect! {|d| "-I" + d}
    idirs -= Shellwords.shellwords($CPPFLAGS)
    unless idirs.empty?
      $CPPFLAGS = (idirs.quote << $CPPFLAGS).join(" ")
    end
  end

  ldirs = ldir ? Array === ldir ? ldir.dup : ldir.split(File::PATH_SEPARATOR) : []
  if defaults
    ldirs.concat(defaults.collect {|d| "#{d}/#{_libdir_basename}"})
    ldir = ([ldir] + ldirs).compact.join(File::PATH_SEPARATOR)
  end
  $LIBPATH = ldirs | $LIBPATH

  $config_dirs[target] = [idir, ldir]
end

#dummy_makefile(srcdir)

creates a stub Makefile.

[ GitHub ]

  
# File 'lib/mkmf.rb', line 2078

def dummy_makefile(srcdir)
  configuration(srcdir) << <<RULES << CLEANINGS
CLEANFILES = #{$cleanfiles.join(' ')}
DISTCLEANFILES = #{$distcleanfiles.join(' ')}

all install static install-so install-rb: Makefile
	@$(NULLCMD)
.PHONY: all install static install-so install-rb
.PHONY: clean clean-so clean-static clean-rb

RULES
end

#each_compile_rules

This method is for internal use only.
[ GitHub ]

  
# File 'lib/mkmf.rb', line 2091

def each_compile_rules # :nodoc:
  vpath_splat = /\$\(\*VPATH\*\)/
  COMPILE_RULES.each do |rule|
    if vpath_splat =~ rule
      $VPATH.each do |path|
        yield rule.sub(vpath_splat) {path}
      end
    else
      yield rule
    end
  end
end

#egrep_cpp(pat, src, opt = "", &b)

This method is for internal use only.

Returns whether or not the src can be preprocessed with the C preprocessor and matches with pat.

If a block given, it is called with the source before compilation. You can modify the source in the block.

pat

a Regexp or a ::String

src

a ::String which contains a C source

opt

a ::String which contains preprocessor options

NOTE: When pat is a Regexp the matching will be checked in process, otherwise egrep(1) will be invoked to check it.

[ GitHub ]

  
# File 'lib/mkmf.rb', line 835

def egrep_cpp(pat, src, opt = "", &b)
  src = create_tmpsrc(src, &b)
  xpopen(cpp_command('', opt)) do |f|
    if Regexp === pat
      puts("    ruby -ne 'print if #{pat.inspect}'")
      f.grep(pat) {|l|
        puts "#{f.lineno}: #{l}"
        return true
      }
      false
    else
      puts("    egrep '#{pat}'")
      begin
        stdin = $stdin.dup
        $stdin.reopen(f)
        system("egrep", pat)
      ensure
        $stdin.reopen(stdin)
      end
    end
  end
ensure
  MakeMakefile.rm_f "#{CONFTEST}*"
  log_src(src)
end

#enable_config(config, default = nil)

Tests for the presence of an --enable-config or --disable-config option. Returns true if the enable option is given, false if the disable option is given, and the default value otherwise.

This can be useful for adding custom definitions, such as debug information.

Example:

if enable_config("debug")
   $defs.push("-DOSSL_DEBUG") unless $defs.include? "-DOSSL_DEBUG"
end
[ GitHub ]

  
# File 'lib/mkmf.rb', line 1677

def enable_config(config, default=nil)
  if arg_config("--enable-"+config)
    true
  elsif arg_config("--disable-"+config)
    false
  elsif block_given?
    yield(config, default)
  else
    return default
  end
end

#find_executable(bin, path = nil)

Searches for the executable bin on path. The default path is your PATH environment variable. If that isn’t defined, it will resort to searching /usr/local/bin, /usr/ucb, /usr/bin and /bin.

If found, it will return the full path, including the executable name, of where it was found.

Note that this method does not actually affect the generated Makefile.

[ GitHub ]

  
# File 'lib/mkmf.rb', line 1607

def find_executable(bin, path = nil)
  checking_for checking_message(bin, path) do
    find_executable0(bin, path)
  end
end

#find_executable0(bin, path = nil)

This method is for internal use only.

This method is used internally by the find_executable method.

Internal use only.

[ GitHub ]

  
# File 'lib/mkmf.rb', line 1562

def find_executable0(bin, path = nil)
  executable_file = proc do |name|
    begin
      stat = File.stat(name)
    rescue SystemCallError
    else
      next name if stat.file? and stat.executable?
    end
  end

  exts = config_string('EXECUTABLE_EXTS') {|s| s.split} || config_string('EXEEXT') {|s| [s]}
  if File.expand_path(bin) == bin
    return bin if executable_file.call(bin)
    if exts
      exts.each {|ext| executable_file.call(file = bin + ext) and return file}
    end
    return nil
  end
  if path ||= ENV['PATH']
    path = path.split(File::PATH_SEPARATOR)
  else
    path = %w[/usr/local/bin /usr/ucb /usr/bin /bin]
  end
  file = nil
  path.each do |dir|
    dir.sub!(/\A"(.*)"\z/m, '\1') if $mswin or $mingw
    return file if executable_file.call(file = File.join(dir, bin))
    if exts
      exts.each {|ext| executable_file.call(ext = file + ext) and return ext}
    end
  end
  nil
end

#find_header(header, *paths)

Instructs mkmf to search for the given header in any of the paths provided, and returns whether or not it was found in those paths.

If the header is found then the path it was found on is added to the list of included directories that are sent to the compiler (via the -I switch).

[ GitHub ]

  
# File 'lib/mkmf.rb', line 1173

def find_header(header, *paths)
  message = checking_message(header, paths)
  header = cpp_include(header)
  checking_for message do
    if try_header(header)
      true
    else
      found = false
      paths.each do |dir|
        opt = "-I#{dir}".quote
        if try_header(header, opt)
          $INCFLAGS << " " << opt
          found = true
          break
        end
      end
      found
    end
  end
end

#find_library(lib, func, *paths, &b)

Returns whether or not the entry point func can be found within the library lib in one of the paths specified, where paths is an array of strings. If func is nil , then the main() function is used as the entry point.

If lib is found, then the path it was found on is added to the list of library paths searched and linked against.

[ GitHub ]

  
# File 'lib/mkmf.rb', line 1047

def find_library(lib, func, *paths, &b)
  dir_config(lib)
  lib = with_config(lib+'lib', lib)
  paths = paths.collect {|path| path.split(File::PATH_SEPARATOR)}.flatten
  checking_for checking_message(func && func.funcall_style, LIBARG%lib) do
    libpath = $LIBPATH
    libs = append_library($libs, lib)
    begin
      until r = try_func(func, libs, &b) or paths.empty?
        $LIBPATH = libpath | [paths.shift]
      end
      if r
        $libs = libs
        libpath = nil
      end
    ensure
      $LIBPATH = libpath if libpath
    end
    r
  end
end

#find_type(type, opt, *headers, &b)

Returns where the static type type is defined.

You may also pass additional flags to opt which are then passed along to the compiler.

See also #have_type.

[ GitHub ]

  
# File 'lib/mkmf.rb', line 1270

def find_type(type, opt, *headers, &b)
  opt ||= ""
  fmt = "not found"
  def fmt.%(x)
    x ? x.respond_to?(:join) ? x.join(",") : x : self
  end
  checking_for checking_message(type, nil, opt), fmt do
    headers.find do |h|
      try_type(type, h, opt, &b)
    end
  end
end

#have_const(const, headers = nil, opt = "", &b)

Returns whether or not the constant const is defined. You may optionally pass the type of const as [const, type], such as:

have_const(%w[PTHREAD_MUTEX_INITIALIZER pthread_mutex_t], "pthread.h")

You may also pass additional headers to check against in addition to the common header files, and additional flags to opt which are then passed along to the compiler.

If found, a macro is passed as a preprocessor constant to the compiler using the type name, in uppercase, prepended with HAVE_CONST_.

For example, if have_const('foo') returned true, then the HAVE_CONST_FOO preprocessor macro would be passed to the compiler.

[ GitHub ]

  
# File 'lib/mkmf.rb', line 1318

def have_const(const, headers = nil, opt = "", &b)
  checking_for checking_message([*const].compact.join(' '), headers, opt) do
    try_const(const, headers, opt, &b)
  end
end

#have_framework(fw, &b)

Returns whether or not the given framework can be found on your system. If found, a macro is passed as a preprocessor constant to the compiler using the framework name, in uppercase, prepended with HAVE_FRAMEWORK_.

For example, if have_framework('Ruby') returned true, then the HAVE_FRAMEWORK_RUBY preprocessor macro would be passed to the compiler.

If fw is a pair of the framework name and its header file name that header file is checked, instead of the normally used header file which is named same as the framework.

[ GitHub ]

  
# File 'lib/mkmf.rb', line 1144

def have_framework(fw, &b)
  if Array === fw
    fw, header = *fw
  else
    header = "#{fw}.h"
  end
  checking_for fw do
    src = cpp_include("#{fw}/#{header}") << "\n" "int main(void){return 0;}"
    opt = " -framework #{fw}"
    if try_link(src, opt, &b) or (objc = try_link(src, "-ObjC#{opt}", &b))
      $defs.push(format("-DHAVE_FRAMEWORK_%s", fw.tr_cpp))
      # TODO: non-worse way than this hack, to get rid of separating
      # option and its argument.
      $LDFLAGS << " -ObjC" if objc and /(\A|\s)-ObjC(\s|\z)/ !~ $LDFLAGS
      $LIBS << opt
      true
    else
      false
    end
  end
end

#have_func(func, headers = nil, opt = "", &b)

Returns whether or not the function func can be found in the common header files, or within any headers that you provide. If found, a macro is passed as a preprocessor constant to the compiler using the function name, in uppercase, prepended with HAVE_.

To check functions in an additional library, you need to check that library first using have_library(). The func shall be either mere function name or function name with arguments.

For example, if have_func('foo') returned true, then the HAVE_FOO preprocessor macro would be passed to the compiler.

[ GitHub ]

  
# File 'lib/mkmf.rb', line 1081

def have_func(func, headers = nil, opt = "", &b)
  checking_for checking_message(func.funcall_style, headers, opt) do
    if try_func(func, $libs, headers, opt, &b)
      $defs << "-DHAVE_#{func.sans_arguments.tr_cpp}"
      true
    else
      false
    end
  end
end

#have_header(header, preheaders = nil, opt = "", &b)

Returns whether or not the given header file can be found on your system. If found, a macro is passed as a preprocessor constant to the compiler using the header file name, in uppercase, prepended with HAVE_.

For example, if have_header('foo.h') returned true, then the HAVE_FOO_H preprocessor macro would be passed to the compiler.

[ GitHub ]

  
# File 'lib/mkmf.rb', line 1121

def have_header(header, preheaders = nil, opt = "", &b)
  dir_config(header[/.*?(?=\/)|.*?(?=\.)/])
  checking_for header do
    if try_header(cpp_include(preheaders)+cpp_include(header), opt, &b)
      $defs.push(format("-DHAVE_%s", header.tr_cpp))
      true
    else
      false
    end
  end
end

#have_library(lib, func = nil, headers = nil, opt = "", &b)

Returns whether or not the given entry point func can be found within lib. If func is nil, the main() entry point is used by default. If found, it adds the library to list of libraries to be used when linking your extension.

If headers are provided, it will include those header files as the header files it looks in when searching for func.

The real name of the library to be linked can be altered by --with-FOOlib configuration option.

[ GitHub ]

  
# File 'lib/mkmf.rb', line 1021

def have_library(lib, func = nil, headers = nil, opt = "", &b)
  dir_config(lib)
  lib = with_config(lib+'lib', lib)
  checking_for checking_message(func && func.funcall_style, LIBARG%lib, opt) do
    if COMMON_LIBS.include?(lib)
      true
    else
      libs = append_library($libs, lib)
      if try_func(func, libs, headers, opt, &b)
        $libs = libs
        true
      else
        false
      end
    end
  end
end

#have_macro(macro, headers = nil, opt = "", &b)

Returns whether or not macro is defined either in the common header files or within any headers you provide.

Any options you pass to opt are passed along to the compiler.

[ GitHub ]

  
# File 'lib/mkmf.rb', line 1004

def have_macro(macro, headers = nil, opt = "", &b)
  checking_for checking_message(macro, headers, opt) do
    macro_defined?(macro, cpp_include(headers), opt, &b)
  end
end

#have_struct_member(type, member, headers = nil, opt = "", &b)

Returns whether or not the struct of type type contains member. If it does not, or the struct type can’t be found, then false is returned. You may optionally specify additional headers in which to look for the struct (in addition to the common header files).

If found, a macro is passed as a preprocessor constant to the compiler using the type name and the member name, in uppercase, prepended with HAVE_.

For example, if have_struct_member('struct foo', 'bar') returned true, then the HAVE_STRUCT_FOO_BAR preprocessor macro would be passed to the compiler.

HAVE_ST_BAR is also defined for backward compatibility.

[ GitHub ]

  
# File 'lib/mkmf.rb', line 1209

def have_struct_member(type, member, headers = nil, opt = "", &b)
  checking_for checking_message("#{type}.#{member}", headers) do
    if try_compile(<<"SRC", opt, &b)
#{cpp_include(headers)}
/*top*/
int s = (char *)&((#{type}*)0)->#{member} - (char *)0;
#{MAIN_DOES_NOTHING}
SRC
      $defs.push(format("-DHAVE_%s_%s", type.tr_cpp, member.tr_cpp))
      $defs.push(format("-DHAVE_ST_%s", member.tr_cpp)) # backward compatibility
      true
    else
      false
    end
  end
end

#have_type(type, headers = nil, opt = "", &b)

Returns whether or not the static type type is defined. You may optionally pass additional headers to check against in addition to the common header files.

You may also pass additional flags to opt which are then passed along to the compiler.

If found, a macro is passed as a preprocessor constant to the compiler using the type name, in uppercase, prepended with HAVE_TYPE_.

For example, if have_type('foo') returned true, then the HAVE_TYPE_FOO preprocessor macro would be passed to the compiler.

[ GitHub ]

  
# File 'lib/mkmf.rb', line 1257

def have_type(type, headers = nil, opt = "", &b)
  checking_for checking_message(type, headers, opt) do
    try_type(type, headers, opt, &b)
  end
end

#have_var(var, headers = nil, opt = "", &b)

Returns whether or not the variable var can be found in the common header files, or within any headers that you provide. If found, a macro is passed as a preprocessor constant to the compiler using the variable name, in uppercase, prepended with HAVE_.

To check variables in an additional library, you need to check that library first using have_library().

For example, if have_var('foo') returned true, then the HAVE_FOO preprocessor macro would be passed to the compiler.

[ GitHub ]

  
# File 'lib/mkmf.rb', line 1103

def have_var(var, headers = nil, opt = "", &b)
  checking_for checking_message(var, headers, opt) do
    if try_var(var, headers, opt, &b)
      $defs.push(format("-DHAVE_%s", var.tr_cpp))
      true
    else
      false
    end
  end
end

#init_mkmf(config = CONFIG, rbconfig = RbConfig::CONFIG)

This method is for internal use only.
[ GitHub ]

  
# File 'lib/mkmf.rb', line 2528

def init_mkmf(config = CONFIG, rbconfig = RbConfig::CONFIG)
  $makefile_created = false
  $arg_config = []
  $enable_shared = config['ENABLE_SHARED'] == 'yes'
  $defs = []
  $extconf_h = nil
  $config_dirs = {}

  if $warnflags = CONFIG['warnflags'] and CONFIG['GCC'] == 'yes'
    # turn warnings into errors only for bundled extensions.
    config['warnflags'] = $warnflags.gsub(/(\A|\s)-Werror[-=]/, '\1-W')
    if /icc\z/ =~ config['CC']
      config['warnflags'].gsub!(/(\A|\s)-W(?:division-by-zero|deprecated-declarations)/, '\1')
    end
    RbConfig.expand(rbconfig['warnflags'] = config['warnflags'].dup)
    config.each do |key, val|
      RbConfig.expand(rbconfig[key] = val.dup) if /warnflags/ =~ val
    end
    $warnflags = config['warnflags'] unless $extmk
  end
  if (w = rbconfig['CC_WRAPPER']) and !w.empty? and !File.executable?(w)
    rbconfig['CC_WRAPPER'] = config['CC_WRAPPER'] = ''
  end
  $CFLAGS = with_config("cflags", arg_config("CFLAGS", config["CFLAGS"])).dup
  $CXXFLAGS = (with_config("cxxflags", arg_config("CXXFLAGS", config["CXXFLAGS"]))||'').dup
  $ARCH_FLAG = with_config("arch_flag", arg_config("ARCH_FLAG", config["ARCH_FLAG"])).dup
  $CPPFLAGS = with_config("cppflags", arg_config("CPPFLAGS", config["CPPFLAGS"])).dup
  $LDFLAGS = with_config("ldflags", arg_config("LDFLAGS", config["LDFLAGS"])).dup
  $INCFLAGS = "-I$(arch_hdrdir)"
  $INCFLAGS << " -I$(hdrdir)/ruby/backward" unless $extmk
  $INCFLAGS << " -I$(hdrdir) -I$(srcdir)"
  $DLDFLAGS = with_config("dldflags", arg_config("DLDFLAGS", config["DLDFLAGS"])).dup
  config_string("ADDITIONAL_DLDFLAGS") {|flags| $DLDFLAGS << " " << flags} unless $extmk
  $LIBEXT = config['LIBEXT'].dup
  $OBJEXT = config["OBJEXT"].dup
  $EXEEXT = config["EXEEXT"].dup
  $ASMEXT = config_string('ASMEXT', &:dup) || 'S'
  $LIBS = "#{config['LIBS']} #{config['DLDLIBS']}"
  $LIBRUBYARG = ""
  $LIBRUBYARG_STATIC = config['LIBRUBYARG_STATIC']
  $LIBRUBYARG_SHARED = config['LIBRUBYARG_SHARED']
  $DEFLIBPATH = [$extmk ? "$(topdir)" : "$(#{config["libdirname"] || "libdir"})"]
  $DEFLIBPATH.unshift(".")
  $LIBPATH = []
  $INSTALLFILES = []
  $NONINSTALLFILES = [/~\z/, /\A#.*#\z/, /\A\.#/, /\.bak\z/i, /\.orig\z/, /\.rej\z/, /\.l[ao]\z/, /\.o\z/]
  $VPATH = %w[$(srcdir) $(arch_hdrdir)/ruby $(hdrdir)/ruby]

  $objs = nil
  $srcs = nil
  $headers = []
  $libs = ""
  if $enable_shared or RbConfig.expand(config["LIBRUBY"].dup) != RbConfig.expand(config["LIBRUBY_A"].dup)
    $LIBRUBYARG = config['LIBRUBYARG']
  end

  $LOCAL_LIBS = ""

  $cleanfiles = config_string('CLEANFILES') {|s| Shellwords.shellwords(s)} || []
  $cleanfiles << "mkmf.log"
  $distcleanfiles = config_string('DISTCLEANFILES') {|s| Shellwords.shellwords(s)} || []
  $distcleandirs = config_string('DISTCLEANDIRS') {|s| Shellwords.shellwords(s)} || []

  $extout ||= nil
  $extout_prefix ||= nil

  $arg_config.clear
  $config_dirs.clear
  dir_config("opt")
end

#install_dirs(target_prefix = nil)

This method is for internal use only.
[ GitHub ]

  
# File 'lib/mkmf.rb', line 183

def install_dirs(target_prefix = nil)
  if $extout and $extmk
    dirs = [
      ['BINDIR',        '$(extout)/bin'],
      ['RUBYCOMMONDIR', '$(extout)/common'],
      ['RUBYLIBDIR',    '$(RUBYCOMMONDIR)$(target_prefix)'],
      ['RUBYARCHDIR',   '$(extout)/$(arch)$(target_prefix)'],
      ['HDRDIR',        '$(extout)/include/ruby$(target_prefix)'],
      ['ARCHHDRDIR',    '$(extout)/include/$(arch)/ruby$(target_prefix)'],
      ['extout',        "#$extout"],
      ['extout_prefix', "#$extout_prefix"],
    ]
  elsif $extmk
    dirs = [
      ['BINDIR',        '$(bindir)'],
      ['RUBYCOMMONDIR', '$(rubylibdir)'],
      ['RUBYLIBDIR',    '$(rubylibdir)$(target_prefix)'],
      ['RUBYARCHDIR',   '$(archdir)$(target_prefix)'],
      ['HDRDIR',        '$(rubyhdrdir)/ruby$(target_prefix)'],
      ['ARCHHDRDIR',    '$(rubyhdrdir)/$(arch)/ruby$(target_prefix)'],
    ]
  elsif $configure_args.has_key?('--vendor')
    dirs = [
      ['BINDIR',        '$(bindir)'],
      ['RUBYCOMMONDIR', '$(vendordir)$(target_prefix)'],
      ['RUBYLIBDIR',    '$(vendorlibdir)$(target_prefix)'],
      ['RUBYARCHDIR',   '$(vendorarchdir)$(target_prefix)'],
      ['HDRDIR',        '$(vendorhdrdir)$(target_prefix)'],
      ['ARCHHDRDIR',    '$(vendorarchhdrdir)$(target_prefix)'],
    ]
  else
    dirs = [
      ['BINDIR',        '$(bindir)'],
      ['RUBYCOMMONDIR', '$(sitedir)$(target_prefix)'],
      ['RUBYLIBDIR',    '$(sitelibdir)$(target_prefix)'],
      ['RUBYARCHDIR',   '$(sitearchdir)$(target_prefix)'],
      ['HDRDIR',        '$(sitehdrdir)$(target_prefix)'],
      ['ARCHHDRDIR',    '$(sitearchhdrdir)$(target_prefix)'],
    ]
  end
  dirs << ['target_prefix', (target_prefix ? "/#{target_prefix}" : "")]
  dirs
end

#install_files(mfile, ifiles, map = nil, srcprefix = nil)

This method is for internal use only.
[ GitHub ]

  
# File 'lib/mkmf.rb', line 902

def install_files(mfile, ifiles, map = nil, srcprefix = nil)
  ifiles or return
  ifiles.empty? and return
  srcprefix ||= "$(srcdir)/#{srcprefix}".chomp('/')
  RbConfig::expand(srcdir = srcprefix.dup)
  dirs = []
  path = Hash.new {|h, i| h[i] = dirs.push([i])[-1]}
  ifiles.each do |files, dir, prefix|
    dir = map_dir(dir, map)
    prefix &&= %r|\A#{Regexp.quote(prefix)}/?|
    if /\A\.\// =~ files
      # install files which are in current working directory.
      files = files[2..-1]
      len = nil
    else
      # install files which are under the $(srcdir).
      files = File.join(srcdir, files)
      len = srcdir.size
    end
    f = nil
    Dir.glob(files) do |fx|
      f = fx
      f[0..len] = "" if len
      case File.basename(f)
      when *$NONINSTALLFILES
        next
      end
      d = File.dirname(f)
      d.sub!(prefix, "") if prefix
      d = (d.empty? || d == ".") ? dir : File.join(dir, d)
      f = File.join(srcprefix, f) if len
      path[d] << f
    end
    unless len or f
      d = File.dirname(files)
      d.sub!(prefix, "") if prefix
      d = (d.empty? || d == ".") ? dir : File.join(dir, d)
      path[d] << files
    end
  end
  dirs
end

#install_rb(mfile, dest, srcdir = nil)

This method is for internal use only.
[ GitHub ]

  
# File 'lib/mkmf.rb', line 945

def install_rb(mfile, dest, srcdir = nil)
  install_files(mfile, [["lib/**/*.rb", dest, "lib"]], nil, srcdir)
end

#libpath_env

This method is for internal use only.
[ GitHub ]

  
# File 'lib/mkmf.rb', line 377

def libpath_env
  # used only if native compiling
  if libpathenv = config_string("LIBPATHENV")
    pathenv = ENV[libpathenv]
    libpath = RbConfig.expand($DEFLIBPATH.join(File::PATH_SEPARATOR))
    {libpathenv => [libpath, pathenv].compact.join(File::PATH_SEPARATOR)}
  else
    {}
  end
end

#libpathflag(libpath = $DEFLIBPATH|$LIBPATH)

This method is for internal use only.
[ GitHub ]

  
# File 'lib/mkmf.rb', line 528

def libpathflag(libpath=$DEFLIBPATH|$LIBPATH)
  libpath.map{|x|
    case x
    when "$(topdir)", /\A\./
      LIBPATHFLAG
    else
      LIBPATHFLAG+RPATHFLAG
    end % x.quote
  }.join
end

#log_src(src, heading = "checked program was")

This method is for internal use only.
[ GitHub ]

  
# File 'lib/mkmf.rb', line 423

def log_src(src, heading="checked program was")
  src = src.split(/^/)
  fmt = "%#{src.size.to_s.size}d: %s"
  Logging::message <<"EOM"
#{heading}:
/* begin */
EOM
  src.each_with_index {|line, no| Logging::message fmt, no+1, line}
  Logging::message <<"EOM"
/* end */

EOM
end

#macro_defined?(macro, src, opt = "", &b) ⇒ Boolean

This method is for internal use only.

This is used internally by the have_macro? method.

[ GitHub ]

  
# File 'lib/mkmf.rb', line 862

def macro_defined?(macro, src, opt = "", &b)
  src = src.sub(/[^\n]\z/, "\\&\n")
  try_compile(src + <<"SRC", opt, &b)
/*top*/
#ifndef #{macro}
# error
|:/ === #{macro} undefined === /:|
#endif
SRC
end

MAIN_DOES_NOTHING(*refs) (private)

This method is for internal use only.
[ GitHub ]

  
# File 'lib/mkmf.rb', line 2625

def MAIN_DOES_NOTHING(*refs)
  src = MAIN_DOES_NOTHING
  unless refs.empty?
    src = src.sub(/\{/) do
      $& +
        "\n  if (argc > 1000000) {\n" +
        refs.map {|n|"    int (* volatile #{n}p)(void)=(int (*)(void))&#{n};\n"}.join("") +
        refs.map {|n|"    printf(\"%d\", (*#{n}p)());\n"}.join("") +
        "  }\n"
    end
  end
  src
end

#map_dir(dir, map = nil)

This method is for internal use only.
[ GitHub ]

  
# File 'lib/mkmf.rb', line 227

def map_dir(dir, map = nil)
  map ||= INSTALL_DIRS
  map.inject(dir) {|d, (orig, new)| d.gsub(orig, new)}
end

#merge_libs(*libs)

This method is for internal use only.
[ GitHub ]

  
# File 'lib/mkmf.rb', line 290

def merge_libs(*libs)
  libs.inject([]) do |x, y|
    y = y.inject([]) {|ary, e| ary.last == e ? ary : ary << e}
    y.each_with_index do |v, yi|
      if xi = x.rindex(v)
        x[(xi+1)..-1] = merge_libs(y[(yi+1)..-1], x[(xi+1)..-1])
        x[xi, 0] = y[0...yi]
        break
      end
    end and x.concat(y)
    x
  end
end

#message(*s)

This method is for internal use only.
[ GitHub ]

  
# File 'lib/mkmf.rb', line 953

def message(*s)
  unless Logging.quiet and not $VERBOSE
    printf(*s)
    $stdout.flush
  end
end

#mkintpath(path)

This method is for internal use only.
[ GitHub ]

  
# File 'lib/mkmf.rb', line 1920

def mkintpath(path)
  path
end

#mkmf_failed(path)

This method is for internal use only.

Returns whether or not the Makefile was successfully generated. If not, the script will abort with an error message.

Internal use only.

[ GitHub ]

  
# File 'lib/mkmf.rb', line 2612

def mkmf_failed(path)
  unless $makefile_created or File.exist?("Makefile")
    opts = $arg_config.collect {|t, n| "\t#{t}#{n ? "=#{n}" : ""}\n"}
    abort "*** #{path} failed ***\n" + FailedMessage + opts.join
  end
end

#modified?(target, times) ⇒ Boolean

This method is for internal use only.

Returns time stamp of the target file if it exists and is newer than or equal to all of times.

[ GitHub ]

  
# File 'lib/mkmf.rb', line 280

def modified?(target, times)
  (t = File.mtime(target)) rescue return nil
  Array === times or times = [times]
  t if times.all? {|n| n <= t}
end

#pkg_config(pkg, option = nil)

Returns compile/link information about an installed library in a tuple of [cflags, ldflags, libs], by using the command found first in the following commands:

  1. If --with-{pkg}-config={command} is given via command line option: {command} {option}

  2. {pkg}-config {option}

  3. pkg-config {option} {pkg}

Where option is, for instance, --cflags.

The values obtained are appended to $INCFLAGS, $CFLAGS, $LDFLAGS and $libs.

If an option argument is given, the config command is invoked with the option and a stripped output string is returned without modifying any of the global values mentioned above.

[ GitHub ]

  
# File 'lib/mkmf.rb', line 1822

def pkg_config(pkg, option=nil)
  if pkgconfig = with_config("#{pkg}-config") and find_executable0(pkgconfig)
    # iff package specific config command is given
  elsif ($PKGCONFIG ||=
         (pkgconfig = with_config("pkg-config", ("pkg-config" unless CROSS_COMPILING))) &&
         find_executable0(pkgconfig) && pkgconfig) and
      xsystem("#{$PKGCONFIG} --exists #{pkg}")
    # default to pkg-config command
    pkgconfig = $PKGCONFIG
    get = proc {|opt|
      opt = xpopen("#{$PKGCONFIG} --#{opt} #{pkg}", err:[:child, :out], &:read)
      Logging.open {puts opt.each_line.map{|s|"=> #{s.inspect}"}}
      opt.strip if $?.success?
    }
  elsif find_executable0(pkgconfig = "#{pkg}-config")
    # default to package specific config command, as a last resort.
  else
    pkgconfig = nil
  end
  if pkgconfig
    get ||= proc {|opt|
      opt = xpopen("#{pkgconfig} --#{opt}", err:[:child, :out], &:read)
      Logging.open {puts opt.each_line.map{|s|"=> #{s.inspect}"}}
      opt.strip if $?.success?
    }
  end
  orig_ldflags = $LDFLAGS
  if get and option
    get[option]
  elsif get and try_ldflags(ldflags = get['libs'])
    if incflags = get['cflags-only-I']
      $INCFLAGS << " " << incflags
      cflags = get['cflags-only-other']
    else
      cflags = get['cflags']
    end
    libs = get['libs-only-l']
    if cflags
      $CFLAGS += " " << cflags
      $CXXFLAGS += " " << cflags
    end
    if libs
      ldflags = (Shellwords.shellwords(ldflags) - Shellwords.shellwords(libs)).quote.join(" ")
    else
      libs, ldflags = Shellwords.shellwords(ldflags).partition {|s| s =~ /-l([^ ]+)/ }.map {|l|l.quote.join(" ")}
    end
    $libs += " " << libs

    $LDFLAGS = [orig_ldflags, ldflags].join(' ')
    Logging::message "package configuration for %s\n", pkg
    Logging::message "incflags: %s\ncflags: %s\nldflags: %s\nlibs: %s\n\n",
                     incflags, cflags, ldflags, libs
    [[incflags, cflags].join(' '), ldflags, libs]
  else
    Logging::message "package configuration for %s is not found\n", pkg
    nil
  end
end

#relative_from(path, base)

This method is for internal use only.
[ GitHub ]

  
# File 'lib/mkmf.rb', line 158

def relative_from(path, base)
  dir = File.join(path, "")
  if File.expand_path(dir) == File.expand_path(dir, base)
    path
  else
    File.join(base, path)
  end
end

#scalar_ptr_type?(type, member = nil, headers = nil, &b) ⇒ Boolean

This method is for internal use only.

Used internally by the what_type? method to determine if type is a scalar pointer.

[ GitHub ]

  
# File 'lib/mkmf.rb', line 1463

def scalar_ptr_type?(type, member = nil, headers = nil, &b)
  try_compile(<<"SRC", &b)   # pointer
#{cpp_include(headers)}
/*top*/
volatile #{type} conftestval;
extern int t(void);
#{MAIN_DOES_NOTHING 't'}
int t(void) {return (int)(1-*(conftestval#{member ? ".#{member}" : ""}));}
SRC
end

#scalar_type?(type, member = nil, headers = nil, &b) ⇒ Boolean

This method is for internal use only.

Used internally by the what_type? method to determine if type is a scalar pointer.

[ GitHub ]

  
# File 'lib/mkmf.rb', line 1476

def scalar_type?(type, member = nil, headers = nil, &b)
  try_compile(<<"SRC", &b)   # pointer
#{cpp_include(headers)}
/*top*/
volatile #{type} conftestval;
extern int t(void);
#{MAIN_DOES_NOTHING 't'}
int t(void) {return (int)(1-(conftestval#{member ? ".#{member}" : ""}));}
SRC
end

#split_libs(*strs)

This method is for internal use only.
[ GitHub ]

  
# File 'lib/mkmf.rb', line 286

def split_libs(*strs)
  strs.map {|s| s.split(/\s+(?=-|\z)/)}.flatten
end

#timestamp_file(name, target_prefix = nil)

This method is for internal use only.
[ GitHub ]

  
# File 'lib/mkmf.rb', line 2061

def timestamp_file(name, target_prefix = nil)
  pat = {}
  name = '$(RUBYARCHDIR)' if name == '$(TARGET_SO_DIR)'
  install_dirs.each do |n, d|
    pat[n] = $` if /\$\(target_prefix\)\z/ =~ d
  end
  name = name.gsub(/\$\((#{pat.keys.join("|")})\)/) {pat[$1]+target_prefix}
  name.sub!(/(\$\((?:site)?arch\))\/*/, '')
  arch = $1 || ''
  name.chomp!('/')
  name = name.gsub(/(\$[({]|[})])|(\/)|[^-.\w]/) {$1 ? "" : $2 ? ".-." : "_"}
  File.join("$(TIMESTAMP_DIR)", arch, "#{name.sub(/\A(?=.)/, '.')}.time")
end

#try_cflags(flags, opts = {})

This method is for internal use only.
[ GitHub ]

  
# File 'lib/mkmf.rb', line 660

def try_cflags(flags, opts = {})
  try_compile(MAIN_DOES_NOTHING, flags, {:werror => true}.update(opts))
end

#try_compile(src, opt = "", *opts, &b)

This method is for internal use only.

Returns whether or not the src can be compiled as a C source. opt is passed to the C compiler as options. Note that $CFLAGS is also passed to the compiler.

If a block given, it is called with the source before compilation. You can modify the source in the block.

src

a ::String which contains a C source

opt

a ::String which contains compiler options

[ GitHub ]

  
# File 'lib/mkmf.rb', line 596

def try_compile(src, opt="", *opts, &b)
  with_werror(opt, *opts) {|_opt, *| try_do(src, cc_command(_opt), *opts, &b)} and
    File.file?("#{CONFTEST}.#{$OBJEXT}")
ensure
  MakeMakefile.rm_f "#{CONFTEST}*"
end

#try_const(const, headers = nil, opt = "", &b)

Returns whether or not the constant const is defined.

See also #have_const

[ GitHub ]

  
# File 'lib/mkmf.rb', line 1287

def try_const(const, headers = nil, opt = "", &b)
  const, type = *const
  if try_compile(<<"SRC", opt, &b)
#{cpp_include(headers)}
/*top*/
typedef #{type || 'int'} conftest_type;
conftest_type conftestval = #{type ? '' : '(int)'}#{const};
SRC
    $defs.push(format("-DHAVE_CONST_%s", const.tr_cpp))
    true
  else
    false
  end
end

#try_constant(const, headers = nil, opt = "", &b)

This method is for internal use only.
[ GitHub ]

  
# File 'lib/mkmf.rb', line 706

def try_constant(const, headers = nil, opt = "", &b)
  includes = cpp_include(headers)
  neg = try_static_assert("#{const} < 0", headers, opt)
  if CROSS_COMPILING
    if neg
      const = "-(#{const})"
    elsif try_static_assert("#{const} > 0", headers, opt)
      # positive constant
    elsif try_static_assert("#{const} == 0", headers, opt)
      return 0
    else
      # not a constant
      return nil
    end
    upper = 1
    until try_static_assert("#{const} <= #{upper}", headers, opt)
      lower = upper
      upper <<= 1
    end
    return nil unless lower
    while upper > lower + 1
      mid = (upper + lower) / 2
      if try_static_assert("#{const} > #{mid}", headers, opt)
        lower = mid
      else
        upper = mid
      end
    end
    upper = -upper if neg
    return upper
  else
    src = %{#{includes}
#include <stdio.h>
/*top*/
typedef#{neg ? '' : ' unsigned'}
#ifdef PRI_LL_PREFIX
#define PRI_CONFTEST_PREFIX PRI_LL_PREFIX
LONG_LONG
#else
#define PRI_CONFTEST_PREFIX "l"
long
#endif
conftest_type;
conftest_type conftest_const = (conftest_type)(#{const});
int main() {printf("%"PRI_CONFTEST_PREFIX"#{neg ? 'd' : 'u'}\\n", conftest_const); return 0;}
}
    begin
      if try_link0(src, opt, &b)
        xpopen("./#{CONFTEST}") do |f|
          return Integer(f.gets)
        end
      end
    ensure
      MakeMakefile.rm_f "#{CONFTEST}#{$EXEEXT}"
    end
  end
  nil
end

#try_cpp(src, opt = "", *opts, &b)

This method is for internal use only.

Returns whether or not the src can be preprocessed with the C preprocessor. opt is passed to the preprocessor as options. Note that $CFLAGS is also passed to the preprocessor.

If a block given, it is called with the source before preprocessing. You can modify the source in the block.

src

a ::String which contains a C source

opt

a ::String which contains preprocessor options

[ GitHub ]

  
# File 'lib/mkmf.rb', line 612

def try_cpp(src, opt="", *opts, &b)
  try_do(src, cpp_command(CPPOUTFILE, opt), *opts, &b) and
    File.file?("#{CONFTEST}.i")
ensure
  MakeMakefile.rm_f "#{CONFTEST}*"
end

#try_cppflags(flags, opts = {})

This method is for internal use only.
[ GitHub ]

  
# File 'lib/mkmf.rb', line 638

def try_cppflags(flags, opts = {})
  try_header(MAIN_DOES_NOTHING, flags, {:werror => true}.update(opts))
end

#try_do(src, command, *opts, &b)

This method is for internal use only.
[ GitHub ]

  
# File 'lib/mkmf.rb', line 469

def try_do(src, command, *opts, &b)
  unless have_devel?
    raise <<MSG
The compiler failed to generate an executable file.
You have to install development tools first.
MSG
  end
  begin
    src = create_tmpsrc(src, &b)
    xsystem(command, *opts)
  ensure
    log_src(src)
  end
end

#try_func(func, libs, headers = nil, opt = "", &b)

This method is for internal use only.

You should use #have_func rather than try_func.

func

a ::String which contains a symbol name

libs

a ::String which contains library names.

headers

a ::String or an ::Array of strings which contains names of header files.

[ GitHub ]

  
# File 'lib/mkmf.rb', line 771

def try_func(func, libs, headers = nil, opt = "", &b)
  headers = cpp_include(headers)
  case func
  when /^&/
    decltype = proc {|x|"const volatile void *#{x}"}
  when /\)$/
    call = func
  when nil
    call = ""
  else
    call = "#{func}()"
    decltype = proc {|x| "void ((*#{x})())"}
  end
  if opt and !opt.empty?
    [[:to_str], [:join, " "], [:to_s]].each do |meth, *args|
      if opt.respond_to?(meth)
        break opt = opt.__send__(meth, *args)
      end
    end
    opt = "#{opt} #{libs}"
  else
    opt = libs
  end
  decltype && try_link(<<"SRC", opt, &b) or
#{headers}
/*top*/
extern int t(void);
#{MAIN_DOES_NOTHING 't'}
int t(void) { #{decltype["volatile p"]}; p = (#{decltype[]})#{func}; return !p; }
SRC
  call && try_link(<<"SRC", opt, &b)
#{headers}
/*top*/
extern int t(void);
#{MAIN_DOES_NOTHING 't'}
#{"extern void #{call};" if decltype}
int t(void) { #{call}; return 0; }
SRC
end

#try_ldflags(flags, opts = {})

This method is for internal use only.
[ GitHub ]

  
# File 'lib/mkmf.rb', line 682

def try_ldflags(flags, opts = {})
  opts = {:werror => true}.update(opts) if $mswin
  try_link(MAIN_DOES_NOTHING, flags, opts)
end

#try_link0(src, opt = "", *opts, &b)

This method is for internal use only.
[ GitHub ]

  
# File 'lib/mkmf.rb', line 550

def try_link0(src, opt="", *opts, &b) # :nodoc:
  exe = CONFTEST+$EXEEXT
  cmd = link_command("", opt)
  if $universal
    require 'tmpdir'
    Dir.mktmpdir("mkmf_", oldtmpdir = ENV["TMPDIR"]) do |tmpdir|
      begin
        ENV["TMPDIR"] = tmpdir
        try_do(src, cmd, *opts, &b)
      ensure
        ENV["TMPDIR"] = oldtmpdir
      end
    end
  else
    try_do(src, cmd, *opts, &b)
  end and File.executable?(exe) or return nil
  exe
ensure
  MakeMakefile.rm_rf(*Dir["#{CONFTEST}*"]-[exe])
end

#try_run(src, opt = "", &b)

This method is for internal use only.

Returns whether or not:

  • the src can be compiled as a C source,

  • the result object can be linked with its depending libraries successfully,

  • the linked file can be invoked as an executable

  • and the executable exits successfully

opt is passed to the linker as options. Note that $CFLAGS and $LDFLAGS are also passed to the linker.

If a block given, it is called with the source before compilation. You can modify the source in the block.

src

a ::String which contains a C source

opt

a ::String which contains linker options

Returns true when the executable exits successfully, false when it fails, or nil when preprocessing, compilation or link fails.

[ GitHub ]

  
# File 'lib/mkmf.rb', line 891

def try_run(src, opt = "", &b)
  raise "cannot run test program while cross compiling" if CROSS_COMPILING
  if try_link0(src, opt, &b)
    xsystem("./#{CONFTEST}")
  else
    nil
  end
ensure
  MakeMakefile.rm_f "#{CONFTEST}*"
end

#try_signedness(type, member, headers = nil, opts = nil)

This method is for internal use only.

Raises:

  • (ArgumentError)
[ GitHub ]

  
# File 'lib/mkmf.rb', line 1337

def try_signedness(type, member, headers = nil, opts = nil)
  raise ArgumentError, "don't know how to tell signedness of members" if member
  if try_static_assert("(#{type})-1 < 0", headers, opts)
    return -1
  elsif try_static_assert("(#{type})-1 > 0", headers, opts)
    return +1
  end
end

#try_static_assert(expr, headers = nil, opt = "", &b)

This method is for internal use only.
[ GitHub ]

  
# File 'lib/mkmf.rb', line 697

def try_static_assert(expr, headers = nil, opt = "", &b)
  headers = cpp_include(headers)
  try_compile(<<SRC, opt, &b)
#{headers}
/*top*/
int conftest_const[(#{expr}) ? 1 : -1];
SRC
end

#try_type(type, headers = nil, opt = "", &b)

Returns whether or not the static type type is defined.

See also #have_type

[ GitHub ]

  
# File 'lib/mkmf.rb', line 1230

def try_type(type, headers = nil, opt = "", &b)
  if try_compile(<<"SRC", opt, &b)
#{cpp_include(headers)}
/*top*/
typedef #{type} conftest_type;
int conftestval[sizeof(conftest_type)?1:-1];
SRC
    $defs.push(format("-DHAVE_TYPE_%s", type.tr_cpp))
    true
  else
    false
  end
end

#try_var(var, headers = nil, opt = "", &b)

This method is for internal use only.

You should use #have_var rather than try_var.

[ GitHub ]

  
# File 'lib/mkmf.rb', line 812

def try_var(var, headers = nil, opt = "", &b)
  headers = cpp_include(headers)
  try_compile(<<"SRC", opt, &b)
#{headers}
/*top*/
extern int t(void);
#{MAIN_DOES_NOTHING 't'}
int t(void) { const volatile void *volatile p; p = &(&#{var})[0]; return !p; }
SRC
end

#typedef_expr(type, headers)

This method is for internal use only.
[ GitHub ]

  
# File 'lib/mkmf.rb', line 1330

def typedef_expr(type, headers)
  typename, member = type.split('.', 2)
  prelude = cpp_include(headers).split(/$/)
  prelude << "typedef #{typename} rbcv_typedef_;\n"
  return "rbcv_typedef_", member, prelude
end

#what_type?(type, member = nil, headers = nil, &b) ⇒ Boolean

This method is for internal use only.
[ GitHub ]

  
# File 'lib/mkmf.rb', line 1499

def what_type?(type, member = nil, headers = nil, &b)
  m = "#{type}"
  var = val = "*rbcv_var_"
  func = "rbcv_func_(void)"
  if member
    m << "." << member
  else
    type, member = type.split('.', 2)
  end
  if member
    val = "(#{var}).#{member}"
  end
  prelude = [cpp_include(headers).split(/^/)]
  prelude << ["typedef #{type} rbcv_typedef_;\n",
              "extern rbcv_typedef_ *#{func};\n",
              "rbcv_typedef_ #{var};\n",
             ]
  type = "rbcv_typedef_"
  fmt = member && !(typeof = have_typeof?) ? "seems %s" : "%s"
  if typeof
    var = "*rbcv_member_"
    func = "rbcv_mem_func_(void)"
    member = nil
    type = "rbcv_mem_typedef_"
    prelude[-1] << "typedef #{typeof}(#{val}) #{type};\n"
    prelude[-1] << "extern #{type} *#{func};\n"
    prelude[-1] << "#{type} #{var};\n"
    val = var
  end
  def fmt.%(x)
    x ? super : "unknown"
  end
  checking_for checking_message(m, headers), fmt do
    if scalar_ptr_type?(type, member, prelude, &b)
      if try_static_assert("sizeof(*#{var}) == 1", prelude)
        return "string"
      end
      ptr = "*"
    elsif scalar_type?(type, member, prelude, &b)
      unless member and !typeof or try_static_assert("(#{type})-1 < 0", prelude)
        unsigned = "unsigned"
      end
      ptr = ""
    else
      next
    end
    type = UNIVERSAL_INTS.find do |t|
      pre = prelude
      unless member
        pre += [["#{unsigned} #{t} #{ptr}#{var};\n",
                 "extern #{unsigned} #{t} #{ptr}*#{func};\n"]]
      end
      try_static_assert("sizeof(#{ptr}#{val}) == sizeof(#{unsigned} #{t})", pre)
    end
    type or next
    [unsigned, type, ptr].join(" ").strip
  end
end

#winsep(s)

This method is for internal use only.

Converts forward slashes to backslashes. Aimed at MS Windows.

Internal use only.

[ GitHub ]

  
# File 'lib/mkmf.rb', line 1892

def winsep(s)
  s.tr('/', '\\')
end

#with_cflags(flags)

This method is for internal use only.
[ GitHub ]

  
# File 'lib/mkmf.rb', line 652

def with_cflags(flags)
  cflags = $CFLAGS
  $CFLAGS = flags.dup
  ret = yield
ensure
  $CFLAGS = cflags unless ret
end

#with_config(config, default = nil)

Tests for the presence of a --with-config or --without-config option. Returns true if the with option is given, false if the without option is given, and the default value otherwise.

This can be useful for adding custom definitions, such as debug information.

Example:

if with_config("debug")
   $defs.push("-DOSSL_DEBUG") unless $defs.include? "-DOSSL_DEBUG"
end
[ GitHub ]

  
# File 'lib/mkmf.rb', line 1642

def with_config(config, default=nil)
  config = config.sub(/^--with[-_]/, '')
  val = arg_config("--with-"+config) do
    if arg_config("--without-"+config)
      false
    elsif block_given?
      yield(config, default)
    else
      break default
    end
  end
  case val
  when "yes"
    true
  when "no"
    false
  else
    val
  end
end

#with_cppflags(flags)

This method is for internal use only.
[ GitHub ]

  
# File 'lib/mkmf.rb', line 630

def with_cppflags(flags)
  cppflags = $CPPFLAGS
  $CPPFLAGS = flags.dup
  ret = yield
ensure
  $CPPFLAGS = cppflags unless ret
end

#with_destdir(dir)

This method is for internal use only.
[ GitHub ]

  
# File 'lib/mkmf.rb', line 1883

def with_destdir(dir)
  dir = dir.sub($dest_prefix_pattern, '')
  /\A\$[\(\{]/ =~ dir ? dir : "$(DESTDIR)"+dir
end

#with_ldflags(flags)

This method is for internal use only.
[ GitHub ]

  
# File 'lib/mkmf.rb', line 674

def with_ldflags(flags)
  ldflags = $LDFLAGS
  $LDFLAGS = flags.dup
  ret = yield
ensure
  $LDFLAGS = ldflags unless ret
end

#with_werror(opt, opts = nil)

This method is for internal use only.
[ GitHub ]

  
# File 'lib/mkmf.rb', line 539

def with_werror(opt, opts = nil)
  if opts
    if opts[:werror] and config_string("WERRORFLAG") {|flag| opt = opt ? "#{opt} #{flag}" : flag}
      (opts = opts.dup).delete(:werror)
    end
    yield(opt, opts)
  else
    yield(opt)
  end
end

#xpopen(command, *mode, &block)

This method is for internal use only.
[ GitHub ]

  
# File 'lib/mkmf.rb', line 411

def xpopen command, *mode, &block
  Logging::open do
    case mode[0]
    when nil, /^r/
      puts "#{command} |"
    else
      puts "| #{command}"
    end
    IO.popen(libpath_env, command, *mode, &block)
  end
end

#xsystem(command, opts = nil)

This method is for internal use only.
[ GitHub ]

  
# File 'lib/mkmf.rb', line 388

def xsystem command, opts = nil
  varpat = /\$\((\w)\)|\$\{(\w)\}/
  if varpat =~ command
    vars = Hash.new {|h, k| h[k] = ENV[k]}
    command = command.dup
    nil while command.gsub!(varpat) {vars[$1||$2]}
  end
  Logging::open do
    puts command.quote
    if opts and opts[:werror]
      result = nil
      Logging.postpone do |log|
        output = IO.popen(libpath_env, command, &:read)
        result = ($?.success? and File.zero?(log.path))
        output
      end
      result
    else
      system(libpath_env, command)
    end
  end
end