1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129
|
# -*- coding: utf-8 -*-
import contextlib
from distutils import ccompiler
from distutils.errors import *
import os
import sys
import types
def _has_function(self, funcname, includes=None, include_dirs=None,
libraries=None, library_dirs=None):
"""Return a boolean indicating whether funcname is supported on
the current platform. The optional arguments can be used to
augment the compilation environment.
"""
# this can't be included at module scope because it tries to
# import math which might not be available at that point - maybe
# the necessary logic should just be inlined?
import tempfile
if includes is None:
includes = []
if include_dirs is None:
include_dirs = []
if libraries is None:
libraries = []
if library_dirs is None:
library_dirs = []
fd, fname = tempfile.mkstemp(".c", funcname, text=True)
f = os.fdopen(fd, "w")
try:
for incl in includes:
f.write("""#include "%s"\n""" % incl)
f.write("""\
int main (int argc, char **argv) {
%s;
return 0;
}
""" % funcname)
finally:
f.close()
try:
objects = self.compile([fname], include_dirs=include_dirs)
except CompileError:
return False
finally:
os.remove(fname)
try:
self.link_executable(objects, "a.out",
libraries=libraries,
library_dirs=library_dirs)
except (LinkError, TypeError):
return False
else:
os.remove("a.out")
finally:
for fn in objects:
os.remove(fn)
return True
@contextlib.contextmanager
def stdchannel_redirected(stdchannel, dest_filename):
"""
A context manager to temporarily redirect stdout or stderr
e.g.:
with stdchannel_redirected(sys.stderr, os.devnull):
...
"""
try:
oldstdchannel = os.dup(stdchannel.fileno())
dest_file = open(dest_filename, 'w')
os.dup2(dest_file.fileno(), stdchannel.fileno())
yield
finally:
if oldstdchannel is not None:
os.dup2(oldstdchannel, stdchannel.fileno())
if dest_file is not None:
dest_file.close()
def has_function(*args, **kw):
with stdchannel_redirected(sys.stderr, os.devnull):
return _has_function(*args, **kw)
def new_compiler():
compiler = ccompiler.new_compiler()
compiler.has_function = types.MethodType(has_function, compiler)
return compiler
def find_compiler():
from subprocess import run, STDOUT, PIPE
for cc in ['cc', 'gcc']:
x = run("which %s" % cc, stdout=PIPE, stderr=STDOUT, shell=True)
if x.returncode == 0:
return True
return False
def check_clock_gettime(libraries):
"""
check for clock_gettime, link with librt for glibc<2.17
"""
compiler = new_compiler()
try:
if not compiler.has_function('clock_gettime(0,NULL)', includes=['time.h']):
if compiler.has_function('clock_gettime(0,NULL)', includes=['time.h'], libraries=['rt']):
libraries.append('rt')
else:
if find_compiler():
print("setup.py: could not locate 'clock_gettime' function required by FreeTDS.", file=sys.stderr)
else:
print("setup.py: ERROR: Could not find C compiler", file=sys.stderr)
sys.exit(1)
except Exception as exc:
print(f"setup.py: ERROR: {exc}", file=sys.stderr)
sys.exit(1)
|