Linking static method in wrapper class for leveldb - c++

I try to write a wrapper class for leveldb. Basically the part of the header file which generates my problem is (CLevelDBStore.h:)
#include "leveldb/db.h"
#include "leveldb/comparator.h"
using namespace leveldb;
class CLevelDBStore {
public:
CLevelDBStore(const char* dbFileName);
virtual ~CLevelDBStore();
/* more stuff */ 67 private:
private:
CLevelDBStore();
static leveldb::DB* ldb_;
};
The corresponding code in the CLevelDBStore.cpp file is:
#include "CLevelDBStore.h"
DB* CLevelDBStore::ldb_;
CLevelDBStore::CLevelDBStore(const char* dbFileName) {
Options options;
options.create_if_missing = true;
DB::Open((const Options&)options, (const std::string&) dbFileName, (DB**)&ldb_);
Status status = DB::Open(options, dbFileName);
}
I now try to compile my test file (test.cpp), which basically is
#include "leveldb/db.h"
#include "leveldb/comparator.h"
#include "CLevelDBStore.h"
int main() {
std::cout << "does not compile" << std::endl;
return 0;
}
Note, I don't even use the wrapper class yet. It's just to generate the compilation error.
The compilation
g++ -Wall -O0 -ggdb -c CLevelDBStore.cpp -I/path/to/leveldb/include
g++ -Wall test.cpp -O0 -ggdb -L/path/to/leveldb -I/path/to/leveldb/include \
-lleveldb -Wall -O2 -lz -lpthread ./CLevelDBStore.o -llog4cxx \
-o levelDBStoretest
yields
CLevelDBStore.cpp:27: undefined reference to `leveldb::DB::Open(leveldb::Options const&, std::basic_string<char, std::char_traits<char>, std::allocator<char> > const&, leveldb::DB**)'
I looked at the leveldb code where leveldb::DB::Open is defined and it turned out to be a static method.
class DB {
public:
static Status Open(const Options& options,
const std::string& name,
DB** dbptr);
/* much more stuff */
}
Could this somehow generated problemes when linking?

I think this is library link order. Try placing -leveldb after CLevelDBStore.o:
g++ -Wall test.cpp -O0 -ggdb -L/path/to/leveldb -I/path/to/leveldb/include
-Wall -O2 ./CLevelDBStore.o -lleveldb -lz -lpthread -llog4cxx
-o levelDBStoretest
From GCC Options for Linking:
-llibrary
Search the library named library when linking. It makes a difference where in the command you write this option; the linker searches and processes libraries and object files in the order they are specified. Thus, foo.o -lz bar.o' searches libraryz' after file foo.o but before bar.o. If bar.o refers to functions in `z', those functions may not be loaded.

Related

C++ objcopy to make class method weak

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;
}

Separate instance of static variable in static library for shared library

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.

C++ shared library undefined reference

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?

C++ shared library undefined reference to `FooClass::SayHello()'

I'm making a C++ Shared Library and when I compile a main exe that uses the library the compiler gives me:
main.cpp:(.text+0x21): undefined reference to `FooClass::SayHello()'
collect2: ld returned 1 exit status
Library code:
fooclass.h
#ifndef __FOOCLASS_H__
#define __FOOCLASS_H__
class FooClass
{
public:
char* SayHello();
};
#endif //__FOOCLASS_H__
fooclass.cpp
#include "fooclass.h"
char* FooClass::SayHello()
{
return "Hello Im a Linux Shared Library";
}
Compiling with:
g++ -shared -fPIC fooclass.cpp -o libfoo.so
Main:
main.cpp
#include "fooclass.h"
#include <iostream>
using namespace std;
int main(int argc, char const *argv[])
{
FooClass * fooClass = new FooClass();
cout<< fooClass->SayHello() << endl;
return 0;
}
Compiling with:
g++ -I. -L. -lfoo main.cpp -o main
The machine is an Ubuntu Linux 12
Thanks!
g++ -I. -L. -lfoo main.cpp -o main
is the problem. Recent versions of GCC require that you put the object files and libraries in the order that they depend on each other - as a consequential rule of thumb, you have to put the library flags as the last switch for the linker; i. e., write
g++ -I. -L. main.cpp -o main -lfoo
instead.

Static Libraries which depend on other static libraries

I have a question about making static libraries that use other static libraries.
I set up an example with 3 files - main.cpp, slib1.cpp and slib2.cpp. slib1.cpp and slib2.cpp are both compiled as individual static libraries (e.g. I end up with slib1.a and slib2.a) main.cpp is compiled into a standard ELF executable linked against both libraries.
There also exists a header file named main.h which prototypes the functions in slib1 and slib2.
main.cpp calls a function called lib2func() from slib2. This function in turn calls lib1func() from slib1.
If I compile the code as is, g++ will return with a linker error stating that it could not find lib1func() in slib1. However, if I make a call to lib1func() BEFORE any calls to any functions in slib2, the code compiles and works correctly.
My question is simply as follows: is it possible to create a static library that depends on another static library? It would seem like a very severe limitation if this were not possible.
The source code for this problem is attached below:
main.h:
#ifndef MAIN_H
#define MAIN_H
int lib1func();
int lib2func();
#endif
slib1.cpp:
#include "main.h"
int lib1func() {
return 1;
}
slib2.cpp:
#include "main.h"
int lib2func() {
return lib1func();
}
main.cpp:
#include <iostream>
#include "main.h"
int main(int argc, char **argv) {
//lib1func(); // Uncomment and compile will succeed. WHY??
cout << "Ans: " << lib2func() << endl;
return 0;
}
gcc output (with line commented out):
g++ -o src/slib1.o -c src/slib1.cpp
ar rc libslib1.a src/slib1.o
ranlib libslib1.a
g++ -o src/slib2.o -c src/slib2.cpp
ar rc libslib2.a src/slib2.o
ranlib libslib2.a
g++ -o src/main.o -c src/main.cpp
g++ -o main src/main.o -L. -lslib1 -lslib2
./libslib2.a(slib2.o): In function `lib2func()':
slib2.cpp:(.text+0x5): undefined reference to `lib1func()'
collect2: ld returned 1 exit status
gcc output (with line uncommented)
g++ -o src/slib1.o -c src/slib1.cpp
ar rc libslib1.a src/slib1.o
ranlib libslib1.a
g++ -o src/slib2.o -c src/slib2.cpp
ar rc libslib2.a src/slib2.o
ranlib libslib2.a
g++ -o src/main.o -c src/main.cpp
g++ -o main src/main.o -L. -lslib1 -lslib2
$ ./main
Ans: 1
Please, try g++ -o main src/main.o -L. -Wl,--start-group -lslib1 -lslib2 -Wl,--end-group.
Group defined with --start-group, --end-group helps to resolve circular dependencies between libraries.
See also: GCC: what are the --start-group and --end-group command line options?
The order make the difference. Here's from gcc(1) manual page:
It makes a difference where in the command you write this option; the linker searches and processes libraries and object files in the order they are specified. Thus, foo.o -lz bar.o searches library z after file foo.o but before bar.o. If bar.o refers to functions in z, those functions may not be loaded.