proj-plbook-plChToolingImpl

Table of Contents for Programming Languages: a survey

Chapter ?: Tooling

Part of what draws people to (or repels people from) a programming language is its tooling. So if you are implementing a programming language, you may wonder, what does good tooling look like? For now, we'll settle for just surveying what tooling is out there, good or bad.

Note that many tools span multiple categories; in such cases we made a more-or-less arbitrary choice as to which category to put the tool in, so don't get too hung up on that.

Our focus here is language-specific tooling, rather than language-independent tools. However, there are many tools that, although they can in theory be used upon codebases of any language, in practice are associated with a particular language (typically the same language that the tool is written in). In some cases such tools may have a better fit with one language, in others they are just more popular in one language community than in others. In any case, we'll list many of these as well.

In addition, we sometimes list the most popular language-independent tools in each category.


Compiler features

Readable errors

IDEs and IDE API/module case studies

OmniSharp .NET IDE module

http://www.omnisharp.net/

Go Oracle

todo? https://docs.google.com/document/d/1SLk36YRjjMgKqe490mSRzOPYEDe0Y_WQNRv-EiFYUyw/view

Go for Visual Studio Code

"This extension adds rich language support for the Go language to VS Code, including:

    Colorization
    Completion Lists (using gocode)
    Signature Help (using godoc)
    Snippets
    Quick Info (using godef)
    Goto Definition (using godef)
    Find References (using go-find-references)
    File outline (using go-outline)
    Workspace symbol search (using go-symbols)
    Rename (using gorename)
    Build-on-save (using go build and go test)
    Format (using goreturns or goimports or gofmt)
    Add Imports (using gopkgs)
    [partially implemented] Debugging (using delve)" -- https://github.com/Microsoft/vscode-go

Sublimetext syntax definition format

https://www.sublimetext.com/docs/3/syntax.html

Kythe

http://www.kythe.io/docs/schema/

links about kythe

opinions on Kythe

https://plus.google.com/115849739354666812574/posts/WUgoSr8VVsq

summary: that is a rant against the cloud-based nature of at-that-time Grok. Mentioned some other related systems and features:

desired features:

'similar projects' to Kythe from wikipedia

another blog post with lists of similar projects (todo take notes on this; i think i read it years ago already tho):

See also [1].

Haskell ghc-mod

Language-server-protocol

https://github.com/Microsoft/language-server-protocol https://github.com/Microsoft/language-server-protocol/blob/master/protocol.md

