Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
108 changes: 107 additions & 1 deletion src/tup/parser.c
Original file line number Diff line number Diff line change
Expand Up @@ -240,10 +240,16 @@ int parse(struct node *n, struct graph *g, struct timespan *retts, int refactori
tf.g = g;
tf.refactoring = refactoring;
if(tf.variant->root_variant) {
char cmd[] = "!tup-variant = |> |>";
tf.srctent = NULL;
if(parse_bang_definition(&tf, cmd, 0) < 0)
return -1;
} else {
char cmd[] = "!tup-variant = |> tup-variant |> %b";
if(variant_get_srctent(tf.variant, tf.tupid, &tf.srctent) < 0)
goto out_server_stop;
if(parse_bang_definition(&tf, cmd, 0) < 0)
return -1;
}
tf.ign = 0;
tf.circular_dep_error = 0;
Expand Down Expand Up @@ -3239,6 +3245,10 @@ int do_rule(struct tupfile *tf, struct rule *r, struct name_list *nl,
struct tup_entry *group = NULL;
struct tup_entry *old_group = NULL;
int command_modified = 0;
int is_variant_copy = 0;

if(strcmp(r->command, "tup-variant") == 0)
is_variant_copy = 1;

/* t3017 - empty rules are just pass-through to get the input into the
* bin.
Expand Down Expand Up @@ -3335,7 +3345,7 @@ int do_rule(struct tupfile *tf, struct rule *r, struct name_list *nl,
while(onle->extlesslen > 0 && onle->path[onle->extlesslen] != '.')
onle->extlesslen--;

if(tf->srctent) {
if(tf->srctent && !is_variant_copy) {
struct tup_entry *tent;
if(tup_db_select_tent(tf->srctent->tnode.tupid, onle->path, &tent) < 0)
return -1;
Expand Down Expand Up @@ -3389,6 +3399,54 @@ int do_rule(struct tupfile *tf, struct rule *r, struct name_list *nl,
del_pl(pl, oplist);
}

if(is_variant_copy) {
char *path;
int len;
int dfd;
int rc;

onle = TAILQ_FIRST(&onl.entries);
nle = TAILQ_FIRST(&r->inputs.entries);
if(onl.num_entries != 1 || nl->num_entries != 1) {
fprintf(tf->f, "tup error: Expected only one input/output for tup-variant copy.\n");
return -1;
}
if(get_relative_dir(NULL, NULL, NULL, onle->tent->tnode.tupid, nle->tent->tnode.tupid, &len) < 0)
return -1;
path = malloc(len);
if(!path) {
perror("malloc");
return -1;
}
if(get_relative_dir(NULL, NULL, path, onle->tent->tnode.tupid, nle->tent->tnode.tupid, &len) < 0){
free(path);
return -1;
}
dfd = tup_entry_open(onle->tent->parent);
if(dfd < 0){
free(path);
return -1;
}
rc = symlinkat(path, dfd, onle->path);
if(close(dfd) < 0) {
perror("close(dfd)");
free(path);
return -1;
}
if(rc < 0) {
if(errno == EEXIST){
free(path);
return 0;
}
perror(path);
fprintf(tf->f, "tup error: Unable to create symlink for variant copy.\n");
free(path);
return -1;
}
free(path);
return 0;
}

tcmd = tup_printf(tf, r->command, -1, nl, &onl, ext, extlen, r->extra_command);
if(!tcmd)
return -1;
Expand Down Expand Up @@ -3978,6 +4036,30 @@ static char *eval(struct tupfile *tf, const char *string, int allow_nodes)
return NULL;
}
len += clen;
} else if(rparen-var == 7 &&
strncmp(var, "TUP_RWD", 7) == 0) {
tupid_t root;
int clen = 0;
root = find_dir_tupid(get_tup_top());
if(get_relative_dir(NULL, NULL, NULL, root, tf->tupid, &clen) < 0) {
fprintf(tf->f, "tup internal error: Unable to find relative directory from ID %lli -> %lli\n", root, tf->tupid);
tup_db_print(tf->f, root);
tup_db_print(tf->f, tf->tupid);
return NULL;
}
len += clen;
} else if(rparen-var == 8 &&
strncmp(var, "TUP_ROOT", 8) == 0) {
tupid_t root;
int clen = 0;
root = find_dir_tupid(get_tup_top());
if(get_relative_dir(NULL, NULL, NULL, tf->tupid, root, &clen) < 0) {
fprintf(tf->f, "tup internal error: Unable to find relative directory from ID %lli -> %lli\n", tf->tupid, root);
tup_db_print(tf->f, tf->tupid);
tup_db_print(tf->f, root);
return NULL;
}
len += clen;
} else if(rparen - var > 7 &&
strncmp(var, "CONFIG_", 7) == 0) {
const char *atvar;
Expand Down Expand Up @@ -4090,6 +4172,30 @@ static char *eval(struct tupfile *tf, const char *string, int allow_nodes)
return NULL;
}
p += clen;
} else if(rparen-var == 7 &&
strncmp(var, "TUP_RWD", 7) == 0) {
tupid_t root;
int clen = 0;
root = find_dir_tupid(get_tup_top());
if(get_relative_dir(NULL, NULL, p, root, tf->tupid, &clen) < 0) {
fprintf(tf->f, "tup internal error: Unable to find relative directory from ID %lli -> %lli\n", root, tf->tupid);
tup_db_print(tf->f, root);
tup_db_print(tf->f, tf->tupid);
return NULL;
}
p += clen;
} else if(rparen-var == 8 &&
strncmp(var, "TUP_ROOT", 8) == 0) {
tupid_t root;
int clen = 0;
root = find_dir_tupid(get_tup_top());
if(get_relative_dir(NULL, NULL, p, tf->tupid, root, &clen) < 0) {
fprintf(tf->f, "tup internal error: Unable to find relative directory from ID %lli -> %lli\n", tf->tupid, root);
tup_db_print(tf->f, tf->tupid);
tup_db_print(tf->f, root);
return NULL;
}
p += clen;
} else if(rparen - var > 7 &&
strncmp(var, "CONFIG_", 7) == 0) {
const char *atvar;
Expand Down
10 changes: 10 additions & 0 deletions tup.1
Original file line number Diff line number Diff line change
Expand Up @@ -357,6 +357,8 @@ A command string can begin with the special sequence ^\ TEXT^, which will tell t
.fi
.IP
A command string can also begin with the special character '!', in which case the !-macro specified will be substituted in for the actual command. See the !-macro definition later. Commands can also be blank, which is useful to put all the input files in a {bin} for a later rule.
.IP
The !tup-variant macro is treated specially by Tup. If there are no active variants, the macro is a no-op. When building a variant, Tup will create symlinks to the given normal input files inside the variant build directory. This can be useful if you want a normal file to be present in variant build directories.
.TP
.B outputs
The outputs section specifies the files that will be written to by the command. Only one command can write to a specific file, but a single command can output multiple files (such as how a bison command will output both a .c and .h file). The output can use any %-flags except %o. Once a file is specified in an output section, it is put into the tup database. Any following rules can use that file as an input, even if it doesn't exist in the filesystem yet.
Expand Down Expand Up @@ -477,6 +479,12 @@ Append "value" to the end of the current value of "var". If "var" has not been s
.TP
.B $(TUP_CWD)
The special $-variable TUP_CWD is always set to the path relative to the Tupfile currently parsed. It can change value when including a file in a different directory. For example, if you "include ../foo.tup", then TUP_CWD will be set to ".." when parsing foo.tup. This lets foo.tup specify flags like "CFLAGS += -I$(TUP_CWD)", and CFLAGS will always have the -I directory where foo.tup is located, no matter if it was included as "../foo.tup" or "../../foo.tup" or "subdir/foo.tup". For an alternative to $(TUP_CWD) when referring to files, see the section on &-variables below.
.TP
.B $(TUP_ROOT)
The special $-variable TUP_ROOT is always set to the path relative from the Tupfile currently parsed to root directory of a project.
.TP
.B $(TUP_RWD)
The special $-variable TUP_RWD is always set to the path relative from root directory of a project to the Tupfile currently parsed.
.P
No other special $-variables exist yet, but to be on the safe side you should assume that all variables named TUP_* are reserved.
.TP
Expand Down Expand Up @@ -532,6 +540,8 @@ include_rules

.fi
You will only want to specify the output parameter in either the !-macro or the :-rule that uses it, but not both. If you specify any inputs in the !-macro, they would usually be order-only inputs. For example, if you have a !cc rule where you are using a compiler that has been generated by tup, you can list the compiler file in the order-only list of the !-macro. The compiler file will then become an input dependency for any :-rule that uses the macro.
.IP
Tup reserves all !-macro names which begin "!tup-".
.TP
.B include file
Reads the specified file and continues parsing almost as if that file was pasted inline in the current Tupfile. Only regular files are allowed to be included -- attempting to include a generated file is an error. Any include statements that occur in the included file will be parsed relative to the included file's directory.
Expand Down