Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to tell which specific compiler will be invoked for a Python C extension: GCC or Clang?

I have a Python C++ extension that requires the following compilation flags when compiled using Clang on OS X:

CPPFLAGS='-std=c++11 -stdlib=libc++ -mmacosx-version-min=10.8'
LDFLAGS='-lc++'

Detecting OS X in my setup.py is easy enough. I can do this:

if sys.prefix == 'darwin':
    compile_args.append(['-mmacosx-version-min=10.8', '-stdlib=libc++'])
    link_args.append('-lc++')

(See here for full context)

However, on GCC this compilation flag is invalid. So, compilation will fail if someone will try to use GCC on OS X if I write the setup.py this way.

GCC and Clang support different compiler flags. So, I need to know which compiler will be invoked, so I can send different flags. What is the right way to detect the compiler in the setup.py?

Edit 1:
Note that no Python exception is raised for compilation errors:

$ python setup.py build_ext --inplace
running build_ext
building 'spacy.strings' extension
gcc -pthread -fno-strict-aliasing -g -O2 -DNDEBUG -g -fwrapv -O3 -Wall -Wstrict-prototypes -fPIC -c spacy/strings.cpp -o build/temp.linux-x86_64-2.7/spacy/strings.o -O3 -mmacosx-version-min=10.8 -stdlib=libc++
gcc: error: unrecognized command line option ‘-mmacosx-version-min=10.8’
gcc: error: unrecognized command line option ‘-stdlib=libc++’
error: command 'gcc' failed with exit status 1
$
like image 323
syllogism_ Avatar asked Feb 21 '15 02:02

syllogism_


People also ask

Does clang define __ GNUC __?

(GNU C is a language, GCC is a compiler for that language.Clang defines __GNUC__ / __GNUC_MINOR__ / __GNUC_PATCHLEVEL__ according to the version of gcc that it claims full compatibility with.

Is GCC the same as clang?

Clang is much faster and uses far less memory than GCC. Clang aims to provide extremely clear and concise diagnostics (error and warning messages), and includes support for expressive diagnostics. GCC's warnings are sometimes acceptable, but are often confusing and it does not support expressive diagnostics.

Does Python use clang?

Note that the Python bindings are part of the source distribution of Clang.

Does GCC use clang?

Clang is compatible with GCC. Its command-line interface shares many of GCC's flags and options. Clang implements many GNU language extensions and compiler intrinsics, some of which are purely for compatibility.


1 Answers

Add the following code to your setup.py. It explicitly detects which flags are accepted by the compiler and then only those are added.

# check whether compiler supports a flag
def has_flag(compiler, flagname):
    import tempfile
    from distutils.errors import CompileError
    with tempfile.NamedTemporaryFile('w', suffix='.cpp') as f:
        f.write('int main (int argc, char **argv) { return 0; }')
        try:
            compiler.compile([f.name], extra_postargs=[flagname])
        except CompileError:
            return False
    return True


# filter flags, returns list of accepted flags
def flag_filter(compiler, *flags):
    result = []
    for flag in flags:
        if has_flag(compiler, flag):
            result.append(flag)
    return result


class BuildExt(build_ext):
    # these flags are not checked and always added
    compile_flags = {"msvc": ['/EHsc'], "unix": ["-std=c++11"]}

    def build_extensions(self):
        ct = self.compiler.compiler_type
        opts = self.compile_flags.get(ct, [])
        if ct == 'unix':
            # only add flags which pass the flag_filter
            opts += flag_filter(self.compiler,
                                '-fvisibility=hidden', '-stdlib=libc++', '-std=c++14')
        for ext in self.extensions:
            ext.extra_compile_args = opts
        build_ext.build_extensions(self)

setup(
   cmdclass=dict(build_ext=BuildExt),
   # other options...
)

The has_flag method was taken from this pybind11 example. https://github.com/pybind/python_example

like image 147
olq_plo Avatar answered Oct 15 '22 06:10

olq_plo