Swift: Decide what should be required for declaring/using modules that re-export other modules
A classic example is swift-collections. It contains three modules:
DequeModule
OrderedCollections
-
Collections
, which re-exports the other two
The re-exporting means that if you import Collections
in Swift you can use the public parts of the other two modules without explicitly importing them.
Currently that project is set up to co-locate all the module files it generates, which works fine… unless you happen to have your own DequeModule
and want to import Apple's OrderedCollections
, in which case you might get Apple's DequeModule
instead depending on how the -I
options line up.
There are two questions: how do you publish a module like Collections
and how do you consume it?
Consume
This is the easy one. What's required for each case?
-
import Collections
: Seems obvious thatCollections
should be in thetarget_link_libraries
, and that it shouldn't be necessary to listDequeModule
orOrderedCollections
explicitly. -
import DequeModule
: Clearly puttingDequeModule
intarget_link_libraries
should be sufficient, but I think it should work to listCollections
instead.
Publish
Currently Collections
dependencies are declared thus:
target_link_libraries(Collections PRIVATE
DequeModule
OrderedCollections)
And if we stop co-locating the modules, you can import DequeModule
or OrderedCollections
as long as you list them explicitly in target_link_libraries
, but if you only list Collections
the import will fail. That's maybe expected given PRIVATE
, but maybe that should be
target_link_libraries(Collections PUBLIC
DequeModule
OrderedCollections)
or even
target_link_libraries(Collections
DequeModule
OrderedCollections)
Neither of those options currently makes it work for a client to list Collections
in its target_link_libraries
and import DequeModule
, but we can change CMake to make it work if that's what we think should happen.
If I add the following, which (I think correctly?) makes the module directories of the re-exported modules transitively available to clients of Collections
, that usage does work. But I don't think anything like this should be required of the publisher of a re-exporting Swift module.
# Makes <exported> importable by any target listing <exporter> in its
# target_link_libraries.
function(swift_module_re_exports exporter exported)
set(swift_module_directory "$<TARGET_PROPERTY:${exported},Swift_MODULE_DIRECTORY>")
set(binary_directory "$<TARGET_PROPERTY:${exported},BINARY_DIR>")
set_property(TARGET ${exporter}
APPEND
PROPERTY INTERFACE_INCLUDE_DIRECTORIES
"$<IF:$<STREQUAL:${swift_module_directory},>,${binary_directory},${swift_module_directory}>")
endfunction()
swift_module_re_exports(Collections DequeModule)
swift_module_re_exports(Collections OrderedCollections)