Qt Creator + CUDA + Linux – Review

As many people has found my last (and only) post interesting, I’ve decided make an update taking into account the problems that people had when they followed the instructions. I’ve also improved the .pro file with new tricks I’ve found in the last year.

Main problems came by the fact that people do not read the comments and do not take a second to see what they are copying and pasting. Said that, other bunch of problems come for using the CUDA SDK. Although the SDK has some useful tools, It is not part of CUDA. So I’ve removed it from the basic configuration. If you want add the code of the SDK examples into this project you must adjust your .pro file properly.

The idea is create a wrapper to call the cuda functions from another file and instruct the compiler what we want compile with the g++ (for example Qt calls) and what we want compile with the nvcc compiler.

Let’s begin creating  a new Qt Console Application. The default .pro file configuration would be something as follows:

QT       += core
QT       -= gui

TARGET    = QtCuda
CONFIG   += console
CONFIG   -= app_bundle

TEMPLATE  = app
# C++ source code
SOURCES  += main.cpp

I have also added some custom properties:

# project build directories
DESTDIR     = $$system(pwd)
OBJECTS_DIR = $$DESTDIR/Obj
# C++ flags
QMAKE_CXXFLAGS_RELEASE =-O3

At this point we should have available a main.cpp file as follows:

#include <QtCore/QCoreApplication>

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

    return a.exec();
}

Now, we can add a new source file for the CUDA code to the project (File->New File or Project->C++ Source File), for example cuda_code.cu. Note that .cu files won’t be compiled with the g++ compiler but with the nvcc compiler, so we are going to manually add them into another variable:

# Cuda sources
CUDA_SOURCES += cuda_code.cu

And indicate the path to the cuda toolkit, including the header and libs path

# Path to cuda toolkit install
CUDA_DIR      = /usr/local/cuda
# Path to header and libs files
INCLUDEPATH  += $$CUDA_DIR/include
QMAKE_LIBDIR += $$CUDA_DIR/lib64     # Note I'm using a 64 bits Operating system
# libs used in your code
LIBS += -lcudart -lcuda
# GPU architecture
CUDA_ARCH     = sm_20                # Yeah! I've a new device. Adjust with your compute capability
# Here are some NVCC flags I've always used by default.
NVCCFLAGS     = --compiler-options -fno-strict-aliasing -use_fast_math --ptxas-options=-v

Finally, we must customize our Makefile output to take into account the CUDA parameters (more info about this topic)

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

cuda.commands = $$CUDA_DIR/bin/nvcc -m64 -O3 -arch=$$CUDA_ARCH -c $$NVCCFLAGS \
                $$CUDA_INC $$LIBS  ${QMAKE_FILE_NAME} -o ${QMAKE_FILE_OUT} \
                2>&1 | sed -r \"s/\\(([0-9]+)\\)/:\\1/g\" 1>&2
# nvcc error printout format ever so slightly different from gcc
# http://forums.nvidia.com/index.php?showtopic=171651               

cuda.dependency_type = TYPE_C # there was a typo here. Thanks workmate!
cuda.depend_command = $$CUDA_DIR/bin/nvcc -O3 -M $$CUDA_INC $$NVCCFLAGS   ${QMAKE_FILE_NAME}

cuda.input = CUDA_SOURCES
cuda.output = ${OBJECTS_DIR}${QMAKE_FILE_BASE}_cuda.o
# Tell Qt that we want add more stuff to the Makefile
QMAKE_EXTRA_COMPILERS += cuda

That’s all regarding the .pro file. Do not miss the line 36. I will talk about it later. Now it’s time to prepare our CUDA code.

The trick is tell the compiler that the CUDA functions are declared in a different file (code unit) using the extern clause. So, we must modified the main.cpp file as follow:

#include <QtCore/QCoreApplication>
#include <iostream>
using namespace std;
// the next 'include' is for CUDA error checks
#include <cuda_runtime.h>
// This is the 'elder trick of the...' - Tell the compiler this function is defined in other place
extern "C"
cudaError_t cuda_main();

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

    // run your cuda application
    cudaError_t cuerr = cuda_main();
    // check for errors is always a good practice!
    if (cuerr != cudaSuccess) cout << "CUDA Error: " << cudaGetErrorString( cuerr ) << endl;

    return a.exec();
}

Finally, we can create our CUDA functions in the cuda_code.cu file indicating that the cuda_main() function is defined here using the extern clause. The next code is an example of thrust, which I consider clearer for this example, taken from the GTC 2010 Talk ‘Thrust by Example, Advanced Features and Techniques’ by Jared Hoberock.

#include <thrust/host_vector.h>
#include <thrust/device_vector.h>
#include <thrust/sort.h>
extern "C"
cudaError_t cuda_main()
{
    // generate 16M random numbers on the host
    thrust::host_vector<int> h_vec(1 << 24);
    thrust::generate(h_vec.begin(), h_vec.end(), rand);
 
    // transfer data to the device
    thrust::device_vector<int> d_vec = h_vec;
 
    // sort data on the device (805 Mkeys/sec on GeForce GTX 480)
    thrust::sort(d_vec.begin(), d_vec.end());
 
    // transfer data back to host
    thrust::copy(d_vec.begin(), d_vec.end(), h_vec.begin());
 
    return cudaGetLastError();
}

 

Tips and tricks

  1. Take a moment to annotate your path to the CUDA toolkit, if your operating system is 32 or 64 bits and the compute capability of your graphic device. You will need that information to adjust your configuration file.
  2. Do not forget run qmake (Build->run qmake) when modify the .pro file
  3. Enjoy the autocomplete feature with the CUDA functions!
  4. Back on line 36 in the .pro file. You can now double click in the Build issue error messages and jump to the file and line of the error.
  5. This is a tutorial without sponsors and has been created only as a guide to help others.
  6. Others have reported that has worked on Windows and Mac, so try it yourself.

Q. How to add cu-files to the Qt Creator Projects tree

You can use an ‘old trick’ for that purpose. First, add the .cu files to the SOURCES:

SOURCES += main.cpp \
cuda_code.cu

At this point, the Qt Creator will add the cuda_code.cu file to the project tree. Below those lines remove the .cu files from the SOURCES:

SOURCES -= cuda_code.cu

The Qt Creator will not remove the file from the project tree!! and the SOURCES variable will hold only the C++ files. This trick also work with the HEADER files.

7 thoughts on “Qt Creator + CUDA + Linux – Review

  1. 1. made thrust cuda_main in vs2015 – OK
    2. but exactly( with my dirs) your code in Qt on the same comp gives:
    C:\Qt\Qt5.6.3\Tools\QtCreator\bin\jom.exe -f Makefile.Release
    C:/Program Files/NVIDIA GPU Computing Toolkit/CUDA/v9.1/bin/nvcc -m64 -O3 -arch=sm_61 -c –compiler-options -fno-strict-aliasing -use_fast_math –ptxas-options=-v -IC:/Program Files/NVIDIA GPU Computing Toolkit/CUDA/v9.1/include -lcudart -lcuda ..\Qt_Con\cuda_code.cu -o release\Obj\cuda_code_cuda.obj 2>&1 | sed -r “s/\(([0-9]+)\)/:\1/g” 1>&2
    jom: C:\Users\sa\Documents\build-Qt_Con-Desktop_Qt_5_6_3_MSVC2015_64bit-Release\Makefile.Release [release\Obj\cuda_code_cuda.obj] Error 255
    jom: C:\Users\sa\Documents\build-Qt_Con-Desktop_Qt_5_6_3_MSVC2015_64bit-Release\Makefile [release] Error 2

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Google photo

You are commenting using your Google account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s