module MakeMakefile
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.
Constants
- ASSEMBLE_C
Command which will translate C files to assembler sources in the generated Makefile
- ASSEMBLE_CXX
Command which will translate C++ files to assembler sources in the generated Makefile
- CLEANINGS
Makefile rules that will clean the extension build directory
- COMMON_HEADERS
Common headers for Ruby C extensions
- COMMON_LIBS
Common libraries for Ruby C extensions
- COMPILE_C
Command which will compile C files in the generated Makefile
- COMPILE_CXX
Command which will compile C++ files in the generated Makefile
- COMPILE_RULES
make compile rules
- CONFIG
The makefile configuration using the defaults from when Ruby was built.
- CXX_EXT
Extensions for files complied with a C++ compiler
- C_EXT
Extensions for files compiled with a C compiler
- EXPORT_PREFIX
- HDR_EXT
Extensions for header files
- LIBARG
Argument which will add a library to the linker
- LIBPATHFLAG
Argument which will add a library path to the linker
- LINK_SO
Command which will link a shared library
- MAIN_DOES_NOTHING
A C main function which does no work
- ORIG_LIBPATH
- RPATHFLAG
- RULE_SUBST
- SRC_EXT
Extensions for source files
- TRY_LINK
Command which will compile a program in order to test linking a library
- UNIVERSAL_INTS
Public Instance Methods
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
preprocessor macro would be passed to
the compiler. The SIGNEDNESS_OF_INT=-1
macro would be set for
check_signedness('int')
# File lib/mkmf.rb, line 1360 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
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.
# File lib/mkmf.rb, line 1331 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
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 thetype
name, followed by=X
where “X” is the found convertible type name. -
TYP2NUM
andNUM2TYP
, whereTYP
is thetype
name in uppercase with replacing an_t
suffix with “T”, followed by=X
where “X” is the macro name to converttype
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
# File lib/mkmf.rb, line 1395 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
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.
# File lib/mkmf.rb, line 1687 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
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
.
# File lib/mkmf.rb, line 2186 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.sub(/\A\.\//, ''))}) $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+)(\))/) {$1+sep+$2} s.gsub(/(\$\{\w+)(\})/) {$1+sep+$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
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.
# File lib/mkmf.rb, line 2070 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) line.gsub!(%r"\$\(hdrdir\)/(?!ruby(?![^:;/\s]))(?=[-\w]+\.h)", '\&ruby/') 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
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.
# File lib/mkmf.rb, line 1737 def dir_config(target, idefault=nil, ldefault=nil) 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 [idir, ldir] end
creates a stub Makefile.
# File lib/mkmf.rb, line 2039 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
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
# File lib/mkmf.rb, line 1649 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
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.
# File lib/mkmf.rb, line 1579 def find_executable(bin, path = nil) checking_for checking_message(bin, path) do find_executable0(bin, path) end end
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).
# File lib/mkmf.rb, line 1145 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
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.
# File lib/mkmf.rb, line 1021 def find_library(lib, func, *paths, &b) 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
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
.
# File lib/mkmf.rb, line 1242 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
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.
# File lib/mkmf.rb, line 1290 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
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.
# File lib/mkmf.rb, line 1116 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
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.
# File lib/mkmf.rb, line 1054 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
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.
# File lib/mkmf.rb, line 1094 def have_header(header, preheaders = nil, opt = "", &b) 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
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.
# File lib/mkmf.rb, line 996 def have_library(lib, func = nil, headers = nil, opt = "", &b) 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
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.
# File lib/mkmf.rb, line 979 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
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.
# File lib/mkmf.rb, line 1181 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
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.
# File lib/mkmf.rb, line 1229 def have_type(type, headers = nil, opt = "", &b) checking_for checking_message(type, headers, opt) do try_type(type, headers, opt, &b) end end
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.
# File lib/mkmf.rb, line 1076 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
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:
-
If
--with-{pkg}-config={command}
is given via command line option:{command} {option}
-
{pkg}-config {option}
-
pkg-config {option} {pkg}
Where {option} is, for instance, --cflags
.
The values obtained are appended to +$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.
# File lib/mkmf.rb, line 1790 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 "cflags: %s\nldflags: %s\nlibs: %s\n\n", cflags, ldflags, libs [cflags, ldflags, libs] else Logging::message "package configuration for %s is not found\n", pkg nil end end
Returns whether or not the constant const
is defined.
See also have_const
# File lib/mkmf.rb, line 1259 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
Returns whether or not the static type type
is defined.
See also have_type
# File lib/mkmf.rb, line 1202 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
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
# File lib/mkmf.rb, line 1614 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