[Top][All Lists]
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
Re: Questions on exporting functions from a shared library
From: |
Jef Driesen |
Subject: |
Re: Questions on exporting functions from a shared library |
Date: |
Thu, 02 Oct 2008 17:08:55 +0200 |
User-agent: |
Thunderbird 2.0.0.17 (X11/20080925) |
Ralf Wildenhues wrote:
Hello Jef,
* Jef Driesen wrote on Tue, Sep 23, 2008 at 08:44:47PM CEST:
Brian Dessent wrote:
There are two aspects to the symbol visibility stuff:
[ snip nice explanation ]
Now that I start to understand all the differences, I only need to find
a way how to incorporate everything nicely in my automake build system.
Suggestions? I guess I'm not the first one struggling with this, so I'm
surprised there is not more information available. Most projects (at
least the ones I checked) seems to be using -export-symbols.
Well, as you don't seem to say exactly what you need: you can
- add -export-symbols* to libfoo_la_LDFLAGS, or
- add visibility annotations right to your source files
(preferably through a #define so you can factor for different
spellings).
You can get better help if you describe more precisely what you already
tried, and more importantly, which way you decided to go now.
What I want to achieve is the following (in order of importance):
1. Only export the functions that are part of the public api. It is
important that the solution is supported by at least gcc/autotools and
msvc. It should also have little to no impact on the users of the
library, so the library remains easy to use. (Having to add stuff to the
build system of the library is of course fine, because that would go
into the shipped autotools or msvc project files.)
2. Take advantage of the visibility/dllimport performance improvements.
Currently, I'm using -export-symbols with a separate "mylib.symbols"
file. However, since my library has multiple backends, that are not
always enabled, the contents of this file is not static. I solved this
by using the C preprocessor:
/* File: mylib.symbols */
mylib_abc
#ifdef MYLIB_XYZ_SUPPORT
mylib_xyz
#endif
/* File: Makefile.am */
if XYZ
mylib_la_SOURCES += xyz.h xyz.c
endif
mylib_la_LDFLAGS = -no-undefined -export-symbols mylib.exp
mylib_la_DEPENDENCIES = mylib.exp
mylib.exp: mylib.symbols
if XYZ
$(CPP) -P -DMYLIB_XYZ_SUPPORT - < mylib.symbols | sed -e '/^$$/d' > $@
else
$(CPP) -P - < mylib.symbols | sed -e '/^$$/d' > $@
endif
CLEANFILES = mylib.exp
EXTRA_DIST = mylib.symbol
One of the downside of this method is that I need to maintain the
separate symbols file (not a real issue). But more important is that
this setup is not supported by the msvc compiler. That compiler does not
export any function by default, unless a DEF file or the dllexport
attribute is used. But I don't know if it is possible to do a similar
trick for msvc, and generate the DEF file on the fly. And I don't want
to maintain two almost identical symbol files.
If I could use the dllexport (win32) or visibility (unix) mechanism,
that would work for both the gcc and msvc compiler. And in addition, I
would be able to take advantage of the performance improvements.
So I tried with this (following the gcc visibility guide):
/* File: Makefile.am */
mylib_la_CFLAGS = -fvisibility=hidden -DMYLIB_BUILD
Note: How do can I detect whether the visibility attribute is supported?
/* File: Makefile.am */
#ifdef WIN32
#define IMPORT __declspec(dllimport)
#define EXPORT __declspec(dllexport)
#else
#define IMPORT __attribute__ ((visibility("default")))
#define EXPORT __attribute__ ((visibility("default")))
#endif
#ifndef MYLIB_STATIC
# ifdef MYLIB_BUILD
# define API EXPORT
# else
# define API IMPORT
# endif
#else
# define API
#endif
where MYLIB_BUILD is always defined when building the library, and
MYLIB_STATIC should be defined for static building and linking.
And that last one is where the problem is, because libtool builds both a
static and dynamic library (unless I explicitly disable one of them with
./configure --disable-* of course). This happens regardless of the
platform (windows mingw or linux gcc). The result is that MYLIB_STATIC
is never defined when building the library, and the static library gets
build with EXPORT. I'm not really sure this is a allowed (it seems to work).
A closely related problem is when I try to build the examples. Those
examples are part of my package, but they are located in a different
directory than the library code. When linking against the shared library
everything is fine, but when I try to link against the static library I
get this error (on Windows): "undefined reference to
`__imp__myfunction'". Obviously because MYLIB_STATIC was not defined and
the compiler tries to dllimport my functions.
BTW, is it possible to force automake to link my examples against the
static library, in case both the static and shared library are build?
Now I'm using a separate build tree with ./configure --disable-shared,
thus affecting the complete project, when I need statically linked examples.