On Wed, Jul 25, 2012 at 7:25 AM, Allan Odgaard <
text...@gmail.com> wrote:
> I generate my ninja build files and can’t figure out how to make it so that a) no special action is required for bootstrapping the build on a clean system and b) the involved ninja files are regenerated when required.
To start with, I haven't put much thought into this area so I'm open
to improvements.
It sounds like for (a) you want bootstrapping to happen implicitly
when you run "ninja" first?
I think the reason this hasn't come up before is that many (most?)
projects allow for some sort of arguments to the generator which ninja
won't know to pass through, so such projects require you to always
manually run the generator first. E.g. even with a simple app like
ninja there are flags like --debug or --with-gtest=/path/to/gtest that
you can pass to configure.py. Larger tools like cmake, gyp, or
autoconf have more extensive configure-time flags.
> Two things here that I think ninja fails at:
>
> 1. The include is prefixed with a dash, this means it won’t fail if the file does not exist, meaning on a “clean system” the user need not take any special actions.
It wouldn't be hard to extend ninja to allow some sort of "optional
include" syntax, but I want to to be sure it ends up being useful.
> My attempt at porting this to ninja has resulted in the following:
>
> builddir = /tmp/build
>
> rule gen_build
> command = ./gen_build -d $out.d > $out $in
> depfile = $out.d
> generator = 1
>
> build $builddir/build.ninja: gen_build manifest | ./gen_build
>
> subninja $builddir/build.ninja
>
> Unfortunately on a clean system I need to bootstrap the process with:
>
> mkdir -p /tmp/build && touch -t 200101010000 /tmp/build/build.ninja && ninja /tmp/build/build.ninja
>
> Furthermore, I regularly need to invoke:
>
> ninja /tmp/build/build.ninja
>
> To be sure the build file is up-to-date.
To be sure I follow you: I think what you're saying is that due to the
"subninja $builddir/build.ninja", you want ninja to check for changes
in that file and rerun the generator if necessary?
Right now the dependency rule is simplistic: any build implicitly does
the equivalent of running "ninja build.ninja" before running the build
itself. What I think you're requesting is something like:
build the-build-itself: build.ninja $builddir/build.ninja
and for ninja to instead compute the dependencies "the-build-itself"
as the first rule.
Part of the reason this is awkward to express is that ninja is
designed around the idea that the topmost build.ninja itself will be
generated. If that were the case, expressing the above is as simple
as adding $builddir/build.ninja to your generator build line, like:
build build.ninja: gen_build manifest | ./gen_build $builddir/build.ninja
(It is unfortunate that build.ninja ends up being a build-time file
that is written in your source tree. An alternative approach -- the
one we use in Chrome and the one encouraged by autoconf etc. -- is to
generate the build files like build.ninja in the build directory and
run all builds starting from that directory, either by cd'ing into
that directory first or by the -C flag.)
> I should add that the conditional include feature of make is also useful to include ‘Makefile.$USER’ — this will allow users to augment the goals (targets). For example I may add something like this to Makefile.«me»:
>
> app/scp: app_binary
> scp $< «my_other_machine»
>
> app/deploy: app/scp
>
> No-one but me want the ‘app/scp’ target since it is specific to my development environment.
>
> Furthermore the above show that make’s ability to append to dependencies is sometimes rather useful. E.g. I assume that the standard Makefile already define ‘app/deploy’ as a target which builds and links the executable. I add my custom ‘app/scp’ as a dependency to this goal so on my system ‘make app/deploy’ additionally copies the application to my other machine.
I think I follow you here. I'll note that there's no way to express
Makefile.$USER (where $USER is expanded in the environment) as an
input in Ninja syntax itself, though something like Makefile.user
could surely be done.
In all, I think the reason you're having to fight with ninja's
behavior here is that ninja assumes you'll be (re)generating
build.ninja. In that case, adding conditional includes that obey
environment variables etc. are trivial as you can just do that logic
in your build file generator. I worry that conditional includes may
end up not being enough to get all the build muscle you want, but I'm
willing to hear arguments for it.