On Mon, Dec 5, 2011 at 1:40 AM, Tom Gall tom.gall@linaro.org wrote:
I probably know the answer to this already but ...
For shared libs one can define and use something like:
void __attribute__ ((constructor)) my_init(void); void __attribute__ ((destructor)) my_fini(void);
Which of course allows your lib to run code just after the library is loaded and just before the library is going to be unloaded. This helps keep out cruft such as the following out of your design:
PleaseCallThisLibraryFunctionFirstOrThereWillBeAnErrorWhichYouWillHitCausingYouToPostToTheMailingListAskingTheSameQuestionThatHasBeenAsked1000sOfTimes();
Yeah .. you know the function. I don't like it either.
Unfortunately this doesn't work when people link in the .a from your lib. Libs like libjpeg-turbo in theory should never ever need to be linked in that fashion but consider the browsers who link to the universe instead of using system shared libs.
On Mon, Dec 05, 2011 at 04:19:11PM +0800, Kito Cheng wrote:
Here is some triky way for this problem, you can put the constructor and destructor to the source file which contain necessary function call in your libraries to enforce the linker to archive your constructor and destructor.
However if this solution is not work for your situation, you can apply the patch in attach for build script to enable the LOCAL_WHOLE_STATIC_LIBRARIES for executable,
After patch you can just add a line in your Android.mk :
LOCAL_WHOLE_STATIC_LIBRARIES += libfoo
The most disadvantage of this way is you should always link libfoo by LOCAL_WHOLE_STATIC_LIBRARIES...and this patch don't send to linaro and aosp yet.
[...]
Part of the problem here is that .a libraries lack the dependency and linkage metadata that shared libraries have.
-2)
Put up with the need to call an explicit initialisation function for the library. A lot of commonly-used libraries require an initialisation call, and I'm not sure it causes that much of a problem in practice...
-1)
Put a C++ wrapper around just enough of your library such that your constructor/destructor code is recognised as a needed static constructor/descructor by the toolchain.
I can't think of a very nice way of doing this, so I won't elaborate on it...
It's also not really a solution, since you still need to pull in a dummy static object from somewhere in order to cause the construcor and descructor to get called.
0)
libtool or similar may help solve this problem, but I don't know much about this -- also, for solving the problem, that approach only works if uses of your library link via libtool.
1)
One hacky approach is to rename your library to libmylib-real.a, and then make replace libmylib.a with a linker script which pulls in the needed constructor as well as the real library:
libmylib.a: EXTERN(__mylib_constructor) INPUT(/path/to/libmylib-real.a)
This works, providing that __mylib_constructor is external (normally, you would be able have the constructor function static, but it needs to be externally visible in order to be pulled in in this way.
2)
Another way of doing a similar thing is to mark __mylib_constructor as undefined in all the objects that make up the library.
Unfortunately, there seems to be no obvious way of doing that: the assembler generates undefined symbol references automatically for unresolved references at assembly time. There's no way for force the existence of an undefined symbol without an actual reference to it. objcopy/elfedit don't seem to support adding such a symbol either. It would be simple to write a tool to add the undefined symbol reference (such tools may exist already), but binutils doesn't seem to provide this for you. The plausible-looking -u option to gcc doesn't do anything unless doing a link.
One other way of doing it without a special tool is to insert a bogus relocation into the text section of each object with an assembler .reloc directive specifying relocation type R_<arch>_NONE.
There isn't really a portable way to do that, though. The name of the relocation changes per-arch, and some arches have other quirks (on ARM for example, .reloc cannot refer to the current location, but seems instead to need to refer to a defined symbol which is non-zero distance away from the location counter).
One advantage to this approach is that your .a file looks just like any other .a file. Also, you can include that dependency in only those objects which really require the library to be initialised (normally, this is not a huge benefit though, since probably most of your objects _do_ require the library to be initialised).
A disadvantage (other than portability problems) is that, like (1), the constructor symbol must be external (not static)... so it pollutes the symbol table and isn't protected against people calling it directly.
You can create a dummy symbol instead of referring to the constructor symbol directly though -- this solves the second problem.
3)
Finally, you can split your contructor/destructor code out into a separate .o file (say mylib-ctors.o), and use the linker script trick for (1) to forcibly include this object when linking:
libmylib.a: INPUT(/path/to/mylib-ctors.o /path/to/mylib-real.a)
This avoids some of the disadvantages of the other approaches, but you still end up with a strange-looking library which is really a linker script.
This is closer to how the C library traditionally solves the problem (i.e., the crt*.o stuff). libc.so also tends to be a linker script, which deals with the fact that some parts of libc must be statically linked from a separate library when linking to -lc.
Obviously, approaches (1)..(3) all suffer from arch or toolchain portability problems (or both). (The GNU/GCC __constructor__ thing is obviously a portability problem in itself, it you're minded to care about it.)
Cheers ---Dave