CMake script for CUDA 6.0 with C++11 - macos

I am working on a 64-bit Mac OSX 10.9 for my CUDA 6.0 + Boost 1.55.0 + OpenCV 2.4.9 project, compiled using a makefile, but since I will eventually test it on 64-bit Windows 8.1, I thought I'd get acquainted with CMake. Since I am using C++11, I am generating object files for the C++ code with clang++ (version 5.1 (clang-503.0.40), which g++ now links to in mavericks) and CUDA code with nvcc separately, then linking the object files together for the final executable in my makefile.
I have no idea how to do this in CMake though. I tried compiling the CUDA code as a static library (using both CMake built-ins and FindCUDA.cmake utilities) and then linking it, but that did not work. I have not been able to find a solution online which takes C++11 into account.
Here is my CMake script so far:
cmake_minimum_required(VERSION 2.8)
project(pupil_tracker)
include_directories(include)
include_directories(include/cuda)
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11 -Wall")
set(CUDA_NVCC_FLAGS ${CUDA_NVCC_FLAGS};-gencode arch=compute_20, code=sm_20)
#set(CUDA_HOST_COMPILER clang++) # Fails with 'invalid argument '-std=c++11' not allowed with 'C/ObjC''
find_package(Boost COMPONENTS system filesystem REQUIRED)
include_directories(${Boost_INCLUDE_DIR})
find_package(CUDA REQUIRED)
include_directories(${CUDA_INCLUDE_DIRS})
set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} ${CMAKE_CURRENT_SOURCE_DIR}) # So CMake finds FindOpenCV.cmake
find_package(OpenCV REQUIRED)
include_directories(${OpenCV_INCLUDE_DIRS})
CUDA_ADD_LIBRARY(cuda_obj STATIC src/cuda/Tools.cu) # Doesn't seem to work
add_executable(main src/main.cpp src/CenteredHaarFeature.cpp src/PupilTracker.cpp src/Tools.cpp)
target_link_libraries(main ${Boost_LIBRARIES})
target_link_libraries(main ${CUDA_LIBRARIES})
target_link_libraries(main ${OpenCV_LIBS})
target_link_libraries(main ${cuda_obj})
install(TARGETS main DESTINATION ../bin)
If all fails, I'll have to try and set up a MSVC project on my Windows machine to do the same.

The CMAKE_CXX_FLAGS can interfere with the NVCC compilation so you have to be careful about where you put them.
I recreated your setup with a really simple example using only the CUDA library. After rearranging and editing a few of the CMake commands I was able to compile and run the program.
CMakeLists.txt:
cmake_minimum_required(VERSION 2.8)
project(pupil_tracker)
include_directories(include)
include_directories(include/cuda)
# removed a space and added C++11 functionality (note the double '--' for NVCC)
set(CUDA_NVCC_FLAGS ${CUDA_NVCC_FLAGS};-gencode arch=compute_20,code=sm_20;--std=c++11)
set(CUDA_HOST_COMPILER clang++) # shouldn't fail anymore
# didn't test with Boost
# find_package(Boost COMPONENTS system filesystem REQUIRED)
# include_directories(${Boost_INCLUDE_DIR})
find_package(CUDA REQUIRED)
include_directories(${CUDA_INCLUDE_DIRS})
# didn't test with OpenCV
# set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} ${CMAKE_CURRENT_SOURCE_DIR}) # So CMake finds FindOpenCV.cmake
# find_package(OpenCV REQUIRED)
# include_directories(${OpenCV_INCLUDE_DIRS})
CUDA_ADD_LIBRARY(cuda_obj STATIC src/cuda/Tools.cu) # works for me now
# moved the CXX flags to after the cuda_add_library call
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11 -Wall")
add_executable(main src/main.cpp src/Tools.cpp) # only used one c++ class for this test
# target_link_libraries(main ${Boost_LIBRARIES})
target_link_libraries(main ${CUDA_LIBRARIES})
# target_link_libraries(main ${OpenCV_LIBS})
target_link_libraries(main cuda_obj) # changed ${cuda_obj} to cuda_obj
install(TARGETS main DESTINATION ../bin)
The project directory setup can be inferred from the CMake file but for clarification it looks like:
ProjectDir:
CMakeLists.txt
include
Tools.hpp
cuda
Tools.cuh
src
main.cpp
Tools.cpp
cuda
Tools.cu
Tools.cuh:
#ifndef TOOLS_CUH
#define TOOLS_CUH
extern "C"
{
void do_cuda_stuff();
}
#endif
Tools.cu:
#include <cuda_runtime.h>
#include <stdio.h>
extern "C"
{
__global__
void do_cuda_stuff_kernel()
{
int idx = blockIdx.x * blockDim.x + threadIdx.x;
printf("Hello from thread %d!\n", idx);
}
void do_cuda_stuff()
{
// 2 blocks, 3 threads each
do_cuda_stuff_kernel<<<2, 3>>>();
cudaDeviceSynchronize(); // to print results
}
}
Tools.hpp:
#ifndef TOOLS_HPP
#define TOOLS_HPP
class Tools
{
public:
int execute();
};
#endif
Tools.cpp:
#include "Tools.hpp"
#include "Tools.cuh"
int Tools::execute()
{
do_cuda_stuff();
return 0;
}
main.cpp:
#include "Tools.hpp"
int main(void)
{
Tools tools;
return tools.execute();
}
Output:
Hello from thread 3!
Hello from thread 4!
Hello from thread 5!
Hello from thread 0!
Hello from thread 1!
Hello from thread 2!
I'm currently using CUDA 7.5 and OSX 10.10 but I think the biggest issue was the placement of the CMAKE_CXX_FLAGS variable. Hope this helps! Cheers!

