6 ms·
I come from a sofware world not typical for HN. I am a (very) low level software and FPGA guy. Despite my best efforts, I don't understand: What do any of these
by rthomas6 6y ago
I come from a sofware world not typical for HN. I am a (very) low level software and FPGA guy. Despite my best efforts, I don't understand: What do any of these tools do that Make does not? Are they faster and easier to use? Do they work better?
- throwawaylabor 6y agoMake build configurations can be difficult to understand for newcomers in the industry. If the goal is to obscure the code, by all means continue using the older tools. If the goal is continued maintenance, then encouraging new engineers to explore and read the codebase with tools they can comprehend is critical. disclaimer: have not used these particular tools, but the domain is nice and polite
- junon 6y agoI have use all of these tools and your take isn't accurate at all. Make doesn't obfuscate anything more than Plz or CMake or whatever. Here are some real reasons why Make isn't the end-all: - Make doesn't allow platform selection in a nice way. - Make doesn't work on Windows natively (no, NMake doesn't count). - Recursive make doesn't work well at all. - Make doesn't track byproducts or deleted artifacts. - Make doesn't have auto-clean. - Make doesn't facilitate out-of-source builds. - Make itself isn't a scripting language (arguably good/bad). - Make doesn't facilitate compiler selection cross-platform, so things like MSVC are nearly impossible to integrate nicely without the use of the developer tools prompt. - Make can't (elegantly) handle a number of rule cases, such as single-input multiple-output rules (it can, but it's a hack). Not sure why you think Make is unapproachable. That's like saying shell scripting is unapproachable. No developer worth a damn is going to avoid shell scripting, and as long as they understand "this file turns into this file using this command" then Make makes sense. As with all tools, Make and Autotools and CMake and probably Plz will be misused by developers that think they're being clever. In actuality, they make things worse at best and unusable/unmaintainable at worst. As a build systems designer, I've evaluated Plz personally and found it to be neat but not suitable for most of the problems I think build systems should solve.
- tus88 6y agoMake is not written in Golang/Rust/Haskell and lacks a cool logo and hip landing page.
- ironmagma 6y agoThe problem with Make is that it’s never just Make. It’s also Autoconf, Automake, m4, and god-knows-what-else. If Make is so great, why are people resorting to generating the Makefiles? There’s clearly some kind of deep UX problem there.
- ur-whale 6y ago> Autoconf, Automake, m4 all of which are even worse than make itself.
- jes5199 6y agoI think it’s 1. people find makefiles confusing, and if someone’s introduction to the concept is a large project they may never pick up the basics and 2. Make’s fundamental assumptions: that each command creates a single, sensible artifact that is the input for the next phase, maps poorly to the dynamic build processes of browser and phone ecosystems, which are themselves barely controlled explosions of complexity
- johnnujler 6y agoI don’t about these new build tools, but I’ve usually found ninja to be faster than make in most situations at least. Also curious to know, is there no work done in the realm of developer productivity inside the FPGA world?
- rthomas6 6y agoNo unfortunately. The FPGA "build" realm is mostly a clusterfuck of proprietary tooling. It all has poor to nonexistent integration with, well, anything else. There are some things that are okay for simulation like Cocotb, but for actually building hardware FPGA designs, you are locked into the vendor's tools. The only exception is if you use a small, slow, and outdated FPGA, not suitable for large designs used in industry. For these reasons, there isn't much of an open source community making things like Please and Bazel specific to FPGAs. You can set it up yourself, but a packaged product that just works out of the box doesn't exist to my knowledge.
- kingosticks 6y agoI work in a similar field and this is accurate for us too, except our tools do at least have some integration with Make (you can generate makefiles from the proprietary project files, although it's not useful to us and we don't use it). Like most (I assume), we've built our own build language/system on top of Make. It works but only in a few well-defined ways that modern software shops would probably baulk at. We don't support parallel builds, no caching, only coarse grained incremental builds (at a subproject/library level) and who knows what else that others benefit from. I've only looked at modern tools briefly but everytime I come away realising we'd have to re-write everything. There is no out-of-the-box support for our tools/language and it would be a lot of work to learn someone else's DSL, re-implement everything and then potentially discover a load of ways it's broken for our workflow. Personally I think it'd be worth it in the long run but it's a really hard sell.
- haberman 6y agoMakefiles operate at a low level of abstraction. The Makefile abstraction is "run this command when the output files don't exist or are older than the input files." You manually specify every tool to be run and all of its arguments. These tools operate at a higher level of abstraction. The BUILD file abstraction is something like "I am declaring a C library with these sources and headers." The build system then turns that into a set of commands to run. This higher-level abstraction provides a bunch of compelling features: - Reliability: it's easy to write Makefiles that are fragile, for example one that works when run on a single CPU but fails when run with -j, because of undeclared dependencies. When the tool is in charge, it has more control and can sandbox each build step so that undeclared dependencies simply won't be available in the sandbox. - Reproducibility: similar to the previous point, it's easy to write a Makefile that produces incorrect results with an incremental rebuild. For example, unless you implement your own header scanning (or manually list your header dependencies) "make" won't know to rebuild a source file when a header changes. These tools can ensure that builds are reproducible and incremental rebuilds are always correct. Besides that, working at a higher level generally means writing less code to accomplish the same task, and the code you do write is closer to expressing your actual intent compared with a Makefile.
- moonchild 6y ago> The Makefile abstraction is "run this command when the output files don't exist or are older than the input files." You manually specify every tool to be run and all of its arguments. > The BUILD file abstraction is something like "I am declaring a C library with these sources and headers." This is wrong. Even ninja has generic rules. Here's an example of a minimal makefile: OBJ = src/a.o src/b.o src/c.o libfoo.so: $(OBJ) $(CC) -shared -o libfoo.so $(OBJ) > When the tool is in charge, it has more control and can sandbox each build step so that undeclared dependencies simply won't be available in the sandbox. There's no reason this shouldn't be possible with make; it just hasn't been implemented so. Do bazel/buck/please actually do this? As far as I know tup is the only tool that actually verifies inputs/outputs of rules, and it needs FUSE to do so. > For example, unless you implement your own header scanning (or manually list your header dependencies) "make" won't know to rebuild a source file when a header changes. At least with GNU make, it's very easy: CFLAGS += -MMD -include $(patsubst %.o,%.d,$(OBJ)) True, it's a bit of a footgun, but by no means difficult. Make has problems, but the ones you listed aren't they.
- ur-whale 6y agoMake is only good at one thing: calculating how to execute a dependency graph to produce a specific target. Everything else that is needed for a modern build system is lacking: - expressive scripting language - platform-related configuration - feature-related configuration - handling hierarchical projects - properly handling rebuilds when the Makefile itself has been changed - dealing with dynamically generated parts of the dependency graph - handling third-party dependencies - build reproducibility - etc... the list is very long This is why people these days mostly take the path of generating Makefiles, because make is only good at one thing: executing a statically defined dependency graph.
- saurik 6y agoMake is a programming language: it is only good at executing that language, and that language kind of sucks, but saying Make is somehow only good at executing static dependency graphs is a fundamental misunderstanding of Make (but AFAIK might be a good description of say, ninja). All of the Make scripts I have written for the past 15 years have dynamically generated configuration and autodetected files and calculated version numbers and essentially done all of this work that somehow you think Make can't do.
- ur-whale 6y agoAnything that is (like make) turing complete can be made to do all the things you list. At a very minor cost after all: your sanity.
- klodolph 6y agoMake has a laundry list of problems: - Cannot handle multiple outputs for a single rule - Does not rebuild when flags change - Make rules may contain implicit dependencies - Slow for large codebases - Does not understand how to build for multiple platforms, sucks for cross-compiling - Recursive make sucks (job control does not work across recursive invocation boundaries) - You must create output directories yourself - You must create your own rule to clean This adds up to a fragile & slow build system, where you have to do a full rebuild to have a reasonable level of assurance that your build is correct—incremental builds aren’t safe. There have been a few attempts to make a “better make” over the years like Jam, SCons, Ninja, Tup, etc. each with their own pros and cons. The new generation of build tools—Bazel, Buck, Pants, and Please are all an attempt to redesign build systems so that the design is resistant to the flaws that plague Make build systems. You can use a shared cache (shared between different users) fairly easily, and you have reasonable assurance than incremental builds are identical to full builds (so your CI pipeline can move a lot faster, developers almost never have to "make clean" when they change things, etc). Personally I’m working on a project right now that uses Bazel (which is similar to Please) and is for an embedded system. It’s been a great experience, and I can pass a flag to Bazel to tell it to build for the embedded target using the cross compiler or for the native host--that makes it easy to share code between tools and the target system, and I can do things like write tests that run on both the target & host. Anyone who does any cross-compiling is missing out if they are using Make—but, do note that setting up a cross-compiling toolchain in Bazel isn’t exactly a cakewalk.
- panda88888 6y agoI am interested in setting up cross compiling environment with Bazel. Do you have any recommended documentation that I can read?
- panda88888 6y agoDid some searching and found this documentation on customizing C++ toolchain. I'll give it a try. https://docs.bazel.build/versions/master/tutorial/cc-toolchain-config.html https://docs.bazel.build/versions/master/tutorial/cc-toolcha...
- dfgdghdf 6y agoThe short answer is yes, they are (well, can be) easier and faster and work better. I would strongly recommend watching this talk if you want to understand why systems like Bazel and Please were created: Build Systems with Andrey Mokhov (Jane Street) https://www.youtube.com/watch?v=V9YA32uV3Ls https://www.youtube.com/watch?v=V9YA32uV3Ls
- jedberg 6y agoI think one good way to think about it is all of these build systems create Make environments. They create the makefiles and have all the other tools that go with it. So at the end of the day you end up with an executable artifact, but hopefully you did a lot less work to get there.
- patrec 6y agoOnly garbage like autotools or CMake generates Makefiles, all remotely sane build systems (including the various bazel/blaze derivatives) do away with make, which even sucks as a low level abstraction.
- gravypod 6y agoI think there's a few advantages of bazel-like systems: 1. Reproducible/Hermetic: your builds cannot, say, access the network during a step or produce changing binaries for the same input. This makes sure that once you've downloaded your deps locally everything builds correctly from then on. 2. Caching: Because everything is reproducible in bazel-likes everything is cachable. Dependencies, builds, and even tests! If you've worked with Makefiles you've likely run `make clean; make tests` or something similar. I've never needed to do `bazel clean` to make sure things were working right. 3. Visibility: you don't only control who can see what in your source code. Different dependencies can be marked as private/protected/public to control who can import them. This is a huge boon to large monorepos. 4. Everything is uniform: code generation, compilation, etc is all described in "rules" and "toolchains" and can "easily" expanded to other languages. The community manages a Rust and Golang rules set for bazel itself and they're better then the Google rule sets for Java (only "officially" supported rule set right now) in some areas. So if you have a lot of code/internal libraries/code generation, what to write a LOT of unit tests and cache their results, and write code in multiple languages bazel is probably for you. You can also use tools like BuildBuddy [0] to share a cache with your team and extract build performance metrics to identify areas you can improve performance in. [0] - https://www.buildbuddy.io/ https://www.buildbuddy.io/ or https://github.com/buildbuddy-io/buildbuddy https://github.com/buildbuddy-io/buildbuddy