^ Not a duplicate, here I'm investigating why one method is preferred, not wich are the differencies, a carefull read would make it glaring to peer reviewers it is not a duplicate.
I was reading that:
And suddendly the question popped out in my mind. Is there any sane reason that make a static or shared library preferred over a plain Obj file?
When creating a static/shared library we lose much information and also chance for optimization (wich don't matters to me). Instead we could compile our source files into Obj files, and then link all Obj files (also the Obj files of the library) into the final executable.
=>
we retain all info, especially usefull for exception handling and preventing duplicated type_info (dependency injection with C++ relies on C++11 Type_info, but there's no guarantee you'll not get a duplicated std::type_info
object for different classes in different libraries).
If visibility warry you, you can do a "Ghost Compile/Link" step (compile application and then link with the static library to see if we get "undefined symbol" because accessing internal stuff) and then proceed with the real Compile/Link (everything to Obj files and then Obj to the Executable)
The final executable will be smaller and faster, there will not be issues with exceptions and the build system will be more Emscripten friendly :).
Do you see possible issues (I'm using already that and works flawless, but maybe already existing code may have "duplicate" issues? Maybe unfeasible for large codebases?)
SMALL EXAMPLE:
My static library is compiled from 2 files:
MyFoo.hpp
//declare MyFoo to be internal to my library
void __attribute__ ((visibility ("hidden"))) MyFoo();
MyFoo.cpp
#include <MyFoo.hpp>
#include <iostream>
void MyFoo(){
std::cout<<"MyFoo()"<<std::endl;
}
MyBar.cpp
#include <MyBar.hpp>
#include <MyFoo.hpp>
#include <iostream>
void MyBar(){
std::cout<<"MyBar() calling "; MyFoo(); //calling MyFoo
}
When we compile, we get 2 ObjFiles
MyFoo.o
MyBar.o
When we link we get
MyLib.a
MyBar, can still "see" and call MyFoo (otherwise it could not compile).
When I create my executable if I link against MyLib.a
I can call only MyBar
wich is correct
#include <MyBar.hpp>
#include <MyFoo.hpp>
int main(){
MyBar(); //ok
//MyFoo(); // error undefined symbol
return 0;
}
That's because I lost some info (desired in most cases: note I had to specify hidden
), but hence the "visibility" feature turns into a problem because hiding stuff we could end up with different classes (inside different libraries) that have the same full qualified names:
That's an issue when throwing exceptions, or when trying to use std::type_info
So the only viable solution seems doing a 2 steps compilation, 1 is just to check we are not breaking visibility (and hence the API contract), the 2nd build is to avoid the issues in the aforementioned link (strange to debug exceptions behaviour or misterious crashes).
Linking MyFoo.o
,MyBar.o
,main.o
togheter would be conceptually wrong because allows compilation of the following code
#include <MyBar.hpp>
#include <MyFoo.hpp>
int main(){
MyBar(); //ok
MyFoo(); // compile NOT OK!
return 0;
}
but linking object files togheter is the only way to avoid exceptions issues.