*参照元 [#k36921b1] #backlinks *説明 [#z23f58d0] -パス: [[gcc-8.3/gcc/gcc.c]] -FIXME: これは何? --説明 **引数 [#k628c198] - -- -なし **返り値 [#na102ad6] - -int -- **参考 [#e7886444] *実装 [#i0faf42f] /* Execute the command specified by the arguments on the current line of spec. When using pipes, this includes several piped-together commands with `|' between them. Return 0 if successful, -1 if failed. */ static int execute (void) { int i; int n_commands; /* # of command. */ char *string; struct pex_obj *pex; struct command { const char *prog; /* program name. */ const char **argv; /* vector of args. */ }; const char *arg; struct command *commands; /* each command buffer with above info. */ gcc_assert (!processing_spec_function); if (wrapper_string) { string = find_a_file (&exec_prefixes, argbuf[0], X_OK, false); if (string) argbuf[0] = string; insert_wrapper (wrapper_string); } /* Count # of piped commands. */ for (n_commands = 1, i = 0; argbuf.iterate (i, &arg); i++) if (strcmp (arg, "|") == 0) n_commands++; /* Get storage for each command. */ commands = (struct command *) alloca (n_commands * sizeof (struct command)); /* Split argbuf into its separate piped processes, and record info about each one. Also search for the programs that are to be run. */ argbuf.safe_push (0); commands[0].prog = argbuf[0]; /* first command. */ commands[0].argv = argbuf.address (); if (!wrapper_string) { string = find_a_file (&exec_prefixes, commands[0].prog, X_OK, false); commands[0].argv[0] = (string) ? string : commands[0].argv[0]; } for (n_commands = 1, i = 0; argbuf.iterate (i, &arg); i++) if (arg && strcmp (arg, "|") == 0) { /* each command. */ #if defined (__MSDOS__) || defined (OS2) || defined (VMS) fatal_error (input_location, "-pipe not supported"); #endif argbuf[i] = 0; /* Termination of command args. */ commands[n_commands].prog = argbuf[i + 1]; commands[n_commands].argv = &(argbuf.address ())[i + 1]; string = find_a_file (&exec_prefixes, commands[n_commands].prog, X_OK, false); if (string) commands[n_commands].argv[0] = string; n_commands++; } /* If -v, print what we are about to do, and maybe query. */ if (verbose_flag) { /* For help listings, put a blank line between sub-processes. */ if (print_help_list) fputc ('\n', stderr); /* Print each piped command as a separate line. */ for (i = 0; i < n_commands; i++) { const char *const *j; if (verbose_only_flag) { for (j = commands[i].argv; *j; j++) { const char *p; for (p = *j; *p; ++p) if (!ISALNUM ((unsigned char) *p) && *p != '_' && *p != '/' && *p != '-' && *p != '.') break; if (*p || !*j) { fprintf (stderr, " \""); for (p = *j; *p; ++p) { if (*p == '"' || *p == '\\' || *p == '$') fputc ('\\', stderr); fputc (*p, stderr); } fputc ('"', stderr); } /* If it's empty, print "". */ else if (!**j) fprintf (stderr, " \"\""); else fprintf (stderr, " %s", *j); } } else for (j = commands[i].argv; *j; j++) /* If it's empty, print "". */ if (!**j) fprintf (stderr, " \"\""); else fprintf (stderr, " %s", *j); /* Print a pipe symbol after all but the last command. */ if (i + 1 != n_commands) fprintf (stderr, " |"); fprintf (stderr, "\n"); } fflush (stderr); if (verbose_only_flag != 0) { /* verbose_only_flag should act as if the spec was executed, so increment execution_count before returning. This prevents spurious warnings about unused linker input files, etc. */ execution_count++; return 0; } #ifdef DEBUG fnotice (stderr, "\nGo ahead? (y or n) "); fflush (stderr); i = getchar (); if (i != '\n') while (getchar () != '\n') ; if (i != 'y' && i != 'Y') return 0; #endif /* DEBUG */ } #ifdef ENABLE_VALGRIND_CHECKING /* Run the each command through valgrind. To simplify prepending the path to valgrind and the option "-q" (for quiet operation unless something triggers), we allocate a separate argv array. */ for (i = 0; i < n_commands; i++) { const char **argv; int argc; int j; for (argc = 0; commands[i].argv[argc] != NULL; argc++) ; argv = XALLOCAVEC (const char *, argc + 3); argv[0] = VALGRIND_PATH; argv[1] = "-q"; for (j = 2; j < argc + 2; j++) argv[j] = commands[i].argv[j - 2]; argv[j] = NULL; commands[i].argv = argv; commands[i].prog = argv[0]; } #endif /* Run each piped subprocess. */ pex = pex_init (PEX_USE_PIPES | ((report_times || report_times_to_file) ? PEX_RECORD_TIMES : 0), progname, temp_filename); if (pex == NULL) fatal_error (input_location, "pex_init failed: %m"); for (i = 0; i < n_commands; i++) { const char *errmsg; int err; const char *string = commands[i].argv[0]; errmsg = pex_run (pex, ((i + 1 == n_commands ? PEX_LAST : 0) | (string == commands[i].prog ? PEX_SEARCH : 0)), string, CONST_CAST (char **, commands[i].argv), NULL, NULL, &err); - --サブコマンド(cc1, as, ld など)の起動を行う --[[gcc-8.3/gcc/pex_run()]] if (errmsg != NULL) { if (err == 0) fatal_error (input_location, errmsg); else { errno = err; pfatal_with_name (errmsg); } } if (i && string != commands[i].prog) free (CONST_CAST (char *, string)); } execution_count++; /* Wait for all the subprocesses to finish. */ { int *statuses; struct pex_time *times = NULL; int ret_code = 0; statuses = (int *) alloca (n_commands * sizeof (int)); if (!pex_get_status (pex, n_commands, statuses)) fatal_error (input_location, "failed to get exit status: %m"); if (report_times || report_times_to_file) { times = (struct pex_time *) alloca (n_commands * sizeof (struct pex_time)); if (!pex_get_times (pex, n_commands, times)) fatal_error (input_location, "failed to get process times: %m"); } pex_free (pex); for (i = 0; i < n_commands; ++i) { int status = statuses[i]; if (WIFSIGNALED (status)) switch (WTERMSIG (status)) { case SIGINT: case SIGTERM: /* SIGQUIT and SIGKILL are not available on MinGW. */ #ifdef SIGQUIT case SIGQUIT: #endif #ifdef SIGKILL case SIGKILL: #endif /* The user (or environment) did something to the inferior. Making this an ICE confuses the user into thinking there's a compiler bug. Much more likely is the user or OOM killer nuked it. */ fatal_error (input_location, "%s signal terminated program %s", strsignal (WTERMSIG (status)), commands[i].prog); break; #ifdef SIGPIPE case SIGPIPE: /* SIGPIPE is a special case. It happens in -pipe mode when the compiler dies before the preprocessor is done, or the assembler dies before the compiler is done. There's generally been an error already, and this is just fallout. So don't generate another error unless we would otherwise have succeeded. */ if (signal_count || greatest_status >= MIN_FATAL_STATUS) { signal_count++; ret_code = -1; break; } #endif /* FALLTHROUGH */ default: /* The inferior failed to catch the signal. */ internal_error_no_backtrace ("%s signal terminated program %s", strsignal (WTERMSIG (status)), commands[i].prog); } else if (WIFEXITED (status) && WEXITSTATUS (status) >= MIN_FATAL_STATUS) { /* For ICEs in cc1, cc1obj, cc1plus see if it is reproducible or not. */ const char *p; if (flag_report_bug && WEXITSTATUS (status) == ICE_EXIT_CODE && i == 0 && (p = strrchr (commands[0].argv[0], DIR_SEPARATOR)) && ! strncmp (p + 1, "cc1", 3)) try_generate_repro (commands[0].argv); if (WEXITSTATUS (status) > greatest_status) greatest_status = WEXITSTATUS (status); ret_code = -1; } if (report_times || report_times_to_file) { struct pex_time *pt = ×[i]; double ut, st; ut = ((double) pt->user_seconds + (double) pt->user_microseconds / 1.0e6); st = ((double) pt->system_seconds + (double) pt->system_microseconds / 1.0e6); if (ut + st != 0) { if (report_times) fnotice (stderr, "# %s %.2f %.2f\n", commands[i].prog, ut, st); if (report_times_to_file) { int c = 0; const char *const *j; fprintf (report_times_to_file, "%g %g", ut, st); for (j = &commands[i].prog; *j; j = &commands[i].argv[++c]) { const char *p; for (p = *j; *p; ++p) if (*p == '"' || *p == '\\' || *p == '$' || ISSPACE (*p)) break; if (*p) { fprintf (report_times_to_file, " \""); for (p = *j; *p; ++p) { if (*p == '"' || *p == '\\' || *p == '$') fputc ('\\', report_times_to_file); fputc (*p, report_times_to_file); } fputc ('"', report_times_to_file); } else fprintf (report_times_to_file, " %s", *j); } fputc ('\n', report_times_to_file); } } } } if (commands[0].argv[0] != commands[0].prog) free (CONST_CAST (char *, commands[0].argv[0])); return ret_code; } } *コメント [#d35e01e9]