Hi
I've often wanted to extract information from a large build in some way
that's more reliable than grep. The GNU make (--print-data-base) option has
been a very useful way to see what the complicated makefiles I was working
on finally evaluated to. The only negative about it from my point of view
is that it was still a makefile in the end and still had to be parsed.

So recently I tried cloning the print-data-base feature into something that
delivered JSON.  Now it should be trivial to get a list of targets of some
particular type - even with a tool like "jq".

The result so far is lacking a lot but I am running out of free time to
work on it and I thought that I might as well seek feedback now in the
event that there's anyone else out there who finds this of interest.

At a high level the output looks like a straight dump of make's internal
data structures but there is a tonne of detail about each variable and each
file which I've left out to make this overview simple:

{
  "MakefileName": {
    "variables": {
      "global": {
          "pkgdatadir" : {
            "origin": "makefile",
            "private": false,
            "source": "Makefile",
            "line": 92,
            "assign-recursive": "$(datadir)\/make"
          }
},
      "pattern-specific-variables": {},
      "pattern-specific-rule-count": 0
    },
    "dirs": [],
    "rules": [],
    "files": {
      "src/w32/w32os.c": {},
      "/usr/include/bits/fcntl.h": {},
      "dist": {},
    }
  }
}

The whole thing isn't indented nicely either but one can just run jq on it.

If you looked at an individual file you might see something like this:

"src/w32/w32os.c" : {
  "hname": "src\/w32\/w32os.c",
  "vpath": "",
  "deps":   [],
  "stem": "",
  "also_make":   [],
  "target-variables": {
  },
  "last_mtime": 0,
  "mtime_before_update": 0,
  "considered": 0,
  "command_flags": 0,
  "update_status": 1,
  "command_state": "cs_not_started",
  "builtin": false,
  "precious": false,
  "loaded": false,
  "unloaded": false,
  "low_resolution_time": false,
  "tried_implicit": false,
  "updating": false,
  "updated": false,
  "is_target": false,
  "cmd_target": false,
  "phony": false,
  "intermediate": false,
  "is_explicit": true,
  "secondary": false,
  "notintermediate": false,
  "dontcare": false,
  "ignore_vpath": false,
  "pat_searched": false,
  "no_diag": false,
  "was_shuffled": false,
  "snapped": false
}

HOW TO GET IT:
===============
in the feature/jprint branch on this fork:
   https://github.com/tnmurphy/gmake-experimental

I've added a new commandline option:
   --print-data-base-json

you can build it and then run it like this:

  ./make --print-data-base-json


HOW IT GENERATES OUTPUT:
===========================
The idea is that a JSON file is created in each directory where make runs -
this lets the code avoid intermingling output with other bits of make that
would muck up the JSON.  For now the files are named with the following
convention: makefile-$PID.json where $PID is the pid of the make process
which  created the file. Is this enough? Is it right? I am not sure - it's
interesting. We seem to get 2 files for one directory sometimes - with the
same targets in them - I think it might be a remake.  Anyhow this method
seems to keep everything separated for now.

I've also not mentioned that for the "MakefileName" in the example I
actually have inserted the contents of "$(MAKEFILE_LIST)" as that seems
more correct in a way.

There is an attached json produced by running on make itself - which is all
the testing I've done - this is a hack and probably needs real test data
and a load of tests.

Most of the code is in src/jprint.c.  I had to export some things in
questionable ways and that is one of many reasons why I would never expect
this feature to get back into GNU make proper. I just think it can exist in
a fork and potentially be of use to someone.

Regards,

Tim Murphy

Attachment: makefile-30281.json.gz
Description: application/gzip

Reply via email to