diff options
author | Vladimir Azarov <avm@intermediate-node.net> | 2024-11-26 21:50:24 +0100 |
---|---|---|
committer | Vladimir Azarov <avm@intermediate-node.net> | 2024-11-26 21:50:24 +0100 |
commit | f7789809675968b753f9b40e298d23b2f7ab4c61 (patch) | |
tree | afc937002cf57e0791aa4d69d7405662ee7ca0ae /tools/make.c | |
parent | f777f6a9450d2bd5fc7ec531e6fb69f79942499a (diff) |
Command-line variable assignment
Diffstat (limited to 'tools/make.c')
-rw-r--r-- | tools/make.c | 238 |
1 files changed, 154 insertions, 84 deletions
diff --git a/tools/make.c b/tools/make.c index 0b1f704..0b82cd0 100644 --- a/tools/make.c +++ b/tools/make.c @@ -1,3 +1,9 @@ +/* + * This file is part of musl-esp: modified version of Musl libc library. + * musl-esp in general and this file specifically are available under + * MIT license. See COPYRIGHT file. + */ + #include "common.h" enum { @@ -11,12 +17,6 @@ enum { const char *debug_prx = ">>> "; -struct conf { - char *target; - char *makefile; - int debug_mode; -}; - struct line { int linenum; struct str str; @@ -58,9 +58,15 @@ struct rule_details { int lineno; }; +enum { + vs_makefile, + vs_cmdargs +}; + struct vt_cell { struct str vname; struct str value; + char scope; }; struct vtable { @@ -180,21 +186,21 @@ static struct vt_cell *vtable_getcell(struct vtable *t, struct str *key) } static void vtable_update(struct vtable *vt, struct str *key, - int alloc_name, struct str *value) + int alloc_name, struct str *value, char scope) { struct vt_cell *cell = vtable_getcell(vt, key); if (cell->vname.start == NULL) { ++vt->cells_occupied; if ((double)vt->cells_occupied / hash_table_size >= 0.7) error("vtable: threshold reached"); - } - if (cell->vname.start == NULL) { + if (alloc_name) strdup(&cell->vname, key, 0); else cell->vname = *key; } cell->value = *value; + cell->scope = scope; } static struct str *vtable_find(struct vtable *vt, struct str *key) @@ -233,37 +239,6 @@ static int rtable_find(struct rtable *rt, struct str *key, return 1; } -static void parse_cmdargs(struct conf *conf, char **argv) -{ - ++argv; - for (; argv[0]; ++argv) { - if (argv[0][0] == '-') { - if (argv[0][1] == 'f' && argv[0][2] == 0) { - if (argv[1] == NULL) - error("-f: missing file name"); - conf->makefile = argv[1]; - ++argv; - } else if (argv[0][1] == 'C' && argv[0][2] == 0) { - if (argv[1] == NULL) - error("-C: missing dir"); - if (chdir(argv[1]) == -1) - syscall_error(argv[1]); - ++argv; - } else if (argv[0][1] == 'd' && argv[0][2] == 0) { - conf->debug_mode = 1; - } else { - error("%s: unknown flag", argv[0]); - } - } else { - if (conf->target) - error("%s: target already provided"); - conf->target = argv[0]; - } - } - if (conf->makefile == NULL) - conf->makefile = "Makefile"; -} - static char *mmap_makefile(char *fname) { int fd = open(fname, O_RDONLY, 0); @@ -287,6 +262,15 @@ syserr: return NULL; /* unreachable */ } +static char *strchr(char *s, char c) +{ + for (; *s; ++s) { + if (*s == c) + return s; + } + return NULL; +} + static int readline(char **makefile, struct line *line) { static int linenum = 1; @@ -1724,45 +1708,73 @@ static void make_full_vname(struct buf *dest, struct str *prx, buf_puts(dest, vname); } -static void set_single_var(struct vtable *vt, int mode, struct str *prefix, - struct str *vname,struct str *value, int alloc_name) +struct variable { + struct str name; + struct strbuf *goals; + struct str *value; + char scope; + + int linenum; + struct vtable *vt; +}; + +static int check_policy(struct variable *var, struct str *name) +{ + struct vt_cell *cell = vtable_getcell(var->vt, name); + if (cell->vname.start == NULL) + return 1; + + if (var->scope == vs_makefile) { + if (cell->scope == vs_makefile) + lerror(var->linenum, "%S: variable redefinition", + name); + return 0; + } + return 1; +} + +static void set_single_var(struct variable *var, struct str *goal, int mode) { static char localbuf[buf_static_size]; struct buf buf; - struct str tmp; + struct str fullname; + /* TODO: Why do we need to alloc for goal specific assignments */ + int alloc = goal ? 1 : 0; buf_static_init(buf, localbuf, buf_static_size); - if (prefix != NULL) { - make_full_vname(&buf, prefix, vname); - tmp = (struct str) { buf.start, buf.cur }; + if (goal != NULL) { + make_full_vname(&buf, goal, &var->name); + fullname = (struct str) { buf.start, buf.cur }; } else { - tmp = *vname; + fullname = var->name; } + if (mode == svmode_set) { - vtable_update(vt, &tmp, alloc_name, value); + if (check_policy(var, &fullname) == 0) + return; + /* Double work, but I do not think we should even bother */ + vtable_update(var->vt, &fullname, alloc, var->value, var->scope); } else { struct str newval; - struct str *oldval = vtable_find(vt, &tmp); + struct str *oldval = vtable_find(var->vt, &fullname); if (oldval == NULL) - oldval = vtable_find(vt, vname); - str_combine(&newval, oldval, value); - vtable_update(vt, &tmp, alloc_name, &newval); + oldval = vtable_find(var->vt, &var->name); + str_combine(&newval, oldval, var->value); + vtable_update(var->vt, &fullname, alloc, &newval, var->scope); } } -static void setvar(struct vtable *vt, int mode, struct strbuf *targets, - struct str *vname, struct str *value) +static void setvar(struct variable *var, int mode) { - trim(value); + trim(var->value); - if (targets != NULL) { + if (var->goals != NULL) { int i; - for (i = 0; i < targets->len; ++i) { - set_single_var(vt, mode, &targets->buf[i].str, vname, value, 1); - } + for (i = 0; i < var->goals->len; ++i) + set_single_var(var, &var->goals->buf[i].str, mode); } else { - set_single_var(vt, mode, NULL, vname, value, 0); + set_single_var(var, NULL, mode); } } @@ -1773,32 +1785,37 @@ static int is_followed(struct line *line, char c) static void follows(struct line *line, char c) { - if (is_followed(line, c)) { - line->str.start += 2; + if (is_followed(line, c)) return; - } lerror(line->linenum, "expected %c after %c", c, line->str.start[0]); } -static void parse_assignment(struct world *world, struct strbuf *targets, - struct buf *buf, struct line *line) +static void parse_assignment(struct world *world, struct strbuf *goals, + struct buf *buf, struct line *line, char scope) { - struct str vname = { buf->start, buf->cur }; + struct variable var = { + { buf->start, buf->cur }, + goals, + &line->str, + scope, + + line->linenum, + &world->vtable + }; - trim(&vname); - if (!valid_var_name(&vname)) { + trim(&var.name); + if (!valid_var_name(&var.name)) { lerror(line->linenum, "[%S]: invalid variable name", - &vname); + &var.name); } - if (line->str.start[0] == '+') { + if (var.value->start[0] == '+') { follows(line, '='); - setvar(&world->vtable, svmode_append, targets, &vname, - &line->str); + var.value->start += 2; + setvar(&var, svmode_append); } else { - ++line->str.start; - setvar(&world->vtable, svmode_set, targets, &vname, - &line->str); + ++var.value->start; + setvar(&var, svmode_set); } } @@ -1975,7 +1992,7 @@ static void handle_target_spec(struct world *world, struct buf *buf, if (*line->str.start == ':') lerror(line->linenum, "expected target-specific var"); - parse_assignment(world, &rule->targets, buf, line); + parse_assignment(world, &rule->targets, buf, line, vs_makefile); } static void parse_rule(struct world *world, struct buf *buf, @@ -2016,7 +2033,7 @@ static int parse_toplev(struct world *world) } else if (*line.str.start == ':') { parse_rule(world, buf, &line); } else { - parse_assignment(world, NULL, buf, &line); + parse_assignment(world, NULL, buf, &line, vs_makefile); } return 1; } @@ -2027,14 +2044,11 @@ static void parse(struct world *world) ; } -static void world_init(struct world *world, struct conf *conf, char **envp) +static void world_init(struct world *world, char **envp) { - world->makefile = mmap_makefile(conf->makefile); - world->target = conf->target ? STR(conf->target) : CSTR(""); world->envp = envp; world->pat_rule_num = 0; - world->debug_mode = conf->debug_mode; vtable_init(&world->vtable); rtable_init(&world->rtable); @@ -2427,6 +2441,63 @@ static void exec(struct world *world) exec_target(world, &world->target, &info); } +static int is_assignment(char *arg, char **equal_sign) +{ + char *tmp = strchr(arg, '='); + if (tmp == NULL) + return 0; + *equal_sign = tmp; + return 1; +} + +static void parse_cmdarg_assignment(struct world *world, char *arg, + char *equal_sign) +{ + struct buf buf = { arg, equal_sign, equal_sign }; + char *end = equal_sign + strzlen(equal_sign); + struct line line = { 0, { equal_sign, end } }; + + parse_assignment(world, NULL, &buf, &line, vs_cmdargs); +} + +static void parse_cmdargs(struct world *world, char **argv) +{ + char *makefile = "Makefile"; + char *target = NULL; + char *equal_sign; + + ++argv; + for (; argv[0]; ++argv) { + if (argv[0][0] == '-') { + if (argv[0][1] == 'f' && argv[0][2] == 0) { + if (argv[1] == NULL) + error("-f: missing file name"); + makefile = argv[1]; + ++argv; + } else if (argv[0][1] == 'C' && argv[0][2] == 0) { + if (argv[1] == NULL) + error("-C: missing dir"); + if (chdir(argv[1]) == -1) + syscall_error(argv[1]); + ++argv; + } else if (argv[0][1] == 'd' && argv[0][2] == 0) { + world->debug_mode = 1; + } else { + error("%s: unknown flag", argv[0]); + } + } else if (is_assignment(argv[0], &equal_sign)) { + parse_cmdarg_assignment(world, argv[0], + equal_sign); + } else { + if (target) + error("%s: target already provided"); + target = argv[0]; + } + } + world->makefile = mmap_makefile(makefile); + world->target = target ? STR(target) : CSTR(""); +} + static void print_program_time(int debug) { struct rusage rusage; @@ -2442,11 +2513,10 @@ static void print_program_time(int debug) int main(int argc, char **argv, char **envp) { struct world world; - struct conf conf = { NULL, NULL }; - parse_cmdargs(&conf, argv); + world_init(&world, envp); + parse_cmdargs(&world, argv); - world_init(&world, &conf, envp); parse(&world); exec(&world); |