/* * CDDL HEADER START * * The contents of this file are subject to the terms of the * Common Development and Distribution License (the "License"). * You may not use this file except in compliance with the License. * * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE * or http://www.opensolaris.org/os/licensing. * See the License for the specific language governing permissions * and limitations under the License. * * When distributing Covered Code, include this CDDL HEADER in each * file and include the License file at usr/src/OPENSOLARIS.LICENSE. * If applicable, add the following below this CDDL HEADER, with the * fields enclosed by brackets "[]" replaced with your own identifying * information: Portions Copyright [yyyy] [name of copyright owner] * * CDDL HEADER END */ /* * Copyright 2006 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. * * Copyright 2019, Joyent, Inc. * Copyright 2019 RackTop Systems. * Copyright 2019 OmniOS Community Edition (OmniOSce) Association. */ /* * main.cc * * make program main routine plus some helper routines */ /* * Included files */ #include /* bsd_signal() */ #include /* setlocale() */ #include #include #include /* getvar() */ #include /* getmem(), setup_char_semantics() */ #include /* getpwnam() */ #include #include #include #include /* ENOENT */ #include /* fstat() */ #include /* open() */ # include /* sysinfo() */ #include /* stat() */ #include /* wait() */ #include /* execv(), unlink(), access() */ #include /* report_dependency(), get_report_file() */ // From read2.cc extern Name normalize_name(register wchar_t *name_string, register int length); extern void job_adjust_fini(); /* * Defined macros */ #define LD_SUPPORT_ENV_VAR "SGS_SUPPORT_32" #define LD_SUPPORT_ENV_VAR_32 "SGS_SUPPORT_32" #define LD_SUPPORT_ENV_VAR_64 "SGS_SUPPORT_64" #define LD_SUPPORT_MAKE_LIB "libmakestate.so.1" #ifdef __x86 #define LD_SUPPORT_MAKE_ARCH "i386" #elif __sparc #define LD_SUPPORT_MAKE_ARCH "sparc" #else #error "Unsupported architecture" #endif /* * typedefs & structs */ /* * Static variables */ static char *argv_zero_string; static Boolean build_failed_ever_seen; static Boolean continue_after_error_ever_seen; /* `-k' */ static Boolean dmake_group_specified; /* `-g' */ static Boolean dmake_max_jobs_specified; /* `-j' */ static Boolean dmake_mode_specified; /* `-m' */ static Boolean dmake_add_mode_specified; /* `-x' */ static Boolean dmake_output_mode_specified; /* `-x DMAKE_OUTPUT_MODE=' */ static Boolean dmake_compat_mode_specified; /* `-x SUN_MAKE_COMPAT_MODE=' */ static Boolean dmake_odir_specified; /* `-o' */ static Boolean dmake_rcfile_specified; /* `-c' */ static Boolean env_wins; /* `-e' */ static Boolean ignore_default_mk; /* `-r' */ static Boolean list_all_targets; /* `-T' */ static int mf_argc; static char **mf_argv; static Dependency_rec not_auto_depen_struct; static Dependency not_auto_depen = ¬_auto_depen_struct; static Boolean pmake_cap_r_specified; /* `-R' */ static Boolean pmake_machinesfile_specified; /* `-M' */ static Boolean stop_after_error_ever_seen; /* `-S' */ static Boolean trace_status; /* `-p' */ #ifdef DMAKE_STATISTICS static Boolean getname_stat = false; #endif static time_t start_time; static int g_argc; static char **g_argv; /* * File table of contents */ extern "C" void cleanup_after_exit(void); extern "C" { extern void dmake_exit_callback(void); extern void dmake_message_callback(char *); } extern Name normalize_name(register wchar_t *name_string, register int length); extern int main(int, char * []); static void append_makeflags_string(Name, String); static void doalarm(int); static void enter_argv_values(int , char **, ASCII_Dyn_Array *); static void make_targets(int, char **, Boolean); static int parse_command_option(char); static void read_command_options(int, char **); static void read_environment(Boolean); static void read_files_and_state(int, char **); static Boolean read_makefile(Name, Boolean, Boolean, Boolean); static void report_recursion(Name); static void set_sgs_support(void); static void setup_for_projectdir(void); static void setup_makeflags_argv(void); static void report_dir_enter_leave(Boolean entering); extern void expand_value(Name, register String , Boolean); static const char verstring[] = "illumos make"; jmp_buf jmpbuffer; /* * main(argc, argv) * * Parameters: * argc You know what this is * argv You know what this is * * Static variables used: * list_all_targets make -T seen * trace_status make -p seen * * Global variables used: * debug_level Should we trace make actions? * keep_state Set if .KEEP_STATE seen * makeflags The Name "MAKEFLAGS", used to get macro * remote_command_name Name of remote invocation cmd ("on") * running_list List of parallel running processes * stdout_stderr_same true if stdout and stderr are the same * auto_dependencies The Name "SUNPRO_DEPENDENCIES" * temp_file_directory Set to the dir where we create tmp file * trace_reader Set to reflect tracing status * working_on_targets Set when building user targets */ int main(int argc, char *argv[]) { /* * cp is a -> to the value of the MAKEFLAGS env var, * which has to be regular chars. */ register char *cp; char make_state_dir[MAXPATHLEN]; Boolean parallel_flag = false; Boolean argv_zero_relative = false; char *prognameptr; char *slash_ptr; mode_t um; int i; struct itimerval value; char def_dmakerc_path[MAXPATHLEN]; Name dmake_name, dmake_name2; Name dmake_value, dmake_value2; Property prop, prop2; struct stat statbuf; int statval; struct stat out_stat, err_stat; hostid = gethostid(); bsd_signals(); (void) setlocale(LC_ALL, ""); #ifdef DMAKE_STATISTICS if (getenv("DMAKE_STATISTICS")) { getname_stat = true; } #endif #ifndef TEXT_DOMAIN #define TEXT_DOMAIN "SYS_TEST" #endif textdomain(TEXT_DOMAIN); g_argc = argc; g_argv = (char **) malloc((g_argc + 1) * sizeof(char *)); for (i = 0; i < argc; i++) { g_argv[i] = argv[i]; } g_argv[i] = NULL; /* * Set argv_zero_string to some form of argv[0] for * recursive MAKE builds. */ if (*argv[0] == (int) slash_char) { /* argv[0] starts with a slash */ argv_zero_string = strdup(argv[0]); } else if (strchr(argv[0], (int) slash_char) == NULL) { /* argv[0] contains no slashes */ argv_zero_string = strdup(argv[0]); } else { /* * argv[0] contains at least one slash, * but doesn't start with a slash */ char *tmp_current_path; char *tmp_string; tmp_current_path = get_current_path(); tmp_string = getmem(strlen(tmp_current_path) + 1 + strlen(argv[0]) + 1); (void) sprintf(tmp_string, "%s/%s", tmp_current_path, argv[0]); argv_zero_string = strdup(tmp_string); retmem_mb(tmp_string); argv_zero_relative = true; } /* * The following flags are reset if we don't have the * (.nse_depinfo or .make.state) files locked and only set * AFTER the file has been locked. This ensures that if the user * interrupts the program while file_lock() is waiting to lock * the file, the interrupt handler doesn't remove a lock * that doesn't belong to us. */ make_state_lockfile = NULL; make_state_locked = false; /* * look for last slash char in the path to look at the binary * name. This is to resolve the hard link and invoke make * in svr4 mode. */ /* Sun OS make standard */ svr4 = false; posix = false; if(!strcmp(argv_zero_string, "/usr/xpg4/bin/make")) { svr4 = false; posix = true; } else { prognameptr = strrchr(argv[0], '/'); if(prognameptr) { prognameptr++; } else { prognameptr = argv[0]; } if(!strcmp(prognameptr, "svr4.make")) { svr4 = true; posix = false; } } if (getenv(USE_SVR4_MAKE) || getenv("USE_SVID")){ svr4 = true; posix = false; } /* * Find the dmake_compat_mode: posix, sun, svr4, or gnu_style, . */ char * dmake_compat_mode_var = getenv("SUN_MAKE_COMPAT_MODE"); if (dmake_compat_mode_var != NULL) { if (0 == strcasecmp(dmake_compat_mode_var, "GNU")) { gnu_style = true; } //svr4 = false; //posix = false; } /* * Temporary directory set up. */ char * tmpdir_var = getenv("TMPDIR"); if (tmpdir_var != NULL && *tmpdir_var == '/' && strlen(tmpdir_var) < MAXPATHLEN) { strcpy(mbs_buffer, tmpdir_var); for (tmpdir_var = mbs_buffer+strlen(mbs_buffer); *(--tmpdir_var) == '/' && tmpdir_var > mbs_buffer; *tmpdir_var = '\0'); if (strlen(mbs_buffer) + 32 < MAXPATHLEN) { /* 32 = strlen("/dmake.stdout.%d.%d.XXXXXX") */ sprintf(mbs_buffer2, "%s/dmake.tst.%d.XXXXXX", mbs_buffer, getpid()); int fd = mkstemp(mbs_buffer2); if (fd >= 0) { close(fd); unlink(mbs_buffer2); tmpdir = strdup(mbs_buffer); } } } /* find out if stdout and stderr point to the same place */ if (fstat(1, &out_stat) < 0) { fatal(gettext("fstat of standard out failed: %s"), errmsg(errno)); } if (fstat(2, &err_stat) < 0) { fatal(gettext("fstat of standard error failed: %s"), errmsg(errno)); } if ((out_stat.st_dev == err_stat.st_dev) && (out_stat.st_ino == err_stat.st_ino)) { stdout_stderr_same = true; } else { stdout_stderr_same = false; } /* Make the vroot package scan the path using shell semantics */ set_path_style(0); setup_char_semantics(); /* * If running with .KEEP_STATE, curdir will be set with * the connected directory. */ (void) atexit(cleanup_after_exit); load_cached_names(); /* * Set command line flags */ setup_makeflags_argv(); read_command_options(mf_argc, mf_argv); read_command_options(argc, argv); if (debug_level > 0) { cp = getenv(makeflags->string_mb); (void) printf(gettext("MAKEFLAGS value: %s\n"), cp == NULL ? "" : cp); } /* * Reset argv_zero_string if it was built from a relative path and the * -C option was specified. */ if (argv_zero_relative && rebuild_arg0) { char *tmp_current_path; char *tmp_string; free(argv_zero_string); tmp_current_path = get_current_path(); tmp_string = getmem(strlen(tmp_current_path) + 1 + strlen(argv[0]) + 1); (void) sprintf(tmp_string, "%s/%s", tmp_current_path, argv[0]); argv_zero_string = strdup(tmp_string); retmem_mb(tmp_string); } setup_for_projectdir(); setup_interrupt(handle_interrupt); read_files_and_state(argc, argv); /* * Find the dmake_output_mode: TXT1, TXT2 or HTML1. */ MBSTOWCS(wcs_buffer, "DMAKE_OUTPUT_MODE"); dmake_name2 = GETNAME(wcs_buffer, FIND_LENGTH); prop2 = get_prop(dmake_name2->prop, macro_prop); if (prop2 == NULL) { /* DMAKE_OUTPUT_MODE not defined, default to TXT1 mode */ output_mode = txt1_mode; } else { dmake_value2 = prop2->body.macro.value; if ((dmake_value2 == NULL) || (IS_EQUAL(dmake_value2->string_mb, "TXT1"))) { output_mode = txt1_mode; } else if (IS_EQUAL(dmake_value2->string_mb, "TXT2")) { output_mode = txt2_mode; } else if (IS_EQUAL(dmake_value2->string_mb, "HTML1")) { output_mode = html1_mode; } else { warning(gettext("Unsupported value `%s' for DMAKE_OUTPUT_MODE after -x flag (ignored)"), dmake_value2->string_mb); } } /* * Find the dmake_mode: parallel, or serial. */ if ((!pmake_cap_r_specified) && (!pmake_machinesfile_specified)) { char *s, *b; if ((s = strdup(argv[0])) == NULL) fatal(gettext("Out of memory")); b = basename(s); MBSTOWCS(wcs_buffer, "DMAKE_MODE"); dmake_name2 = GETNAME(wcs_buffer, FIND_LENGTH); prop2 = get_prop(dmake_name2->prop, macro_prop); // If we're invoked as 'make' run serially, regardless of DMAKE_MODE // If we're invoked as 'make' but passed -j, run parallel // If we're invoked as 'dmake', without DMAKE_MODE, default parallel // If we're invoked as 'dmake' and DMAKE_MODE is set, honour it. if ((strcmp(b, "make") == 0) && !dmake_max_jobs_specified) { dmake_mode_type = serial_mode; no_parallel = true; } else if (prop2 == NULL) { /* DMAKE_MODE not defined, default based on our name */ if (strcmp(b, "dmake") == 0) { dmake_mode_type = parallel_mode; no_parallel = false; } } else { dmake_value2 = prop2->body.macro.value; if (IS_EQUAL(dmake_value2->string_mb, "parallel")) { dmake_mode_type = parallel_mode; no_parallel = false; } else if (IS_EQUAL(dmake_value2->string_mb, "serial")) { dmake_mode_type = serial_mode; no_parallel = true; } else { fatal(gettext("Unknown dmake mode argument `%s' after -m flag"), dmake_value2->string_mb); } } free(s); } parallel_flag = true; putenv(strdup("DMAKE_CHILD=TRUE")); // // If dmake is running with -t option, set dmake_mode_type to serial. // This is done because doname() calls touch_command() that runs serially. // If we do not do that, maketool will have problems. // if(touch) { dmake_mode_type = serial_mode; no_parallel = true; } /* * Check whether stdout and stderr are physically same. * This is in order to decide whether we need to redirect * stderr separately from stdout. * This check is performed only if __DMAKE_SEPARATE_STDERR * is not set. This variable may be used in order to preserve * the 'old' behaviour. */ out_err_same = true; char * dmake_sep_var = getenv("__DMAKE_SEPARATE_STDERR"); if (dmake_sep_var == NULL || (0 != strcasecmp(dmake_sep_var, "NO"))) { struct stat stdout_stat; struct stat stderr_stat; if( (fstat(1, &stdout_stat) == 0) && (fstat(2, &stderr_stat) == 0) ) { if( (stdout_stat.st_dev != stderr_stat.st_dev) || (stdout_stat.st_ino != stderr_stat.st_ino) ) { out_err_same = false; } } } /* * Enable interrupt handler for alarms */ (void) bsd_signal(SIGALRM, (SIG_PF)doalarm); /* * Check if make should report */ if (getenv(sunpro_dependencies->string_mb) != NULL) { FILE *report_file; report_dependency(""); report_file = get_report_file(); if ((report_file != NULL) && (report_file != (FILE*)-1)) { (void) fprintf(report_file, "\n"); } } /* * Make sure SUNPRO_DEPENDENCIES is exported (or not) properly. */ if (keep_state) { maybe_append_prop(sunpro_dependencies, macro_prop)-> body.macro.exported = true; } else { maybe_append_prop(sunpro_dependencies, macro_prop)-> body.macro.exported = false; } working_on_targets = true; if (trace_status) { dump_make_state(); fclose(stdout); fclose(stderr); exit_status = 0; exit(0); } if (list_all_targets) { dump_target_list(); fclose(stdout); fclose(stderr); exit_status = 0; exit(0); } trace_reader = false; /* * Set temp_file_directory to the directory the .make.state * file is written to. */ if ((slash_ptr = strrchr(make_state->string_mb, (int) slash_char)) == NULL) { temp_file_directory = strdup(get_current_path()); } else { *slash_ptr = (int) nul_char; (void) strcpy(make_state_dir, make_state->string_mb); *slash_ptr = (int) slash_char; /* when there is only one slash and it's the first ** character, make_state_dir should point to '/'. */ if(make_state_dir[0] == '\0') { make_state_dir[0] = '/'; make_state_dir[1] = '\0'; } if (make_state_dir[0] == (int) slash_char) { temp_file_directory = strdup(make_state_dir); } else { char tmp_current_path2[MAXPATHLEN]; (void) sprintf(tmp_current_path2, "%s/%s", get_current_path(), make_state_dir); temp_file_directory = strdup(tmp_current_path2); } } report_dir_enter_leave(true); make_targets(argc, argv, parallel_flag); report_dir_enter_leave(false); if (build_failed_ever_seen) { if (posix) { exit_status = 1; } exit(1); } exit_status = 0; exit(0); /* NOTREACHED */ } /* * cleanup_after_exit() * * Called from exit(), performs cleanup actions. * * Parameters: * status The argument exit() was called with * arg Address of an argument vector to * cleanup_after_exit() * * Global variables used: * command_changed Set if we think .make.state should be rewritten * current_line Is set we set commands_changed * do_not_exec_rule * True if -n flag on * done The Name ".DONE", rule we run * keep_state Set if .KEEP_STATE seen * parallel True if building in parallel * quest If -q is on we do not run .DONE * report_dependencies * True if -P flag on * running_list List of parallel running processes * temp_file_name The temp file is removed, if any */ extern "C" void cleanup_after_exit(void) { Running rp; extern long getname_bytes_count; extern long getname_names_count; extern long getname_struct_count; extern long freename_bytes_count; extern long freename_names_count; extern long freename_struct_count; extern long other_alloc; extern long env_alloc_num; extern long env_alloc_bytes; #ifdef DMAKE_STATISTICS if(getname_stat) { printf(">>> Getname statistics:\n"); printf(" Allocated:\n"); printf(" Names: %ld\n", getname_names_count); printf(" Strings: %ld Kb (%ld bytes)\n", getname_bytes_count/1000, getname_bytes_count); printf(" Structs: %ld Kb (%ld bytes)\n", getname_struct_count/1000, getname_struct_count); printf(" Total bytes: %ld Kb (%ld bytes)\n", getname_struct_count/1000 + getname_bytes_count/1000, getname_struct_count + getname_bytes_count); printf("\n Unallocated: %ld\n", freename_names_count); printf(" Names: %ld\n", freename_names_count); printf(" Strings: %ld Kb (%ld bytes)\n", freename_bytes_count/1000, freename_bytes_count); printf(" Structs: %ld Kb (%ld bytes)\n", freename_struct_count/1000, freename_struct_count); printf(" Total bytes: %ld Kb (%ld bytes)\n", freename_struct_count/1000 + freename_bytes_count/1000, freename_struct_count + freename_bytes_count); printf("\n Total used: %ld Kb (%ld bytes)\n", (getname_struct_count/1000 + getname_bytes_count/1000) - (freename_struct_count/1000 + freename_bytes_count/1000), (getname_struct_count + getname_bytes_count) - (freename_struct_count + freename_bytes_count)); printf("\n>>> Other:\n"); printf( " Env (%ld): %ld Kb (%ld bytes)\n", env_alloc_num, env_alloc_bytes/1000, env_alloc_bytes ); } #endif parallel = false; /* If we used the SVR4_MAKE, don't build .DONE or .FAILED */ if (!getenv(USE_SVR4_MAKE)){ /* Build the target .DONE or .FAILED if we caught an error */ if (!quest && !list_all_targets) { Name failed_name; MBSTOWCS(wcs_buffer, ".FAILED"); failed_name = GETNAME(wcs_buffer, FIND_LENGTH); if ((exit_status != 0) && (failed_name->prop != NULL)) { /* * [tolik] switch DMake to serial mode */ dmake_mode_type = serial_mode; no_parallel = true; (void) doname(failed_name, false, true); } else { if (!trace_status) { /* * Switch DMake to serial mode */ dmake_mode_type = serial_mode; no_parallel = true; (void) doname(done, false, true); } } } } /* * Remove the temp file utilities report dependencies thru if it * is still around */ if (temp_file_name != NULL) { (void) unlink(temp_file_name->string_mb); } /* * Do not save the current command in .make.state if make * was interrupted. */ if (current_line != NULL) { command_changed = true; current_line->body.line.command_used = NULL; } /* * For each parallel build process running, remove the temp files * and zap the command line so it won't be put in .make.state */ for (rp = running_list; rp != NULL; rp = rp->next) { if (rp->temp_file != NULL) { (void) unlink(rp->temp_file->string_mb); } if (rp->stdout_file != NULL) { (void) unlink(rp->stdout_file); retmem_mb(rp->stdout_file); rp->stdout_file = NULL; } if (rp->stderr_file != NULL) { (void) unlink(rp->stderr_file); retmem_mb(rp->stderr_file); rp->stderr_file = NULL; } command_changed = true; /* line = get_prop(rp->target->prop, line_prop); if (line != NULL) { line->body.line.command_used = NULL; } */ } /* Remove the statefile lock file if the file has been locked */ if ((make_state_lockfile != NULL) && (make_state_locked)) { (void) unlink(make_state_lockfile); make_state_lockfile = NULL; make_state_locked = false; } /* Write .make.state */ write_state_file(1, (Boolean) 1); job_adjust_fini(); } /* * handle_interrupt() * * This is where C-C traps are caught. * * Parameters: * * Global variables used (except DMake 1.0): * current_target Sometimes the current target is removed * do_not_exec_rule But not if -n is on * quest or -q * running_list List of parallel running processes * touch Current target is not removed if -t on */ void handle_interrupt(int) { Property member; Running rp; (void) fflush(stdout); if (childPid > 0) { kill(childPid, SIGTERM); childPid = -1; } for (rp = running_list; rp != NULL; rp = rp->next) { if (rp->state != build_running) { continue; } if (rp->pid > 0) { kill(rp->pid, SIGTERM); rp->pid = -1; } } if (getpid() == getpgrp()) { bsd_signal(SIGTERM, SIG_IGN); kill (-getpid(), SIGTERM); } /* Clean up all parallel children already finished */ finish_children(false); /* Make sure the processes running under us terminate first */ while (wait((int *) NULL) != -1); /* Delete the current targets unless they are precious */ if ((current_target != NULL) && current_target->is_member && ((member = get_prop(current_target->prop, member_prop)) != NULL)) { current_target = member->body.member.library; } if (!do_not_exec_rule && !touch && !quest && (current_target != NULL) && !(current_target->stat.is_precious || all_precious)) { /* BID_1030811 */ /* azv 16 Oct 95 */ current_target->stat.time = file_no_time; if (exists(current_target) != file_doesnt_exist) { (void) fprintf(stderr, "\n*** %s ", current_target->string_mb); if (current_target->stat.is_dir) { (void) fprintf(stderr, gettext("not removed.\n"), current_target->string_mb); } else if (unlink(current_target->string_mb) == 0) { (void) fprintf(stderr, gettext("removed.\n"), current_target->string_mb); } else { (void) fprintf(stderr, gettext("could not be removed: %s.\n"), current_target->string_mb, errmsg(errno)); } } } for (rp = running_list; rp != NULL; rp = rp->next) { if (rp->state != build_running) { continue; } if (rp->target->is_member && ((member = get_prop(rp->target->prop, member_prop)) != NULL)) { rp->target = member->body.member.library; } if (!do_not_exec_rule && !touch && !quest && !(rp->target->stat.is_precious || all_precious)) { rp->target->stat.time = file_no_time; if (exists(rp->target) != file_doesnt_exist) { (void) fprintf(stderr, "\n*** %s ", rp->target->string_mb); if (rp->target->stat.is_dir) { (void) fprintf(stderr, gettext("not removed.\n"), rp->target->string_mb); } else if (unlink(rp->target->string_mb) == 0) { (void) fprintf(stderr, gettext("removed.\n"), rp->target->string_mb); } else { (void) fprintf(stderr, gettext("could not be removed: %s.\n"), rp->target->string_mb, errmsg(errno)); } } } } /* Have we locked .make.state or .nse_depinfo? */ if ((make_state_lockfile != NULL) && (make_state_locked)) { unlink(make_state_lockfile); make_state_lockfile = NULL; make_state_locked = false; } /* * Re-read .make.state file (it might be changed by recursive make) */ check_state(NULL); report_dir_enter_leave(false); exit_status = 2; exit(2); } /* * doalarm(sig, ...) * * Handle the alarm interrupt but do nothing. Side effect is to * cause return from wait3. * * Parameters: * sig * * Global variables used: */ static void doalarm(int sig __attribute__((unused))) { return; } /* * read_command_options(argc, argv) * * Scan the cmd line options and process the ones that start with "-" * * Return value: * -M argument, if any * * Parameters: * argc You know what this is * argv You know what this is * * Global variables used: */ static void read_command_options(register int argc, register char **argv) { register int ch; int current_optind = 1; int last_optind_with_double_hyphen = 0; int last_optind; int last_current_optind; register int i; register int j; register int k; register int makefile_next = 0; /* * flag to note options: * -c, f, g, j, m, o */ const char *tptr; const char *CMD_OPTS; extern char *optarg; extern int optind, opterr, optopt; #define SUNPRO_CMD_OPTS "-~Bbc:C:Ddef:g:ij:K:kM:m:NnO:o:PpqRrSsTtuVvwx:" # define SVR4_CMD_OPTS "-c:C:ef:g:ij:km:nO:o:pqrsTtVv" /* * Added V in SVR4_CMD_OPTS also, which is going to be a hidden * option, just to make sure that the getopt doesn't fail when some * users leave their USE_SVR4_MAKE set and try to use the makefiles * that are designed to issue commands like $(MAKE) -V. Anyway it * sets the same flag but ensures that getopt doesn't fail. */ opterr = 0; optind = 1; while (1) { last_optind=optind; /* Save optind and current_optind values */ last_current_optind=current_optind; /* in case we have to repeat this round. */ if (svr4) { CMD_OPTS=SVR4_CMD_OPTS; ch = getopt(argc, argv, SVR4_CMD_OPTS); } else { CMD_OPTS=SUNPRO_CMD_OPTS; ch = getopt(argc, argv, SUNPRO_CMD_OPTS); } if (ch == EOF) { if(optind < argc) { /* * Fixing bug 4102537: * Strange behaviour of command make using -- option. * Not all argv have been processed * Skip non-flag argv and continue processing. */ optind++; current_optind++; continue; } else { break; } } if (ch == '?') { if (optopt == '-') { /* Bug 5060758: getopt() changed behavior (s10_60), * and now we have to deal with cases when options * with double hyphen appear here, from -$(MAKEFLAGS) */ i = current_optind; if (argv[i][0] == '-') { if (argv[i][1] == '-') { if (argv[i][2] != '\0') { /* Check if this option is allowed */ tptr = strchr(CMD_OPTS, argv[i][2]); if (tptr) { if (last_optind_with_double_hyphen != current_optind) { /* This is first time we are trying to fix "--" * problem with this option. If we come here second * time, we will go to fatal error. */ last_optind_with_double_hyphen = current_optind; /* Eliminate first hyphen character */ for (j=0; argv[i][j] != '\0'; j++) { argv[i][j] = argv[i][j+1]; } /* Repeat the processing of this argument */ optind=last_optind; current_optind=last_current_optind; continue; } } } } } } } if (ch == '?') { if (svr4) { fprintf(stderr, gettext("Usage : dmake [ -f makefile ][ -c dmake_rcfile ][ -g dmake_group ][-C directory]\n")); fprintf(stderr, gettext(" [ -j dmake_max_jobs ][ -m dmake_mode ][ -o dmake_odir ]...\n")); fprintf(stderr, gettext(" [ -e ][ -i ][ -k ][ -n ][ -p ][ -q ][ -r ][ -s ][ -t ][ -v ]\n")); tptr = strchr(SVR4_CMD_OPTS, optopt); } else { fprintf(stderr, gettext("Usage : dmake [ -f makefile ][ -c dmake_rcfile ][ -g dmake_group ][-C directory]\n")); fprintf(stderr, gettext(" [ -j dmake_max_jobs ][ -K statefile ][ -m dmake_mode ][ -x MODE_NAME=VALUE ][ -o dmake_odir ]...\n")); fprintf(stderr, gettext(" [ -d ][ -dd ][ -D ][ -DD ][ -e ][ -i ][ -k ][ -n ][ -p ][ -P ][ -u ][ -w ]\n")); fprintf(stderr, gettext(" [ -q ][ -r ][ -s ][ -S ][ -t ][ -v ][ -V ][ target... ][ macro=value... ][ \"macro +=value\"... ]\n")); tptr = strchr(SUNPRO_CMD_OPTS, optopt); } if (!tptr) { fatal(gettext("Unknown option `-%c'"), optopt); } else { fatal(gettext("Missing argument after `-%c'"), optopt); } } makefile_next |= parse_command_option(ch); /* * If we're done processing all of the options of * ONE argument string... */ if (current_optind < optind) { i = current_optind; k = 0; /* If there's an argument for an option... */ if ((optind - current_optind) > 1) { k = i + 1; } switch (makefile_next) { case 0: argv[i] = NULL; /* This shouldn't happen */ if (k) { argv[k] = NULL; } break; case 1: /* -f seen */ argv[i] = (char *)"-f"; break; case 2: /* -c seen */ argv[i] = (char *)"-c"; break; case 4: /* -g seen */ argv[i] = (char *)"-g"; break; case 8: /* -j seen */ argv[i] = (char *)"-j"; break; case 16: /* -M seen */ argv[i] = (char *)"-M"; break; case 32: /* -m seen */ argv[i] = (char *)"-m"; break; case 128: /* -O seen */ argv[i] = (char *)"-O"; break; case 256: /* -K seen */ argv[i] = (char *)"-K"; break; case 512: /* -o seen */ argv[i] = (char *)"-o"; break; case 1024: /* -x seen */ argv[i] = (char *)"-x"; break; case 2048: argv[i] = (char *)"-C"; if (chdir(argv[k]) != 0) { fatal(gettext("failed to change to directory %s: %s"), argv[k], strerror(errno)); } path_reset = true; rebuild_arg0 = true; (void) get_current_path(); break; default: /* > 1 of -c, f, g, j, K, M, m, O, o, x seen */ fatal(gettext("Illegal command line. More than one option requiring\nan argument given in the same argument group")); } makefile_next = 0; current_optind = optind; } } } static void quote_str(char *str, char *qstr) { char *to; char *from; to = qstr; for (from = str; *from; from++) { switch (*from) { case ';': /* End of command */ case '(': /* Start group */ case ')': /* End group */ case '{': /* Start group */ case '}': /* End group */ case '[': /* Reg expr - any of a set of chars */ case ']': /* End of set of chars */ case '|': /* Pipe or logical-or */ case '^': /* Old-fashioned pipe */ case '&': /* Background or logical-and */ case '<': /* Redirect stdin */ case '>': /* Redirect stdout */ case '*': /* Reg expr - any sequence of chars */ case '?': /* Reg expr - any single char */ case '$': /* Variable substitution */ case '\'': /* Singe quote - turn off all magic */ case '"': /* Double quote - span whitespace */ case '`': /* Backquote - run a command */ case '#': /* Comment */ case ' ': /* Space (for MACRO=value1 value2 */ case '\\': /* Escape char - turn off magic of next char */ *to++ = '\\'; break; default: break; } *to++ = *from; } *to = '\0'; } static void unquote_str(char *str, char *qstr) { char *to; char *from; to = qstr; for (from = str; *from; from++) { if (*from == '\\') { from++; } *to++ = *from; } *to = '\0'; } /* * Convert the MAKEFLAGS string value into a vector of char *, similar * to argv. */ static void setup_makeflags_argv() { char *cp; char *cp1; char *cp2; char *cp3; char *cp_orig; Boolean add_hyphen; int i; char tmp_char; mf_argc = 1; cp = getenv(makeflags->string_mb); cp_orig = cp; if (cp) { /* * If new MAKEFLAGS format, no need to add hyphen. * If old MAKEFLAGS format, add hyphen before flags. */ if ((strchr(cp, (int) hyphen_char) != NULL) || (strchr(cp, (int) equal_char) != NULL)) { /* New MAKEFLAGS format */ add_hyphen = false; /* Check if MAKEFLAGS value begins with multiple * hyphen characters, and remove all duplicates. * Usually it happens when the next command is * used: $(MAKE) -$(MAKEFLAGS) * * This was a workaround for BugID 5060758, but * appears to have survived as a fix in make. */ while (*cp) { if (*cp != (int) hyphen_char) { break; } cp++; if (*cp == (int) hyphen_char) { /* There are two hyphens. Skip one */ cp_orig = cp; cp++; } if (!(*cp)) { /* There are hyphens only. Skip all */ cp_orig = cp; break; } } } else { /* Old MAKEFLAGS format */ add_hyphen = true; } } /* Find the number of arguments in MAKEFLAGS */ while (cp && *cp) { /* Skip white spaces */ while (cp && *cp && isspace(*cp)) { cp++; } if (cp && *cp) { /* Increment arg count */ mf_argc++; /* Go to next white space */ while (cp && *cp && !isspace(*cp)) { if(*cp == (int) backslash_char) { cp++; } cp++; } } } /* Allocate memory for the new MAKEFLAGS argv */ mf_argv = (char **) malloc((mf_argc + 1) * sizeof(char *)); mf_argv[0] = (char *)"MAKEFLAGS"; /* * Convert the MAKEFLAGS string value into a vector of char *, * similar to argv. */ cp = cp_orig; for (i = 1; i < mf_argc; i++) { /* Skip white spaces */ while (cp && *cp && isspace(*cp)) { cp++; } if (cp && *cp) { cp_orig = cp; /* Go to next white space */ while (cp && *cp && !isspace(*cp)) { if(*cp == (int) backslash_char) { cp++; } cp++; } tmp_char = *cp; *cp = (int) nul_char; if (add_hyphen) { mf_argv[i] = getmem(2 + strlen(cp_orig)); mf_argv[i][0] = '\0'; (void) strcat(mf_argv[i], "-"); // (void) strcat(mf_argv[i], cp_orig); unquote_str(cp_orig, mf_argv[i]+1); } else { mf_argv[i] = getmem(2 + strlen(cp_orig)); //mf_argv[i] = strdup(cp_orig); unquote_str(cp_orig, mf_argv[i]); } *cp = tmp_char; } } mf_argv[i] = NULL; } /* * parse_command_option(ch) * * Parse make command line options. * * Return value: * Indicates if any -f -c or -M were seen * * Parameters: * ch The character to parse * * Static variables used: * dmake_group_specified Set for make -g * dmake_max_jobs_specified Set for make -j * dmake_mode_specified Set for make -m * dmake_add_mode_specified Set for make -x * dmake_compat_mode_specified Set for make -x SUN_MAKE_COMPAT_MODE= * dmake_output_mode_specified Set for make -x DMAKE_OUTPUT_MODE= * dmake_odir_specified Set for make -o * dmake_rcfile_specified Set for make -c * env_wins Set for make -e * ignore_default_mk Set for make -r * trace_status Set for make -p * * Global variables used: * .make.state path & name set for make -K * continue_after_error Set for make -k * debug_level Set for make -d * do_not_exec_rule Set for make -n * filter_stderr Set for make -X * ignore_errors_all Set for make -i * no_parallel Set for make -R * quest Set for make -q * read_trace_level Set for make -D * report_dependencies Set for make -P * silent_all Set for make -s * touch Set for make -t */ static int parse_command_option(register char ch) { static int invert_next = 0; int invert_this = invert_next; invert_next = 0; switch (ch) { case '-': /* Ignore "--" */ return 0; case '~': /* Invert next option */ invert_next = 1; return 0; case 'B': /* Obsolete */ return 0; case 'b': /* Obsolete */ return 0; case 'c': /* Read alternative dmakerc file */ if (invert_this) { dmake_rcfile_specified = false; } else { dmake_rcfile_specified = true; } return 2; case 'C': /* Change directory */ return 2048; case 'D': /* Show lines read */ if (invert_this) { read_trace_level--; } else { read_trace_level++; } return 0; case 'd': /* Debug flag */ if (invert_this) { debug_level--; } else { debug_level++; } return 0; case 'e': /* Environment override flag */ if (invert_this) { env_wins = false; } else { env_wins = true; } return 0; case 'f': /* Read alternative makefile(s) */ return 1; case 'g': /* Use alternative DMake group */ if (invert_this) { dmake_group_specified = false; } else { dmake_group_specified = true; } return 4; case 'i': /* Ignore errors */ if (invert_this) { ignore_errors_all = false; } else { ignore_errors_all = true; } return 0; case 'j': /* Use alternative DMake max jobs */ if (invert_this) { dmake_max_jobs_specified = false; } else { dmake_mode_type = parallel_mode; no_parallel = false; dmake_max_jobs_specified = true; } return 8; case 'K': /* Read alternative .make.state */ return 256; case 'k': /* Keep making even after errors */ if (invert_this) { continue_after_error = false; } else { continue_after_error = true; continue_after_error_ever_seen = true; } return 0; case 'M': /* Read alternative make.machines file */ if (invert_this) { pmake_machinesfile_specified = false; } else { pmake_machinesfile_specified = true; dmake_mode_type = parallel_mode; no_parallel = false; } return 16; case 'm': /* Use alternative DMake build mode */ if (invert_this) { dmake_mode_specified = false; } else { dmake_mode_specified = true; } return 32; case 'x': /* Use alternative DMake mode */ if (invert_this) { dmake_add_mode_specified = false; } else { dmake_add_mode_specified = true; } return 1024; case 'N': /* Reverse -n */ if (invert_this) { do_not_exec_rule = true; } else { do_not_exec_rule = false; } return 0; case 'n': /* Print, not exec commands */ if (invert_this) { do_not_exec_rule = false; } else { do_not_exec_rule = true; } return 0; case 'O': /* Integrate with maketool, obsolete */ return 0; case 'o': /* Use alternative dmake output dir */ if (invert_this) { dmake_odir_specified = false; } else { dmake_odir_specified = true; } return 512; case 'P': /* Print for selected targets */ if (invert_this) { report_dependencies_level--; } else { report_dependencies_level++; } return 0; case 'p': /* Print description */ if (invert_this) { trace_status = false; do_not_exec_rule = false; } else { trace_status = true; do_not_exec_rule = true; } return 0; case 'q': /* Question flag */ if (invert_this) { quest = false; } else { quest = true; } return 0; case 'R': /* Don't run in parallel */ if (invert_this) { pmake_cap_r_specified = false; no_parallel = false; } else { pmake_cap_r_specified = true; dmake_mode_type = serial_mode; no_parallel = true; } return 0; case 'r': /* Turn off internal rules */ if (invert_this) { ignore_default_mk = false; } else { ignore_default_mk = true; } return 0; case 'S': /* Reverse -k */ if (invert_this) { continue_after_error = true; } else { continue_after_error = false; stop_after_error_ever_seen = true; } return 0; case 's': /* Silent flag */ if (invert_this) { silent_all = false; } else { silent_all = true; } return 0; case 'T': /* Print target list */ if (invert_this) { list_all_targets = false; do_not_exec_rule = false; } else { list_all_targets = true; do_not_exec_rule = true; } return 0; case 't': /* Touch flag */ if (invert_this) { touch = false; } else { touch = true; } return 0; case 'u': /* Unconditional flag */ if (invert_this) { build_unconditional = false; } else { build_unconditional = true; } return 0; case 'V': /* SVR4 mode */ svr4 = true; return 0; case 'v': /* Version flag */ if (invert_this) { } else { fprintf(stdout, "%s: %s\n", getprogname(), verstring); exit_status = 0; exit(0); } return 0; case 'w': /* Unconditional flag */ if (invert_this) { report_cwd = false; } else { report_cwd = true; } return 0; #if 0 case 'X': /* Filter stdout */ if (invert_this) { filter_stderr = false; } else { filter_stderr = true; } return 0; #endif default: break; } return 0; } /* * setup_for_projectdir() * * Read the PROJECTDIR variable, if defined, and set the sccs path * * Parameters: * * Global variables used: * sccs_dir_path Set to point to SCCS dir to use */ static void setup_for_projectdir(void) { static char path[MAXPATHLEN]; char cwdpath[MAXPATHLEN]; uid_t uid; int done=0; /* Check if we should use PROJECTDIR when reading the SCCS dir. */ sccs_dir_path = getenv("PROJECTDIR"); if ((sccs_dir_path != NULL) && (sccs_dir_path[0] != (int) slash_char)) { struct passwd *pwent; { uid = getuid(); pwent = getpwuid(uid); if (pwent == NULL) { fatal(gettext("Bogus USERID ")); } if ((pwent = getpwnam(sccs_dir_path)) == NULL) { /*empty block : it'll go & check cwd */ } else { (void) sprintf(path, "%s/src", pwent->pw_dir); if (access(path, F_OK) == 0) { sccs_dir_path = path; done = 1; } else { (void) sprintf(path, "%s/source", pwent->pw_dir); if (access(path, F_OK) == 0) { sccs_dir_path = path; done = 1; } } } if (!done) { if (getcwd(cwdpath, MAXPATHLEN - 1 )) { (void) sprintf(path, "%s/%s", cwdpath,sccs_dir_path); if (access(path, F_OK) == 0) { sccs_dir_path = path; done = 1; } else { fatal(gettext("Bogus PROJECTDIR '%s'"), sccs_dir_path); } } } } } } char * make_install_prefix(void) { int ret; char origin[PATH_MAX]; char *dir; if ((ret = readlink("/proc/self/path/a.out", origin, PATH_MAX - 1)) < 0) fatal("failed to read origin from /proc\n"); origin[ret] = '\0'; return strdup(dirname(origin)); } static char * add_to_env(const char *var, const char *value, const char *fallback) { const char *oldpath; char *newpath; oldpath = getenv(var); if (oldpath == NULL) { if (value != NULL) { asprintf(&newpath, "%s=%s", var, value); } else { asprintf(&newpath, "%s=%s", var, fallback); } } else { if (value != NULL) { asprintf(&newpath, "%s=%s:%s", var, oldpath, value); } else { asprintf(&newpath, "%s=%s:%s", var, oldpath, fallback); } } return (newpath); } /* * set_sgs_support() * * Add the libmakestate.so.1 lib to the env var SGS_SUPPORT * if it's not already in there. * The SGS_SUPPORT env var and libmakestate.so.1 is used by * the linker ld to report .make.state info back to make. * * In the new world we always will set the 32-bit and 64-bit versions of this * variable explicitly so that we can take into account the correct isa and our * prefix. So say that the prefix was /opt/local. Then we would want to search * /opt/local/lib/libmakestate.so.1:libmakestate.so.1. We still want to search * the original location just as a safety measure. */ static void set_sgs_support() { int len; char *newpath, *newpath64; char *lib32, *lib64; static char *prev_path, *prev_path64; char *origin = make_install_prefix(); struct stat st; asprintf(&lib32, "%s/%s/%s", origin, "../lib", LD_SUPPORT_MAKE_LIB); if (stat(lib32, &st) != 0) { free(lib32); // Try the tools path asprintf(&lib32, "%s/%s/%s/%s", origin, "../../lib/", LD_SUPPORT_MAKE_ARCH, LD_SUPPORT_MAKE_LIB); if (stat(lib32, &st) != 0) { free(lib32); lib32 = NULL; } } asprintf(&lib64, "%s/%s/64/%s", origin, "../lib", LD_SUPPORT_MAKE_LIB); if (stat(lib64, &st) != 0) { free(lib64); // Try the tools path asprintf(&lib64, "%s/%s/%s/64/%s", origin, "../../lib/", LD_SUPPORT_MAKE_ARCH, LD_SUPPORT_MAKE_LIB); if (stat(lib64, &st) != 0) { free(lib64); lib64 = NULL; } } newpath = add_to_env(LD_SUPPORT_ENV_VAR_32, lib32, LD_SUPPORT_MAKE_LIB); newpath64 = add_to_env(LD_SUPPORT_ENV_VAR_64, lib64, LD_SUPPORT_MAKE_LIB); putenv(newpath); if (prev_path) { free(prev_path); } prev_path = newpath; putenv(newpath64); if (prev_path64) { free(prev_path64); } prev_path64 = newpath64; free(lib32); free(lib64); free(origin); } /* * read_files_and_state(argc, argv) * * Read the makefiles we care about and the environment * Also read the = style command line options * * Parameters: * argc You know what this is * argv You know what this is * * Static variables used: * env_wins make -e, determines if env vars are RO * ignore_default_mk make -r, determines if make.rules is read * not_auto_depen dwight * * Global variables used: * default_target_to_build Set to first proper target from file * do_not_exec_rule Set to false when makfile is made * dot The Name ".", used to read current dir * empty_name The Name "", use as macro value * keep_state Set if KEEP_STATE is in environment * make_state The Name ".make.state", used to read file * makefile_type Set to type of file being read * makeflags The Name "MAKEFLAGS", used to set macro value * not_auto dwight * read_trace_level Checked to se if the reader should trace * report_dependencies If -P is on we do not read .make.state * trace_reader Set if reader should trace * virtual_root The Name "VIRTUAL_ROOT", used to check value */ static void read_files_and_state(int argc, char **argv) { wchar_t buffer[1000]; wchar_t buffer_posix[1000]; register char ch; register char *cp; Property def_make_macro = NULL; Name def_make_name; Name default_makefile; String_rec dest; wchar_t destbuffer[STRING_BUFFER_LENGTH]; register int i; register int j; Name keep_state_name; int length; Name Makefile; register Property macro; struct stat make_state_stat; Name makefile_name; register int makefile_next = 0; register Boolean makefile_read = false; String_rec makeflags_string; String_rec makeflags_string_posix; String_rec * makeflags_string_current; Name makeflags_value_saved; register Name name; Name new_make_value; Boolean save_do_not_exec_rule; static wchar_t state_file_str; static char state_file_str_mb[MAXPATHLEN]; static struct _Name state_filename; Boolean temp; char tmp_char; wchar_t *tmp_wcs_buffer; register Name value; ASCII_Dyn_Array makeflags_and_macro; Boolean is_xpg4; /* * Remember current mode. It may be changed after reading makefile * and we will have to correct MAKEFLAGS variable. */ is_xpg4 = posix; MBSTOWCS(wcs_buffer, "KEEP_STATE"); keep_state_name = GETNAME(wcs_buffer, FIND_LENGTH); MBSTOWCS(wcs_buffer, "Makefile"); Makefile = GETNAME(wcs_buffer, FIND_LENGTH); MBSTOWCS(wcs_buffer, "makefile"); makefile_name = GETNAME(wcs_buffer, FIND_LENGTH); /* * initialize global dependency entry for .NOT_AUTO */ not_auto_depen->next = NULL; not_auto_depen->name = not_auto; not_auto_depen->automatic = not_auto_depen->stale = false; /* * Read internal definitions and rules. */ if (read_trace_level > 1) { trace_reader = true; } if (!ignore_default_mk) { if (svr4) { MBSTOWCS(wcs_buffer, "svr4.make.rules"); default_makefile = GETNAME(wcs_buffer, FIND_LENGTH); } else { MBSTOWCS(wcs_buffer, "make.rules"); default_makefile = GETNAME(wcs_buffer, FIND_LENGTH); } default_makefile->stat.is_file = true; (void) read_makefile(default_makefile, true, false, true); } /* * If the user did not redefine the MAKE macro in the * default makefile (make.rules), then we'd like to * change the macro value of MAKE to be some form * of argv[0] for recursive MAKE builds. */ MBSTOWCS(wcs_buffer, "MAKE"); def_make_name = GETNAME(wcs_buffer, wcslen(wcs_buffer)); def_make_macro = get_prop(def_make_name->prop, macro_prop); if ((def_make_macro != NULL) && (IS_EQUAL(def_make_macro->body.macro.value->string_mb, "make"))) { MBSTOWCS(wcs_buffer, argv_zero_string); new_make_value = GETNAME(wcs_buffer, wcslen(wcs_buffer)); (void) SETVAR(def_make_name, new_make_value, false); } default_target_to_build = NULL; trace_reader = false; /* * Read environment args. Let file args which follow override unless * -e option seen. If -e option is not mentioned. */ read_environment(env_wins); if (getvar(virtual_root)->hash.length == 0) { maybe_append_prop(virtual_root, macro_prop) ->body.macro.exported = true; MBSTOWCS(wcs_buffer, "/"); (void) SETVAR(virtual_root, GETNAME(wcs_buffer, FIND_LENGTH), false); } /* * We now scan mf_argv and argv to see if we need to set * any of the DMake-added options/variables in MAKEFLAGS. */ makeflags_and_macro.start = 0; makeflags_and_macro.size = 0; enter_argv_values(mf_argc, mf_argv, &makeflags_and_macro); enter_argv_values(argc, argv, &makeflags_and_macro); /* * Set MFLAGS and MAKEFLAGS * * Before reading makefile we do not know exactly which mode * (posix or not) is used. So prepare two MAKEFLAGS strings * for both posix and solaris modes because they are different. */ INIT_STRING_FROM_STACK(makeflags_string, buffer); INIT_STRING_FROM_STACK(makeflags_string_posix, buffer_posix); append_char((int) hyphen_char, &makeflags_string); append_char((int) hyphen_char, &makeflags_string_posix); switch (read_trace_level) { case 2: append_char('D', &makeflags_string); append_char('D', &makeflags_string_posix); /* FALLTHROUGH */ case 1: append_char('D', &makeflags_string); append_char('D', &makeflags_string_posix); } switch (debug_level) { case 2: append_char('d', &makeflags_string); append_char('d', &makeflags_string_posix); /* FALLTHROUGH */ case 1: append_char('d', &makeflags_string); append_char('d', &makeflags_string_posix); } if (env_wins) { append_char('e', &makeflags_string); append_char('e', &makeflags_string_posix); } if (ignore_errors_all) { append_char('i', &makeflags_string); append_char('i', &makeflags_string_posix); } if (continue_after_error) { if (stop_after_error_ever_seen) { append_char('S', &makeflags_string_posix); append_char((int) space_char, &makeflags_string_posix); append_char((int) hyphen_char, &makeflags_string_posix); } append_char('k', &makeflags_string); append_char('k', &makeflags_string_posix); } else { if (stop_after_error_ever_seen && continue_after_error_ever_seen) { append_char('k', &makeflags_string_posix); append_char((int) space_char, &makeflags_string_posix); append_char((int) hyphen_char, &makeflags_string_posix); append_char('S', &makeflags_string_posix); } } if (do_not_exec_rule) { append_char('n', &makeflags_string); append_char('n', &makeflags_string_posix); } switch (report_dependencies_level) { case 4: append_char('P', &makeflags_string); append_char('P', &makeflags_string_posix); /* FALLTHROUGH */ case 3: append_char('P', &makeflags_string); append_char('P', &makeflags_string_posix); /* FALLTHROUGH */ case 2: append_char('P', &makeflags_string); append_char('P', &makeflags_string_posix); /* FALLTHROUGH */ case 1: append_char('P', &makeflags_string); append_char('P', &makeflags_string_posix); } if (trace_status) { append_char('p', &makeflags_string); append_char('p', &makeflags_string_posix); } if (quest) { append_char('q', &makeflags_string); append_char('q', &makeflags_string_posix); } if (silent_all) { append_char('s', &makeflags_string); append_char('s', &makeflags_string_posix); } if (touch) { append_char('t', &makeflags_string); append_char('t', &makeflags_string_posix); } if (build_unconditional) { append_char('u', &makeflags_string); append_char('u', &makeflags_string_posix); } if (report_cwd) { append_char('w', &makeflags_string); append_char('w', &makeflags_string_posix); } /* -c dmake_rcfile */ if (dmake_rcfile_specified) { MBSTOWCS(wcs_buffer, "DMAKE_RCFILE"); dmake_rcfile = GETNAME(wcs_buffer, FIND_LENGTH); append_makeflags_string(dmake_rcfile, &makeflags_string); append_makeflags_string(dmake_rcfile, &makeflags_string_posix); } /* -g dmake_group */ if (dmake_group_specified) { MBSTOWCS(wcs_buffer, "DMAKE_GROUP"); dmake_group = GETNAME(wcs_buffer, FIND_LENGTH); append_makeflags_string(dmake_group, &makeflags_string); append_makeflags_string(dmake_group, &makeflags_string_posix); } /* -j dmake_max_jobs */ if (dmake_max_jobs_specified) { MBSTOWCS(wcs_buffer, "DMAKE_MAX_JOBS"); dmake_max_jobs = GETNAME(wcs_buffer, FIND_LENGTH); append_makeflags_string(dmake_max_jobs, &makeflags_string); append_makeflags_string(dmake_max_jobs, &makeflags_string_posix); } /* -m dmake_mode */ if (dmake_mode_specified) { MBSTOWCS(wcs_buffer, "DMAKE_MODE"); dmake_mode = GETNAME(wcs_buffer, FIND_LENGTH); append_makeflags_string(dmake_mode, &makeflags_string); append_makeflags_string(dmake_mode, &makeflags_string_posix); } /* -x dmake_compat_mode */ // if (dmake_compat_mode_specified) { // MBSTOWCS(wcs_buffer, "SUN_MAKE_COMPAT_MODE"); // dmake_compat_mode = GETNAME(wcs_buffer, FIND_LENGTH); // append_makeflags_string(dmake_compat_mode, &makeflags_string); // append_makeflags_string(dmake_compat_mode, &makeflags_string_posix); // } /* -x dmake_output_mode */ if (dmake_output_mode_specified) { MBSTOWCS(wcs_buffer, "DMAKE_OUTPUT_MODE"); dmake_output_mode = GETNAME(wcs_buffer, FIND_LENGTH); append_makeflags_string(dmake_output_mode, &makeflags_string); append_makeflags_string(dmake_output_mode, &makeflags_string_posix); } /* -o dmake_odir */ if (dmake_odir_specified) { MBSTOWCS(wcs_buffer, "DMAKE_ODIR"); dmake_odir = GETNAME(wcs_buffer, FIND_LENGTH); append_makeflags_string(dmake_odir, &makeflags_string); append_makeflags_string(dmake_odir, &makeflags_string_posix); } /* -M pmake_machinesfile */ if (pmake_machinesfile_specified) { MBSTOWCS(wcs_buffer, "PMAKE_MACHINESFILE"); pmake_machinesfile = GETNAME(wcs_buffer, FIND_LENGTH); append_makeflags_string(pmake_machinesfile, &makeflags_string); append_makeflags_string(pmake_machinesfile, &makeflags_string_posix); } /* -R */ if (pmake_cap_r_specified) { append_char((int) space_char, &makeflags_string); append_char((int) hyphen_char, &makeflags_string); append_char('R', &makeflags_string); append_char((int) space_char, &makeflags_string_posix); append_char((int) hyphen_char, &makeflags_string_posix); append_char('R', &makeflags_string_posix); } /* * Make sure MAKEFLAGS is exported */ maybe_append_prop(makeflags, macro_prop)-> body.macro.exported = true; if (makeflags_string.buffer.start[1] != (int) nul_char) { if (makeflags_string.buffer.start[1] != (int) space_char) { MBSTOWCS(wcs_buffer, "MFLAGS"); (void) SETVAR(GETNAME(wcs_buffer, FIND_LENGTH), GETNAME(makeflags_string.buffer.start, FIND_LENGTH), false); } else { MBSTOWCS(wcs_buffer, "MFLAGS"); (void) SETVAR(GETNAME(wcs_buffer, FIND_LENGTH), GETNAME(makeflags_string.buffer.start + 2, FIND_LENGTH), false); } } /* * Add command line macro to POSIX makeflags_string */ if (makeflags_and_macro.start) { tmp_char = (char) space_char; cp = makeflags_and_macro.start; do { append_char(tmp_char, &makeflags_string_posix); } while ( tmp_char = *cp++ ); retmem_mb(makeflags_and_macro.start); } /* * Now set the value of MAKEFLAGS macro in accordance * with current mode. */ macro = maybe_append_prop(makeflags, macro_prop); temp = (Boolean) macro->body.macro.read_only; macro->body.macro.read_only = false; if(posix || gnu_style) { makeflags_string_current = &makeflags_string_posix; } else { makeflags_string_current = &makeflags_string; } if (makeflags_string_current->buffer.start[1] == (int) nul_char) { makeflags_value_saved = GETNAME( makeflags_string_current->buffer.start + 1 , FIND_LENGTH ); } else { if (makeflags_string_current->buffer.start[1] != (int) space_char) { makeflags_value_saved = GETNAME( makeflags_string_current->buffer.start , FIND_LENGTH ); } else { makeflags_value_saved = GETNAME( makeflags_string_current->buffer.start + 2 , FIND_LENGTH ); } } (void) SETVAR( makeflags , makeflags_value_saved , false ); macro->body.macro.read_only = temp; /* * Read command line "-f" arguments and ignore -c, g, j, K, M, m, O and o args. */ save_do_not_exec_rule = do_not_exec_rule; do_not_exec_rule = false; if (read_trace_level > 0) { trace_reader = true; } for (i = 1; i < argc; i++) { if (argv[i] && (argv[i][0] == (int) hyphen_char) && (argv[i][1] == 'f') && (argv[i][2] == (int) nul_char)) { argv[i] = NULL; /* Remove -f */ if (i >= argc - 1) { fatal(gettext("No filename argument after -f flag")); } MBSTOWCS(wcs_buffer, argv[++i]); primary_makefile = GETNAME(wcs_buffer, FIND_LENGTH); (void) read_makefile(primary_makefile, true, true, true); argv[i] = NULL; /* Remove filename */ makefile_read = true; } else if (argv[i] && (argv[i][0] == (int) hyphen_char) && (argv[i][1] == 'c' || argv[i][1] == 'g' || argv[i][1] == 'j' || argv[i][1] == 'K' || argv[i][1] == 'M' || argv[i][1] == 'm' || argv[i][1] == 'O' || argv[i][1] == 'o') && (argv[i][2] == (int) nul_char)) { argv[i] = NULL; argv[++i] = NULL; } } /* * If no command line "-f" args then look for "makefile", and then for * "Makefile" if "makefile" isn't found. */ if (!makefile_read) { (void) read_dir(dot, (wchar_t *) NULL, (Property) NULL, (wchar_t *) NULL); if (!posix) { if (makefile_name->stat.is_file) { if (Makefile->stat.is_file) { warning(gettext("Both `makefile' and `Makefile' exist")); } primary_makefile = makefile_name; makefile_read = read_makefile(makefile_name, false, false, true); } if (!makefile_read && Makefile->stat.is_file) { primary_makefile = Makefile; makefile_read = read_makefile(Makefile, false, false, true); } } else { enum sccs_stat save_m_has_sccs = NO_SCCS; enum sccs_stat save_M_has_sccs = NO_SCCS; if (makefile_name->stat.is_file) { if (Makefile->stat.is_file) { warning(gettext("Both `makefile' and `Makefile' exist")); } } if (makefile_name->stat.is_file) { if (makefile_name->stat.has_sccs == NO_SCCS) { primary_makefile = makefile_name; makefile_read = read_makefile(makefile_name, false, false, true); } else { save_m_has_sccs = makefile_name->stat.has_sccs; makefile_name->stat.has_sccs = NO_SCCS; primary_makefile = makefile_name; makefile_read = read_makefile(makefile_name, false, false, true); } } if (!makefile_read && Makefile->stat.is_file) { if (Makefile->stat.has_sccs == NO_SCCS) { primary_makefile = Makefile; makefile_read = read_makefile(Makefile, false, false, true); } else { save_M_has_sccs = Makefile->stat.has_sccs; Makefile->stat.has_sccs = NO_SCCS; primary_makefile = Makefile; makefile_read = read_makefile(Makefile, false, false, true); } } if (!makefile_read && makefile_name->stat.is_file) { makefile_name->stat.has_sccs = save_m_has_sccs; primary_makefile = makefile_name; makefile_read = read_makefile(makefile_name, false, false, true); } if (!makefile_read && Makefile->stat.is_file) { Makefile->stat.has_sccs = save_M_has_sccs; primary_makefile = Makefile; makefile_read = read_makefile(Makefile, false, false, true); } } } do_not_exec_rule = save_do_not_exec_rule; allrules_read = makefile_read; trace_reader = false; /* * Now get current value of MAKEFLAGS and compare it with * the saved value we set before reading makefile. * If they are different then MAKEFLAGS is subsequently set by * makefile, just leave it there. Otherwise, if make mode * is changed by using .POSIX target in makefile we need * to correct MAKEFLAGS value. */ Name mf_val = getvar(makeflags); if( (posix != is_xpg4) && (!strcmp(mf_val->string_mb, makeflags_value_saved->string_mb))) { if (makeflags_string_posix.buffer.start[1] == (int) nul_char) { (void) SETVAR(makeflags, GETNAME(makeflags_string_posix.buffer.start + 1, FIND_LENGTH), false); } else { if (makeflags_string_posix.buffer.start[1] != (int) space_char) { (void) SETVAR(makeflags, GETNAME(makeflags_string_posix.buffer.start, FIND_LENGTH), false); } else { (void) SETVAR(makeflags, GETNAME(makeflags_string_posix.buffer.start + 2, FIND_LENGTH), false); } } } if (makeflags_string.free_after_use) { retmem(makeflags_string.buffer.start); } if (makeflags_string_posix.free_after_use) { retmem(makeflags_string_posix.buffer.start); } makeflags_string.buffer.start = NULL; makeflags_string_posix.buffer.start = NULL; if (posix) { /* * If the user did not redefine the ARFLAGS macro in the * default makefile (make.rules), then we'd like to * change the macro value of ARFLAGS to be in accordance * with "POSIX" requirements. */ MBSTOWCS(wcs_buffer, "ARFLAGS"); name = GETNAME(wcs_buffer, wcslen(wcs_buffer)); macro = get_prop(name->prop, macro_prop); if ((macro != NULL) && /* Maybe (macro == NULL) || ? */ (IS_EQUAL(macro->body.macro.value->string_mb, "rv"))) { MBSTOWCS(wcs_buffer, "-rv"); value = GETNAME(wcs_buffer, wcslen(wcs_buffer)); (void) SETVAR(name, value, false); } } if (!posix && !svr4) { set_sgs_support(); } /* * Make sure KEEP_STATE is in the environment if KEEP_STATE is on. */ macro = get_prop(keep_state_name->prop, macro_prop); if ((macro != NULL) && macro->body.macro.exported) { keep_state = true; } if (keep_state) { if (macro == NULL) { macro = maybe_append_prop(keep_state_name, macro_prop); } macro->body.macro.exported = true; (void) SETVAR(keep_state_name, empty_name, false); /* * Read state file */ /* Before we read state, let's make sure we have ** right state file. */ /* just in case macro references are used in make_state file ** name, we better expand them at this stage using expand_value. */ INIT_STRING_FROM_STACK(dest, destbuffer); expand_value(make_state, &dest, false); make_state = GETNAME(dest.buffer.start, FIND_LENGTH); if(!stat(make_state->string_mb, &make_state_stat)) { if(!(make_state_stat.st_mode & S_IFREG) ) { /* copy the make_state structure to the other ** and then let make_state point to the new ** one. */ memcpy(&state_filename, make_state,sizeof(state_filename)); state_filename.string_mb = state_file_str_mb; /* Just a kludge to avoid two slashes back to back */ if((make_state->hash.length == 1)&& (make_state->string_mb[0] == '/')) { make_state->hash.length = 0; make_state->string_mb[0] = '\0'; } sprintf(state_file_str_mb,"%s%s", make_state->string_mb,"/.make.state"); make_state = &state_filename; /* adjust the length to reflect the appended string */ make_state->hash.length += 12; } } else { /* the file doesn't exist or no permission */ char tmp_path[MAXPATHLEN]; char *slashp; if (slashp = strrchr(make_state->string_mb, '/')) { strncpy(tmp_path, make_state->string_mb, (slashp - make_state->string_mb)); tmp_path[slashp - make_state->string_mb]=0; if(strlen(tmp_path)) { if(stat(tmp_path, &make_state_stat)) { warning(gettext("directory %s for .KEEP_STATE_FILE does not exist"),tmp_path); } if (access(tmp_path, F_OK) != 0) { warning(gettext("can't access dir %s"),tmp_path); } } } } if (report_dependencies_level != 1) { Makefile_type makefile_type_temp = makefile_type; makefile_type = reading_statefile; if (read_trace_level > 1) { trace_reader = true; } (void) read_simple_file(make_state, false, false, false, false, false, true); trace_reader = false; makefile_type = makefile_type_temp; } } } /* * Scan the argv for options and "=" type args and make them readonly. */ static void enter_argv_values(int argc, char *argv[], ASCII_Dyn_Array *makeflags_and_macro) { register char *cp; register int i; int length; register Name name; int opt_separator = argc; char tmp_char; wchar_t *tmp_wcs_buffer; register Name value; Boolean append = false; Property macro; struct stat statbuf; /* Read argv options and "=" type args and make them readonly. */ makefile_type = reading_nothing; for (i = 1; i < argc; ++i) { append = false; if (argv[i] == NULL) { continue; } else if (((argv[i][0] == '-') && (argv[i][1] == '-')) || ((argv[i][0] == (int) ' ') && (argv[i][1] == (int) '-') && (argv[i][2] == (int) ' ') && (argv[i][3] == (int) '-'))) { argv[i] = NULL; opt_separator = i; continue; } else if ((i < opt_separator) && (argv[i][0] == (int) hyphen_char)) { switch (parse_command_option(argv[i][1])) { case 1: /* -f seen */ ++i; continue; case 2: /* -c seen */ if (argv[i+1] == NULL) { fatal(gettext("No dmake rcfile argument after -c flag")); } MBSTOWCS(wcs_buffer, "DMAKE_RCFILE"); name = GETNAME(wcs_buffer, FIND_LENGTH); break; case 4: /* -g seen */ if (argv[i+1] == NULL) { fatal(gettext("No dmake group argument after -g flag")); } MBSTOWCS(wcs_buffer, "DMAKE_GROUP"); name = GETNAME(wcs_buffer, FIND_LENGTH); break; case 8: /* -j seen */ if (argv[i+1] == NULL) { fatal(gettext("No dmake max jobs argument after -j flag")); } MBSTOWCS(wcs_buffer, "DMAKE_MAX_JOBS"); name = GETNAME(wcs_buffer, FIND_LENGTH); break; case 16: /* -M seen */ if (argv[i+1] == NULL) { fatal(gettext("No pmake machinesfile argument after -M flag")); } MBSTOWCS(wcs_buffer, "PMAKE_MACHINESFILE"); name = GETNAME(wcs_buffer, FIND_LENGTH); break; case 32: /* -m seen */ if (argv[i+1] == NULL) { fatal(gettext("No dmake mode argument after -m flag")); } MBSTOWCS(wcs_buffer, "DMAKE_MODE"); name = GETNAME(wcs_buffer, FIND_LENGTH); break; case 256: /* -K seen */ if (argv[i+1] == NULL) { fatal(gettext("No makestate filename argument after -K flag")); } MBSTOWCS(wcs_buffer, argv[i+1]); make_state = GETNAME(wcs_buffer, FIND_LENGTH); keep_state = true; argv[i] = NULL; argv[i+1] = NULL; continue; case 512: /* -o seen */ if (argv[i+1] == NULL) { fatal(gettext("No dmake output dir argument after -o flag")); } MBSTOWCS(wcs_buffer, "DMAKE_ODIR"); name = GETNAME(wcs_buffer, FIND_LENGTH); break; case 1024: /* -x seen */ if (argv[i+1] == NULL) { fatal(gettext("No argument after -x flag")); } length = strlen( "SUN_MAKE_COMPAT_MODE="); if (strncmp(argv[i+1], "SUN_MAKE_COMPAT_MODE=", length) == 0) { argv[i+1] = &argv[i+1][length]; MBSTOWCS(wcs_buffer, "SUN_MAKE_COMPAT_MODE"); name = GETNAME(wcs_buffer, FIND_LENGTH); dmake_compat_mode_specified = dmake_add_mode_specified; break; } length = strlen( "DMAKE_OUTPUT_MODE="); if (strncmp(argv[i+1], "DMAKE_OUTPUT_MODE=", length) == 0) { argv[i+1] = &argv[i+1][length]; MBSTOWCS(wcs_buffer, "DMAKE_OUTPUT_MODE"); name = GETNAME(wcs_buffer, FIND_LENGTH); dmake_output_mode_specified = dmake_add_mode_specified; } else { warning(gettext("Unknown argument `%s' after -x flag (ignored)"), argv[i+1]); argv[i] = argv[i + 1] = NULL; continue; } break; case 2048: /* -C seen */ /* * The chdir() will have been performed * in read_command_options(). * Just set DMAKE_CDIR here. */ if (argv[i + 1] == NULL) { fatal(gettext( "No argument after -C flag")); } MBSTOWCS(wcs_buffer, "DMAKE_CDIR"); name = GETNAME(wcs_buffer, FIND_LENGTH); break; default: /* Shouldn't reach here */ argv[i] = NULL; continue; } argv[i] = NULL; if (i == (argc - 1)) { break; } if ((length = strlen(argv[i+1])) >= MAXPATHLEN) { tmp_wcs_buffer = ALLOC_WC(length + 1); (void) mbstowcs(tmp_wcs_buffer, argv[i+1], length + 1); value = GETNAME(tmp_wcs_buffer, FIND_LENGTH); retmem(tmp_wcs_buffer); } else { MBSTOWCS(wcs_buffer, argv[i+1]); value = GETNAME(wcs_buffer, FIND_LENGTH); } argv[i+1] = NULL; } else if ((cp = strchr(argv[i], (int) equal_char)) != NULL) { /* * Combine all macro in dynamic array */ if(*(cp-1) == (int) plus_char) { if(isspace(*(cp-2))) { append = true; cp--; } } if(!append) append_or_replace_macro_in_dyn_array(makeflags_and_macro, argv[i]); while (isspace(*(cp-1))) { cp--; } tmp_char = *cp; *cp = (int) nul_char; MBSTOWCS(wcs_buffer, argv[i]); *cp = tmp_char; name = GETNAME(wcs_buffer, wcslen(wcs_buffer)); while (*cp != (int) equal_char) { cp++; } cp++; while (isspace(*cp) && (*cp != (int) nul_char)) { cp++; } if ((length = strlen(cp)) >= MAXPATHLEN) { tmp_wcs_buffer = ALLOC_WC(length + 1); (void) mbstowcs(tmp_wcs_buffer, cp, length + 1); value = GETNAME(tmp_wcs_buffer, FIND_LENGTH); retmem(tmp_wcs_buffer); } else { MBSTOWCS(wcs_buffer, cp); value = GETNAME(wcs_buffer, FIND_LENGTH); } argv[i] = NULL; } else { /* Illegal MAKEFLAGS argument */ continue; } if(append) { setvar_append(name, value); append = false; } else { macro = maybe_append_prop(name, macro_prop); macro->body.macro.exported = true; SETVAR(name, value, false)->body.macro.read_only = true; } } } /* * Append the DMake option and value to the MAKEFLAGS string. */ static void append_makeflags_string(Name name, register String makeflags_string) { const char *option; if (strcmp(name->string_mb, "DMAKE_GROUP") == 0) { option = " -g "; } else if (strcmp(name->string_mb, "DMAKE_MAX_JOBS") == 0) { option = " -j "; } else if (strcmp(name->string_mb, "DMAKE_MODE") == 0) { option = " -m "; } else if (strcmp(name->string_mb, "DMAKE_ODIR") == 0) { option = " -o "; } else if (strcmp(name->string_mb, "DMAKE_RCFILE") == 0) { option = " -c "; } else if (strcmp(name->string_mb, "PMAKE_MACHINESFILE") == 0) { option = " -M "; } else if (strcmp(name->string_mb, "DMAKE_OUTPUT_MODE") == 0) { option = " -x DMAKE_OUTPUT_MODE="; } else if (strcmp(name->string_mb, "SUN_MAKE_COMPAT_MODE") == 0) { option = " -x SUN_MAKE_COMPAT_MODE="; } else { fatal(gettext("Internal error: name not recognized in append_makeflags_string()")); } Property prop = maybe_append_prop(name, macro_prop); if( prop == 0 || prop->body.macro.value == 0 || prop->body.macro.value->string_mb == 0 ) { return; } char mbs_value[MAXPATHLEN + 100]; strcpy(mbs_value, option); strcat(mbs_value, prop->body.macro.value->string_mb); MBSTOWCS(wcs_buffer, mbs_value); append_string(wcs_buffer, makeflags_string, FIND_LENGTH); } /* * read_environment(read_only) * * This routine reads the process environment when make starts and enters * it as make macros. The environment variable SHELL is ignored. * * Parameters: * read_only Should we make env vars read only? * * Global variables used: * report_pwd Set if this make was started by other make */ static void read_environment(Boolean read_only) { register char **environment; int length; wchar_t *tmp_wcs_buffer; Boolean alloced_tmp_wcs_buffer = false; register wchar_t *name; register wchar_t *value; register Name macro; Property val; Boolean read_only_saved; reading_environment = true; environment = environ; for (; *environment; environment++) { read_only_saved = read_only; if ((length = strlen(*environment)) >= MAXPATHLEN) { tmp_wcs_buffer = ALLOC_WC(length + 1); alloced_tmp_wcs_buffer = true; (void) mbstowcs(tmp_wcs_buffer, *environment, length + 1); name = tmp_wcs_buffer; } else { MBSTOWCS(wcs_buffer, *environment); name = wcs_buffer; } value = (wchar_t *) wcschr(name, (int) equal_char); /* * Looks like there's a bug in the system, but sometimes * you can get blank lines in *environment. */ if (!value) { continue; } MBSTOWCS(wcs_buffer2, "SHELL="); if (IS_WEQUALN(name, wcs_buffer2, wcslen(wcs_buffer2))) { continue; } MBSTOWCS(wcs_buffer2, "MAKEFLAGS="); if (IS_WEQUALN(name, wcs_buffer2, wcslen(wcs_buffer2))) { report_pwd = true; /* * In POSIX mode we do not want MAKEFLAGS to be readonly. * If the MAKEFLAGS macro is subsequently set by the makefile, * it replaces the MAKEFLAGS variable currently found in the * environment. * See Assertion 50 in section 6.2.5.3 of standard P1003.3.2/D8. */ if(posix) { read_only_saved = false; } } /* * We ignore SUNPRO_DEPENDENCIES. This environment variable is * set by make and read by cpp which then writes info to * .make.dependency.xxx. When make is invoked by another make * (recursive make), we don't want to read this because then * the child make will end up writing to the parent * directory's .make.state and clobbering them. */ MBSTOWCS(wcs_buffer2, "SUNPRO_DEPENDENCIES"); if (IS_WEQUALN(name, wcs_buffer2, wcslen(wcs_buffer2))) { continue; } macro = GETNAME(name, value - name); maybe_append_prop(macro, macro_prop)->body.macro.exported = true; if ((value == NULL) || ((value + 1)[0] == (int) nul_char)) { val = setvar_daemon(macro, (Name) NULL, false, no_daemon, false, debug_level); } else { val = setvar_daemon(macro, GETNAME(value + 1, FIND_LENGTH), false, no_daemon, false, debug_level); } val->body.macro.read_only = read_only_saved; if (alloced_tmp_wcs_buffer) { retmem(tmp_wcs_buffer); alloced_tmp_wcs_buffer = false; } } reading_environment = false; } /* * read_makefile(makefile, complain, must_exist, report_file) * * Read one makefile and check the result * * Return value: * false is the read failed * * Parameters: * makefile The file to read * complain Passed thru to read_simple_file() * must_exist Passed thru to read_simple_file() * report_file Passed thru to read_simple_file() * * Global variables used: * makefile_type Set to indicate we are reading main file * recursion_level Initialized */ static Boolean read_makefile(register Name makefile, Boolean complain, Boolean must_exist, Boolean report_file) { Boolean b; makefile_type = reading_makefile; recursion_level = 0; reading_dependencies = true; b = read_simple_file(makefile, true, true, complain, must_exist, report_file, false); reading_dependencies = false; return b; } /* * make_targets(argc, argv, parallel_flag) * * Call doname on the specified targets * * Parameters: * argc You know what this is * argv You know what this is * parallel_flag True if building in parallel * * Global variables used: * build_failed_seen Used to generated message after failed -k * commands_done Used to generate message "Up to date" * default_target_to_build First proper target in makefile * init The Name ".INIT", use to run command * parallel Global parallel building flag * quest make -q, suppresses messages * recursion_level Initialized, used for tracing * report_dependencies make -P, regroves whole process */ static void make_targets(int argc, char **argv, Boolean parallel_flag) { int i; char *cp; Doname result; register Boolean target_to_make_found = false; (void) doname(init, true, true); recursion_level = 1; parallel = parallel_flag; /* * make remaining args */ /* if ((report_dependencies_level == 0) && parallel) { */ if (parallel) { /* * If building targets in parallel, start all of the * remaining args to build in parallel. */ for (i = 1; i < argc; i++) { if ((cp = argv[i]) != NULL) { commands_done = false; if ((cp[0] == (int) period_char) && (cp[1] == (int) slash_char)) { cp += 2; } if((cp[0] == (int) ' ') && (cp[1] == (int) '-') && (cp[2] == (int) ' ') && (cp[3] == (int) '-')) { argv[i] = NULL; continue; } MBSTOWCS(wcs_buffer, cp); //default_target_to_build = GETNAME(wcs_buffer, // FIND_LENGTH); default_target_to_build = normalize_name(wcs_buffer, wcslen(wcs_buffer)); if (default_target_to_build == wait_name) { if (parallel_process_cnt > 0) { finish_running(); } continue; } top_level_target = get_wstring(default_target_to_build->string_mb); /* * If we can't execute the current target in * parallel, hold off the target processing * to preserve the order of the targets as they appeared * in command line. */ if (!parallel_ok(default_target_to_build, false) && parallel_process_cnt > 0) { finish_running(); } result = doname_check(default_target_to_build, true, false, false); gather_recursive_deps(); if (/* !commands_done && */ (result == build_ok) && !quest && (report_dependencies_level == 0) /* && (exists(default_target_to_build) > file_doesnt_exist) */) { if (posix) { if (!commands_done) { (void) printf(gettext("`%s' is updated.\n"), default_target_to_build->string_mb); } else { if (no_action_was_taken) { (void) printf(gettext("`%s': no action was taken.\n"), default_target_to_build->string_mb); } } } else { default_target_to_build->stat.time = file_no_time; if (!commands_done && (exists(default_target_to_build) > file_doesnt_exist)) { (void) printf(gettext("`%s' is up to date.\n"), default_target_to_build->string_mb); } } } } } /* Now wait for all of the targets to finish running */ finish_running(); // setjmp(jmpbuffer); } for (i = 1; i < argc; i++) { if ((cp = argv[i]) != NULL) { target_to_make_found = true; if ((cp[0] == (int) period_char) && (cp[1] == (int) slash_char)) { cp += 2; } if((cp[0] == (int) ' ') && (cp[1] == (int) '-') && (cp[2] == (int) ' ') && (cp[3] == (int) '-')) { argv[i] = NULL; continue; } MBSTOWCS(wcs_buffer, cp); default_target_to_build = normalize_name(wcs_buffer, wcslen(wcs_buffer)); top_level_target = get_wstring(default_target_to_build->string_mb); report_recursion(default_target_to_build); commands_done = false; if (parallel) { result = (Doname) default_target_to_build->state; } else { result = doname_check(default_target_to_build, true, false, false); } gather_recursive_deps(); if (build_failed_seen) { build_failed_ever_seen = true; warning(gettext("Target `%s' not remade because of errors"), default_target_to_build->string_mb); } build_failed_seen = false; if (report_dependencies_level > 0) { print_dependencies(default_target_to_build, get_prop(default_target_to_build->prop, line_prop)); } default_target_to_build->stat.time = file_no_time; if (default_target_to_build->colon_splits > 0) { default_target_to_build->state = build_dont_know; } if (!parallel && /* !commands_done && */ (result == build_ok) && !quest && (report_dependencies_level == 0) /* && (exists(default_target_to_build) > file_doesnt_exist) */) { if (posix) { if (!commands_done) { (void) printf(gettext("`%s' is updated.\n"), default_target_to_build->string_mb); } else { if (no_action_was_taken) { (void) printf(gettext("`%s': no action was taken.\n"), default_target_to_build->string_mb); } } } else { if (!commands_done && (exists(default_target_to_build) > file_doesnt_exist)) { (void) printf(gettext("`%s' is up to date.\n"), default_target_to_build->string_mb); } } } } } /* * If no file arguments have been encountered, * make the first name encountered that doesnt start with a dot */ if (!target_to_make_found) { if (default_target_to_build == NULL) { fatal(gettext("No arguments to build")); } commands_done = false; top_level_target = get_wstring(default_target_to_build->string_mb); report_recursion(default_target_to_build); if (getenv("SPRO_EXPAND_ERRORS")){ (void) printf("::(%s)\n", default_target_to_build->string_mb); } result = doname_parallel(default_target_to_build, true, false); gather_recursive_deps(); if (build_failed_seen) { build_failed_ever_seen = true; warning(gettext("Target `%s' not remade because of errors"), default_target_to_build->string_mb); } build_failed_seen = false; if (report_dependencies_level > 0) { print_dependencies(default_target_to_build, get_prop(default_target_to_build-> prop, line_prop)); } default_target_to_build->stat.time = file_no_time; if (default_target_to_build->colon_splits > 0) { default_target_to_build->state = build_dont_know; } if (/* !commands_done && */ (result == build_ok) && !quest && (report_dependencies_level == 0) /* && (exists(default_target_to_build) > file_doesnt_exist) */) { if (posix) { if (!commands_done) { (void) printf(gettext("`%s' is updated.\n"), default_target_to_build->string_mb); } else { if (no_action_was_taken) { (void) printf(gettext("`%s': no action was taken.\n"), default_target_to_build->string_mb); } } } else { if (!commands_done && (exists(default_target_to_build) > file_doesnt_exist)) { (void) printf(gettext("`%s' is up to date.\n"), default_target_to_build->string_mb); } } } } } /* * report_recursion(target) * * If this is a recursive make and the parent make has KEEP_STATE on * this routine reports the dependency to the parent make * * Parameters: * target Target to report * * Global variables used: * makefiles_used List of makefiles read * recursive_name The Name ".RECURSIVE", printed * report_dependency dwight */ static void report_recursion(register Name target) { register FILE *report_file = get_report_file(); if ((report_file == NULL) || (report_file == (FILE*)-1)) { return; } if (primary_makefile == NULL) { /* * This can happen when there is no makefile and * only implicit rules are being used. */ return; } (void) fprintf(report_file, "%s: %s ", get_target_being_reported_for(), recursive_name->string_mb); report_dependency(get_current_path()); report_dependency(target->string_mb); report_dependency(primary_makefile->string_mb); (void) fprintf(report_file, "\n"); } /* Next function "append_or_replace_macro_in_dyn_array" must be in "misc.cc". */ /* NIKMOL */ extern void append_or_replace_macro_in_dyn_array(ASCII_Dyn_Array *Ar, char *macro) { register char *cp0; /* work pointer in macro */ register char *cp1; /* work pointer in array */ register char *cp2; /* work pointer in array */ register char *cp3; /* work pointer in array */ register char *name; /* macro name */ register char *value; /* macro value */ register int len_array; register int len_macro; char * esc_value = NULL; int esc_len; if (!(len_macro = strlen(macro))) return; name = macro; while (isspace(*(name))) { name++; } if (!(value = strchr(name, (int) equal_char))) { /* no '=' in macro */ goto ERROR_MACRO; } cp0 = value; value++; while (isspace(*(value))) { value++; } while (isspace(*(cp0-1))) { cp0--; } if (cp0 <= name) goto ERROR_MACRO; /* no name */ if (!(Ar->size)) goto ALLOC_ARRAY; cp1 = Ar->start; LOOK_FOR_NAME: if (!(cp1 = strchr(cp1, name[0]))) goto APPEND_MACRO; if (!(cp2 = strchr(cp1, (int) equal_char))) goto APPEND_MACRO; if (strncmp(cp1, name, (size_t)(cp0-name))) { /* another name */ cp1++; goto LOOK_FOR_NAME; } if (cp1 != Ar->start) { if (!isspace(*(cp1-1))) { /* another name */ cp1++; goto LOOK_FOR_NAME; } } for (cp3 = cp1 + (cp0-name); cp3 < cp2; cp3++) { if (isspace(*cp3)) continue; /* else: another name */ cp1++; goto LOOK_FOR_NAME; } /* Look for the next macro name in array */ cp3 = cp2+1; if (*cp3 != (int) doublequote_char) { /* internal error */ goto ERROR_MACRO; } if (!(cp3 = strchr(cp3+1, (int) doublequote_char))) { /* internal error */ goto ERROR_MACRO; } cp3++; while (isspace(*cp3)) { cp3++; } cp2 = cp1; /* remove old macro */ if ((*cp3) && (cp3 < Ar->start + Ar->size)) { for (; cp3 < Ar->start + Ar->size; cp3++) { *cp2++ = *cp3; } } for (; cp2 < Ar->start + Ar->size; cp2++) { *cp2 = 0; } if (*cp1) { /* check next name */ goto LOOK_FOR_NAME; } goto APPEND_MACRO; ALLOC_ARRAY: if (Ar->size) { cp1 = Ar->start; } else { cp1 = 0; } Ar->size += 128; Ar->start = getmem(Ar->size); for (len_array=0; len_array < Ar->size; len_array++) { Ar->start[len_array] = 0; } if (cp1) { strcpy(Ar->start, cp1); retmem((wchar_t *) cp1); } APPEND_MACRO: len_array = strlen(Ar->start); esc_value = (char*)malloc(strlen(value)*2 + 1); quote_str(value, esc_value); esc_len = strlen(esc_value) - strlen(value); if (len_array + len_macro + esc_len + 5 >= Ar->size) goto ALLOC_ARRAY; strcat(Ar->start, " "); strncat(Ar->start, name, cp0-name); strcat(Ar->start, "="); strncat(Ar->start, esc_value, strlen(esc_value)); free(esc_value); return; ERROR_MACRO: /* Macro without '=' or with invalid left/right part */ return; } static void report_dir_enter_leave(Boolean entering) { char rcwd[MAXPATHLEN]; static char * mlev = NULL; char * make_level_str = NULL; int make_level_val = 0; make_level_str = getenv("MAKELEVEL"); if(make_level_str) { make_level_val = atoi(make_level_str); } if(mlev == NULL) { mlev = (char*) malloc(MAXPATHLEN); } if(entering) { sprintf(mlev, "MAKELEVEL=%d", make_level_val + 1); } else { make_level_val--; sprintf(mlev, "MAKELEVEL=%d", make_level_val); } putenv(mlev); if(report_cwd) { if(make_level_val <= 0) { if(entering) { sprintf(rcwd, gettext("%s: Entering directory `%s'\n"), getprogname(), get_current_path()); } else { sprintf(rcwd, gettext("%s: Leaving directory `%s'\n"), getprogname(), get_current_path()); } } else { if(entering) { sprintf(rcwd, gettext("%s[%d]: Entering directory `%s'\n"), getprogname(), make_level_val, get_current_path()); } else { sprintf(rcwd, gettext("%s[%d]: Leaving directory `%s'\n"), getprogname(), make_level_val, get_current_path()); } } printf("%s", rcwd); } }