summaryrefslogtreecommitdiff
path: root/numpy/core/setup_common.py
diff options
context:
space:
mode:
authorDavid Cournapeau <cournape@gmail.com>2009-11-06 07:29:41 +0000
committerDavid Cournapeau <cournape@gmail.com>2009-11-06 07:29:41 +0000
commit5da4c5e945d860bc39be6d90ecd144f740ca3a56 (patch)
tree49c826786298e5f79cd543841b20400f75d7abff /numpy/core/setup_common.py
parenta5ebfbbea01dafe360578c5c22da9a84c8f1319e (diff)
downloadnumpy-5da4c5e945d860bc39be6d90ecd144f740ca3a56.tar.gz
ENH: add a check to get long double representation in distutils build.
Diffstat (limited to 'numpy/core/setup_common.py')
-rw-r--r--numpy/core/setup_common.py125
1 files changed, 125 insertions, 0 deletions
diff --git a/numpy/core/setup_common.py b/numpy/core/setup_common.py
index d42705fff..72c18265b 100644
--- a/numpy/core/setup_common.py
+++ b/numpy/core/setup_common.py
@@ -2,6 +2,10 @@
import sys
from os.path import join
import warnings
+import copy
+import binascii
+
+from distutils.ccompiler import CompileError
#-------------------
# Versioning support
@@ -120,3 +124,124 @@ def sym2def(symbol):
def type2def(symbol):
define = symbol.replace(' ', '_')
return define.upper()
+
+# Code to detect long double representation taken from MPFR m4 macro
+def check_long_double_representation(cmd):
+ cmd._check_compiler()
+ body = LONG_DOUBLE_REPRESENTATION_SRC % {'type': 'long double'}
+
+ # We need to use _compile because we need the object filename
+ src, object = cmd._compile(body, None, None, 'c')
+ try:
+ type = long_double_representation(pyod(object))
+ return type
+ finally:
+ cmd._clean()
+
+LONG_DOUBLE_REPRESENTATION_SRC = r"""
+/* "before" is 16 bytes to ensure there's no padding between it and "x".
+ * We're not expecting any "long double" bigger than 16 bytes or with
+ * alignment requirements stricter than 16 bytes. */
+typedef %(type)s test_type;
+
+struct {
+ char before[16];
+ test_type x;
+ char after[8];
+} foo = {
+ { '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0',
+ '\001', '\043', '\105', '\147', '\211', '\253', '\315', '\357' },
+ -123456789.0,
+ { '\376', '\334', '\272', '\230', '\166', '\124', '\062', '\020' }
+};
+"""
+
+def pyod(filename):
+ """Python implementation of the od UNIX utility (od -b, more exactly).
+
+ Parameters
+ ----------
+ filename: str
+ name of the file to get the dump from.
+
+ Returns
+ -------
+ out: seq
+ list of lines of od output
+ Note
+ ----
+ We only implement enough to get the necessary information for long double
+ representation, this is not intended as a compatible replacement for od.
+ """
+ out = []
+
+ fid = open(filename, 'r')
+ try:
+ yo = [int(oct(int(binascii.b2a_hex(o), 16))) for o in fid.read()]
+ for i in range(0, len(yo), 16):
+ line = ['%07d' % int(oct(i))]
+ line.extend(['%03d' % c for c in yo[i:i+16]])
+ out.append(" ".join(line))
+ return out
+ finally:
+ fid.close()
+
+_BEFORE_SEQ = ['000','000','000','000','000','000','000','000',
+ '001','043','105','147','211','253','315','357']
+_AFTER_SEQ = ['376', '334','272','230','166','124','062','020']
+
+_IEEE_DOUBLE_BE = ['301', '235', '157', '064', '124', '000', '000', '000']
+_IEEE_DOUBLE_LE = _IEEE_DOUBLE_BE[::-1]
+_INTEL_EXTENDED_12B = ['000', '000', '000', '000', '240', '242', '171', '353',
+ '031', '300', '000', '000']
+_INTEL_EXTENDED_16B = ['000', '000', '000', '000', '240', '242', '171', '353',
+ '031', '300', '000', '000', '000', '000', '000', '000']
+_IEEE_QUAD_PREC_BE = ['300', '031', '326', '363', '105', '100', '000', '000',
+ '000', '000', '000', '000', '000', '000', '000', '000']
+_IEEE_QUAD_PREC_LE = _IEEE_QUAD_PREC_BE[::-1]
+
+def long_double_representation(lines):
+ """Given a binary dump as given by GNU od -b, look for long double
+ representation."""
+
+ # Read contains a list of 32 items, each item is a byte (in octal
+ # representation, as a string). We 'slide' over the output until read is of
+ # the form before_seq + content + after_sequence, where content is the long double
+ # representation:
+ # - content is 12 bytes: 80 bits Intel representation
+ # - content is 16 bytes: 80 bits Intel representation (64 bits) or quad precision
+ # - content is 8 bytes: same as double (not implemented yet)
+ read = [''] * 32
+ saw = None
+ for line in lines:
+ # we skip the first word, as od -b output an index at the beginning of
+ # each line
+ for w in line.split()[1:]:
+ read.pop(0)
+ read.append(w)
+
+ # If the end of read is equal to the after_sequence, read contains
+ # the long double
+ if read[-8:] == _AFTER_SEQ:
+ saw = copy.copy(read)
+ if read[:12] == _BEFORE_SEQ[4:]:
+ if read[12:-8] == _INTEL_EXTENDED_12B:
+ return 'INTEL_EXTENDED_12B_LE'
+ elif read[:8] == _BEFORE_SEQ[8:]:
+ if read[8:-8] == _INTEL_EXTENDED_16B:
+ return 'INTEL_EXTENDED_16B_LE'
+ elif read[8:-8] == _IEEE_QUAD_PREC_BE:
+ return 'IEEE_QUAD_16B_BE'
+ elif read[8:-8] == _IEEE_QUAD_PREC_LE:
+ return 'IEEE_QUAD_16B_LE'
+ elif read[:16] == _BEFORE_SEQ:
+ if read[16:-8] == _IEEE_DOUBLE_LE:
+ return 'IEEE_DOUBLE_LE'
+ elif read[16:-8] == _IEEE_DOUBLE_BE:
+ return 'IEEE_DOUBLE_BE'
+
+ if saw is not None:
+ raise ValueError("Unrecognized format (%s)" % saw)
+ else:
+ # We never detected the after_sequence
+ raise ValueError("Could not lock sequences (%s)" % saw)