Compiling Cuda Code in Qt Creator on Windows

Compiling Cuda code in Qt Creator on Windows

So I finally managed to assemble a .pro file that works on my and probably on all Windows systems. The following is an easy test programme that should probably do the trick. The following is a small project file plus test programme that works at least on my system.

The file system looks as follows:

TestCUDA \
TestCUDA.pro
main.cpp
vectorAddition.cu

The project file reads:

TARGET = TestCUDA

# Define output directories
DESTDIR = release
OBJECTS_DIR = release/obj
CUDA_OBJECTS_DIR = release/cuda

# Source files
SOURCES += src/main.cpp

# This makes the .cu files appear in your project
OTHER_FILES += vectorAddition.cu

# CUDA settings <-- may change depending on your system
CUDA_SOURCES += src/cuda/vectorAddition.cu
CUDA_SDK = "C:/ProgramData/NVIDIA Corporation/NVIDIA GPU Computing SDK 4.2/C" # Path to cuda SDK install
CUDA_DIR = "C:/Program Files/NVIDIA GPU Computing Toolkit/CUDA/v4.2" # Path to cuda toolkit install
SYSTEM_NAME = Win32 # Depending on your system either 'Win32', 'x64', or 'Win64'
SYSTEM_TYPE = 32 # '32' or '64', depending on your system
CUDA_ARCH = sm_11 # Type of CUDA architecture, for example 'compute_10', 'compute_11', 'sm_10'
NVCC_OPTIONS = --use_fast_math

# include paths
INCLUDEPATH += $$CUDA_DIR/include \
$$CUDA_SDK/common/inc/ \
$$CUDA_SDK/../shared/inc/

# library directories
QMAKE_LIBDIR += $$CUDA_DIR/lib/$$SYSTEM_NAME \
$$CUDA_SDK/common/lib/$$SYSTEM_NAME \
$$CUDA_SDK/../shared/lib/$$SYSTEM_NAME
# Add the necessary libraries
LIBS += -lcuda -lcudart

# The following library conflicts with something in Cuda
QMAKE_LFLAGS_RELEASE = /NODEFAULTLIB:msvcrt.lib
QMAKE_LFLAGS_DEBUG = /NODEFAULTLIB:msvcrtd.lib

# The following makes sure all path names (which often include spaces) are put between quotation marks
CUDA_INC = $$join(INCLUDEPATH,'" -I"','-I"','"')

# Configuration of the Cuda compiler
CONFIG(debug, debug|release) {
# Debug mode
cuda_d.input = CUDA_SOURCES
cuda_d.output = $$CUDA_OBJECTS_DIR/${QMAKE_FILE_BASE}_cuda.o
cuda_d.commands = $$CUDA_DIR/bin/nvcc.exe -D_DEBUG $$NVCC_OPTIONS $$CUDA_INC $$LIBS --machine $$SYSTEM_TYPE -arch=$$CUDA_ARCH -c -o ${QMAKE_FILE_OUT} ${QMAKE_FILE_NAME}
cuda_d.dependency_type = TYPE_C
QMAKE_EXTRA_COMPILERS += cuda_d
}
else {
# Release mode
cuda.input = CUDA_SOURCES
cuda.output = $$CUDA_OBJECTS_DIR/${QMAKE_FILE_BASE}_cuda.o
cuda.commands = $$CUDA_DIR/bin/nvcc.exe $$NVCC_OPTIONS $$CUDA_INC $$LIBS --machine $$SYSTEM_TYPE -arch=$$CUDA_ARCH -c -o ${QMAKE_FILE_OUT} ${QMAKE_FILE_NAME}
cuda.dependency_type = TYPE_C
QMAKE_EXTRA_COMPILERS += cuda
}

Note the QMAKE_LFLAGS_RELEASE = /NODEFAULTLIB:msvcrt.lib: it took me a long time to figure out, but this library seems to clash with other things in Cuda, which produces strange linking warnings and errors. If someone has an explanation for this, and potentially a prettier way to get around this, I'd like to hear it.

