mirror of
https://github.com/python/cpython.git
synced 2024-11-25 02:44:06 +08:00
Big patch from Rene Liebscher to simplify the CCompiler API and
implementations. Details: * replace 'link_shared_object()', 'link_shared_lib()', and 'link_executable()' with 'link()', which is (roughly) the union of the three methods it replaces * in all implementation classes (UnixCCompiler, MSVCCompiler, etc.), ditch the old 'link_*()' methods and replace them with 'link()' * in the abstract base class (CCompiler), add the old 'link_*()' methods as wrappers around the new 'link()' (they also print a warning of the deprecated interface) Also increases consistency between MSVCCompiler and BCPPCompiler, hopefully to make it easier to factor out the mythical WindowsCCompiler class. Details: * use 'self.linker' instead of 'self.link' * add ability to compile resource files to BCPPCompiler * added (redundant?) 'object_filename()' method to BCPPCompiler * only generate a .def file if 'export_symbols' defined
This commit is contained in:
parent
3ad4e74870
commit
4240648a9d
@ -63,7 +63,7 @@ class BCPPCompiler(CCompiler) :
|
||||
# indicate their installation locations.
|
||||
|
||||
self.cc = "bcc32.exe"
|
||||
self.link = "ilink32.exe"
|
||||
self.linker = "ilink32.exe"
|
||||
self.lib = "tlib.exe"
|
||||
|
||||
self.preprocess_options = None
|
||||
@ -73,6 +73,8 @@ class BCPPCompiler(CCompiler) :
|
||||
self.ldflags_shared = ['/Tpd', '/Gn', '/q', '/x']
|
||||
self.ldflags_shared_debug = ['/Tpd', '/Gn', '/q', '/x']
|
||||
self.ldflags_static = []
|
||||
self.ldflags_exe = ['/Gn', '/q', '/x']
|
||||
self.ldflags_exe_debug = ['/Gn', '/q', '/x','/r']
|
||||
|
||||
|
||||
# -- Worker methods ------------------------------------------------
|
||||
@ -108,16 +110,33 @@ class BCPPCompiler(CCompiler) :
|
||||
if skip_sources[src]:
|
||||
self.announce ("skipping %s (%s up-to-date)" % (src, obj))
|
||||
else:
|
||||
src = os.path.normpath(src)
|
||||
obj = os.path.normpath(obj)
|
||||
self.mkpath(os.path.dirname(obj))
|
||||
|
||||
if ext == '.res':
|
||||
# This is already a binary file -- skip it.
|
||||
continue # the 'for' loop
|
||||
if ext == '.rc':
|
||||
# This needs to be compiled to a .res file -- do it now.
|
||||
try:
|
||||
self.spawn (["brcc32", "-fo", obj, src])
|
||||
except DistutilsExecError, msg:
|
||||
raise CompileError, msg
|
||||
continue # the 'for' loop
|
||||
|
||||
# The next two are both for the real compiler.
|
||||
if ext in self._c_extensions:
|
||||
input_opt = ""
|
||||
elif ext in self._cpp_extensions:
|
||||
input_opt = "-P"
|
||||
else:
|
||||
# Unknown file type -- no extra options. The compiler
|
||||
# will probably fail, but let it just in case this is a
|
||||
# file the compiler recognizes even if we don't.
|
||||
input_opt = ""
|
||||
|
||||
src = os.path.normpath(src)
|
||||
obj = os.path.normpath(obj)
|
||||
|
||||
output_opt = "-o" + obj
|
||||
self.mkpath(os.path.dirname(obj))
|
||||
|
||||
# Compiler command line syntax is: "bcc32 [options] file(s)".
|
||||
# Note that the source file names must appear at the end of
|
||||
@ -163,45 +182,20 @@ class BCPPCompiler(CCompiler) :
|
||||
|
||||
# create_static_lib ()
|
||||
|
||||
|
||||
def link_shared_lib (self,
|
||||
objects,
|
||||
output_libname,
|
||||
output_dir=None,
|
||||
libraries=None,
|
||||
library_dirs=None,
|
||||
runtime_library_dirs=None,
|
||||
export_symbols=None,
|
||||
debug=0,
|
||||
extra_preargs=None,
|
||||
extra_postargs=None,
|
||||
build_temp=None):
|
||||
|
||||
self.link_shared_object (objects,
|
||||
self.shared_library_name(output_libname),
|
||||
output_dir=output_dir,
|
||||
libraries=libraries,
|
||||
library_dirs=library_dirs,
|
||||
runtime_library_dirs=runtime_library_dirs,
|
||||
export_symbols=export_symbols,
|
||||
debug=debug,
|
||||
extra_preargs=extra_preargs,
|
||||
extra_postargs=extra_postargs,
|
||||
build_temp=build_temp)
|
||||
|
||||
|
||||
def link_shared_object (self,
|
||||
objects,
|
||||
output_filename,
|
||||
output_dir=None,
|
||||
libraries=None,
|
||||
library_dirs=None,
|
||||
runtime_library_dirs=None,
|
||||
export_symbols=None,
|
||||
debug=0,
|
||||
extra_preargs=None,
|
||||
extra_postargs=None,
|
||||
build_temp=None):
|
||||
def link (self,
|
||||
target_desc,
|
||||
objects,
|
||||
output_filename,
|
||||
output_dir=None,
|
||||
libraries=None,
|
||||
library_dirs=None,
|
||||
runtime_library_dirs=None,
|
||||
export_symbols=None,
|
||||
debug=0,
|
||||
extra_preargs=None,
|
||||
extra_postargs=None,
|
||||
build_temp=None):
|
||||
|
||||
# XXX this ignores 'build_temp'! should follow the lead of
|
||||
# msvccompiler.py
|
||||
@ -213,45 +207,61 @@ class BCPPCompiler(CCompiler) :
|
||||
if runtime_library_dirs:
|
||||
self.warn ("I don't know what to do with 'runtime_library_dirs': "
|
||||
+ str (runtime_library_dirs))
|
||||
|
||||
|
||||
if output_dir is not None:
|
||||
output_filename = os.path.join (output_dir, output_filename)
|
||||
|
||||
if self._need_link (objects, output_filename):
|
||||
|
||||
if debug:
|
||||
ld_args = self.ldflags_shared_debug[:]
|
||||
# Figure out linker args based on type of target.
|
||||
if target_desc == CCompiler.EXECUTABLE:
|
||||
startup_obj = 'c0w32'
|
||||
if debug:
|
||||
ld_args = self.ldflags_exe_debug[:]
|
||||
else:
|
||||
ld_args = self.ldflags_exe[:]
|
||||
else:
|
||||
ld_args = self.ldflags_shared[:]
|
||||
startup_obj = 'c0d32'
|
||||
if debug:
|
||||
ld_args = self.ldflags_shared_debug[:]
|
||||
else:
|
||||
ld_args = self.ldflags_shared[:]
|
||||
|
||||
|
||||
# Create a temporary exports file for use by the linker
|
||||
head, tail = os.path.split (output_filename)
|
||||
modname, ext = os.path.splitext (tail)
|
||||
temp_dir = os.path.dirname(objects[0]) # preserve tree structure
|
||||
def_file = os.path.join (temp_dir, '%s.def' % modname)
|
||||
contents = ['EXPORTS']
|
||||
for sym in (export_symbols or []):
|
||||
contents.append(' %s=_%s' % (sym, sym))
|
||||
self.execute(write_file, (def_file, contents),
|
||||
"writing %s" % def_file)
|
||||
if export_symbols is None:
|
||||
def_file = ''
|
||||
else:
|
||||
head, tail = os.path.split (output_filename)
|
||||
modname, ext = os.path.splitext (tail)
|
||||
temp_dir = os.path.dirname(objects[0]) # preserve tree structure
|
||||
def_file = os.path.join (temp_dir, '%s.def' % modname)
|
||||
contents = ['EXPORTS']
|
||||
for sym in (export_symbols or []):
|
||||
contents.append(' %s=_%s' % (sym, sym))
|
||||
self.execute(write_file, (def_file, contents),
|
||||
"writing %s" % def_file)
|
||||
|
||||
# Borland C++ has problems with '/' in paths
|
||||
objects = map(os.path.normpath, objects)
|
||||
startup_obj = 'c0d32'
|
||||
objects.insert(0, startup_obj)
|
||||
|
||||
# either exchange python15.lib in the python libs directory against
|
||||
# a Borland-like one, or create one with name bcpp_python15.lib
|
||||
# there and remove the pragmas from config.h
|
||||
libraries.append ('import32')
|
||||
libraries.append ('cw32mt')
|
||||
|
||||
# Start building command line flags and options.
|
||||
|
||||
objects2 = map(os.path.normpath, objects)
|
||||
# split objects in .obj and .res files
|
||||
# Borland C++ needs them at different positions in the command line
|
||||
objects = [startup_obj]
|
||||
resources = []
|
||||
for file in objects2:
|
||||
(base, ext) = os.path.splitext(os.path.normcase(file))
|
||||
if ext == '.res':
|
||||
resources.append(file)
|
||||
else:
|
||||
objects.append(file)
|
||||
|
||||
|
||||
for l in library_dirs:
|
||||
ld_args.append("/L%s" % os.path.normpath(l))
|
||||
|
||||
ld_args.extend(objects) # list of object files
|
||||
ld_args.append("/L.") # we sometimes use relative paths
|
||||
|
||||
# list of object files
|
||||
ld_args.extend(objects)
|
||||
|
||||
# XXX the command-line syntax for Borland C++ is a bit wonky;
|
||||
# certain filenames are jammed together in one big string, but
|
||||
@ -263,14 +273,14 @@ class BCPPCompiler(CCompiler) :
|
||||
# because 'spawn()' would quote any filenames with spaces in
|
||||
# them. Arghghh!. Apparently it works fine as coded...
|
||||
|
||||
# name of dll file
|
||||
# name of dll/exe file
|
||||
ld_args.extend([',',output_filename])
|
||||
# no map file and start libraries
|
||||
ld_args.append(',,')
|
||||
|
||||
for lib in libraries:
|
||||
# see if we find it and if there is a bcpp specific lib
|
||||
# (bcpp_xxx.lib)
|
||||
# (xxx_bcpp.lib)
|
||||
libfile = self.find_library_file(library_dirs, lib, debug)
|
||||
if libfile is None:
|
||||
ld_args.append(lib)
|
||||
@ -279,8 +289,17 @@ class BCPPCompiler(CCompiler) :
|
||||
else:
|
||||
# full name which prefers bcpp_xxx.lib over xxx.lib
|
||||
ld_args.append(libfile)
|
||||
|
||||
# some default libraries
|
||||
ld_args.append ('import32')
|
||||
ld_args.append ('cw32mt')
|
||||
|
||||
# def file for export symbols
|
||||
ld_args.extend([',',def_file])
|
||||
# add resource files
|
||||
ld_args.append(',')
|
||||
ld_args.extend(resources)
|
||||
|
||||
|
||||
if extra_preargs:
|
||||
ld_args[:0] = extra_preargs
|
||||
@ -289,88 +308,24 @@ class BCPPCompiler(CCompiler) :
|
||||
|
||||
self.mkpath (os.path.dirname (output_filename))
|
||||
try:
|
||||
self.spawn ([self.link] + ld_args)
|
||||
self.spawn ([self.linker] + ld_args)
|
||||
except DistutilsExecError, msg:
|
||||
raise LinkError, msg
|
||||
|
||||
else:
|
||||
self.announce ("skipping %s (up-to-date)" % output_filename)
|
||||
|
||||
# link_shared_object ()
|
||||
|
||||
|
||||
def link_executable (self,
|
||||
objects,
|
||||
output_progname,
|
||||
output_dir=None,
|
||||
libraries=None,
|
||||
library_dirs=None,
|
||||
runtime_library_dirs=None,
|
||||
debug=0,
|
||||
extra_preargs=None,
|
||||
extra_postargs=None):
|
||||
|
||||
(objects, output_dir) = self._fix_object_args (objects, output_dir)
|
||||
(libraries, library_dirs, runtime_library_dirs) = \
|
||||
self._fix_lib_args (libraries, library_dirs, runtime_library_dirs)
|
||||
|
||||
if runtime_library_dirs:
|
||||
self.warn ("I don't know what to do with 'runtime_library_dirs': "
|
||||
+ str (runtime_library_dirs))
|
||||
|
||||
lib_opts = gen_lib_options (self,
|
||||
library_dirs, runtime_library_dirs,
|
||||
libraries)
|
||||
output_filename = output_progname + self.exe_extension
|
||||
if output_dir is not None:
|
||||
output_filename = os.path.join (output_dir, output_filename)
|
||||
|
||||
if self._need_link (objects, output_filename):
|
||||
|
||||
if debug:
|
||||
ldflags = self.ldflags_shared_debug[1:]
|
||||
else:
|
||||
ldflags = self.ldflags_shared[1:]
|
||||
|
||||
ld_args = ldflags + lib_opts + \
|
||||
objects + ['/OUT:' + output_filename]
|
||||
|
||||
if extra_preargs:
|
||||
ld_args[:0] = extra_preargs
|
||||
if extra_postargs:
|
||||
ld_args.extend (extra_postargs)
|
||||
|
||||
self.mkpath (os.path.dirname (output_filename))
|
||||
try:
|
||||
self.spawn ([self.link] + ld_args)
|
||||
except DistutilsExecError, msg:
|
||||
raise LinkError, msg
|
||||
else:
|
||||
self.announce ("skipping %s (up-to-date)" % output_filename)
|
||||
|
||||
# link ()
|
||||
|
||||
# -- Miscellaneous methods -----------------------------------------
|
||||
# These are all used by the 'gen_lib_options() function, in
|
||||
# ccompiler.py.
|
||||
|
||||
def library_dir_option (self, dir):
|
||||
return "-L" + dir
|
||||
|
||||
def runtime_library_dir_option (self, dir):
|
||||
raise DistutilsPlatformError, \
|
||||
("don't know how to set runtime library search path "
|
||||
"for Borland C++")
|
||||
|
||||
def library_option (self, lib):
|
||||
return self.library_filename (lib)
|
||||
|
||||
|
||||
def find_library_file (self, dirs, lib, debug=0):
|
||||
# List of effective library names to try, in order of preference:
|
||||
# bcpp_xxx.lib is better than xxx.lib
|
||||
# xxx_bcpp.lib is better than xxx.lib
|
||||
# and xxx_d.lib is better than xxx.lib if debug is set
|
||||
#
|
||||
# The "bcpp_" prefix is to handle a Python installation for people
|
||||
# The "_bcpp" suffix is to handle a Python installation for people
|
||||
# with multiple compilers (primarily Distutils hackers, I suspect
|
||||
# ;-). The idea is they'd have one static library for each
|
||||
# compiler they care about, since (almost?) every Windows compiler
|
||||
@ -390,3 +345,31 @@ class BCPPCompiler(CCompiler) :
|
||||
# Oops, didn't find it in *any* of 'dirs'
|
||||
return None
|
||||
|
||||
# overwrite the one from CCompiler to support rc and res-files
|
||||
def object_filenames (self,
|
||||
source_filenames,
|
||||
strip_dir=0,
|
||||
output_dir=''):
|
||||
if output_dir is None: output_dir = ''
|
||||
obj_names = []
|
||||
for src_name in source_filenames:
|
||||
# use normcase to make sure '.rc' is really '.rc' and not '.RC'
|
||||
(base, ext) = os.path.splitext (os.path.normcase(src_name))
|
||||
if ext not in (self.src_extensions + ['.rc','.res']):
|
||||
raise UnknownFileError, \
|
||||
"unknown file type '%s' (from '%s')" % \
|
||||
(ext, src_name)
|
||||
if strip_dir:
|
||||
base = os.path.basename (base)
|
||||
if ext == '.res':
|
||||
# these can go unchanged
|
||||
obj_names.append (os.path.join (output_dir, base + ext))
|
||||
elif ext == '.rc':
|
||||
# these need to be compiled to .res-files
|
||||
obj_names.append (os.path.join (output_dir, base + '.res'))
|
||||
else:
|
||||
obj_names.append (os.path.join (output_dir,
|
||||
base + self.obj_extension))
|
||||
return obj_names
|
||||
|
||||
# object_filenames ()
|
||||
|
@ -561,24 +561,32 @@ class CCompiler:
|
||||
pass
|
||||
|
||||
|
||||
def link_shared_lib (self,
|
||||
objects,
|
||||
output_libname,
|
||||
output_dir=None,
|
||||
libraries=None,
|
||||
library_dirs=None,
|
||||
runtime_library_dirs=None,
|
||||
export_symbols=None,
|
||||
debug=0,
|
||||
extra_preargs=None,
|
||||
extra_postargs=None,
|
||||
build_temp=None):
|
||||
"""Link a bunch of stuff together to create a shared library file.
|
||||
Similar semantics to 'create_static_lib()', with the addition of
|
||||
other libraries to link against and directories to search for them.
|
||||
Also, of course, the type and name of the generated file will
|
||||
almost certainly be different, as will the program used to create
|
||||
it.
|
||||
# values for target_desc parameter in link()
|
||||
SHARED_OBJECT = "shared_object"
|
||||
SHARED_LIBRARY = "shared_library"
|
||||
EXECUTABLE = "executable"
|
||||
|
||||
def link (self,
|
||||
target_desc,
|
||||
objects,
|
||||
output_filename,
|
||||
output_dir=None,
|
||||
libraries=None,
|
||||
library_dirs=None,
|
||||
runtime_library_dirs=None,
|
||||
export_symbols=None,
|
||||
debug=0,
|
||||
extra_preargs=None,
|
||||
extra_postargs=None,
|
||||
build_temp=None):
|
||||
"""Link a bunch of stuff together to create an executable or
|
||||
shared library file.
|
||||
|
||||
The "bunch of stuff" consists of the list of object files supplied
|
||||
as 'objects'. 'output_filename' should be a filename. If
|
||||
'output_dir' is supplied, 'output_filename' is relative to it
|
||||
(i.e. 'output_filename' can provide directory components if
|
||||
needed).
|
||||
|
||||
'libraries' is a list of libraries to link against. These are
|
||||
library names, not filenames, since they're translated into
|
||||
@ -610,7 +618,31 @@ class CCompiler:
|
||||
|
||||
Raises LinkError on failure.
|
||||
"""
|
||||
pass
|
||||
raise NotImplementedError
|
||||
|
||||
|
||||
# old methods, rewritten to use the new link() method.
|
||||
|
||||
def link_shared_lib (self,
|
||||
objects,
|
||||
output_libname,
|
||||
output_dir=None,
|
||||
libraries=None,
|
||||
library_dirs=None,
|
||||
runtime_library_dirs=None,
|
||||
export_symbols=None,
|
||||
debug=0,
|
||||
extra_preargs=None,
|
||||
extra_postargs=None,
|
||||
build_temp=None):
|
||||
self.warn("link_shared_lib(..) is deprecated, please "
|
||||
"use link(CCompiler.SHARED_LIBRARY, ...) instead")
|
||||
self.link(CCompiler.SHARED_LIBRARY, objects,
|
||||
self.library_filename(output_libname, lib_type='shared'),
|
||||
output_dir,
|
||||
libraries, library_dirs, runtime_library_dirs,
|
||||
export_symbols, debug,
|
||||
extra_preargs, extra_postargs, build_temp)
|
||||
|
||||
|
||||
def link_shared_object (self,
|
||||
@ -625,16 +657,13 @@ class CCompiler:
|
||||
extra_preargs=None,
|
||||
extra_postargs=None,
|
||||
build_temp=None):
|
||||
"""Link a bunch of stuff together to create a shared object file.
|
||||
Much like 'link_shared_lib()', except the output filename is
|
||||
explicitly supplied as 'output_filename'. If 'output_dir' is
|
||||
supplied, 'output_filename' is relative to it
|
||||
(i.e. 'output_filename' can provide directory components if
|
||||
needed).
|
||||
|
||||
Raises LinkError on failure.
|
||||
"""
|
||||
pass
|
||||
self.warn("link_shared_object(...) is deprecated, please "
|
||||
"use link(CCompiler.SHARED_OBJECT,...) instead.")
|
||||
self.link(CCompiler.SHARED_OBJECT, objects,
|
||||
output_filename, output_dir,
|
||||
libraries, library_dirs, runtime_library_dirs,
|
||||
export_symbols, debug,
|
||||
extra_preargs, extra_postargs, build_temp)
|
||||
|
||||
|
||||
def link_executable (self,
|
||||
@ -647,16 +676,12 @@ class CCompiler:
|
||||
debug=0,
|
||||
extra_preargs=None,
|
||||
extra_postargs=None):
|
||||
"""Link a bunch of stuff together to create a binary executable
|
||||
file. The "bunch of stuff" is as for 'link_shared_lib()'.
|
||||
'output_progname' should be the base name of the executable
|
||||
program--e.g. on Unix the same as the output filename, but on
|
||||
DOS/Windows ".exe" will be appended.
|
||||
|
||||
Raises LinkError on failure.
|
||||
"""
|
||||
pass
|
||||
|
||||
self.warn("link_executable(...) is deprecated, please "
|
||||
"use link(CCompiler.EXECUTABLE,...) instead.")
|
||||
self.link (CCompiler.EXECUTABLE, objects,
|
||||
self.executable_filename(output_progname), output_dir,
|
||||
libraries, library_dirs, runtime_library_dirs, None,
|
||||
debug, extra_preargs, extra_postargs, None)
|
||||
|
||||
|
||||
# -- Miscellaneous methods -----------------------------------------
|
||||
@ -756,6 +781,14 @@ class CCompiler:
|
||||
basename = os.path.basename (basename)
|
||||
return os.path.join (output_dir, basename + self.shared_lib_extension)
|
||||
|
||||
def executable_filename (self,
|
||||
basename,
|
||||
strip_dir=0,
|
||||
output_dir=''):
|
||||
if output_dir is None: output_dir = ''
|
||||
if strip_dir:
|
||||
basename = os.path.basename (basename)
|
||||
return os.path.join(output_dir, basename + (self.exe_extension or ''))
|
||||
|
||||
def library_filename (self,
|
||||
libname,
|
||||
|
@ -39,14 +39,17 @@ cygwin in no-cygwin mode).
|
||||
# By specifying -static we force ld to link against the import libraries,
|
||||
# this is windows standard and there are normally not the necessary symbols
|
||||
# in the dlls.
|
||||
# *** only the version of June 2000 shows these problems
|
||||
|
||||
# created 2000/05/05, Rene Liebscher
|
||||
|
||||
__revision__ = "$Id$"
|
||||
|
||||
import os,sys,copy
|
||||
from distutils.ccompiler import gen_preprocess_options, gen_lib_options
|
||||
from distutils.unixccompiler import UnixCCompiler
|
||||
from distutils.file_util import write_file
|
||||
from distutils.errors import DistutilsExecError, CompileError, UnknownFileError
|
||||
|
||||
class CygwinCCompiler (UnixCCompiler):
|
||||
|
||||
@ -87,9 +90,9 @@ class CygwinCCompiler (UnixCCompiler):
|
||||
# same as the rest of binutils ( also ld )
|
||||
# dllwrap 2.10.90 is buggy
|
||||
if self.ld_version >= "2.10.90":
|
||||
self.linker = "gcc"
|
||||
self.linker_dll = "gcc"
|
||||
else:
|
||||
self.linker = "dllwrap"
|
||||
self.linker_dll = "dllwrap"
|
||||
|
||||
# Hard-code GCC because that's what this is all about.
|
||||
# XXX optimization, warnings etc. should be customizable.
|
||||
@ -97,7 +100,7 @@ class CygwinCCompiler (UnixCCompiler):
|
||||
compiler_so='gcc -mcygwin -mdll -O -Wall',
|
||||
linker_exe='gcc -mcygwin',
|
||||
linker_so=('%s -mcygwin -mdll -static' %
|
||||
self.linker))
|
||||
self.linker_dll))
|
||||
|
||||
# cygwin and mingw32 need different sets of libraries
|
||||
if self.gcc_version == "2.91.57":
|
||||
@ -111,58 +114,108 @@ class CygwinCCompiler (UnixCCompiler):
|
||||
|
||||
# __init__ ()
|
||||
|
||||
def link_shared_object (self,
|
||||
objects,
|
||||
output_filename,
|
||||
output_dir=None,
|
||||
libraries=None,
|
||||
library_dirs=None,
|
||||
runtime_library_dirs=None,
|
||||
export_symbols=None,
|
||||
debug=0,
|
||||
extra_preargs=None,
|
||||
extra_postargs=None,
|
||||
build_temp=None):
|
||||
# not much different of the compile method in UnixCCompiler,
|
||||
# but we have to insert some lines in the middle of it, so
|
||||
# we put here a adapted version of it.
|
||||
# (If we would call compile() in the base class, it would do some
|
||||
# initializations a second time, this is why all is done here.)
|
||||
def compile (self,
|
||||
sources,
|
||||
output_dir=None,
|
||||
macros=None,
|
||||
include_dirs=None,
|
||||
debug=0,
|
||||
extra_preargs=None,
|
||||
extra_postargs=None):
|
||||
|
||||
(output_dir, macros, include_dirs) = \
|
||||
self._fix_compile_args (output_dir, macros, include_dirs)
|
||||
(objects, skip_sources) = self._prep_compile (sources, output_dir)
|
||||
|
||||
# Figure out the options for the compiler command line.
|
||||
pp_opts = gen_preprocess_options (macros, include_dirs)
|
||||
cc_args = pp_opts + ['-c']
|
||||
if debug:
|
||||
cc_args[:0] = ['-g']
|
||||
if extra_preargs:
|
||||
cc_args[:0] = extra_preargs
|
||||
if extra_postargs is None:
|
||||
extra_postargs = []
|
||||
|
||||
# Compile all source files that weren't eliminated by
|
||||
# '_prep_compile()'.
|
||||
for i in range (len (sources)):
|
||||
src = sources[i] ; obj = objects[i]
|
||||
ext = (os.path.splitext (src))[1]
|
||||
if skip_sources[src]:
|
||||
self.announce ("skipping %s (%s up-to-date)" % (src, obj))
|
||||
else:
|
||||
self.mkpath (os.path.dirname (obj))
|
||||
if ext == '.rc' or ext == '.res':
|
||||
# gcc needs '.res' and '.rc' compiled to object files !!!
|
||||
try:
|
||||
self.spawn (["windres","-i",src,"-o",obj])
|
||||
except DistutilsExecError, msg:
|
||||
raise CompileError, msg
|
||||
else: # for other files use the C-compiler
|
||||
try:
|
||||
self.spawn (self.compiler_so + cc_args +
|
||||
[src, '-o', obj] +
|
||||
extra_postargs)
|
||||
except DistutilsExecError, msg:
|
||||
raise CompileError, msg
|
||||
|
||||
# Return *all* object filenames, not just the ones we just built.
|
||||
return objects
|
||||
|
||||
# compile ()
|
||||
|
||||
|
||||
def link (self,
|
||||
target_desc,
|
||||
objects,
|
||||
output_filename,
|
||||
output_dir=None,
|
||||
libraries=None,
|
||||
library_dirs=None,
|
||||
runtime_library_dirs=None,
|
||||
export_symbols=None,
|
||||
debug=0,
|
||||
extra_preargs=None,
|
||||
extra_postargs=None,
|
||||
build_temp=None):
|
||||
|
||||
# use separate copies, so we can modify the lists
|
||||
extra_preargs = copy.copy(extra_preargs or [])
|
||||
libraries = copy.copy(libraries or [])
|
||||
|
||||
objects = copy.copy(objects or [])
|
||||
|
||||
# Additional libraries
|
||||
libraries.extend(self.dll_libraries)
|
||||
|
||||
# we want to put some files in the same directory as the
|
||||
# object files are, build_temp doesn't help much
|
||||
|
||||
# where are the object files
|
||||
temp_dir = os.path.dirname(objects[0])
|
||||
|
||||
# name of dll to give the helper files (def, lib, exp) the same name
|
||||
(dll_name, dll_extension) = os.path.splitext(
|
||||
os.path.basename(output_filename))
|
||||
|
||||
# generate the filenames for these files
|
||||
def_file = None # this will be done later, if necessary
|
||||
exp_file = os.path.join(temp_dir, dll_name + ".exp")
|
||||
lib_file = os.path.join(temp_dir, 'lib' + dll_name + ".a")
|
||||
|
||||
#extra_preargs.append("--verbose")
|
||||
if self.linker == "dllwrap":
|
||||
extra_preargs.extend([#"--output-exp",exp_file,
|
||||
"--output-lib",lib_file,
|
||||
])
|
||||
else:
|
||||
# doesn't work: bfd_close build\...\libfoo.a: Invalid operation
|
||||
extra_preargs.extend([#"-Wl,--out-implib,%s" % lib_file,
|
||||
])
|
||||
|
||||
# check what we got in export_symbols
|
||||
if export_symbols is not None:
|
||||
# Make .def file
|
||||
# (It would probably better to check if we really need this,
|
||||
# handle export symbols by creating a def-file
|
||||
# with executables this only works with gcc/ld as linker
|
||||
if ((export_symbols is not None) and
|
||||
(target_desc != self.EXECUTABLE or self.linker_dll == "gcc")):
|
||||
# (The linker doesn't do anything if output is up-to-date.
|
||||
# So it would probably better to check if we really need this,
|
||||
# but for this we had to insert some unchanged parts of
|
||||
# UnixCCompiler, and this is not what we want.)
|
||||
|
||||
# we want to put some files in the same directory as the
|
||||
# object files are, build_temp doesn't help much
|
||||
# where are the object files
|
||||
temp_dir = os.path.dirname(objects[0])
|
||||
# name of dll to give the helper files the same base name
|
||||
(dll_name, dll_extension) = os.path.splitext(
|
||||
os.path.basename(output_filename))
|
||||
|
||||
# generate the filenames for these files
|
||||
def_file = os.path.join(temp_dir, dll_name + ".def")
|
||||
exp_file = os.path.join(temp_dir, dll_name + ".exp")
|
||||
lib_file = os.path.join(temp_dir, 'lib' + dll_name + ".a")
|
||||
|
||||
# Generate .def file
|
||||
contents = [
|
||||
"LIBRARY %s" % os.path.basename(output_filename),
|
||||
"EXPORTS"]
|
||||
@ -171,35 +224,78 @@ class CygwinCCompiler (UnixCCompiler):
|
||||
self.execute(write_file, (def_file, contents),
|
||||
"writing %s" % def_file)
|
||||
|
||||
if def_file:
|
||||
if self.linker == "dllwrap":
|
||||
# next add options for def-file and to creating import libraries
|
||||
|
||||
# dllwrap uses different options than gcc/ld
|
||||
if self.linker_dll == "dllwrap":
|
||||
extra_preargs.extend([#"--output-exp",exp_file,
|
||||
"--output-lib",lib_file,
|
||||
])
|
||||
# for dllwrap we have to use a special option
|
||||
extra_preargs.append("--def")
|
||||
# for gcc/ld it is specified as any other object file
|
||||
extra_preargs.append(def_file)
|
||||
extra_preargs.extend(["--def", def_file])
|
||||
# we use gcc/ld here and can be sure ld is >= 2.9.10
|
||||
else:
|
||||
# doesn't work: bfd_close build\...\libfoo.a: Invalid operation
|
||||
#extra_preargs.extend(["-Wl,--out-implib,%s" % lib_file])
|
||||
# for gcc/ld the def-file is specified as any other object files
|
||||
objects.append(def_file)
|
||||
|
||||
#end: if ((export_symbols is not None) and
|
||||
# (target_desc <> self.EXECUTABLE or self.linker_dll == "gcc")):
|
||||
|
||||
# who wants symbols and a many times larger output file
|
||||
# should explicitly switch the debug mode on
|
||||
# otherwise we let dllwrap/ld strip the output file
|
||||
# (On my machine unstripped_file = stripped_file + 254KB
|
||||
# 10KB < stripped_file < ??100KB )
|
||||
# (On my machine: 10KB < stripped_file < ??100KB
|
||||
# unstripped_file = stripped_file + XXX KB
|
||||
# ( XXX=254 for a typical python extension))
|
||||
if not debug:
|
||||
extra_preargs.append("-s")
|
||||
|
||||
UnixCCompiler.link_shared_object(self,
|
||||
objects,
|
||||
output_filename,
|
||||
output_dir,
|
||||
libraries,
|
||||
library_dirs,
|
||||
runtime_library_dirs,
|
||||
None, # export_symbols, we do this in our def-file
|
||||
debug,
|
||||
extra_preargs,
|
||||
extra_postargs,
|
||||
build_temp)
|
||||
UnixCCompiler.link(self,
|
||||
target_desc,
|
||||
objects,
|
||||
output_filename,
|
||||
output_dir,
|
||||
libraries,
|
||||
library_dirs,
|
||||
runtime_library_dirs,
|
||||
None, # export_symbols, we do this in our def-file
|
||||
debug,
|
||||
extra_preargs,
|
||||
extra_postargs,
|
||||
build_temp)
|
||||
|
||||
# link_shared_object ()
|
||||
# link ()
|
||||
|
||||
# -- Miscellaneous methods -----------------------------------------
|
||||
|
||||
# overwrite the one from CCompiler to support rc and res-files
|
||||
def object_filenames (self,
|
||||
source_filenames,
|
||||
strip_dir=0,
|
||||
output_dir=''):
|
||||
if output_dir is None: output_dir = ''
|
||||
obj_names = []
|
||||
for src_name in source_filenames:
|
||||
# use normcase to make sure '.rc' is really '.rc' and not '.RC'
|
||||
(base, ext) = os.path.splitext (os.path.normcase(src_name))
|
||||
if ext not in (self.src_extensions + ['.rc','.res']):
|
||||
raise UnknownFileError, \
|
||||
"unknown file type '%s' (from '%s')" % \
|
||||
(ext, src_name)
|
||||
if strip_dir:
|
||||
base = os.path.basename (base)
|
||||
if ext == '.res' or ext == '.rc':
|
||||
# these need to be compiled to object files
|
||||
obj_names.append (os.path.join (output_dir,
|
||||
base + ext + self.obj_extension))
|
||||
else:
|
||||
obj_names.append (os.path.join (output_dir,
|
||||
base + self.obj_extension))
|
||||
return obj_names
|
||||
|
||||
# object_filenames ()
|
||||
|
||||
# class CygwinCCompiler
|
||||
|
||||
@ -227,7 +323,7 @@ class Mingw32CCompiler (CygwinCCompiler):
|
||||
compiler_so='gcc -mno-cygwin -mdll -O -Wall',
|
||||
linker_exe='gcc -mno-cygwin',
|
||||
linker_so='%s -mno-cygwin -mdll -static %s'
|
||||
% (self.linker, entry_point))
|
||||
% (self.linker_dll, entry_point))
|
||||
# Maybe we should also append -mthreads, but then the finished
|
||||
# dlls need another dll (mingwm10.dll see Mingw32 docs)
|
||||
# (-mthreads: Support thread-safe exception handling on `Mingw32')
|
||||
|
@ -205,7 +205,7 @@ class MSVCCompiler (CCompiler) :
|
||||
version = versions[0] # highest version
|
||||
|
||||
self.cc = find_exe("cl.exe", version)
|
||||
self.link = find_exe("link.exe", version)
|
||||
self.linker = find_exe("link.exe", version)
|
||||
self.lib = find_exe("lib.exe", version)
|
||||
self.rc = find_exe("rc.exe", version) # resource compiler
|
||||
self.mc = find_exe("mc.exe", version) # message compiler
|
||||
@ -221,7 +221,7 @@ class MSVCCompiler (CCompiler) :
|
||||
else:
|
||||
# devstudio not found in the registry
|
||||
self.cc = "cl.exe"
|
||||
self.link = "link.exe"
|
||||
self.linker = "link.exe"
|
||||
self.lib = "lib.exe"
|
||||
self.rc = "rc.exe"
|
||||
self.mc = "mc.exe"
|
||||
@ -396,45 +396,19 @@ class MSVCCompiler (CCompiler) :
|
||||
|
||||
# create_static_lib ()
|
||||
|
||||
|
||||
def link_shared_lib (self,
|
||||
objects,
|
||||
output_libname,
|
||||
output_dir=None,
|
||||
libraries=None,
|
||||
library_dirs=None,
|
||||
runtime_library_dirs=None,
|
||||
export_symbols=None,
|
||||
debug=0,
|
||||
extra_preargs=None,
|
||||
extra_postargs=None,
|
||||
build_temp=None):
|
||||
|
||||
self.link_shared_object (objects,
|
||||
self.shared_library_name(output_libname),
|
||||
output_dir=output_dir,
|
||||
libraries=libraries,
|
||||
library_dirs=library_dirs,
|
||||
runtime_library_dirs=runtime_library_dirs,
|
||||
export_symbols=export_symbols,
|
||||
debug=debug,
|
||||
extra_preargs=extra_preargs,
|
||||
extra_postargs=extra_postargs,
|
||||
build_temp=build_temp)
|
||||
|
||||
|
||||
def link_shared_object (self,
|
||||
objects,
|
||||
output_filename,
|
||||
output_dir=None,
|
||||
libraries=None,
|
||||
library_dirs=None,
|
||||
runtime_library_dirs=None,
|
||||
export_symbols=None,
|
||||
debug=0,
|
||||
extra_preargs=None,
|
||||
extra_postargs=None,
|
||||
build_temp=None):
|
||||
def link (self,
|
||||
target_desc,
|
||||
objects,
|
||||
output_filename,
|
||||
output_dir=None,
|
||||
libraries=None,
|
||||
library_dirs=None,
|
||||
runtime_library_dirs=None,
|
||||
export_symbols=None,
|
||||
debug=0,
|
||||
extra_preargs=None,
|
||||
extra_postargs=None,
|
||||
build_temp=None):
|
||||
|
||||
(objects, output_dir) = self._fix_object_args (objects, output_dir)
|
||||
(libraries, library_dirs, runtime_library_dirs) = \
|
||||
@ -452,10 +426,16 @@ class MSVCCompiler (CCompiler) :
|
||||
|
||||
if self._need_link (objects, output_filename):
|
||||
|
||||
if debug:
|
||||
ldflags = self.ldflags_shared_debug
|
||||
if target_desc == CCompiler.EXECUTABLE:
|
||||
if debug:
|
||||
ldflags = self.ldflags_shared_debug[1:]
|
||||
else:
|
||||
ldflags = self.ldflags_shared[1:]
|
||||
else:
|
||||
ldflags = self.ldflags_shared
|
||||
if debug:
|
||||
ldflags = self.ldflags_shared_debug
|
||||
else:
|
||||
ldflags = self.ldflags_shared
|
||||
|
||||
export_opts = []
|
||||
for sym in (export_symbols or []):
|
||||
@ -469,12 +449,13 @@ class MSVCCompiler (CCompiler) :
|
||||
# needed! Make sure they are generated in the temporary build
|
||||
# directory. Since they have different names for debug and release
|
||||
# builds, they can go into the same directory.
|
||||
(dll_name, dll_ext) = os.path.splitext(
|
||||
os.path.basename(output_filename))
|
||||
implib_file = os.path.join(
|
||||
os.path.dirname(objects[0]),
|
||||
self.library_filename(dll_name))
|
||||
ld_args.append ('/IMPLIB:' + implib_file)
|
||||
if export_symbols is not None:
|
||||
(dll_name, dll_ext) = os.path.splitext(
|
||||
os.path.basename(output_filename))
|
||||
implib_file = os.path.join(
|
||||
os.path.dirname(objects[0]),
|
||||
self.library_filename(dll_name))
|
||||
ld_args.append ('/IMPLIB:' + implib_file)
|
||||
|
||||
if extra_preargs:
|
||||
ld_args[:0] = extra_preargs
|
||||
@ -483,66 +464,16 @@ class MSVCCompiler (CCompiler) :
|
||||
|
||||
self.mkpath (os.path.dirname (output_filename))
|
||||
try:
|
||||
self.spawn ([self.link] + ld_args)
|
||||
self.spawn ([self.linker] + ld_args)
|
||||
except DistutilsExecError, msg:
|
||||
raise LinkError, msg
|
||||
|
||||
else:
|
||||
self.announce ("skipping %s (up-to-date)" % output_filename)
|
||||
|
||||
# link_shared_object ()
|
||||
# link ()
|
||||
|
||||
|
||||
def link_executable (self,
|
||||
objects,
|
||||
output_progname,
|
||||
output_dir=None,
|
||||
libraries=None,
|
||||
library_dirs=None,
|
||||
runtime_library_dirs=None,
|
||||
debug=0,
|
||||
extra_preargs=None,
|
||||
extra_postargs=None):
|
||||
|
||||
(objects, output_dir) = self._fix_object_args (objects, output_dir)
|
||||
(libraries, library_dirs, runtime_library_dirs) = \
|
||||
self._fix_lib_args (libraries, library_dirs, runtime_library_dirs)
|
||||
|
||||
if runtime_library_dirs:
|
||||
self.warn ("I don't know what to do with 'runtime_library_dirs': "
|
||||
+ str (runtime_library_dirs))
|
||||
|
||||
lib_opts = gen_lib_options (self,
|
||||
library_dirs, runtime_library_dirs,
|
||||
libraries)
|
||||
output_filename = output_progname + self.exe_extension
|
||||
if output_dir is not None:
|
||||
output_filename = os.path.join (output_dir, output_filename)
|
||||
|
||||
if self._need_link (objects, output_filename):
|
||||
|
||||
if debug:
|
||||
ldflags = self.ldflags_shared_debug[1:]
|
||||
else:
|
||||
ldflags = self.ldflags_shared[1:]
|
||||
|
||||
ld_args = ldflags + lib_opts + \
|
||||
objects + ['/OUT:' + output_filename]
|
||||
|
||||
if extra_preargs:
|
||||
ld_args[:0] = extra_preargs
|
||||
if extra_postargs:
|
||||
ld_args.extend (extra_postargs)
|
||||
|
||||
self.mkpath (os.path.dirname (output_filename))
|
||||
try:
|
||||
self.spawn ([self.link] + ld_args)
|
||||
except DistutilsExecError, msg:
|
||||
raise LinkError, msg
|
||||
else:
|
||||
self.announce ("skipping %s (up-to-date)" % output_filename)
|
||||
|
||||
|
||||
# -- Miscellaneous methods -----------------------------------------
|
||||
# These are all used by the 'gen_lib_options() function, in
|
||||
# ccompiler.py.
|
||||
|
@ -190,45 +190,19 @@ class UnixCCompiler (CCompiler):
|
||||
# create_static_lib ()
|
||||
|
||||
|
||||
def link_shared_lib (self,
|
||||
objects,
|
||||
output_libname,
|
||||
output_dir=None,
|
||||
libraries=None,
|
||||
library_dirs=None,
|
||||
runtime_library_dirs=None,
|
||||
export_symbols=None,
|
||||
debug=0,
|
||||
extra_preargs=None,
|
||||
extra_postargs=None,
|
||||
build_temp=None):
|
||||
|
||||
self.link_shared_object(
|
||||
objects,
|
||||
self.library_filename(output_libname, lib_type='shared'),
|
||||
output_dir,
|
||||
libraries,
|
||||
library_dirs,
|
||||
runtime_library_dirs,
|
||||
export_symbols,
|
||||
debug,
|
||||
extra_preargs,
|
||||
extra_postargs,
|
||||
build_temp)
|
||||
|
||||
|
||||
def link_shared_object (self,
|
||||
objects,
|
||||
output_filename,
|
||||
output_dir=None,
|
||||
libraries=None,
|
||||
library_dirs=None,
|
||||
runtime_library_dirs=None,
|
||||
export_symbols=None,
|
||||
debug=0,
|
||||
extra_preargs=None,
|
||||
extra_postargs=None,
|
||||
build_temp=None):
|
||||
def link (self,
|
||||
target_desc,
|
||||
objects,
|
||||
output_filename,
|
||||
output_dir=None,
|
||||
libraries=None,
|
||||
library_dirs=None,
|
||||
runtime_library_dirs=None,
|
||||
export_symbols=None,
|
||||
debug=0,
|
||||
extra_preargs=None,
|
||||
extra_postargs=None,
|
||||
build_temp=None):
|
||||
|
||||
(objects, output_dir) = self._fix_object_args(objects, output_dir)
|
||||
(libraries, library_dirs, runtime_library_dirs) = \
|
||||
@ -253,54 +227,16 @@ class UnixCCompiler (CCompiler):
|
||||
ld_args.extend(extra_postargs)
|
||||
self.mkpath(os.path.dirname(output_filename))
|
||||
try:
|
||||
self.spawn(self.linker_so + ld_args)
|
||||
if target_desc == CCompiler.EXECUTABLE:
|
||||
self.spawn(self.linker_exe + ld_args)
|
||||
else:
|
||||
self.spawn(self.linker_so + ld_args)
|
||||
except DistutilsExecError, msg:
|
||||
raise LinkError, msg
|
||||
else:
|
||||
self.announce("skipping %s (up-to-date)" % output_filename)
|
||||
|
||||
# link_shared_object ()
|
||||
|
||||
|
||||
def link_executable (self,
|
||||
objects,
|
||||
output_progname,
|
||||
output_dir=None,
|
||||
libraries=None,
|
||||
library_dirs=None,
|
||||
runtime_library_dirs=None,
|
||||
debug=0,
|
||||
extra_preargs=None,
|
||||
extra_postargs=None):
|
||||
|
||||
(objects, output_dir) = self._fix_object_args(objects, output_dir)
|
||||
(libraries, library_dirs, runtime_library_dirs) = \
|
||||
self._fix_lib_args(libraries, library_dirs, runtime_library_dirs)
|
||||
|
||||
lib_opts = gen_lib_options(self,
|
||||
library_dirs, runtime_library_dirs,
|
||||
libraries)
|
||||
output_filename = output_progname # Unix-ism!
|
||||
if output_dir is not None:
|
||||
output_filename = os.path.join(output_dir, output_filename)
|
||||
|
||||
if self._need_link(objects, output_filename):
|
||||
ld_args = objects + self.objects + lib_opts + ['-o', output_filename]
|
||||
if debug:
|
||||
ld_args[:0] = ['-g']
|
||||
if extra_preargs:
|
||||
ld_args[:0] = extra_preargs
|
||||
if extra_postargs:
|
||||
ld_args.extend(extra_postargs)
|
||||
self.mkpath(os.path.dirname(output_filename))
|
||||
try:
|
||||
self.spawn(self.linker_exe + ld_args)
|
||||
except DistutilsExecError, msg:
|
||||
raise LinkError, msg
|
||||
else:
|
||||
self.announce("skipping %s (up-to-date)" % output_filename)
|
||||
|
||||
# link_executable ()
|
||||
# link ()
|
||||
|
||||
|
||||
# -- Miscellaneous methods -----------------------------------------
|
||||
|
Loading…
Reference in New Issue
Block a user