3248 lines
85 KiB
C++
3248 lines
85 KiB
C++
/*
|
|
* 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.
|
|
*/
|
|
|
|
/*
|
|
* main.cc
|
|
*
|
|
* make program main routine plus some helper routines
|
|
*/
|
|
|
|
/*
|
|
* Included files
|
|
*/
|
|
#include <bsd/bsd.h> /* bsd_signal() */
|
|
|
|
|
|
#include <locale.h> /* setlocale() */
|
|
#include <libgen.h>
|
|
#include <mk/defs.h>
|
|
#include <mksh/macro.h> /* getvar() */
|
|
#include <mksh/misc.h> /* getmem(), setup_char_semantics() */
|
|
|
|
#include <pwd.h> /* getpwnam() */
|
|
#include <setjmp.h>
|
|
#include <signal.h>
|
|
#include <stdlib.h>
|
|
#include <sys/errno.h> /* ENOENT */
|
|
#include <sys/stat.h> /* fstat() */
|
|
#include <fcntl.h> /* open() */
|
|
#include <ctype.h>
|
|
|
|
#ifdef __sun
|
|
# include <sys/systeminfo.h> /* sysinfo() */
|
|
#else
|
|
#include <sys/sysinfo.h>
|
|
#endif
|
|
|
|
#include <sys/types.h> /* stat() */
|
|
#include <sys/wait.h> /* wait() */
|
|
#include <unistd.h> /* execv(), unlink(), access() */
|
|
#include <vroot/report.h> /* report_dependency(), get_report_file() */
|
|
|
|
#include <libintl.h> // gettext()
|
|
|
|
#include <comp/progname.h>
|
|
|
|
// 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"
|
|
#if defined(__i386) || defined(__x86_64__)
|
|
#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;
|
|
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();
|
|
#ifdef __sun
|
|
bsd_signals();
|
|
#else
|
|
// XXX necessary on linux?
|
|
#endif
|
|
|
|
(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);
|
|
}
|
|
|
|
/*
|
|
* 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 standart */
|
|
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();
|
|
|
|
setup_for_projectdir();
|
|
|
|
/*
|
|
* 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);
|
|
}
|
|
|
|
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
|
|
*/
|
|
#ifdef __sun
|
|
(void) bsd_signal(SIGALRM, (SIG_PF)doalarm);
|
|
#else
|
|
(void) bsd_signal(SIGALRM, doalarm);
|
|
#endif
|
|
|
|
/*
|
|
* 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:
|
|
*/
|
|
/*ARGSUSED*/
|
|
static void
|
|
doalarm(int)
|
|
{
|
|
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;
|
|
|
|
// Apparently, the semantics of a leading '-' in the optstring differ
|
|
// between Solaris and GNU libc.
|
|
// Also, the '+' is probably a good idea for GNU libc to avoid
|
|
// reording of arguments.
|
|
#ifdef __sun
|
|
#define SUNPRO_CMD_OPTS "-~Bbc:Ddef:g:ij:K:kM:m:NnO:o:PpqRrSsTtuVvwx:"
|
|
#define SVR4_CMD_OPTS "-c:ef:g:ij:km:nO:o:pqrsTtVv"
|
|
#else
|
|
#define SUNPRO_CMD_OPTS "+~Bbc:Ddef:g:ij:K:kM:m:NnO:o:PpqRrSsTtuVvwx:"
|
|
#define SVR4_CMD_OPTS "+c:ef:g:ij:km:nO:o:pqrsTtVv"
|
|
#endif
|
|
|
|
|
|
/*
|
|
* 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 ]\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 ]\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;
|
|
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 '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(
|
|
#ifdef __sun
|
|
"/proc/self/path/a.out",
|
|
#else
|
|
"/proc/self/exe",
|
|
#endif
|
|
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;
|
|
Name sdotMakefile;
|
|
Name sdotmakefile_name;
|
|
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);
|
|
MBSTOWCS(wcs_buffer, "s.makefile");
|
|
sdotmakefile_name = GETNAME(wcs_buffer, FIND_LENGTH);
|
|
MBSTOWCS(wcs_buffer, "s.Makefile");
|
|
sdotMakefile = 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);
|
|
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);
|
|
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);
|
|
case 3:
|
|
append_char('P', &makeflags_string);
|
|
append_char('P', &makeflags_string_posix);
|
|
case 2:
|
|
append_char('P', &makeflags_string);
|
|
append_char('P', &makeflags_string_posix);
|
|
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;
|
|
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);
|
|
}
|
|
}
|