0%

Troubleshooting between C++ Module and NVCC

在開發自己的Toy Project時,做了許多大膽的舉動,其中之一就是使用了C++20 Module,不過夜路走多了總是會碰到鬼,列下目前遇到的血淚史

NVCC doesn’t support C++20 Module

一開始沒打算使用CUDA,等到引進CUDA時才發現這是個超級大坑

Because it requires complex interaction between the CUDA device compiler and the host compiler, modules are not supported in CUDA C++
山不轉路轉,原先的程式碼大概長這樣

1
2
3
4
5
6
7
export module A;

export {
enum Flag {
// blabla
};
}

退化成C++17能接受的語法

1
2
3
4
#prgram once
enum Flag {
// blabla
};

1
2
3
4
5
6
7
8
module;
#inlcude "header.h"

export module A;

export {
using Flag;
}

以及CUDA的Header file

1
2
3
#pragma  once
#include "header.h"
void doSomething(Flag);

至少是我目前想到最好的解法
乍看之下問題解決了,不過事情沒這麼簡單,假設有個Implementation unit

1
2
3
4
5
6
7
8
9
module;
#include "header.h"

module A;

void work()
{
doSomething(Flag{});
}

會發現Compiler會告訴你Flag被重複定義,於是乎想到一個解決方案,forward references,改寫Cuda Header的部分

1
2
3
#pragma  once
enum Flag : int;
void doSomething(Flag);

然後將獨立出Cuda Implementation Unit

1
2
#include "header.h"
void doSomething(Flag) {}

雖然很難看,不過現在跑起來沒啥問題

location on extern function

上面的方式是將cuda function拆成兩個檔案,header和implementation
如果我們要省略header該怎麼做

1
2
3
4
5
6
7
module A;
extern void funcFromCuda();

void work()
{
funcFromCuda();
}

在MSVC上編譯沒問題,不過在Linux Clang下編譯就會出錯了
修正方式也很簡單,將extern function移到Global module fragment就好了

1
2
3
4
5
6
7
8
9
module;
extern void funcFromCuda();

module A;

void work()
{
funcFromCuda();
}

One more thing

這其實跟C++20 Module無關,只是因為現階段Clang支持Module,而GCC還沒準備好,所以開發就以Clang為主,因此遇到了這麼一個問題

1
2
3
4
5
6
7
8
9
10
module;
#include <string>
extern void funcFromCuda(std::string);

module A;

void work()
{
funcFromCuda("Hello World");
}

NVCC會告訴你找不到funcFromCuda function,因為我們外部的Compiler是使用clang,使用的是libc++,而NVCC使用的是libstdc++,兩者並不相容
於是乎只好退回舊方法,直接傳指標了

1
2
3
4
5
6
7
8
9
10
module;
#include <string>
extern void funcFromCuda(const char*);

module A;

void work()
{
funcFromCuda("Hello World");
}

Conclusion

目前看來,NVCC支援C++20 Moudle遙遙無期,不然問題一和問題二應該都能解決
問題三比較麻煩,就算支援Module還是不行,只能使用老方法