Also, since Windows file paths often include spaces (and NVIDIA's SDK by default does so too), it is necessary to artificially add quotation marks around the include paths. Again, if someone knows a more elegant way of solving this problem, I'd be interested to know.

The main.cpp file looks like this:

#include <cuda.h>
#include <builtin_types.h>
#include <drvapi_error_string.h>

#include <QtCore/QCoreApplication>
#include <QDebug>

// Forward declare the function in the .cu file
void vectorAddition(const float* a, const float* b, float* c, int n);

void printArray(const float* a, const unsigned int n) {
QString s = "(";
unsigned int ii;
for (ii = 0; ii < n - 1; ++ii)
s.append(QString::number(a[ii])).append(", ");
s.append(QString::number(a[ii])).append(")");

qDebug() << s;
}

int main(int argc, char* argv [])
{
QCoreApplication(argc, argv);

int deviceCount = 0;
int cudaDevice = 0;
char cudaDeviceName [100];

unsigned int N = 50;
float *a, *b, *c;

cuInit(0);
cuDeviceGetCount(&deviceCount);
cuDeviceGet(&cudaDevice, 0);
cuDeviceGetName(cudaDeviceName, 100, cudaDevice);
qDebug() << "Number of devices: " << deviceCount;
qDebug() << "Device name:" << cudaDeviceName;

a = new float [N]; b = new float [N]; c = new float [N];
for (unsigned int ii = 0; ii < N; ++ii) {
a[ii] = qrand();
b[ii] = qrand();
}

// This is the function call in which the kernel is called
vectorAddition(a, b, c, N);

qDebug() << "input a:"; printArray(a, N);
qDebug() << "input b:"; printArray(b, N);
qDebug() << "output c:"; printArray(c, N);

if (a) delete a;
if (b) delete b;
if (c) delete c;
}

The Cuda file vectorAddition.cu, which describes a simple vector addition, look like this:

#include <cuda.h>
#include <builtin_types.h>

extern "C"
__global__ void vectorAdditionCUDA(const float* a, const float* b, float* c, int n)
{
int ii = blockDim.x * blockIdx.x + threadIdx.x;
if (ii < n)
c[ii] = a[ii] + b[ii];
}

void vectorAddition(const float* a, const float* b, float* c, int n) {
float *a_cuda, *b_cuda, *c_cuda;
unsigned int nBytes = sizeof(float) * n;
int threadsPerBlock = 256;
int blocksPerGrid = (n + threadsPerBlock - 1) / threadsPerBlock;

// allocate and copy memory into the device
cudaMalloc((void **)& a_cuda, nBytes);
cudaMalloc((void **)& b_cuda, nBytes);
cudaMalloc((void **)& c_cuda, nBytes);
cudaMemcpy(a_cuda, a, nBytes, cudaMemcpyHostToDevice);
cudaMemcpy(b_cuda, b, nBytes, cudaMemcpyHostToDevice);

vectorAdditionCUDA<<<blocksPerGrid, threadsPerBlock>>>(a_cuda, b_cuda, c_cuda, n);

// load the answer back into the host
cudaMemcpy(c, c_cuda, nBytes, cudaMemcpyDeviceToHost);

cudaFree(a_cuda);
cudaFree(b_cuda);
cudaFree(c_cuda);
}

If you get this to work, then more complicated examples are self-evident, I think.

Edit (24-1-2013): I added the QMAKE_LFLAGS_DEBUG = /NODEFAULTLIB:msvcrtd.lib and the CONFIG(debug) with the extra D_DEBUG flag, such that it also compiles in debug mode.

Compiling c++ and cuda code with MinGW in QTCreator

I'm a bit confused, are you using MinGW or Visual? The title seems to state that you are using MinGW but the project file seems to use a mix of both. You can't mix those two. If you compiled (or downloaded the binary directly from NVidia) CUDA with Visual Studio 2010, you HAVE to use VS10 to compile your project, otherwise it won't work.

I never used CUDA myself but it seems that the system requirements mention only Visual Studio 2008, 2010 and 2012. If you want to use it with Qt, it's possible, you just have to grab a Qt compiled with VS (there are builds for 32 and 64 bit for both on the download page. You can get Visual Studio Express for free as long as you don't create any commercial application with it.

To use QtCreator with the MSVC backend compiler go to Tools > Options > Build and Run > Kits and add a new Kit with the MSVC compiler, cdb as the debugger and the Qt version you just downloaded (it must have been compiled with the same Visual Studio version otherwise it won't work). Then open your project, go to the Projects tab (on the left) and select the Kit you just created. You should probably clean your .pro file as well before everything work smoothly.

On a side note, there are a few things that seems out of place in your linker line:

g++ -Wl,-s -Wl,-subsystem,windows -mthreads -o release\Cuda.exe release/cuda/vectorAddition_cuda.o release/obj/main.o  -lglu32 -lopengl32 -lgdi32 -luser32 -lmingw32 -lqtmain -LC:\Cuda\CudaToolkit\lib\Win32 -LC:\Cuda\CudaSamples\common\lib\Win32 -LC:\Cuda\CudaSamples\..\shared\lib\Win32 -LC:\CUDA\VS10\VC\lib -LQMAKE_LIBS -L+= -L-lmsvcrt -L-llibcmt -L-llibcpmt -lcuda -lcudart -LF:\Programs\Qt5.1.1\5.1.1\mingw48_32\lib -lQt5Gui -lQt5Core 

First this -L+=, which might be caused by the escaping backslash at the end of the QMAKE_LIBDIR.

Then the syntax -L-lmsvcrt seems wrong. It might be because you are using QMAKE_LIBS, I personally never had to use it, and according to the documentation you shouldn't either as it is an internal variable. Same goes for QMAKE_LIBDIR btw. I would just use the LIBS variable for any external dependency.

Compiling with Cuda in Qt gives linking error

As mentioned by @asm you are compiling to PTX intermediate files and then trying to link them as object files. But counter to @asm's suggestion, you should not compile to cubin, but to object files. To do so, you want the -c option rather than the -ptx option:

cuda.input = CUDA_SOURCES
cuda.output = $$CUDA_OBJECTS_DIR/${QMAKE_FILE_BASE}_cuda.o
cuda.commands = $$CUDA_DIR/bin/nvcc.exe $$CUDA_INC $$LIBS --machine 32 -c -o ${QMAKE_FILE_OUT} ${QMAKE_FILE_NAME}

Caveat: not a QMAKE user so the above might not be exactly right. I second the recommendation for CMake.

CUDA, Win7, Qt Creator - LNK1104: cannot open file 'cuda file.obj'

The OP was able to get a successful compile link by making the following changes:

1) In the .pro file, added

MSVCRT_LINK_FLAG_DEBUG = "/MDd"

MSVCRT_LINK_FLAG_RELEASE = "/MD"

along with (to the cuda.command statement)
-Xcompiler $$MSVCRT_LINK_FLAG_DEBUG -or- -Xcompiler $$MSVCRT_LINK_FLAG_RELEASE

as described in:
Compile cuda file error: "runtime library" mismatch value 'MDd_DynamicDebug' doesn't match value 'MTd_StaticDebug' in vectorAddition_cuda.o

2) Also had a very strange detail in the makefile that I had to fix manually. I hope that there is a real fix for this, but I haven't been able to figure it out.

