Combining rules.

80 views
Skip to first unread message

Ildus K

unread,
Nov 22, 2024, 7:35:57 AM11/22/24
to ninja-build
Hi,
I am seeking an advice for the correct approach.
I have a generator project that outputs ninja file, but struggling to find a best output
The current (not working prototype) output looks something like this:

rule Archive
  command = ar ru $out $in
rule Ranlib
  command = ranlib $out
rule RmTemps
  command = rm -f $in
...
build libtest.a: Archive one.o two.o test.o
build libtest.a: Ranlib
build libtest.a: RmTemps one.o two.o test.o
build one.o: Cc one.c
build two.o: Cc two.c
build test.o: Cc test.c

So rules look nice by themselves, but for each output there should only one `build` block. Currenly I see that only way to fix this is merging the rules to one, and call that, but maybe there is a more correct way to do the same?

Christophe D.

unread,
Nov 22, 2024, 7:58:48 AM11/22/24
to ninja-build
Hi,
I have written a generator (https://github.com/CDSoft/bang) that can chain rules using temporary files for intermediate result.
The problem in your case is that ranlib modifies its input in place. If you want to keep both rules separated you may have to copy the output of ar.
E.g. with bang, you can write:

var "builddir" ".build"
rule "Archive.a" { command = "ar ru $out $in" }
rule "Ranlib.a" { command = "cp $in $out && ranlib $out" }
archive_and_ranlib = pipe { "Archive.a", "Ranlib.a" }

archive_and_ranlib "libtest.a" {
    "one.o", "two.o", "test.o"
}

It will generate this ninja file :

builddir = .build

rule Archive.a

  command = ar ru $out $in

rule Ranlib.a
  command = cp $in $out && ranlib $out

build $builddir/tmp/libtest.a.tmp/libtest-1.a: Archive.a one.o two.o test.o
build libtest.a: Ranlib.a $builddir/tmp/libtest.a.tmp/libtest-1.a

(no need to remove the intermediate files, they are generated in a separate build directory)

The names of the temporary files are autogenerated (and ugly...)

But in your case, the simplest solution may be to combine ar and ranlib. E.g.

rule Archive
  command = ar ru $out $in && ranlib $out

Eli Schwartz

unread,
Nov 22, 2024, 10:56:56 AM11/22/24
to ninja...@googlegroups.com
This "limitation" is intrinsic to the nature of designing a build system
that operates on files. Consider: which order do you run these in, and
why? How do you handle resume?

The larger issue to me though is that this entire approach appears
extremely misguided. Why would you want to "remove temps"? This means
that libtest.a doesn't have the file dependencies it needs, which build
systems generally do not allow (not a ninja specific issue), and for
quite practical reasons: if you modify one.c, then you need to recompile
one.o and update libtest.a, but modifying libtest.a requires having
two.o and test.o as *ninja* dependencies, and you previously deleted
those. So now you have to recompile them.... :)

Every other build system as a rule will try to run `ar` using `csrD`
rather than `ru`, there's a reason for this. The "r" mode is not a real
optimization, quite honestly.


--
Eli Schwartz
OpenPGP_signature.asc
Reply all
Reply to author
Forward
0 new messages