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

Python code coverage for Lib/distutils/bcppcompiler.py

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