这是我第一次处理比简单的写入单源文件和编译例程稍微复杂的 CUDA 项目。正如预期的那样,我遇到了一些 C 标头问题,即重复的符号。
根据链接器,在多个.cu
文件中包含以下头文件时会出现冲突:
env_vars.h
#ifndef ENV_VARS_H_
#define ENV_VARS_H_
/*** GLOBAL VARIABLES ***/
unsigned int h_n_osc;
__device__ unsigned int d_n_osc;
/*** CONSTANTS ***/
const double OMEGA_0 = 6.447421494058077e+09;
/* other constants defined in the middle */
#endif
multigpu.cu
#include "env_vars.h"
/* assigns h_n_osc */
adm_matrix.cu
#include "env_vars.h"
/* uses h_n_osc */
在 Nsight Eclipse Edition 中构建项目会导致链接器抱怨h_n_osc
变量被定义两次:
duplicate symbol _h_n_osc in:
./adm_matrix.o
./multigpu.o
ld: 1 duplicate symbol for architecture x86_64
在互联网上搜索,我意识到将h_n_osc
变量的声明移动到multigpu.cu
并将其重新声明为adm_matrix.cu
中的extern
变量(以及我以后可能需要它的地方(可以解决问题,事实上它确实如此。
问题解决了,但我想更深入地研究一下:
- 为什么链接器也不抱怨
d_n_osc
变量?为什么常量(如OMEGA_0
(同样不是问题? - 这是否意味着无法在头文件中放置全局变量?
- 最让我困惑的是,互联网上的许多来源都指出,只有当头文件包含变量的定义时,才会发生重复的符号错误,而它的简单声明应该不会构成问题。我很难相信的原因是,即使我的标题只包含一个声明,我也面临着这个问题!我错过了什么吗?
提前感谢您的耐心等待,伙计们!
头文件通常应仅包含声明性代码。 h_n_osc
应该在这里声明,而不是定义。
extern unsigned int h_n_osc;
在至少一个模块中,或者它自己的一个新模块中,您将需要一个定义;例如:
env_vars.铜
#include "env_vars.h"
unsigned int h_n_osc;
然后链接它。 或者,您当然可以将定义放在现有模块之一中 multigpu.cu 或 adm_matrix.cu。
我不确定 CUDA __device__
扩展的语义,虽然它可能链接,但它不一定正确;你最终可能会得到每个模块引用设备变量的单独副本;可能也有必要用extern
来限定它。 这个问题似乎涉及这个问题。