Commit 47474c30 authored by Gustavo Niemeyer's avatar Gustavo Niemeyer

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().
parent 8c157b7b
...@@ -146,8 +146,7 @@ class BCPPCompiler(CCompiler) : ...@@ -146,8 +146,7 @@ class BCPPCompiler(CCompiler) :
output_libname, output_libname,
output_dir=None, output_dir=None,
debug=0, debug=0,
extra_preargs=None, target_lang=None):
extra_postargs=None):
(objects, output_dir) = self._fix_object_args (objects, output_dir) (objects, output_dir) = self._fix_object_args (objects, output_dir)
output_filename = \ output_filename = \
...@@ -157,10 +156,6 @@ class BCPPCompiler(CCompiler) : ...@@ -157,10 +156,6 @@ class BCPPCompiler(CCompiler) :
lib_args = [output_filename, '/u'] + objects lib_args = [output_filename, '/u'] + objects
if debug: if debug:
pass # XXX what goes here? pass # XXX what goes here?
if extra_preargs:
lib_args[:0] = extra_preargs
if extra_postargs:
lib_args.extend (extra_postargs)
try: try:
self.spawn ([self.lib] + lib_args) self.spawn ([self.lib] + lib_args)
except DistutilsExecError, msg: except DistutilsExecError, msg:
...@@ -183,7 +178,8 @@ class BCPPCompiler(CCompiler) : ...@@ -183,7 +178,8 @@ class BCPPCompiler(CCompiler) :
debug=0, debug=0,
extra_preargs=None, extra_preargs=None,
extra_postargs=None, extra_postargs=None,
build_temp=None): build_temp=None,
target_lang=None):
# XXX this ignores 'build_temp'! should follow the lead of # XXX this ignores 'build_temp'! should follow the lead of
# msvccompiler.py # msvccompiler.py
......
...@@ -74,6 +74,19 @@ class CCompiler: ...@@ -74,6 +74,19 @@ class CCompiler:
shared_lib_format = None # prob. same as static_lib_format shared_lib_format = None # prob. same as static_lib_format
exe_extension = None # string 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, def __init__ (self,
verbose=0, verbose=0,
...@@ -572,6 +585,27 @@ class CCompiler: ...@@ -572,6 +585,27 @@ class CCompiler:
# _need_link () # _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 ------------------------------------------------ # -- Worker methods ------------------------------------------------
# (must be implemented by subclasses) # (must be implemented by subclasses)
...@@ -671,7 +705,8 @@ class CCompiler: ...@@ -671,7 +705,8 @@ class CCompiler:
objects, objects,
output_libname, output_libname,
output_dir=None, output_dir=None,
debug=0): debug=0,
target_lang=None):
"""Link a bunch of stuff together to create a static library file. """Link a bunch of stuff together to create a static library file.
The "bunch of stuff" consists of the list of object files supplied The "bunch of stuff" consists of the list of object files supplied
as 'objects', the extra object files supplied to as 'objects', the extra object files supplied to
...@@ -688,6 +723,10 @@ class CCompiler: ...@@ -688,6 +723,10 @@ class CCompiler:
compile step where this matters: the 'debug' flag is included here compile step where this matters: the 'debug' flag is included here
just for consistency). 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. Raises LibError on failure.
""" """
pass pass
...@@ -710,7 +749,8 @@ class CCompiler: ...@@ -710,7 +749,8 @@ class CCompiler:
debug=0, debug=0,
extra_preargs=None, extra_preargs=None,
extra_postargs=None, extra_postargs=None,
build_temp=None): build_temp=None,
target_lang=None):
"""Link a bunch of stuff together to create an executable or """Link a bunch of stuff together to create an executable or
shared library file. shared library file.
...@@ -748,6 +788,10 @@ class CCompiler: ...@@ -748,6 +788,10 @@ class CCompiler:
of course that they supply command-line arguments for the of course that they supply command-line arguments for the
particular linker being used). 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. Raises LinkError on failure.
""" """
raise NotImplementedError raise NotImplementedError
...@@ -766,13 +810,14 @@ class CCompiler: ...@@ -766,13 +810,14 @@ class CCompiler:
debug=0, debug=0,
extra_preargs=None, extra_preargs=None,
extra_postargs=None, extra_postargs=None,
build_temp=None): build_temp=None,
target_lang=None):
self.link(CCompiler.SHARED_LIBRARY, objects, self.link(CCompiler.SHARED_LIBRARY, objects,
self.library_filename(output_libname, lib_type='shared'), self.library_filename(output_libname, lib_type='shared'),
output_dir, output_dir,
libraries, library_dirs, runtime_library_dirs, libraries, library_dirs, runtime_library_dirs,
export_symbols, debug, export_symbols, debug,
extra_preargs, extra_postargs, build_temp) extra_preargs, extra_postargs, build_temp, target_lang)
def link_shared_object (self, def link_shared_object (self,
...@@ -786,12 +831,13 @@ class CCompiler: ...@@ -786,12 +831,13 @@ class CCompiler:
debug=0, debug=0,
extra_preargs=None, extra_preargs=None,
extra_postargs=None, extra_postargs=None,
build_temp=None): build_temp=None,
target_lang=None):
self.link(CCompiler.SHARED_OBJECT, objects, self.link(CCompiler.SHARED_OBJECT, objects,
output_filename, output_dir, output_filename, output_dir,
libraries, library_dirs, runtime_library_dirs, libraries, library_dirs, runtime_library_dirs,
export_symbols, debug, export_symbols, debug,
extra_preargs, extra_postargs, build_temp) extra_preargs, extra_postargs, build_temp, target_lang)
def link_executable (self, def link_executable (self,
...@@ -803,11 +849,12 @@ class CCompiler: ...@@ -803,11 +849,12 @@ class CCompiler:
runtime_library_dirs=None, runtime_library_dirs=None,
debug=0, debug=0,
extra_preargs=None, extra_preargs=None,
extra_postargs=None): extra_postargs=None,
target_lang=None):
self.link(CCompiler.EXECUTABLE, objects, self.link(CCompiler.EXECUTABLE, objects,
self.executable_filename(output_progname), output_dir, self.executable_filename(output_progname), output_dir,
libraries, library_dirs, runtime_library_dirs, None, libraries, library_dirs, runtime_library_dirs, None,
debug, extra_preargs, extra_postargs, None) debug, extra_preargs, extra_postargs, None, target_lang)
# -- Miscellaneous methods ----------------------------------------- # -- Miscellaneous methods -----------------------------------------
......
...@@ -477,6 +477,9 @@ class build_ext (Command): ...@@ -477,6 +477,9 @@ class build_ext (Command):
objects.extend(ext.extra_objects) objects.extend(ext.extra_objects)
extra_args = ext.extra_link_args or [] 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( self.compiler.link_shared_object(
objects, ext_filename, objects, ext_filename,
libraries=self.get_libraries(ext), libraries=self.get_libraries(ext),
...@@ -485,7 +488,8 @@ class build_ext (Command): ...@@ -485,7 +488,8 @@ class build_ext (Command):
extra_postargs=extra_args, extra_postargs=extra_args,
export_symbols=self.get_export_symbols(ext), export_symbols=self.get_export_symbols(ext),
debug=self.debug, debug=self.debug,
build_temp=self.build_temp) build_temp=self.build_temp,
target_lang=language)
def swig_sources (self, sources): def swig_sources (self, sources):
......
...@@ -148,7 +148,8 @@ class config (Command): ...@@ -148,7 +148,8 @@ class config (Command):
prog = os.path.splitext(os.path.basename(src))[0] prog = os.path.splitext(os.path.basename(src))[0]
self.compiler.link_executable([obj], prog, self.compiler.link_executable([obj], prog,
libraries=libraries, libraries=libraries,
library_dirs=library_dirs) library_dirs=library_dirs,
target_lang=lang)
prog = prog + self.compiler.exe_extension prog = prog + self.compiler.exe_extension
self.temp_files.append(prog) self.temp_files.append(prog)
......
...@@ -140,7 +140,8 @@ class CygwinCCompiler (UnixCCompiler): ...@@ -140,7 +140,8 @@ class CygwinCCompiler (UnixCCompiler):
debug=0, debug=0,
extra_preargs=None, extra_preargs=None,
extra_postargs=None, extra_postargs=None,
build_temp=None): build_temp=None,
target_lang=None):
# use separate copies, so we can modify the lists # use separate copies, so we can modify the lists
extra_preargs = copy.copy(extra_preargs or []) extra_preargs = copy.copy(extra_preargs or [])
...@@ -218,7 +219,8 @@ class CygwinCCompiler (UnixCCompiler): ...@@ -218,7 +219,8 @@ class CygwinCCompiler (UnixCCompiler):
debug, debug,
extra_preargs, extra_preargs,
extra_postargs, extra_postargs,
build_temp) build_temp,
target_lang)
# link () # link ()
......
...@@ -102,7 +102,8 @@ class EMXCCompiler (UnixCCompiler): ...@@ -102,7 +102,8 @@ class EMXCCompiler (UnixCCompiler):
debug=0, debug=0,
extra_preargs=None, extra_preargs=None,
extra_postargs=None, extra_postargs=None,
build_temp=None): build_temp=None,
target_lang=None):
# use separate copies, so we can modify the lists # use separate copies, so we can modify the lists
extra_preargs = copy.copy(extra_preargs or []) extra_preargs = copy.copy(extra_preargs or [])
...@@ -171,7 +172,8 @@ class EMXCCompiler (UnixCCompiler): ...@@ -171,7 +172,8 @@ class EMXCCompiler (UnixCCompiler):
debug, debug,
extra_preargs, extra_preargs,
extra_postargs, extra_postargs,
build_temp) build_temp,
target_lang)
# link () # link ()
......
...@@ -75,6 +75,9 @@ class Extension: ...@@ -75,6 +75,9 @@ class Extension:
extension_name. extension_name.
depends : [string] depends : [string]
list of files that the extension depends on 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, def __init__ (self, name, sources,
...@@ -89,6 +92,7 @@ class Extension: ...@@ -89,6 +92,7 @@ class Extension:
extra_link_args=None, extra_link_args=None,
export_symbols=None, export_symbols=None,
depends=None, depends=None,
language=None,
): ):
assert type(name) is StringType, "'name' must be a string" assert type(name) is StringType, "'name' must be a string"
...@@ -109,6 +113,7 @@ class Extension: ...@@ -109,6 +113,7 @@ class Extension:
self.extra_link_args = extra_link_args or [] self.extra_link_args = extra_link_args or []
self.export_symbols = export_symbols or [] self.export_symbols = export_symbols or []
self.depends = depends or [] self.depends = depends or []
self.language = language
# class Extension # class Extension
......
...@@ -367,8 +367,7 @@ class MSVCCompiler (CCompiler) : ...@@ -367,8 +367,7 @@ class MSVCCompiler (CCompiler) :
output_libname, output_libname,
output_dir=None, output_dir=None,
debug=0, debug=0,
extra_preargs=None, target_lang=None):
extra_postargs=None):
(objects, output_dir) = self._fix_object_args (objects, output_dir) (objects, output_dir) = self._fix_object_args (objects, output_dir)
output_filename = \ output_filename = \
...@@ -378,10 +377,6 @@ class MSVCCompiler (CCompiler) : ...@@ -378,10 +377,6 @@ class MSVCCompiler (CCompiler) :
lib_args = objects + ['/OUT:' + output_filename] lib_args = objects + ['/OUT:' + output_filename]
if debug: if debug:
pass # XXX what goes here? pass # XXX what goes here?
if extra_preargs:
lib_args[:0] = extra_preargs
if extra_postargs:
lib_args.extend (extra_postargs)
try: try:
self.spawn ([self.lib] + lib_args) self.spawn ([self.lib] + lib_args)
except DistutilsExecError, msg: except DistutilsExecError, msg:
...@@ -404,7 +399,8 @@ class MSVCCompiler (CCompiler) : ...@@ -404,7 +399,8 @@ class MSVCCompiler (CCompiler) :
debug=0, debug=0,
extra_preargs=None, extra_preargs=None,
extra_postargs=None, extra_postargs=None,
build_temp=None): build_temp=None,
target_lang=None):
(objects, output_dir) = self._fix_object_args (objects, output_dir) (objects, output_dir) = self._fix_object_args (objects, output_dir)
(libraries, library_dirs, runtime_library_dirs) = \ (libraries, library_dirs, runtime_library_dirs) = \
......
...@@ -84,7 +84,8 @@ class MWerksCompiler (CCompiler) : ...@@ -84,7 +84,8 @@ class MWerksCompiler (CCompiler) :
debug=0, debug=0,
extra_preargs=None, extra_preargs=None,
extra_postargs=None, extra_postargs=None,
build_temp=None): build_temp=None,
target_lang=None):
# First fixup. # First fixup.
(objects, output_dir) = self._fix_object_args (objects, output_dir) (objects, output_dir) = self._fix_object_args (objects, output_dir)
(libraries, library_dirs, runtime_library_dirs) = \ (libraries, library_dirs, runtime_library_dirs) = \
......
...@@ -139,11 +139,13 @@ def customize_compiler(compiler): ...@@ -139,11 +139,13 @@ def customize_compiler(compiler):
varies across Unices and is stored in Python's Makefile. varies across Unices and is stored in Python's Makefile.
""" """
if compiler.compiler_type == "unix": if compiler.compiler_type == "unix":
(cc, opt, ccshared, ldshared, so_ext) = \ (cc, cxx, opt, ccshared, ldshared, so_ext) = \
get_config_vars('CC', 'OPT', 'CCSHARED', 'LDSHARED', 'SO') get_config_vars('CC', 'CXX', 'OPT', 'CCSHARED', 'LDSHARED', 'SO')
if os.environ.has_key('CC'): if os.environ.has_key('CC'):
cc = os.environ['CC'] cc = os.environ['CC']
if os.environ.has_key('CXX'):
cxx = os.environ['CXX']
if os.environ.has_key('CPP'): if os.environ.has_key('CPP'):
cpp = os.environ['CPP'] cpp = os.environ['CPP']
else: else:
...@@ -163,6 +165,7 @@ def customize_compiler(compiler): ...@@ -163,6 +165,7 @@ def customize_compiler(compiler):
preprocessor=cpp, preprocessor=cpp,
compiler=cc_cmd, compiler=cc_cmd,
compiler_so=cc_cmd + ' ' + ccshared, compiler_so=cc_cmd + ' ' + ccshared,
compiler_cxx=cxx,
linker_so=ldshared, linker_so=ldshared,
linker_exe=cc) linker_exe=cc)
......
...@@ -57,6 +57,7 @@ class UnixCCompiler(CCompiler): ...@@ -57,6 +57,7 @@ class UnixCCompiler(CCompiler):
executables = {'preprocessor' : None, executables = {'preprocessor' : None,
'compiler' : ["cc"], 'compiler' : ["cc"],
'compiler_so' : ["cc"], 'compiler_so' : ["cc"],
'compiler_cxx' : ["cc"],
'linker_so' : ["cc", "-shared"], 'linker_so' : ["cc", "-shared"],
'linker_exe' : ["cc"], 'linker_exe' : ["cc"],
'archiver' : ["ar", "-cr"], 'archiver' : ["ar", "-cr"],
...@@ -114,7 +115,7 @@ class UnixCCompiler(CCompiler): ...@@ -114,7 +115,7 @@ class UnixCCompiler(CCompiler):
raise CompileError, msg raise CompileError, msg
def create_static_lib(self, objects, output_libname, 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) objects, output_dir = self._fix_object_args(objects, output_dir)
output_filename = \ output_filename = \
...@@ -143,7 +144,7 @@ class UnixCCompiler(CCompiler): ...@@ -143,7 +144,7 @@ class UnixCCompiler(CCompiler):
output_filename, output_dir=None, libraries=None, output_filename, output_dir=None, libraries=None,
library_dirs=None, runtime_library_dirs=None, library_dirs=None, runtime_library_dirs=None,
export_symbols=None, debug=0, extra_preargs=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) objects, output_dir = self._fix_object_args(objects, output_dir)
libraries, library_dirs, runtime_library_dirs = \ libraries, library_dirs, runtime_library_dirs = \
self._fix_lib_args(libraries, library_dirs, runtime_library_dirs) self._fix_lib_args(libraries, library_dirs, runtime_library_dirs)
...@@ -167,9 +168,12 @@ class UnixCCompiler(CCompiler): ...@@ -167,9 +168,12 @@ class UnixCCompiler(CCompiler):
self.mkpath(os.path.dirname(output_filename)) self.mkpath(os.path.dirname(output_filename))
try: try:
if target_desc == CCompiler.EXECUTABLE: if target_desc == CCompiler.EXECUTABLE:
self.spawn(self.linker_exe + ld_args) linker = self.linker_exe[:]
else: 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: except DistutilsExecError, msg:
raise LinkError, msg raise LinkError, msg
else: else:
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment