I have developed a set of libraries/common classes that I use in all my apps (this is on unix), and compiled them into a shared object (.so). Then, when I compile my individual apps, I link the library with the executable with -L /libs/ -l mylib . When running any app, I then make sure that the /libs directory is in my LD_LIBRARY_PATH

This works perfectly fine in most cases. The problem I'm facing is that I change these libraries often, and therefore for my existing applications stop working if they are not recompiled/re-linked against the new .so file.

Here's my question: (finally)
Is there a way that I can link in my library code (via compiler flags, etc.) such that the executable is 'stand-alone' meaning that all of the required code is there? This way, the apps can use the code that it was compiled with, without regard to if and when I change the library. I don't care if the executable size grows or anything like that - I've got the disk space.

Recommended Answers

All 15 Replies

Yes. - it's called a static link. It means that all of the runtime you need is part of the image file - obviously a much bigger image file.

I can't tell which version of unix you have, but your man ld page will tell you how to do that. In most flavors of Unix you provide the cc command with a list of static libraries ".a" files including libc.a. You will also have to put your own runtime into one of these archives as well - or link against the objects in it. Again, the ld manpage is your friend.

I'm using Solaris and I'm using the forte compiler (ie CC ). I'm now trying to use the 'ar' command...

Also note that my library contains a lot of template code. Is this going to work if statically linked?

You're on the right track. I don't use Solaris, but I do know it has some (what I think are) funny conventions.

Now that I know it's Solaris, you can use versioning of your .so files, as long as you keep all the old ones out there. You can park all you stuff in a special area that won't get clobbered in an update, then define LD_LIBRARY_PATH (or SHRLIB_PATH) so that dld can open the libraries -if you plan to move them around later. Link specifically against a version like "-l mylib.3.2"

The versioning idea is a possibility, I was just hoping I could keep an executable stand-alone (this way I could move it to another solaris machine without having to copy over the library, etc.)

The "moving over" part is the reason for which static linking exists.

Your problem could be looked at another way: as an implementation/deployment issue.
Matching up correct code with correct run-times. If you are working for a company ask them to look at TeamTrack and ChangeMan from Serena. You can also package everything as one tarball and use cvs or whatever to manage your tarballs.

Yes, this is why I want to link statically. My problem now however seems to be that my template code cannot be linked statically. Is that a known issue? Does template code need to be linked dynamically? (Given that it determines the classes/types at runtime, it seems somewhat logical).. If that's the case, I may be stuck.

Does template code need to be linked dynamically?

No.

OK, I'll guess I'll just keep playing with the compile/link flags..

No, no, not flags...

I'm assuming you're using C++ code - look for something like "libc++.a" and link against that. I don't know the name for the library file in Solaris.

No, no, not flags...

I'm assuming you're using C++ code - look for something like "libc++.a" and link against that. I don't know the name for the library file in Solaris.

Not sure what you're talking about... To refocus ourselves, what I'm trying to do is take a shared object that I wrote and have it be included as part of an executable itself so I can provide the executable without the library. Note sure where libc++ came into play...

My bad.

Just to clarify:
1. You can link an entire module statically.
2. You can link just one or two libraries statically, and link the rest of the image dynamically:

cc myfile.c /path/to/mylib.a /path/to/anotherlib.a -o myfile

My bad.

Just to clarify:
1. You can link an entire module statically.
2. You can link just one or two libraries statically, and link the rest of the image dynamically:

cc myfile.c /path/to/mylib.a /path/to/anotherlib.a -o myfile

Jim,

That's what I tried, but it doesn't like any of my classes that use templates. I don't have this trouble with the .so

So, how did you compile and link the .so file?

Compile library:
CC -c -I./ -I./unix -g -D_DEBUG -D__SUNOS__ -D__UNIX__ -c *.cpp
BaseClass.cpp:
CommandLine.cpp:
DHException.cpp:
DHLogException.cpp:
DataBase.cpp:
Date.cpp:
FileUtilities.cpp:
General.cpp:
Globals.cpp:
Identifiable.cpp:
Log.cpp:
MainProgram.cpp:
MultiLog.cpp:
Printable.cpp:
StringUtils.cpp:

Link library:
CC -G -lsocket -lnsl -ldl *.o -o libhoff.so


Compile app:
CC -w -c -I./ -I../libs -D__SUNOS__ -c *.cpp

Link app:
CC -Bdynamic -lhoff *.o -o MyApp

---------------------------------------
Failed attempt with static:
CC -c -I./ -I./unix -g -D_DEBUG -D__SUNOS__ -D__UNIX__ -c *.cpp
BaseClass.cpp:
CommandLine.cpp:
DHException.cpp:
DHLogException.cpp:
DataBase.cpp:
Date.cpp:
FileUtilities.cpp:
General.cpp:
Globals.cpp:
Identifiable.cpp:
Log.cpp:
MainProgram.cpp:
MultiLog.cpp:
Printable.cpp:
StringUtils.cpp:

Link library:
/usr/ccs/bin/ar rc libhoffstatic.a *.o

Compile and Link app (and link errors)
CC -w -c -I./ -I../libs -I../libs/unix -D__SUNOS__ -c *.cpp
CC *.o ../libs/libhoffstatic.a -o Hoff
Undefined first referenced
symbol in file
long Properties<std::basic_string<char,std::char_traits<char>,std::allocator<char> >,std::basic_string<char,std::char_traits<char>,std::allocator<char> > >::getPropertyL(const std::basic_string<char,std::char_traits<char>,std::allocator<char> >&,const long) ../libs/libhoffstatic.a(CommandLine.o)
bool Properties<std::basic_string<char,std::char_traits<char>,std::allocator<char> >,std::basic_string<char,std::char_traits<char>,std::allocator<char> > >::getPropertyBool(const std::basic_string<char,std::char_traits<char>,std::allocator<char> >&) ../libs/libhoffstatic.a(CommandLine.o)
int Properties<std::basic_string<char,std::char_traits<char>,std::allocator<char> >,std::basic_string<char,std::char_traits<char>,std::allocator<char> > >::getPropertyI(const std::basic_string<char,std::char_traits<char>,std::allocator<char> >&) ../libs/libhoffstatic.a(CommandLine.o)
__rwstd::__rb_tree<std::basic_string<char,std::char_traits<char>,std::allocator<char> >,std::pair<const std::basic_string<char,std::char_traits<char>,std::allocator<char> >,CommandLineArg>,__rwstd::__select1st<std::pair<const std::basic_string<char,std::char_traits<char>,std::allocator<char> >,CommandLineArg>,std::basic_string<char,std::char_traits<char>,std::allocator<char> > >,std::less<std::basic_string<char,std::char_traits<char>,std::allocator<char> > >,std::allocator<std::pair<const std::basic_string<char,std::char_traits<char>,std::allocator<char> >,CommandLineArg> > >::iterator __rwstd::__rb_tree<std::basic_string<char,std::char_traits<char>,std::allocator<char> >,std::pair<const std::basic_string<char,std::char_traits<char>,std::allocator<char> >,CommandLineArg>,__rwstd::__select1st<std::pair<const std::basic_string<char,std::char_traits<char>,std::allocator<char> >,CommandLineArg>,std::basic_string<char,std::char_traits<char>,std::allocator<char> > >,std::less<std::basic_string<char,std::char_traits<char>,std::allocator<char> > >,std::allocator<std::pair<const std::basic_string<char,std::char_traits<char>,std::allocator<char> >,CommandLineArg> > >::erase(__rwstd::__rb_tree<std::basic_string<char,std::char_traits<char>,std::allocator<char> >,std::pair<const std::basic_string<char,std::char_traits<char>,std::allocator<char> >,CommandLineArg>,__rwstd::__select1st<std::pair<const std::basic_string<char,std::char_traits<char>,std::allocator<char> >,CommandLineArg>,std::basic_string<char,std::char_traits<char>,std::allocator<char> > >,std::less<std::basic_string<char,std::char_traits<char>,std::allocator<char> > >,std::allocator<std::pair<const std::basic_string<char,std::char_traits<char>,std::allocator<char> >,CommandLineArg> > >::iterator,__rwstd::__rb_tree<std::basic_string<char,std::char_traits<char>,std::allocator<char> >,std::pair<const std::basic_string<char,std::char_traits<char>,std::allocator<char> >,CommandLineArg>,__rwstd::__select1st<std::pair<const std::basic_string<char,std::char_traits<char>,std::allocator<char> >,CommandLineArg>,std::basic_string<char,std::char_traits<char>,std::allocator<char> > >,std::less<std::basic_string<char,std::char_traits<char>,std::allocator<char> > >,std::allocator<std::pair<const std::basic_string<char,std::char_traits<char>,std::allocator<char> >,CommandLineArg> > >::iterator) ../libs/libhoffstatic.a(CommandLine.o)
void Properties<std::basic_string<char,std::char_traits<char>,std::allocator<char> >,CommandLineArg>::add(const std::basic_string<char,std::char_traits<char>,std::allocator<char> >&,const CommandLineArg&,bool) ../libs/libhoffstatic.a(CommandLine.o)
std::list<std::basic_string<char,std::char_traits<char>,std::allocator<char> >,std::allocator<std::basic_string<char,std::char_traits<char>,std::allocator<char> > > >::iterator std::list<std::basic_string<char,std::char_traits<char>,std::allocator<char> ...


..etc...

I got it! I needed to compile the library like this.
CC -xar *.o -o libhoffstatic.a
where ( -xar is: )
-xar Create archive library with instantiated templates

and then compile the app:
CC -w -c -I./ -I../libs -I../libs/unix -D__SUNOS__ -c *.cpp
CC *.o ../libs/libhoffstatic.a -o Hoff

That worked - I was able to move the app 'Hoff' to another machine without the library.

Be a part of the DaniWeb community

We're a friendly, industry-focused community of developers, IT pros, digital marketers, and technology enthusiasts meeting, networking, learning, and sharing knowledge.