On Sun, Oct 15, 2017 at 5:28 PM, Lee Winter <
lee.j.i...@gmail.com> wrote:
> It is my intention to add TCL and LuA as cross platform shells. TCL
> because it is very comprehensive and even includes a GUI tool kit.
> Lua because it it the smallest/fastest shell that I know of.
I tend to partially agree with Lee on this topic, namely that I think
a much more problematic issue with Ninja generators is the actual
command generation part, and in fact it is the first stumbling block
into writing correct and portable build scripts. Currently the
`ninja` manual says that the commands are actually just thrown to `sh
-c '...'`.
Thus the generator writer has not only to target the "portable" shell
subset, but also to get correct the shell escaping and quoting and
syntax. (And being a Linux user, I don't even take into account the
differences between *NIX / Windows worlds. Also being a *NIX user, I
think that choosing `$` as an escape character was the worst possible
choice, as `sh` scripts are full of `$`...)
However, and here is where I only partially agree with this topic, we
don't actually need a full-blown shell. From my experience with Ninja
--- I've written a generator in Chibi Scheme, and a handful of narrow
domain generators -- all we actually need inside commands is:
* the majority of the time just a command with some arguments,
something that could be easily run by Ninja itself;
* some of the times a sequence of commands, and if one fails just
stop; (i.e. `cmd1 && cmd2 && cmd3`;) this is again something that
Ninja can easily handle;
* in rare cases a sequence of commands, and if one fails just stop and
run some cleanup; (i.e. `{ cmd1 && cmd2 && cmd3 ; } || { cmd4 && cmd5
; }`); again this could be handled by Ninja itself;
* in even rarer cases -- because such an usage is quite complex and
could be split into multiple build rules -- one requires more involved
"code", like scripts; this case I think would be better handled by
just taking out that code and putting it into an "executable" (which
can easily be a script); however even in this case Ninja could handle
it by using a special syntax, for example by replacing `command` with
`interpreter = python -s $script` and `script = ...`, where `$script`
is replaced by the path of a temporary file holding the contents of
the script (or in case of Linux even a pipe `/dev/fd/99` with a large
buffer, to eliminate all the file-system touching); (and it would be
wonderful if one can write `script = ...`, or even `command = ...` as
a multi-line construct without having to resort to `... $` syntax;)
* and finally a way to change the environment variables of the
launched processes; (for example a special syntax `env:VARIABLE =
VALUE`);
* (and just for completion, and the rare occasions where such a
feature would be needed, perhaps throw in some "process limits and
control", starting with `ulimit`, `nice`, `chrt`, `ionice`, and
`taskset`...) :)
As Lee mentioned there are multiple ways to implement such -- or any
-- shell, but the two variants that make the most sense are
(especially in *NIX):
* embedded into Ninja itself, executing each command instead of `sh`;
(optionally `fork`-ing itself;)
* executing another tool (perhaps part of the Ninja package), just
like it does with `sh` now, but with a much clearer "protocol" than
`sh` has when it comes to executing sequences of commands; (this tool
could even be usable outside of Ninja;)
Ciprian.
P.S.: Minor rant related with this: if Ninja is not meant as a
direct "language" for humans to write build scripts in, but as a
target for "generators", then why don't we use a syntax that is easily
parseable and already supported in almost any language known to man,
like for example JSON?
How is this related to all of this? If one would to design a
"protocol" between Ninja and the "shell", why can't we use JSON as the
syntax between the two, like in:
~~~~
{
"version" : 1,
"commands": [
["do", "this"],
["do", "that"]
],
"cleanup" : [
["rm", "this"],
["rm", "that"]
],
"environment" : {
"PATH" : "something"
}
}
~~~~