blob: e267e9ffde2dea25d2718412082bb8421535d2d5 [file] [log] [blame]
Tarek Ziade1231a4e2011-05-19 13:07:25 +02001"""Compiler abstraction model used by packaging.
2
3An abstract base class is defined in the ccompiler submodule, and
4concrete implementations suitable for various platforms are defined in
5the other submodules. The extension module is also placed in this
6package.
7
8In general, code should not instantiate compiler classes directly but
9use the new_compiler and customize_compiler functions provided in this
10module.
11
12The compiler system has a registration API: get_default_compiler,
13set_compiler, show_compilers.
14"""
15
16import os
17import sys
18import re
Tarek Ziade1231a4e2011-05-19 13:07:25 +020019import sysconfig
Tarek Ziade2bc55e42011-05-22 21:21:44 +020020
Tarek Ziade1231a4e2011-05-19 13:07:25 +020021from packaging.util import resolve_name
22from packaging.errors import PackagingPlatformError
Tarek Ziade2bc55e42011-05-22 21:21:44 +020023from packaging import logger
Tarek Ziade1231a4e2011-05-19 13:07:25 +020024
25def customize_compiler(compiler):
26 """Do any platform-specific customization of a CCompiler instance.
27
28 Mainly needed on Unix, so we can plug in the information that
29 varies across Unices and is stored in Python's Makefile.
30 """
31 if compiler.name == "unix":
32 cc, cxx, opt, cflags, ccshared, ldshared, so_ext, ar, ar_flags = (
33 sysconfig.get_config_vars('CC', 'CXX', 'OPT', 'CFLAGS',
34 'CCSHARED', 'LDSHARED', 'SO', 'AR',
35 'ARFLAGS'))
36
37 if 'CC' in os.environ:
38 cc = os.environ['CC']
39 if 'CXX' in os.environ:
40 cxx = os.environ['CXX']
41 if 'LDSHARED' in os.environ:
42 ldshared = os.environ['LDSHARED']
43 if 'CPP' in os.environ:
44 cpp = os.environ['CPP']
45 else:
46 cpp = cc + " -E" # not always
47 if 'LDFLAGS' in os.environ:
48 ldshared = ldshared + ' ' + os.environ['LDFLAGS']
49 if 'CFLAGS' in os.environ:
50 cflags = opt + ' ' + os.environ['CFLAGS']
51 ldshared = ldshared + ' ' + os.environ['CFLAGS']
52 if 'CPPFLAGS' in os.environ:
53 cpp = cpp + ' ' + os.environ['CPPFLAGS']
54 cflags = cflags + ' ' + os.environ['CPPFLAGS']
55 ldshared = ldshared + ' ' + os.environ['CPPFLAGS']
56 if 'AR' in os.environ:
57 ar = os.environ['AR']
58 if 'ARFLAGS' in os.environ:
59 archiver = ar + ' ' + os.environ['ARFLAGS']
60 else:
61 if ar_flags is not None:
62 archiver = ar + ' ' + ar_flags
63 else:
64 # see if its the proper default value
65 # mmm I don't want to backport the makefile
66 archiver = ar + ' rc'
67
68 cc_cmd = cc + ' ' + cflags
69 compiler.set_executables(
70 preprocessor=cpp,
71 compiler=cc_cmd,
72 compiler_so=cc_cmd + ' ' + ccshared,
73 compiler_cxx=cxx,
74 linker_so=ldshared,
75 linker_exe=cc,
76 archiver=archiver)
77
78 compiler.shared_lib_extension = so_ext
79
80
81# Map a sys.platform/os.name ('posix', 'nt') to the default compiler
82# type for that platform. Keys are interpreted as re match
83# patterns. Order is important; platform mappings are preferred over
84# OS names.
85_default_compilers = (
Tarek Ziade1231a4e2011-05-19 13:07:25 +020086 # Platform string mappings
87
88 # on a cygwin built python we can use gcc like an ordinary UNIXish
89 # compiler
90 ('cygwin.*', 'unix'),
Tarek Ziade1231a4e2011-05-19 13:07:25 +020091
92 # OS name mappings
93 ('posix', 'unix'),
94 ('nt', 'msvc'),
Éric Araujo25987d02011-06-01 15:20:44 +020095)
Tarek Ziade1231a4e2011-05-19 13:07:25 +020096
97def get_default_compiler(osname=None, platform=None):
98 """ Determine the default compiler to use for the given platform.
99
100 osname should be one of the standard Python OS names (i.e. the
101 ones returned by os.name) and platform the common value
102 returned by sys.platform for the platform in question.
103
104 The default values are os.name and sys.platform in case the
105 parameters are not given.
106
107 """
108 if osname is None:
109 osname = os.name
110 if platform is None:
111 platform = sys.platform
112 for pattern, compiler in _default_compilers:
113 if re.match(pattern, platform) is not None or \
114 re.match(pattern, osname) is not None:
115 return compiler
116 # Defaults to Unix compiler
117 return 'unix'
118
119
120# compiler mapping
121# XXX useful to expose them? (i.e. get_compiler_names)
122_COMPILERS = {
123 'unix': 'packaging.compiler.unixccompiler.UnixCCompiler',
124 'msvc': 'packaging.compiler.msvccompiler.MSVCCompiler',
125 'cygwin': 'packaging.compiler.cygwinccompiler.CygwinCCompiler',
126 'mingw32': 'packaging.compiler.cygwinccompiler.Mingw32CCompiler',
127 'bcpp': 'packaging.compiler.bcppcompiler.BCPPCompiler',
128}
129
130def set_compiler(location):
131 """Add or change a compiler"""
132 cls = resolve_name(location)
133 # XXX we want to check the class here
134 _COMPILERS[cls.name] = cls
135
136
137def show_compilers():
138 """Print list of available compilers (used by the "--help-compiler"
139 options to "build", "build_ext", "build_clib").
140 """
141 from packaging.fancy_getopt import FancyGetopt
142 compilers = []
143
144 for name, cls in _COMPILERS.items():
145 if isinstance(cls, str):
146 cls = resolve_name(cls)
147 _COMPILERS[name] = cls
148
149 compilers.append(("compiler=" + name, None, cls.description))
150
151 compilers.sort()
152 pretty_printer = FancyGetopt(compilers)
153 pretty_printer.print_help("List of available compilers:")
154
155
156def new_compiler(plat=None, compiler=None, verbose=0, dry_run=False,
157 force=False):
158 """Generate an instance of some CCompiler subclass for the supplied
159 platform/compiler combination. 'plat' defaults to 'os.name'
160 (eg. 'posix', 'nt'), and 'compiler' defaults to the default compiler
161 for that platform. Currently only 'posix' and 'nt' are supported, and
162 the default compilers are "traditional Unix interface" (UnixCCompiler
163 class) and Visual C++ (MSVCCompiler class). Note that it's perfectly
164 possible to ask for a Unix compiler object under Windows, and a
165 Microsoft compiler object under Unix -- if you supply a value for
166 'compiler', 'plat' is ignored.
167 """
168 if plat is None:
169 plat = os.name
170
171 try:
172 if compiler is None:
173 compiler = get_default_compiler(plat)
174
175 cls = _COMPILERS[compiler]
176 except KeyError:
177 msg = "don't know how to compile C/C++ code on platform '%s'" % plat
178 if compiler is not None:
179 msg = msg + " with '%s' compiler" % compiler
180 raise PackagingPlatformError(msg)
181
182 if isinstance(cls, str):
183 cls = resolve_name(cls)
184 _COMPILERS[compiler] = cls
185
186
187 # XXX The None is necessary to preserve backwards compatibility
188 # with classes that expect verbose to be the first positional
189 # argument.
190 return cls(None, dry_run, force)
191
192
193def gen_preprocess_options(macros, include_dirs):
194 """Generate C pre-processor options (-D, -U, -I) as used by at least
195 two types of compilers: the typical Unix compiler and Visual C++.
196 'macros' is the usual thing, a list of 1- or 2-tuples, where (name,)
197 means undefine (-U) macro 'name', and (name,value) means define (-D)
198 macro 'name' to 'value'. 'include_dirs' is just a list of directory
199 names to be added to the header file search path (-I). Returns a list
200 of command-line options suitable for either Unix compilers or Visual
201 C++.
202 """
203 # XXX it would be nice (mainly aesthetic, and so we don't generate
204 # stupid-looking command lines) to go over 'macros' and eliminate
205 # redundant definitions/undefinitions (ie. ensure that only the
206 # latest mention of a particular macro winds up on the command
207 # line). I don't think it's essential, though, since most (all?)
208 # Unix C compilers only pay attention to the latest -D or -U
209 # mention of a macro on their command line. Similar situation for
210 # 'include_dirs'. I'm punting on both for now. Anyways, weeding out
211 # redundancies like this should probably be the province of
212 # CCompiler, since the data structures used are inherited from it
213 # and therefore common to all CCompiler classes.
214
215 pp_opts = []
216 for macro in macros:
217
218 if not isinstance(macro, tuple) and 1 <= len(macro) <= 2:
219 raise TypeError(
220 "bad macro definition '%s': each element of 'macros'"
221 "list must be a 1- or 2-tuple" % macro)
222
223 if len(macro) == 1: # undefine this macro
224 pp_opts.append("-U%s" % macro[0])
225 elif len(macro) == 2:
226 if macro[1] is None: # define with no explicit value
227 pp_opts.append("-D%s" % macro[0])
228 else:
229 # XXX *don't* need to be clever about quoting the
230 # macro value here, because we're going to avoid the
231 # shell at all costs when we spawn the command!
232 pp_opts.append("-D%s=%s" % macro)
233
234 for dir in include_dirs:
235 pp_opts.append("-I%s" % dir)
236
237 return pp_opts
238
239
240def gen_lib_options(compiler, library_dirs, runtime_library_dirs, libraries):
241 """Generate linker options for searching library directories and
242 linking with specific libraries.
243
244 'libraries' and 'library_dirs' are, respectively, lists of library names
245 (not filenames!) and search directories. Returns a list of command-line
246 options suitable for use with some compiler (depending on the two format
247 strings passed in).
248 """
249 lib_opts = []
250
251 for dir in library_dirs:
252 lib_opts.append(compiler.library_dir_option(dir))
253
254 for dir in runtime_library_dirs:
255 opt = compiler.runtime_library_dir_option(dir)
256 if isinstance(opt, list):
257 lib_opts.extend(opt)
258 else:
259 lib_opts.append(opt)
260
261 # XXX it's important that we *not* remove redundant library mentions!
262 # sometimes you really do have to say "-lfoo -lbar -lfoo" in order to
263 # resolve all symbols. I just hope we never have to say "-lfoo obj.o
264 # -lbar" to get things to work -- that's certainly a possibility, but a
265 # pretty nasty way to arrange your C code.
266
267 for lib in libraries:
268 lib_dir, lib_name = os.path.split(lib)
269 if lib_dir != '':
270 lib_file = compiler.find_library_file([lib_dir], lib_name)
271 if lib_file is not None:
272 lib_opts.append(lib_file)
273 else:
Tarek Ziade2bc55e42011-05-22 21:21:44 +0200274 logger.warning("no library file corresponding to "
Tarek Ziade1231a4e2011-05-19 13:07:25 +0200275 "'%s' found (skipping)" % lib)
276 else:
277 lib_opts.append(compiler.library_option(lib))
278
279 return lib_opts