Please help me make my library work!


AquaAnalogue

Member
Joined
Jan 19, 2010
Messages
355
I'm trying to make my own library of commonly (re)written functions and classes for my own projects to share, so that I don't need to waste my time re-creating them. I don't want to just copy-paste them between my projects; ideally I'd use a shared library, but a static one will do.


The problem is, at least the way I've been told, that C++ makes it impossible to include classes in libraries in the standard way.


So, then, what do I do? I'm totally lost, nothing on stackoverflow, etc. is helping much, and my primary project cannot go forward until I finish this secondary project, so that future projects may go more smoothly.
 
The problem is, at least the way I've been told, that C++ makes it impossible to include classes in libraries in the standard way.
Huhh ???


You need the compiled library and the header, be it for c or c++, else how would project like QT works ?


http://www.adp-gmbh.ch/cpp/gcc/create_lib.html (just replace gcc by g++ here)


The original language dont matter once you have your objects (.o) files ;)
 
Last edited by a moderator:
The original language dont matter once you have your objects (.o) files ;)
That is not true, name mangling can cause quite a bit of problems, even if you are only working within C++.


If a C program wants to link against C++ code, the C++ stuff that it wants to access needs to be unmangled as a C compiler would do it (that's what the whole 'extern "C"' stuff is for) - which automatically limits the usable interface to functions and structs, therefore people often create a compatibility layer which wraps all the classes into C friendly functions.


If a C++ program wants to link against C++ code, it needs to follow the same mangling conventions (or the linker needs to be able to support the other convention) - but that shouldn't be a problem on the Pandora as everyone just uses GCC. It is more problematic on Windows where you are more often working with objects produced by different compilers (the C++ standard does not define how to do the mangling, therefore compilers tend to do it differently).
 
Yeahm, you need to be careful .. if you link a C++ lib, then any caller should be built by C++ compiler as well, or if a C compiler, then your lib must be "Extern C".


Not that you can make a bridge as well .. You can have a C++ lib, and a C program, and then make a little middle-guy that has extern "C" functions but is compiled by C++ (g++) and so can talk to the C++ lib.


So you can pretty much get away with anything from C to C++, but what I suggest is .. if you want a C++ lib (using g++), then use g++ on your projects as well, and not too many concerns. Or be careful with your extern "C" markings so gcc and g++ play nicely together (and I'd suggest doing it anyway, to be explicit.)


--


Note that historically and for good reasons, sometimes you need extra pragma's in g++'s class headers and implementations to make linking work efficiently; ie: on many desktop systems like Windows, Mac etc the vendor of the OS supports the linker -- for Windows, the linker comes with the compiler, so they can cheat a lot. With Unix and Linux you can 'assume' somethign similar but its not right, since some vendors supply the linker with the OS, and the compiler would be gcc in this case (say). ie: You coudl use Solaris, and use the Sun CC and Sun linker .. but if you use Solaris with gcc and Sun linker, we're tlaking different folks for linker and compiler.. so no cheating. So to be broadly supporting, gcc sometimes has to have some help .. consider --


In the case where you have a C++ lib, and 2 normal files refer to it (so a lib, and two .o's that need it); for C++, instanciated class stuff, then if the compielr and linker are not the same vendor and don't know each other too well, then the compiler may assume it needs to instanciate the class into each .o just to make sure its there -- since it may not know if another .o file will instanciate it. Without doing thatm, then the dev needs to make another .o that explicitly instanciated any classes, or use special markup to say 'for this .o ionstanciate, but for this other one, do not.' So in some compiler/linker mixtures you end up with a class instanciated from template in multiple .,o files, making for giant application with multiple codebases for the same templates. ie: Instea d of a 10k app, you might have a 20k one, with some code duplicated. Other ways a linker can work are to keep a database and say hey, we instanciated that template for object1.o, so lets skip it for object2.o .. but is that at compiler or linker stage? does linker need magic to say 'saw that, skip it..'. When multiepl vendors are involved, and multiple ways of doing things.. . its just a big old mess.


So g++ includes pragmas to help control all these different possible things. So in the _worst case_, you have to manually control template instanciation, which sucks ass, but it absolutely makes sense why its like that, and its not anyones fault except for having a non-monoculture for linker/compiler. But Windows and Mac folks often see this as a liability, since they're used to the 'single compiler option'.


Now, more recent g++'s and environments and whatnot have alleviated all this, but you may find notes about it online to scare the heck out of you.


So remember..


You probably don't need to care. But if you do, its really not as bad as it all may sound from notes or the above. At worst its just a drag, but it does all demystify how things work.. where as usually you just trust 'it'll all work', but you dont know for sure ;)


--


Horror story .. there was a time long ago when a builf of MS compielr TI hink did it like this.. a per-project database of instanciations; so if STL got used for linked lists, it'd get instanciated into code once per use (ie: a hash table of string to int mapping woudl get instanciated once, and string to string once.. so if two object files in same project used string-to-string hash tab le say, only one copy of the code, since its in the project DB. But if you had two projects in overlapping directories, you'd randomly have functions missing when linking and other mishaps. A database is easy for one project but leda to sync problems.. no database means code duplication in generated binary. ITs always a pita :)


jeff
 
So, if I build a static library using C++ with no "extern C" declarations, and use it only with C++ programs, I shouldn't have a problem.... and I'd only have a problem with a shared library if everyone didn't use the GCC, which they do.


So if I go with the static library, I'll be good everywhere, and plus I'll be standard/precedent/convention-compliant as well, right? People (who hypothetically care about my project) can just build it from source whenever they need to build anything else I write.


I'm thinking the space implications of a few things being statically linked is negligible in our modern age, when compared to the PITA of wrapping every. single. thing. in "extern C"-safe functions.


If this all works, then I can just write a nice "install" script (or just another make target) for the library which builds it into a static library, copies the headers, etc to the normal library spot for the system, and then anyone can build my projects.


Is that "rude" or something? Should I expect nastygrams saying things like, "Why should I install your library just to build your program?"


This is all assuming, of course, that I make something actually worth distributing to others.
 
I usually put "extern C" type notation in the header top and bottom (only when it detects a C++ compiler, so you don't error out when a C compiler hits it); ifg you wrap the whole header(s), then that implies the functions delcared are externed. ie: 6 lines in your head .. so its hardly any work. (And only for the 'interface header' you want to expose to C and C++.


But yeah, if your target is C++ users, hell with it, you're all good, no worry. If someone needs to, they can make an adapter and in turn use extern "C" on _that_.


IF this lib is 'general utility functions that are handy', it might be rude to make peopel get it (just another library namespace to deal with installing); if itsd a dedicated purpose library, then may be worth publishing and building 2 packages .. one ofr lib, the other for app, and posting dependancy (ie: assuming rpm or debian or whatever port system, its no trouble.) ie: If you're making "mycoolstuff.lib", then you're a goof; if you're makintg a 'libpng' type lib that works on png files, and is general purtpose and others may want it, then that makes sense.


Nothing says you can't have two directories in your distribution for source ..


./mylib


./myproject


(See Colem emulator source from Marat .. it inclues 3 related projects, 2 are utility libs and the third is the actual emu. He uses the util libs in multiple emus, but includes them in each source distro so as not to be a pain in the ass.)


Probably theres a Makefile with rule for 'dist-source' so you can do 'make dist-source' which tar's up your two dirs into one tgz you can disribute. Then no one would have a problem.


jeff
 
It consists of a couple of SDL helper functions that I don't want to rewrite, a pseudorandom number generator made to my liking, and a container template built upon said generator that randomly returns one of its members, and it continues to grow as I see fit (read: as long as there are functions I think of that I want to re-use).


So yeah, just odds and ends; it sounds like I'll be better off just including the CPP/HPP files in every project, although I really hate that kind of repetition.


The problem is, I'm trying to figure out how to nicely tie this in with my git repositories. Right now the least messy solution looks like I'll have to put a script into each project to clone the library's git repo and stuff it into that project's folder under "libmycoolstuff". ( :p ) Any better or more standard ideas?
 
Last edited by a moderator:
Like I mentioned above .. "make distsource" or something might be the way to go; build however you like, but to bundle it up that step can create the tarball for you all ready to go. ie: So you don't have any duplication in _your_ setup, but when you send it out, it gets duped and set up just right, so everyone else can be happy. I've done that a few times.. its a little clumsy, but easy to set up and works well.


jeff
 
for reference you may want to look at the wiz3d pack I put together. It builds a number of shared libs and installs to the toolchain designated.
 
I'm not sure if this is what you were looking for, but here is a quick knocked together example of how to building a couple of files to make a static library, and then how to build a separate code file, and link it against the static library in order to make a final executable:



Code:
# Some compile/link flags

CXXFLAGS  = -c -x c++ -fsigned-char -mcpu=cortex-a8 -mfpu=neon -ftree-vectorize

CXXFLAGS += -mfloat-abi=softfp -ffast-math -fsingle-precision-constant

CXXFLAGS += -Wno-deprecated -Wno-psabi -fno-exceptions -fno-rtti -g -O0

LDFLAGS   = -Wl,-rpath=Libs -LLibs -Wl,--no-undefined -g -lstdc++ -lrt

LDFLAGS  += -lGLES_CM -lx11 -lopenal

# Compile PandoraGraphics.cpp and PandoraAudio.cpp to PandoraGraphics.o and PandoraAudio.o

arm-none-linux-gnueabi-g++.exe $(CXXFLAGS) PandoraGraphics.cpp

arm-none-linux-gnueabi-g++.exe $(CXXFLAGS) PandoraAudio.cpp

# Make a static library for PandoraEngine.debug.a out of the above.

arm-none-linux-gnueabi-ar.exe "ru" PandoraEngine.debug.a PandoraGraphics.o PandoraAudio.o

# Compile our program code.

arm-none-linux-gnueabi-g++.exe $(CXXFLAGS) main.cpp

# Link together our program with our static library

arm-none-linux-gnueabi-g++.exe -Wl,-soname,MyGame.debug $(LDFLAGS) main.o PandoraEngine.debug.a  -o "MyGame.debug.out"


I haven't tried executing that exact block, but it at the very least outlines the basic process.


Steve
 
Last edited by a moderator:
Back
Top