11 ms·
Ninja: A simple way to do builds
- chovyfu 6y agoThat's just BASH with extra steps.
- datashaman 6y agoCorrect, simple.
- bla3 6y agoThe advantage are the incremental builds they mention. If just one input file changes and you run ninja again, it'll only re-run one step instead of converting all files again.
- m000 6y agoI'm pretty sure make does that too. The problem is that most people don't know how to write a proper Makefile, even for a simple project, so make ends up doing more work than it should. For small projects, I've tried ninja a while ago, and frankly the effort seemed unjustified, since (a) I already could do the same things with make, and (b) make is already available on most unix-likes. Ninja seems to be better suited for big projects, where make's slowness in dependency resolution shows. Ninja files also look easier to generate automatically.
- iainmerrick 6y agoYes, Ninja files are very easy to generate, that’s it’s big selling point for me. I have a project with dozens of C/C++/asm/precompiled libraries, a few thousand source files in all. I would have trouble writing Makefile(s) for everything that would even be correct, let alone performant, either by hand or generated. But I have a set of Python scripts to generate a big Ninja build file and it all works very nicely.
- flohofwoe 6y agoNinja hasn't been created for small one-liners like in this blog post, but for massive C++ builds with tens- or hundreds-of-thousands of source files arranged in a complex dependency tree. Figuring out quickly what needs to be rebuilt for massive builds like this isn't trivial, but that's essentially the one important thing that ninja does. Also see: https://ninja-build.org/manual.html#_design_goals https://ninja-build.org/manual.html#_design_goals
- AtlasBarfed 6y ago... What mechanism is used to perform incremental builds? It is referenced in the article and unexplained from what I can tell. What enables "quickly" for you to determine what needs to be built? Make simply compares timestamps I believe. ... What mechanisms/tricks speed up builds? Or is it just the "simplicity" that is the BFD? Edit: It sure would have been helpful if somewhere was stated: "the build system of Chrome":-) That statement indicates a huge difference between some rando build system on someone's personal project, and a build system on operating-system-size codebase that is over a decade old.
- busrf 6y agoNinja uses time stamps. See the “Comparison to Make” section in the linked manual.
- sbierwagen 6y agoIsn't using mtime a bad idea? https://news.ycombinator.com/item?id=18473744 https://news.ycombinator.com/item?id=18473744
- slavik81 6y agoNo? The top comment in that thread is the author of Ninja discussing how he addressed the problems described in the article. And, despite its title, the article itself goes on to discuss why and how to use mtime in a build system.
- 6y ago
- antoinealb 6y agoIf you don't know it, CMake can use ninja instead of make for compilation so instead of "mkdir build && cd build && cmake .. && make" you can run "mkdir build && cd build && cmake -GNinja && ninja". It feels faster on my side projects (haven't benchmarked it really), but most importantly, when running a parallel build it does not interleave the output of the different steps, making it much easier to read warnings and errors.
- jart 6y agoIf anyone wants to know more about preventing interleaving, try using `make -O` or adding `GNUMAKEFLAGS += --output-sync` to the top of your Makefile.
- ihnorton 6y agoA small warning for code with many CMake ExternalProject dependencies: the defaults for cmake+ninja will recursively run `ninja -jN` for each level of the dependency tree, which can spawn a very large number of compile jobs. There is a proposal to add jobserver support for global process count management [1], but it has not been merged for philosophical reasons (IIRC). The CMake folks maintain a soft fork with this patch applied, available in the `ninja` package on PyPI and probably elsewhere. [1] https://github.com/ninja-build/ninja/issues/1139 https://github.com/ninja-build/ninja/issues/1139
- tomjakubowski 6y agoNinja is especially beneficial on large projects with lots of source files. Where Make can take 30+ seconds to run a "no-op" build, when nothing needs rebuilding, ninja does it instantly.
- kingosticks 6y agoThe conclusion at https://david.rothlis.net/ninja-benchmark/ https://david.rothlis.net/ninja-benchmark/ (2016) was that this doesn't have an impact until you get to really large projects (assuming you are able to utilise make -j).
- CUViper 6y ago
- hinkley 6y ago> for filename in things_to_convert: Undeclared variables and random indentation levels. Is it safe to assume these examples are abridged? Or is it a case of magic?
- jorams 6y agoSince the comment above that line says this: > # some for loop with every file I need to build It's safe to say that it's not a complete example. That said, the indentation levels are not random. These are multiline strings.
- grive 6y agoI've only worked on one project (https://www.dpdk.org/ https://www.dpdk.org/) using meson+ninja. Overall it seems to be an improvement, barring the make idiosyncrasies that needs to be forgotten. That being said, if the project had used make properly from the beginning (i.e. avoid recursive calls), it would not have been plagued by such latency for incremental builds. But then, make should not have made it so easy to fall for such mistake. I'm still not a fan of having two steps (meson + ninja), but I guess it's always needed for multi-platform projects. I'm wondering if there is a make rewrite project that tried to make the recursive make antipattern less painful? Maybe trying to recognize sub-calls and avoid creating a sub-process? I guess it would take creating a small internal shell with only make as a builtin command...
- jhasse 6y agoThere are other things in make that could be improved. If your rewrite fixes those, too, I'm wondering why not use Ninja at that point?
- inglor 6y agoI don't know I did a few things in Chromium and admittedly it's a really big project BUT ninja and autoninja get really cryptic and complex pretty fast. To be fair it's better than make or the older gyp setup BUT for non trivial workloads ninja is pretty fast but leaves a lot to be desired in terms of DX.
- jhasse 6y agoAre you sure that is a Ninja issue and not an issue with Chromium's build generator GN?
- chrismorgan 6y agoFor comparison, here’s a makefile for the trivial example (though you’ll have to fix the indentation): all: $(patsubst ${things_to_convert},%.svg,%.pdf) %.pdf: %.svg inkscape $< --export-text-to-path --export-pdf=$@ ${things_to_convert} is left undefined, as in the source article. It might be something like $(wildcard [STAR].svg) or $(shell find src -name '[STAR].svg'). [Turn each [STAR] into *; HN formatting idiosyncrasies are in play.] I like makefiles in substantial part because there’s a very high probability of Make already being installed. I’m comfortable enough with them that I didn’t need to look anything up to write any of what I wrote above. It’s a bit of a pity about the sigils; though would people really find $first_prerequisite and $target better than $< and $@? No idea. Ninja uses $in and $out, but it’s simpler in a way that lets it reasonably get away with that. Make, on the other hand, is complex in a way that is pretty powerful if you know what you’re doing, but generally more manual (e.g. Ninja looks like it tracks dependencies roughly automatically, whereas dependencies are manual in Make, as many have found to their sorrow) and it makes it fairly easy to shoot yourself in the foot if you do the wrong thing, which is easy to do if you’re not expert, which not many are.
- patrec 6y agoYou are not wrong, but if the world where not full with even worse build systems it'd be a bit saying I prefer to drink from puddles because I find them wherever I go. Make is everywhere, but apart from UX issues such as the dumb syntax or the different flavors you'll encounter, the fundamental problem with it is that it just can't build things properly (the existence of make clean is the dead give away here). That's fine for trivial stuff, but for real work you really owe it to yourself (and society at large) to use a build system which can correctly build things. Some examples applying to the above: - if your paths have white space in them, you are generally fucked - if your change your Makefile, nothing will be rebuilt - if inkscape writes out a partial file because full disk and you fix the problem, the partial svg will no be rebuilt - if you install a new version of inkscape nothing will be rebuilt
- dan00 6y ago> - if your paths have white space in them, you are generally fucked Paths containing ':' are also fun. That make doesn't handle paths - and most likely other things - as a unit, but just substitutes their string representation into the makefile, is just asking for trouble.
- desine 6y agoI've been compiling some libraries and projects on my raspberry pi, and I've been having to invoke meson and ninja quite a bit. If nothing else, they've been getting it right on the first try more often than the cmake && make projects. That may be biased though, with newer/more active projects using newer build systems supporting newer hardware. Anyways, it's been enough that I'm looking into it, but still working (hacking? copy/pasting?) in make
- draw_down 6y agoBuilds are never simple.
- runiq 6y agoThe one thing that's keeping me from using Ninja for the use-case Julia is describing is lacking support for reading environment variables in build.ninja. I understand why that's not part of Ninja, but it does stunt its usefulness.
- e12e 6y agoThere's an obvious fix for that... Mix in some M4... ;-) https://en.m.wikipedia.org/wiki/M4_(computer_language) https://en.m.wikipedia.org/wiki/M4_(computer_language)
- nsm 6y agoThe ninja author has a (relatively) recent blog post about design decisions and lessons learned: * The success and failure of ninja http://neugierig.org/software/blog/2020/05/ninja.html http://neugierig.org/software/blog/2020/05/ninja.html
- brabel 6y agoThanks for the link, it was a very nice read! The author wrote Ninja initially as a weekend project. I've written a small build system like that as well, but I think I am the only person using it though :D funny to think that your weekend project could've accidentally become something widespread like Ninja (used to build Chrome, Android, Swift etc).
- gravypod 6y agoI wish more people were taking a look at Bazel, and the Bazel-family, of build systems. I've looked at Meson/Ninja/Make and it works but it's truely very complicated and very difficult to get hermetic & reproducible builds from these systems. In my opinion, Bazel will be the future once the currently ongoing external dependency management design doc is implemented. I've migrated quite a few builds to bazel at work and I've seen a dramatic reduction in compile times - not even from compiling source code! Doing things like packaging zips, generating code, generating docs (swagger), etc all adds up in CI time and automating, and caching, absolutely all of it is astonishingly useful.
- dcolkitt 6y agoOut of curiosity, how difficult did you find the migration process? Especially in terms of having to restructure the project. I have no direct experience, but from what I've heard Bazel is very opinionated about structure. Which makes it particularly challenging to migrate pre-existing projects that may not conform to its view. But again this all hearsay, so I'd like to hear from someone with direct experience.
- gravypod 6y agoIt was pretty easy for the software I was migrating because it was already in a monorepo and we were already using some very similar conventions. Anyone writing Java code that uses Gradle or Maven shouldn't have much pain migrating. I'm acutally currently supporting both Gradle and Bazel on the same backend code base to give another team (who depends on my code) a chance to gracefully migrate. The "hardest" thing to migrate has been C and Python code. For these the package for something is based on an absolute file path from the root of your repo. So `company/foobar/thing.py` is `from company.foobar import thing`. I find this very useful personally because it's now standardized through the codebase (no one just plops a setup.py somewhere and does whatever they want) but it makes the migration difficult because you need to change the paths. There's some work being done in rules_python and in cc_library/cc_binary that lets you control this behavior and hack it to align with your current company standards though which is really nice to use for a gradual migration.
- cb321 6y agoShe missed the step where you just say [ "$dst" -nt "$i" ] || svg2pdf "$i" "$dst" in her for-loop. That is about as much extra typing/text as her comment and makes that build script about as fast as alternatives for that simple scenario. { This is not to say there isn't maybe more motivation for grander designs..or various failure modes..just that she missed a step. :-) }
- pierrebai 6y agoOf note, meson is mentioned to optionally use ninja as a build system, but the same is true of CMake. On thing to note is that the simplicity of ninja means that a lot of things need to be repeated. For a project I'm working on, the input build.ninja file is 142MB. Just generating that files takes a few minutes. I think an improvement would be to be able to split it in sub-trees and have ninja produce a "mark" file that has a date that represent when the last time the sub-tree was touched and to not even read any sub-tree files, even the sub-ninja file if an entire sub-tree date is older than the mark file.
- iainmerrick 6y agoAre you sure Ninja is the cause of the problems there? I agree that it’s repetitive, but you can at least put common expressions into build variables, so the overall build script size should scale about linearly with the number of files. 142MB is massive! How many files are being built and how much work is being done per file? 142,000 files with 1KB of unique command-line flags each? Also, even though that’s a very large build script, I would have thought generating it should only take seconds, not minutes. How is the script being generated, and how long is spent generating it versus executing it?
- ur-whale 6y agoThe article keeps on saying that make is "complicated" ... make is an abomination in many, many ways, but claiming that Makefile language is complicated is just sheer ignorance.
- Lammy 6y ago“esoteric”?
- ncmncm 6y agoIt is a mistake to imagine Ninja just replacing Make. Ninja is the "rebuild-it" part of Make, made really, really fast and clean, a joy to use. The Ninja config file is not something you write or, even, look at. It's an intermediate file generated by your build-dependency tool such as CMake, Meson, or even (gods forbid) SCons. Those are smarter than Make in various ways, but are really not very good at all at actually running builds, so you get them to just make a ninja file, instead, and then get the hell out of your way. This is good because you don't want to analyze the dependency tree on every build when you haven't changed any of it. So, you just run ninja in your edit-build-test loop. Ninja is smart enough to rerun Meson or whatever if you do change the build configuration. It understands build directories separate from sources, and ccache compiler wrappers to cache build targets, things you don't want your build-configuation infrastructure to bother with. Besides being fantastic to use, ninja is worthy of study as a truly superb example of a program that does one thing really, really well, and integrates cleanly with other programs that do other stuff: build analyzers on one side, compilers on the other. It demonstrates a design discipline that we would all be better off if everyone were to follow it.
- junon 6y agoMeson still doesn't get submodules right. So far, CMake gets the closest. The Meson developer is a bit of a jerk about this subject, too - he has a very dogmatic view of how a project should be structured and has designed meson around that. For example, you cannot have nested subprojects with Meson.
- ribaldev 6y agoWe use task management apps to save us time and give more visibility over the work. However, the app can become so complicated to use by itself, that we may choose to go for very basic note-taking apps to avoid the complexity. I was looking for a minimal, simple and user-friendly app for daily task management, so I developed Renoj. Fast to-do task management in Desktop for ultimate productivity. Website: https://ribal.dev/renoj https://ribal.dev/renoj