At the top of the makefile, there are several definitions, including one for LIBS. After close inspection of this definition, I found that there was an extra set of quotation marks in the specification of library locations. Like this:

LIBS          = /LIBPATH:"C:\Program Files\NVIDIA GPU Computing Toolkit\CUDA\v7.0\lib\x64" ""C:\Program Files\NVIDIA GPU Computing Toolkit\CUDA\v7.0\lib\x64"\cuda.lib" ""C:\Program Files\NVIDIA GPU Computing Toolkit\CUDA\v7.0\lib\x64"\cudart.lib" /LIBPATH:C:\Qt\5.2.1\msvc2012_64_opengl\lib C:\Qt\5.2.1\msvc2012_64_opengl\lib\Qt5Cored.lib 

If you look closely, you can see the extra set of quotation marks in the locations for cuda.lib and cudart.lib. I couldn't figure out what might be causing this (probably something in my .pro file), but if I manually removed the extra quotations, the compile/link worked. Here's the corrected line in the makefile:

LIBS          = /LIBPATH:"C:\Program Files\NVIDIA GPU Computing Toolkit\CUDA\v7.0\lib\x64" "C:\Program Files\NVIDIA GPU Computing Toolkit\CUDA\v7.0\lib\x64\cuda.lib" "C:\Program Files\NVIDIA GPU Computing Toolkit\CUDA\v7.0\lib\x64\cudart.lib" /LIBPATH:C:\Qt\5.2.1\msvc2012_64_opengl\lib C:\Qt\5.2.1\msvc2012_64_opengl\lib\Qt5Cored.lib 

