diff --git a/src/main.c b/src/main.c index 799b2e91..1deb926d 100644 --- a/src/main.c +++ b/src/main.c @@ -460,7 +460,7 @@ static const struct command_switch switches[] = { 'S', flag_off, &keep_going_flag, 1, 1, 0, 0, &default_keep_going_flag, "no-keep-going" }, { 't', flag, &touch_flag, 1, 1, 1, 0, 0, "touch" }, - { 'v', flag, &print_version_flag, 1, 1, 0, 0, 0, "version" }, + { 'v', flag, &print_version_flag, 1, 0, 0, 0, 0, "version" }, { 'w', flag, &print_directory_flag, 1, 1, 0, 0, &default_print_directory_flag, "print-directory" }, @@ -686,6 +686,52 @@ initialize_stopchar_map (void) } } +/* This code is stolen from gnulib. + If/when we abandon the requirement to work with K&R compilers, we can + remove this (and perhaps other parts of GNU make!) and migrate to using + gnulib directly. + + This is called only through atexit(), which means die() has already been + invoked. So, call exit() here directly. Apparently that works...? +*/ + +/* Close standard output, exiting with status 'exit_failure' on failure. + If a program writes *anything* to stdout, that program should close + stdout and make sure that it succeeds before exiting. Otherwise, + suppose that you go to the extreme of checking the return status + of every function that does an explicit write to stdout. The last + printf can succeed in writing to the internal stream buffer, and yet + the fclose(stdout) could still fail (due e.g., to a disk full error) + when it tries to write out that buffered data. Thus, you would be + left with an incomplete output file and the offending program would + exit successfully. Even calling fflush is not always sufficient, + since some file systems (NFS and CODA) buffer written/flushed data + until an actual close call. + + Besides, it's wasteful to check the return value from every call + that writes to stdout -- just let the internal stream state record + the failure. That's what the ferror test is checking below. + + It's important to detect such failures and exit nonzero because many + tools (most notably 'make' and other build-management systems) depend + on being able to detect failure in other tools via their exit status. */ + +static void +close_stdout (void) +{ + int prev_fail = ferror (stdout); + int fclose_fail = fclose (stdout); + + if (prev_fail || fclose_fail) + { + if (fclose_fail) + perror_with_name (_("write error: stdout"), ""); + else + O (error, NILF, _("write error: stdout")); + exit (MAKE_TROUBLE); + } +} + static const char * expand_command_line_file (const char *name) { @@ -833,6 +879,38 @@ decode_output_sync_flags (void) #endif } +/* Print a nice usage method and exit. */ + +static void NORETURN +print_usage (int bad) +{ + const char *const *cpp; + FILE *usageto; + + if (print_version_flag) + { + print_version (); + fputs ("\n", stdout); + } + + usageto = bad ? stderr : stdout; + + fprintf (usageto, _("Usage: %s [options] [target] ...\n"), program); + + for (cpp = usage; *cpp; ++cpp) + fputs (_(*cpp), usageto); + + if (!remote_description || *remote_description == '\0') + fprintf (usageto, _("\nThis program built for %s\n"), make_host); + else + fprintf (usageto, _("\nThis program built for %s (%s)\n"), + make_host, remote_description); + + fprintf (usageto, _("Report bugs to <bug-make@gnu.org>\n")); + + die (bad ? MAKE_FAILURE : MAKE_SUCCESS); +} + #ifdef WINDOWS32 /* @@ -1089,6 +1167,11 @@ main (int argc, char **argv, char **envp) /* Useful for attaching debuggers, etc. */ SPIN ("main-entry"); +#ifdef HAVE_ATEXIT + if (ANY_SET (check_io_state (), IO_STDOUT_OK)) + atexit (close_stdout); +#endif + output_init (&make_sync); initialize_stopchar_map(); @@ -1501,6 +1584,23 @@ main (int argc, char **argv, char **envp) arg_job_slots = env_slots; } + if (print_usage_flag) + print_usage (0); + + /* Print version information, and exit. */ + if (print_version_flag) + { + print_version (); + die (MAKE_SUCCESS); + } + + /* Now that we know we'll be running, force stdout to be line-buffered. */ +#ifdef HAVE_SETVBUF + setvbuf (stdout, 0, _IOLBF, BUFSIZ); +#elif HAVE_SETLINEBUF + setlinebuf (stdout); +#endif + /* Handle shuffle mode argument. */ if (shuffle_mode) { @@ -1569,15 +1669,14 @@ main (int argc, char **argv, char **envp) if (no_builtin_variables_flag) no_builtin_rules_flag = 1; - /* Print version information, and exit. */ - if (print_version_flag) + if (ISDB (DB_BASIC)) { print_version (); - die (MAKE_SUCCESS); - } - if (ISDB (DB_BASIC)) - print_version (); + /* Flush stdout so the user doesn't have to wait to see the + version information while make thinks about things. */ + fflush (stdout); + } #ifndef VMS /* Set the "MAKE_COMMAND" variable to the name we were invoked with. @@ -2960,33 +3059,6 @@ handle_non_switch_argument (const char *arg, int env) } } -/* Print a nice usage method. */ - -static void -print_usage (int bad) -{ - const char *const *cpp; - FILE *usageto; - - if (print_version_flag) - print_version (); - - usageto = bad ? stderr : stdout; - - fprintf (usageto, _("Usage: %s [options] [target] ...\n"), program); - - for (cpp = usage; *cpp; ++cpp) - fputs (_(*cpp), usageto); - - if (!remote_description || *remote_description == '\0') - fprintf (usageto, _("\nThis program built for %s\n"), make_host); - else - fprintf (usageto, _("\nThis program built for %s (%s)\n"), - make_host, remote_description); - - fprintf (usageto, _("Report bugs to <bug-make@gnu.org>\n")); -} - /* Decode switches from ARGC and ARGV. They came from the environment if ENV is nonzero. */ @@ -3187,11 +3259,8 @@ decode_switches (int argc, const char **argv, int env) while (optind < argc) handle_non_switch_argument (argv[optind++], env); - if (!env && (bad || print_usage_flag)) - { - print_usage (bad); - die (bad ? MAKE_FAILURE : MAKE_SUCCESS); - } + if (bad && !env) + print_usage (bad); /* If there are any options that need to be decoded do it now. */ decode_debug_flags (); @@ -3558,10 +3627,6 @@ print_version (void) precede, precede, precede); printed_version = 1; - - /* Flush stdout so the user doesn't have to wait to see the - version information while make thinks about things. */ - fflush (stdout); } /* Print a bunch of information about this and that. */ diff --git a/src/output.c b/src/output.c index 91a1dc31..d806159f 100644 --- a/src/output.c +++ b/src/output.c @@ -299,53 +299,6 @@ output_dump (struct output *out) #endif /* NO_OUTPUT_SYNC */ -/* This code is stolen from gnulib. - If/when we abandon the requirement to work with K&R compilers, we can - remove this (and perhaps other parts of GNU make!) and migrate to using - gnulib directly. - - This is called only through atexit(), which means die() has already been - invoked. So, call exit() here directly. Apparently that works...? -*/ - -/* Close standard output, exiting with status 'exit_failure' on failure. - If a program writes *anything* to stdout, that program should close - stdout and make sure that it succeeds before exiting. Otherwise, - suppose that you go to the extreme of checking the return status - of every function that does an explicit write to stdout. The last - printf can succeed in writing to the internal stream buffer, and yet - the fclose(stdout) could still fail (due e.g., to a disk full error) - when it tries to write out that buffered data. Thus, you would be - left with an incomplete output file and the offending program would - exit successfully. Even calling fflush is not always sufficient, - since some file systems (NFS and CODA) buffer written/flushed data - until an actual close call. - - Besides, it's wasteful to check the return value from every call - that writes to stdout -- just let the internal stream state record - the failure. That's what the ferror test is checking below. - - It's important to detect such failures and exit nonzero because many - tools (most notably 'make' and other build-management systems) depend - on being able to detect failure in other tools via their exit status. */ - -static void -close_stdout (void) -{ - int prev_fail = ferror (stdout); - int fclose_fail = fclose (stdout); - - if (prev_fail || fclose_fail) - { - if (fclose_fail) - perror_with_name (_("write error: stdout"), ""); - else - O (error, NILF, _("write error: stdout")); - exit (MAKE_TROUBLE); - } -} - - void output_init (struct output *out) { @@ -356,23 +309,10 @@ output_init (struct output *out) return; } - /* Configure this instance of make. Be sure stdout is line-buffered. */ - -#ifdef HAVE_SETVBUF - setvbuf (stdout, 0, _IOLBF, BUFSIZ); -#elif HAVE_SETLINEBUF - setlinebuf (stdout); -#endif /* setlinebuf missing. */ - - /* Force stdout/stderr into append mode. This ensures parallel jobs won't - lose output due to overlapping writes. */ + /* Force stdout/stderr into append mode (if they are files) to ensure + parallel jobs won't lose output due to overlapping writes. */ fd_set_append (fileno (stdout)); fd_set_append (fileno (stderr)); - -#ifdef HAVE_ATEXIT - if (ANY_SET (check_io_state (), IO_STDOUT_OK)) - atexit (close_stdout); -#endif } void