]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - test/libcxx/compiler.py
Import libc++ 3.7.0 release (r246257).
[FreeBSD/FreeBSD.git] / test / libcxx / compiler.py
1 import os
2 import lit.util
3 import libcxx.util
4
5
6 class CXXCompiler(object):
7     def __init__(self, path, flags=None, compile_flags=None, link_flags=None,
8                  use_ccache=False):
9         self.path = path
10         self.flags = list(flags or [])
11         self.compile_flags = list(compile_flags or [])
12         self.link_flags = list(link_flags or [])
13         self.use_ccache = use_ccache
14         self.type = None
15         self.version = None
16         self._initTypeAndVersion()
17
18     def _initTypeAndVersion(self):
19         # Get compiler type and version
20         macros = self.dumpMacros()
21         if macros is None:
22             return
23         compiler_type = None
24         major_ver = minor_ver = patchlevel = None
25         if '__clang__' in macros.keys():
26             compiler_type = 'clang'
27             # Treat apple's llvm fork differently.
28             if '__apple_build_version__' in macros.keys():
29                 compiler_type = 'apple-clang'
30             major_ver = macros['__clang_major__']
31             minor_ver = macros['__clang_minor__']
32             patchlevel = macros['__clang_patchlevel__']
33         elif '__GNUC__' in macros.keys():
34             compiler_type = 'gcc'
35             major_ver = macros['__GNUC__']
36             minor_ver = macros['__GNUC_MINOR__']
37             patchlevel = macros['__GNUC_PATCHLEVEL__']
38         self.type = compiler_type
39         self.version = (major_ver, minor_ver, patchlevel)
40
41     def _basicCmd(self, source_files, out, is_link=False, input_is_cxx=False):
42         cmd = []
43         if self.use_ccache and not is_link:
44             cmd += ['ccache']
45         cmd += [self.path]
46         if out is not None:
47             cmd += ['-o', out]
48         if input_is_cxx:
49             cmd += ['-x', 'c++']
50         if isinstance(source_files, list):
51             cmd += source_files
52         elif isinstance(source_files, str):
53             cmd += [source_files]
54         else:
55             raise TypeError('source_files must be a string or list')
56         return cmd
57
58     def preprocessCmd(self, source_files, out=None, flags=[]):
59         cmd = self._basicCmd(source_files, out, input_is_cxx=True) + ['-E']
60         cmd += self.flags + self.compile_flags + flags
61         return cmd
62
63     def compileCmd(self, source_files, out=None, flags=[]):
64         cmd = self._basicCmd(source_files, out, input_is_cxx=True) + ['-c']
65         cmd += self.flags + self.compile_flags + flags
66         return cmd
67
68     def linkCmd(self, source_files, out=None, flags=[]):
69         cmd = self._basicCmd(source_files, out, is_link=True)
70         cmd += self.flags + self.link_flags + flags
71         return cmd
72
73     def compileLinkCmd(self, source_files, out=None, flags=[]):
74         cmd = self._basicCmd(source_files, out, is_link=True)
75         cmd += self.flags + self.compile_flags + self.link_flags + flags
76         return cmd
77
78     def preprocess(self, source_files, out=None, flags=[], env=None, cwd=None):
79         cmd = self.preprocessCmd(source_files, out, flags)
80         out, err, rc = lit.util.executeCommand(cmd, env=env, cwd=cwd)
81         return cmd, out, err, rc
82
83     def compile(self, source_files, out=None, flags=[], env=None, cwd=None):
84         cmd = self.compileCmd(source_files, out, flags)
85         out, err, rc = lit.util.executeCommand(cmd, env=env, cwd=cwd)
86         return cmd, out, err, rc
87
88     def link(self, source_files, out=None, flags=[], env=None, cwd=None):
89         cmd = self.linkCmd(source_files, out, flags)
90         out, err, rc = lit.util.executeCommand(cmd, env=env, cwd=cwd)
91         return cmd, out, err, rc
92
93     def compileLink(self, source_files, out=None, flags=[], env=None,
94                     cwd=None):
95         cmd = self.compileLinkCmd(source_files, out, flags)
96         out, err, rc = lit.util.executeCommand(cmd, env=env, cwd=cwd)
97         return cmd, out, err, rc
98
99     def compileLinkTwoSteps(self, source_file, out=None, object_file=None,
100                             flags=[], env=None, cwd=None):
101         if not isinstance(source_file, str):
102             raise TypeError('This function only accepts a single input file')
103         if object_file is None:
104             # Create, use and delete a temporary object file if none is given.
105             with_fn = lambda: libcxx.util.guardedTempFilename(suffix='.o')
106         else:
107             # Otherwise wrap the filename in a context manager function.
108             with_fn = lambda: libcxx.util.nullContext(object_file)
109         with with_fn() as object_file:
110             cc_cmd, cc_stdout, cc_stderr, rc = self.compile(
111                     source_file, object_file, flags=flags, env=env, cwd=cwd)
112             if rc != 0:
113                 return cc_cmd, cc_stdout, cc_stderr, rc
114
115             link_cmd, link_stdout, link_stderr, rc = self.link(
116                     object_file, out=out, flags=flags, env=env, cwd=cwd)
117             return (cc_cmd + ['&&'] + link_cmd, cc_stdout + link_stdout,
118                     cc_stderr + link_stderr, rc)
119
120     def dumpMacros(self, source_files=None, flags=[], env=None, cwd=None):
121         if source_files is None:
122             source_files = os.devnull
123         flags = ['-dM'] + flags
124         cmd, out, err, rc = self.preprocess(source_files, flags=flags, env=env,
125                                             cwd=cwd)
126         if rc != 0:
127             return None
128         parsed_macros = {}
129         lines = [l.strip() for l in out.split('\n') if l.strip()]
130         for l in lines:
131             assert l.startswith('#define ')
132             l = l[len('#define '):]
133             macro, _, value = l.partition(' ')
134             parsed_macros[macro] = value
135         return parsed_macros
136
137     def getTriple(self):
138         cmd = [self.path] + self.flags + ['-dumpmachine']
139         return lit.util.capture(cmd).strip()
140
141     def hasCompileFlag(self, flag):
142         if isinstance(flag, list):
143             flags = list(flag)
144         else:
145             flags = [flag]
146         # Add -Werror to ensure that an unrecognized flag causes a non-zero
147         # exit code. -Werror is supported on all known compiler types.
148         if self.type is not None:
149             flags += ['-Werror']
150         cmd, out, err, rc = self.compile(os.devnull, out=os.devnull,
151                                          flags=flags)
152         return rc == 0