[CMake] Static libraries depending on libraries: only on headers/options/defines
Hi all; I'm working on modernizing our large complex CMake environment. It builds a number of different binaries from an even larger number of static libraries, and these libraries depend on each other as well, in that they need to include headers and, sometimes, -D options etc. I've used straightforward target_link_libraries() to declare the relationship between these libraries; for example: add_library(foo STATIC ...) target_include_directories(foo PUBLIC ...) target_compile_definitions(foo PUBLIC ...) target_compile_options(foo PUBLIC ...) add_library(bar STATIC ...) target_link_libraries(bar PUBLIC foo) add_executable(one ...) target_link_libraries(one PRIVATE bar) This works, in that everything builds properly but it has a side-effect we want to avoid. Because the source tree is large many developers have a habit of testing compilation of subsets of the code using something like: make -jX bar and expect it to just build the static library bar. Because it's a static library you don't need to actually build "foo" until link time. But we do need all the include directories, compile definitions, and compile options to be inherited from "foo" into "bar". However with the above formulation, building "bar" also forces the compilation of "foo", which we don't need or want. I've played around with the different values of PUBLIC, PRIVATE, and INTERFACE but there doesn't seem to be a straightforward way to say, "take the interface values for includes, definitions, and options, but don't depend on the generated target". I can write a function to do this myself but this seems like the most common way someone would want to treat static libraries referencing other static libraries, so I wondered if I was missing something that would allow this in a simpler way. Thanks! -- Powered by www.kitware.com Please keep messages on-topic and check the CMake FAQ at: http://www.cmake.org/Wiki/CMake_FAQ Kitware offers various services to support the CMake community. For more information on each offering, please visit: CMake Support: http://cmake.org/cmake/help/support.html CMake Consulting: http://cmake.org/cmake/help/consulting.html CMake Training Courses: http://cmake.org/cmake/help/training.html Visit other Kitware open-source projects at http://www.kitware.com/opensource/opensource.html Follow this link to subscribe/unsubscribe: https://cmake.org/mailman/listinfo/cmake
Re: [CMake] Static libraries depending on libraries: only on headers/options/defines
Hi Paul, I understand the relationship between libraries as strict, such that you always build all dependent libraries before. In your use case I thought about splitting the libraries in the actual target and the interface one. For example, you could create an interface library foo_interface add_library(foo_interface INTERFACE ) set the properties and then link foo and bar to this interface library using target_link_libraries. But be aware, that now every executable, which links against bar must manually link against foo. If your project is large, this seems not really desirable. But I think you could also split the library bar in two bar_withoutFoo and bar. The library bar_withoutFoo would link against foo_interface and compile the sources, whereas bar is an interface library which depends on bar_withoutFoo and foo. The developer could than build bar completely independent from foo and you could transport the transitive dependencies to the executable. I don't know if this doubled structure using pure interfaces libraries and the actual libraries is maintainable. Hope that helps a bit, Andreas Am 16.02.19 um 20:20 schrieb Paul Smith: Hi all; I'm working on modernizing our large complex CMake environment. It builds a number of different binaries from an even larger number of static libraries, and these libraries depend on each other as well, in that they need to include headers and, sometimes, -D options etc. I've used straightforward target_link_libraries() to declare the relationship between these libraries; for example: add_library(foo STATIC ...) target_include_directories(foo PUBLIC ...) target_compile_definitions(foo PUBLIC ...) target_compile_options(foo PUBLIC ...) add_library(bar STATIC ...) target_link_libraries(bar PUBLIC foo) add_executable(one ...) target_link_libraries(one PRIVATE bar) This works, in that everything builds properly but it has a side-effect we want to avoid. Because the source tree is large many developers have a habit of testing compilation of subsets of the code using something like: make -jX bar and expect it to just build the static library bar. Because it's a static library you don't need to actually build "foo" until link time. But we do need all the include directories, compile definitions, and compile options to be inherited from "foo" into "bar". However with the above formulation, building "bar" also forces the compilation of "foo", which we don't need or want. I've played around with the different values of PUBLIC, PRIVATE, and INTERFACE but there doesn't seem to be a straightforward way to say, "take the interface values for includes, definitions, and options, but don't depend on the generated target". I can write a function to do this myself but this seems like the most common way someone would want to treat static libraries referencing other static libraries, so I wondered if I was missing something that would allow this in a simpler way. Thanks! -- Powered by www.kitware.com Please keep messages on-topic and check the CMake FAQ at: http://www.cmake.org/Wiki/CMake_FAQ Kitware offers various services to support the CMake community. For more information on each offering, please visit: CMake Support: http://cmake.org/cmake/help/support.html CMake Consulting: http://cmake.org/cmake/help/consulting.html CMake Training Courses: http://cmake.org/cmake/help/training.html Visit other Kitware open-source projects at http://www.kitware.com/opensource/opensource.html Follow this link to subscribe/unsubscribe: https://cmake.org/mailman/listinfo/cmake
Re: [CMake] Static libraries depending on libraries: only on headers/options/defines
I wrote this function. At first attempt it seems to do what I want but I've definitely not completed my work so I may well still find issues with it. Basically it does everything that target_link_libraries() does (at least, it tries to as best as I understand it other than a bunch of properties I don't know what they are and don't use) with one caveat: it adds libraries to INTERFACE_* but not LINK_LIBRARIES: function(static_link_libraries tgt mode) foreach(lib ${ARGN}) # Import all the source-level properties as normal foreach(t COMPILE_DEFINITIONS COMPILE_FEATURES COMPILE_OPTIONS INCLUDE_DIRECTORIES SOURCES SYSTEM_INCLUDE_DIRECTORIES) if(${mode} STREQUAL "PRIVATE" OR ${mode} STREQUAL "PUBLIC") set_property(TARGET ${tgt} APPEND PROPERTY ${t} $) endif() if(${mode} STREQUAL "PUBLIC" OR ${mode} STREQUAL "INTERFACE") set_property(TARGET ${tgt} APPEND PROPERTY INTERFACE_${t} $) endif() endforeach() # Import all the library-level properties as INTERFACE only foreach(t LINK_DEPENDS LINK_DIRECTORIES LINK_OPTIONS) set_property(TARGET ${tgt} APPEND PROPERTY INTERFACE_${t} $) endforeach() # Import the library itself as INTERFACE only set_property(TARGET ${tgt} APPEND PROPERTY INTERFACE_LINK_LIBRARIES ${lib}) endforeach() endfunction() On Sat, 2019-02-16 at 23:03 +0100, Andreas Naumann wrote: > Hi Paul, > > I understand the relationship between libraries as strict, such that you > always build all dependent libraries before. > In your use case I thought about splitting the libraries in the actual > target and the interface one. > For example, you could create an interface library foo_interface > add_library(foo_interface INTERFACE ) > set the properties and then link foo and bar to this interface library > using target_link_libraries. > > But be aware, that now every executable, which links against bar must > manually link against foo. If your project is large, this seems not > really desirable. But I think you could also split the library bar in > two bar_withoutFoo and bar. The library bar_withoutFoo would link > against foo_interface and compile the sources, whereas bar is an > interface library which depends on bar_withoutFoo and foo. > The developer could than build bar completely independent from foo and > you could transport the transitive dependencies to the executable. > > I don't know if this doubled structure using pure interfaces libraries > and the actual libraries is maintainable. > > Hope that helps a bit, > Andreas > > Am 16.02.19 um 20:20 schrieb Paul Smith: > > Hi all; > > > > I'm working on modernizing our large complex CMake environment. It > > builds a number of different binaries from an even larger number of > > static libraries, and these libraries depend on each other as well, in > > that they need to include headers and, sometimes, -D options etc. > > > > I've used straightforward target_link_libraries() to declare the > > relationship between these libraries; for example: > > > >add_library(foo STATIC ...) > >target_include_directories(foo PUBLIC ...) > >target_compile_definitions(foo PUBLIC ...) > >target_compile_options(foo PUBLIC ...) > > > >add_library(bar STATIC ...) > >target_link_libraries(bar PUBLIC foo) > > > >add_executable(one ...) > >target_link_libraries(one PRIVATE bar) > > > > This works, in that everything builds properly but it has a side-effect > > we want to avoid. Because the source tree is large many developers > > have a habit of testing compilation of subsets of the code using > > something like: > > > >make -jX bar > > > > and expect it to just build the static library bar. Because it's a > > static library you don't need to actually build "foo" until link time. > > But we do need all the include directories, compile definitions, and > > compile options to be inherited from "foo" into "bar". > > > > However with the above formulation, building "bar" also forces the > > compilation of "foo", which we don't need or want. > > > > I've played around with the different values of PUBLIC, PRIVATE, and > > INTERFACE but there doesn't seem to be a straightforward way to say, > > "take the interface values for includes, definitions, and options, but > > don't depend on the generated target". > > > > I can write a function to do this myself but this seems like the most > > common way someone would want to treat static libraries referencing > > other static libraries, so I wondered if I was missing something > > that would allow this in a simpler way. > > > > Thanks! -- Powered by www.kitware.com Please keep messages on-topic and check the CMake FAQ at: http://www.cmake.org/Wiki/CMake_FAQ Kitware offers various services to support the CMake community. For mo
Re: [CMake] Static libraries depending on libraries: only on headers/options/defines
FYI, this function appears to work for me with one caveat: there appears to be a bug where SYSTEM_INCLUDE_DIRECTORIES are not handled properly so you can't use this function if you need that property to be propagated. I filed https://gitlab.kitware.com/cmake/cmake/issues/18940 for that. I think I'll submit this as an enhancement request and see what the CMake devs think of it. It could be there are issues that I haven't thought of. On Sat, 2019-02-16 at 17:46 -0500, Paul Smith wrote: > I wrote this function. At first attempt it seems to do what I want but > I've definitely not completed my work so I may well still find issues > with it. > > Basically it does everything that target_link_libraries() does (at > least, it tries to as best as I understand it other than a bunch of > properties I don't know what they are and don't use) with one caveat: > it adds libraries to INTERFACE_* but not LINK_LIBRARIES: > > function(static_link_libraries tgt mode) > foreach(lib ${ARGN}) > # Import all the source-level properties as normal > foreach(t COMPILE_DEFINITIONS COMPILE_FEATURES COMPILE_OPTIONS > INCLUDE_DIRECTORIES SOURCES SYSTEM_INCLUDE_DIRECTORIES) > if(${mode} STREQUAL "PRIVATE" OR ${mode} STREQUAL "PUBLIC") > set_property(TARGET ${tgt} APPEND PROPERTY > ${t} $) > endif() > if(${mode} STREQUAL "PUBLIC" OR ${mode} STREQUAL "INTERFACE") > set_property(TARGET ${tgt} APPEND PROPERTY > INTERFACE_${t} $) > endif() > endforeach() > # Import all the library-level properties as INTERFACE only > foreach(t LINK_DEPENDS LINK_DIRECTORIES LINK_OPTIONS) > set_property(TARGET ${tgt} APPEND PROPERTY > INTERFACE_${t} $) > endforeach() > # Import the library itself as INTERFACE only > set_property(TARGET ${tgt} APPEND PROPERTY > INTERFACE_LINK_LIBRARIES ${lib}) > endforeach() > endfunction() > > > > On Sat, 2019-02-16 at 23:03 +0100, Andreas Naumann wrote: > > Hi Paul, > > > > I understand the relationship between libraries as strict, such that you > > always build all dependent libraries before. > > In your use case I thought about splitting the libraries in the actual > > target and the interface one. > > For example, you could create an interface library foo_interface > > add_library(foo_interface INTERFACE ) > > set the properties and then link foo and bar to this interface library > > using target_link_libraries. > > > > But be aware, that now every executable, which links against bar must > > manually link against foo. If your project is large, this seems not > > really desirable. But I think you could also split the library bar in > > two bar_withoutFoo and bar. The library bar_withoutFoo would link > > against foo_interface and compile the sources, whereas bar is an > > interface library which depends on bar_withoutFoo and foo. > > The developer could than build bar completely independent from foo and > > you could transport the transitive dependencies to the executable. > > > > I don't know if this doubled structure using pure interfaces libraries > > and the actual libraries is maintainable. > > > > Hope that helps a bit, > > Andreas > > > > Am 16.02.19 um 20:20 schrieb Paul Smith: > > > Hi all; > > > > > > I'm working on modernizing our large complex CMake environment. It > > > builds a number of different binaries from an even larger number of > > > static libraries, and these libraries depend on each other as well, in > > > that they need to include headers and, sometimes, -D options etc. > > > > > > I've used straightforward target_link_libraries() to declare the > > > relationship between these libraries; for example: > > > > > >add_library(foo STATIC ...) > > >target_include_directories(foo PUBLIC ...) > > >target_compile_definitions(foo PUBLIC ...) > > >target_compile_options(foo PUBLIC ...) > > > > > >add_library(bar STATIC ...) > > >target_link_libraries(bar PUBLIC foo) > > > > > >add_executable(one ...) > > >target_link_libraries(one PRIVATE bar) > > > > > > This works, in that everything builds properly but it has a side-effect > > > we want to avoid. Because the source tree is large many developers > > > have a habit of testing compilation of subsets of the code using > > > something like: > > > > > >make -jX bar > > > > > > and expect it to just build the static library bar. Because it's a > > > static library you don't need to actually build "foo" until link time. > > > But we do need all the include directories, compile definitions, and > > > compile options to be inherited from "foo" into "bar". > > > > > > However with the above formulation, building "bar" also forces the > > > compilation of "foo", which we don't need or want. > > > > > > I've played around with the different values