aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--ChangeLog5
-rw-r--r--lib/mkmf.rb80
-rw-r--r--test/mkmf/test_convertible.rb26
3 files changed, 98 insertions, 13 deletions
diff --git a/ChangeLog b/ChangeLog
index cac81c48cb..223caf31ad 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,4 +1,7 @@
-Fri Dec 3 19:48:11 2010 Nobuyoshi Nakada <nobu@ruby-lang.org>
+Fri Dec 3 19:53:50 2010 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * lib/mkmf.rb (convertible_int): detect convertible integer type.
+ port RUBY_REPLACE_INT from configure.in.
* lib/mkmf.rb (check_sizeof): should return integer always.
diff --git a/lib/mkmf.rb b/lib/mkmf.rb
index 3e078779c7..5a12ed2acf 100644
--- a/lib/mkmf.rb
+++ b/lib/mkmf.rb
@@ -1084,6 +1084,23 @@ STRING_OR_FAILED_FORMAT = "%s"
def STRING_OR_FAILED_FORMAT.%(x)
x ? super : "failed"
end
+
+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
+
+def try_signedness(type, member, headers = nil, opts = nil, &b)
+ 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
+
# :startdoc:
# Returns the size of the given +type+. You may optionally specify additional
@@ -1097,10 +1114,8 @@ end
# SIZEOF_MYSTRUCT=12 preprocessor macro would be passed to the compiler.
#
def check_sizeof(type, headers = nil, opts = "", &b)
- typename, member = type.split('.', 2)
- prelude = cpp_include(headers).split(/$/)
- prelude << "typedef #{typename} rbcv_typedef_;\n"
- prelude << "static rbcv_typedef_ *rbcv_ptr_;\n"
+ typedef, member, prelude = typedef_expr(type, headers)
+ prelude << "static #{typedef} *rbcv_ptr_;\n"
prelude = [prelude]
expr = "sizeof((*rbcv_ptr_)#{"." << member if member})"
fmt = STRING_OR_FAILED_FORMAT
@@ -1127,22 +1142,63 @@ end
# compiler, and SIGNEDNESS_OF_INT=-1 if check_signedness('int') is
# done.
#
-def check_signedness(type, headers = nil)
+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
- if try_static_assert("(#{type})-1 < 0")
- signed = -1
- elsif try_static_assert("(#{type})-1 > 0")
- signed = +1
- else
- next nil
- end
+ signed = try_signedness(typedef, member, headers, opts, &b) or next nil
$defs.push("-DSIGNEDNESS_OF_%s=%+d" % [type.tr_cpp, signed])
signed < 0 ? "signed" : "unsigned"
end
signed
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 same type, or typedefed from same type.
+#
+# If the +type+ is a integer type and _convertible_ type is found,
+# 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 sans '_t'
+# suffix, followed by '=X' where 'X' is the macro name to convert
+# +type+ to +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
+# macros:
+#
+# #define TYPEOF_FOOBAR_T unsigned long
+# #define FOOBAR2NUM ULONG2NUM
+# #define NUM2FOOBAR NUM2ULONG
+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)
+ 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, &b)
+ }
+ if compat
+ macname ||= type.chomp("_t").tr_cpp
+ conv = (u ? "U" : "") + (compat == "long long" ? "LL" : compat.upcase)
+ compat = "#{u}#{compat}"
+ $defs.push(format("-DTYPEOF_%s=%s", type.tr_cpp, compat.quote))
+ $defs.push(format("-D%s2NUM=%s2NUM", macname, conv))
+ $defs.push(format("-DNUM2%s=NUM2%s", macname, conv))
+ compat
+ end
+ end
+ end
+end
# :stopdoc:
# Used internally by the what_type? method to determine if +type+ is a scalar
diff --git a/test/mkmf/test_convertible.rb b/test/mkmf/test_convertible.rb
new file mode 100644
index 0000000000..e8cc280eeb
--- /dev/null
+++ b/test/mkmf/test_convertible.rb
@@ -0,0 +1,26 @@
+require_relative 'base'
+
+class TestMkmf
+ class TestConvertible < TestMkmf
+ def test_typeof_builtin
+ ["", ["signed ", ""], "unsigned "].each do |signed, prefix|
+ %w[short int long].each do |type|
+ assert_equal((prefix || signed)+type,
+ mkmf {convertible_int(signed+type)})
+ end
+ end
+ end
+
+ def test_typeof_typedef
+ ["", ["signed ", ""], "unsigned "].each do |signed, prefix|
+ %w[short int long].each do |type|
+ open("confdefs.h", "w") {|f|
+ f.puts "typedef #{signed}#{type} test1_t;"
+ }
+ assert_equal((prefix || signed)+type,
+ mkmf {convertible_int("test1_t", "confdefs.h")})
+ end
+ end
+ end
+ end
+end