I created a shared library "A" that use an other shared library "B".
I have a problem when I link my program with the shared library "A".
When I use some function from the other shared library ("B") inside cpp file of the shared library "A", all is fine.
But when I use these functions inside .h file (inside a templated method or an inlined method) of the shared library "A", the symbol is not loaded and I get an error "undefined reference to symbol".
I used g++ 7.2.
I think the option -l forget to load the symbols used in header file.
Do you have an idea to avoid this?
Update 2:
Here a full reproducible example:
A.cpp
#include "A.h"
A.h
#ifndef A_H
# define A_H
#include <type_traits>
#include "B.h"
class A
{
public:
template <typename Type>
std::enable_if_t<std::is_arithmetic<Type>::value,void> funcA(Type value);
};
template <typename Type>
std::enable_if_t<std::is_arithmetic<Type>::value,void> A::funcA(Type value)
{
B tmp;
tmp.funcB(value);
}
#endif
B.cpp
#include "B.h"
#include <iostream>
void B::example()
{
std::cout << "works" << std::endl;
}
B.h
#ifndef B_H
# define B_H
class B
{
public:
void funcB(int value);
private:
void example();
};
inline void B::funcB(int value)
{
value += 1;
example();
}
#endif
main.cpp
#include "A.h"
int main()
{
A tmp;
tmp.funcA(5);
return 1;
}
Compile
g++ -std=c++17 -m64 -O2 -DNDEBUG -Wall -Wextra -Werror -fPIC -o A.o -c A.cpp
g++ -std=c++17 -m64 -O2 -DNDEBUG -Wall -Wextra -Werror -fPIC -o B.o -c B.cpp
g++ -std=c++17 -m64 -O2 -DNDEBUG -Wall -Wextra -Werror -fPIC -o main.o -c main.cpp
g++ -o libB.so B.o -shared
g++ -o libA.so A.o -shared -L. -lB
g++ -o application main.o -L . -lA
Error
main.o: In function `main':
main.cpp:(.text.startup+0x1a): undefined reference to `B::example()'
collect2: error: ld returned 1 exit status
Thank you,
SOLVED:
Finally, I solved my problem with this thread:
GCC 4.5 vs 4.4 linking with dependencies
Thank you!
I'm trying to wrap a library function with the GCC linker option -wrap.
As far as I've read up, this should replace the symbol libfoo with __wrap_libfoo and give access to the original definition by __real_libfoo.
I've implemented it like this:
original.h
#ifndef ORIGINAL_H
#define ORIGINAL_H
void libfoo();
#endif //ORIGINAL_H
original.cpp
#include "original.h"
#include <iostream>
void libfoo()
{
std::cout<<"Original libfoo called from original.cpp"<<std::endl;
return;
};
And compiled to a static lib with g++ --std=c++11 -c original.cpp -o liboriginal.o, packed up with ar rcs liboriginal.a liboriginal.o and moved to a location known to the linker.
wrapper.h
#ifndef WRAPPER_H
#define WRAPPER_H
// should not need anything here
#endif //WRAPPER_H
wrapper.cpp
#include "wrapper.h"
#include <iostream>
//forward declaration to suppress compiler error
void __real_libfoo();
void __wrap_libfoo()
{
std::cout<<"Wrapper libfoo called from wrapper.cpp"<<std::endl;
__real_libfoo();
return;
};
Compiled again to a static lib with g++ --std=c++11 -c wrapper.cpp -o libwrapper.o, packed up with ar rcs libwrapper.a libwrapper.o.
main.cpp
#include "original.h"
int main()
{
libfoo();
return 0;
}
Compiled with g++ --std=c++11 -c main.cpp -o main.o and linked everything together with g++ -L. -Wl,-wrap=libfoo -o test ./main.o -loriginal -lwrapper
On execution, I only get
Original libfoo called from original.cpp
at the console.
Why does the linker not replace the symbol so the call is redirected to __wrap_libfoo()?
And, if this is solved, how do I handle multiple, overloaded functions, which all should be wrapped? Do I need just one -wrap=function_name or do I need to somehow add a more detailed signature to the linker option?
Update: I've also tried not linking the wrapper as a lib, but as an object file instead. This gives me a undefined ref error from the linker regarding the missing __real_libfoo() implementation.
I just started using makefiles and came across a problem. (C++ project)
I'm trying to make a dependency chain:
main.cpp depends on class a. And class a depends on class b.
The main idea is to recompile class a using the allready compiled class b, while class a doesn't have the main() function. (When class a is modified)
Here is my makefile:
makefile
all: main.o
main.o: main.cpp classa.o
g++ main.cpp classa.o -o main.o
classa.o: classa.h classa.cpp classb.o
g++ -c classa.cpp classb.o -o classa.o
classb.o: classb.h classb.cpp
g++ -c classb.cpp -o classb.o
And the code:
main.cpp
#include "classa.h"
int main() {
ClassA a;
return 0;
}
classa.h
#ifndef CLASSA_H
#define CLASSA_H
#include "classb.h"
class ClassA {
private:
ClassB b;
public:
ClassA();
};
#endif // CLASSA_H
classa.cpp
#include "classa.h"
ClassA::ClassA() {
}
classb.h
#ifndef CLASSB_H
#define CLASSB_H
class ClassB {
public:
ClassB();
};
#endif // CLASSB_H
classb.cpp
#include "classb.h"
ClassB::ClassB() {
}
The Problem:
When i use make -f makefile i get the following error:
g++ -c classb.cpp -o classb.o
g++ -c classa.cpp classb.o -o classa.o
g++: warning: classb.o: linker input file unused because linking not done
g++ main.cpp classa.o -o main.o
classa.o: In function `ClassA::ClassA()':
classa.cpp:(.text+0x18): undefined reference to `ClassB::ClassB()'
collect2: error: ld returned 1 exit status
makefile:4: recipe for target 'main.o' failed
make: *** [main.o] Error 1
I believe that it starts on reusing classb.o with the parameter -c.
To me -c is a magical "use when i compile code without the main() function" parameter.
I would be happy if you could enlighten me where i did go wrong, and wether what i'm trying to do is possible.
Regards, chocolateftw
Your makefile should look more like this:
all: main
main: main.cpp classa.o classb.o
g++ main.cpp classa.o classb.o -o main
classa.o: classa.h classa.cpp
g++ -c classa.cpp -o classa.o
classb.o: classb.h classb.cpp
g++ -c classb.cpp -o classb.o
You build .o files from .cpp files and then link .o files into the final output (also built from a .cpp file).
You need to list all relevant object files when linking and do not need to list them when only compiling (which is what happens when you use the -c flag which tells gcc to skip the linking step).
The key here is that classa.o does not depend on classb.o or classb.cpp (it probably does depend on classb.h though in which case you might want to add that to the requirements). The fully linked binary depends on both of them and they then depend on each other as needed.
That said you can dramatically simplify the above makefile by not specifying your own rules and simply using the built-in rules. The following makefile should do what you want.
all: main
main: classa.o classb.o
classa.o: classa.h
classb.o: classb.h
If you need custom compiler/linker flags later you can use the default variables to have them used on the appropriat lines. See 10.3 Variables Used by Implicit Rules and 10.2 Catalogue of Built-In Rules for the variables and what rules use them.
I'm learning to program C++ in Linux, and I have the following problem:
I have 4 files: main.cpp, model.cpp, view.cpp and controller.cpp, each (except main) with their own header files. main.cpp includes model.h, view.h and controller.h, and view.h includes other libraries that are only relevant to it (necessary to run the graphic library). Those libraries are in different folders and have other dependencies on their own (that's why I don't want to move them). So, my makefile looks as follows:
model: model.cpp model.h
g++ -c model.cpp
view: view.cpp view.h
g++ -I/opt/vc/include -I/opt/vc/include/interface/vcos/pthreads -I.. -c view.cpp
controller: controller.cpp
g++ -c controller.cpp
main: main.cpp
g++ -c main.cpp
and also a line to link all the files together (I didn't added it because I'm writing this on my Mac and copying it from the screen of my Raspberry Pi).
My problem is that when I try to compile them, all of them work, except for main, it tells me the following:
In file included from main.cpp:6:0:
view.h:4:23: fatal error: VG/openvg.h: No such file or directory
compilation terminated.
make: *** [main] Error 1
From what I can understand, when I compile view with "make view", it can find the files included without problem, because it has the paths in which it must look, but since "make main" doesn't have those paths, it doesn't know where to look for openvg.h. The problem is that if I add the paths to main, it tells me that there's multiple definitions for what's inside the library... Any help?
The #include VG/openvg.h is in /opt/vc/include and is included from view.h
When you make view you are including it from view.cpp which is compiled with -I/opt/vc/include
When you make main you are including it from main.cpp which is compiled without flags so it can't find the file.
You need to add the flags
main: main.cpp
g++ -c -I/opt/vc/include main.cpp
You may need the other flags as well, depending on what view.h includes.
The multiple definitions are caused by $(OPENVGLIBDIR)/fontinfo.h
which contains
Fontinfo SansTypeface, SerifTypeface, MonoTypeface;
so if you include that file in more than one object file and link them (main.o and view.o in this case) you will get multiple definitions.
Change it to
extern Fontinfo SansTypeface, SerifTypeface, MonoTypeface;
I then got Background etc undefined as libshapes is a C library. To get round this I changed
#include "fontinfo.h"
#include "shapes.h"
in view.h to
extern "C" {
#include "fontinfo.h"
#include "shapes.h"
}
and it builds for me (with references to model and controller removed).
In your makefile, the view/model/controller/main targets are making the .o files so they should be .o too. When you make test when no .o exists, it is looking for the .o target. If there isn't one in your makefile it will use the default which is a straight g++ -c.
Your make file should be like this:
test: model.o view.o controller.o main.o $(OPENVGLIBDIR)/libshapes.o $(OPENVGLIBDIR)/oglinit.o
g++ -o test view.o main.o model.o controller.o $(OPENVGLIBDIR)/libshapes.o $(OPENVGLIBDIR)oglinit.o -L/opt/vc/lib -L/opt/vc/include -lGLES -ljpeg
view.o: view.cpp
g++ -I/opt/vc/include -I/opt/vc/include/interface/vcos/pthreads -I.. -c view.cpp
main.o: main.cpp
g++ -I/opt/vc/include -I/opt/vc/include/interface/vcos/pthreads -I.. -c main.cpp view.cpp
model.o: model.cpp
g++ -c model.cpp
controller.o: controller.cpp
g++ -c controller.cpp
here are my files, the code seems to run fine if in main.cpp I include view.cpp instead of view.h, but I don't think that's what I'm supposed to be doing:
main.cpp
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <iostream>
#include "model.h"
#include "view.h"
#include "controller.h"
using namespace std;
int main() {
int n;
View view;
view.initialize();
view.drawBackground();
view.show();
std::cin >> n;
}
view.h:
#ifndef VIEW_H
#define VIEW_H
#include "VG/openvg.h"
#include "VG/vgu.h"
#include "fontinfo.h"
#include "shapes.h"
class View{
private:
int width, height;
public:
View();
int getWidth();
int getHeight();
void drawBackground();
void initialize();
void show();
};
#endif
view.cpp
#include "view.h"
View::View(){
int width, height;
VGfloat w2, h2, w;
}
int View::getWidth(){
return width;
}
int View::getHeight(){
return height;
}
void View::drawBackground(){
Background(0,0,0);
Stroke(255,255,255,1);
Fill(255,0,0,1.0);
Circle(width/2, height/2, 100);
}
void View::initialize(){
init(&width, &height);
Start(width, height);
}
void View::show(){
End();
}
Thanks A LOT for your help man! I've been fighting with this for the last couple of days (that's what I get for getting used to automatic compiling/linking). It's somewhat based on that example. I can make it run if I make each object by itself and then link them all together like this:
test: model.o view.o controller.o main.o $(OPENVGLIBDIR)/libshapes.o $(OPENVGLIBDIR)/oglinit.o
g++ -o test view.o main.o model.o controller.o $(OPENVGLIBDIR)/libshapes.o $(OPENVGLIBDIR)oglinit.o -L/opt/vc/lib -L/opt/vc/include -lGLES -ljpeg
view: view.cpp
g++ -I/opt/vc/include -I/opt/vc/include/interface/vcos/pthreads -I.. -c view.cpp
main: main.cpp
g++ -I/opt/vc/include -I/opt/vc/include/interface/vcos/pthreads -I.. -c main.cpp view.cpp
model: model.cpp
g++ -c model.cpp
controller: controller.cpp
g++ -c controller.cpp
if I do "make view" "make main" and then "make test" everything goes fine, but if I try "make test" without any object created prior to that I get fatal error: VG/openvg.h: No such file or directory when it's trying to compile view.cpp
I keep getting complaint from the g++ compiler that the following code has problems.
After careful examination, I still cannot figure out why it cannot find the constructor and destructor of class B from embedMain.cpp.
Can someone give me a little hint?
Thank you
// embedMain.cpp
#include "embed.h"
int main(void)
{
B b("hello world");
return 0;
}
,
// embed.h
#ifndef EMBED_H
#define EMBED_H
#include <string>
class B
{
public:
B(const std::string& _name);
~B();
private:
std::string name;
};
#endif
,
// embed.cpp
#include <iostream>
#include <string>
#include "embed.h"
B::B(const std::string& _name) : name(_name) {}
B::~B() {
std::cout << "This is B::~B()" << std::endl;
}
,
~/Documents/C++ $ g++ --version
g++ (Ubuntu/Linaro 4.5.2-8ubuntu4) 4.5.2
~/Documents/C++ $ g++ -o embedMain embedMain.cpp
/tmp/ccdqT9tn.o: In function `main':
embedMain.cpp:(.text+0x42): undefined reference to `B::B(std::basic_string<char, std::char_traits<char>, std::allocator<char> > const&)'
embedMain.cpp:(.text+0x6b): undefined reference to `B::~B()'
embedMain.cpp:(.text+0x93): undefined reference to `B::~B()'
collect2: ld returned 1 exit status
// Updated //
Based on comments from experts here, I have found the right way to link the embedMain.cpp with the embed library.
Here is the detail step:
user#ubuntu:~/Documents/C++$ tree
.
├── embed.cpp
├── embed.h
├── embedMain.cpp
user#ubuntu:~/Documents/C++$ g++ -Wall -c embed.cpp
user#ubuntu:~/Documents/C++$ ar -cvq libembed.a embed.o
user#ubuntu:~/Documents/C++$ g++ -o embedMain embedMain.cpp -L/home/user/Documents/C++ -lembed
user#ubuntu:~/Documents/C++$ tree
.
├── embed.cpp
├── embed.h
├── embedMain
├── embedMain.cpp
├── embed.o
├── libembed.a
You need to compile embed.cpp and link it into your executable, like so:
g++ -o embedMain embedMain.cpp embed.cpp
This compiles both files and links everything. To separate the three steps:
g++ -c embed.cpp
g++ -c embedMain.cpp
g++ -o embedMain embedMain.o embed.o
You also have to include embed.cpp in your compile/link.