CLI Help


When using compose.mk directly, help not only works, it goes beyond simply listing available targets, and actually parses and displays documentation per target, and per target-namespace. (Under the hood, a dockerized version of charmbracelete/glow renders markdown.).

There are several ways to invoke the help for compose.mk.

# List all targets 
$ ./compose.mk help

# Help for a single target 
$ ./compose.mk help docker.run

# Help for a module namespace with many targets
$ ./compose.mk help docker

Because a dockerized glow is involved if no local tool is available, and because the Makefile-metadata parser is also a container, be warned that rendering help can be very slow, especially the first time it runs. If this bothers you, you can skip some docker-bootstrap time by actually installing stuff. See the implementation details section for more about this, and other hints for granular access to the moving pieces involved here.

Help For Project Makefiles


To enable help your project Makefile, there are a few options depending on how tightly you want to integrate, but usually it's enough to just include compose.mk somewhere near the top.

Docstring Style


Note that for help to render properly, your targets need to use the following style for comments, similar to python-style docstrings. (There is no support for other kinds of # .. comments .. that are above or inlined inside of target-bodies.)

Summary
#!/usr/bin/env -S make -f
# demos/cli-help.mk: 
#   Demonstrates CLI-help and supported syntax for docstrings.
#   Part of the `compose.mk` repo. This file runs as part of the test-suite.  
#
# USAGE:  ./demos/cli-help.mk

include compose.mk 

__main__: my-target my-parametric-target/FOO

my-target:
    @# Comment line one
    @# **Markdown is supported.**
    echo your implementation here

my-parametric-target/%:
    @# Comment line one
    @# **Markdown is supported.**
    echo your implementation here

Basic Integration


The file above is exercised as part of the test-suite, and is actually called demos/cli-help.mk, and invoked with ./demos/cli-help.mk. For the sake of the next examples though, we'll pretend it's your project Makefile and simply invoked as make ....

With a simple setup like this, here's what's enabled:

# Display a FULL list of new-line separated targets,
# most of which are inherited via the `include` statement
$ make help

# Abbreviated list of newline-separated LOCAL targets (no includes)
$ make mk.targets

# Rendered help for all local targets (potentially very slow)
$ make help.local

# Rendered help for 1 target 
$ make mk.help.target/my-target

Full Integration


With the basic integration so far, we haven't yet seen the kind of help for extensions that we started with for compose.mk, i.e. ./compose.mk help <target_or_module>.

Since make help.local actually renders all help strings for all local targets, you may find that invocations like make help <target> are not that useful. In fact.. for technical reasons related to default argument parsing by make1, invocations like make help <target> cannot work with project makefiles because the target would actually be executed.

There are a few ways to work around this.

# use `mk.parse/<fname>` to get all Makefile metadata, including help.  (returns JSON)
$ ./compose.mk mk.parse/demos/cli-help.mk


# use `mk.interpret` to wrap another Makefile, then proxy help commands the wrapper.
$ ./compose.mk mk.interpret demos/cli-help.mk help my-target

The last command mentions an interpreter, which is discussed in more detail in the supervisors and signals docs. For our purposes here, the main point though is just that the help <target> part is working again.


Going further.. we can actually setup compose.mk as the interpreter more directly and mention it in a shebang. In the next example, only the first line of the file changes:

Summary
#!/usr/bin/env -S ./compose.mk mk.interpret
# demos/cli-help-shebang.mk: 
#   Demonstrates compose.mk usage as an interpreter, 
#   which amongst other things enables full support for online help.
#
# See the docs: https://robot-wranglers.github.io/compose.mk/cli-help/  
# Part of the `compose.mk` repo. This file runs as part of the test-suite.  
#
# USAGE:  
#   ./demos/cli-help-shebang.mk help my-target
#   ./demos/cli-help-shebang.mk help my-parametric-target

include compose.mk 

__main__: my-target my-parametric-target/FOO

my-target:
    @# Comment line one
    @# **Markdown is supported.**
    echo your implementation here

my-parametric-target/%:
    @# Comment line one
    @# **Markdown is supported.**
    echo your implementation here

Now ./demos/cli-help-shebang.mk help my-target works as expected. An approach like this will also work if the file is named Makefile, but note that the shebang is ignored unless you execute the file directly!

Implementation Details


Since help involves targets and target-metadata, it's also a special case of reflection, which you can read more about in the standard-library docs.

The implementation for help uses the mk.help.* family of targets, and if you want to customize help or error messages they might be useful.

Heavy lifting for parsing Makefile metadata comes from a dockerized version of the pynchon tool, which can parse help as well as more structural details like target-prerequisites / DAGs.

To see example output or just precache the pynchon container, you can use mk.parse/<some_makefile>. To get an idea about the schema, we can use compose.mk to parse it's own content, then show the JSON structure for the mk.parse target itself.

$ ./compose.mk mk.parse/compose.mk
{
  ..
  "mk.parse/%": {
    "file": "compose.mk",
    "lineno": 2056,
    "chain": [],
    "type": "implicit",
    "docs": [
      " Parses the given Makefile, returning JSON output that describes the targets, docs, etc. This parsing is \"deep\", i.e. it returns docs & metadata for *included* targets as well. This uses a dockerized version of the pynchon[1] tool.",
      "",
      " REFS:",
      "* `[1]`: https://github.com/robot-wranglers/pynchon/",
      ""
    ],
    "prereqs": [],
    "regex": "mk.parse/.*",
    "implementors": []
  },
  ..

References



  1. See the docs for Supervisors & Signals