More makedep features (#80)

yasm.c: Added -MD, -MT and -MP options similar to gcc. Also added --makedep-dos2unix-slash for helping users of NUG make (and similar) on Windows. The -MD option does both assembling and Makefile dependency generation in one go, which convenient and a little quicker.

nasm-preproc.c: Have to always gather dependencies to support -MD. Minimal cost.

Co-authored-by: knut st. osmundsen <bird-skylake@anduin.net>
This commit is contained in:
bird2tori 2023-05-13 06:22:36 +02:00 committed by GitHub
parent 563a03be81
commit 241bf4c42c
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
2 changed files with 188 additions and 33 deletions

View file

@ -70,6 +70,10 @@ static int special_options = 0;
static int preproc_only = 0;
static unsigned int force_strict = 0;
static int generate_make_dependencies = 0;
static int makedep_with_empty_recipts = 0;
static int makedep_dos2unix_slash = 0;
/*@null@*/ /*@only@*/ static const char *makedep_out_filename = NULL;
/*@null@*/ /*@only@*/ static const char *makedep_target = NULL;
static int warning_error = 0; /* warnings being treated as errors */
static FILE *errfile;
/*@null@*/ /*@only@*/ static char *error_filename = NULL;
@ -105,7 +109,11 @@ static int preproc_only_handler(char *cmd, /*@null@*/ char *param, int extra);
static int opt_include_option(char *cmd, /*@null@*/ char *param, int extra);
static int opt_preproc_option(char *cmd, /*@null@*/ char *param, int extra);
static int opt_ewmsg_handler(char *cmd, /*@null@*/ char *param, int extra);
static int opt_makedep_and_assemble_handler(char *cmd, /*@null@*/ char *param, int extra);
static int opt_makedep_empty_handler(char *cmd, /*@null@*/ char *param, int extra);
static int opt_makedep_target_handler(char *cmd, /*@null@*/ char *param, int extra);
static int opt_makedep_handler(char *cmd, /*@null@*/ char *param, int extra);
static int opt_makedep_dos2unix_slash_handler(char *cmd, /*@null@*/ char *param, int extra);
static int opt_prefix_handler(char *cmd, /*@null@*/ char *param, int extra);
static int opt_suffix_handler(char *cmd, /*@null@*/ char *param, int extra);
#if defined(CMAKE_BUILD) && defined(BUILD_SHARED_LIBS)
@ -137,6 +145,10 @@ static void apply_preproc_standard_macros(const yasm_stdmac *stdmacs);
static void apply_preproc_saved_options(void);
static void print_list_keyword_desc(const char *name, const char *keyword);
#ifndef MAX
# define MAX(a, b) ( ((a) > (b)) ? (a) : (b) )
#endif
/* values for special_options */
#define SPECIAL_SHOW_HELP 0x01
#define SPECIAL_SHOW_VERSION 0x02
@ -178,8 +190,18 @@ static opt_option options[] =
N_("inhibits warning messages"), NULL },
{ 'W', NULL, 0, opt_warning_handler, 0,
N_("enables/disables warning"), NULL },
{ 'M', NULL, 0, opt_makedep_handler, 0,
{ 0, "MD", 1, opt_makedep_and_assemble_handler, 0,
N_("generate Makefile dependencies and assemble normally"),
N_("file")},
{ 0, "MP", 0, opt_makedep_empty_handler, 0,
N_("generate empty Makefile recipts for the include files"), NULL },
{ 0, "MT", 1, opt_makedep_target_handler, 0,
N_("the Makefile target to associate the dependencies with"),
N_("target")},
{ 'M', NULL, 0, opt_makedep_handler, 0, /* -M must come after -MD and -MP'! */
N_("generate Makefile dependencies on stdout"), NULL },
{ 0, "makedep-dos2unix-slash", 0, opt_makedep_dos2unix_slash_handler, 0,
N_("convert DOS to UNIX slashes in Makefile dependencies file"), NULL },
{ 'Z', NULL, 1, opt_error_file, 0,
N_("redirect error messages to file"), N_("file") },
{ 's', NULL, 0, opt_error_stdout, 0,
@ -247,12 +269,129 @@ typedef struct constcharparam {
static constcharparam_head preproc_options;
static char *
dos2unix_slash(char *path)
{
char *slash = strchr(path, '\\');
while (slash) {
*slash++ = '/';
slash = strchr(slash, '\\');
}
return path;
}
static int
do_generate_make_dependencies(void)
{
size_t empty_recipts_alloc = 0;
size_t empty_recipts_len = 0;
char *empty_recipts = NULL;
char *preproc_buf;
size_t linelen;
size_t got;
FILE *depout = stdout;
const char *target;
/* Open the -MD <file>. */
if ( makedep_out_filename != NULL
&& strcmp(makedep_out_filename, "-") != 0) {
depout = open_file(makedep_out_filename, "wt");
if (!depout)
return EXIT_FAILURE;
}
/* -MT (and later -MQ?) can be used to specify the target name.
If not given, fall back on the object file. */
target = makedep_target ? makedep_target : obj_filename;
/* Make sure preproc_buf is large enough for either of the main
file names to avoid checking later (very ulikely that it isn't). */
linelen = strlen(target);
got = strlen(in_filename);
preproc_buf = yasm_xmalloc(MAX(PREPROC_BUF_SIZE, MAX(got, linelen) + 1));
/* The target (the object file) to add the dependencies to. */
if (!makedep_dos2unix_slash || makedep_target == NULL)
fputs(target, depout);
else
fputs(dos2unix_slash(memcpy(preproc_buf, target, linelen + 1)),
depout);
/* The source file (no empty rule for it, thus the code duplication). */
linelen += 2 + got;
if (linelen <= 72)
fputs(": ", depout);
else {
fputs(": \\\n ", depout);
linelen = 1 + got;
}
if (!makedep_dos2unix_slash)
fwrite(in_filename, got, 1, depout);
else
fwrite(dos2unix_slash(memcpy(preproc_buf, in_filename, got + 1)),
got, 1, depout);
/* Now the include files. */
while ((got = yasm_preproc_get_included_file(cur_preproc, preproc_buf,
PREPROC_BUF_SIZE)) != 0) {
linelen += 1 + got;
if (linelen <= 72)
fputc(' ', depout);
else {
fputs(" \\\n ", depout);
linelen = 1 + got;
}
if (makedep_dos2unix_slash)
dos2unix_slash(preproc_buf);
fwrite(preproc_buf, got, 1, depout);
if (makedep_with_empty_recipts) {
/* We only get one shot at each include file, so we generate the
dummy recipts in a buffer while we're writing the dependencies
for the object file. (The empty recipts makes make shut up
about deleted includes.) */
static const char empty_tail[] = ":\n\n";
size_t cur_len = empty_recipts_len;
empty_recipts_len = cur_len + got + sizeof(empty_tail) - 1;
if (empty_recipts_len >= empty_recipts_alloc) {
if (empty_recipts_alloc == 0)
empty_recipts_alloc = 4096;
while (empty_recipts_len >= empty_recipts_alloc)
empty_recipts_alloc *= 2;
empty_recipts = yasm_xrealloc(empty_recipts,
empty_recipts_alloc);
}
memcpy(&empty_recipts[cur_len], preproc_buf, got);
cur_len += got;
memcpy(&empty_recipts[cur_len], empty_tail, sizeof(empty_tail));
}
}
fputc('\n', depout);
yasm_xfree(preproc_buf);
if (empty_recipts) {
fputc('\n', depout);
fwrite(empty_recipts, empty_recipts_len, 1, depout);
yasm_xfree(empty_recipts);
}
if ( depout != stdout
&& fclose(depout) != 0) {
print_error(_("error writing `%s'"), makedep_out_filename);
return EXIT_FAILURE;
}
return 0;
}
static int
do_preproc_only(void)
{
yasm_linemap *linemap;
char *preproc_buf;
size_t got;
const char *base_filename;
FILE *out = NULL;
yasm_errwarns *errwarns = yasm_errwarns_create();
@ -301,25 +440,7 @@ do_preproc_only(void)
/* Pre-process until done */
if (generate_make_dependencies) {
size_t totlen;
preproc_buf = yasm_xmalloc(PREPROC_BUF_SIZE);
fprintf(stdout, "%s: %s", obj_filename, in_filename);
totlen = strlen(obj_filename)+2+strlen(in_filename);
while ((got = yasm_preproc_get_included_file(cur_preproc, preproc_buf,
PREPROC_BUF_SIZE)) != 0) {
totlen += got;
if (totlen > 72) {
fputs(" \\\n ", stdout);
totlen = 2;
}
fputc(' ', stdout);
fwrite(preproc_buf, got, 1, stdout);
}
fputc('\n', stdout);
yasm_xfree(preproc_buf);
do_generate_make_dependencies();
} else {
while ((preproc_buf = yasm_preproc_get_line(cur_preproc)) != NULL) {
fputs(preproc_buf, out);
@ -573,6 +694,10 @@ do_assemble(void)
fclose(list);
}
/* Generate make dependency. */
if (generate_make_dependencies)
do_generate_make_dependencies();
yasm_errwarns_output_all(errwarns, linemap, warning_error,
print_yasm_error, print_yasm_warning);
@ -1170,6 +1295,32 @@ opt_ewmsg_handler(/*@unused@*/ char *cmd, char *param, /*@unused@*/ int extra)
return 0;
}
static int
opt_makedep_and_assemble_handler(/*@unused@*/ char *cmd, char *param,
/*@unused@*/ int extra)
{
generate_make_dependencies = 1;
makedep_out_filename = param;
return 0;
}
static int
opt_makedep_empty_handler(/*@unused@*/ char *cmd, /*@unused@*/ char *param,
/*@unused@*/ int extra)
{
makedep_with_empty_recipts = 1;
return 0;
}
static int
opt_makedep_target_handler(/*@unused@*/ char *cmd, char *param,
/*@unused@*/ int extra)
{
makedep_target = param;
return 0;
}
static int
opt_makedep_handler(/*@unused@*/ char *cmd, /*@unused@*/ char *param,
/*@unused@*/ int extra)
@ -1181,6 +1332,14 @@ opt_makedep_handler(/*@unused@*/ char *cmd, /*@unused@*/ char *param,
return 0;
}
static int
opt_makedep_dos2unix_slash_handler(/*@unused@*/ char *cmd, /*@unused@*/ char *param,
/*@unused@*/ int extra)
{
makedep_dos2unix_slash = 1;
return 0;
}
static int
opt_prefix_handler(/*@unused@*/ char *cmd, char *param, /*@unused@*/ int extra)
{

View file

@ -151,7 +151,8 @@ nasm_preproc_create(const char *in_filename, yasm_symtab *symtab,
nasm_symtab = symtab;
cur_lm = lm;
cur_errwarns = errwarns;
preproc_deps = NULL;
preproc_deps = yasm_xmalloc(sizeof(struct preproc_dep_head));
STAILQ_INIT(preproc_deps);
done_dep_preproc = 0;
preproc_nasm->line = NULL;
preproc_nasm->file_name = NULL;
@ -176,8 +177,12 @@ nasm_preproc_destroy(yasm_preproc *preproc)
if (preproc_nasm->in)
fclose(preproc_nasm->in);
yasm_xfree(preproc);
if (preproc_deps)
yasm_xfree(preproc_deps);
while (!STAILQ_EMPTY(preproc_deps)) {
preproc_dep *dep = STAILQ_FIRST(preproc_deps);
STAILQ_REMOVE_HEAD(preproc_deps, link);
yasm_xfree(dep->name);
yasm_xfree(dep);
}
yasm_xfree(nasm_src_set_fname(NULL));
}
@ -222,10 +227,6 @@ nasm_preproc_add_dep(char *name)
{
preproc_dep *dep;
/* If not processing dependencies, simply return */
if (!preproc_deps)
return;
/* Save in preproc_deps */
dep = yasm_xmalloc(sizeof(preproc_dep));
dep->name = yasm__xstrdup(name);
@ -236,11 +237,6 @@ static size_t
nasm_preproc_get_included_file(yasm_preproc *preproc, /*@out@*/ char *buf,
size_t max_size)
{
if (!preproc_deps) {
preproc_deps = yasm_xmalloc(sizeof(struct preproc_dep_head));
STAILQ_INIT(preproc_deps);
}
for (;;) {
char *line;