Reputation: 9465
We have two libraries - lib1 and lib2. Both the libs use a third lib say lib3. If our customer uses lib1 and lib2 in the same application using static linking, the customer faces linking issues due to symbol collision as functions from lib3 are common in lib1 and lib2.
We have access to lib1, lib2, lib3 source codes. What changes should we do to avoid naming collisions?
After reading some posts, namespacing in C++ seems to solve the problem? But will it work in our case as lib3 will still be loaded twice?
Upvotes: 0
Views: 556
Reputation: 1709
I'll leave an answer because this won't fit inside a comment.
As I understand you deploy some kind of software development kit for lib1
and lib2
. Each SDK contains some public headers and the lib1
and lib2
static libs. Both of these libraries are statically linked with lib3
, which is an internal library.
So the SDKs could look something like this:
lib1 SDK
├── lib
│ ├── lib1.lib
├── headers
│ └── lib1.h
lib2 SDK
├── lib
│ ├── lib2.lib
├── headers
│ └── lib2.h
This works great except in the cases in which a customer needs both lib1
, and lib2
. Our suggestion was: don't statically link lib3
, but deploy it inside the lib1
and lib2
SDKs. In this case your customers will simply have to update their build scripts to also link the already included lib3
. So lib1
customers will now link with lib1
and lib3
; lib2
customers will now link with lib2
and lib3
. You already deploy lib3
to the customers, only not as a stand-alone file, but included in the lib1
and lib2
libraries, so there's no big change here.
This means that customers who use both can pick one of the lib3
s you provided and link against it.
Your SDKs now look like this:
lib2 SDK
├── lib
│ ├── lib2.lib
├── headers
│ └── lib2.h
├── dependencies
│ └── lib3.lib
(same for lib1)
There is now the risk that the customer will use lib1 1.0
which depends on lib3 1.0
and lib2 2.0
which depends on lib3 2.0
, with the two lib3
versions being binary compatible (linking will succeed for both lib1
and lib2
regardless of the lib3
version), but there are API changes between the two lib3
versions that will generate runtime errors.
In this case you have to either be able to verify compatibility at build time (harder to do when you don't control the build process), or at run time (easy to do as long as the lib3
API for doing this does not change).
You could also try to accommodate these customers by providing a common SDK for lib1
and lib2
which always includes a lib3
version that is guaranteed to be compatible with both. However, this might not be a cost effective strategy for you.
EDIT: As @lalala mentioned, there are multi-threaded concerns that can make this unfeasible. For example, if lib3
is not thread safe, making lib1
and lib2
use the same lib3
will lead to race conditions, deadlocks, etc.
Upvotes: 3
Reputation: 9465
We finally fixed our problem using dynamic namespacing
First, define a macro for the namespace
#ifndef LIB_NAMESPACE
#define LIB_NAMESPACE SomeNameSpace
#endif
then add namespace around every class.
On compilation override the macro from the compiler command line e.g.
g++ -DMY_LIB_NAMESPACE=Lib1Namespace ...
g++ -DMY_LIB_NAMESPACE=Lib2Namespace ...
The only disadvantage is the size of the final executable will be slightly larger due to duplicate code.
Upvotes: 1