Supported by MS (VS Code), Redhat, CodeEnvy?, Rust Language Server, and others (see https://github.com/Microsoft/language-server-protocol/wiki/Protocol-Implementations ).

Supports features such as (list from [2]):

an implementation for VS Code:

https://github.com/Microsoft/vscode-languageserver-node

Swift SourceKit protocol

https://github.com/apple/swift/blob/master/tools/SourceKit/docs/Protocol.md

note: some commentators note that it seems like SourceKit? pushes syntax highlighting across process boundaries and say that that is too slow: [3]

Typescript Language Service API

Ternjs language service API

(list from [4])

Elixir alchemist language service API

Lisp Swank protocol (within Slime emacs mode)

IDE features

"

-- [5]

IDEs


Code formatters


Static program analysis and transformation case studies


Debuggers

Debugger Case studies


Profiler case studies


Build system case studies

https://en.wikipedia.org/wiki/Build_automation

GNU Build System (make, etc)

https://en.wikipedia.org/wiki/GNU_build_system

make debugger: https://github.com/rocky/remake tips: http://www.cl.cam.ac.uk/~srk31/blog/2014/11/19/#writing-makefiles

"...This does make me wonder how things went so badly with make, makemaker, autoconf, aclocal, and the rest of the Texas Toolchain Massacre." [6]

"I work on a lot of Javascript projects. The fashion in Javascript is to use build tools like Gulp or Webpack that are written and configured in Javascript. I want to talk about the merits of Make (specifically GNU Make). Make is a general-purpose build tool that has been improved upon and refined continuously since its introduction over forty years ago. Make is great at expressing build steps concisely and is not specific to Javascript projects. It is very good at incremental builds, which can save a lot of time when you rebuild after changing one or two files in a large project. Make has been around long enough to have solved problems that newer build tools are only now discovering for themselves." [7]

"I used make heavily in the 80s and 90s, but haven't much since then. Recently I started a project that had source files getting processed into PDF files, for use by humans. Since this is the 21st century, those files have spaces in their names. At a certain point, I realized that I should be managing this processing somehow, so I thought of using a simple Makefile. A little searching reveals that the consensus on using make with files with spaces in their names is simply "don't even try." In the 21st century, this is not an acceptable answer." [8]

"I think the reason make is both so controversial and also long-lived is that despite how everyone thinks of it, it isn't really a build tool. It actually doesn't know anything at all about how to build C, C++, or any other kind of code. (I know this is obvious to those of us that know make, but I often get the impression that a lot of people think of make as gradle or maven for C, which it really isn't.) It's really a workflow automation tool, and the UX for that is actually pretty close to what you would want. You can pretty trivially just copy tiresome sequences of shell commands that you started out typing manually into a Makefile and automate your workflow really easily without thinking too much. Of course that's what shell scripts are for too, but make has an understanding of file based dependencies that lets you much more naturally express the automated steps in a way that's a lot more efficient to run. A lot of more modern build tools mix up the workflow element with the build element (and in some cases with packaging and distribution as well), and so they are "better than make", but only for a specific language and a specific workflow." [9]

"> and the UX for that is actually pretty close to what you would want.

That is so not true. Make has deeply woven into it the assumption that the product of workflows are files, and that the way you can tell the state of a file is by its last modification date. That's often true for builds (which is why make works reasonably well for builds), but often not true for other kinds of workflows...Anything where the relevant state lives in a database, or is part of a config file, or is an event that doesn't leave a file behind (like sending a notification)... " [10] , [11]

" send: foo.log tail foo.log

email
          touch send" [12] (in response to the previous comment about 'make' not being able to record events like the sending of notifications)

"But regardless of that, a tool that makes a semantic distinction between tabs and spaces is NEVER the UX you want unless you're a masochist. " [13]

"GNU make has had an option (.RECIPEPREFIX) to change this..." [14] (in response to the previous comment regarding spaces and tabs)

" Another issue with Make is that it's not smart enough to know that intermediate files may change without those changes being important. Consider that I change the comments in foo.c or reformat for some reason. This generates a new foo.o because the foo.c timestamp is updated. Now it wants to rebuild everything that uses foo.o because foo.o is newer than those targets. Problem, foo.o didn't actually change and a check of its hash would reveal that. Make doesn't know about this. So you end up making a trivial change to a source file and could spend the afternoon rebuilding the whole system because your build system doesn't understand that nothing in the binaries are actually changing. ... With regard to my last comment (the problem with small changes in a file resulting in full-system recompilation), see Tup. It maintains a database of what's happened. So when foo.c is altered it will regenerate foo.o. But if foo.o is not changed, you can set it up to not do anything else. The database is updated to reflect that the current foo.c maps to the current foo.o, and no tasks depending on foo.o will be executed. Tup also handles the case of multiple outputs from a task. There are probably others that do this, it's the one I found that worked well for my (filesystem-based) workflows. " [15] , [16]

" The reason I don't like (((make))) is portability. Since the steps within the makefile are going to be run through a shell, it is going to behave differently on different systems.

If your makefile fixes up a file using sed and your system has gnu sed, your makefile may fail on a system with BSD sed (e.g., a mac). If you rely on bash-isms, your makefile may not work on a debian system where it will be run with dash instead of bash. And so on. " [17]

"Make's interface is horrible. Significant tabs. Syntax which relies on bizarre punctuation... If only whoever authored Make 40 years ago had had the design acumen of a Ken Thompson or a Dennis Ritchie!" [18]

"I've seen plenty of unmanageable Makefiles, but I haven't seen another system that would make them inherently cleaner. (I love CMake, but it's a beast, and even harder to debug than make. If it weren't for its nice cross-platform capabilities, I'm not sure it would see much use. It's also too specialized for a generic build tool. Then again, I definitely prefer it to raw Makefiles for a large C++ project.) " [19]

" "In all seriousness, what's wrong with it?"

1. Claiming a rule makes a target, but then fails to make that target, ought to be a runtime fatal error in the makefile. I can hardly even guess at how much time this one change alone would have saved people.

2. String concatenation as the fundamental composition method is a cute hack for the 1970s... no sarcasm, it really is... but there's better known ways to make "templates" nowadays. It's hard to debug template-based code, it's hard to build a non-trivial system without templates.

3. Debugging makefiles is made much more difficult than necessary by make's default expansion of every target to about 30 different extensions for specific C-based tools (many of which nobody uses anymore), so make -d output is really hard to use. Technically once you learn to read the output it tends to have all the details you need to figure out what's going wrong, but it is simply buried in piles of files that have never and will never be found in my project.

4. The distinction between runtime variables and template-time variables is really difficult and annoying.

5. I have read the description of what INTERMEDIATE does at least a dozen times and I still don't really get it. I'm pretty sure it's basically a hack on the fact the underlying model isn't rich enough to do what people want.

6. Sort of related to 2, but the only datatype being strings makes a lot of things harder than it needs to be. " [20]

" With the debugging expansion thing you're mentioning, now I'm craving a make built on some minimalist functional programming language like Racket where "expand the call tree" is a basic operation. " [21]

" I've been writing Makefiles regularly for maybe 15 years and I always end up on this page every time I need to write a new one: https://www.gnu.org/software/make/manual/html_node/Automatic...

$< $> $* $^ ... Not particularly explicit. You also have the very useful substitution rules, like $(SRC:.c=.o) which are probably more arcane than they ought to be. You can make similar complaints about POSIX shell syntax but at least the shell has the excuse of being used interactively so it makes sense to save on the typing I suppose.

That's my major qualm with it however, the rest of the syntax is mostly straightforward in my opinion, at least for basic Makefiles. " [22]

" give pmake a shot sometime.. the syntax/semantics are much more 'shell-like' imho and some things are just much more possible.. (e.g. looping rather than recursive calls to function definitions)" [23]

" ...some great features of make:

"it could be a lot worse. (see also: m4, autoconf, sendmail.cf)" [25]

"Make is the tried and true, but very rapidly becomes difficult to manage for larger projects, especially in a monorepo." -- [26] (that commentor prefer Bazel)

autoconf and automake

(do these even belong in this section?)

FAKE

https://fake.build/

"an F# "Make" system...a build DSL in F# scripts." [27]

Links:

mk

CMake

"I've seen plenty of unmanageable Makefiles, but I haven't seen another system that would make them inherently cleaner. (I love CMake, but it's a beast, and even harder to debug than make. If it weren't for its nice cross-platform capabilities, I'm not sure it would see much use. It's also too specialized for a generic build tool. Then again, I definitely prefer it to raw Makefiles for a large C++ project.) " [29]

cons:

" Cmake is more of a replacement for autotools than for make.

Advantages: Good Windows support.

Disadvantages: Dictates the directory structure, much less flexible than autotools.

If you know shell, an existing autotools project can be modified easily.

If you want to do something special in cmake, first you need to go to Stackoverflow. If your are lucky, the thing you want to do is supported (often it is not).

All in all, I feel locked in by cmake - to the point that once the build works I'm less inclined to refactor because the directory structure cannot be changed easily. " -- [34]

Used by:

Opinions:

Premake

https://github.com/premake/premake-core/wiki/Your-First-Script

SCons

https://en.wikipedia.org/wiki/SCons

Webpack

"When to stick with Webpack. The job that Webpack does is quite specialized. If you are writing a frontend app and you need code bundling you should absolutely use Webpack (or a similar tool like Parcel). On the other hand if your needs are more general Make is a good go-to tool. I use Make when I am writing a client- or server-side library, or a Node app. Those are cases where I do not benefit from the specialized features in Webpack." [35]

Gulp

Apache Ant

Apache Maven

"Maven, though at first rather overwhelming, turned out to have a ton of features I’d often wished for in other build/dependency management systems." -- https://medium.com/@octskyward/why-kotlin-is-my-next-programming-language-c25c001e26e3

Clojure Leiningen

"I find Leinigen a bit bloated respect to Mix. Mix is faster, lighter and integrated with Elixir. Lein is not. I find Lein a bit slow..." [36]

Clojure Boot

eg with Clojure Boot installed:

$ curl https://raw.githubusercontent.com/alda-lang/alda/master/bin/alda

  1. !/usr/bin/env boot

; this is a minimal dispatch script that fetches the latest version of ; alda from clojars (a maven repository for clojure projects) and runs the ; alda.cli/main method, passing along any command-line arguments.

; this script will automatically update your version of alda as newer ; versions are released.

(set-env! :dependencies '[[alda "LATEST"]])

(require '[alda.cli])

(defn -main [& args] (apply (resolve 'alda.cli/-main) args)) $ sudo curl https://raw.githubusercontent.com/alda-lang/alda/master/bin/alda -o /usr/local/bin/alda $ sudo chmod +x /usr/local/bin/alda $ alda Retrieving boot-2.2.0.jar from https://clojars.org/repo/ Retrieving clojure-1.7.0.jar from https://repo1.maven.org/maven2/ Retrieving dynapath-0.2.3.jar from https://clojars.org/repo/ Retrieving pod-2.2.0.jar from https://clojars.org/repo/ Retrieving shimdandy-impl-1.1.0.jar from https://repo1.maven.org/maven2/ Retrieving core-2.2.0.jar from https://clojars.org/repo/ ...

imake

qmake

bazel

"emphasis has been placed on build speed, correctness, and reproducibility.[2][4] The tool uses parallelization to speed up parts of the build process...One of the goals of Bazel is to create a build system where build target inputs and outputs are fully specified and therefore precisely known to the build system.[7] This allows a more accurate analysis and determination of out-of-date build artifacts in the build system's dependency graph. Making the dependency graph analysis more deterministic leads to potential improvements in build times by avoiding re-executing unnecessary build targets...One of Bazel's goals is to enable distributed and parallel builds on a remote cloud infrastructure. Bazel is also designed to scale up to very large build repositories which may not be practical to download to an individual developer's work machine.[9]

Bazel provides tooling which helps developers to create bit-identical reproducible build outputs. Bazel's implemented rules avoid typical pitfalls such as embedding timestamps in generated outputs to ensure content digest matches. This in turn allows the build system to reliably cache (memoize) the outputs of intermediate build steps. Furthermore, reproducible build makes it possible to share intermediate build results between teams or departments in an organization, using dedicated build servers or distributed caches...Bazel was designed as a multi-language build system. Many commonly used build system are designed with a preference towards a specific programming language. Examples of such systems include Ant and Maven for Java, Leiningen for Clojure, sbt for Scala, etc...Bazel also provides sand-boxed build execution. This can be used to ensure all build dependencies have been properly specified and the build does not depend, for example, on libraries installed only locally on a developer's work computer" -- https://en.wikipedia.org/wiki/Bazel_(software)

Opinions: