ยปCore Development>Code coverage>Lib/packaging/compiler/bcppcompiler.py

Python code coverage for Lib/packaging/compiler/bcppcompiler.py

#countcontent
1n/a"""CCompiler implementation for the Borland C++ compiler."""
2n/a
3n/a# This implementation by Lyle Johnson, based on the original msvccompiler.py
4n/a# module and using the directions originally published by Gordon Williams.
5n/a
6n/a# XXX looks like there's a LOT of overlap between these two classes:
7n/a# someone should sit down and factor out the common code as
8n/a# WindowsCCompiler! --GPW
9n/a
10n/aimport os
11n/a
12n/afrom packaging.errors import (PackagingExecError, CompileError, LibError,
13n/a LinkError, UnknownFileError)
14n/afrom packaging.compiler.ccompiler import CCompiler
15n/afrom packaging.compiler import gen_preprocess_options
16n/afrom packaging.file_util import write_file
17n/afrom packaging.dep_util import newer
18n/afrom packaging import logger
19n/a
20n/a
21n/aclass BCPPCompiler(CCompiler) :
22n/a """Concrete class that implements an interface to the Borland C/C++
23n/a compiler, as defined by the CCompiler abstract class.
24n/a """
25n/a
26n/a name = 'bcpp'
27n/a description = 'Borland C++ Compiler'
28n/a
29n/a # Just set this so CCompiler's constructor doesn't barf. We currently
30n/a # don't use the 'set_executables()' bureaucracy provided by CCompiler,
31n/a # as it really isn't necessary for this sort of single-compiler class.
32n/a # Would be nice to have a consistent interface with UnixCCompiler,
33n/a # though, so it's worth thinking about.
34n/a executables = {}
35n/a
36n/a # Private class data (need to distinguish C from C++ source for compiler)
37n/a _c_extensions = ['.c']
38n/a _cpp_extensions = ['.cc', '.cpp', '.cxx']
39n/a
40n/a # Needed for the filename generation methods provided by the
41n/a # base class, CCompiler.
42n/a src_extensions = _c_extensions + _cpp_extensions
43n/a obj_extension = '.obj'
44n/a static_lib_extension = '.lib'
45n/a shared_lib_extension = '.dll'
46n/a static_lib_format = shared_lib_format = '%s%s'
47n/a exe_extension = '.exe'
48n/a
49n/a
50n/a def __init__(self, dry_run=False, force=False):
51n/a super(BCPPCompiler, self).__init__(dry_run, force)
52n/a
53n/a # These executables are assumed to all be in the path.
54n/a # Borland doesn't seem to use any special registry settings to
55n/a # indicate their installation locations.
56n/a
57n/a self.cc = "bcc32.exe"
58n/a self.linker = "ilink32.exe"
59n/a self.lib = "tlib.exe"
60n/a
61n/a self.preprocess_options = None
62n/a self.compile_options = ['/tWM', '/O2', '/q', '/g0']
63n/a self.compile_options_debug = ['/tWM', '/Od', '/q', '/g0']
64n/a
65n/a self.ldflags_shared = ['/Tpd', '/Gn', '/q', '/x']
66n/a self.ldflags_shared_debug = ['/Tpd', '/Gn', '/q', '/x']
67n/a self.ldflags_static = []
68n/a self.ldflags_exe = ['/Gn', '/q', '/x']
69n/a self.ldflags_exe_debug = ['/Gn', '/q', '/x','/r']
70n/a
71n/a
72n/a # -- Worker methods ------------------------------------------------
73n/a
74n/a def compile(self, sources,
75n/a output_dir=None, macros=None, include_dirs=None, debug=False,
76n/a extra_preargs=None, extra_postargs=None, depends=None):
77n/a
78n/a macros, objects, extra_postargs, pp_opts, build = \
79n/a self._setup_compile(output_dir, macros, include_dirs, sources,
80n/a depends, extra_postargs)
81n/a compile_opts = extra_preargs or []
82n/a compile_opts.append('-c')
83n/a if debug:
84n/a compile_opts.extend(self.compile_options_debug)
85n/a else:
86n/a compile_opts.extend(self.compile_options)
87n/a
88n/a for obj in objects:
89n/a try:
90n/a src, ext = build[obj]
91n/a except KeyError:
92n/a continue
93n/a # XXX why do the normpath here?
94n/a src = os.path.normpath(src)
95n/a obj = os.path.normpath(obj)
96n/a # XXX _setup_compile() did a mkpath() too but before the normpath.
97n/a # Is it possible to skip the normpath?
98n/a self.mkpath(os.path.dirname(obj))
99n/a
100n/a if ext == '.res':
101n/a # This is already a binary file -- skip it.
102n/a continue # the 'for' loop
103n/a if ext == '.rc':
104n/a # This needs to be compiled to a .res file -- do it now.
105n/a try:
106n/a self.spawn(["brcc32", "-fo", obj, src])
107n/a except PackagingExecError as msg:
108n/a raise CompileError(msg)
109n/a continue # the 'for' loop
110n/a
111n/a # The next two are both for the real compiler.
112n/a if ext in self._c_extensions:
113n/a input_opt = ""
114n/a elif ext in self._cpp_extensions:
115n/a input_opt = "-P"
116n/a else:
117n/a # Unknown file type -- no extra options. The compiler
118n/a # will probably fail, but let it just in case this is a
119n/a # file the compiler recognizes even if we don't.
120n/a input_opt = ""
121n/a
122n/a output_opt = "-o" + obj
123n/a
124n/a # Compiler command line syntax is: "bcc32 [options] file(s)".
125n/a # Note that the source file names must appear at the end of
126n/a # the command line.
127n/a try:
128n/a self.spawn([self.cc] + compile_opts + pp_opts +
129n/a [input_opt, output_opt] +
130n/a extra_postargs + [src])
131n/a except PackagingExecError as msg:
132n/a raise CompileError(msg)
133n/a
134n/a return objects
135n/a
136n/a
137n/a def create_static_lib(self, objects, output_libname, output_dir=None,
138n/a debug=False, target_lang=None):
139n/a objects, output_dir = self._fix_object_args(objects, output_dir)
140n/a output_filename = \
141n/a self.library_filename(output_libname, output_dir=output_dir)
142n/a
143n/a if self._need_link(objects, output_filename):
144n/a lib_args = [output_filename, '/u'] + objects
145n/a if debug:
146n/a pass # XXX what goes here?
147n/a try:
148n/a self.spawn([self.lib] + lib_args)
149n/a except PackagingExecError as msg:
150n/a raise LibError(msg)
151n/a else:
152n/a logger.debug("skipping %s (up-to-date)", output_filename)
153n/a
154n/a
155n/a def link(self, target_desc, objects, output_filename, output_dir=None,
156n/a libraries=None, library_dirs=None, runtime_library_dirs=None,
157n/a export_symbols=None, debug=False, extra_preargs=None,
158n/a extra_postargs=None, build_temp=None, target_lang=None):
159n/a
160n/a # XXX this ignores 'build_temp'! should follow the lead of
161n/a # msvccompiler.py
162n/a
163n/a objects, output_dir = self._fix_object_args(objects, output_dir)
164n/a libraries, library_dirs, runtime_library_dirs = \
165n/a self._fix_lib_args(libraries, library_dirs, runtime_library_dirs)
166n/a
167n/a if runtime_library_dirs:
168n/a logger.warning("don't know what to do with "
169n/a "'runtime_library_dirs': %r", runtime_library_dirs)
170n/a
171n/a if output_dir is not None:
172n/a output_filename = os.path.join(output_dir, output_filename)
173n/a
174n/a if self._need_link(objects, output_filename):
175n/a
176n/a # Figure out linker args based on type of target.
177n/a if target_desc == CCompiler.EXECUTABLE:
178n/a startup_obj = 'c0w32'
179n/a if debug:
180n/a ld_args = self.ldflags_exe_debug[:]
181n/a else:
182n/a ld_args = self.ldflags_exe[:]
183n/a else:
184n/a startup_obj = 'c0d32'
185n/a if debug:
186n/a ld_args = self.ldflags_shared_debug[:]
187n/a else:
188n/a ld_args = self.ldflags_shared[:]
189n/a
190n/a
191n/a # Create a temporary exports file for use by the linker
192n/a if export_symbols is None:
193n/a def_file = ''
194n/a else:
195n/a head, tail = os.path.split(output_filename)
196n/a modname, ext = os.path.splitext(tail)
197n/a temp_dir = os.path.dirname(objects[0]) # preserve tree structure
198n/a def_file = os.path.join(temp_dir, '%s.def' % modname)
199n/a contents = ['EXPORTS']
200n/a for sym in (export_symbols or []):
201n/a contents.append(' %s=_%s' % (sym, sym))
202n/a self.execute(write_file, (def_file, contents),
203n/a "writing %s" % def_file)
204n/a
205n/a # Borland C++ has problems with '/' in paths
206n/a objects2 = [os.path.normpath(o) for o in objects]
207n/a # split objects in .obj and .res files
208n/a # Borland C++ needs them at different positions in the command line
209n/a objects = [startup_obj]
210n/a resources = []
211n/a for file in objects2:
212n/a base, ext = os.path.splitext(os.path.normcase(file))
213n/a if ext == '.res':
214n/a resources.append(file)
215n/a else:
216n/a objects.append(file)
217n/a
218n/a
219n/a for l in library_dirs:
220n/a ld_args.append("/L%s" % os.path.normpath(l))
221n/a ld_args.append("/L.") # we sometimes use relative paths
222n/a
223n/a # list of object files
224n/a ld_args.extend(objects)
225n/a
226n/a # XXX the command line syntax for Borland C++ is a bit wonky;
227n/a # certain filenames are jammed together in one big string, but
228n/a # comma-delimited. This doesn't mesh too well with the
229n/a # Unix-centric attitude (with a DOS/Windows quoting hack) of
230n/a # 'spawn()', so constructing the argument list is a bit
231n/a # awkward. Note that doing the obvious thing and jamming all
232n/a # the filenames and commas into one argument would be wrong,
233n/a # because 'spawn()' would quote any filenames with spaces in
234n/a # them. Arghghh!. Apparently it works fine as coded...
235n/a
236n/a # name of dll/exe file
237n/a ld_args.extend((',',output_filename))
238n/a # no map file and start libraries
239n/a ld_args.append(',,')
240n/a
241n/a for lib in libraries:
242n/a # see if we find it and if there is a bcpp specific lib
243n/a # (xxx_bcpp.lib)
244n/a libfile = self.find_library_file(library_dirs, lib, debug)
245n/a if libfile is None:
246n/a ld_args.append(lib)
247n/a # probably a BCPP internal library -- don't warn
248n/a else:
249n/a # full name which prefers bcpp_xxx.lib over xxx.lib
250n/a ld_args.append(libfile)
251n/a
252n/a # some default libraries
253n/a ld_args.append('import32')
254n/a ld_args.append('cw32mt')
255n/a
256n/a # def file for export symbols
257n/a ld_args.extend((',',def_file))
258n/a # add resource files
259n/a ld_args.append(',')
260n/a ld_args.extend(resources)
261n/a
262n/a
263n/a if extra_preargs:
264n/a ld_args[:0] = extra_preargs
265n/a if extra_postargs:
266n/a ld_args.extend(extra_postargs)
267n/a
268n/a self.mkpath(os.path.dirname(output_filename))
269n/a try:
270n/a self.spawn([self.linker] + ld_args)
271n/a except PackagingExecError as msg:
272n/a raise LinkError(msg)
273n/a
274n/a else:
275n/a logger.debug("skipping %s (up-to-date)", output_filename)
276n/a
277n/a # -- Miscellaneous methods -----------------------------------------
278n/a
279n/a
280n/a def find_library_file(self, dirs, lib, debug=False):
281n/a # List of effective library names to try, in order of preference:
282n/a # xxx_bcpp.lib is better than xxx.lib
283n/a # and xxx_d.lib is better than xxx.lib if debug is set
284n/a #
285n/a # The "_bcpp" suffix is to handle a Python installation for people
286n/a # with multiple compilers (primarily Packaging hackers, I suspect
287n/a # ;-). The idea is they'd have one static library for each
288n/a # compiler they care about, since (almost?) every Windows compiler
289n/a # seems to have a different format for static libraries.
290n/a if debug:
291n/a dlib = (lib + "_d")
292n/a try_names = (dlib + "_bcpp", lib + "_bcpp", dlib, lib)
293n/a else:
294n/a try_names = (lib + "_bcpp", lib)
295n/a
296n/a for dir in dirs:
297n/a for name in try_names:
298n/a libfile = os.path.join(dir, self.library_filename(name))
299n/a if os.path.exists(libfile):
300n/a return libfile
301n/a else:
302n/a # Oops, didn't find it in *any* of 'dirs'
303n/a return None
304n/a
305n/a # overwrite the one from CCompiler to support rc and res-files
306n/a def object_filenames(self, source_filenames, strip_dir=False,
307n/a output_dir=''):
308n/a if output_dir is None:
309n/a output_dir = ''
310n/a obj_names = []
311n/a for src_name in source_filenames:
312n/a # use normcase to make sure '.rc' is really '.rc' and not '.RC'
313n/a base, ext = os.path.splitext(os.path.normcase(src_name))
314n/a if ext not in (self.src_extensions + ['.rc','.res']):
315n/a raise UnknownFileError("unknown file type '%s' (from '%s')" % \
316n/a (ext, src_name))
317n/a if strip_dir:
318n/a base = os.path.basename(base)
319n/a if ext == '.res':
320n/a # these can go unchanged
321n/a obj_names.append(os.path.join(output_dir, base + ext))
322n/a elif ext == '.rc':
323n/a # these need to be compiled to .res-files
324n/a obj_names.append(os.path.join(output_dir, base + '.res'))
325n/a else:
326n/a obj_names.append(os.path.join(output_dir,
327n/a base + self.obj_extension))
328n/a return obj_names
329n/a
330n/a
331n/a def preprocess(self, source, output_file=None, macros=None,
332n/a include_dirs=None, extra_preargs=None,
333n/a extra_postargs=None):
334n/a _, macros, include_dirs = \
335n/a self._fix_compile_args(None, macros, include_dirs)
336n/a pp_opts = gen_preprocess_options(macros, include_dirs)
337n/a pp_args = ['cpp32.exe'] + pp_opts
338n/a if output_file is not None:
339n/a pp_args.append('-o' + output_file)
340n/a if extra_preargs:
341n/a pp_args[:0] = extra_preargs
342n/a if extra_postargs:
343n/a pp_args.extend(extra_postargs)
344n/a pp_args.append(source)
345n/a
346n/a # We need to preprocess: either we're being forced to, or the
347n/a # source file is newer than the target (or the target doesn't
348n/a # exist).
349n/a if self.force or output_file is None or newer(source, output_file):
350n/a if output_file:
351n/a self.mkpath(os.path.dirname(output_file))
352n/a try:
353n/a self.spawn(pp_args)
354n/a except PackagingExecError as msg:
355n/a raise CompileError(msg)