Monday, March 23, 2009

CUDA in Code::Blocks - First things second

While my first post highlighted the key sticking-points I faced when I first tried to use the nvcc compiler within the Code::Blocks IDE, it was probably jumping the gun a bit. Here I'll outline the procedure for setting up the nvcc compiler in Code::Blocks from scratch.

First we create a new compiler within Code::Blocks.
  • Settings --> Compiler and debugger...
  • At the top under Selected compiler, make sure "GNU GCC Compiler" is selected, and click the Copy button.
  • Enter a name for the compiler. Something like "NVIDIA NVCC CUDA Compiler", but perhaps with less shouting.
  • Do exactly what you're told, and go to the Toolchain executables tab.
  • Enter nvcc's installation directory (e.g., /opt/local/cuda).
  • Enter C compiler: nvcc
  • C++ compiler: nvcc
  • Linker for dynamic libs: nvcc
  • Linker for static libs: nvcc
  • Debugger: cuda-gdb? (I haven't actually tried it yet)
  • Under the Search directories tab, add /your_location/NVIDIA_CUDA_SDK2/common/inc to the Compiler box (so that headers like cutil.h will be found).
  • Add /your_location/NVIDIA_CUDA_SDK2/lib to the Linker box.
  • Add /your_location/NVIDIA_CUDA_SDK2/common/lib/linux (modify for your OS) to the Linker box.
  • OK.
So now we have the basics set up. Before we get into the really fun stuff (as described in my original blog post), we'll do a couple of easy things to make life more convenient.
  • Project --> Project tree --> Edit file types & categories...
  • Click the Add button.
  • Enter something like "CUDA sources"
  • In the file masks box, enter: *.cu;
  • OK.
Now, when you want to compile a lovely .cu file, you'll have to do something slightly annoying, because I haven't found a way to automate it. You must:
  • NOTE: Do this only for .cu files that need to be compiled, not for those acting as headers that are included by another file!
  • Right-click on your .cu file(s) in the file tree on the left and go to Properties.
  • In the Build tab, tick Compile file and Link file.
  • OK.
That's it for the basics. But those nasty issues I discussed in the first post remain to be dealt with. Here's a step-by-step guide, because I'm feeling typeative:
  • Settings --> Compiler and debugger...
  • Select your new NVIDIA NVCC CUDA Compiler from the list at the top.
  • Scroll right (i.e., not left) through the tabs until you can see the Other settings tab.
  • Take a deep breath, then click Advanced options... (down the bottom).
  • You will be prompted with a very frightening warning about goblins attacking your home if you dare continue. Bravely click Yes.
  • Within the Commands tab, select Compile single file to object file.
  • Replace the Command line macro with this: $compiler --compiler-options "$options" $includes -c $file -o $object
  • Go to the Output parsing tab.
  • Select 'Instantiated from' info and replace the regular expression (regexp) with: ([][{}() #%$~A-Za-z0-9_:+/\.-]+)[(:]([0-9]+)\)?:[ ]+([iI]nstantiated from .*)
  • Select Compiler warning and replace the regexp with: ([][{}() #%$~A-Za-z0-9_:+/\.-]+)[(:]([0-9]+)\)?:[ ]([Ww]arning:[ ].*)
  • Select Compiler error and replace the regexp with: ([][{}() #%$~A-Za-z0-9_:+/\.-]+)[(:]([0-9]+)\)?:[ ](.*)
  • OK.
  • OK.
  • Start breathing again.
Woot, that's it! Now you can try making a project that uses the NVCC compiler. If you want to try compiling the SDK sample projects, this may be of use, which contains Code::Blocks project files I created for a few of the samples. Just extract it to your SDK directory and open projects.workspace. Note that many of the SDK samples need to be linked against the cutil library. If you're setting up a project yourself, just add cutil to the Link libraries box in your project's build settings. Alternatively you could add it to the global compiler settings.

Now go forth and test thy new-fandangled compiler and report back to me if you find yourself in more trouble than you began (I hope not). Good luck! I will update here if I find any further improvements to the system. One thing to try is adding another compiler for running in CUDA's device-emulation mode. I might find time to post the details of doing that some time, depending on how much nagging I receive.

Sunday, January 25, 2009

CUDA in Code::Blocks

I recently installed the Code::Blocks IDE at uni, and, after some initial success, suddenly came across a few issues when trying to use it in conjunction with NVIDIA's CUDA compiler "nvcc". Some quick 'net searching got me nowhere, and I realised my productivity boost may be short-lived. But I was not going to give up, and in a moment of caffeine-powered strength, I found the courage to push past the "Are you really sure you know what you're doing!?" warning messages and delve deep into the Code::Blocks settings dialogs. What I found changed the way I look at compiler flags forever...

The first problem I noticed was the fact that nvcc accepts compiler options in a different format to, say, gcc. The 'net quickly led me to the following syntax:

$compiler --compiler-options "$options" $includes -c $file -o $object

which can be plopped right into Code::Blocks's compile-command format setting. Bye-bye compiler whingeing.

The second problem became apparent when I discovered that error (and warning, etc.) messages were not being parsed and passed to me ("definitely not legal C++;" is definitely not legal C++, even according to nvcc). The syntax of messages reported by gcc (file: line: message) and nvcc (file (line): message) differ very slightly (who knows why :/), meaning Code::Blocks doesn't naturally pick up nvcc's messages. To make things worse, nvcc calls gcc to compile the non-CUDA parts of your code anyway, meaning you are returned error messages in both formats. The road ahead was climbing steeply...

Fortunately, Code::Blocks allows the exact parsing syntax to be defined manually, in the form of regular expressions. This immediately came to mind, as my ventures of only a couple of days before came to the rescue. [Warning: If you don't know regular expressions, look away now!]. I replaced

:([0-9]+):

with

[(:]([0-9]+)\)?:

in the compiler error, warning and "Instantiated from" message parsers, and was suddenly greeted with the delightful, if slightly confusing: "‘definitely’ was not declared in this scope".

I have a feeling there are more surprises lying in wait, but for now I have all the functionality I need. To make things a little more explicit, you can look at the relevant excerpt from my Code::Blocks config file here.

Let me know if you've found this useful, had similar experiences, or know of an existing solution!