This patch fixes the following bugs:
[#413582] g++ must be called for c++ extensions
[#454030] distutils cannot link C++ code with GCC
topdir = "Lib/distutils"
* bcppcompiler.py
(BCPPCompiler.create_static_lib): Fixed prototype, removing extra_preargs
and extra_postargs parameters. Included target_lang parameter.
(BCPPCompiler.link): Included target_lang parameter.
* msvccompiler.py
(MSVCCompiler.create_static_lib): Fixed prototype, removing extra_preargs
and extra_postargs parameters. Included target_lang parameter.
(MSVCCompiler.link): Included target_lang parameter.
* ccompiler.py
(CCompiler): New language_map and language_order attributes, used by
CCompiler.detect_language().
(CCompiler.detect_language): New method, will return the language of
a given source, or list of sources. Individual source language is
detected using the language_map dict. When mixed sources are used,
language_order will stablish the language precedence.
(CCompiler.create_static_lib, CCompiler.link, CCompiler.link_executable,
CCompiler.link_shared_object, CCompiler.link_shared_lib):
Inlcuded target_lang parameter.
* cygwinccompiler.py
(CygwinCCompiler.link): Included target_lang parameter.
* emxccompiler.py
(EMXCCompiler.link): Included target_lang parameter.
* mwerkscompiler.py
(MWerksCompiler.link): Included target_lang parameter.
* extension.py
(Extension.__init__): New 'language' parameter/attribute, initialized
to None by default. If provided will overlap the automatic detection
made by CCompiler.detect_language(), in build_ext command.
* sysconfig.py
(customize_compiler): Check Makefile for CXX option, and also the
environment variable CXX. Use the resulting value in the 'compiler_cxx'
parameter of compiler.set_executables().
* unixccompiler.py
(UnixCCompiler): Included 'compiler_cxx' in executables dict, defaulting
to 'cc'.
(UnixCCompiler.create_static_lib): Included target_lang parameter.
(UnixCCompiler.link): Included target_lang parameter, and made
linker command use compiler_cxx, if target_lang is 'c++'.
* command/build_ext.py
(build_ext.build_extension): Pass new ext.language attribute
to compiler.link_shared_object()'s target_lang parameter. If
ext.language is not provided, detect language using
compiler.detect_language(sources) instead.
* command/config.py
(config._link): Pass already available lang parameter as target_lang
parameter of compiler.link_executable().
diff --git a/Lib/distutils/bcppcompiler.py b/Lib/distutils/bcppcompiler.py
index 6e9d6c6..abe302a 100644
--- a/Lib/distutils/bcppcompiler.py
+++ b/Lib/distutils/bcppcompiler.py
@@ -146,8 +146,7 @@
output_libname,
output_dir=None,
debug=0,
- extra_preargs=None,
- extra_postargs=None):
+ target_lang=None):
(objects, output_dir) = self._fix_object_args (objects, output_dir)
output_filename = \
@@ -157,10 +156,6 @@
lib_args = [output_filename, '/u'] + objects
if debug:
pass # XXX what goes here?
- if extra_preargs:
- lib_args[:0] = extra_preargs
- if extra_postargs:
- lib_args.extend (extra_postargs)
try:
self.spawn ([self.lib] + lib_args)
except DistutilsExecError, msg:
@@ -183,7 +178,8 @@
debug=0,
extra_preargs=None,
extra_postargs=None,
- build_temp=None):
+ build_temp=None,
+ target_lang=None):
# XXX this ignores 'build_temp'! should follow the lead of
# msvccompiler.py
diff --git a/Lib/distutils/ccompiler.py b/Lib/distutils/ccompiler.py
index 60d1cae..317e21e 100644
--- a/Lib/distutils/ccompiler.py
+++ b/Lib/distutils/ccompiler.py
@@ -74,6 +74,19 @@
shared_lib_format = None # prob. same as static_lib_format
exe_extension = None # string
+ # Default language settings. language_map is used to detect a source
+ # file or Extension target language, checking source filenames.
+ # language_order is used to detect the language precedence, when deciding
+ # what language to use when mixing source types. For example, if some
+ # extension has two files with ".c" extension, and one with ".cpp", it
+ # is still linked as c++.
+ language_map = {".c" : "c",
+ ".cc" : "c++",
+ ".cpp" : "c++",
+ ".cxx" : "c++",
+ ".m" : "objc",
+ }
+ language_order = ["c++", "objc", "c"]
def __init__ (self,
verbose=0,
@@ -572,6 +585,27 @@
# _need_link ()
+ def detect_language (self, sources):
+ """Detect the language of a given file, or list of files. Uses
+ language_map, and language_order to do the job.
+ """
+ if type(sources) is not ListType:
+ sources = [sources]
+ lang = None
+ index = len(self.language_order)
+ for source in sources:
+ base, ext = os.path.splitext(source)
+ extlang = self.language_map.get(ext)
+ try:
+ extindex = self.language_order.index(extlang)
+ if extindex < index:
+ lang = extlang
+ index = extindex
+ except ValueError:
+ pass
+ return lang
+
+ # detect_language ()
# -- Worker methods ------------------------------------------------
# (must be implemented by subclasses)
@@ -671,7 +705,8 @@
objects,
output_libname,
output_dir=None,
- debug=0):
+ debug=0,
+ target_lang=None):
"""Link a bunch of stuff together to create a static library file.
The "bunch of stuff" consists of the list of object files supplied
as 'objects', the extra object files supplied to
@@ -688,6 +723,10 @@
compile step where this matters: the 'debug' flag is included here
just for consistency).
+ 'target_lang' is the target language for which the given objects
+ are being compiled. This allows specific linkage time treatment of
+ certain languages.
+
Raises LibError on failure.
"""
pass
@@ -710,7 +749,8 @@
debug=0,
extra_preargs=None,
extra_postargs=None,
- build_temp=None):
+ build_temp=None,
+ target_lang=None):
"""Link a bunch of stuff together to create an executable or
shared library file.
@@ -748,6 +788,10 @@
of course that they supply command-line arguments for the
particular linker being used).
+ 'target_lang' is the target language for which the given objects
+ are being compiled. This allows specific linkage time treatment of
+ certain languages.
+
Raises LinkError on failure.
"""
raise NotImplementedError
@@ -766,13 +810,14 @@
debug=0,
extra_preargs=None,
extra_postargs=None,
- build_temp=None):
+ build_temp=None,
+ target_lang=None):
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)
+ extra_preargs, extra_postargs, build_temp, target_lang)
def link_shared_object (self,
@@ -786,12 +831,13 @@
debug=0,
extra_preargs=None,
extra_postargs=None,
- build_temp=None):
+ build_temp=None,
+ target_lang=None):
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)
+ extra_preargs, extra_postargs, build_temp, target_lang)
def link_executable (self,
@@ -803,11 +849,12 @@
runtime_library_dirs=None,
debug=0,
extra_preargs=None,
- extra_postargs=None):
+ extra_postargs=None,
+ target_lang=None):
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)
+ debug, extra_preargs, extra_postargs, None, target_lang)
# -- Miscellaneous methods -----------------------------------------
diff --git a/Lib/distutils/command/build_ext.py b/Lib/distutils/command/build_ext.py
index 934b457..4bfc20c 100644
--- a/Lib/distutils/command/build_ext.py
+++ b/Lib/distutils/command/build_ext.py
@@ -477,6 +477,9 @@
objects.extend(ext.extra_objects)
extra_args = ext.extra_link_args or []
+ # Detect target language, if not provided
+ language = ext.language or self.compiler.detect_language(sources)
+
self.compiler.link_shared_object(
objects, ext_filename,
libraries=self.get_libraries(ext),
@@ -485,7 +488,8 @@
extra_postargs=extra_args,
export_symbols=self.get_export_symbols(ext),
debug=self.debug,
- build_temp=self.build_temp)
+ build_temp=self.build_temp,
+ target_lang=language)
def swig_sources (self, sources):
diff --git a/Lib/distutils/command/config.py b/Lib/distutils/command/config.py
index 88b1586..9ebe0d9 100644
--- a/Lib/distutils/command/config.py
+++ b/Lib/distutils/command/config.py
@@ -148,7 +148,8 @@
prog = os.path.splitext(os.path.basename(src))[0]
self.compiler.link_executable([obj], prog,
libraries=libraries,
- library_dirs=library_dirs)
+ library_dirs=library_dirs,
+ target_lang=lang)
prog = prog + self.compiler.exe_extension
self.temp_files.append(prog)
diff --git a/Lib/distutils/cygwinccompiler.py b/Lib/distutils/cygwinccompiler.py
index 9aabd8a..a046ee2 100644
--- a/Lib/distutils/cygwinccompiler.py
+++ b/Lib/distutils/cygwinccompiler.py
@@ -140,7 +140,8 @@
debug=0,
extra_preargs=None,
extra_postargs=None,
- build_temp=None):
+ build_temp=None,
+ target_lang=None):
# use separate copies, so we can modify the lists
extra_preargs = copy.copy(extra_preargs or [])
@@ -218,7 +219,8 @@
debug,
extra_preargs,
extra_postargs,
- build_temp)
+ build_temp,
+ target_lang)
# link ()
diff --git a/Lib/distutils/emxccompiler.py b/Lib/distutils/emxccompiler.py
index 7c3ad02..624c0fe 100644
--- a/Lib/distutils/emxccompiler.py
+++ b/Lib/distutils/emxccompiler.py
@@ -102,7 +102,8 @@
debug=0,
extra_preargs=None,
extra_postargs=None,
- build_temp=None):
+ build_temp=None,
+ target_lang=None):
# use separate copies, so we can modify the lists
extra_preargs = copy.copy(extra_preargs or [])
@@ -171,7 +172,8 @@
debug,
extra_preargs,
extra_postargs,
- build_temp)
+ build_temp,
+ target_lang)
# link ()
diff --git a/Lib/distutils/extension.py b/Lib/distutils/extension.py
index d73bb08..7fbeb4e 100644
--- a/Lib/distutils/extension.py
+++ b/Lib/distutils/extension.py
@@ -75,6 +75,9 @@
extension_name.
depends : [string]
list of files that the extension depends on
+ language : string
+ extension language (i.e. "c", "c++", "objc"). Will be detected
+ from the source extensions if not provided.
"""
def __init__ (self, name, sources,
@@ -89,6 +92,7 @@
extra_link_args=None,
export_symbols=None,
depends=None,
+ language=None,
):
assert type(name) is StringType, "'name' must be a string"
@@ -109,6 +113,7 @@
self.extra_link_args = extra_link_args or []
self.export_symbols = export_symbols or []
self.depends = depends or []
+ self.language = language
# class Extension
diff --git a/Lib/distutils/msvccompiler.py b/Lib/distutils/msvccompiler.py
index 65b1143..a2459ad 100644
--- a/Lib/distutils/msvccompiler.py
+++ b/Lib/distutils/msvccompiler.py
@@ -367,8 +367,7 @@
output_libname,
output_dir=None,
debug=0,
- extra_preargs=None,
- extra_postargs=None):
+ target_lang=None):
(objects, output_dir) = self._fix_object_args (objects, output_dir)
output_filename = \
@@ -378,10 +377,6 @@
lib_args = objects + ['/OUT:' + output_filename]
if debug:
pass # XXX what goes here?
- if extra_preargs:
- lib_args[:0] = extra_preargs
- if extra_postargs:
- lib_args.extend (extra_postargs)
try:
self.spawn ([self.lib] + lib_args)
except DistutilsExecError, msg:
@@ -404,7 +399,8 @@
debug=0,
extra_preargs=None,
extra_postargs=None,
- build_temp=None):
+ build_temp=None,
+ target_lang=None):
(objects, output_dir) = self._fix_object_args (objects, output_dir)
(libraries, library_dirs, runtime_library_dirs) = \
diff --git a/Lib/distutils/mwerkscompiler.py b/Lib/distutils/mwerkscompiler.py
index cd66a09..8f62bf7 100644
--- a/Lib/distutils/mwerkscompiler.py
+++ b/Lib/distutils/mwerkscompiler.py
@@ -84,7 +84,8 @@
debug=0,
extra_preargs=None,
extra_postargs=None,
- build_temp=None):
+ build_temp=None,
+ target_lang=None):
# First fixup.
(objects, output_dir) = self._fix_object_args (objects, output_dir)
(libraries, library_dirs, runtime_library_dirs) = \
diff --git a/Lib/distutils/sysconfig.py b/Lib/distutils/sysconfig.py
index e879fa14..cc57188 100644
--- a/Lib/distutils/sysconfig.py
+++ b/Lib/distutils/sysconfig.py
@@ -139,11 +139,13 @@
varies across Unices and is stored in Python's Makefile.
"""
if compiler.compiler_type == "unix":
- (cc, opt, ccshared, ldshared, so_ext) = \
- get_config_vars('CC', 'OPT', 'CCSHARED', 'LDSHARED', 'SO')
+ (cc, cxx, opt, ccshared, ldshared, so_ext) = \
+ get_config_vars('CC', 'CXX', 'OPT', 'CCSHARED', 'LDSHARED', 'SO')
if os.environ.has_key('CC'):
cc = os.environ['CC']
+ if os.environ.has_key('CXX'):
+ cxx = os.environ['CXX']
if os.environ.has_key('CPP'):
cpp = os.environ['CPP']
else:
@@ -163,6 +165,7 @@
preprocessor=cpp,
compiler=cc_cmd,
compiler_so=cc_cmd + ' ' + ccshared,
+ compiler_cxx=cxx,
linker_so=ldshared,
linker_exe=cc)
diff --git a/Lib/distutils/unixccompiler.py b/Lib/distutils/unixccompiler.py
index 692e3eb..2f4546e 100644
--- a/Lib/distutils/unixccompiler.py
+++ b/Lib/distutils/unixccompiler.py
@@ -57,6 +57,7 @@
executables = {'preprocessor' : None,
'compiler' : ["cc"],
'compiler_so' : ["cc"],
+ 'compiler_cxx' : ["cc"],
'linker_so' : ["cc", "-shared"],
'linker_exe' : ["cc"],
'archiver' : ["ar", "-cr"],
@@ -114,7 +115,7 @@
raise CompileError, msg
def create_static_lib(self, objects, output_libname,
- output_dir=None, debug=0):
+ output_dir=None, debug=0, target_lang=None):
objects, output_dir = self._fix_object_args(objects, output_dir)
output_filename = \
@@ -143,7 +144,7 @@
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):
+ extra_postargs=None, build_temp=None, target_lang=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)
@@ -167,9 +168,12 @@
self.mkpath(os.path.dirname(output_filename))
try:
if target_desc == CCompiler.EXECUTABLE:
- self.spawn(self.linker_exe + ld_args)
+ linker = self.linker_exe[:]
else:
- self.spawn(self.linker_so + ld_args)
+ linker = self.linker_so[:]
+ if target_lang == "c++" and self.compiler_cxx:
+ linker[0] = self.compiler_cxx[0]
+ self.spawn(linker + ld_args)
except DistutilsExecError, msg:
raise LinkError, msg
else: