On Wed, 2017-06-21 at 13:54 +0200, Thomas Heller via Boost wrote:
On 06/21/2017 12:58 PM, Peter Dimov via Boost wrote:
Thomas Heller wrote:
People who prefer declarative builds can stick to Boost.Build.
That's missing the point. Declarative build descriptions are preferable in any build system, and any serious use of one leads inevitably to this same conclusion. Witness, for instance, how Meson intentionally makes its language not Python, even though it's very much Python-looking, and how Bazel also has its own language. This is because if the language is Python, people are encouraged to program in it, instead of declaring targets.
Target declarations compose, logic that manipulates global environment doesn't.
I totally get that a declarative build system is superior.
This is what I was originally trying to do with BCM: bcm_boost_package(core VERSION 1.61.0 DEPENDS assert config ) This is quite simple and declarative, but then boost is not creating another build-like system that people are not familiar with. So I think we should try to use as much vanilla cmake as possible, but I do think using some custom function can help enumerating the dependencies in other contexts.
The quote was taken out of context (or I didn't express my intent clearly). The thing is that we already have a declarative build system (Boost.Build). People want to interface with CMake though (which is only very slowly catching up with the declarative stuff), and I assume that most CMake scripts out in the wild are *not* in the declarative paradigm, and it takes to get accustomed to it. Yet, there are a lot of people complaining that Boost is "asocial" because it doesn't interface well with the predominant build plan generator out there. Since CMake is moving more and more towards being declarative, the gap seems to close and we could build a bridge. Or just advertise Boost.Build more prominently so it isn't seen as the odd one in the block, but the goto solution.
Now it's true that the declarative approach is sometimes less convenient. Imperatively, you just check whether zlib is installed, #define or not HAVE_ZLIB and build different things based on that. Whereas the alternative is to have a separate zlib-support library target, which injects a .cpp file into the main program via usage-requirements, which registers the zlib support with the main library. But, the upside is that if everyone writes their build descriptions properly, you just link to the appropriate targets in the root build file and everything "just works".
FWIW, this is totally doable within CMake. Consider this:
# I guess this if statement has to persist, if someone knows a way # around it, please fix. Could be placed in another Setup.cmake or so to # seperate the build logic from this logic. if (PUMPKIN_WITH_ZLIB) # This sets ZLIB_FOUND to TRUE if found and exports and gives you the # ZLIB::ZLIB target. find_package(ZLIB) else() # Workaround to have the target available even when zlib was not # requested... add_library(ZLIB::ZLIB INTERFACE IMPORTED) endif()
# Sets up the zlib dependent target... add_library(pumpkin_zlib EXCLUDE_FROM_ALL ${PUMPKIN_ZLIB_SOURCES}) target_compile_definitions(pumpkin_zlib PUMPKIN_HAVE_ZLIB) target_link_libraries(pumpkin_zlib ZLIB::ZLIB)
# setup the main target. add_library(pumpkin ${PUMPKIN_SOURCES}) target_link_libraries(pumpkin PRIVATE $<$BOOL:${PUMPKIN_WITH_ZLIB}:pumpkin_zlib>)
And yes, the syntax is horrible ;)
The syntax is horrible. It really should just be: if(PUMPKIN_WITH_ZLIB) target_link_libraries(pumpkin pumpkin_zlib) endif() More people will understand the above than the generator expressions.
The generator expressions are the way to achieve proper declarative build logic, I presume.
The generator expressions are there to handle logic that can't be decided during configuration.