Related

In macos 10.15, using CMake's MACOSX_BUNDLE causes qt5.12.11 to get devicePixelRatio of 1?

CMake add to MACOSX_BUNDLE to use, I can build to get the .app folder, but Qt5.12.11 show devicePixelRatio: 1 (expected should be 2).
But when I block the MACOSX_BUNDLE macro, I can't build to get the .app folder, but Qt5.12.11 show devicePixelRatio: 2 (as expected).
This has been confusing me for over a month and I don't know if this is a Qt bug or a CMake bug? Does anyone know the answer?
In macos systems with high resolution display (Retina Display), the device pixel ratio is usually 2.
deam:
// CMakeLists.txt
cmake_minimum_required(VERSION 3.5)
project(Example VERSION 0.1 LANGUAGES CXX)
set(CMAKE_INCLUDE_CURRENT_DIR ON)
set(CMAKE_AUTOUIC ON)
set(CMAKE_AUTOMOC ON)
set(CMAKE_AUTORCC ON)
set(CMAKE_CXX_STANDARD 17)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
find_package(QT NAMES Qt6 Qt5 COMPONENTS Widgets REQUIRED)
find_package(Qt${QT_VERSION_MAJOR} COMPONENTS Widgets REQUIRED)
set(PROJECT_SOURCES
main.cpp
)
if (APPLE)
# add_executable(Example MACOSX_BUNDLE ${PROJECT_SOURCES}) # devicePixelRatio: 1 ???
add_executable(Example ${PROJECT_SOURCES}) # devicePixelRatio: 2 not build .app
else()
# add_executable(Example WIN32 ${PROJECT_SOURCES})
endif()
target_link_libraries(Example PRIVATE Qt${QT_VERSION_MAJOR}::Widgets)
// main.cpp
#include <QApplication>
#include <QScreen>
#include <QDebug>
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
qDebug()<< "devicePixelRatio:" <<QApplication::primaryScreen()->devicePixelRatio();
return a.exec();
}

Mingw64: add a statically linked library adds libstdc++ dependency

