I want to write a shared library and I want to get a compiler/linker error if I forgot to implement some functions.
Consider the following case:
test.h
class Test {
public:
Test();
};
test.cpp
#include "test.h"
main.cpp
#include "test.h"
int main() {
new Test();
}
If I create a library with this command gcc -c -fpic test.cpp && g++ -shared -o libtest.so -Wl,--no-undefined -Wl,--no-allow-shlib-undefined test.o there is no error message, but the library is broken. Is there a way to force the creation of a not broken library?
Edit: adding additional flag, but doesn't change result
These codes have been modified:
test.h :
class Test {
public:
Test();
};
test.cpp :
#include "test.h"
Test::Test(){} // you must implement the constructor
You must have to implement the constructor, and if not, you get an error "undefined reference to `Test::Test()'".
main.cpp :
#include <iostream>
#include "test.h"
using namespace std;
int main(void)
{
Test* t = new Test(); // you must define a pointer
cout << "test* was created: " << t << endl;
delete t;
t = nullptr;
return 0;
}
Now all the code is OK. Then we create a shared-library with the following command:
g++ -shared -o test.so -fPIC test.cpp
Finally, we compile the main.cpp file at the same time as referring to the test.so shared-library and get the exe output, by the command below:
g++ -g main.cpp test.so -o test.exe
Related
I have this header file:
weather.h
#ifndef _WEATHER_H_
#define _WEATHER_H_
#include <string>
using namespace std;
class Weather {
private:
int temp;
public:
Weather();
string announce();
};
#endif
When I compile the related source file, I want to make announce and Weather (the default constructor) weak during compile time.
To do so, the flow looks something like:
g++ -std=c++11 -g -Wall -c weather.cpp
objcopy --weaken-symbol=announce --weaken-symbol=Weather weather.o weather.o
However, when I then compile another version of weather without the weakening? I still get a duplicate symbol error.
I know --weaken exists, but this is just a sample and I do not want to blanket weaken every method in the class.
Weakening the symbols in the one file and linking all the objects together works for me. Make sure you are relinking all the objects (including all constructors).
weather1.cpp
Weather::Weather() {}
string Weather::announce()
{
return string("Bad weather");
}
weather2.cpp
Weather::Weather() {}
string Weather::announce()
{
return string("Bad weather 2");
}
build.sh
g++ weather1.cpp -c -o weather1.o
g++ weather2.cpp -c -o weather2.o
g++ test.cpp -c -o test.o
objcopy --weaken-symbol=_ZN7Weather8announceEv --weaken-symbol=_ZN7WeatherC2Ev --weaken-symbol=_ZN7WeatherC1Ev weather2.o weather2.o
g++ *.o -o test.out
Depending on whether I weaken weather1.o or weather2.o, I see different outputs from my test main function:
int main()
{
Weather w;
std::cout << w.announce() << "\n";
return 0;
}
I am trying to link a dll with a very simple testing program, but I am getting an error, that I will describe at the end of the post.
frvt11.h - Interface (just relevant code) I need to implement to create my dll
namespace FRVT {
class Interface {
public:
static std::shared_ptr<Interface>
getImplementation();
}
}
implementation.h - Header of my implementation of Inteface
#include "frvt11.h"
namespace FRVT {
class Implementation : public FRVT::Interface {
public:
static std::shared_ptr<Interface>
getImplementation();
}
}
implementation.cpp - My implementation of Interface
UPDATE: change from Implementation::getImplementation to Interface::getImplementation
#include "implementation.h"
using namespace FRVT;
std::shared_ptr<Interface>
Interface::getImplementation() {
std::cout<<"getImplementation";
return std::make_shared<Implementation>();
}
main.cpp
UPDATE: Explicitly indicate the namespace Interface::
#include "frvt11.h"
using namespace FRVT;
int main(){
auto obj = Interface::getImplementation();
return 0;
}
compilation directives
UPDATE: include of -L/dll-directory where are all .h, .cpp and dll
g++ -std=c++11 -c -Wall -Werror -m64 -fPIC implementation.cpp
g++ -std=c++11 -shared -m64 -o libimplementation.so implementation.cpp
g++ -std=c++11 -Wall -m64 -o main main.cpp -L/dll-directory -limplementation
error
UPDATE: Original problem solved
main.cpp: In function 'int main()':
main.cpp:6:34: error: 'getImplementation' was not declared in this scope
auto obj = getImplementation();
How to solve this error? I was expecting that the linker would do the "magic" to say to main.cpp, that the implementation of referred function would be at the dll. What am I doing wrong?
At implementation.cpp I've changed from:
Implementation::getImplementation()
to:
Interface::getImplementation()
At main.cpp I've explicitly indicate the interface, like bellow:
auto obj = Interface::getImplementation();
And finally I've used the -L directive to indicate where was the the generated dll.
I have 3 files; main.cpp (which contains main()), FileWriter.h, and FileWriter.cpp. I'm using g++ (version Debian 4.9.2-10) on Debian Jessie. My project contains .cpp files in '/root/dev/Practice/src/', and a single header (FileWriter.h) in '/root/dev/Practice/include/'. The compilation of the two object files works, but the linking to an executable complains about undefined reference to main(), although I do indeed have a seemingly valid one defined in 'main.cpp'.
Here's the output of my make file (which is in the root '/root/dev/Practice/' directory):
g++ -c -g -Wall -o src/FileWriter.o src/FileWriter.cpp
g++ -c -g -Wall -o src/main.o src/FileWriter.cpp
g++ src/FileWriter.o src/main.o -o bin/Practice
/usr/lib/gcc/i586-linux-gnu/4.9/../../../i386-linux-gnu/crt1.o: In function '_start'"
/build/glibc-J1NNmk/glibc-2.19/csu/../sysdeps/i386/start.S:111: undefined reference to 'main'
collect2: error: ls returned 1 exit status
Makefile:10: recipe for target 'bin/Practice' failed
Here's the contents of my main.cpp file:
#include <string>
#include <iostream>
#include "/root/dev/Practice/include/FileWriter.h"
int main() {
std::cout << "Hello!" << std::endl;
FileWriter * fw = new FileWriter("foofile");
fw->AddLine("CRAP!");
fw->AddLine("NO!");
return 0;
}
My FileWriter.h:
#ifndef FILEWRITER_H_
#define FILEWRITER_H_
#include <string>
#include <iostream>
class FileWriter{
public:
FileWriter(std::string);
~FileWriter();
void AddLine(std::string);
private:
std::string fileLocation;
std::ofstream *filestream;
};
#endif /* FILEWRITER_H_ */
...and my FileWriter.cpp:
#include "/root/dev/Practice/include/FileWriter.h"
#include <fstream>
// g++ linker error if 'inline' not included - why?
inline FileWriter::FileWriter(std::string fileName)
{
this->fileLocation = fileName;
const char * x = this->fileLocation.c_str();
this->filestream = new std::ofstream();
this->filestream->open(x, std::ios::out | std::ios::app);
}
inline FileWriter::~FileWriter()
{
this->filestream->close();
}
inline void FileWriter::AddLine(std::string line)
{
*this->filestream << line << std::endl;
}
This line:
g++ -c -g -Wall -o src/main.o src/FileWriter.cpp
should be:
g++ -c -g -Wall -o src/main.o src/main.cpp
I don't have access to this compiler, but in the past if you had main() in a C++ file you needed to "decorate" it with __cdecl
int __cdecl main() {
Try that? Or:
extern "C" int main() {
i'm having something like these files:
libfoo.h
class foo
{
public:
foo() = default;
virtual ~foo();
};
libfoo.cpp
#include "libfoo.h"
foo::~foo() { /* code here */ }
test.cpp
#include <libfoo.h>
int main()
{
foo f;
}
i compile libfoo.h and libfoo.cpp into a shared library and all that is fine.
but when i then try to use the library in test.cpp i get undefined reference to the destructor ~foo().
this error however does not occur if i define the destructor directly in libfoo.h. i have this problem with all functions defined outside the class in my library so im guessing it has something to do with the compilation process (it compiles fine however)
i compile the library like this:
g++ -std=c++0x -Wall -Werror -fPIC -c -o libfoo.o libfoo.cpp
g++ -shared libfoo.o -o libfoo.so
any ideas as to what i might be doing wrong?
(all the functions that i declare inclass, like template functions works fine and causes no undefined reference)
I tried to reproduce the error, but I failed.
I created the files (with slight modifications):
// libfoo.h
struct foo { virtual ~foo(); };
// libfoo.cpp
#include "libfoo.h"
foo::~foo() {}
// test.cpp
#include "libfoo.h"
int main() { foo f; }
Built like this:
$ g++ -std=c++0x -Wall -Werror -fPIC -c -o libfoo.o libfoo.cpp
$ g++ -shared libfoo.o -o libfoo.so
$ g++ test.cpp -L. -lfoo
And ran like this:
$ env LD_LIBRARY_PATH=. ./a.out
I got no errors. Are you sure there is a problem with your code?
This question already has answers here:
creating classes link error
(2 answers)
Closed 8 years ago.
I'm trying to learn how to make classes in C++ where I use a header file, a .cpp file that contains the class function definitions, and a main .cpp file. Here is what I have (taken from an example)
in class.h
class MyClass
{
public:
void foo();
int bar;
};
in class.cpp
#include "class.h"
using namespace std;
void MyClass::foo()
{
cout<< "test";
}
in main.cpp
#include "class.h"
using namespace std;
int main()
{
MyClass a;
a.foo();
return 0;
}
Compiling the main.cpp results in this error:
[Linker error] C:\:(.text+0x16): undefined reference to `MyClass::foo()'
collect2: ld returned 1 exit status
Do I need to compile the class.cpp or class.h? Am I missing a way of linking class.h with class.cpp? If so how do I link them?
You need to compile the implementation files into object files and link them together. The following is an example for when you are using g++:
g++ -c class.cpp -o class.o
g++ -c main.cpp -o main.o
g++ class.o main.o -o main
./main
In reality, you would add more options like -std=c++11 -O3 -Wall -Wextra -Werror etc.
You can try this on Linux shell using g++
Compile Create object files of main.cpp and class.cpp called main.o and class.o
g++ -c class.cpp
g++ -c main.cpp
Linking the object codes main.o and class.o to create executable file called program
g++ -o program main.o class.o
then run the program executable file
./program
You are likely to be compiling only main.cpp and not class.cpp.
What command are you using to generate the output ?
This should work fine :
g++ class.cpp main.cpp -o class
Its working fine
I tried the code in my Compiler
MyClass.h
#include <iostream>
class MyClass
{
public:
void foo();
int bar;
};
MyClass.cpp
#include "MyClass.h"
using namespace std;
void MyClass::foo()
{
cout<< "test";
}
Main.cpp
#include <iostream>
#include "MyClass.h"
int main(int argc, const char * argv[])
{
MyClass a;
a.foo();
return 0;
}
Ive tried the code in Xcode.
Its working just fine.
Use compiler option -I<dir of .h file> while compiling .cpp file. Compile both the .cpp files