I want to create a .dll from a CUDA code (kernel.cu) in order to use this library from an external C program. After some attempts I just left a simple C function in .cu file. Code follows:
kernel.cu
#include <stdio.h>
#include "kernel.h"
void hello(const char *s) {
printf("Hello %s\n", s);
}/*
kernel.h
#ifndef KERNEL_H
#define KERNEL_H
#include "cuda_runtime.h"
#include "device_launch_parameters.h"
#ifdef __cplusplus
extern "C" {
#endif
void __declspec(dllexport) hello(const char *s);
#ifdef __cplusplus
}
#endif
#endif // KERNEL_H
I tried to first generate a kernel.o object with nvcc and after i used g++ for creating DLL as following:
nvcc -c kernel.cu -o kernel.o
g++ -shared -o kernel.dll kernel.o -L"C:\Program Files\NVIDIA GPU Computing Toolkit\CUDA\v5.0\lib\x64" -lcudart
It works fine and generates kernel.dll. To test DLL file I wrote this simple program main.c:
#include <stdio.h>
#ifdef __cplusplus
extern "C" {
#endif
void __declspec ( dllimport ) hello(const char *s);
#ifdef __cplusplus
}
#endif
int main(void) {
hello("World");
return 0;
}
compiled with:
g++ -o app.exe main.c -I"C:\Program Files\NVIDIA GPU Computing Toolkit\CUDA\v5.0\include" -L. -lkernel
Result is a memory access error when execution starts.
Nevertheless, if I rename .cu file in .c (as it is just C code), using the same commands, it does work. nvcc's output changes, as far as I know because it uses default C compiler instead of CUDA one.
What do you think, is it a problem related with nvcc? Or am I making any mistake?
EDIT: I forgot some info which may be important. Warnings appear in the first call to g++ (when dll is created) and they are different depending on whether .cu .c or .cpp.
.cu
Warning: .drectve `/FAILIFMISMATCH:"_MSC_VER=1600" /FAILIFMISMATCH:"_ITERATOR_DEBUG_LEVEL=0"
/DEFAULTLIB:"libcpmt" /DEFAULTLIB:"LIBCMT" /DEFAULTLIB:"OLDNAMES" /EXPORT:hello ' unrecognized
and it doesn't work.
.cpp and .c
Warning: .drectve `/DEFAULTLIB:"LIBCMT" /DEFAULTLIB:"OLDNAMES" /EXPORT:hello ' unrecognized
and it works.
Solved. I still don't know why happened (maybe it is because of not using official compiler like Robert Crovella said), but replacing the two commands for making a DLL by this one works:
nvcc -o kernel.dll --shared kernel.cu
Note the double dash (nvcc works this way), and the fact of making it directly instead of creating first .o and then making DLL from the object.
In visual studio you can also make it compile into a .dll instead of a .obj file by navigating through the options:
DEBUG -> -Project name- Properties -> Configuration properties -> Configuration Type
Change the option from Application(.exe) to Dynamic Library(.dll)
You can find the dll after compiling in the DEBUG folder or RELEASE folder
Related
I built the shared libraries with MinGW and NOT treated WChar_t as a built-in type
#ifdef _NATIVE_WCHAR_T_DEFINED
typedef wchar_t UShort; // Treat as Built In
#else
typedef unsigned short UShort; // NOT treated as Built In
#endif
When linking the shared libraries with a small program,
g++ -o helloworld main.cpp -I../include/.. -L../lib -l.. // By default treating WChar_t as a built-in type and getting the compilation error (undefined reference to `)
I have checked the g++ command-line options here https://man7.org/linux/man-pages/man1/g++.1.html
and also tried the below option
With -fpreprocessed, predefinition of command line and most
builtin macros is disabled. Macros such as "LINE", which are
contextually dependent, are handled normally. This enables
compilation of files previously preprocessed with "-E
-fdirectives-only".
But not succeed, the error remains.
By setting the flag -D_NATIVE_WCHAR_T_DEFINED=OFF works.
g++ -D_NATIVE_WCHAR_T_DEFINED=OFF -o helloworld main.cpp
-I../include/.. -L../lib -l..
Thank you
I am currently working on a project, where I want to execute some code in Cuda, which should be called from the main c++ file. When I am compiling with Clang only the .cpp files are compiled and the compiler tells me "expected exprission" on the <<<>>> Kernel call notation. Any Idea how I can fix this?
I have a .cuh files with the definition which I am including and a .cu source file. I am using CMake to configure the project and building it with Ninja.
I am using ccached clang++ and supplying "--cuda-path=/usr/local/cuda-10.1 --cuda-gpu-arch=sm_61 -L/usr/local/cuda-10.1/lib64 -lcudart_static -ldl -lrt -pthread -std=c++17" to clang args.
When I add the -x cuda flag, the error does not appear, but instead it tells me that a library that I am linking against is not allowed to overwrite some host function, but I think this is because it wants to compile everything as cuda, which is not intended.
I am passing all files inside my source folder to add_executable in CMake via a GLOB ${APP_PATH}/src/*, which should add all files.
main.cpp
#include "ParticleEngine.cuh"
...
int main(){
simulation_timestep(&this->particles[0], this->gravity, 1, delta_frame,
this->particles.size());
}
ParticleEngine.cuh
#pragma once
#include "cuda_runtime.h"
#include "device_launch_parameters.h"
void simulation_timestep(Particle *particles, ci::vec3 gravity, double mass,
double time_delta, unsigned long long n_particles);
ParticleEngine.cu
#include "ParticleEngine.cuh"
__global__ void particle_kernel(Particle *particles, ci::vec3 *gravity,
double *mass, double *time_delta) {
...
}
void simulation_timestep(Particle *particles, ci::vec3 gravity, double mass,
double time_delta, unsigned long long n_particles) {
... //memcpy stuff
particle_kernel<<<dimgrid, dimblock>>>(cuda_particles, cuda_gravity,
cuda_mass, cuda_time_delta);
...
}
edit:
Full error message:
[build] In file included from ../src/main.cpp:1:
[build] ../src/ParticleEngine.cu:43:20: error: expected expression
[build] particle_kernel<<<dimgrid, dimblock>>>(cuda_particles, cuda_gravity,
[build] ^
edit:
Error message when executing clang with -x cuda:
[build] /home/mebenstein/Cinder/include/glm/gtx/io.inl:97:32: error: __host__ __device__ function 'get_facet' cannot overload __host__ function 'get_facet'
[build] GLM_FUNC_QUALIFIER FTy const& get_facet(std::basic_ios<CTy, CTr>& ios)
[build] ^
[build] /home/mebenstein/Cinder/include/glm/gtx/io.hpp:145:14: note: previous declaration is here
[build] FTy const& get_facet(std::basic_ios<CTy,CTr>&);
[build] ^
I am including the c++ library cinder in main.cpp and this error appears.
#include in C++ works by literally replacing that statement with the contents of the included file. As a consequence, the included file is also parsed as C++ code.
To compile a file as CUDA code, the file needs to be a separate compilation unit, i.e. given as an argument to the clang invocation. It also either needs to have a name ending in .cu, or the -x cuda flag needs to be given to clang.
Update after error messages have been included in the question:
It appears that Cinder does not support compilation of the CUDA part with clang++ because of a difference in how __host__/__device__ attributes are treated.
At this point your options are the following:
You can modify Cinder to also support clang++, it's open source.
You can ask the Cinder authors or third parties whether they are willing to make the necessary changes. A cash incentive may or may not increase willingness.
You can use nvcc to compile the code.
How can I get a CMake generated build system to retrieve source files using an arbitrary shell command and update the build properly?
The motivation for doing this is to migrate from another build system to CMake. The intermediate goal is to have a single list of source files shared between the build systems. The list of source files might actually live inside of the other build system but in general suppose some shell command can retrieve the list of source files. This problem is very similar to the problem of using globbing to get source file names but in this case manually listing all the source files in a CMakeLists.txt file is not a reasonable alternative.
Even if there's no way to get CMake itself to do this, an answer that provides any automated solution would be fine (e.g. a script that wraps the generated build system).
Very simple concrete example of the problem
We have an app that consists of two source files, main.cpp and foo.cpp. For some reason it is desirable to acquire the names of sources files with some shell command instead of listing them in a CMakeLists.txt file. For this example, the files are listed one per line in files.txt and we cat this file. In general, the shell command is some script that retrieves a list of source files in mysterious ways.
main.cpp (ver 1)
#include "foo.h"
int main() {
foo();
}
foo.h
#ifndef FOO_H
#define FOO_H
void foo();
#endif
foo.cpp
#include "foo.h"
#include <iostream>
void foo() {
std::cout << "foo()" << std::endl;
}
files.txt (ver 1)
main.cpp
foo.cpp
CMakeLists.txt
cmake_minimum_required(VERSION 2.8.1)
project(SourcesFromCommand)
# run some external command that retrieves our source files
execute_process(COMMAND cat ${CMAKE_CURRENT_SOURCE_DIR}/files.txt OUTPUT_VARIABLE files)
# turn newline separated relative filenames into cmake list of absolute filenames
string(REPLACE "\n" ";${CMAKE_CURRENT_SOURCE_DIR}/" file_list ${files})
# print filenames to make sure the list came out right
foreach(file ${file_list})
message(${file})
endforeach()
add_executable(main ${file_list})
CMake generates a working build system for a project that consists of the above files. Later, our app is successful and popular so we decide to add new functionality for ver. 2.0. main.cpp now calls bar() which lives in bar.h and bar.cpp. We update files.txt accordingly.
main.cpp (ver 2)
#include "foo.h"
#include "bar.h"
int main() {
foo();
bar();
}
bar.h
#ifndef BAR_H
#define BAR_H
void bar();
#endif
bar.cpp
#include "bar.h"
#include <iostream>
void bar() {
std::cout << "bar()" << std::endl;
}
files.txt (ver 2)
main.cpp
foo.cpp
bar.cpp
The build system previously generated by CMake no longer works -- trying to use it results in linker errors because it doesn't know about bar.cpp. This can be solved manually by touching the CMakeLists.txt file or rerunning the cmake command but the point of a build system is to free us from such arduous and easily forgotten manual labor. How can this be automated?
You can solve this problem with a makefile that touchs the relevant CMakeLists.txt files.
I'll continue from the OP's example and also add a directory, glob_us/ from which we want to glob all filenames matching *.cpp. It contains baz.cpp which is similar to the OP's bar.cpp.
Relevant files:
Makefile
CMakeLists.txt
files.txt
main.cpp
main.h
foo.cpp
foo.h
bar.cpp
bar.h
glob_us/baz.h
glob_us/baz.cpp
The bottom of CMakeLists.txt becomes:
file(GLOB globbed_files glob_us/*.cpp)
include_directories(${CMAKE_CURRENT_SOURCE_DIR}/glob_us)
add_executable(main ${file_list} ${globbed_files})
Makefile contains the following:
MAKEFILE_DIR := $(shell dirname $(realpath $(lastword $(MAKEFILE_LIST))))
GLOBBED := $(wildcard $(MAKEFILE_DIR)/glob_us/*cpp)
# phony target that depends on whatever files we need to touch
cmake: $(MAKEFILE_DIR)/CMakeLists.txt
$(MAKEFILE_DIR)/CMakeLists.txt: $(MAKEFILE_DIR)/files.txt $(GLOBBED)
#touch $(MAKEFILE_DIR)/CMakeLists.txt
.PHONY: cmake
Generate a build system:
mkdir build
cd build
cmake -G $MY_FAVORITE_GENERATOR ..
Then build:
make -f ../Makefile && $MY_FAVORITE_BUILD_SYSTEM_COMMAND
Files can be added to and globbed from glob_us or as in the OP's example, to files.txt, without manual intervention.
I have built a shared library under Eclipse/CDT in C++. To manage my projects tests, I would like to have in the same project the library and an executable for running tests on the library.
How can I do that please ?
For the library itself, I have standard build settings : a Debug and a Release target, with the -fPIC compile option, an artifact type Shared Library, extension so and prefix lib, and the -share linker option.
For the test program, I have added in the same project a main.cpp file:
#ifdef TEST_
#include <cstdlib>
#include <iostream>
#include "config.h"
using namespace std;
int main(int argc, char **argv) {
cout << "Test for project utils" << endl;
return 0;
}
#endif /* TEST_ */
I have added a specific Test target copied from the DEBUG one and adapted for standard executable build settings : suppress the -fPIC compile option, add -D TEST_, modify the artifact type to Executable, supress extension so and prefix lib, suppress the -share option for the linker.
Now, just build Debug, Release, and Test as normal, what can be done independently. The Test target could be easily changed for say Test-Debug and Test-Release, to get a library self-test runned just after installation.
I am trying to include 2 platform-specific stdafx.h files in my .cpp file, but the compiler is unhappy when I try to #ifdef it.
#ifdef _WIN32
#include "stdafx.h"
#elif _MAC
#include "MAC/stdafx.h"
#endif
You may wonder why I am using stdafx.h in the Mac code, but that is not important at the moment :).
When I try to compile the code on Windows, I receive: Fatal Error C1018. I tried enclosing other header files with #ifdef in the same file, and the compiler was happy. Therefore, it looks like Windows doesn't like stdafx.h to be #ifdef-ed, or that Windows only allows #include stdafx.h
to be the first line in the file.
So my question is, why?
Kat
When the compiler includes a pre-compiled header, it basically "forgets" anything that came before the header. Thus your #elif isn't matched to a #if anymore.
This is because you have Precompiled Headers turned on - turn it off and you should be fine.