I want to accomplish a c++ executable that links to another c++ library of my own without a libstdc++ dependency. I can create such a c++ executable without the library without difficulty. But as soon as I link it to my library, the executable now has a libstdc++ dependency. A requirement is to NOT need to copy libstdc++6.dll (or any other .dll) onto Windows.
I'm building on Linux (Centos 7) using the latest mingw64 (x86_64-w64-mingw32-gcc (GCC) 4.9.3), cross compiling to Windows. Building on MSYS2/MingW has the same unwanted result.
(BTW, I have both libstdc++-static and glibc-static installed)
In the example, two lines are marked "COMMENT ME OUT": one in hello_c/main.cpp and the other in hello_c/CMakeLists.txt. If you comment these out, the reference to the hello_lib library is removed; the project builds and the executable executes on Windows 10 without a libstdc++ dependency. If you uncomment the two lines, the function in the hello_lib library is linked in; the project builds, but won't execute on Windows 10 due to the libstdc++ dependency. (Note: in powershell it silently fails, in an old-school dos/cmd box it displays an error message.)
The example has this structure:
hello_lib/library.cpp
hello_lib/library.h
hello_lib/CMakeLists.txt
hello_c/main.cpp
hello_c/CMakeLists.xt
buildme.sh
toolchain.cmake
## hello_lib/library.h:
int hello();
// hello_lib/library.cpp:
#include "library.h"
int hello() {
return 666;
}
## hello_lib CMakeLists.txt:
cmake_minimum_required(VERSION 3.13)
project(hello_lib)
set(CMAKE_CXX_STANDARD 11)
if(MINGW)
# Including these flags on Linux on Linux build = "Missing ELF Interpreter" error
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -static -static-libgcc -static-libstdc++")
endif()
add_library(hello_lib STATIC library.cpp)
## hello_c/main.cpp:
#include <iostream>
#include "../hello_lib/library.h"
int main() {
std::cout << "Hello, world" << std::endl;
//COMMENT ME OUT:
printf("x = %d\n", hello());
return 0;
}
## hello_c CMakeLists.txt:
cmake_minimum_required(VERSION 3.13)
project(hello_c)
set(CMAKE_CXX_STANDARD 11)
if(MINGW)
# Including these flags on Linux on Linux build = "Missing ELF Interpreter" error
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -static -static-libgcc -static-libstdc++")
endif()
link_directories(../hello_lib/cmake-build-debug)
add_executable(hello_c main.cpp)
# COMMENT ME OUT:
target_link_libraries(hello_c -static-libgcc -static-libstdc++ libhello_lib.a)
## buildme.sh:
#!/bin/bash
set -e
for i in hello_lib hello_c
do
rm -rf $i/cmake-build-debug
mkdir $i/cmake-build-debug
pushd $i/cmake-build-debug
# For building Win64 on Linux (with MinW64):
cmake .. -DCMAKE_TOOLCHAIN_FILE="../toolchain.cmake" -DCMAKE_BUILD_TYPE=Debug
# For building Win64 on Win64/MSYS2/MinW64:
#cmake .. -G "MSYS Makefiles" -DCMAKE_BUILD_TYPE=Debug
# For building Linux on Linux
#cmake .. -DCMAKE_BUILD_TYPE=Debug
make
popd
done
## toolchain.cmake:
set(CMAKE_SYSTEM_NAME Windows)
set(TOOLCHAIN_PREFIX x86_64-w64-mingw32)
set(CMAKE_C_COMPILER ${TOOLCHAIN_PREFIX}-gcc)
set(CMAKE_CXX_COMPILER ${TOOLCHAIN_PREFIX}-g++)
set(CMAKE_RC_COMPILER ${TOOLCHAIN_PREFIX}-windres)
set(CMAKE_FIND_ROOT_PATH /usr/${TOOLCHAIN_PREFIX})
With both MingW64 on Linux, and MingW64/MSYS2 on Windows 10, I get the libstdc++ dependency when I link with the 'hello_lib' library. In both cases if I comment out the reference to hello_lib, the libstdc++ dependency is eliminated.

How to produce .wasm file using emmake

