如何告诉distutils使用gcc?

63

我想使用Cython将一个包含C++和OpenMP代码的测试项目进行封装,并通过setup.py文件使用distutils进行构建。我的文件内容如下:

from distutils.core import setup
from distutils.extension import Extension
from Cython.Build import cythonize
from Cython.Distutils import build_ext


modules = [Extension("Interface",
                     ["Interface.pyx", "Parallel.cpp"],
                     language = "c++",
                     extra_compile_args=["-fopenmp"],
                     extra_link_args=["-fopenmp"])]

for e in modules:
    e.cython_directives = {"embedsignature" : True}

setup(name="Interface",
     cmdclass={"build_ext": build_ext},
     ext_modules=modules)
-fopenmp标志用于gcc与OpenMP编译和链接。但是,如果我只是调用
cls ~/workspace/CythonOpenMP/src $ python3 setup.py build

因为编译器是Clang,所以无法识别此标志:

running build
running build_ext
skipping 'Interface.cpp' Cython extension (up-to-date)
building 'Interface' extension
cc -Wno-unused-result -fno-common -dynamic -DNDEBUG -g -O3 -Wall -Wstrict-prototypes -I/usr/local/include -I/usr/local/opt/sqlite/include -I/usr/local/Cellar/python3/3.3.0/Frameworks/Python.framework/Versions/3.3/include/python3.3m -c Interface.cpp -o build/temp.macosx-10.8-x86_64-3.3/Interface.o -fopenmp
clang: warning: argument unused during compilation: '-fopenmp'
cc -Wno-unused-result -fno-common -dynamic -DNDEBUG -g -O3 -Wall -Wstrict-prototypes -I/usr/local/include -I/usr/local/opt/sqlite/include -I/usr/local/Cellar/python3/3.3.0/Frameworks/Python.framework/Versions/3.3/include/python3.3m -c Parallel.cpp -o build/temp.macosx-10.8-x86_64-3.3/Parallel.o -fopenmp
clang: warning: argument unused during compilation: '-fopenmp'
Parallel.cpp:24:10: warning: unknown pragma ignored [-Wunknown-pragmas]
        #pragma omp parallel for
                ^
1 warning generated.
c++ -bundle -undefined dynamic_lookup -L/usr/local/lib -L/usr/local/opt/sqlite/lib build/temp.macosx-10.8-x86_64-3.3/Interface.o build/temp.macosx-10.8-x86_64-3.3/Parallel.o -o build/lib.macosx-10.8-x86_64-3.3/Interface.so -fopenmp
ld: library not found for -lgomp
clang: error: linker command failed with exit code 1 (use -v to see invocation)
error: command 'c++' failed with exit status 1

我曾尝试指定gcc,但没有成功:

cls ~/workspace/CythonOpenMP/src $ python3 setup.py build --compiler=g++-4.7
running build
running build_ext
error: don't know how to compile C/C++ code on platform 'posix' with 'g++-4.7' compiler

我该如何告诉distutils使用gcc?

6个回答

59
尝试在setup.py中使用os.environ来设置"CC"环境变量。

27
os.environ["CC"] = "g++-4.7";os.environ["CXX"] = "g++-4.7" 已经生效。 - clstaudt
7
对我来说这行不通。我的问题是setup.py想要使用icc。当我设置CC=gcc时,它确实尝试使用gcc,但它仍然使用适用于icc的命令行参数,其中包括-fp-model strict,而gcc不理解,并且中止。因此,似乎仅设置CC并不是正确的方法。 - amaurea
2
Distutils不会检查CXX,因此设置可能会让你感到困惑。你可能想要删除添加"CXX"的建议,因为这是误导性的。 - SethMMorton
1
psutil.py 部分地忽略了 CC 设置,因此我找到了一种非常丑陋的方法,在 Solaris 11 上进行构建:ln -s /usr/bin/gcc /usr/bin/cc - Philip Kearns
2
我还发现CC设置部分被忽略了。 - Lydia Duncan

23

我刚刚查看了distutils源代码,发现--compiler选项期望输入"unix"、"msvc"、"cygwin"、"mingw32"、"bcpp"或者"emx"。它会通过检查环境变量CC来确定你想使用的编译器名称。试着像这样调用构建:

CC=gcc python setup.py build

