I'm having issues when compiling/Linking with LTO enabled with GCC 4.8.1. I get undefined references to symbols in a DLL even though they seem to be present. The strange thing is, without LTO enabled it compiles and links successfully. LTO seems to struggle when there is a virtual destructor that hasn't been defined in the derived class.
Removing the DECLSPEC makes it compile and work with LTO enabled.
Dependency walker shows the symbols are there. The link time optimizer just can't seem to find them.
Declaring any type of destructor in derived class Test makes it work.
Removing LTO optimization also makes it work successfully, I'm wondering why this is an issue.
Test is a shared library, Main links to the shared library.
Test.h
#include <string>
#ifdef SOURCE
#define DECL __declspec(dllexport)
#warning Exporting!
#else
#define DECL __declspec(dllimport)
#warning Importing!
#endif
class DECL TestBase
{
public:
TestBase(const std::string testing);
virtual ~TestBase();
std::string getTesting();
private:
std::string _testing;
};
class DECL Test : public TestBase
{
public:
Test(const std::string testing);
//~Test(); //removing causes a linker error with LTO! Fine without LTO.
};
Test.cpp
#include "Test.h"
TestBase::TestBase(const std::string testing)
{
_testing = testing;
}
TestBase::~TestBase()
{
}
std::string TestBase::getTesting()
{
return _testing;
}
Test::Test(const std::string testing) :
TestBase(testing)
{
}
/*Test::~Test() //removing causes a linker error with LTO! Fine without LTO.
{
}*/
Main.cpp
#include "Test.h"
#include <iostream>
int main()
{
Test test("testing!");
std::cout << test.getTesting() << std::endl;
return 0;
}
Excuse my messy makefile..
CC=g++
LD=g++
LIBCFLAGS= -O3 -march=pentium4 -mfpmath=sse -flto -fuse-linker-plugin
LIBEXTRA= -c -DSOURCE
LIBLDFLAGS= ${LIBCFLAGS} -shared
LIBSOURCES=Test.cpp
LIBRARY=Test.dll
EXECFLAGS= -O3 -march=pentium4 -mfpmath=sse -flto -fuse-linker-plugin
EXTRA= -c
EXELDFLAGS= ${EXECFLAGS} -L. -lTest
SOURCES=Main.cpp
EXECUTABLE=main
LIBOBJECTS=$(LIBSOURCES:.cpp=.o)
OBJECTS=$(SOURCES:.cpp=.o)
all: $(SOURCES) $(LIBRARY) $(EXECUTABLE)
$(LIBRARY): $(LIBOBJECTS)
$(LD) $(LIBLDFLAGS) $(LIBOBJECTS) -o $#
$(EXECUTABLE): $(OBJECTS)
$(LD) $(EXELDFLAGS) $(OBJECTS) -o $#
$(OBJECTS): CFLAGS := $(EXECFLAGS) $(EXTRA)
$(LIBOBJECTS): CFLAGS := $(LIBCFLAGS) $(LIBEXTRA)
.cpp.o:
#echo "... Making: $#"
$(CC) $(CFLAGS) $< -o $#
clean:
- del /f /q *.o
- del /f /q *.dll
- del /f /q *.exe
Related
I am writing a c++/CUDA library with multiple calls to kernels.
EDIT: I think the original post was a little long, so I have created a better example. Original post below.
Here is the project simplified to a minimal example. It will not compile, and gives the following error:
nvcc -Xcompiler -fPIC -x cu -c -dc -o myclass.o myclass.cpp
nvcc -Xcompiler -fPIC --lib myclass.o kernel.cu -o libhelpme.a -I.
ptxas fatal : Unresolved extern function '_ZN7myclassC1Ei'
makefile:8: recipe for target 'lib' failed
make: *** [lib] Error 255
All documentation on this topic points towards compiling an executable or an object file; I want to do neither of these, rather a static library specifically. How do I do this?
The code:
makefile
program: class lib
nvcc -o program main.cc -I. -L. -lhelpme
class:
nvcc -Xcompiler -fPIC -x cu -c -dc -o myclass.o myclass.cpp
lib: class
nvcc -Xcompiler -fPIC --lib myclass.o kernel.cu -o libhelpme.a -I.
clean:
rm *.o *.a program
main.cc
#include "stdio.h"
#include <iostream>
#include "kernel.h"
int main()
{
std::cout << "hello world" << std::endl;
wrapper();
return 0;
}
myclass.h
#ifdef __CUDACC__
#define COMMON __host__ __device__
#else
#define COMMON
#endif
#ifndef M
#define M
class myclass
{
public:
int x;
COMMON myclass(int y);
COMMON void increment();
};
#endif
myclass.cpp
#include "myclass.h"
#ifdef __CUDACC__
#define COMMON __host__ __device__
#else
#define COMMON
#endif
COMMON myclass::myclass(int y)
{
x = y;
}
COMMON void myclass::increment()
{
x += 1;
}
kernel.h
extern void wrapper();
kernel.cu
#include "stdio.h"
#include <iostream>
#include "myclass.h"
class myotherclass
{
public:
int x;
COMMON myotherclass(int y) {x = y;}
COMMON void decrement() {x -= 1;}
};
__global__ void dokernel()
{
myotherclass p(8); //This compiles just fine.
myclass q(7); //This will not compile
}
void wrapper()
{
std::cout << "hello from wrapper\n";
myclass q(1);
myotherclass s(4);
std::cout << "x = " << s.x << "\n";
s.decrement();
std::cout << "x = " << s.x << "\n";
dokernel<<<1,1>>>();
}
I am slowly becoming convinced that this is impossible...
ORIGINAL POST: I have a number of c++ source/header files, e.g. vec.cpp and vec.h being compiled to object files, e.g. vec.o
Here is an example: vec.h
class vec
{
public:
realnum x,y,z;
__host__ __device__ vec(float _x, float _y, float _z);
}
vec.cpp
__host__ __device__ vec::vec(float _x, float _y, float _z) {x = _x; y = _y; z = _z;}
Here is my full makefile (still in the making):
CC=nvcc
CFLAGS = -Wall -g -O3
HOME_DIR = $(shell pwd)
SRC_DIR := ${HOME_DIR}/../src
OBJ_DIR := ${HOME_DIR}/../lib
LIB_DIR := ${HOME_DIR}/../lib
KER_DIR := ${HOME_DIR}/../kernel
SRC_FILES := $(wildcard $(SRC_DIR)/*.cpp)
OBJ_FILES := $(patsubst $(SRC_DIR)/%.cpp,$(OBJ_DIR)/%.o,$(SRC_FILES))
LPROPS := -L${LIB_DIR} -lcuprops
LMAIN := -L${LIB_DIR} -lsharc
LRDR := -L${LIB_DIR} -lcurdr
INCL_PROPS := -I${SRC_DIR} -I${KER_DIR}
program: $(LIB_DIR)/libcurdr.so ${LIB_DIR}/libsharc.so $(LIB_DIR)/libcuprops.so $(OBJ_FILES)
${CC} -o $# main.cc -I${SRC_DIR} ${LPROPS} ${LMAIN} ${LRDR}
${LIB_DIR}/libsharc.so: $(OBJ_FILES) $(LIB_DIR)/libcuprops.so
${CC} -Xcompiler -fPIC --shared ${OBJ_FILES} -o $(LIB_DIR)/libsharc.so ${INCL_PROPS}
$(OBJ_DIR)/%.o: $(SRC_DIR)/%.cpp
${CC} -Xcompiler -fPIC -dc -o $# $< ${INCL_PROPS}
$(LIB_DIR)/libcuprops.so:
${CC} -Xcompiler -fPIC --shared -o $(LIB_DIR)/libcuprops.so ${KER_DIR}/nvidia_properties.cu ${INCL_PROPS}
$(LIB_DIR)/libcurdr.so: $(OBJ_FILES)
${CC} -Xcompiler -fPIC --shared ${OBJ_FILES} ${KER_DIR}/gpu_rdr.cu -o $(LIB_DIR)/libcurdr.so ${INCL_PROPS}
clean:
rm ${LIB_DIR}/*
When I make I get the following:
ptxas fatal : Unresolved extern function '_ZN3vecC1Eddd'
I have a kernel where I try to initialize a vector:
__global__ void SOME_KERNEL()
{
int row = blockIdx.y*blockDim.y + threadIdx.y;
int col = blockIdx.x*blockDim.x + threadIdx.x;
if (row < dev_height && col < dev_width)
{
vec t(0,0,0); //Compiles nicely when I comment out this line!
}
}
I have read about separate compiling and linking where it is claimed that the typical project architecture (that I believe that I am using) is compatible with separate compiling and linking via the following:
objects = main.o particle.o v3.o
all: $(objects)
nvcc -arch=sm_20 $(objects) -o app
%.o: %.cpp
nvcc -x cu -arch=sm_20 -I. -dc $< -o $#
clean:
rm -f *.o app
Note the use of the "-dc" flag, which is consistent with this answer.
At this point I have tried so many things that I am completely lost. So, how can I compile this project?
In the case that it is helpful, here is the full output from make:
nvcc -Xcompiler -fPIC -dc -o /home/wvn/dirs/projects/sharc/build/../lib/mat33.o /home/wvn/dirs/projects/sharc/build/../src/mat33.cpp -I/home/wvn/dirs/projects/sharc/build/../src -I/home/wvn/dirs/projects/sharc/build/../kernel
nvcc -Xcompiler -fPIC -dc -o /home/wvn/dirs/projects/sharc/build/../lib/vec.o /home/wvn/dirs/projects/sharc/build/../src/vec.cpp -I/home/wvn/dirs/projects/sharc/build/../src -I/home/wvn/dirs/projects/sharc/build/../kernel
nvcc -Xcompiler -fPIC -dc -o /home/wvn/dirs/projects/sharc/build/../lib/sharc.o /home/wvn/dirs/projects/sharc/build/../src/sharc.cpp -I/home/wvn/dirs/projects/sharc/build/../src -I/home/wvn/dirs/projects/sharc/build/../kernel
nvcc -Xcompiler -fPIC -dc -o /home/wvn/dirs/projects/sharc/build/../lib/boundingbox.o /home/wvn/dirs/projects/sharc/build/../src/boundingbox.cpp -I/home/wvn/dirs/projects/sharc/build/../src -I/home/wvn/dirs/projects/sharc/build/../kernel
nvcc -Xcompiler -fPIC --shared /home/wvn/dirs/projects/sharc/build/../lib/mat33.o /home/wvn/dirs/projects/sharc/build/../lib/vec.o /home/wvn/dirs/projects/sharc/build/../lib/sharc.o /home/wvn/dirs/projects/sharc/build/../lib/boundingbox.o /home/wvn/dirs/projects/sharc/build/../kernel/gpu_rdr.cu -o /home/wvn/dirs/projects/sharc/build/../lib/libcurdr.so -I/home/wvn/dirs/projects/sharc/build/../src -I/home/wvn/dirs/projects/sharc/build/../kernel
ptxas fatal : Unresolved extern function '_ZN3vecC1Eddd'
makefile:32: recipe for target '/home/wvn/dirs/projects/sharc/build/../lib/libcurdr.so' failed
make: *** [/home/wvn/dirs/projects/sharc/build/../lib/libcurdr.so] Error 255
Referring to the UPDATED post, not the ORIGINAL post.
As indicated in the comments, one of the things needed was to add -x cu when you are compiling files that end in .cpp but contain CUDA constructs or device code. You've already added that in the proper place.
Your discussion around your COMMON macro has no bearing on this. They serve separate purposes. The macro is not a substitute for -x cu.
The other missing thing is that you need to instruct nvcc at the static library generation point that relocatable device code and device linking is needed. You do this by adding -rdc=true to the compile command line. Your Makefile could be modified like this:
lib: class
nvcc -Xcompiler -fPIC -rdc=true --lib myclass.o kernel.cu -o libhelpme.a -I.
This is needed because you have device code in one compilation unit (kernel.cu) that is calling device code in another compilation unit (myclass.cpp).
With that change, your UPDATED post/project compiles without issue for me and also runs without error.
$ make clean
rm *.o *.a program
$ make
nvcc -Xcompiler -fPIC -x cu -c -dc -o myclass.o myclass.cpp
nvcc -Xcompiler -fPIC -rdc=true --lib myclass.o kernel.cu -o libhelpme.a -I.
nvcc -o program main.cc -I. -L. -lhelpme
$ cuda-memcheck ./program
========= CUDA-MEMCHECK
hello world
hello from wrapper
x = 4
x = 3
========= ERROR SUMMARY: 0 errors
$
I'm new to C++, and I'm having some trouble setting up a simple class reference.
Class: Test.hh
#ifndef _TEST_HH_
#define _TEST_HH_
class Test {
public:
Test (double x);
};
#endif
Class Test.cc
#include "Test.hh"
#include <stdio.h>
Test::Test(double x) {
printf("%f",x);
}
Now I want to access this class from another class:
Class: DriverClass.hh
#ifndef _DRIVERCLASS_HH_
#define _DRIVERCLASS_HH_
#include "Test.hh"
class DriverClass {
public:
DriverClass(double y);
Test *t;
}
#endif
Class DriverClass.cc
#include "DriverClass.hh"
DriverClass::DriverClass(double y) {
t = new Test(y);
}
However, I get an error: "undefined reference to 'Test::Test(double)?
Does anyone know what might be wrong? Please assume that DriverClass is being called directly from a main method (not shown).
There is still an error in your post - a missing ; after the DriverClass
declaration. The rest is correct.
You should compile and link all the sources. The following is a sample Makefile and a
sample test code.
Makefile
all: t
t: t.cc DriverClass.cc Test.cc
g++ -Wall -g -o $# $^
clean:
rm -f *.o t
However, note that it's generally recommended to compile the sources into objects separately in order to compile only the sources changed after the last compilation. For example:
CFLAGS=-Wall -g
all: t
t: t.o DriverClass.o Test.o
g++ -o $# $^
t.o: t.cc DriverClass.o Test.o
g++ $(CFLAGS) -c $< -o $#
DriverClass.o: DriverClass.cc
g++ $(CFLAGS) -c $< -o $#
Test.o: Test.cc
g++ $(CFLAGS) -c $^ -o $#
clean:
rm -f *.o t
I've used the GNU compiler. For the meaning of $# and $^ variables refer to the official documentation.
t.cc
#include "Test.hh"
#include "DriverClass.hh"
int main(int argc, char const* argv[])
{
DriverClass d(10.4);
return 0;
}
Testing
$ make
g++ -Wall -g -o t t.cc DriverClass.cc Test.cc
$ ./t
10.400000
P.S.: don't forget to delete the allocated object.
I am attempting to write a makefile for the Cell Broadband Engine (PS3), which will link an external library.
The Makefile is as follows:
PROJ=apple_sort_ppu
PCC=ppu-g++
CFLAGS=-Wall
LIBS= -lX11 -lspe2 -lpthread
objects = apple_sort_ppu.o lodepng.o ThreadPool.o SPUTask.o
#Imports is for linking the extern spu program library to SPUTask.o. Currently not linking correctly
IMPORTS := spu/lib_process_spu_a.a $(LIBS)
all: $(PROJ)
apple_sort_ppu: $(objects)
$(PCC) $(objects) -o $(LIBS)
apple_sort_ppu.o: apple_sort_ppu.cpp
$(PCC) $(CFLAGS) -c apple_sort_ppu.cpp $(LIBS)
lodepng.o: lodepng.cpp lodepng.h
$(PCC) $(CFLAGS) -c lodepng.cpp
SPUTask.o: SPUTask.cpp SPUTask.h $(IMPORTS) ThreadPool.o
$(PCC) $(CFLAGS) -c SPUTask.cpp
ThreadPool.o: ThreadPool.cpp ThreadPool.h
$(PCC) $(CFLAGS) -c ThreadPool.cpp $(LIBS)
clean:
rm $(objects) *.d
include $(CELL_TOP)/buildutils/make.footer
When I run make on this file, I get :
No rule to make spu/lib_process_spu_a.a, needed by SPUTask.o. STOP
I have confirmed that the library exists in the correct directory. My experience of Makefiles is extremely limited, so I don't really understand what is going on here.
The file causing the problem in the makefile is SPUTask.h, with the header code:
#pragma once
#include "ThreadPool.h"
#include <libspe2.h>
extern spe_program_handle_t process_spu_a;//Program handle
class SPUTask : public Task
{
public:
SPUTask(int i_id = 0);
virtual ~SPUTask(){;}
virtual void execute();
virtual bool hasReturnData(){return false;}
virtual int getTaskID(){return m_id;}
void setData(unsigned char* pData, int pSize);
void setContext(spe_context_ptr_t pContext){mContext = pContext;}
private:
unsigned char* mData __attribute__((aligned(128)));
int m_id;
int mDataSize;
spe_context_ptr_t mContext;
};
process_spu_a has already been compiled into lib_process_spu_a.a in the /spu subdirectory.
Any help would be greatly appreciated.
I have a static method in class as follows in file Convert.h
class Convert
{
public :
static string convertIntToStr(unsigned int integer);
};
In Convert.cpp
string
Convert::convertIntToStr(unsigned int integer)
{
ostringstream ostr;
ostr << integer;
return ostr.str();
}
I use this in some other class method in another .cpp file as Convert::convertIntToStr, but I get linking error, which says undefined reference to Convert::convertIntToStr(unsigned int). Could you please let me know what could be wrong?
With multiple cpp file, you have to link the compiled object file into executable. In IDE like eclipse CDT or Visual stdio, It has been done for you.
To compile and link by yourself, with gcc for example, write Makefile:
CC=g++
CPPFLAGS=-fPIC -Wall -g -O2
all:executable
executable: convert.o other.o
$(CC) $(CPPFLAGS) -o $# $^
convert.o: convert.cpp
$(RC) $^
other.o: other.cpp
$(CC) -o $# -c $^
.PHONY:clean
clean:
rm *.o executable
I had a project, where I had only .cpp files. It worked well, but then I realized, that it's not a good practice, so I decided to split it to .cpp and .h files. Nevetheless now I'm not able to compile the project. Could anybody please look at the source and tell me, where the problem is?
Bot.h
#ifndef BOT_H
#define BOT_H
#include <vector>
#include <string>
#include <cstdlib>
using namespace std;
/**
* Class that represents casual Bot - the parent of other bots
*/
class Bot {
public:
Bot();
virtual ~Bot();
bool initialized;
string getRandomMessage();
string getName();
protected:
vector<string> messages;
string name;
};
#endif /* BOT_H */
Bot.cpp
#include <vector>
#include <string>
#include <cstdlib>
#include "Bot.h"
using namespace std;
string Bot::getRandomMessage() {
int r = static_cast<double> (std::rand()) / RAND_MAX * this->messages.size();
return messages[r];
}
Bot::Bot(){
}
Bot::~Bot(){
}
string Bot::getName() {
return this->name;
}
Example of the class that inherits from the Bot class:
GrumpyBot.h
#ifndef GRUMPYBOT_H
#define GRUMPYBOT_H
#include "Bot.h"
class GrumpyBot : public Bot{
public:
GrumpyBot();
GrumpyBot(const GrumpyBot& orig);
virtual ~GrumpyBot();
};
#endif /* GRUMPYBOT_H */
GrumpyBot.cpp
#include "GrumpyBot.h"
GrumpyBot::GrumpyBot() {
initialized = true;
this->name = "GrumpyBot";
messages.push_back("I hate dogs.");
messages.push_back("I hate cats.");
messages.push_back("I hate goats.");
messages.push_back("I hate humans.");
messages.push_back("I hate you.");
messages.push_back("I hate school.");
messages.push_back("I hate love.");
}
Till now it is ok, but problems appear in the Server.cpp class, where I try to create new instances of those classes and call their functions.
I include there both #include "Bot.h" & #include "GrumpyBot.h" and the compiler keeps getting me messages like /home/ubuntu/NetBeansProjects/SemestralniPraceChat/./Server.cpp:335: undefined reference to 'GrumpyBot::GrumpyBot()'
My makefile looks like this:
#macros
Remove=rm -rf
Doxygen=Doxyfile
RUN=./dvoram64
FLAGS=-Wall -pedantic -Wno-long-long -O0 -ggdb -lncurses -pthread -g
OBJECTS=main.o Bot.o Server.o Client.o
#generates final binary and documentation
all: $(Doxygen)
make compile
#build into final binary
compile: $(RUN)
#run program
run: $(RUN)
$(RUN)
clean:
$(Remove) dvoram64
$(Remove) $(OBJECTS)
#generate documentation in '<login>/doc' folder
doc: $(Doxygen) /*
( cd ./ | doxygen $(Doxygen))
#rules how to compile into the executalble file
$(RUN): $(OBJECTS)
Bot.o: ./Bot.cpp ./Bot.h
g++ $(FLAGS) -c ./Bot.cpp
DummyBot.o: ./DummyBot.cpp ./DummyBot.h ./Bot.h
g++ $(FLAGS) -c ./DummyBot.cpp
GrumpyBot.o: ./GrumpyBot.cpp ./GrumpyBot.h ./Bot.h
g++ $(FLAGS) -c ./GrumpyBot.cpp
JokerBot.o: ./JokerBot.cpp ./JokerBot.h ./Bot.h
g++ $(FLAGS) -c ./JokerBot.cpp
WeatherBot.o: ./WeatherBot.cpp ./WeatherBot.h ./Bot.h
g++ $(FLAGS) -c ./WeatherBot.cpp
Client.o: ./Client.cpp
g++ $(FLAGS) -c ./Client.cpp
main.o: ./main.cpp ./Server.cpp ./Bot.h ./JokerBot.h ./WeatherBot.h ./GrumpyBot.h ./DummyBot.h ./Client.cpp
g++ ./main.cpp $(FLAGS) -o ./dvoram64
Server.o: ./Server.cpp ./Bot.h ./JokerBot.h ./WeatherBot.h ./GrumpyBot.h ./DummyBot.h
g++ $(FLAGS) -c ./Server.cpp
undefined reference is a linker error, you are not passing the objects for the linking process.
In the makefile, replace main.o: lines with
main.o: main.cpp
g++ $(FLAGS) -c main.cpp
remove -lncurses from $(FLAGS) and add:
link: <all the o files>
g++ <all the o files> -lncurses -pthread -o dvoram64
then calling:
make link
will create the correctly linked executable.
Edit:
If you define the $(OBJECTS) variable, the link should be:
link: $(OBJECTS)
g++ $(OBJECTS) -lncurses -pthread -o dvoram64