Stephen Kelly wrote: > * Port cmGeneratorExpression API to cmTarget > * Add a way to determine at runtime whether linking-related information is > being requested at configure-time or generate-time. A property on the > Makefile might work. > * Add a const char *config where appropriate to cmTarget API to pass to > the generator expressions. > * Return to the depends issue and everything else. >
I've done parts of everything in the wip-target-interface branch in my clone. I'll want to get everything working with the relevant INTERFACE target properties and the new INTERFACE_LIBRARY type before submitting any of it, to make sure that we can get it all into one release with confidence. Using the branch, I'm able to use Qt5Widgets just by using it with target_link_libraries without specifying the include directories, compile definitions, -fPIC flag or Qt5::WinMain in my CMakeLists.txt. Even if the implementation changes, this will remain my goal: https://codereview.qt-project.org/#patch,all_unified,38876,2 1) Policy The include directories and compile definitions are set by the target_link_libraries command. It might make sense to add a policy for that feature, as otherwise the order of include directories would change, eg: add_executable(foo ...) target_link_libraries(foo bar bat) include_directories(${bat_INCLUDE_DIRS} ${bar_INCLUDE_DIRS}) 2) Transitivity The topic branch also introduces the use of generator-expression-based transitive behavior for the include directories and compile definitions. For linking, the transitive behavior is not based on generator expressions, but relies on the existing cmComputeLinkDepends. The link order and the include order should not necessarily be the same, so I think it's ok for the includes and libraries to be processed in a different way. The transitive includes still need to be specified as I described before. I would like target_link_libraries to be the 'universal' use function. Unfortunately at the moment it is not possible to use it with an imported target, so in Qt I couldn't do this: target_link_libraries(Qt5::Gui LINK_INTERFACE_LIBRARIES Qt5::WinMain) but I had to use set_property instead. This doesn't matter in the above case in Qt as Qt5::WinMain has no public includes or compile definition requirements. For another library in a similar situation though, there might be a need to add include directories or compile definitions. Currently that requires multiple set_property calls, which is not convenient, makes tll() non-universal (We can't document 'always just use it'), and the user might not call set_property as many times as they should (ie, currently for both include directories and compile definitions, but that might be expanded in the future, which could be encapsulated in tll()). I propose that target_link_libraries(foo LINK_INTERFACE_LIBRARIES bar) should be allowed for an imported foo, but target_link_libraries(foo bar) remains not-allowed. As I introduced the INTERFACE_LINK_LIBRARIES property, I also introduced a backward-compatibility feature to also read the old IMPORTED*_<CONFIG> properties. I don't know enough about cmComputeLinkDepends to know if that's ok. 3) INTERFACE_LIBRARY depends Also on the subject of link depends, the INTERFACE library type might have a funny behavior. I asked before for more information about why direct depends are separated from transitive ones. The reason seems to be related to ordering of the depends when invoking the linker, which is relevant for static libraries (but not shared libraries, right?). So, say I have this: add_library(iface INTERFACE) set_property(TARGET iface PROPERTY INTERFACE_LINK_LIBRARIES foo bar) add_executable(test_exe ...) And I do this: target_link_libraries(test_exe directdep1 iface directdep2) It is not really equivalent to this: target_link_libraries(test_exe directdep1 foo bar directdep2) But maybe it should be, or maybe I would want it to be? Maybe we can make it possible to populate the non-INTERFACE LINK_LIBRARIES property on libraries of type INTERFACE_LIBRARY to use the contents as direct depends of test_exe? 4) GenEx context and memoization Finally in my topic, I created a patch to remove a lot of memoization in cmake and pass a contextual target from cmComputeLinkDepends. This is necessary because the generator expression transitive feature are not used for linking. I need it so that I can target_link_libraries(Qt5::Gui LINK_INTERFACE_LIBRARIES $<$<TARGET_PROPERTY:WIN32_EXECUTABLE>:Qt5::WinMain> ) such that the $<TARGET_PROPERTY:WIN32_EXECUTABLE> is evaluated in the context of the caller, not in the context of Qt5::Gui. I'm thinking of simply removing the memoization from cmTarget. The mappings need to be cleared multiple times during configure-time, and now they will depend not only on the config (which most of the memoizations use as the key), but also the target, which would make the memoization more complex to achieve, and/or make the code more complex to forego memoization when it is really not wanted. Any thoughts on that? 5) Boost as a use-case and cicular depends Finally, I've been looking a little bit at boost. They are in the process of modularizing and assessing CMake, and they're interested in these features too (they're a good fit), and they linked to a previous thread on the subject of usage requirements too on their wiki page https://svn.boost.org/trac/boost/wiki/CMakeModularizationStatus I am not very familiar with boost, but I started looking into it a few days ago as a way to feature-proove this work that I'm doing. Because many boost libraries are header-only, my idea was that boost could generate config and target files with content such as (pseudo dependencies): add_library(boost::core INTERFACE IMPORTED) set_property(TARGET boost::core INTERFACE_INCLUDE_DIRECTORIES ${CMAKE_INSTALL_PREFIX}/boost/core # Or whatever ) add_library(boost::bind INTERFACE IMPORTED) set_property(TARGET boost::bind INTERFACE_INCLUDE_DIRECTORIES ${CMAKE_INSTALL_PREFIX}/boost/bind $<TARGET_PROPERTY:boost::core,INTERFACE_INCLUDE_DIRECTORIES> ) (Or: target_link_libraries(boost::bind INTERFACE boost::core) ) add_library(boost::msm INTERFACE IMPORTED) set_property(TARGET boost::msm INTERFACE_INCLUDE_DIRECTORIES ${CMAKE_INSTALL_PREFIX}/boost/msm $<TARGET_PROPERTY:boost::bind,INTERFACE_INCLUDE_DIRECTORIES> ) So that it is fully aware of all of its [transitive] dependencies (and any includes and compile defintions requirements) and I would use it like this: add_executable(foo_exe ...) target_link_libraries(foo_exe boost::mpl) The problem is that boost dependencies are circular. I didn't look into it much, but at least boost::config depends on boost::core, and boost::core depends on boost::config, boost::integer, etc. One way to solve that would be to do something like this to make it non- circular by using more internal-implementation-detail INTERFACE libraries: # Not documented. Note that they do not know their dependencies. add_library(boost::private::core_iface INTERFACE IMPORTED) set_property(TARGET boost::private::core_iface INTERFACE_INCLUDE_DIRECTORIES ${CMAKE_INSTALL_PREFIX}/boost/core # Or whatever ) add_library(boost::private::config_iface INTERFACE IMPORTED) set_property(TARGET boost::private::config_iface INTERFACE_INCLUDE_DIRECTORIES ${CMAKE_INSTALL_PREFIX}/boost/config ) add_library(boost::private::integer_iface INTERFACE IMPORTED) set_property(TARGET boost::private::integer_iface INTERFACE_INCLUDE_DIRECTORIES ${CMAKE_INSTALL_PREFIX}/boost/integer ) # Documented. Depends on the iface targets to break the circular dependence add_library(boost::core INTERFACE IMPORTED) set_property(TARGET boost::core INTERFACE_INCLUDE_DIRECTORIES $<TARGET_PROPERTY:boost::private::config_iface,INTERFACE_INCLUDE_DIRECTORIES> $<TARGET_PROPERTY:boost::private::integer_iface,INTERFACE_INCLUDE_DIRECTORIES> ) add_library(boost::config INTERFACE IMPORTED) set_property(TARGET boost::config INTERFACE_INCLUDE_DIRECTORIES $<TARGET_PROPERTY:boost::private::core_iface,INTERFACE_INCLUDE_DIRECTORIES> ) I don't know if boost::core and boost::config really are public API, but lets assume that they are for the purpose of the discussion, as a comparable situation will arise with other boost libraries anyway. I'm not sure if there's any good alternative to the _iface targets for cycle-avoidance, but if it's good enough, and can be implemented, I'd say it would be feature-prooven. Thanks, Steve. -- Powered by www.kitware.com Visit other Kitware open-source projects at http://www.kitware.com/opensource/opensource.html Please keep messages on-topic and check the CMake FAQ at: http://www.cmake.org/Wiki/CMake_FAQ Follow this link to subscribe/unsubscribe: http://public.kitware.com/cgi-bin/mailman/listinfo/cmake-developers