Commit 7ae8c4f3 authored by Kirill Smelkov's avatar Kirill Smelkov

pyx.build: Allow to combine C and C++ sources in one extension

The next patch will add `go` to Pyx API and correspondingly C, C++ and Pyx
level tests for it that will go into _golang_test.pyx extension. For
C-level test we'll use C source file - to verify that libgolang.h could
be used by C projects with C compiler, while for C++ and Pyx-level tests
the sources will be in C++. Thus _golang_test.so will be build from both
C and C++ sources.

This creates a problem: distutils / setuptools use the _same_ compiler
to compile both C and C++ sources and only use C++ compiler at link
stage. Thus, as it is not possible to tune compiler that is used only
for C++ sources, and also as it is not possible to provide per-source
flags, when compiling C-level test, the compiler will be invoked with
`-std=c++11` option that we inject. Gcc tolerates that and only prints a
warning, but Clang considers that an error and gives:

	error: invalid argument '-std=c++11' not allowed with 'C'`

A proper fix would be to change the build system from distutils to
something more flexible that uses C++ compiler for C++ sources and C
compiler for C sources and allows to tune per-unit flags. However it is
not a small step at this stage.

-> Use workaround and tweak options that are used when compiling sources
depending on whether it is C or C++.
parent ce8152a2
......@@ -65,9 +65,59 @@ def _findpkg(pkgname): # -> _PyPkg
pypkg.path = path
return pypkg
# _build_ext amends setuptools_dso.build_ext to allow combining C and C++
# sources in one extension without hitting `error: invalid argument
# '-std=c++11' not allowed with 'C'`.
_dso_build_ext = setuptools_dso.build_ext
class _build_ext(_dso_build_ext):
def build_extension(self, ext):
# wrap _compiler <src> -> <obj> with our code
_compile = self.compiler._compile
def _(obj, src, ext, cc_args, extra_postargs, pp_opts):
# filter_out removes arguments that start with argprefix
cc_args = cc_args[:]
extra_postargs = extra_postargs[:]
pp_opts = pp_opts[:]
def filter_out(argprefix):
for l in (cc_args, extra_postargs, pp_opts):
_ = []
for arg in l:
if not arg.startswith(argprefix):
_.append(arg)
l[:] = _
# filter-out C++ only options from non-C++ sources
#
# reason: while gcc only warns about -std=c++ passed with C source,
# clang considers that an error. Given that with distutils /
# setuptools the _same_ compiler is used to compile C and C++
# sources, and that it is not possible to provide per-source flags,
# without filtering, that leads to inability to use both C and C++
# sources in one extension.
cxx = (self.compiler.language_map[ext] == 'c++')
if not cxx:
filter_out('-std=c++')
filter_out('-std=gnu++')
_compile(obj, src, ext, cc_args, extra_postargs, pp_opts)
self.compiler._compile = _
try:
_dso_build_ext.build_extension(self, ext) # super doesn't work for _dso_build_ext
finally:
self.compiler._compile = _compile
# setup should be used instead of setuptools.setup
def setup(**kw):
return setuptools_dso.setup(**kw)
# setuptools_dso.setup hardcodes setuptools_dso.build_ext to be used.
# temporarily inject our code there.
_ = setuptools_dso.build_ext
try:
setuptools_dso.build_ext = _build_ext
setuptools_dso.setup(**kw)
finally:
setuptools_dso.build_ext = _
# Extension should be used to build extensions that use pygolang.
#
......
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