Implement -MD, -MF, -MT, -MQ

Implement the dependency options:

-MF: set the file to which dependencies are written.
-MD: generate dependencies in parallel with compilation.
-MT: set the name of the dependency target.
-MQ: same as -MT, but *attempt* to quote it for Makefile safety.
This commit is contained in:
H. Peter Anvin 2008-05-29 19:09:11 -07:00
parent b037a67e68
commit 07b7b9e15e
3 changed files with 177 additions and 26 deletions

181
nasm.c
View File

@ -38,7 +38,7 @@ struct forwrefinfo { /* info held on forward refs. */
static int get_bits(char *value);
static uint32_t get_cpu(char *cpu_str);
static void parse_cmdline(int, char **);
static void assemble_file(char *);
static void assemble_file(char *, FILE *);
static void register_output_formats(void);
static void report_error_gnu(int severity, const char *fmt, ...);
static void report_error_vc(int severity, const char *fmt, ...);
@ -88,9 +88,12 @@ enum op_type {
op_normal, /* Preprocess and assemble */
op_preprocess, /* Preprocess only */
op_depend, /* Generate dependencies */
op_depend_missing_ok, /* Generate dependencies, missing OK */
};
static enum op_type operating_mode;
/* Dependency flags */
static bool depend_missing_ok = false;
static const char *depend_target = NULL;
static const char *depend_file = NULL;
/*
* Which of the suppressible warnings are suppressed. Entry zero
@ -133,7 +136,7 @@ static const char *suppressed_what[ERR_WARN_MAX+1] = {
* not preprocess their source file.
*/
static void no_pp_reset(char *, int, efunc, evalfunc, ListGen *);
static void no_pp_reset(char *, int, efunc, evalfunc, ListGen *, FILE *);
static char *no_pp_getline(void);
static void no_pp_cleanup(int);
static Preproc no_pp = {
@ -241,6 +244,8 @@ static void define_macros_late(void)
int main(int argc, char **argv)
{
FILE *depends;
time(&official_compile_time);
pass0 = 1;
@ -284,22 +289,39 @@ int main(int argc, char **argv)
/* define some macros dependent of command-line */
define_macros_late();
depends = NULL;
if (depend_file) {
depends = fopen(depend_file, "w");
if (!depends) {
report_error(ERR_FATAL | ERR_NOFILE,
"unable to open dependencies file `%s'",
depend_file);
}
}
if (!depend_target)
depend_target = outname;
switch (operating_mode) {
case op_depend_missing_ok:
pp_include_path(NULL); /* "assume generated" */
/* fall through */
case op_depend:
{
char *line;
preproc->reset(inname, 0, report_error, evaluate, &nasmlist);
if (!depends)
depends = stdout;
if (depend_missing_ok)
pp_include_path(NULL); /* "assume generated" */
preproc->reset(inname, 0, report_error, evaluate, &nasmlist,
depends);
if (outname[0] == '\0')
ofmt->filename(inname, outname, report_error);
ofile = NULL;
fprintf(stdout, "%s: %s", outname, inname);
fprintf(depends, "%s: %s", depend_target, inname);
while ((line = preproc->getline()))
nasm_free(line);
preproc->cleanup(0);
putc('\n', stdout);
}
break;
@ -321,8 +343,12 @@ int main(int argc, char **argv)
location.known = false;
/* pass = 1; */
preproc->reset(inname, 2, report_error, evaluate, &nasmlist);
/* pass = 1; */
preproc->reset(inname, 2, report_error, evaluate, &nasmlist,
depends);
if (depends)
fprintf(depends, "%s: %s", depend_target, inname);
while ((line = preproc->getline())) {
/*
* We generate %line directives if needed for later programs
@ -378,7 +404,7 @@ int main(int argc, char **argv)
ofmt->init(ofile, report_error, define_label, evaluate);
assemble_file(inname);
assemble_file(inname, depends);
if (!terminate_after_phase) {
ofmt->cleanup(using_debug_info);
@ -398,6 +424,12 @@ int main(int argc, char **argv)
break;
}
if (depends) {
putc('\n', depends);
if (depends != stdout)
fclose(depends);
}
if (want_usage)
usage();
@ -448,6 +480,88 @@ static void copy_filename(char *dst, const char *src)
strncpy(dst, src, FILENAME_MAX);
}
/*
* Convert a string to Make-safe form
*/
static char *quote_for_make(const char *str)
{
const char *p;
char *os, *q;
size_t n = 1; /* Terminating zero */
size_t nbs = 0;
if (!str)
return NULL;
for (p = str; *p; p++) {
switch (*p) {
case ' ':
case '\t':
/* Convert N backslashes + ws -> 2N+1 backslashes + ws */
n += nbs + 2;
nbs = 0;
break;
case '$':
case '#':
nbs = 0;
n += 2;
break;
case '\\':
nbs++;
n++;
break;
default:
nbs = 0;
n++;
break;
}
}
/* Convert N backslashes at the end of filename to 2N backslashes */
if (nbs)
n += nbs;
os = q = nasm_malloc(n);
nbs = 0;
for (p = str; *p; p++) {
switch (*p) {
case ' ':
case '\t':
while (nbs--)
*q++ = '\\';
*q++ = '\\';
*q++ = *p;
break;
case '$':
*q++ = *p;
*q++ = *p;
nbs = 0;
break;
case '#':
*q++ = '\\';
*q++ = *p;
nbs = 0;
break;
case '\\':
*q++ = *p;
nbs++;
break;
default:
*q++ = *p;
nbs = 0;
break;
}
}
while (nbs--)
*q++ = '\\';
*q = '\0';
return os;
}
struct textargs {
const char *label;
int value;
@ -709,7 +823,37 @@ static bool process_arg(char *p, char *q)
break;
case 'M':
operating_mode = p[2] == 'G' ? op_depend_missing_ok : op_depend;
switch (p[2]) {
case 0:
case 'M':
operating_mode = op_depend;
break;
case 'G':
operating_mode = op_depend;
depend_missing_ok = true;
break;
case 'D':
depend_file = q;
advance = true;
break;
case 'T':
depend_target = q;
advance = true;
break;
case 'Q':
depend_target = quote_for_make(q);
advance = true;
break;
default:
report_error(ERR_NONFATAL|ERR_NOFILE|ERR_USAGE,
"unknown dependency option `-M%c'", p[2]);
break;
}
if (advance && (!q || !q[0])) {
report_error(ERR_NONFATAL|ERR_NOFILE|ERR_USAGE,
"option `-M%c' requires a parameter", p[2]);
break;
}
break;
case '-':
@ -969,7 +1113,7 @@ static const char *directives[] = {
};
static enum directives getkw(char **directive, char **value);
static void assemble_file(char *fname)
static void assemble_file(char *fname, FILE *depends)
{
char *directive, *value, *p, *q, *special, *line, debugid[80];
insn output_ins;
@ -1013,7 +1157,11 @@ static void assemble_file(char *fname)
raa_free(offsets);
offsets = raa_init();
}
preproc->reset(fname, pass1, report_error, evaluate, &nasmlist);
preproc->reset(fname, pass1, report_error, evaluate, &nasmlist,
pass1 == 2 ? depends : NULL);
if (pass1 == 2 && depends)
fprintf(depends, "%s: %s", depend_target, inname);
globallineno = 0;
if (passn == 1)
location.known = true;
@ -1802,7 +1950,7 @@ static ListGen *no_pp_list;
static int32_t no_pp_lineinc;
static void no_pp_reset(char *file, int pass, efunc error, evalfunc eval,
ListGen * listgen)
ListGen * listgen, FILE *depends)
{
src_set_fname(nasm_strdup(file));
src_set_linnum(0);
@ -1815,6 +1963,7 @@ static void no_pp_reset(char *file, int pass, efunc error, evalfunc eval,
no_pp_list = listgen;
(void)pass; /* placate compilers */
(void)eval; /* placate compilers */
(void)depends; /* placate compilers */
}
static char *no_pp_getline(void)

4
nasm.h
View File

@ -291,7 +291,7 @@ typedef expr *(*evalfunc) (scanner sc, void *scprivate,
#define EXPR_SEGBASE (EXPR_REG_END+4)
/*
* Preprocessors ought to look like this:
* preprocessors ought to look like this:
*/
typedef struct preproc_ops {
/*
@ -299,7 +299,7 @@ typedef struct preproc_ops {
* of the pass, an error reporting function, an evaluator
* function, and a listing generator to talk to.
*/
void (*reset) (char *, int, efunc, evalfunc, ListGen *);
void (*reset) (char *, int, efunc, evalfunc, ListGen *, FILE *);
/*
* Called to fetch a line of preprocessed source. The line

View File

@ -327,6 +327,7 @@ static efunc _error; /* Pointer to client-provided error reporting fu
static evalfunc evaluate;
static int pass; /* HACK: pass 0 = generate dependencies only */
static FILE *deplist; /* Write dependencies to this FILE */
static uint64_t unique; /* unique identifier numbers */
@ -1275,13 +1276,13 @@ static FILE *inc_fopen(char *file)
strcpy(combine, prefix);
strcat(combine, file);
fp = fopen(combine, "r");
if (pass == 0 && fp) {
if (fp && deplist) {
namelen += strlen(combine) + 1;
if (namelen > 62) {
printf(" \\\n ");
fprintf(deplist, " \\\n ");
namelen = 2;
}
printf(" %s", combine);
fprintf(deplist, " %s", combine);
}
nasm_free(combine);
if (fp)
@ -1293,13 +1294,13 @@ static FILE *inc_fopen(char *file)
if (!prefix) {
/* -MG given and file not found */
if (pass == 0) {
if (deplist) {
namelen += strlen(file) + 1;
if (namelen > 62) {
printf(" \\\n ");
namelen = 2;
fprintf(deplist, " \\\n ");
namelen = 2;
}
printf(" %s", file);
fprintf(deplist, " %s", file);
}
return NULL;
}
@ -3733,7 +3734,7 @@ static void error(int severity, const char *fmt, ...)
static void
pp_reset(char *file, int apass, efunc errfunc, evalfunc eval,
ListGen * listgen)
ListGen * listgen, FILE * adeplist)
{
_error = errfunc;
cstk = NULL;
@ -3762,6 +3763,7 @@ pp_reset(char *file, int apass, efunc errfunc, evalfunc eval,
list = listgen;
evaluate = eval;
pass = apass;
deplist = adeplist;
}
static char *pp_getline(void)