I have this project skeleton on github The project allows to move a cursor using SDL lib. Which I want to port afterward into browser. The files were generated based on this turorial
MouseMove/src/main.cpp:
#include <iostream>
#include <SDL.h>
#include <unistd.h>
int main(int, char**){
if (SDL_Init(SDL_INIT_VIDEO) != 0){
std::cout << "SDL_Init Error: " << SDL_GetError() << std::endl;
return 1;
}
SDL_Window *window = SDL_CreateWindow(
"Mouse coordinates test", 0, 0, 100, 100,
NULL);
usleep(1000);
SDL_WarpMouseInWindow(window , 600, 600);
SDL_Quit();
return 0;
}
MouseMove/CMakeLists.txt:
project(MouseMove)
add_executable(MouseMove src/main.cpp)
target_link_libraries(MouseMove ${SDL2_LIBRARY})
install(TARGETS MouseMove RUNTIME DESTINATION ${BIN_DIR})
CMakeLists.txt:
cmake_minimum_required(VERSION 2.6)
project(webassembly_plugin)
# Use our modified FindSDL2* modules
set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${webassembly_plugin_SOURCE_DIR}/cmake")
# Set an output directory for our binaries
set(BIN_DIR ${webassembly_plugin_SOURCE_DIR}/bin)
# Bump up warning levels appropriately for clang, gcc & msvc
# Also set debug/optimization flags depending on the build type. IDE users choose this when
# selecting the build mode in their IDE
if (${CMAKE_CXX_COMPILER_ID} STREQUAL "GNU" OR ${CMAKE_CXX_COMPILER_ID} STREQUAL "Clang")
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall -Wextra -pedantic -std=c++11")
set(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS} ${CMAKE_CXX_FLAGS_DEBUG} -g")
set(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS} ${CMAKE_CXX_FLAGS_RELEASE} -O2")
elseif (${CMAKE_CXX_COMPILER_ID} STREQUAL "MSVC")
if (CMAKE_CXX_FLAGS MATCHES "/W[0-4]")
string(REGEX REPLACE "/W[0-4]" "/W4" CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS}")
else()
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /W4")
endif()
endif()
# Look up SDL2 and add the include directory to our include path
find_package(SDL2 REQUIRED)
include_directories(${SDL2_INCLUDE_DIR})
# Look in the Lesson0 subdirectory to find its CMakeLists.txt so we can build the executable
add_subdirectory(MouseMove)
cmake/FindSDL2.cmake
I can compile it into an executable file using emake
mkdir build && cd build
cmake -G "Unix Makefiles" -DCMAKE_BUILD_TYPE=Debug ../
emconfigure cmake .
emmake make
This will generate elf executable that I'm able to run on my x86 system and it indeed moves the mouse. How do I produce wasm file that's suitable for WebAssembly stack-based virtual machine? I need to execute this with emcc somehow so it accepts cmake configuration.

Boost generated successfully but can't generate a makefile. Where did I go wrong?

