Как узнать, какой компилятор будет вызываться для расширения Python C в setuptools?

У меня есть расширение Python C++, для которого требуются следующие флаги компиляции при компиляции с помощью clang в OSX:

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

Обнаружить OSX в моем файле setup.py достаточно просто. Я могу сделать это:

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

(См. https://github.com/honnibal/spaCy/blob/ba1d3ddd7f527d2e6e41b86da0f2887cc4dec83a/setup.py#L70 для полного контекста)

Однако в GCC этот флаг компиляции недействителен. Таким образом, компиляция завершится ошибкой, если кто-то попытается использовать GCC на OSX, если я напишу setup.py таким образом.

GCC и clang поддерживают разные флаги компилятора. Итак, мне нужно знать, какой компилятор будет вызываться, чтобы я мог отправлять разные флаги. Как правильно определить компилятор в setup.py?

Редактировать 1:

Обратите внимание, что исключение Python для ошибок компиляции не возникает:

$ 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
$

person syllogism_    schedule 21.02.2015    source источник
comment
Какое исключение возникает (в вашем скрипте Python), когда вы передаете GCC плохой флаг? Правильный путь будет try: send_flags_for_clang() except ThatException: send_flags_for_gcc().   -  person Two-Bit Alchemist    schedule 21.02.2015
comment
См. Изменить --- никаких исключений не возникает.   -  person syllogism_    schedule 21.02.2015


Ответы (2)


Я наткнулся на ваш вопрос, так как мне нужен такой же переключатель. Кроме того, в моем случае sys.prefix не очень хорошо, так как флаги для clang вне зависимости от платформы.

Я не уверен, что это идеально, но вот то, что работает лучше всего для меня. Итак, я проверяю, установлена ​​ли переменная CC; если нет, я проверяю, куда, как мне кажется, смотрит distutils.

Любое лучшее решение приветствуется!

import os
import distutils

try:
    if os.environ['CC'] == "clang":
        clang = True
except KeyError:
    clang = False

if clang or distutils.sysconfig_get_config_vars()['CC'] == 'clang':
    try:
        _ = os.environ['CFLAGS']
    except KeyError:
        os.environ['CFLAGS'] = ""
    os.environ['CFLAGS'] += " -Wno-unused-function"
    os.environ['CFLAGS'] += " -Wno-int-conversion"
    os.environ['CFLAGS'] += " -Wno-incompatible-pointer-types

Примечание для сварливых парней: мне бы очень хотелось использовать параметр extra_compile_args, но он ставит флаги в неправильное положение в команде компиляции clang.

person xoolive    schedule 11.06.2016

Добавьте следующий код в файл setup.py. Он явно определяет, какие флаги принимаются компилятором, а затем добавляются только они.

# 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...
)

Метод has_flag был взят из этого примера pybind11. https://github.com/pybind/python_example

person olq_plo    schedule 04.02.2019