使用CUDA编译失败:异常规范与前一个函数 "rsqrt" 不兼容

编程语言 2026-07-09

我在我的机器上安装了手动版的CUDA 13.1,运行Devuan GNU/Linux Freia。最近更新发行版的软件包后,包含一些CUDA头文件的C++程序的编译失败,错误信息如下:

/usr/include/x86_64-linux-gnu/bits/mathcalls.h(206): error: exception
specification is incompatible with that of previous function "rsqrt"
(declared at line 629 of
/usr/local/cuda-13.1/bin/../targets/x86_64-linux/include/crt/math_functions.h)

extern double rsqrt (double __x) noexcept (true); extern double __rsqrt (double __x) noexcept (true);

mathcalls.h 中,我看到那一行写着:

__MATHCALL (rsqrt,, (_Mdouble_ __x));

它展开为:

extern double rsqrt(double __x) noexcept (true);
extern double __rsqrt(double __x) noexcept (true);

而在 /usr/local/cuda-13.1/bin/../targets/x86_64-linux/include/crt/math_functions.h 中,我有:

extern __DEVICE_FUNCTIONS_DECL__ __device_builtin__ double                 rsqrt(double x);

我猜这个宏展开成一个 noexcept(true),还是某种东西,与NVIDIA在 CUDA头文件中的定义不兼容。

我尝试把默认编译器从发行版中的版本15换成GCC 14,或13,但都没用。

  1. 为什么会这样?我知道很可能是发行版的软件包升级造成的,但究竟是为什么呢?
  2. 我应该如何规避这个问题?

备注:

  • 这在CUDA 13.2上不会发生
  • 这让我想起了一个 类似的问题,我(以及大家)在某些三角函数的异常规范上遇到的情况,比如 __sinpi()__cospi();我希望不必再次对CUDA进行打补丁 :-(

解决方案

tl;dr:你需要对CUDA头文件进行打补丁 :-(

为什么会这样?

较新版本的glibc(你的版本是2.42)提供了越来越多过去不可用的数学函数,其中一些也以CUDA __device__ 函数的形式出现在CUDA头文件中。去年是 sinpi()cospi() 等,今年是 rsqrt()rsqrtf()。基本签名是相同的,但函数的声明可能是抛出异常的,或是不抛出异常的,取决于……等因素,而CUDA发行版必须使用匹配的声明。

通过对宏的处理,可以让所有GCC版本实现这种匹配,但NVIDIA只处理了他们已经知道的声明冲突。对于额外的函数,我们必须自己动手——通过补丁来实现。

致谢 @mohangk和 @morgwai666在 NVIDIA开发者论坛上的贡献,他们提供了两种替代补丁。

当你当前目录位于 /usr/local/cuda/include/crt(或在 crt/ 子目录中的CUDA include目录)时,必须同时应用这两种补丁。

针对CUDA 13.0及更高版本的补丁

较新版本的CUDA已经意识到glibc的问题 此补丁 适用于CUDA的较新版本,并使用基于宏的机制来控制是否将某些数学函数定义为抛出异常:

--- math_functions.h    2026-03-07 12:36:19.092019479 +0100
+++ math_functions.h    2026-03-07 17:15:33.322027903 +0100
@@ -604,6 +604,11 @@ extern __DEVICE_FUNCTIONS_DECL__ __devic
 #if defined(__QNX__) && !defined(_LIBCPP_VERSION)
 } /* std */
 #endif
+#if __NV_GLIBC_PROVIDES_IEC_60559_FUNCS
+#define __NV_IEC_60559_FUNCS_EXCEPTION_SPECIFIER __THROW
+#else
+#define __NV_IEC_60559_FUNCS_EXCEPTION_SPECIFIER
+#endif
 /**
  * \ingroup CUDA_MATH_DOUBLE
  * \brief Calculate the reciprocal of the square root of the input argument.
@@ -626,7 +631,7 @@ extern __DEVICE_FUNCTIONS_DECL__ __devic
  *
  * \note_accuracy_double
  */
-extern __DEVICE_FUNCTIONS_DECL__ __device_builtin__ double                 rsqrt(double x);
+extern __DEVICE_FUNCTIONS_DECL__ __device_builtin__ double                 rsqrt(double x) __NV_IEC_60559_FUNCS_EXCEPTION_SPECIFIER;

 /**
  * \ingroup CUDA_MATH_SINGLE
@@ -650,7 +655,8 @@ extern __DEVICE_FUNCTIONS_DECL__ __devic
  *
  * \note_accuracy_single
  */
-extern __DEVICE_FUNCTIONS_DECL__ __device_builtin__ float                  rsqrtf(float x);
+extern __DEVICE_FUNCTIONS_DECL__ __device_builtin__ float                  rsqrtf(float x) __NV_IEC_60559_FUNCS_EXCEPTION_SPECIFIER;
+#undef __NV_IEC_60559_FUNCS_EXCEPTION_SPECIFIER

 #if defined(__QNX__) && !defined(_LIBCPP_VERSION)
 namespace std {

针对CUDA 12.* 及更早版本的补丁

这是一个“更丑”的补丁,可能仅对较新版本的glibc有效?:

--- a/math_functions.h
+++ b/math_functions.h
@@ -626,7 +626,7 @@
  *
  * \note_accuracy_double
  */
-extern __DEVICE_FUNCTIONS_DECL__ __device_builtin__ double                 rsqrt(double x);
+extern __DEVICE_FUNCTIONS_DECL__ __device_builtin__ double                 rsqrt(double x) noexcept (true);

 /**
  * \ingroup CUDA_MATH_SINGLE
@@ -650,7 +650,7 @@
  *
  * \note_accuracy_single
  */
-extern __DEVICE_FUNCTIONS_DECL__ __device_builtin__ float                  rsqrtf(float x);
+extern __DEVICE_FUNCTIONS_DECL__ __device_builtin__ float                  rsqrtf(float x) noexcept (true);

 #if defined(__QNX__) && !defined(_LIBCPP_VERSION)
 namespace std {
站内所有文章版权归属LeftHeroAI导航站,无授权禁止任何主体转载、抄袭、复制内容,亦不得私自架设镜像站点。一经侵权,本站将通过法律途径追责。

相关文章