Even though CMake has successfully configured and generated the makefile with Boost, I just can't produce an executable file for ARM processor using the make command as shown below.
Here is my configuration setting:
1.) I downloaded boost library 1.49 compiled in Raspberry Pi in this link:
http://www.raspberrypi.org/phpBB3/viewtopic.php?t=8111&p=195468
2.) The file hierarchy is as follows:
sample-boost
-> boost-stage (Contains the lib, and include directories of the boost taken from number 1)
-> build (Contains the generated files from CMake)
-> CMakeLists.txt
-> main.cpp
NOTE: The ARM Cross Compiler is fully working and I've cross compiled a hello world and run it in Raspberry Pi successfully using CMake in Cygwin (using a cross toolchain file located in C:/cygwin/arm-pi.toolchain.cmake).
main.cpp
#include <iostream>
#include <boost/thread.hpp>
int main(){
cout << "Hello" << endl;
boost::this_thread::sleep(boost::posix_time::millisec(20));
return 0;
}
CMakeLists.txt
cmake_minimum_required(VERSION 2.8)
Project(main)
SET(Boost_INCLUDE_DIR C:/Users/Emmett/Documents/EMMETT/sample-boost/boost-stage/include)
SET(CMAKE_INCLUDE_PATH ${CMAKE_INCLUDE_PATH} "C:/Users/Emmett/Documents/EMMETT/sample-boost/boost-stage/include")
SET(BOOST_ROOT C:/Users/Emmett/Documents/EMMETT/sample-boost/boost-stage)
FIND_PACKAGE(Boost)
message("BOOST LIBRARY" ${Boost_LIBRARY_DIRS})
message("Boost LIBRARIES:" ${Boost_LIBRARIES})
IF(Boost_FOUND)
message("Boost include directory is found")
message("Boost_INCLUDE_DIRS": ${Boost_INCLUDE_DIRS})
include_directories(${Boost_INCLUDE_DIRS})
add_executable(main main.cpp)
target_link_libraries( main ${Boost_LIBRARIES} )
ENDIF(Boost_FOUND)
Boost-stage
-> include (came from sample-boost\boost_1_49_0\boost)
-> lib (came from boost_1_49_0(bin-only)\lib
Also, invoking ccmake . shows that boost_dir is not found. However, boost package is found!
As you can see, it has successfully generated makefiles using CMake but I can't create an executable file for it. I think I missed out something in setting up boost. Maybe I've failed to successfully link the libraries? Does not the
message("Boost LIBRARIES:" ${Boost_LIBRARIES})
display the library files?
ADDITION: I did what you ask for. Here is my new cmakelists.txt
cmake_minimum_required(VERSION 2.8)
Project(main)
SET(Boost_INCLUDE_DIR C:/Users/Emmett/Documents/EMMETT/sample-boost/boost-stage/include)
SET(CMAKE_INCLUDE_PATH ${CMAKE_INCLUDE_PATH} "C:/Users/Emmett/Documents/EMMETT/sample-boost/boost-stage/include")
SET(BOOST_ROOT C:/Users/Emmett/Documents/EMMETT/sample-boost/boost-stage)
SET(Boost_USE_STATIC_LIBS TRUE)
SET(Boost_DEBUG ON)
#FIND_PACKAGE(Boost)
FIND_PACKAGE(Boost COMPONENTS thread)
message("BOOST LIBRARY: " ${Boost_LIBRARY_DIRS})
message("Boost LIBRARIES: " ${Boost_LIBRARIES})
message("LIBS : " ${LIBS})
IF(Boost_FOUND)
message("Boost include directory is found")
message("Boost_INCLUDE_DIRS: "${Boost_INCLUDE_DIRS})
include_directories(${Boost_INCLUDE_DIRS})
add_executable(main main.cpp)
target_link_libraries( main ${Boost_LIBRARIES} )
ENDIF(Boost_FOUND)
Here is the output console:
For using the boost thread module with CMake you must do
find(Boost COMPONENTS thread)
Normaly, this add the path to the boost thread lib in Boost_LIBRARIES var.

CUDA 5.0 separate compilation of library with cmake

The buildtime of my cuda library is increasing and so I thought that separate compilation introduced in CUDA 5.0 might help me. I couldn't figure out how to achieve separate compilation with cmake. I looked into the NVCC documentation and found how to compile device object (using the -dc option) and how to link them (using the -dlink). My attempts to get it running using cmake failed. I'm using cmake 2.8.10.2 and the head of the trunk of the FindCUDA.cmake. I couldn't however find out how to specify which files should be compiled and how to link them into a library.
Especially the syntax of the function(CUDA_LINK_SEPARABLE_COMPILATION_OBJECTS output_file_var cuda_target options object_files source_files)
is unclear to me because I don't know what the output_file_var and the cuda_target are.
Here the not working results of my attemps:
cuda_compile(DEVICEMANAGER_O devicemanager.cu OPTIONS -dc)
cuda_compile(BLUB_O blub.cu OPTIONS -dc)
CUDA_LINK_SEPARABLE_COMPILATION_OBJECTS(TEST_O gpuacceleration
"" DEVICEMANGER_O BLUB_O)
set(LIB_TYPE SHARED)
#cuda_add_library(gpuacceleration ${LIB_TYPE}
#${gpuacc_SRCS}
#devicemanager.cu
# blub.cu
#DEVICEMANAGER_O
# TEST_O
#)
Does anyone know how to compile and link a cuda library using cmake?
Thanks in advance.
EDIT:
After a friend consulted the developer of the FindCUDA.cmake, a bug got fixed in the example provided with FindCUDA.cmake (https://gforge.sci.utah.edu/gf/project/findcuda/scmsvn/?action=browse&path=%2Fcheckout%2Ftrunk%2FFindCuda.html).
I'm now able to build the example.
In my project I can build the library as needed using the following (cmake 2.8.10 required):
set(LIB_TYPE SHARED)
set(CUDA_SEPARABLE_COMPILATION ON)
cuda_add_library(gpuacceleration ${LIB_TYPE}
blub.cu
blab.cu
)
BUT:
I cannot link against this library. When I builded the lib without separate compilation i was able to link against it.
Now getting the following error:
undefined reference to `__cudaRegisterLinkedBinary_53_tmpxft_00005ab4_00000000_6_blub_cpp1_ii_d07d5695'
for every file with a function used in the interface. Seems strange since it builds without any warning etc.
Any ideas how to get this working?
EDIT:
I finally figured out how to do this. See #PHD's and my answer for details.
I finally got it running ;)
In Addition to the answer of #PHD and my comment on it I modified: set(BUILD_SHARED_LIBS OFF) in my CMakeLists.txt since shared libs are not supported for separate compilation according to the nvcc manually v5.0 page 40.
In addition to that use the latest rev (1223) from the repository instead of rev 1221. I contacted the developer and he fixed some issue blocking this.
This revision doesn't set the nvcc -arch=sm_xx flag correctly, so I added this manually for my project and informed the developer of FindCUDA.cmake. So this might get fixed in the future.
Don't forget to get cmake > 2.8.10 for this to work.
Hope this helps anyone but me ;)
Here is my CMakeLists.txt:
#Required for CUDA-Check
cmake_minimum_required(VERSION 2.8.10)
project(gpulib)
set(CMAKE_MODULE_PATH "${CMAKE_SOURCE_DIR}/CMake/cuda" ${CMAKE_MODULE_PATH})
# ============================================
# === Target
# ============================================
file(GLOB_RECURSE gpuacc_SRCS "*.cu")
include_directories(.)
# ---------------------------------------
# Find Cuda
find_package(CUDA REQUIRED)
set(CUDA_ATTACH_VS_BUILD_RULE_TO_CUDA_FILE ON)
set(BUILD_SHARED_LIBS OFF)
set(CUDA_SEPARABLE_COMPILATION ON)
#list(APPEND CUDA_NVCC_FLAGS -arch=sm_20)
set(LIB_NAME "gpuacceleration")
cuda_add_library(${LIB_NAME}
${gpuacc_SRCS}
OPTIONS -DSTUFF="blah blah"
RELEASE -DNDEBUG
DEBUG -g -DDEBUG
)
set(PUBLIC_HEADERS "myheader1.h;myheader2.h")
INSTALL(FILES ${PUBLIC_HEADERS} DESTINATION include)
INSTALL(FILES "${CMAKE_BINARY_DIR}/src/lib${LIB_NAME}.a" DESTINATION lib)
EDIT: this is not working!
The problem is that there are undefined references to all cuda functions (eg. cudaMalloc) when linking the generated library when building a executable in the main project.
Still working on it
EDIT (2016-03-15): Yes, it is confirmed as a bug in FindCUDA: https://cmake.org/Bug/view.php?id=15157
TL;DR: This seems to be a bug in FindCUDA, which makes objects lose info on external definitions before the final linking.
The problem is that, even if separable compilation is enabled, a linking step is still performed for all the targets individually before the final linking.
For instance, I have module.cu with:
#include "module.h"
#include <cstdio>
double arr[10] = {1,2,3,4,5,6,7,8,9,10};
__constant__ double carr[10];
void init_carr() {
cudaMemcpyToSymbol(carr,arr,10*sizeof(double));
}
__global__ void pkernel() {
printf("(pkernel) carr[%d]=%g\n",threadIdx.x,carr[threadIdx.x]);
}
void print_carr() {
printf("in print_carr\n");
pkernel<<<1,10>>>();
}
and module.h with:
extern __constant__ double carr[10];
extern double arr[10];
void print_carr();
void init_carr();
and finally main.cu with:
#include "module.h"
#include <cstdio>
__global__ void kernel() {
printf("(kernel) carr[%d]=%g\n",threadIdx.x,carr[threadIdx.x]);
}
int main(int argc, char *argv[]) {
printf("arr: %g %g %g ..\n",arr[0],arr[1],arr[2]);
kernel<<<1,10>>>();
cudaDeviceSynchronize();
print_carr();
cudaDeviceSynchronize();
init_carr();
cudaDeviceSynchronize();
kernel<<<1,10>>>();
cudaDeviceSynchronize();
print_carr();
cudaDeviceSynchronize();
return 0;
}
This then works fine with the following Makefile:
NVCC=nvcc
NVCCFLAGS=-arch=sm_20
LIB=libmodule.a
OBJS=module.o main.o
PROG=extern
$(PROG): main.o libmodule.a
$(NVCC) $(NVCCFLAGS) -o $# $^
%.o: %.cu
$(NVCC) $(NVCCFLAGS) -dc -c -o $# $^
$(LIB): module.o
ar cr $# $^
clean:
$(RM) $(PROG) $(OBJS) $(LIB)
But then I try to use the following CMakeLists.txt:
CMAKE_MINIMUM_REQUIRED(VERSION 2.8.8)
PROJECT(extern)
FIND_PACKAGE(CUDA REQUIRED)
SET(CUDA_SEPARABLE_COMPILATION ON)
SITE_NAME(HOSTNAME)
SET(CUDA_NVCC_FLAGS ${CUDA_NVCC_FLAGS} -arch=sm_20)
cuda_add_library(module module.cu)
CUDA_ADD_EXECUTABLE(extern main.cu)
TARGET_LINK_LIBRARIES(extern module)
When then compiling, what then happens is that the following:
$ cmake ..
-- The C compiler identification is GNU 4.9.2
...
$ make VERBOSE=1
...
[ 25%] Building NVCC (Device) object CMakeFiles/module.dir//./module_generated_module.cu.o
...
-- Generating <...>/build/CMakeFiles/module.dir//./module_generated_module.cu.o
/usr/local/cuda/bin/nvcc <...>/module.cu -dc -o <...>/build/CMakeFiles/module.dir//./module_generated_module.cu.o -ccbin /usr/bin/cc -m64 -Xcompiler ,\"-g\" -arch=sm_20 -DNVCC -I/usr/local/cuda/include
[ 50%] Building NVCC intermediate link file CMakeFiles/module.dir/./module_intermediate_link.o
/usr/local/cuda/bin/nvcc -arch=sm_20 -m64 -ccbin "/usr/bin/cc" -dlink <...>/build/CMakeFiles/module.dir//./module_generated_module.cu.o -o <...>/build/CMakeFiles/module.dir/./module_intermediate_link.o
...
/usr/bin/ar cr libmodule.a CMakeFiles/module.dir/./module_generated_module.cu.o CMakeFiles/module.dir/./module_intermediate_link.o
/usr/bin/ranlib libmodule.a
...
[ 50%] Built target module
[ 75%] Building NVCC (Device) object CMakeFiles/extern.dir//./extern_generated_main.cu.o
...
-- Generating <...>/build/CMakeFiles/extern.dir//./extern_generated_main.cu.o
/usr/local/cuda/bin/nvcc <...>/main.cu -dc -o <...>/build/CMakeFiles/extern.dir//./extern_generated_main.cu.o -ccbin /usr/bin/cc -m64 -Xcompiler ,\"-g\" -arch=sm_20 -DNVCC -I/usr/local/cuda/include -I/usr/local/cuda/include
...
[100%] Building NVCC intermediate link file CMakeFiles/extern.dir/./extern_intermediate_link.o
/usr/local/cuda/bin/nvcc -arch=sm_20 -m64 -ccbin "/usr/bin/cc" -dlink <...>/build/CMakeFiles/extern.dir//./extern_generated_main.cu.o -o <...>/build/CMakeFiles/extern.dir/./extern_intermediate_link.o
nvlink error : Undefined reference to 'carr' in '<...>/build/CMakeFiles/extern.dir//./extern_generated_main.cu.o'
Clearly, the problem are the nvcc -dlink obj.o -o obj_intermediate_link.o lines. Then, I guess, the info on external definitions are lost. So, the question is, it is possible to make CMake/FindCUDA not do this extra linking step?
Otherwise, I would argue that this is a bug. Do you agree? I can file a bug report with CMake.
Tested it with nvcc version:
nvcc: NVIDIA (R) Cuda compiler driver Copyright (c) 2005-2012 NVIDIA
Corporation Built on Fri_Sep_21_17:28:58_PDT_2012 Cuda compilation
tools, release 5.0, V0.2.1221
and svn revision:
URL: https://gforge.sci.utah.edu/svn/findcuda/trunk
Repository Root: https://gforge.sci.utah.edu/svn/findcuda
Repository UUID: 81322f20-870f-0410-845c-a4cd4664c908
Revision: 1221
Node Kind: directory
Schedule: normal
Last Changed Rev: 1221
Last Changed Date: 2013-01-28 22:31:07 +0100 (Mon, 28 Jan 2013)
In this example includes following classes:
lib.h / lib.cu
kernel.h / kernel.cu
kernel.cu contains a simple CUDA kernel and a class with a public method to call the CUDA kernel. The class lib contains an instance of the class kernel and a method calling the public method of class kernel.
Following CMakeLists.txt works with this configuration:
cmake_minimum_required(VERSION 2.6.2)
project(Cuda-project)
set(CMAKE_MODULE_PATH "${CMAKE_SOURCE_DIR}/CMake/cuda" ${CMAKE_MODULE_PATH})
find_package(CUDA QUIET REQUIRED)
set(CUDA_ATTACH_VS_BUILD_RULE_TO_CUDA_FILE OFF)
set(BUILD_SHARED_LIBS ON)
list(APPEND CUDA_NVCC_FLAGS -DBLAH="he he" -DTEST1="this is a test")
CUDA_ADD_LIBRARY(test_lib
kernel.cu
lib.cu
# SHARED
# STATIC
OPTIONS -DSTUFF="blah blah"
RELEASE --use_fast_math -DNDEBUG
DEBUG -g -DDEBUG
)
INSTALL(FILES lib.h kernel.h
DESTINATION include)
INSTALL(FILES "${CMAKE_BINARY_DIR}/libtest_lib.so"
DESTINATION lib)
I couldn't make it works using CUDA_ADD_EXECUTABLE so I created a function that makes a custom target to do so.
function(add_cuda_exe_lib name files libraries is_lib)
set (obj_list)
foreach(file ${files})
add_custom_command(
OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/${file}.o
DEPENDS ${file}
COMMAND ${CMAKE_COMMAND} -E cmake_echo_color --blue "Building NVCC Device object ${CMAKE_CURRENT_SOURCE_DIR}/${file}"
COMMAND ${CUDA_NVCC_EXECUTABLE} ${CUDA_NVCC_FLAGS} -dc "${CMAKE_CURRENT_SOURCE_DIR}/${file}" -o "${CMAKE_CURRENT_BINARY_DIR}/${file}.o"
COMMENT "Building ${CMAKE_CURRENT_SOURCE_DIR}/${file}"
VERBATIM
)
LIST(APPEND obj_list ${CMAKE_CURRENT_BINARY_DIR}/${file}.o)
endforeach()
set (lib_list)
LIST(APPEND lib_list "-lcudadevrt")
foreach(library_name ${libraries})
LIST(APPEND lib_list "-l${library_name}")
endforeach()
set (flags ${CUDA_NVCC_FLAGS})
if (is_lib)
LIST(APPEND flags "-dlink")
set (obj_name "${CMAKE_CURRENT_BINARY_DIR}/${name}.so")
else()
set (obj_name "${CMAKE_CURRENT_BINARY_DIR}/${name}")
endif()
add_custom_target(${name} ALL
COMMAND ${CMAKE_COMMAND} -E cmake_echo_color --red "Linking CXX executable ${name}"
COMMAND ${CUDA_NVCC_EXECUTABLE} ${flags} ${obj_list} ${lib_list} -o ${obj_name}
DEPENDS ${obj_list}
COMMENT "Linking ${name}"
)
endfunction()
function(add_cuda_exe name files libraries)
add_cuda_exe_lib(${name} "${files}" "${libraries}" OFF)
endfunction()
function(add_cuda_lib name files libraries)
add_cuda_exe_lib(${name} "${files}" "${libraries}" ON)
endfunction()
Now, to generate a lib, just use:
add_cuda_lib(testar "devicemanager.cu;blub.cu" "")
Or this to generate an executable:
add_cuda_exe(testar "devicemanager.cu;blub.cu" "")
The last param is a list of libs to be attached.
I hope it helps.

Resources