master xplshn/aruu / cmd / dev / ninqu / main.c
  1#include "ninqu.h"
  2
  3#include <limits.h>
  4#include <stdio.h>
  5#include <stdlib.h>
  6#include <string.h>
  7#include <unistd.h>
  8
  9static void
 10usage(void)
 11{
 12  eprintf(
 13      "usage: %s [-jN] [-f manifest] [-C dir] [-Dvar=val]... [-S] [-F] [-G ninja] "
 14      "[target|meta.target ...]\n"
 15      "       %s query (features|groups|metas|rules|graph) [arg]\n",
 16      argv0,
 17      argv0
 18  );
 19}
 20
 21int
 22main(int argc, char *argv[])
 23{
 24  const char    *manifest      = "ninqu.rules";
 25  int            features_mode = 0;
 26  int            query_mode    = 0;
 27  const char    *query_sub     = NULL;
 28  const char    *query_arg     = NULL;
 29  const char    *generator     = NULL;
 30  int            i;
 31  struct StrList wanted = {0};
 32
 33  /* detect query before ARGBEGIN so it is not parsed as a target */
 34  if (argc >= 2 && strcmp(argv[1], "query") == 0) {
 35    query_mode = 1;
 36    if (argc < 3)
 37      usage();
 38    query_sub = argv[2];
 39    query_arg = (argc >= 4) ? argv[3] : NULL;
 40    for (i = 3; i < argc; i++) {
 41      if (argv[i][0] == '-' && argv[i][1] == 'f')
 42        manifest = argv[i][2] ? argv[i] + 2 : argv[++i];
 43      else if (argv[i][0] == '-' && argv[i][1] == 'C') {
 44        if (chdir(argv[i][2] ? argv[i] + 2 : argv[++i]) != 0)
 45          eprintf("chdir:");
 46      } else if (argv[i][0] == '-' && argv[i][1] == 'D') {
 47        char *spec = argv[i][2] ? argv[i] + 2 : argv[++i];
 48        char *eq   = strchr(spec, '=');
 49        if (!eq)
 50          usage();
 51        *eq = '\0';
 52        kv_set_cli(spec, eq + 1);
 53      }
 54    }
 55  } else {
 56    ARGBEGIN
 57    {
 58      case 'j':
 59        jobs_n = (int)estrtonum(EARGF(usage()), 1, INT_MAX);
 60        break;
 61      case 'f':
 62        manifest = EARGF(usage());
 63        break;
 64      case 'C':
 65        if (chdir(EARGF(usage())) != 0)
 66          eprintf("chdir:");
 67        break;
 68      case 'D': {
 69        char *spec = EARGF(usage());
 70        char *eq   = strchr(spec, '=');
 71        if (!eq)
 72          usage();
 73        *eq = '\0';
 74        kv_set_cli(spec, eq + 1);
 75        break;
 76      }
 77      case 'S':
 78        summary_mode = 1;
 79        break;
 80      case 'F':
 81        features_mode = 1;
 82        break;
 83      case 'G':
 84        generator = EARGF(usage());
 85        break;
 86      default:
 87        usage();
 88    }
 89    ARGEND
 90
 91    for (i = 0; i < argc; i++)
 92      sl_push(&wanted, argv[i]);
 93  }
 94
 95  load_file(manifest);
 96  resolve_all_bareword_deps();
 97
 98  if (query_mode) {
 99    do_query(query_sub, query_arg);
100    return 0;
101  }
102  if (features_mode) {
103    do_features();
104    return 0;
105  }
106
107  if (wanted.n == 0)
108    build_default_group();
109  else
110    for (i = 0; i < wanted.n; i++)
111      resolve_wanted(wanted.v[i]);
112
113  resolve_deps();
114
115  if (generator) {
116    const struct Backend *be = backend_by_name(generator);
117    if (!be)
118      eprintf("ninqu: unknown generator '%s'\n", generator);
119    be->emit(be->file, &wanted);
120    return failed_any ? 1 : 0;
121  }
122
123  /* BACKEND=internal forces executor. otherwise generate file and exec backend binary */
124  if (strcmp(kv_get_or("BACKEND", "auto"), "internal") != 0) {
125    char                 *bin;
126    const struct Backend *be = backend_resolve(&bin);
127    if (be) {
128      be->emit(be->file, &wanted);
129      if (failed_any)
130        return 1;
131      backend_exec(be, bin, &wanted);
132    }
133  }
134
135  schedule_and_run();
136
137  return failed_any ? 1 : 0;
138}