Boost logo

Boost-Build :

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