我有一个Python C ++扩展,在OSX上使用clang编译时需要以下编译标志:
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上,此编译标志无效。因此,如果有人试图在OSX上使用GCC,如果我用这种方式编写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
$
答案 0 :(得分:2)
我遇到了你的问题,因为我需要同样的开关。此外,在我的情况下, [\p{IsHiragana}一-龯{}\p{Lm}]+
不是很好,因为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
编译命令中的错误位置。 / p>
答案 1 :(得分:0)
将以下代码添加到您的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
答案 2 :(得分:0)
这是一个交叉编译器和跨平台的解决方案:
from setuptools import setup
from setuptools.command.build_ext import build_ext
class build_ext_ex(build_ext):
extra_args = {
'extension_name': {
'clang': (
['-std=c++11', '-stdlib=libc++', '-mmacosx-version-min=10.8'],
['-lc++']
)
}
}
def build_extension(self, ext):
extra_args = self.extra_args.get(ext.name)
if extra_args is not None:
# only Unix compilers and their ports have `compiler_so`
compiler_cmd = getattr(self.compiler, 'compiler_so', None)
# account for absolute path and Windows version
if compiler_cmd is not None and 'clang' in compiler_cmd[0]:
cname = 'clang'
else:
cname = self.compiler.compiler_type
extra_args = extra_args.get(cname)
if extra_args is not None:
ext.extra_compile_args = extra_args[0]
ext.extra_link_args = extra_args[1]
build_ext.build_extension(self, ext)
setup(
...
cmdclass = {'build_ext': build_ext_ex},
...
)
... 以及支持的编译器类型列表(由 setup.py build_ext --help-compiler
返回):
--compiler=bcpp Borland C++ Compiler
--compiler=cygwin Cygwin port of GNU C Compiler for Win32
--compiler=mingw32 Mingw32 port of GNU C Compiler for Win32
--compiler=msvc Microsoft Visual C++
--compiler=unix standard UNIX-style compiler
如果您遇到与@xoolive 相同的问题,您可以改写 build_extensions()
并将选项分别附加到 self.compiler.compiler_so
和 self.compiler.linker_so
的末尾。