From: David Abrahams (gclbb-jamboost_at_[hidden])
Date: 2003-07-21 15:40:16
Ali has been having trouble posting for some reason; he asked me to
send this on for him.
--- Since I last left you all, I've been progressing a bit on extending my own make-based build system to Mac OSX and have had to confront this conditional requirements issue again in my own context, with some new insight resulting. I have come to believe that the problem here is that BBv2 "properties" are used for representing both "configuration aspects" and "tool aspects"...inescapably confusing. The former represent aspects that the user can request, the latter represent final aspects associated with a specific tool, used to generate a command. I agree with Volodya that some distinction must be made for properties that can be used as conditions, but I don't know that distinguishing simply based on attributes such as "free" or "incidental" is the right delineation...I think the right distinction is between properties of "configuration aspects" and "tool aspects". Let me explain in terms of my working design. In my system, there are a number of "configuration aspects", some of them global, like <os> and <os_version>, whose values are determined globally. Then, based on the target-type (e.g. "c++lib"), one or more "tools" get pre-loaded (e.g. "tools/c++", which in turn loads extensions "tools/c++/gcc", "tools/c++/msvc" etc). Each "tool" may introduce a number of additional "configuration aspects" (e.g. <c++_compiler>, <c++_version_major>, <c++_version_minor>, <c++_variant>, <c++_libtype>), which are all like BBv2 "non-free" features, i.e. they all have possible values based on available compilers etc. Each "tool" also introduces a number of "tool aspects" or "tool variables" associated with it (e.g. CXX, CC, CPPFLAGS, LDLIBS, etc). (Note that I have no BBv2 notion of "toolset normalization"...I have personally found no great use for that abstractopm...I map directly from "configuration aspects" to "tool variables"...but for generality, and relation to BBv2, we can consider "tool aspects" rather than concrete "tool variables".) In this design, each "tool aspect" acquires its final value by conditioning itself off of the values of "configuration aspects". Values of "tool aspects" cannot be used as conditions. This clarifies the build system processing...first you figure out the values of the "configuration aspects", then you compute the final values of "tool aspects" from those. So, how does this stand up to our test cases? Consider: exe a : a.cpp : <variant>debug:<optimization>speed <optimization>off:<define>USE_SLOW_BUT_TESTED_ALGORITHM ; In my system, <variant> would be a configuration aspect, but <optimization> and <define> would be "tool aspects". Granted, this is somewhat of a judgement call...why is <optimization> not part of the "configuration"? In my view, because it is too fine-grained a property of the "tool" for users to be messing around with. Instead, the developer should be able easily to define new "variants" to solve this problem. The developer would introduce (in the Makefile/Jamfile) a new "variant" called "debug_slow" resulting in a "requirements" expression <variant>debug:<optimization>speed <variant>debug_slow:<optimization>off,<define>USE_SLOW The key is making it easy to define new variants. It's really easy to imagine other cases. For example, on platforms X,Y, and Z use toolset A and on toolset A define FOOBAR Looks reasonable, though I'm not sure extra implementation complexity is justified. This is actually a very common case, which is solved in my system by layering the various sources of "configuration aspects". In my system, there are three abstract types of extensions to the build system that are naturally layered ---"os", "tool", and "module-type" --- each of which can contribute "configuration aspects". (N.B. "module-type" can be thought of as "target-type" in BBv2...in my system each Makefile has a single "target-type" associated with it...this is not fundamental...conceptually it could support multiple target types in a "module" or "project".) All "os" extensions (e.g. "linux", "cygwin", "darwin", etc) are loaded first. Then "module-type" extensions (e.g. "c++lib", "c++exe", "distribution", etc) are loaded, each of which pre-loads various tools (e.g. "tools/c++", "tools/java", "tools/extract", "tools/patch" etc). Thus, concept "module-type" is layered on top of concept "tool", which is layered on top of concept "OS". Thus it is natural that any "configuration aspects" associated with a tool can depend upon "configuration aspects" associated with OS. So I can express things like <os>linux:<c++_compiler>gcc,<c++_version>2 <os>cygwin:<c++_compiler>msvc,<c++_version>7 <os>darwin:<c++_compiler>gcc,<c++_version>3 <c++_compiler>gcc,<c++_version>3:<define>FOOBAR but, of course, not the other way around like <compiler>gcc:<os>linux (which doesn't make sense anyway...it doesn't make sense because it is a quite natural layering to have tools on top of os). In summary, I hope that I've expressed some insight into the problem by virtue of analyzing an existing working design and how it might address the test cases. The two critical design issues for me were to separate "configuration aspects" from "tool aspects" and to treat "configuration aspects" as layered. Both the separation and the layering directly reflect the design and function of the build system, in which OS extensions are loaded first, then Tool extensions; in which "configuration aspects" are computed first, then "tool aspects". I have a lot to say about this from a design standpoint, so I'll just stop here and see what you think. -Ali -- Dave Abrahams Boost Consulting www.boost-consulting.com
Boost-Build list run by bdawes at acm.org, david.abrahams at rcn.com, gregod at cs.rpi.edu, cpdaniel at pacbell.net, john at johnmaddock.co.uk