我有一个Python C ++的扩展,需要以下编译标志使用的OSX铛编译时:
CPPFLAGS='-std=c++11 -stdlib=libc++ -mmacosx-version-min=10.8'
LDFLAGS='-lc++'
在我的setup.py检测OSX是很容易的。我可以做这个:
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和铿锵支持不同的编译器标志。所以,我需要知道哪些编译器将被调用,这样我就可以发送不同的标志。什么是检测在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
$
我偶然发现了你的问题,因为我需要同类型的交换机。此外,在我的情况,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
编译命令错误的位置。
下面的代码添加到您的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