Friday, June 27, 2008

gcc: statically linked shared library

Usually it's painful to distribute binaries of shared libraries across different linux distributions. They have different set of versions of shared libraries. For example if you have a library that uses libpq.so.5.0 to communicate with PostgreSQL you will fail to link against your library on distribution that has libpq.so.5.1. But there is no difference for you which to use: libpq.so.5.0 or libpq.so.5.1, anyway you will be able to connect to PostgreSQL and do DB related stuff. There is an option to compile a shared library with statically linked shared libraries in it. Let's try to build library that uses PostgreSQL's libpq: At first you just create objects for you library:

gcc -fPIC test.c -c
and compile shared library:
gcc test.o -o libtest.so -static-libgcc -shared -Wl,-soname=libtest.so\
-Wl,-static -lpq -lssl -lcrypt -lcrypto -lz
-static-libgcc is needed to link against libgcc statically[not all versions of gcc need that]. Shared libraries should go after -Wl,-static option. Be aware that you have to specify all shared libraries that can be involved on linking stage, otherwise they should be specified for binary that will be linked against libtest. Here I specified libpq, libssl, libcrypt, libcrypto, libz, to be linked statically. libpq also depends on krb5, but there's no static version of it in my distribution, so I'll link it to final binary. ldd output:
ldd libtest.so 
 statically linked
Now you can link your binary against libtest:
g++ usetest.cc -o usetest -L./ -ltest -lkrb5
That's all. ldd shows:
ldd usetest
 linux-gate.so.1 =>  (0xb7f37000)
 lib1.so => /tmp/work/lib1.so (0xb7c37000)
 libkrb5.so.3 => /usr/lib/libkrb5.so.3 (0xb7bad000)
 libstdc++.so.6 => /usr/lib/libstdc++.so.6 (0xb7aca000)
 libm.so.6 => /lib/libm.so.6 (0xb7aa4000)
 libc.so.6 => /lib/libc.so.6 (0xb7964000)
 libk5crypto.so.3 => /usr/lib/libk5crypto.so.3 (0xb7940000)
 libcom_err.so.2 => /lib/libcom_err.so.2 (0xb793c000)
 libkrb5support.so.0 => /usr/lib/libkrb5support.so.0 (0xb7934000)
 libresolv.so.2 => /lib/libresolv.so.2 (0xb7921000)
 libgcc_s.so.1 => /usr/lib/libgcc_s.so.1 (0xb7916000)
 /lib/ld-linux.so.2 (0xb7f38000)
 libdl.so.2 => /lib/libdl.so.2 (0xb7912000)
No libpq or libssl, libcrypt, libcrypto, libz. Congratulations. As far as I know, not all versions of ld support this. I succeeded with 'GNU ld version 2.17.50.0.6 20061020' and 'GNU ld (GNU Binutils) 2.18', but failed with 'GNU ld version 2.16.1'[on x86_64]

Thursday, June 26, 2008

c++: coma operator

I use coma operator all the time:

int a, b;
for (a=1,b=1;a<3;++a,++b)
    ...
Probably some other cases. By specification coma operator allows to call a sequence of instructions where one is allowed. So
true?(++a,b+=2,a+b):(a+=2,++b,a-b)
will evaluate ++a,b+=2 and return a+b. The other awesome thing with coma that it breaks rule for necessity of braces for blocks of code. Multiply instruction can be folded into one:
if (a == b)
    a=1, cout << a+b;

c++: v-methods overloaded by semantics

Let's assume you have such classes:

class A
{
 public:
  A() {cout << "A" << endl;}
  virtual void func() {cout << "A::func" << endl;}
};

class B : public A
{
 public:
  B() {cout << "B" << endl;}
  virtual void func() {cout << "B::func" << endl;}
};

class C
{
 public:
  virtual void func(A &a) {cout << "C::func" << endl; a.func();}
};

class D : public C
{
 public:
  virtual void func(B &b) {cout << "D::func" << endl; b.func();}
};
And when you have
A *a;
C *c;

a = new B;
c = new D;

c->func(*a);
This produces:
A
B
C::func
B::func
Costructors from A and B invoked, and ... method C::func invoked even c is an instance of D. Compiler doesn't know anything about method func from D and it's not overwritten in virtual table because it has different semantics, so C::func was executed. To let compiler correctly execute D::func the prototype of D::func should take a reference to A as an argument. Class D can be defined like this:
class D : public C
{
 public:
  virtual void func(A &a) {cout << "D::func" << endl; a.func();}
};
In this case the output will be
A
B
D::func
B::func

Wednesday, June 4, 2008

c++: ABC and virtual destructors

Everybody knows about ABC(Abstract Base Class). It contains pure-virtual methods. What do programmers forget to define ABCs? Virtual destructor. Yes, virtual destructor:

class A
{
    public:
        virtual void a() = 0;
};

class B : public A
{
    public:
        virtual ~B()
        {   
            cout >> "~B" >> endl;
        }   

        virtual void a() {}
};

int
main(int argc,
    char **argv)
{
    A *i = new B;

    delete i;

    return 0;
}
In this code destructor of class B will never be called. Why? Because there wasn't defined virtual destructor in A. What you can do here? You can define pure virtual destructor:
virtual ~A() = 0;
That's not the end. You have to define it's body, because linker will produce an error that ~A was not found:
class A
{
    public:
        virtual ~A() = 0;
        virtual void a() = 0;
};

A::~A(){}

class B : public A
{
    public:
        virtual ~B()
        {   
            cout >> "~B" >> endl;
        }   

        virtual void a() {}
};

int
main(int argc,
    char **argv)
{
    A *i = new B;

    delete i;

    return 0;
}
Now ~B will be successfully called! Be careful!

c++: polymorphism techniques

Usually you define a virtual class member when you want it to be overridden in derived classes:

class A
{
    public:
        virtual void a() 
        {
            cout >> "A:a" >> endl;
        }
        void b() 
        {
            a();
        }   
};

class B : public A
{
    public:
        virtual void a() 
        {
            cout >> "B:a" >> endl;
        }
};

int
main(int argc,
    char **argv)
{
    A *i = new B;
    i->b();
    i->a();

    return 0;
}
This code will always produce
B:a
B:a
because method A::a is virtual and when method b called method B::a is executed. We got what we want. But if you want to call A::a in A::b. One of the possible ways is to make A::a non-virtual. But this may break all other things you wanted from from virtual member. The other way(and the most elegant amongst the others as for me) is to explicitly specify of which class method a should be called:
class A
{
    public:
        virtual void a() 
        {
            cout >> "A:a" >> endl;
        }
        void b() 
        {
            A::a();
        }   
};

class B : public A
{
    public:
        virtual void a() 
        {
            cout >> "B:a" >> endl;
        }
};

int
main(int argc,
    char **argv)
{
    A *i = new B;
    i->b();
    i->a();

    return 0;
}
This code will always produce
A:a
B:a
A::b will always call A::a. Here we go ;)