你不需要设置 CXX,它不会检查那个。


在Ubuntu 12.04上,它实际上并不查看CXX环境变量,这不是人们所期望的。 (当然,在其他平台上也可能不检查) - hetepeperfan
@hetepeperfan,我很难理解你的评论。你是赞成还是反对这个答案? - SethMMorton
2
在像autotools、CMake(生成Makefiles)和Makefiles这样的构建系统中,它们会检查CC和CXX环境变量。然后在makefile中执行$(CC) -c csource.c$(CXX) -c cppsource.cpp来创建目标文件。而显然distunitils违反了这些约定。这就是为什么我点赞你的答案,因为“你不需要设置CXX”这句话解决了我的问题,但是许多使用上述构建工具的人会期望CC用于构建C程序,而CXX用于构建C++程序。 - hetepeperfan
我理解你的意思。是的,确实令人困惑。我不确定原始作者是否在使用distutils时考虑到了整个事情。 - SethMMorton
在 macOS 中,我还必须设置 CXX=g++-9 才能使其正常工作。否则它会使用 clang++。 - rvimieiro

22

如果其他人在Windows下遇到相同的问题(其中CC环境变量没有任何作用):

  • 创建文件"C:\Python27\Lib\distutils\distutils.cfg"并在其中编写以下内容:

代码:

[build]
compiler = mingw32
  • 从文件 "C:\Python27\Lib\distutils\cygwinccompiler.py" 中删除所有 "-mno-cygwin" gcc 选项:

这样做:

    self.set_executables(compiler='gcc -mno-cygwin -O -Wall',
                         compiler_so='gcc -mno-cygwin -mdll -O -Wall',
                         compiler_cxx='g++ -mno-cygwin -O -Wall',
                         linker_exe='gcc -mno-cygwin',
                         linker_so='%s -mno-cygwin %s %s'
                                    % (self.linker_dll, shared_option,
                                       entry_point))
self.set_executables(compiler='gcc -O -Wall',
                     compiler_so='gcc -mdll -O -Wall',
                     compiler_cxx='g++ -O -Wall',
                     linker_exe='gcc',
                     linker_so='%s %s %s'
                                % (self.linker_dll, shared_option,
                                   entry_point))

如果您使用的是最近版本的gcc,那么第二点可能是必要的,因为已经删除了弃用选项-mno-cygwin

希望这能有所帮助,即使它与原帖的实际需求无直接关系(但仍然与问题的标题有关...)


1
我几分钟前还在苦恼这个问题,但现在我已经明白了。谢谢!我们为什么要向distutils添加一个新文件呢? - thwildfire
现在是2014年,我有GCC版本4.3.3和Python版本3.4。我已经尝试了您的解决方案,但没有结果。我得到了相同的错误。我在配置文件中写入了[build] compiler = mingw32,并删除了-mcygwin... - the_prole
我的答案可能已经过时了。这是完全有可能的。如果是这种情况,我很抱歉,但是我已经很久没有在Windows下工作可移植性方面的问题了(几个月以来一直在进行“Linux工作”),实际上现在也无法帮助您解决这个问题......请确保您在正确的位置创建了distutils.cfg文件(该文件的要求可能已更改)。您是否尝试直接使用python3 setup.py build --compiler=mingw32进行编译? - Gauthier Boaglio

4
根据这篇维基,Python 3.4之后的版本不再支持MinGW。 Windows上的CPython 3.7使用MSC v.1916编译。使用上述方法并在distutils.cfg中尝试时,将会从distutils收到一个错误:Unknown MS Compiler Version 1916。看起来它在其cygwincompiler.py文件(也负责MinGW)中有一个硬编码的msvcr库表,该文件已知的最后一个版本是来自VS2010 / MSVC 10.0的1600版本。

2
你找到解决方案了吗? - Андрей Севостьянов

1

发现了这个,但是 python setup.py build --compiler=g++ 的结果和上面一样。 - clstaudt
如果您不指定版本会发生什么? - Andrew W
python setup.py build --compiler=g++ 与 python setup.py build --compiler=g++-4.7 - Andrew W

0
在Linux上使用distutils.ccompiler时,执行os.environ('CC')='gcc',然后调用distutils.sysconfig.customize_compiler(compiler)即可完成任务。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接