generated from jweinst1/PyCExtension
-
Notifications
You must be signed in to change notification settings - Fork 1
/
check_c_compiles.py
80 lines (71 loc) · 2.76 KB
/
check_c_compiles.py
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
import distutils.ccompiler
import os
import random
import subprocess
"""
These classes allow a test to see if source code with the C compiler actually
compiles.
"""
DEFAULT_COMPILER = distutils.ccompiler.get_default_compiler()
C_EXTENSION = ".c"
def create_file_with_rand_name(source):
cur_dir = os.getcwd()
rand_file = os.path.join(cur_dir, "c_" + str(random.getrandbits(72)))
while os.path.exists(rand_file):
rand_file = os.path.join(cur_dir, "c_" + str(random.getrandbits(72)))
with open(rand_file + C_EXTENSION, "w") as c_file:
c_file.write(source)
return rand_file
class CheckCCompiles(object):
def __init__(self, name = "", source_code = ""):
self.name = name
self.source_code = source_code
self.compiler = distutils.ccompiler.new_compiler()
if DEFAULT_COMPILER == 'unix':
# The idea here is that we want to have the compiler try and generate all the possible
# simd instructions, then see by running it, if we get an illegal hardware instruction
self.extra_args = ["-m" + self.name]
elif DEFAULT_COMPILER == 'msvc':
self.extra_args = ['/arch:AVX', '/arch:AVX2', '/arch:AVX512']
else:
self.extra_args = []
self.works = False
def try_run(self):
try:
self.run_result = subprocess.run(self.file_name, check=False)
self.works = self.run_result.returncode == 0
except Exception:
self.works = False
return self.works
def __enter__(self):
self.file_name = create_file_with_rand_name(self.source_code)
self.c_name = self.file_name + C_EXTENSION
try:
self.obj_names = self.compiler.compile([self.c_name], extra_preargs=self.extra_args)
except Exception as exc:
print("FAILED " + self.name + " compile check: " + str(exc))
return self
self.compiles = True
try:
self.compiler.link_executable(self.obj_names, self.file_name)
except Exception as exc:
print("FAILED " + self.name + " link check: " + str(exc))
return self
self.links = True
if self.try_run():
print("PASSED " + self.name)
else:
print("FAILED " + self.name + " run check: " + str(self.run_result.stderr))
return self
def __exit__(self, exc_type, exc_val, exc_tb):
try:
os.remove(self.c_name)
if os.name == 'nt':
os.remove(self.file_name + ".exe")
else:
os.remove(self.file_name)
for objfile in self.obj_names:
os.remove(objfile)
except Exception as exc:
# Avoid noise for non existant files
return