【问题标题】:Enable code indexing of Cuda in Clion在 Clion 中启用 Cuda 的代码索引
【发布时间】:2021-02-01 10:15:34
【问题描述】:

我正在使用 Clion 开发一个 cuda 程序。当扩展名为 .h 时,代码高亮显示效果很好。但是,当它更改为 .cuh 时,Clion 只会将新文件视为纯文本文件,而我无法启用代码突出显示。我知道完整的 Cuda 工具链是不可能的,所以我不希望 Clion 解析 mykernel>> 之类的语句。如果它能像解析普通的 header/cpp 文件一样解析文件,我仍然会非常满意。

非常感谢

【问题讨论】:

    标签: cuda clion


    【解决方案1】:

    首先,确保使用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 甚至可以优雅地处理&lt;&lt;&lt;...&gt;&gt;&gt; 语法。它在启动块的每一端的一个字符下放置一条小红线,但在其他方面将其视为函数调用 - 这非常好:

    【讨论】:

    • 如果你使用cuda-api-wrappers,你甚至不需要使用那些烦人的人字形(注意:自插。)
    • 不过,我其实很喜欢人字形。启动配置参数与内核参数的分离非常好。内核通常有大量的位置参数,再加四个就很烦人:D
    【解决方案2】:

    项目工具窗口右键文件->关联文件类型->C++

    但是Clion现在官方不支持cuda,无法解析cuda语法。

    更新:

    从 CLion 2020.1 开始,我们提供了官方 CUDA C/C++ 支持。 CLion 现在可以正确处理它们了。

    【讨论】:

    • 解决了问题!谢谢
    • 我有同样的问题,但解决方案不起作用。我在 Ubuntu 16.04 上使用 Clion 2016.2.2。您使用的是什么操作系统?
    • 发现问题了,只要确定带有main函数的文件是.cpp即可。
    • CLion 19.1 中没有这样的上下文菜单选项
    【解决方案3】:

    谢谢!我添加了更多“假”声明以允许 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
    

    【讨论】:

    • 您需要更新您的答案以描述“扩展”的确切含义。提供一些 cmets。
    • 你是怎么做到的?
    • 可能只是将 sn-p 添加到 C++ 代码或制作一个不在 IDE 之外构建的标头(请参阅 JETBRAINS_IDE)定义
    • 我很惊讶这看起来令人困惑。只是把它放在一个标题中的某个地方来定义 CLion 解析器没有的东西;t regnize
    【解决方案4】:

    我使用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
    

    【讨论】:

    • 您可能会发现 my revised approach 感兴趣 - 一个避免自己重新定义宇宙的通用解决方案:D
    • @ChrisKitching 哇,如果使用那个编译器,那肯定是更好的方法。在 GCC 上使用 Clang 的框中的另一个勾号。不幸的是,在我发布我的答案之前,我已经对你的答案投了赞成票。这似乎很容易与内联编辑语法检查联系起来,因为我相信 Clion 和几乎每个 C++ IDE 在编译错误检查之前都使用 Clang 来做。我想 Jetbrains 可以很容易地在 IDE 中实现这一点,即使只是作为一个插件。
    【解决方案5】:

    如果您希望 clion 将所有 .cu 文件解析为 .cpp 或任何其他支持的文件类型,您可以这样做:

    1. 转到文件 -> 设置 -> 编辑器 -> 文件类型
    2. 在第一列 (.cpp) 中选择您希望解析的文件类型
    3. 点击第二列的加号,写*.cu

    4. 按应用,clion 将解析您的所有 .cu 文件,因为它是您在上列 (.cpp) 中指定的文件类型

    您可以查看更多文档here

    【讨论】:

    • 这对我有帮助,不知道最佳答案中的“项目工具窗口”到底是什么。
    • 感谢您让我知道 :) 乐于提供帮助
    【解决方案6】:

    我发现 clion 似乎对所有构建目标进行了代码索引,而不仅仅是您选择构建的目标。我的策略是从我的 .cu 文件中创建 .cpp 符号链接,并创建一个引用这些 .cpp 链接的子 clion/cmake c++ 构建目标(仅用于索引)。这种方法似乎适用于 Unbuntu 16.04.3 中 clion 2017.3.3 中的小型 cuda/thrust c++11 项目。

    我这样做是:

    • 使用 clion 注册 .cu/cuh 文件,与其他答案一样
    • 将 cuda/clion 宏 voodoo 添加到我的 .cu 文件中,与其他答案一样(voodoo 的位置可能很重要,但我还没有遇到任何麻烦)
    • 在项目目录中创建指向 .cu/.cuh 文件的 .cpp/.hpp 符号链接
    • 使用名为 clionShadow/CMakeLists.txt 的单个文件创建一个新文件夹,其中包含:
    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})
    
    • 在主 CMakeLists.txt 的末尾添加对 clionShadow/CMakeLists.txt 的依赖项,如下所示:
    add_subdirectory(clionShadow)
    

    现在,clion 通过 .cpp 文件解析和编码索引 .cu 文件。

    请记住,cudaNoBuild 目标不是用于构建 - 它将使用不起作用的 c++ 工具链。如果您突然遇到编译错误,请检查 clion 的构建目标设置 - 我注意到它有时会混合并匹配项目之间的当前构建设置。在这种情况下,请转到 Run 菜单下的 Edit_Configurations 对话框,并确保 clion 没有将 target_executable 更改为来自 cudaNoBuild 目标。

    编辑: 啊!在更新到 clion 2017.3.3 后重建 CMake 和 ide 缓存后,事情并没有像以前那样工作。索引仅适用于 .cpp 文件,断点仅适用于 .cu 文件。

    【讨论】:

      【解决方案7】:

      虽然不是特别相关,但不知何故,这个问题出现在谷歌搜索结果“Pycharm cuda highlight”中。但是,然后将 CLion 用于 C/C++ 项目!

      从 PyCharm 2020.3 Community Edition for Mac 开始,它位于文件 > 文件类型 > 与文件类型关联。

      如果不确定,请使用帮助菜单下的搜索栏搜索“文件类型”。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2015-03-22
        • 1970-01-01
        • 2017-10-26
        • 2018-06-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多