Issue
I am having issues with conflicting names of libraries in installed c++ packages on a linux system. Both packages are built into installable apt packages using cpack. There are two packages being installed (A
and B
).
Do note that although I have control over these packages and so I can change the CMake and whatnot, they are to be compiled down into debian packages and installed as system libraries, not installed under /usr/local/
.
Each package have their own utils
module.
Each module is installed with namespaces of the parent project (so A::utils
and B::utils
), and the library .so files are in subfolders of the project name, not directly in /usr/lib
- so /usr/lib/A/libutils.so
and /usr/lib/B/libutils.so
.
As a postinstall script, a file with the name of the project (A
or B
) is added to /etc/ld.so.conf.d
that contains the path to the installed library (/usr/lib/A
for example) to the library paths.
In addition to utils
project A
also has a library foo
which depends on A::utils
I have a third project C
which has an executable which depends upon A::foo
, but (as far as I can tell) does not utilize B
at all.
When building C
I encounter errors stating that there are undefined references. With some further investigation I determined that when C
builds and A::foo
has to resolve utils
it finds B::utils
instead of A::utils
causing errors. I'm hoping to get some explanation as to why this is happening/how to fix it? It was my understanding that the namespaces (in addition to putting the libraries in subfolders so the files themselves do not conflict) would solve this issue of naming conflicts of libraries.
Below is an example of the install portion of one of the CMakeLists
set(PROJECT_NAME A)
set(component utils)
add_library(${component} SHARED
src/UtilsExample.cpp
)
add_library(${PROJECT_NAME}::${component} ALIAS ${component})
#... stuff with the libraries and whatnot
install(TARGETS ${component} EXPORT ${component}Targets
COMPONENT ${component}
LIBRARY DESTINATION lib/${PROJECT_NAME}
ARCHIVE DESTINATION lib/${PROJECT_NAME}
RUNTIME DESTINATION bin
)
install(EXPORT ${component}Targets
FILE "${PROJECT_NAME}-${component}Targets.cmake"
NAMESPACE ${PROJECT_NAME}::
DESTINATION lib/cmake/${PROJECT_NAME}
COMPONENT ${component}
)
To ensure that the library names are unique, do I need to prepend the project name or something like that? So the library would be named A_utils
? This seems like it would make the alias for external projects quite odd, A::A_utils
Solution
Linux dynamic library resolution is purely by the name of the needed library. All of the search paths are checked until a matching file name is found, so you can't have a duplicate .so filename.
However, it's really only the library filename that has to be unique. You can keep the CMake namespace names for all internal purposes, and just set the output filename to be A_utils:
set_target_properties(A::utils PROPERTIES LIBRARY_OUTPUT_NAME A_utils)
Continue to use A::utils
for target_link_libraries()
and similar throughout your project.
Answered By - Peter