diff options
author | David Cournapeau <cournape@gmail.com> | 2009-11-06 07:29:41 +0000 |
---|---|---|
committer | David Cournapeau <cournape@gmail.com> | 2009-11-06 07:29:41 +0000 |
commit | 5da4c5e945d860bc39be6d90ecd144f740ca3a56 (patch) | |
tree | 49c826786298e5f79cd543841b20400f75d7abff /numpy/core/setup_common.py | |
parent | a5ebfbbea01dafe360578c5c22da9a84c8f1319e (diff) | |
download | numpy-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.py | 125 |
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) |