Pybind11指定C++标准后Windows仍按C++98编译问题排查
问题原因与可行解决方案
1. Windows下cxx_std=11失效、显示C++98的核心原因
- 你看到的
__cplusplus输出199711(对应C98)是MSVC的历史兼容默认行为,不是真的在按C98编译:MSVC长期默认不更新__cplusplus宏的返回值,除非手动指定/Zc:__cplusplus编译参数,哪怕实际用C17编译,这个宏默认还是返回C98的数值。 - Windows平台下setuptools默认优先调用MSVC编译C扩展,旧版本pybind11和setuptools的适配逻辑没有给MSVC自动追加
/Zc:__cplusplus参数,才会出现这个误导性的输出。另外MSVC从2017版开始就不再支持C11,最低编译标准是C14,根本不可能用C98成功编译pybind11代码——pybind11本身大量使用C11语法,C98连语法检查都过不了,你之前能正常导入运行,就说明实际编译标准根本不是C++98。 - 你之前指定
--compiler=mingw32时报/EHsc//bigobj//std:c++14找不到,是因为setuptools的MinGW适配层存在遗留bug,会把MSVC专用的斜杠开头参数直接传给GCC,GCC不识别MSVC格式的参数自然报错。
2. Windows下强制用MinGW-GCC统一编译标准的配置方法
不要直接敲裸编译命令,在setup.py里自定义编译逻辑,过滤无效参数即可,参考配置:
from setuptools import setup from pybind11.setup_helpers import Pybind11Extension, build_ext class CustomBuildExt(build_ext): def build_extensions(self): # 针对MinGW编译器修正参数 if self.compiler.compiler_type == "mingw32": for ext in self.extensions: # 过滤所有MSVC专属的斜杠开头参数 ext.extra_compile_args = [arg for arg in ext.extra_compile_args if not arg.startswith("/")] ext.extra_link_args = [arg for arg in ext.extra_link_args if not arg.startswith("/")] # 追加GCC编译需要的参数,强制指定C++11 ext.extra_compile_args += ["-std=c++11", "-DMS_WIN64", "-fPIC"] # 针对MSVC编译器追加参数,让__cplusplus宏返回正确值 elif self.compiler.compiler_type == "msvc": for ext in self.extensions: ext.extra_compile_args += ["/Zc:__cplusplus"] super().build_extensions() ext_modules = [ Pybind11Extension( modulename, sources=[filename], language="c++", cxx_std=11 ), ] setup( name=modulename, ext_modules=ext_modules, cmdclass={"build_ext": CustomBuildExt}, )
配置完成后执行编译时带上--compiler=mingw32参数即可调用MinGW-GCC,和Linux环境保持编译器、C++标准一致:python setup.py install --compiler=mingw32
提前把MinGW的bin目录加入系统PATH,避免setuptools找不到编译器。
3. 手动GCC编译后仍检测到_MSVC_LANG宏的原因
你手动编译时犯了两个低级错误:
- 你调用的是
gcc.exe而不是g++.exe:编译C代码必须用g命令,gcc默认按C语言模式处理,不会自动链接C标准库,根本编不出正确的C扩展。 - 你只生成了
.o目标文件,不是Python可加载的.pyd格式扩展,你导入成功的其实是之前MSVC编译留下的旧版本.pyd文件,和你刚编译的.o没关系,检测到MSVC宏是理所当然的。
正确的手动编译命令要调用g++,最终输出.pyd文件,编译前先清空目录下旧的编译产物:
D:\mingw-w64\x86_64-8.1.0-posix-seh-rt_v6-rev0\mingw64\bin\g++.exe -static -shared -std=c++11 -DMS_WIN64 -fPIC ^ "-IF:\...\env_csmar\lib\site-packages\pybind11\include" ^ "-IF:\...\env_csmar\include" ^ "-LF:\...\env_csmar\libs" ^ example_cpp.cpp -o example_cpp.pyd ^ -lpython3x # 替换为你当前Python版本对应的库名,比如Python3.9就写-lpython39
验证标准是否生效:编译完成后在Python中打印
__cplusplus的值,返回201103即对应C11,201402对应C14。
内容的提问来源于stack exchange,提问作者Jerry
相关产品推荐
相关产品推荐

