Is there a cross platform way to selectively export certain functions and structs from a C project which builds a shared library?
I want to do in a way that does not require a specific build system (the visibility should be defined in the code, eg as a macro), and in a way which both GCC and MSVC can understand.
Thank you.
Strictly no, of course, because the toolchains aren't the same.
But people do this. The complexities are that in windows, you need to
specifically tag the declarations of functions you want exported from
a DLL with __declspec(dllexport) in the location in the library where
the function is defined and __declspec(dllimport) in the locations
in client code where the funciton is referenced. Because standard
C practice has only one declaration in a single header file, this
means that you generally need to do some macro work to have a single
prefix that works in both locations. It seems like every project
picks its own standard for this.
On the Unix side, you don't need to tag exports at all, which is nice.
This is because every non-static function is exported by default,
which is not so nice. Often you can get away with this as long as
your non-public/non-static symbols have sane prefixes, which is what
most projects seem to do. If you need finer control over your
exported symbols, you can use a Solaris-style "mapfile" with the GNU
linker's --version-script (-M under solaris) argument to define explicitly which symbols should appear
in the external namespace.
There are a few more gotchas between the platforms, like the way the
per-library global namespace works and the handling of
startup/shutdown code. Basically, it's a rats nest that can't be
sanely explained in a post this short, but as long as you're careful
that your library contains simple functions and your namespace doesn't
pollute, you shouldn't have much trouble. Look to some of the more
popular cross-platform shared libraries (e.g. Qt, Glib/Gtk+, anything
distributed with msys, etc...) for guidance.
Related
I want to use pthread stuff in my static user library, but dependent projects won't link unless I add '-lpthread' to each project that uses it.
I would rather specify '-lpthread' in my own user library. Actually, I HAVE done that, but it doesn't do anything; I still need to add '-lpthread' to dependent projects, otherwise I get
Invoking: GCC C++ Linker
g++ <....>
/usr/bin/ld: /home/xxx/git/xxx/xxx.CUtil/Debug/libxxx.CUtil.a(EzyThread.o): undefined reference to symbol 'pthread_create##GLIBC_2.2.5'
IMO it defeats the purpose of my own user library, if I also have to include its dependencies in the projects using it; what if I decide to use another internal mechanism instead of pthread?
I've used
#pragma comment(lib, "SomeOtherStuff.lib")
in MS VC which does what I want - but I'm now in a gcc environment. I checked out #pragma comment(lib, "xxx.lib") equivalent under Linux? which seemed high on emotion and low on usable info. Is there either something similar in gcc, or some other way to avoid specifying '-lpthread' in each dependent project? I know that C isn't OOP but why make each dependency have to work out how the user library is implemented?
(Please don't say that something like the #pragma method is longer than '-lpthread'. Note that the #pragma, or equivalent mechanism in my user library, is typed once, but the '-lpthread' is needed potentially hundreds of times, and needs changing as many times if the underlying mechanism in the user library changes.)
Static libraries are really a tiny sauce on top of dumb archives of object files. In particular they do not track dependencies on other libraries.
Is there either something similar in gcc, or some other way to avoid specifying '-lpthread' in each dependent project?
...
the '-lpthread' is needed potentially hundreds of times, and needs changing as many times if the underlying mechanism in the user library changes
In Unix world this is usually done at build system level (e.g. by setting LIBS environment variable appropriately if you deal with Autoconf).
Note that the #pragma, or equivalent mechanism in my user library, is typed once
Semantics of pragma isn't well specified though. To begin with, if there are two pragmas in different source files, which library should be linked first?
Here's the situation. I have an old legacy library that is broken in many places, but has a lot of important code built in (we do not have the source, just the lib + headers). The functions exposed by this library have to be handled in a "special" way, some post and pre-processing or things go bad. What I'm thinking is to create another library that uses this old library, and exposes a new set of functions that are "safe".
I quickly tried creating this new library, and linked that into the main program. However, it still links to the symbols in the old library that are exposed through the new library.
One thing would obviously be to ask people not to use these functions, but if I could hide them through some way, only exposing the safe functions, that would be even better.
Is it possible? Alternatives?
(it's running on an ARM microcontroller. the file format is ELF, and the OS is an RTOS from Keil, using their compiler)
[update]
Here's what i ended up doing: I created dummy functions within the new library that use the same prototypes as the ones in the old. Linked the new library into the main program, and if the other developers try to use the "bad" functions from the old library it will break the build with a "Symbol abcd multiply defined (by old_lib.o and new_lib.o)." Good enough for government work...
[update2]
I actually found out that i can manually hide components of a library when linking them in through the IDE =P, much better solution. sorry for taking up space here.
If you're using the GNU binutils, objcopy can prefix all symbols with a string of your choice. Just use objcopy --prefix-symbols=brokenlib_ old.so new.so (be careful: omitting new.so will cause old.so to be overwritten!)
Now you use brokenlib_foo() to call the original version of foo().
If you use libtool to compile and link the library instead of ld, you can provide -export-symbols to control the output symbols, but this will only work if your old library can be statically linked. If it is dynamically linked (.so, .dylib, or .dll), this will not be possible.
I saw the code on the top of a GLUT demo and I'm curious about its functionality.
Why would someone want to write a #pragma instead of just including the library?
This pragma allows the library author to define library imports based on a range of criteria that can be analysed at compile-time. For instance, you can link against different libs, based on whether you want to link with:
multithreading on or off;
the shared or static version of the library in question;
the shared or static version of the standard runtime library;
the debug or release library;
the 32-bit or 64-bit library.
With the pragma form, all this can be decided via #ifdef preprocessor tests in one of the library's header files.
The #pragma is useful if you're distributing a library. Especially if you have different compiled .libs for different build settings (e.g. debug vs. release, multi-threaded C runtime vs. single-threaded, DLL vs. static library, etc). You can use #ifdefs in your code to select the correct .lib file, rather than requiring your users to set up their build environment to select the correct one.
It reduces support time because your users cannot choose the wrong .lib file.
It's an MSVC-specific pragma that means the named library will be automatically included at link time. The rest of your question about "just including the library" suggests that you're not appreciating the difference between headers and libraries: the header (GL/glut.h) describes what functions the compiler can expect at link time. The library (lib/glut32.lib) provides the implementation of these functions.
As the other answers have explained, it can be convenient, but I personally consider it a terrible idea to use this because it adds another barrier to writing portable code (other platforms and compilers may not support it). This question (thanks, #martin clayton) explains why it's not a good idea for portable code.
I compiled libxml2 with BCC 5.5 command line compiler, now I have lots of .obj files which I'd like to link into my Delphi application. Unfortunately, I get lots of "Unsatisfied forward or external declaration" errors, pointing to standard C library functions like memcpy, open, recv etc ...
What should I do to compile it correctly? I'd like to avoid depending on msvcrt.dll or any other external libraries.
Thanks in advance!
Depending on the version of Delphi you have, there should be a unit called crtl.dcu with which you can link. Just use the $L directive for each .obj file in a unit that also uses crtl. You may also need to "use" other various units like Windows, WinSock, etc... The point is to provide the symbols and functions to resolve during the link phase.
This is the same technique used to statically link in the DataSnap TClientDataSet code used to also build midas.dll.
you should read article of Rudy here "Using C object files in Delphi"
Don't use those functions, but rewrite them to call operating system functions (kernel32/system32) directly.
I'm developing a shared library, and since the code is big, I've decided to split it in many headers and source files, like any normal program :).
The problem is that most of these headers are for internal use, i.e. I don't want them to be accessible from outside of my library. So I'm thinking to move them all to a big source file and only provide headers for what is going to be visible.
It's a good idea do that? Should I worry on visibility?
Thanks
Instead of merging the headers, just keep them alongside your source files and don't "publish" them as a part of your development package. As an example of this, the linux kernel has many headers in the source tree, but only certain headers are exposed to applications (in the include structure).
You should approach it from a "cleanliness" angle; don't ship headers which include functions you aren't intending people to call. Don't document functions which you aren't shipping headers for.
If someone really wants to call a function in your library, they can, but you should try to make it clear that that's an unsupported use case and it's their problem if it all goes wrong.
Yes you should worry about symbol visibility. On Windows, set up to use DLLEXPORT. On Linux, define DLLEXPORT to set default symbol visibility, but compile everything with -fvisibility=hidden. There's an Ulrich Drepper article on it that is useful.
For the include files, you can separate them into directories and/or you can use your packaging system to just copy the public files.