I've been working on my GPU-raytracer implementation, but as I am new to CUDA I have some problems with compiling and linking the separate .cu files.
My 2 classes: Shader and Lambert. Lambert inherits the interface Shader. When I compile I recieve the following errors:
Error 4 error MSB3721: The command ""G:\Development\CUDA Toolkit\CUDA Toolkit v5.5\bin\nvcc.exe"
-dlink -o "Debug\CUDA RayTracer.device-link.obj" -Xcompiler "/EHsc /W3 /nologo /Od /Zi /RTC1
/MDd " -L"P:\My Projects\CUDA Ray-Tracer\CUDA RayTracer\ThirdParty\SDL\lib\x86" -L"P:\My
Projects\CUDA Ray-Tracer\CUDA RayTracer\CUDA RayTracer\\..\ThirdParty" -L"G:\Development\CUDA
Toolkit\CUDA Toolkit v5.5\lib\Win32" cudart.lib kernel32.lib user32.lib gdi32.lib winspool.lib
comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib
SDL.lib SDLmain.lib -gencode=arch=compute_30,code=sm_30 -G --machine 32 Debug\Camera.cu.obj
Debug\IShader.cu.obj Debug\Lambert.cu.obj Debug\Matrix.cu.obj Debug\Plane.cu.obj
Debug\sdl.cu.obj Debug\cuda_renderer.cu.obj" exited with code -1.
C:\Program Files(x86)\MSBuild\Microsoft.Cpp\v4.0\V110\BuildCustomizations\CUDA 5.5.targets 668
1>nvlink : error : Undefined reference to '_ZN6ShaderD1Ev' in 'Debug/IShader.cu.obj'
1>nvlink : error : Undefined reference to '_ZN6ShaderD0Ev' in 'Debug/IShader.cu.obj'
1>nvlink : error : Undefined reference to '_ZN6ShaderD2Ev' in 'Debug/Lambert.cu.obj'
I have no idea what '_ZN6ShaderD1Ev' means, I think everything is correct in my implementation (C++ wise, not sure what CUDA thinks about it). As far as I know CUDA 5.5 supports virtual functions and inheritance.
I have installed CUDA 5.5 Toolkit and I have enabled the "Generate Relocatable Device Code" in my Visual Studio 2012. Also I've set 'compute_30,sm_30'in order to use 'operator new' (my graphics card is capable of it - GTX670MX). My project consists only of .cu and .cuh files.
My source code:
//IShader.cuh
#ifndef I_SHADER_H
#define I_SHADER_H
#include "Vector3D.cuh"
#include "Color.cuh"
#include "IGeometry.cuh"
__device__ extern Vector cameraPos;
__device__ extern Vector lightPos;
__device__ extern Color lightColor;
__device__ extern float lightPower;
__device__ extern Color ambientLight;
class Shader
{
protected:
Color _color;
public:
__device__ Shader(const Color& color);
__device__ virtual ~Shader();
__device__ virtual Color shade(Ray ray, const IntersectionData& data) = 0;
};
#endif
//IShader.cu
#include "IShader.cuh"
__device__ Shader::Shader(const Color& color)
{
this->_color = color;
}
// Lambert.cuh
#ifndef LAMBERT_H
#define LAMBERT_H
#include "IShader.cuh"
class Lambert : public Shader
{
public:
__device__ Lambert(const Color& diffuseColor);
__device__ Color shade(Ray ray, const IntersectionData& data);
};
#endif
//Lambert.cu
#include "Lambert.cuh"
Vector cameraPos;
Vector lightPos;
Color lightColor;
float lightPower;
Color ambientLight;
__device__ Lambert::Lambert(const Color& diffuseColor)
: Shader(diffuseColor)
{
}
__device__ Color Lambert::shade(Ray ray, const IntersectionData& data)
{
Color result = _color;
result = result * lightColor * lightPower / (data.p - lightPos).lengthSqr();
Vector lightDir = lightPos - data.p;
lightDir.normalize();
double cosTheta = dot(lightDir, data.normal);
result = result * cosTheta;
return result;
}
If you need more code I could give you link to github repo.
I hope you can help me.
Thanks in advance!
C++ enables different entities (e.g., functions) named with the same identifier to belong to different namespaces. To uniquely resolve names, the compiler uses name mangling, that is, it encodes additional information in the name of the involved entities. This is the reason why nvlink is referring to this "obscure" entity _ZN6ShaderD1Ev. In order to restore a more understandable name, a demangling operation is necessary.
Although demangling software exist, I'm often using an online demangler
c++filtjs
Using this page, you can discover that
_ZN6ShaderD1Ev
actually means
Shader::~Shader()
which, in turn, suggests that you are not defining the destructor for the Shader() class.
Related
I have an issue with compiling CUDA code using nvcc. To demonstrate it I created a dummy class to represent a surface in 3D space.
Here goes the file surface.h:
#ifndef SURFACE_H
#define SURFACE_H
class surface
{
private:
float dX; // grid resolution in x [m]
float dY; // grid resolution in y [m]
int nX; // number of elements in x
int nY; // number of elements in y
float* depth; // pointer to depth array [m]
public:
__host__ __device__ void set_dim(const int _nX, const int _nY);
__host__ __device__ void set_res(const float _dX, const float _dY);
__host__ __device__ float get_surface_mm(const int iX, const int iY);
};
#endif
And here is the corresponding surface.cpp file:
#include "surface.h"
__host__ __device__ void surface::set_dim(const int _nX, const int _nY){
nX = _nX;
nY = _nY;
return;
}
__host__ __device__ void surface::set_res(const float _dX, const float _dY){
dX = _dX;
dY = _dY;
return;
}
__host__ __device__ float surface::get_surface_mm(const int iX, const int iY){
float surfLvl = (float) iX * iY;
return surfLvl;
}
I am trying to compile it with nvcc -x cu -arch=sm_50 -I. -dc surface.cpp -o surface.o but get the following errors:
surface.h(4): error: argument list for class template "surface" is missing
surface.cpp(7): error: argument list for class template "surface" is missing
surface.cpp(8): error: identifier "nX" is undefined
surface.cpp(9): error: identifier "nY" is undefined
surface.cpp(13): error: argument list for class template "surface" is missing
surface.cpp(14): error: identifier "dX" is undefined
surface.cpp(15): error: identifier "dY" is undefined
surface.cpp(19): error: argument list for class template "surface" is missing
8 errors detected in the compilation of "/tmp/tmpxft_000bedf2_00000000-6_surface.cpp1.ii".
I really don't get the reason for this error because in my opinion the class is fully defined and the argument list should be known to the compiler. Did any of you already experience a similar issue? If I remove the __device__ and __host__ flags and compile it with gcc everything works fine.
nvcc --version output:
nvcc: NVIDIA (R) Cuda compiler driver
Copyright (c) 2005-2019 NVIDIA Corporation
Built on Wed_Oct_23_19:24:38_PDT_2019
Cuda compilation tools, release 10.2, V10.2.89
I am aware that CUDA does not necessarily support every single feature of object oriented programming but double-checked that the stuff I am trying to compile here should be compatible.
I appreciate every hint :). Thanks a lot in advance.
The only problem with this code was that surface is already a built-in type of cuda.h resulting in this problem. After renaming it everything runs through without error.
I define a class template in files template.cu and template.cuh. I mark the constructor and destructor as device and host callable by using host and device keyword.
template.cuh
#pragma once
#include "cuda_runtime.h"
template<class T>
class Foo
{
public:
__host__ __device__
Foo();
__host__ __device__
~Foo();
};
template.cu
#include "template.cuh"
template<class T>
__host__ __device__
Foo<T>::Foo()
{
}
template<class T>
__host__ __device__
Foo<T>::~Foo()
{
}
// Instantiating template of type int
template
class Foo<int> ;
My main function is inside Kernel.cu file which includes template.cuh header. I just instantiate a Foo object of type int inside host and device code.
#include "cuda_runtime.h"
#include "device_launch_parameters.h"
#include "template.cuh"
__global__ void addKernel(int *c, const int *a, const int *b)
{
Foo<int> f;
int i = threadIdx.x;
c[i] = a[i] + b[i];
}
int main()
{
Foo<int> t;
return 0;
}
When I compile the above code files in a Visual Studio C++ project of type NVIDIA CUDA 6.5 runtime, I get unresolved extern function error with following logs:
1> c:\Users\admin\documents\visual studio 2013\Projects\Test\Testtemplates>"C:\Program Files\NVIDIA GPU Computing Toolkit\CUDA\v6.5\bin\nvcc.exe" -gencode=arch=compute_20,code=\"sm_20,compute_20\" --use-local-env --cl-version 2013 -ccbin "C:\Program Files (x86)\Microsoft Visual Studio 12.0\VC\bin" -I"C:\Program Files\NVIDIA GPU Computing Toolkit\CUDA\v6.5\include" -I"C:\Program Files\NVIDIA GPU Computing Toolkit\CUDA\v6.5\include" -G --keep-dir Debug -maxrregcount=0 --machine 32 --compile -cudart static -g -DWIN32 -D_DEBUG -D_CONSOLE -D_MBCS -Xcompiler "/EHsc /W3 /nologo /Od /Zi /RTC1 /MDd " -o Debug\kernel.cu.obj "c:\Users\admin\documents\visual studio 2013\Projects\Test\Testtemplates\kernel.cu"
1> ptxas fatal : Unresolved extern function '_ZN3FooIiEC1Ev'
1> kernel.cu
What is that I am doing wrong here ?
The reason you get this error is that you did not use device code linking.
Have a look at this article: Separate Compilation and Linking of CUDA C++ Device Code
I just tried the following with your code and it worked for me. Pay attention to the additional flag -dc:
nvcc template.cu kernel.cu -dc
nvcc template.o kernel.o -o kernel
I do not have much experience with Visual Studio directly, I prefer using CMake to cover generating the correct settings for VS.
The following CMakeLists.txt file worked for me on Linux and gcc, you might give it a try on Windows and VS and then compare the generated project settings with the ones you use.
PROJECT(kernel)
FIND_PACKAGE(CUDA REQUIRED)
SET(CUDA_SEPARABLE_COMPILATION ON)
CUDA_ADD_EXECUTABLE(kernel template.cuh template.cu kernel.cu)
I've tried to find a solution to this problem by looking through the old questions and answers, but I can't spot what's wrong in my case. I get the following error:
Error 66 error LNK2019: unresolved external symbol "public: static class PhysicsBody *
__cdecl PhysicsBody::createBox(float,float,enum PhysicsBodyType,float)"
(?createBox#PhysicsBody##SAPAV1#MMW4PhysicsBodyType##M#Z) referenced in function
"public: __thiscall Enemy::Enemy(void)" (??0Enemy##QAE#XZ)
The weird thing is, the code file is there, both .H and .CPP, and they are included in the solution and compiled correctly. Here's the code files:
// Enemy.h
#pragma once
class Enemy {
public:
Enemy();
private:
PhysicsBody* m_body;
};
// Enemy.cpp
#include "Enemy.h"
#include "PhysicsBody.h"
Enemy::Enemy() {
m_body = PhysicsBody::createBox(1.f, 1.f, PhysicsBodyType::Dynamic);
}
// PhysicsBody.h
#pragma once
enum PhysicsBodyType {
Static, Dynamic, Kinematic
};
class PhysicsBody {
public:
static PhysicsBody* createBox(float width, float height, PhysicsBodyType type, float mass = 1.f);
private:
PhysicsBody();
};
// PhysicsBody.cpp
#include "PhysicsBody.h"
PhysicsBody::PhysicsBody() {
}
PhysicsBody* PhysicsBody::createBox(float width, float height, PhysicsBodyType type, float mass) {
return new PhysicsBody();
}
(I have cropped out some non-relevant code here.)
I've literally skimmed through the code tens of times and cannot spot anything wrong with it. I have similar code throughout my project and everything else works. For some reason, this PhysicsBody class causes these problems. I've checked that it's included in the project / solution, the file type is C/C++ Code, it's not marked as content and overall it should be working.
The problem was quite probably caused by a faulty VS project file. I copied the contents of PhysicsBody.h / .cpp files, deleted both files, created new files and pasted the original contents. All code is exactly the same and it works now, so I conclude that it's a VS-related bug.
Bug in the code in the question
The function that is not found is:
PhysicsBody::createBox(float, float, enum PhysicsBodyType, float)
The function that is shown as defined is:
PhysicsBody::createBox(float, float, enum PhysicsBodyType)
There's a different number of arguments between the two functions.
Questions arising:
Which is the correct definition?
How did the erroneous definition get used?
Where was the declaration for the erroneous use?
You may need to simply recompile everything. You may need to look at where your PhysicsBody class is defined because it is defined in two places.
This problem has now been fixed in the question.
No significant bug in the code in the question
With the code as in the amended question (with #include "PhysicsBody.h" added at the start of Enemy.h so the header can be compiled standalone), and ignoring warnings about the unused parameters to the createBox function, I can compile and link the code using g++ from GCC 4.9.1 and a trivial main():
#include "Enemy.h"
int main()
{
Enemy e;
return 0;
}
That suggests to me that the problem is not in the code you show but rather the problem is in the code you don't show. Please study how to create a MCVE (How to create a Minimal, Complete, and Verifiable Example?) or
SSCCE (Short, Self-Contained, Correct Example) — two names and links for the same basic idea.
Please post exactly the minimal code that reproduces the problem. (I created a new subdirectory, placed 5 source files — two headers, two implementation files and a trivial main() — into the directory, and a makefile and compiled from there. I suggest you do the equivalent on your Windows machine.)
If you affirm that the code posted above plus the main.cpp I show does (1) compile and (2) fail to link, thus reproducing the problem, then there is superficially a bug in MSVC. I think that's unlikely to be the case, but funnier things have been known.
For the record, I was compiling on Mac OS X 10.9.4 Mavericks with GCC 4.9.1 and the following commands (with warning messages shown):
$ g++ -O3 -g -std=c++11 -Wall -Wextra -c Enemy.cpp
$ g++ -O3 -g -std=c++11 -Wall -Wextra -c PhysicsBody.cpp
PhysicsBody.cpp:8:43: warning: unused parameter ‘width’ [-Wunused-parameter]
PhysicsBody* PhysicsBody::createBox(float width, float height, PhysicsBodyType type, float mass) {
^
PhysicsBody.cpp:8:56: warning: unused parameter ‘height’ [-Wunused-parameter]
PhysicsBody* PhysicsBody::createBox(float width, float height, PhysicsBodyType type, float mass) {
^
PhysicsBody.cpp:8:80: warning: unused parameter ‘type’ [-Wunused-parameter]
PhysicsBody* PhysicsBody::createBox(float width, float height, PhysicsBodyType type, float mass) {
^
PhysicsBody.cpp:8:92: warning: unused parameter ‘mass’ [-Wunused-parameter]
PhysicsBody* PhysicsBody::createBox(float width, float height, PhysicsBodyType type, float mass) {
^
$ g++ -O3 -g -std=c++11 -Wall -Wextra -c main.cpp
$ g++ -o main *.o
$ ./main
$ echo $?
0
$
I'm really surprised, today I downloaded Ubuntu 12 LTS 32bit and installed build essential.
Then I created a makefile for my project which I just copy pasted from another project from the internet and edited a bit to enable C++11 stuff if it's needed for GLM stuff?
anyway the makefile:
GPP = g++
GCC = gcc
plugin_OUTFILE = "./QuaternionStuff.so"
COMPILE_FLAGS = -std=c++0x -m32 -O3 -fPIC -c -I ./ -w -D LINUX -D PROJECT_NAME=\"plugin\"
plugin = -D plugin $(COMPILE_FLAGS)
all: plugin
clean:
-rm -f *~ *.o *.so
plugin: clean
$(GPP) $(plugin) ./*.cpp
$(GPP) -std=c++0x -m32 --static -fshort-wchar -shared -o $(plugin_OUTFILE) *.o
now, when I run it, linux spits there errors out and I seriously don't understand them..
Now, the code works on windows, compiles fine with highest warning level etc, and it's good!
But the g++ program is somewhat not happy with this:
no matching function for call to ‘GetPitchYawBetweenCoords(glm::vec3, glm::vec3, glm::vec2&)’
note: glm::vec2 GetPitchYawBetweenCoords(glm::vec3&, glm::vec3&)
note: candidate expects 2 arguments, 3 provided
//prototypes:
inline glm::vec2 GetPitchYawBetweenCoords(glm::vec3 &source, glm::vec3 &target);
inline void GetPitchYawBetweenCoords(glm::vec3 &source, glm::vec3 &target, glm::vec2 &output);
And the code, with the according functions which calls it:
//the call
inline void AmxSetVector3(AMX * amx, cell * ¶ms, unsigned char startpos, glm::vec3 vector)
{
//some code here
}
inline void AmxSetVector2Inverse(AMX * amx, cell * ¶ms, unsigned char startpos, glm::vec2 vector)
{
//some code here
}
static cell AMX_NATIVE_CALL GetPitchYawBetweenPositions( AMX* amx, cell* params )
{
glm::vec2 rot;
GetPitchYawBetweenCoords(AmxGetVector3(params,1),AmxGetVector3(params,4),rot);
AmxSetVector2Inverse(amx,params,7,rot);
return 1;
}
How the hell can it not distinguishsuch two very different functions (prototypes)?
This is the most confusing part of all the errors, but there is more :(
I don't see anything that is wrong with that.
So, what I do is: I change (with big pain, because now my code gets quircky because I need to change everything just for the linux distirbution) the functions to different names, I just added an 'R' to the end of the second prototype, but then another ton of errors come up..
In function ‘cell SomeFunction(AMX*, cell*)’:
error: invalid initialization of non-const reference of type ‘glm::vec3&
{aka glm::detail::tvec3<float>&}’ from an rvalue of type ‘glm::detail::tvec3<float>’
and that's again.. on the same function...:
static cell AMX_NATIVE_CALL GetPitchYawBetweenPositions( AMX* amx, cell* params )
{
glm::vec2 rot;
GetPitchYawBetweenCoords(AmxGetVector3(params,1),AmxGetVector3(params,4),rot);
AmxSetVector2Inverse(amx,params,7,rot);//HERE
return 1;
}
What is going on? I have no idea how to fix this..
The G++ version is 4.6
Apparently, AmxGetVector3 returns a glm::detail::tvec3<float>.
According to the standard, this temporary object can't be bound to a non-const reference (this is what the second message is trying to tell you).
Unfortunately, Visual C++ has a silly non-standard extension, enabled by default, that allows that kind of binding.
Change your functions to have these (const-correct) prototypes:
inline glm::vec2 GetPitchYawBetweenCoords(const glm::vec3 &source, const glm::vec3 &target);
inline void GetPitchYawBetweenCoords(const glm::vec3 &source, const glm::vec3 &target, glm::vec2 &output);
I've a strange problem with linking a static member from a dll using Visual Studio Express 2010. On Linux platform
and MSYS/MinGW (GCC) this failure doesn't occurs.
I've a Math library using an export macro explicitly for this library module:
#ifdef WIN32
#ifdef MATH_LIBRARY_EXPORT
#define MATH_LIBRARY_API __declspec(dllexport)
#else
#define MATH_LIBRARY_API __declspec(dllimport)
#endif
#else
//define empty values for linux OS
#define MATH_LIBRARY_API
#endif
And this is a snipped of my Vector class i export with static members:
ifndef BINREV_VECTOR_H__
#define BINREV_VECTOR_H__
// include common header with dll import/export macro
#include <brMath/brCommons.h>
namespace binrev{
namespace brMath{
class MATH_LIBRARY_API brVector3f
{
public:
float m_fX, m_fY, m_fZ;
brVector3f(void);
brVector3f(float x, float y, float z);
...
public:
static const brVector3f ZERO;
static const brVector3f NEGATIVE_UNIT_Z;
...
};
And the cpp module:
// Ensure that the dll hader will be exported
#define MATH_LIBRARY_EXPORT
#include <brMath/brVector3f.h>
namespace binrev{
namespace brMath{
const brVector3f brVector3f::ZERO(0.0f, 0.0f, 0.0f);
const brVector3f brVector3f::NEGATIVE_UNIT_Z( 0.0f, 0.0f, -1.0f);
...
In my Graphics module (is also an dll with an different explicit export macro) using this Math dll i try to access one of those static members:
#include <brMath/brVector3f.h>
brMath::brVector3f brCamera::getDirection(void)
{
return m_orientation.rotate(brMath::brVector3f::NEGATIVE_UNIT_Z);
}
On the other platforms anything works well, but with MVSE 2010 i got
a linker failure:
1>------ Erstellen gestartet: Projekt: ZERO_CHECK, Konfiguration: Debug Win32 ------
2>------ Erstellen gestartet: Projekt: brGraphics, Konfiguration: Debug Win32 ------
2> brCamera.cpp
2>brCamera.obj : error LNK2001: Nicht aufgelöstes externes Symbol ""public: static class binrev::brMath::brVector3f const binrev::brMath::brVector3f::NEGATIVE_UNIT_Z" (?NEGATIVE_UNIT_Z#brVector3f#brMath#binrev##2V123#B)".
2>C:\binrev\repository\binrevengine\modules\brGraphics\trunk\bin\brGraphics.dll : fatal error LNK1120: 1 nicht aufgelöste externe Verweise.
========== Erstellen: 1 erfolgreich, Fehler bei 1, 0 aktuell, 0 übersprungen ==========
I'm not a friend of MVSE and this are my first tries to get our code runable with MVSE. While I've different solutions I've add the brMath.lib as additional dependency at the project settings. I've also set the path of the additional library directory to the location of my brMath.lib. This is the output of the linker command for review of my settings:
/OUT:"C:\binrev\repository\binrevengine\modules\brGraphics\trunk\bin\brGraphics.dll" /INCREMENTAL /NOLOGO
/LIBPATH:"C:\binrev\repository\binrevengine\modules\brMath\trunk\lib\Debug" /DLL "kernel32.lib" "user32.lib" "gdi32.lib"
"winspool.lib" "shell32.lib" "ole32.lib" "oleaut32.lib" "uuid.lib" "comdlg32.lib" "advapi32.lib" "brCore.lib" "brMath.lib"
"c:\binrev\development\vs2010\VC\lib\libboost_signals-vc100-mt-gd-1_47.lib" "c:\binrev \development\vs2010\VC\lib\libboost_system-vc100-mt-gd-1_47.lib"
/MANIFEST /ManifestFile:"brGraphics.dir\Debug\brGraphics.dll.intermediate.manifest" /ALLOWISOLATION
/MANIFESTUAC:"level='asInvoker' uiAccess='false'" /DEBUG /PDB:"C:\binrev\repository \binrevengine\modules\brGraphics\trunk\bin\brGraphics.pdb"
/SUBSYSTEM:CONSOLE /STACK:"10000000" /PGD:"C:\binrev\repository\binrevengine\modules\brGraphics\trunk\bin\brGraphics.pgd" /TLBID:1
/DYNAMICBASE /NXCOMPAT /IMPLIB:"C:/binrev/repository/binrevengine/modules/brGraphics /trunk/lib/Debug/brGraphics.lib" /MACHINE:X86 /ERRORREPORT:QUEUE
It seems too me that anything is linked correctly. When I remove the call of the const static dll member of brVector3f the build is successfull. I think there must be a problem with the const static member. But why in hell only with MVSE ?
I couldn't find any difference to this introducion: http://stackoverflow...c-data-in-a-dll
So it normally should be working ...
Now i running out of ideas what could be wrong.
I'm grateful for any help or hint.
"...When modifying a variable or function at file scope, the static keyword specifies that the variable or function has internal linkage (its name is not visible from outside the file in which it is declared)." from MSDN