読者です 読者をやめる 読者になる 読者になる

CUDAコンパイラは糞。マクロを正常に展開しない。

某Hiroaki Softwareが、Win32APIコードをcuコードに混ぜてコンパイルしようとして妙なエラーに巻きこまれたらしいので調査したら、

CUDAのコンパイラであるところのnvccはクソであることが判明した。

具体的には、CreateWindow()中に一行コメントを書こうとして失敗したらしい。

この動作を以下のように再現できる。

test.cu

#define func_macro(x,y) func(x,y)

func(x, //comment
    y);
func_macro(x, //comment
    y);

do preprocessing

$ nvcc -E test.cu | tail
{
  return cudaFuncGetAttributes(attr, (const char*)entry);
}
# 1 "<command-line>" 2
# 1 "test.cu"


func(x, //comment
    y);
func(x,//comment y);

_

見ての通り、コメント削除等先にやるべきことを飛ばしてマクロの置換のみ行い、しかも改行文字を削除などといった犯罪級の挙動をしている。

このような頭のおかしいコンパイラを信用するわけにはいかない。CUDAを利用するにあたっては、本当に最低限のCUDAコア部分だけをcuファイルに書き、残りのソースはcppファイルとして別にコンパイルすることをお勧めする。

なお、OpenCLは正統なC99らしいので素晴らしい。そもそもホストコードとゲストコードが分離されているのでこのようなことは起きないのだが。

追記

ちなみに、nvccの挙動は正統なANSI Cと考えてもおかしい(仕様を読んだことがないのでGCCとの比較で言っているが。)
例えば以下のようなコード。

#define str_(x) #x
#define pint(x) printf(str_(x)" = %d\n", (x))

pint(x);

pint(x /* x is int */);

これをGCCプリプロセスすると以下のようになる。

printf("x"" = %d\n", (x));

printf("x"" = %d\n", (x));

NVCCでプリプロセスすると以下のようになる。

printf("x"" = %d\n", (x));

printf("x /* x is int */"" = %d\n", (x /* x is int */));

おかしいのは自明。