【发布时间】:2021-02-01 10:15:34
【问题描述】:
我正在使用 Clion 开发一个 cuda 程序。当扩展名为 .h 时,代码高亮显示效果很好。但是,当它更改为 .cuh 时,Clion 只会将新文件视为纯文本文件,而我无法启用代码突出显示。我知道完整的 Cuda 工具链是不可能的,所以我不希望 Clion 解析 mykernel>> 之类的语句。如果它能像解析普通的 header/cpp 文件一样解析文件,我仍然会非常满意。
非常感谢
【问题讨论】:
我正在使用 Clion 开发一个 cuda 程序。当扩展名为 .h 时,代码高亮显示效果很好。但是,当它更改为 .cuh 时,Clion 只会将新文件视为纯文本文件,而我无法启用代码突出显示。我知道完整的 Cuda 工具链是不可能的,所以我不希望 Clion 解析 mykernel>> 之类的语句。如果它能像解析普通的 header/cpp 文件一样解析文件,我仍然会非常满意。
非常感谢
【问题讨论】:
首先,确保使用File Types 设置菜单告诉 CLion 将 .cu 和 .cuh 文件视为 C++。
CLion 无法解析 CUDA 的语言扩展,但它确实提供了一个预处理器宏,该宏仅在 clion 解析代码时定义。您可以使用它自己实现几乎完整的 CUDA 支持。
大部分问题在于 CLion 的解析器被 __host__ 或 __device__ 等关键字脱轨,导致它无法执行原本知道该怎么做的事情:
CLion 无法理解此示例中的 Dtype,因为 CUDA 内容混淆了它的解析。
这个问题的最小解决方案是给 clion 预处理器宏以忽略新的关键字,修复最坏的问题:
#ifdef __JETBRAINS_IDE__
#define __host__
#define __device__
#define __shared__
#define __constant__
#define __global__
#endif
这修正了上面的例子:
但是,__syncthreads、__popc 等 CUDA 函数仍然无法建立索引。像 threadIdx 这样的 CUDA 内置函数也是如此。一种选择是为它们提供无穷无尽的预处理器宏(甚至是结构定义),但这很丑陋并且会牺牲类型安全。
如果您使用 Clang 的 CUDA 前端,您可以做得更好。 Clang 通过在头文件中定义它们来实现隐式定义的 CUDA 内置函数,然后在编译代码时将其包含在内。这些提供了诸如threadIdx 之类的定义。通过伪装成 CUDA 编译器的预处理器并包含device_functions.h,我们也可以让__popc 和朋友一起工作:
#ifdef __JETBRAINS_IDE__
#define __host__
#define __device__
#define __shared__
#define __constant__
#define __global__
// This is slightly mental, but gets it to properly index device function calls like __popc and whatever.
#define __CUDACC__
#include <device_functions.h>
// These headers are all implicitly present when you compile CUDA with clang. Clion doesn't know that, so
// we include them explicitly to make the indexer happy. Doing this when you actually build is, obviously,
// a terrible idea :D
#include <__clang_cuda_builtin_vars.h>
#include <__clang_cuda_intrinsics.h>
#include <__clang_cuda_math_forward_declares.h>
#include <__clang_cuda_complex_builtins.h>
#include <__clang_cuda_cmath.h>
#endif // __JETBRAINS_IDE__
这将使您能够完美地索引几乎所有 CUDA 代码。 CLion 甚至可以优雅地处理<<<...>>> 语法。它在启动块的每一端的一个字符下放置一条小红线,但在其他方面将其视为函数调用 - 这非常好:
【讨论】:
项目工具窗口右键文件->关联文件类型->C++
但是Clion现在官方不支持cuda,无法解析cuda语法。
更新:
从 CLion 2020.1 开始,我们提供了官方 CUDA C/C++ 支持。 CLion 现在可以正确处理它们了。
【讨论】:
main函数的文件是.cpp即可。
谢谢!我添加了更多“假”声明以允许 CLion 更好地解析 CUDA:
#ifdef __JETBRAINS_IDE__
#define __CUDACC__ 1
#define __host__
#define __device__
#define __global__
#define __forceinline__
#define __shared__
inline void __syncthreads() {}
inline void __threadfence_block() {}
template<class T> inline T __clz(const T val) { return val; }
struct __cuda_fake_struct { int x; };
extern __cuda_fake_struct blockDim;
extern __cuda_fake_struct threadIdx;
extern __cuda_fake_struct blockIdx;
#endif
【讨论】:
我使用this answer 中的方法扩展了this answer 以提供更全面的解析宏,您现在可以让.x、.y 和.z 正常工作而没有问题,并使用网格暗淡。除此之外,我还更新了列表以包括在CUDA 8.0 documentation guide 中找到的大多数内在函数和值。请注意,这应该具有完全的 C++ 兼容性,也许还有 C。这并没有考虑到所有函数(缺少原子、数学函数(大多数情况下只包括 math.h)、纹理、表面、计时、warp votie 和 shuffle、断言、发射边界和视频功能)
#ifdef __JETBRAINS_IDE__
#include "math.h"
#define __CUDACC__ 1
#define __host__
#define __device__
#define __global__
#define __noinline__
#define __forceinline__
#define __shared__
#define __constant__
#define __managed__
#define __restrict__
// CUDA Synchronization
inline void __syncthreads() {};
inline void __threadfence_block() {};
inline void __threadfence() {};
inline void __threadfence_system();
inline int __syncthreads_count(int predicate) {return predicate};
inline int __syncthreads_and(int predicate) {return predicate};
inline int __syncthreads_or(int predicate) {return predicate};
template<class T> inline T __clz(const T val) { return val; }
template<class T> inline T __ldg(const T* address){return *address};
// CUDA TYPES
typedef unsigned short uchar;
typedef unsigned short ushort;
typedef unsigned int uint;
typedef unsigned long ulong;
typedef unsigned long long ulonglong;
typedef long long longlong;
typedef struct uchar1{
uchar x;
}uchar1;
typedef struct uchar2{
uchar x;
uchar y;
}uchar2;
typedef struct uchar3{
uchar x;
uchar y;
uchar z;
}uchar3;
typedef struct uchar4{
uchar x;
uchar y;
uchar z;
uchar w;
}uchar4;
typedef struct char1{
char x;
}char1;
typedef struct char2{
char x;
char y;
}char2;
typedef struct char3{
char x;
char y;
char z;
}char3;
typedef struct char4{
char x;
char y;
char z;
char w;
}char4;
typedef struct ushort1{
ushort x;
}ushort1;
typedef struct ushort2{
ushort x;
ushort y;
}ushort2;
typedef struct ushort3{
ushort x;
ushort y;
ushort z;
}ushort3;
typedef struct ushort4{
ushort x;
ushort y;
ushort z;
ushort w;
}ushort4;
typedef struct short1{
short x;
}short1;
typedef struct short2{
short x;
short y;
}short2;
typedef struct short3{
short x;
short y;
short z;
}short3;
typedef struct short4{
short x;
short y;
short z;
short w;
}short4;
typedef struct uint1{
uint x;
}uint1;
typedef struct uint2{
uint x;
uint y;
}uint2;
typedef struct uint3{
uint x;
uint y;
uint z;
}uint3;
typedef struct uint4{
uint x;
uint y;
uint z;
uint w;
}uint4;
typedef struct int1{
int x;
}int1;
typedef struct int2{
int x;
int y;
}int2;
typedef struct int3{
int x;
int y;
int z;
}int3;
typedef struct int4{
int x;
int y;
int z;
int w;
}int4;
typedef struct ulong1{
ulong x;
}ulong1;
typedef struct ulong2{
ulong x;
ulong y;
}ulong2;
typedef struct ulong3{
ulong x;
ulong y;
ulong z;
}ulong3;
typedef struct ulong4{
ulong x;
ulong y;
ulong z;
ulong w;
}ulong4;
typedef struct long1{
long x;
}long1;
typedef struct long2{
long x;
long y;
}long2;
typedef struct long3{
long x;
long y;
long z;
}long3;
typedef struct long4{
long x;
long y;
long z;
long w;
}long4;
typedef struct ulonglong1{
ulonglong x;
}ulonglong1;
typedef struct ulonglong2{
ulonglong x;
ulonglong y;
}ulonglong2;
typedef struct ulonglong3{
ulonglong x;
ulonglong y;
ulonglong z;
}ulonglong3;
typedef struct ulonglong4{
ulonglong x;
ulonglong y;
ulonglong z;
ulonglong w;
}ulonglong4;
typedef struct longlong1{
longlong x;
}longlong1;
typedef struct longlong2{
longlong x;
longlong y;
}longlong2;
typedef struct float1{
float x;
}float1;
typedef struct float2{
float x;
float y;
}float2;
typedef struct float3{
float x;
float y;
float z;
}float3;
typedef struct float4{
float x;
float y;
float z;
float w;
}float4;
typedef struct double1{
double x;
}double1;
typedef struct double2{
double x;
double y;
}double2;
typedef uint3 dim3;
extern dim3 gridDim;
extern uint3 blockIdx;
extern dim3 blockDim;
extern uint3 threadIdx;
extern int warpsize;
#endif
【讨论】:
如果您希望 clion 将所有 .cu 文件解析为 .cpp 或任何其他支持的文件类型,您可以这样做:
点击第二列的加号,写*.cu
按应用,clion 将解析您的所有 .cu 文件,因为它是您在上列 (.cpp) 中指定的文件类型
您可以查看更多文档here
【讨论】:
我发现 clion 似乎对所有构建目标进行了代码索引,而不仅仅是您选择构建的目标。我的策略是从我的 .cu 文件中创建 .cpp 符号链接,并创建一个引用这些 .cpp 链接的子 clion/cmake c++ 构建目标(仅用于索引)。这种方法似乎适用于 Unbuntu 16.04.3 中 clion 2017.3.3 中的小型 cuda/thrust c++11 项目。
我这样做是:
cmake_minimum_required(VERSION 3.9) project(cudaNoBuild) set(CMAKE_CXX_STANDARD 11) add_executable(cudaNoBuild ../yourcudacode.cpp ../yourcudacode.hpp) target_include_directories(cudaNoBuild PUBLIC ${CUDA_INCLUDE_DIRS})
add_subdirectory(clionShadow)
现在,clion 通过 .cpp 文件解析和编码索引 .cu 文件。
请记住,cudaNoBuild 目标不是用于构建 - 它将使用不起作用的 c++ 工具链。如果您突然遇到编译错误,请检查 clion 的构建目标设置 - 我注意到它有时会混合并匹配项目之间的当前构建设置。在这种情况下,请转到 Run 菜单下的 Edit_Configurations 对话框,并确保 clion 没有将 target_executable 更改为来自 cudaNoBuild 目标。
编辑: 啊!在更新到 clion 2017.3.3 后重建 CMake 和 ide 缓存后,事情并没有像以前那样工作。索引仅适用于 .cpp 文件,断点仅适用于 .cu 文件。
【讨论】:
虽然不是特别相关,但不知何故,这个问题出现在谷歌搜索结果“Pycharm cuda highlight”中。但是,然后将 CLion 用于 C/C++ 项目!
从 PyCharm 2020.3 Community Edition for Mac 开始,它位于文件 > 文件类型 > 与文件类型关联。
如果不确定,请使用帮助菜单下的搜索栏搜索“文件类型”。
【讨论】: