This discussion will eventually lead to the realisation that a cross-platform builder tool requires separate concepts for (amongst others): * source files * libraries (dynamic and static) * dependencies * executables built for the target system * executables built for the build host (i.e. intermediate build tools) * scopes * -D macro definitions * abstractions of compiler options * abstractions of build host fundamental operations (environment variables, file existence, file copying, file locks, spawning subprocesses etc) … and so on. To short-circuit the discussion I can offer the following observations: * bjam, clever as it is, is basically a form of makefile. It will never be a build tool It’s therefore not useful to anyone but boost maintainers or single-target projects. * makefiles are great for creating dependency graphs. They are suitable for the output or intermediate stages of a build tool. You build a makefile hierarchy from the build tool abstractions given a target toolset and options. We already have Scons and CMake, which are both awful in their own way. I really think that effort would be better spent retro fitting python (or javascript, or [insert well maintained scripting language here]) into cmake so that cmake becomes beautiful. Either that, or recreate cmake in python (or javascript), but cleanly, using the combined knowledge of several years of evolution. Why the cmake team chose to build their own godawful scripting language is a mystery to me. I suspect someone just wanted to write a DSL one day and it all got way out of hand (original poster, please take note!) R
On 30 Nov 2017, at 11:51, Hans Dembinski via Boost
wrote: On 29. Nov 2017, at 14:31, Stefan Seefeld
wrote: On 29.11.2017 07:59, Hans Dembinski wrote:
from faber.artefacts.binary import binary
greet = module('greet')
hello = binary('hello', ['hello.cpp', greet.greet])
rule(action('test', '$(>)'), 'test', hello, attrs=notfile|always)
default = hello
(from https://github.com/stefanseefeld/faber/blob/develop/examples/modular/fabscri... https://github.com/stefanseefeld/faber/blob/develop/examples/modular/fabscri...), which uses higher-level artefacts (`binary`, `library`) and doesn't require the user to define his own actions to build.
This example remains cryptic.
from faber.artefacts...: artefacts? The term "artefact" is very general and non-descriptive. The first definition provided by Google is essentially "human-made thing".
Right, it's what "faber" generates (using the same stem even).
:) Fair enough, but it is still not very descriptive. Why use an uncommon latin word if you could use a common word from day-to-day language? The purpose of language is to transmit information, so it is usually a good idea to use common words that leave no room for ambiguity.
Ironically, the other meaning of "artefact" is "any error in the *perception or representation of any information*, introduced by the involved equipment or technique(s)" [Wikipedia]
Then, I have to type many redundant things here. Note, the many occurrences of greet in these two lines
greet = module('greet') hello = binary('hello', ['hello.cpp', greet.greet])
It seems like hello is a binary which depends on 'hello.cpp' and the module greet. Why the latter?
"hello" is a binary built from a "hello.cpp" source file and a "greet" library provided from another ("greet") module (thus using Pythonic syntax, we refer to the latter as "greet.greet"). If the library would have been built by the same module, the above would simply be
greet = library('greet', 'greet.cpp') hello = binary('hello', ['hello.cpp', greet])
as is in fact done in this example: https://github.com/stefanseefeld/faber/blob/develop/examples/implicit_rules/... https://github.com/stefanseefeld/faber/blob/develop/examples/implicit_rules/...
I think source code is allowed to be verbose, but it should not be redundant, especially if said redundancy could lead to mistakes. I suppose you run the fabscript through a special interpreter, not just the standard Python interpreter. If so, then you can use this shorthand syntax instead:
greet = library('greet.cpp')
That way, one cannot make a mistake like this
greet = library('great', 'greet.cpp')
To make the syntax very consistent (the Zen of Python says: "There should be one - preferably only one - obvious way to do it."), you could define all build items like library and binary in this way:
def binary(*inputs, attribute1=default1, attribute2=default2, …): ...
All positional arguments would always be inputs of any kind, like a source file or a library. If you always use positional arguments consistently like this, then my complaint about ambiguity is gone, because there is a clear rule which is easy to remember.
Attributes would be passed consistently via keywords. They have reasonable defaults that Faber picks for me. Like, if I want another file extension for a library than the default for the platform. For libraries, I could specify whether to build a static or shared one. Or if I really don't want to name the library "greet", I could pass the keyword name="great".
This declaration enforces the use of keywords for attributes, positional arguments are not allowed for attributes, which is a good for clarity.
The rule to make a test is very cryptic. The action takes several positional arguments, and I can only guess what each positional argument does.
rules take at least two (positional) arguments (an action and a name for the target artefact). All other arguments have default values, and thus *may* be given as keyword arguments or as positional arguments, depending on your preference. (But given that a "source" argument is still very common, I just chose to not spell it out as "source=hello" for compactness.) As a fabscript author you are of course free to name all your rule arguments, if that helps readability. I not inventing anything here, but rather take the most natural approach possible following Python language rules and idioms.
I am also critical about this in bjam. By using a syntax that uses a lot of positional arguments, you need to read the documentation to figure out what is going on.
Again, Python allows you to name all arguments. This is up to the caller, not the API designer. As far as the API is concerned, rules have two mandatory arguments, so it wouldn't make sense to make them keyword arguments.
I hope I explained better above what I had in mind. I agree, of course, that writing things like source="bla" all the time is annoying and superfluous.
But if you prefer some help in drafting your fabscript logic, there are good tools to help interactively editing Python code, including code completion etc. That's the beauty of using Python: we can tap into a fabulous ecosystem of tools and modules, including ipython, jupyter, spyder, etc., etc.
Agreed, that's why I am also in favour of using an established scripting language to describe a build tree. I am sorry that I am so critical, but we have some common ground. All this is meant in a constructive way.
Best regards, Hans
_______________________________________________ Unsubscribe & other changes: http://lists.boost.org/mailman/listinfo.cgi/boost