
I almost agree. When it comes to build system it is oftentimes better to be more verbose and less elegant, because it is easier for the user to maintain the build system code. And also, being less abstract, more low-level is often desirable, as users do want to control various platform-specific details of the build process. But there are also time they are not! So I guess, there should be some sound abstraction level. Also, I need to notice, being meta-build system has its disatvantages: 1. Requires extra step. This matters, because you need to remember arguments tools, manage files, env. vars etc. 2. The meta-build system could not do more than a build system. See, you can add fancy pre- and post- build rules to visual studio, but the logic of how this rules are invoked are determined by the build system, not the meta-build one. 3. Synchronization between the two might be annoying, for example, regenerating Visual Studio solution, while it is opened in IDE; understanding build system files are temporaries and should not be checked in the source control and so on. On the other hand, as somebody mentioned, good IDE should be interoperable w/ any reasonable build-system, however, in practice this is oftentimes not the case, so meta-build comes handy. On Sat, May 12, 2012 at 6:56 AM, Dave Abrahams <dave@boostpro.com> wrote:
on Thu May 10 2012, Beren Minor <beren.minor+boost-AT-gmail.com> wrote:
Hi,
My 2 cents regarding build systems as I've recently had to write a build framework using CMake and as I use Boost.Build for personal projects.
I think Boost.Build and CMake are at a totally different level of abstraction: CMake is low-level when Boost.Build is high-level. For comparison with other build systems, Make, SCons are at the same level as CMake. Premake is probably closer to Boost.Build (I don't know enough others but there's not a lot being as high-level as BBv2).
One of the problems people have with Boost.Build is that its high-level abstractions make it hard to control. There's so much going on between the code you write in your Jamfile and the actual command-lines that come out the other end, that it can be hard to know how to get the effect you want. If you need to do something specific for a given platform or compiler, you can't use a simple if/then statement based on some variable; you have to use a creatively-defined declarative language, and hope that the Boost.Build engine makes the choices you intend. I was a major participant in the design of that language, and in principle I think a declarative approach is ideal, but I now accept that the language we have doesn't match up well with the way that most users of the build system think, and that the high level of abstraction is not a net win.
Parts of Boost.Build are an elegant design, no doubt. When Troy and Doug started talking up CMake to me, I kept pushing them to implement more of the abstractions in Boost.Build. But I've come to see that many of them aren't needed. Boost is a pretty good test case for complexity, and the CMake files for building boost portably (https://github.com/ryppl/boost-zero/tree/master/cmake) are not especially more complicated than its Jamfiles. But there's an order of magnitude more code in Boost.Build than there is in Ryppl's CMake support (https://github.com/ryppl/ryppl/tree/develop/cmake/Modules).
Of course SCons and CMake still have a major advantage over Make because of their portability. But they offer a very little abstraction over simple Make. Surely, there are some built-in rules to easily create shared/static libraries or executables, but you still have to define a lot of things manually. As an example, I quickly realized that CMake is simply unable to create both shared and static version of a library if you don't explicitly write the two rules to build them.
You mean, in a single build run?
This is exactly the sort of situation where I think the abstraction capabilities you're wishing for are a net loss. It's not that much better to write
lib foo : a.cpp b.cpp : : <link>static <link>shared ;
(or is it <link>static/shared? I forget. And that's part of the problem)
than it is to write
set(sources a.cpp b.cpp) add_library(foo STATIC ${sources}) add_library(foo SHARED ${sources})
and the latter one matches up really well with what users understand. Furthermore, anyone who wants to build a library both ways with less boilerplate can write a simple function that does it.
For comparison, with Boost.Build, creating a library is as simple as writing: lib foo : bar.c ;
Then, depending in which context the library is used, BBv2 will create shared or static or both versions of the library. You don't have to care about the details, you'll have automatic resolution of what is required to satisfy the build request, based on the build condition you asked for.
...until it surprises you, as in https://trac.lvk.cs.msu.su/boost.build/wiki/AlternativeSelection Sometimes it's better to be a little more verbose and a little less automatic.
The abstraction level of Boost.Build is also very visible when you start working on multiple compiler and/or multiple build variants. As long as you don't need fancy compiler flags (and I think most projects shouldn't play with fancy compiler flags) you can trust Boost.Build to abstract all the details of the compiler flags and to offer you the possibility to build everything you want, at once.
With CMake and others, as comparison, you are only able to build one variant at a time, and by default everything will be build in conflicting way between build variants (build once in release mode and once in debug mode, and you'll overwrite the previous build output).
Meh; you just use different build directories. This is another one of those advantages of Boost.Build that cost more than they deliver, IMO. It means that every Boost.Build target is actually a meta-target representing one or more real targets, which complexity makes the whole system harder to understand and control... and, especially, harder to extend.
As said, you can use different build folders for different variants, but that's much less easy to use and not very maintainable unless you maintain a wrapper around the build system that does this for you.
The advantage of maintaining a thin wrapper over the build system, if you need this kind of thing regularly, is that it's easy to get in underneath this layer and work with the build system directly: to experiment, extend, whatever. And at that level, you're just dealing with a single target and build variant. In the case of Boost.Build, there's no way to separate anything from the possibility of multiple variants, compilers, etc. In the end, most users of the build system don't need to do multiple builds at once anyway, so they never see the wrapper and never even have to deal with that incremental increase in complexity.
I like very much Boost.Build, and I was quite disappointed to hear that there's a plan to move Boost to CMake. Boost is the main user of Boost.Build and I'm a little bit afraid of seeing it disappear, or being less and less unsupported. Even if I perfectly understand the reason of this change: Boost.Build suffers from lack of documentation and lack of popularity, whereas CMake is very well documented and widely used, it leaves me a bitter taste in mouth.
I don't know that the change will happen, but I hope very much that it will. I'm sorry for the bitter taste and for the hurt feelings of those who have invested so much in Boost.Build. However, my priority has to be on what's best for Boost's mission as a vehicle for C++ libraries.
From a personal point of view, Boost.Build (even if not perfect as it is) does what a build system should do: abstract the user all the detail on how the objects will be built and let him only care about the high-level objects and their relations.
The problem with that approach is that when something breaks, you usually end up working backwards from the actual command-lines you need the system to issue, and if the connection between the build description files and those command-lines is too distant, it can be hard to make the leap.
CMake and others are "old-generation" build systems, which may be used as building blocks to achieve this goal.
I think you're not giving CMake enough credit. It has been evolving quite quickly over the past few years. Its programming language may be old and crusty, but it's expressive enough to get the job done. Most importantly, it hits a "sweet spot" between abstract and direct that makes it practical and accessible.
-- Dave Abrahams BoostPro Computing http://www.boostpro.com
_______________________________________________ Unsubscribe & other changes: http://lists.boost.org/mailman/listinfo.cgi/boost
-- Daniel Krikun