TriBITS
TriBITS copied to clipboard
TRIBITS_ADD_EXECUTABLE(): Allow for manual lib link specification for libs inside of SE package
This story is to upgrade the TriBITS handling of library and include directories inside of an SE package to allow manual linking of libraries and include directories for libraries and executables (not between SE packages). The current system has different behavior for linking in libraries in TRIBITS_ADD_LIBRARY() and TRIBITS_ADD_EXECUTABLE() which confuses many people. The current system was designed for the most common use case where an SE package has just one main library but many test executables. For this very common use case, the current TriBITS setup eliminates a lot of duplication.
The current behavior which as been the case for man many years (since the birth of TriBITS in Trilinos before it was called TriBITS) is that you need to manually define the linkage between multiple libraries inside of an SE package by passing them in through DEPLIBS in TRIBITS_ADD_LIBRARY(). However, when you define an executable, all of the libraries defined in the current SE package always get linked in, regardless of what was passed in through the DEPLIBS argument to TRIBITS_ADD_EXECUTABLE(). Before I deprecated DEPLIBS argument to TRIBITS_ADD_EXECUTABLE() and replaced it with TESTONLYLIBS and IMPORTEDLIBS (see #24), the DEPLIBS argument was only supposed to be used to pass in extra TESTONLY libs. However, it was always the case that every executable that got created in an SE package always linked to all of the non-TESTONLY libraries listed in that SE package's ${PACKAGE_NAME}_LIBRARIES variable. You can see that, for example, in lines 397-402:
# Second, add the package's own regular libraries
IF(NOT ${PROJECT_NAME}_ENABLE_INSTALLATION_TESTING)
APPEND_SET(LINK_LIBS ${${PACKAGE_NAME}_LIBRARIES})
ELSE()
APPEND_SET(LINK_LIBS ${${PACKAGE_NAME}_INSTALLATION_LIBRARIES})
ENDIF()
of TribitsAddExectuble.cmake from commit 3b15e81 before I introduced TESTONLYLIBS and IMPORTEDLIBS and deprecated DEPLIBS.
The goal of this story is to reintroduce the DEPLIBS argument to TRIBITS_ADD_EXECUTABLE() so then when it is passed in, then no longer will ${PACKAGE_NAME}_LIBRARIES be linked in but instead only libraries specified in DEPLIBS will be linked in.
Therefore, the game plan to implement this behavior is:
- Remove all current usage of
DEPLIBSinTRIBITS_ADD_EXECUTABLE()in all TriBITS packages. - Remove
DEPLIBSaltogether fromTRIBITS_ADD_EXECUTABLE()so that no CMakeLists.txt code can depend on it. - Leave enough time for everyone to upgrade TriBITS to and remove
DEPLIBSfrom their calls toTRIBITS_ADD_EXECUTABLE(). - Reintroduce
DEPLIBStoTRIBITS_ADD_EXECUTABLE()and in this case don't link in${PACKAGE_NAME}_LIBRARIESwhen provided.
After this, SE package developers will be able to use the new DEPLIBS argument to define executables and control which of the libraries in their SE packages to link in consistent with TRIBITS_ADD_LIBRARY(). This will allow the developers to specify manual linkage within an SE package for libs and execs just like with a regular cmake project. However, automatic linkage to libs in upstream SE packages and TPL will always automatically be enforced for simplicity and correctness.
It was suggested that it would be desirable for TRIBITS_ADD_LIBRARY() and TRIBITS_ADD_EXECUTABLE() to have to list libraries to upstream SE packages and TPLs to make things more explicit. But if an SE package has a dependency on another SE package or TPL declared in its Dependencies.cmake file, is it not clear that the libraries in the current SE package will depend on these? If that was not the case, why were those listed as dependencies?
The only argument I can see for encouraging (or even allowing) manually listing libs from upstream SE packages and TPLs is to allow the definition of multiple peer libraries and executables in an SE package without depending on all of the enabled upstream SE packages and TPLs such that it would provide some advantage to not just linking against all of them.
So what is the harm in listing extra libraries even if you don't need them when you link an executable? We can consider static and shared libs independently.
For every linker I have seen, it will only pull in object code from a static library if those symbols are needed in the executable. So the only harm I can see in listing extra libraries is that it might slow down the linker some having to look through static libs that have no symbols.
As for shared libraries, the only downside to listing extra shared libraries is that you have to install them if you install the executables. See:
http://stackoverflow.com/questions/4639360/unnecessary-linked-libraries-in-linker
Therefore, I don't see a need to clutter up the CMakeLists.txt files to manually link to libraries in upstream SE packages and doing so weakens the checking that the TriBITS system can do. I will write this up in a new section in the TribitsDevelopersGuide.rst document that provides the full argument.