I would sure like to be able to fix this in my .pro file so that these extra quotations didn't appear. Suggestions would be appreciated.

For reference, here's my latest .pro file.

QT       += core
QT -= gui

TARGET = QtCuda
CONFIG += console
CONFIG -= app_bundle

TEMPLATE = app

SOURCES += main.cpp \
cuda_code.cu

# project build directories
DESTDIR = $$PWD
OBJECTS_DIR = $$DESTDIR/obj

# C++ flags
QMAKE_CXXFLAGS_RELEASE =-O3

# Cuda sources
CUDA_SOURCES += cuda_code.cu

# Path to cuda toolkit install
CUDA_DIR = "C:/Program Files/NVIDIA GPU Computing Toolkit/CUDA/v7.0"

# Path to header and libs files
INCLUDEPATH += $$CUDA_DIR/include
QMAKE_LIBDIR += $$CUDA_DIR/lib/x64

SYSTEM_TYPE = 64 # '32' or '64', depending on your system

# libs used in your code
LIBS += -lcuda -lcudart

# GPU architecture
CUDA_ARCH = sm_50

# Here are some NVCC flags I've always used by default.
NVCCFLAGS = --use_fast_math

# Prepare the extra compiler configuration (taken from the nvidia forum - i'm not an expert in this part)
CUDA_INC = $$join(INCLUDEPATH,'" -I"','-I"','"')

# MSVCRT link option (static or dynamic, it must be the same with your Qt SDK link option)
MSVCRT_LINK_FLAG_DEBUG = "/MDd"
MSVCRT_LINK_FLAG_RELEASE = "/MD"

# Tell Qt that we want add more stuff to the Makefile
QMAKE_EXTRA_COMPILERS += cuda

# Configuration of the Cuda compiler
CONFIG(debug, debug|release) {
# Debug mode
cuda_d.input = CUDA_SOURCES
cuda_d.output = $$OBJECTS_DIR/${QMAKE_FILE_BASE}.obj
cuda_d.commands = $$CUDA_DIR/bin/nvcc.exe -D_DEBUG $$NVCC_OPTIONS $$CUDA_INC $$LIBS --machine $$SYSTEM_TYPE \
-arch=$$CUDA_ARCH -c -o ${QMAKE_FILE_OUT} ${QMAKE_FILE_NAME} -Xcompiler $$MSVCRT_LINK_FLAG_DEBUG
cuda_d.dependency_type = TYPE_C
QMAKE_EXTRA_COMPILERS += cuda_d
}
else {
# Release mode
cuda.input = CUDA_SOURCES
cuda.output = $$CUDA_OBJECTS_DIR/${QMAKE_FILE_BASE}.obj
cuda.commands = $$CUDA_DIR/bin/nvcc.exe $$NVCC_OPTIONS $$CUDA_INC $$LIBS --machine $$SYSTEM_TYPE \
-arch=$$CUDA_ARCH -c -o ${QMAKE_FILE_OUT} ${QMAKE_FILE_NAME} -Xcompiler $$MSVCRT_LINK_FLAG_RELEASE
cuda.dependency_type = TYPE_C
QMAKE_EXTRA_COMPILERS += cuda
}

[Note: this answer has been created from an edit to the question which included the solution. It has been added as a community wiki entry to get the question off the unanswered list for the CUDA tag]

Error 2 when building CUDA/C++ test program with QtCreator

What you are trying to do is unsupported.

As per the documentation, the only supported toolchain on Windows platforms is Visual Studio. You may well be able to use QT Creator and Qmake to build projects, but you must use the Microsoft toolchain to compile and link code. MinGW and gcc are unsupported. Note also that 32 bit toolchains are also unsupported in recent versions of CUDA. You can cross compile to a 32 bit target using the toolchain, but native 32 bit toolchain support on Windows was dropped several years ago.

Determining if a file is parsed by Qt Creator (CUDA Syntax highlighting)

Try

#ifdef Q_CREATOR_RUN
// ...
#endif


Related Topics



Leave a reply



Submit