I have to create a Library for my work that contains Protobuf elements. It should run on every other PC without installing Protobuf. But I can not make the library run without having also the Protobuf files in the same folder (so I compile this files to and the user have to install Protobuf)
So I created for this a test program to demonstrate my problem:
->alias.proto
syntax = "proto3";
package aliasPackage;
message NumberSave{
int32 number = 1;
}
I created the .h and .cc with
protoc -I. --cpp_out=. alias.proto
->Backbone.h
#include "alias.pb.h"
class Backbone{
public:
Backbone();
~Backbone();
void save_Number(int value);
int get_Number();
private:
aliasPackage::NumberSave number;
};
->Backbone.cpp
#include "../header/Backbone.h"
#include <google/protobuf/stubs/common.h>
Backbone::Backbone()
{
number.set_number(0);
}
Backbone::~Backbone()
{
google::protobuf::ShutdownProtobufLibrary();
}
void Backbone::save_Number(int value)
{
number.set_number(value);
}
int Backbone::get_Number()
{
return number.number();
}
->Backbone.h for the lib
class Backbone{
public:
Backbone();
~Backbone();
void save_Number(int value);
int get_Number();
};
Creating the lib out of the files with this command (I thought about a static one, compiling the all independences into the file, but it seems not to work)
g++ -c --std=c++20 -O3 -DBUILD_SHARED_LIBS=ON -I/usr/local/include *.c* -lpthread -L/usr/local/lib -lprotobuf && ar rcs Backbone.sll *.o
->main.cpp
#include "../libs/lib/Backbone.h"
#include <iostream>
int main(){
auto backbone = new Backbone();
backbone->save_Number(5);
std::cout<<backbone->get_Number()<<std::endl;
delete backbone;
return 0;
}
Compile command
g++ -Wall -Wextra -Wpedantic --std=c++20 -O3 main.cpp -L. -l:../libs/lib/Backbone.sll
What am I doing wrong? What's the right command to create a Lib so that users can use it without installing Protobuf?
Related
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
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 try to include my self built .so library in the test.cpp file.
When I try to make the test.cpp file I get this exception:
root#airdrop:/home/pi/naza-interface/examples# make
g++ -c test.cpp
test.cpp:31:35: fatal error: naza_interface_manual.h: No such file or
directory
#include "naza_interface_manual.h"
^
compilation terminated.
Makefile:5: recipe for target 'test.o' failed
make: *** [test.o] Error 1
The Makefile for test.cpp looks like that:
output: test.o
g++ -L. -lnazainterface -o test test.o
test.o:
g++ -c test.cpp
clean:
rm -f *.o
test.cpp just includes the library.
#include "naza_interface_manual.h"
The library contains two files, naza_interface_manual.h and naza_interface_manual.cpp. The library's makefile looks like that:
libso: naza_interface_manual.o pca9685.o
g++ -fPIC -L/usr/local/lib -shared naza_interface_manual.o
pca9685.o -lbcm2835 -o libnazainterface.so
naza_interface_manual.o: src/naza_interface_manual.cpp src/naza_interface_manual.h
g++ -fPIC -c -Wall src/naza_interface_manual.cpp
pca9685.o: src/PCA9685/pca9685.cpp src/PCA9685/pca9685.h
g++ -c src/PCA9685/pca9685.cpp
install: naza_interface_manual.o pca9685.o
g++ -L/usr/local/lib naza_interface_manual.o pca9685.o -lbcm2835 -
shared -o /usr/local/libnazainterface.so
clean:
rm *.o output
naza_interface_manual.h:
#ifndef NAZA_INTERFACE_MANUAL_H_
#define NAZA_INTERFACE_MANUAL_H_
class naza_interface_manual_c{
public:
naza_interface_manual_c();
// A: For roll control (left/right)
// E: For pitch control (front/back)
// T: For throttle control
// R: For rudder control
// U: For Control Model Switch
void configure_pins(int A, int E, int T, int R, int U);
void fly_forward(int speed);
void fly_backward(int speed);
void fly_up(int speed);
void fly_down(int speed);
void fly_left(int speed);
void fly_right(int speed);
};
#endif
naza_interface_manual.cpp:
#include <iostream>
#include <wiringPi.h>
#include <stdio.h>
#include <stdint.h>
#include <unistd.h>
#include "naza_interface_manual.h"
#include "PCA9685/pca9685.h"
naza_interface_manual_c::naza_interface_manual_c(){
std::cout << "Starting Naza Interface";
}
void naza_interface_manual_c::configure_pins(int A, int E, int T, int R, int U){
PCA9685 pca9685;
pca9685.SetFrequency(100);
pca9685.Write(CHANNEL(0), VALUE(350));
}
void naza_interface_manual_c::fly_forward(int speed){
}
void naza_interface_manual_c::fly_backward(int speed){
}
void naza_interface_manual_c::fly_up(int speed){
}
void naza_interface_manual_c::fly_down(int speed){
}
void naza_interface_manual_c::fly_left(int speed){
}
void naza_interface_manual_c::fly_right(int speed){
}
Your Makefile doesn't install the header file. In fact, it also installs the shared object in a non-standard location: /usr/local. You want the library to go into /usr/local/lib and you need the header file installed in /usr/local/include.
Your Makefile is not consistent with conventional rules: You have no all rule, you are creating the library directly in the installation directory, instead of calling /usr/bin/install... I suggest you look into "proper" Makefile layout, if you want to distribute this. Users expect a lot of things from the Makefiles you give them; there are de-facto standards to follow.
If you want to use the library without having installed it, you need to provide the compiler the relevant include directive in your test.o: target; something like -Ipath/to/your/header.
Your compilation doesn't give the compiler the include path to find the header.
Instead, specify a base location and add the path to the compile. Otherwise if you can change the naza interface library, its install target should install the headers to a system (or $PREFIX/include) location.
test.o:
g++ -I$(NAZA_INTERFACE_LIB)/src/ -c test.cpp
Consider the following setup consisting of two shared libraries which both use a static library:
static.cpp
#include "static.h"
static int a = 0;
int getA()
{
return a++;
}
static.h
#pragma once
int getA();
shareda.cpp
#include <iostream>
#include "shareda.h"
#include "static.h"
void printA()
{
std::cout << getA() << std::endl;
}
shareda.h
#pragma once
void printA();
sharedb.cpp
#include <iostream>
#include "sharedb.h"
#include "static.h"
void printB()
{
std::cout << getA() << std::endl;
}
sharedb.h
#pragma once
void printB();
main.cpp
#include "shareda.h"
#include "sharedb.h"
int main()
{
printA();
printA();
printB();
printA();
printB();
return 0;
}
I compiled and ran these files with the following commands (using Clang 3.8.0, compiled from source, and 64-bit Debian with GNU ld 2.25):
clang++ -c static.cpp -o static.o -fPIC
ar rcs libstatic.a static.o
clang++ -c shareda.cpp -o shareda.o -fPIC
clang++ -shared -o libshareda.so shareda.o libstatic.a
clang++ -c sharedb.cpp -o sharedb.o -fPIC
clang++ -shared -o libsharedb.so sharedb.o libstatic.a
clang++ -L. -lshareda -lsharedb -o main main.cpp
LD_LIBRARY_PATH=.:$LD_LIBRARY_PATH ./main
To my surprise, the output was the following:
0
1
2
3
4
My expectation was this:
0
1
0
2
1
Apparently, despite the static keyword in front of a in static.cpp, only one instance of a exists. Is there a way to have two instances of a, one for each of the shared libraries?
Apparently, despite the static keyword in front of a in static.cpp, only one instance of a exists.
That is incorrect: two instances of a exist, but only one is actually used.
And that is happening because (contrary to your expectations) printB calls the first getA available to it (the one from libshareda.so, not the one from libsharedb.so). That is one major difference between UNIX shared libraries and Windows DLLs. UNIX shared libraries emulate what would have happened if your link was:
clang++ -L. -o main main.cpp shareda.o sharedb.o libstatic.a
So what can you do to "fix" this?
You could link libsharedb.so to prefer its own getA, by using -Bsymbolic.
You could hide getA inside libsharedb.so completely (as if it's a private implementation detail):
clang++ -c -fvisibility=hidden -fPIC static.cpp
ar rcs libstatic.a static.o
clang++ -shared -o libsharedb.so sharedb.o libstatic.a
You could achieve similar result using linker version script.
P.S. Your link command:
clang++ -L. -lshareda -lsharedb -o main main.cpp
is completely backwards. It should be:
clang++ -L. -o main main.cpp -lshareda -lsharedb
The order of sources/object files and libraries on command line matters, and libraries should follow object files that reference 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