1535 lines
37 KiB
C
1535 lines
37 KiB
C
#ident "@(#)main.c 1.1 94/10/31 Copyright 1986,1987,1988 Sun Micro"
|
|
|
|
/*
|
|
* main.c
|
|
*
|
|
* make program main routine plus some helper routines
|
|
*/
|
|
|
|
/*
|
|
* Included files
|
|
*/
|
|
#include "defs.h"
|
|
#include "report.h"
|
|
#include <signal.h>
|
|
#include <pwd.h>
|
|
#include <sys/file.h>
|
|
#include <sys/wait.h>
|
|
#include <sys/resource.h>
|
|
#include <sys/stat.h>
|
|
#include <sys/dk.h>
|
|
#include <rpcsvc/rstat.h>
|
|
|
|
/*
|
|
* Defined macros
|
|
*/
|
|
|
|
/*
|
|
* typedefs & structs
|
|
*/
|
|
|
|
/*
|
|
* Static variables
|
|
*/
|
|
static Boolean env_wins; /* `-e' */
|
|
static Boolean ignore_default_mk; /* `-r' */
|
|
static Dependency_rec not_auto_depen_struct;
|
|
static Dependency not_auto_depen = ¬_auto_depen_struct;
|
|
static Boolean trace_status; /* `-p' */
|
|
|
|
/*
|
|
* File table of contents
|
|
*/
|
|
extern void main();
|
|
extern int cleanup_after_exit();
|
|
extern void handle_interrupt();
|
|
extern void doalarm();
|
|
extern Name read_command_options();
|
|
extern int parse_command_option();
|
|
extern void set_target_host_arch();
|
|
extern void setup_for_projectdir();
|
|
extern void read_files_and_state();
|
|
extern void read_environment();
|
|
extern Boolean read_makefile();
|
|
extern void make_targets();
|
|
extern void print_dependencies();
|
|
extern void print_more_deps();
|
|
extern void print_deps();
|
|
extern Boolean should_print_dep();
|
|
extern void report_recursion();
|
|
|
|
|
|
/*
|
|
* main(argc, argv)
|
|
*
|
|
* Parameters:
|
|
* argc You know what this is
|
|
* argv You know what this is
|
|
*
|
|
* Static variables used:
|
|
* 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
|
|
*/
|
|
void
|
|
main(argc, argv)
|
|
register int argc;
|
|
register char *argv[];
|
|
{
|
|
register char *cp;
|
|
register Property macro;
|
|
struct stat out_stat, err_stat;
|
|
Boolean parallel_flag = false;
|
|
struct sigvec vec;
|
|
Name make_machines;
|
|
|
|
/* find out if stdout and stderr point to the same place */
|
|
if (fstat(1, &out_stat) < 0) {
|
|
fatal("fstat of standard out failed: %s", errmsg(errno));
|
|
}
|
|
if (fstat(2, &err_stat) < 0) {
|
|
fatal("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) on_exit(cleanup_after_exit, (char *) NULL);
|
|
|
|
load_cached_names();
|
|
|
|
set_target_host_arch();
|
|
|
|
/*
|
|
* Set command line flags
|
|
*/
|
|
for (cp = getenv(makeflags->string);
|
|
(cp != NULL) && (*cp != (int) nul_char);
|
|
cp++) {
|
|
(void) parse_command_option(*cp);
|
|
}
|
|
make_machines = read_command_options(argc, argv);
|
|
if (debug_level > 0) {
|
|
cp = getenv(makeflags->string);
|
|
(void) printf("MAKEFLAGS value: %s\n", cp == NULL ? "":cp);
|
|
}
|
|
|
|
|
|
read_files_and_state(argc, argv);
|
|
|
|
/*
|
|
* Set the parallel variables in the environment
|
|
*/
|
|
macro = get_prop(remote_command_name->prop, macro_prop);
|
|
if (macro != NULL) {
|
|
macro->body.macro.exported = true;
|
|
(void) SETVAR(remote_command_name,
|
|
macro->body.macro.value,
|
|
false);
|
|
}
|
|
|
|
#ifdef PARALLEL
|
|
parallel_flag = read_make_machines(make_machines);
|
|
#else
|
|
parallel_flag = false;
|
|
#endif
|
|
|
|
setup_interrupt();
|
|
|
|
/*
|
|
* Enable interrupt handler for alarms
|
|
*/
|
|
vec.sv_handler = doalarm;
|
|
vec.sv_mask = 0;
|
|
vec.sv_flags = SV_INTERRUPT;
|
|
if (sigvec(SIGALRM, &vec, (struct sigvec *) NULL) < 0) {
|
|
fatal("sigvec for alarm failed: %s", errmsg(errno));
|
|
}
|
|
|
|
/*
|
|
* Check if make should report
|
|
*/
|
|
if (getenv(sunpro_dependencies->string) != 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
|
|
* and NSE_DEP.
|
|
*/
|
|
if (keep_state) {
|
|
maybe_append_prop(sunpro_dependencies, macro_prop)->
|
|
body.macro.exported = true;
|
|
(void) SETVAR(sunpro_dependencies,
|
|
GETNAME("", FIND_LENGTH),
|
|
false);
|
|
(void) setenv("NSE_DEP", get_current_path());
|
|
} else {
|
|
maybe_append_prop(sunpro_dependencies, macro_prop)->
|
|
body.macro.exported = false;
|
|
}
|
|
|
|
working_on_targets = true;
|
|
if (trace_status) {
|
|
dump_make_state();
|
|
exit(0);
|
|
}
|
|
trace_reader = false;
|
|
temp_file_directory = get_current_path();
|
|
|
|
make_targets(argc, argv, parallel_flag);
|
|
|
|
exit(0);
|
|
/* NOTREACHED */
|
|
}
|
|
|
|
/*
|
|
* cleanup_after_exit()
|
|
*
|
|
* Called from exit(), performs cleanup actions.
|
|
*
|
|
* Parameters:
|
|
* status The argument exit() was called with
|
|
*
|
|
* 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
|
|
*/
|
|
int
|
|
cleanup_after_exit(status)
|
|
int status;
|
|
{
|
|
Running rp;
|
|
Property line;
|
|
char push_cmd[MAXPATHLEN + MAXPATHLEN +
|
|
NSE_TFS_PUSH_LEN + 3];
|
|
char *active;
|
|
|
|
parallel = false;
|
|
/* Build the target .DONE or .FAILED if we caught an error */
|
|
if (!quest) {
|
|
Name failed_name;
|
|
|
|
failed_name = GETNAME(".FAILED", FIND_LENGTH);
|
|
if ((status != 0) && (failed_name->prop != NULL)) {
|
|
(void) doname(failed_name, false, true);
|
|
} else {
|
|
(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);
|
|
}
|
|
/* 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);
|
|
}
|
|
if (rp->stdout_file != NULL) {
|
|
(void) unlink(rp->stdout_file->string);
|
|
}
|
|
if (rp->stderr_file != NULL) {
|
|
(void) unlink(rp->stderr_file->string);
|
|
}
|
|
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 (make_state_lockfile != NULL) {
|
|
(void) unlink(make_state_lockfile);
|
|
}
|
|
/* Write .make.state */
|
|
write_state_file(1);
|
|
/* If running inside an activated environment, push the */
|
|
/* .nse_depinfo file (if written) */
|
|
active = getenv(NSE_VARIANT_ENV);
|
|
if (keep_state &&
|
|
(NULL != active) &&
|
|
!IS_EQUAL(active, NSE_RT_SOURCE_NAME) &&
|
|
!do_not_exec_rule &&
|
|
!report_dependencies_only) {
|
|
(void) sprintf(push_cmd,
|
|
"%s %s/%s",
|
|
NSE_TFS_PUSH,
|
|
get_current_path(),
|
|
NSE_DEPINFO);
|
|
(void) system(push_cmd);
|
|
}
|
|
}
|
|
|
|
/*
|
|
* handle_interrupt()
|
|
*
|
|
* This is where C-C traps are caught.
|
|
*
|
|
* Parameters:
|
|
*
|
|
* Global variables used:
|
|
* 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()
|
|
{
|
|
Property member;
|
|
Running rp;
|
|
|
|
(void) fflush(stdout);
|
|
#ifdef PARALLEL
|
|
/* Clean up all parallel children already finished */
|
|
finish_children(false);
|
|
#endif
|
|
/* Make sure the processes running under us terminate first */
|
|
while (wait((union wait *) 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) {
|
|
if (exists(current_target) != (int) file_doesnt_exist) {
|
|
(void) fprintf(stderr,
|
|
"\n*** %s ",
|
|
current_target->string);
|
|
if (current_target->stat.is_dir) {
|
|
(void) fprintf(stderr,
|
|
"not removed.\n",
|
|
current_target->string);
|
|
} else if (unlink(current_target->string) == 0) {
|
|
(void) fprintf(stderr,
|
|
"removed.\n",
|
|
current_target->string);
|
|
} else {
|
|
(void) fprintf(stderr,
|
|
"could not be removed: %s.\n",
|
|
current_target->string,
|
|
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) {
|
|
if (exists(rp->target) != (int) file_doesnt_exist) {
|
|
(void) fprintf(stderr,
|
|
"\n*** %s ",
|
|
rp->target->string);
|
|
if (rp->target->stat.is_dir) {
|
|
(void) fprintf(stderr,
|
|
"not removed.\n",
|
|
rp->target->string);
|
|
} else if (unlink(rp->target->string) == 0) {
|
|
(void) fprintf(stderr,
|
|
"removed.\n",
|
|
rp->target->string);
|
|
} else {
|
|
(void) fprintf(stderr,
|
|
"could not be removed: %s.\n",
|
|
rp->target->string,
|
|
errmsg(errno));
|
|
}
|
|
}
|
|
}
|
|
}
|
|
exit(2);
|
|
}
|
|
|
|
/*
|
|
* doalarm(sig, code, scp)
|
|
*
|
|
* Handle the alarm interrupt but do nothing. Side effect is to
|
|
* cause return from wait3.
|
|
*
|
|
* Parameters:
|
|
* sig
|
|
* code
|
|
* scp
|
|
*
|
|
* Global variables used:
|
|
*/
|
|
/*ARGSUSED*/
|
|
static void
|
|
doalarm(sig, code, scp)
|
|
int sig;
|
|
int code;
|
|
struct sigcontext *scp;
|
|
{
|
|
return;
|
|
}
|
|
|
|
|
|
/*
|
|
* read_command_options(argc, argv)
|
|
*
|
|
* Scan the command 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 Name
|
|
read_command_options(argc, argv)
|
|
register int argc;
|
|
register char **argv;
|
|
{
|
|
register int i;
|
|
register int j;
|
|
register char ch;
|
|
register int makefile_next = 0; /* flag to note -f option */
|
|
Name make_machines = NULL;
|
|
|
|
for (i = 1; i < argc; i++) {
|
|
switch (makefile_next) {
|
|
case 1:
|
|
makefile_next = 0;
|
|
continue;
|
|
case 2:
|
|
make_state = GETNAME(argv[i], FIND_LENGTH);
|
|
makefile_next = 0;
|
|
continue;
|
|
case 4:
|
|
make_machines = GETNAME(argv[i], FIND_LENGTH);
|
|
makefile_next = 0;
|
|
continue;
|
|
}
|
|
if ((argv[i] != NULL) && (argv[i][0] == (int) hyphen_char)) {
|
|
for (j = 1; (ch = argv[i][j]) != (int) nul_char; j++) {
|
|
makefile_next |=
|
|
parse_command_option(ch);
|
|
}
|
|
switch (makefile_next) {
|
|
case 0:
|
|
argv[i] = NULL;
|
|
break;
|
|
case 1: /* -f seen */
|
|
argv[i] = "-f";
|
|
break;
|
|
case 2: /* -F seen */
|
|
argv[i] = "-F";
|
|
break;
|
|
case 4: /* -M seen */
|
|
argv[i] = "-M";
|
|
break;
|
|
default: /* more than one of -f, -F, -M seen */
|
|
fatal("Illegal command line. More than one option requiring\nfile argument given in the same argument group");
|
|
}
|
|
}
|
|
}
|
|
return make_machines;
|
|
}
|
|
|
|
/*
|
|
* parse_command_option(ch)
|
|
*
|
|
* Parse make command line options.
|
|
*
|
|
* Return value:
|
|
* Indicates if any -f -F or -M were seen
|
|
*
|
|
* Parameters:
|
|
* ch The character to parse
|
|
*
|
|
* Static variables used:
|
|
* env_wins Set for make -e
|
|
* ignore_default_mk Set for make -r
|
|
* trace_status Set for make -p
|
|
*
|
|
* Global variables used:
|
|
* 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 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 Set for make -s
|
|
* touch Set for make -t
|
|
*/
|
|
static int
|
|
parse_command_option(ch)
|
|
register char ch;
|
|
{
|
|
static int invert_next = 0;
|
|
int invert_this = invert_next;
|
|
|
|
invert_next = 0;
|
|
switch (ch) {
|
|
case '~': /* Invert next option */
|
|
invert_next = 1;
|
|
return 0;
|
|
case 'B': /* Obsolete */
|
|
return 0;
|
|
case 'b': /* Obsolete */
|
|
return 0;
|
|
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 .make.state */
|
|
return 2;
|
|
case 'f': /* Read alternative makefile(s) */
|
|
return 1;
|
|
case 'g': /* sccs get files not found */
|
|
return 0;
|
|
case 'i': /* ignore errors */
|
|
if (invert_this) {
|
|
ignore_errors = false;
|
|
} else {
|
|
ignore_errors = true;
|
|
}
|
|
return 0;
|
|
case 'k': /* Keep making even after errors */
|
|
if (invert_this) {
|
|
continue_after_error = false;
|
|
} else {
|
|
continue_after_error = true;
|
|
}
|
|
return 0;
|
|
case 'm': /* Obsolete */
|
|
return 0;
|
|
#ifdef PARALLEL
|
|
case 'M': /* Read alt make.machines file */
|
|
return 4;
|
|
#endif PARALLEL
|
|
case 'n': /* print, not exec commands */
|
|
if (invert_this) {
|
|
do_not_exec_rule = false;
|
|
} else {
|
|
do_not_exec_rule = true;
|
|
}
|
|
return 0;
|
|
case 'N': /* Reverse -n */
|
|
if (invert_this) {
|
|
do_not_exec_rule = true;
|
|
} else {
|
|
do_not_exec_rule = false;
|
|
}
|
|
return 0;
|
|
case 'P': /* print for selected targets */
|
|
if (invert_this) {
|
|
report_dependencies_only = false;
|
|
} else {
|
|
report_dependencies_only = true;
|
|
}
|
|
return 0;
|
|
case 'p': /* print description */
|
|
if (invert_this) {
|
|
trace_status = false;
|
|
} else {
|
|
trace_status = true;
|
|
}
|
|
return 0;
|
|
case 'q': /* question flag */
|
|
if (invert_this) {
|
|
quest = false;
|
|
} else {
|
|
quest = true;
|
|
}
|
|
return 0;
|
|
case 'r': /* turn off internal rules */
|
|
if (invert_this) {
|
|
ignore_default_mk = false;
|
|
} else {
|
|
ignore_default_mk = true;
|
|
}
|
|
return 0;
|
|
#ifdef PARALLEL
|
|
case 'R': /* don't run in parallel */
|
|
if (invert_this) {
|
|
no_parallel = false;
|
|
} else {
|
|
no_parallel = true;
|
|
}
|
|
return 0;
|
|
#endif
|
|
case 'S': /* Reverse -k */
|
|
if (invert_this) {
|
|
continue_after_error = true;
|
|
} else {
|
|
continue_after_error = false;
|
|
}
|
|
return 0;
|
|
case 's': /* silent flag */
|
|
if (invert_this) {
|
|
silent = false;
|
|
} else {
|
|
silent = true;
|
|
}
|
|
return 0;
|
|
case 't': /* touch flag */
|
|
if (invert_this) {
|
|
touch = false;
|
|
} else {
|
|
touch = true;
|
|
}
|
|
return 0;
|
|
case 'X': /* Filter stdout */
|
|
if (invert_this) {
|
|
filter_stderr = true;
|
|
} else {
|
|
filter_stderr = true;
|
|
}
|
|
return 0;
|
|
default:
|
|
fatal("Unknown option `-%c'", ch);
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
/*
|
|
* set_target_host_arch()
|
|
*
|
|
* Set the magic macros TARGET_ARCH, HOST_ARCH,
|
|
* TARGET_MACH & HOST_MACH
|
|
*
|
|
* Parameters:
|
|
*
|
|
* Global variables used:
|
|
*/
|
|
static void
|
|
set_target_host_arch()
|
|
{
|
|
String_rec result_string;
|
|
char buffer[STRING_BUFFER_LENGTH];
|
|
FILE *pipe;
|
|
Name name;
|
|
register int ch;
|
|
|
|
INIT_STRING_FROM_STACK(result_string, buffer);
|
|
append_char((int) hyphen_char, &result_string);
|
|
if ((pipe = popen("/bin/arch", "r")) == NULL) {
|
|
fatal("Execute of /bin/arch failed");
|
|
}
|
|
while ((ch = getc(pipe)) != EOF) {
|
|
append_char(ch, &result_string);
|
|
}
|
|
if (pclose(pipe) != NULL) {
|
|
fatal("Execute of /bin/arch failed");
|
|
}
|
|
|
|
name = GETNAME(result_string.buffer.start,
|
|
strlen(result_string.buffer.start)-1);
|
|
(void) SETVAR(host_arch, name, false);
|
|
(void) SETVAR(target_arch, name, false);
|
|
INIT_STRING_FROM_STACK(result_string, buffer);
|
|
append_char((int) hyphen_char, &result_string);
|
|
if ((pipe = popen("/bin/mach", "r")) == NULL) {
|
|
fatal("Execute of /bin/mach failed");
|
|
}
|
|
while ((ch = getc(pipe)) != EOF) {
|
|
append_char(ch, &result_string);
|
|
}
|
|
if (pclose(pipe) != NULL) {
|
|
fatal("Execute of /bin/mach failed");
|
|
}
|
|
|
|
name = GETNAME(result_string.buffer.start,
|
|
strlen(result_string.buffer.start)-1);
|
|
(void) SETVAR(GETNAME("HOST_MACH", FIND_LENGTH), name, false);
|
|
(void) SETVAR(GETNAME("TARGET_MACH", FIND_LENGTH), name, false);
|
|
}
|
|
|
|
/*
|
|
* 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()
|
|
{
|
|
char path[MAXPATHLEN];
|
|
|
|
/* 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;
|
|
|
|
if ((pwent = getpwnam(sccs_dir_path)) == NULL) {
|
|
fatal("Bogus PROJECTDIR '%s'", sccs_dir_path);
|
|
}
|
|
(void) sprintf(path, "%s/src", pwent->pw_dir);
|
|
if (access(path, F_OK) == 0) {
|
|
sccs_dir_path = path;
|
|
} else {
|
|
(void) sprintf(path, "%s/source", pwent->pw_dir);
|
|
if (access(path, F_OK) == 0) {
|
|
sccs_dir_path = path;
|
|
} else {
|
|
sccs_dir_path = NULL;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
/*
|
|
* 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 default.mk 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
|
|
* nse Set if NSE_ENV is in the environment
|
|
* 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(argc, argv)
|
|
int argc;
|
|
char **argv;
|
|
{
|
|
register int i;
|
|
register char *cp;
|
|
register Name name;
|
|
register Boolean makefile_read = false;
|
|
Boolean save_do_not_exec_rule;
|
|
register Property macro;
|
|
Name keep_state_name;
|
|
Name Makefile;
|
|
Name makefile_name;
|
|
Boolean temp;
|
|
String_rec makeflags_string;
|
|
char buffer[100];
|
|
|
|
keep_state_name = GETNAME("KEEP_STATE", FIND_LENGTH);
|
|
Makefile = GETNAME("Makefile", FIND_LENGTH);
|
|
makefile_name = GETNAME("makefile", FIND_LENGTH);
|
|
|
|
/*
|
|
* Set flag if NSE is active
|
|
*/
|
|
if (getenv("NSE_ENV") != NULL) {
|
|
nse = true;
|
|
}
|
|
|
|
/*
|
|
* 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) {
|
|
Name default_makefile;
|
|
|
|
default_makefile = GETNAME("default.mk", FIND_LENGTH);
|
|
default_makefile->stat.is_file = true;
|
|
|
|
(void) read_makefile(default_makefile,
|
|
true,
|
|
false,
|
|
false);
|
|
}
|
|
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;
|
|
(void) SETVAR(virtual_root,
|
|
GETNAME("/", FIND_LENGTH),
|
|
false);
|
|
}
|
|
|
|
/*
|
|
* Read state file
|
|
*/
|
|
if (!report_dependencies_only) {
|
|
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;
|
|
}
|
|
default_target_to_build = NULL;
|
|
|
|
/*
|
|
* Set MFLAGS and MAKEFLAGS
|
|
*/
|
|
INIT_STRING_FROM_STACK(makeflags_string, buffer);
|
|
append_char((int) hyphen_char, &makeflags_string);
|
|
|
|
switch (read_trace_level) {
|
|
case 2:
|
|
append_char('D', &makeflags_string);
|
|
case 1:
|
|
append_char('D', &makeflags_string);
|
|
}
|
|
switch (debug_level) {
|
|
case 2:
|
|
append_char('d', &makeflags_string);
|
|
case 1:
|
|
append_char('d', &makeflags_string);
|
|
}
|
|
if (env_wins) {
|
|
append_char('e', &makeflags_string);
|
|
}
|
|
if (ignore_errors) {
|
|
append_char('i', &makeflags_string);
|
|
}
|
|
if (continue_after_error) {
|
|
append_char('k', &makeflags_string);
|
|
}
|
|
if (do_not_exec_rule) {
|
|
append_char('n', &makeflags_string);
|
|
}
|
|
if (report_dependencies_only) {
|
|
append_char('P', &makeflags_string);
|
|
}
|
|
if (trace_status) {
|
|
append_char('p', &makeflags_string);
|
|
}
|
|
if (quest) {
|
|
append_char('q', &makeflags_string);
|
|
}
|
|
#ifdef PARALLEL
|
|
if (no_parallel) {
|
|
append_char('P', &makeflags_string);
|
|
}
|
|
#endif
|
|
if (silent) {
|
|
append_char('s', &makeflags_string);
|
|
}
|
|
if (touch) {
|
|
append_char('t', &makeflags_string);
|
|
}
|
|
if (filter_stderr) {
|
|
append_char('X', &makeflags_string);
|
|
}
|
|
|
|
/*
|
|
* Make sure MAKEFLAGS is exported
|
|
*/
|
|
maybe_append_prop(makeflags, macro_prop)->
|
|
body.macro.exported = true;
|
|
if (makeflags_string.buffer.start[1] != (int) nul_char) {
|
|
(void) SETVAR(GETNAME("MFLAGS", FIND_LENGTH),
|
|
GETNAME(makeflags_string.buffer.start,
|
|
FIND_LENGTH),
|
|
false);
|
|
}
|
|
macro = maybe_append_prop(makeflags, macro_prop);
|
|
temp = macro->body.macro.read_only;
|
|
macro->body.macro.read_only = false;
|
|
(void) SETVAR(makeflags,
|
|
GETNAME(makeflags_string.buffer.start + 1, FIND_LENGTH),
|
|
false);
|
|
macro->body.macro.read_only = temp;
|
|
if (makeflags_string.free_after_use) {
|
|
retmem(makeflags_string.buffer.start);
|
|
}
|
|
makeflags_string.buffer.start = NULL;
|
|
|
|
/*
|
|
* Read command line "=" type args and make them readonly.
|
|
*/
|
|
makefile_type = reading_nothing;
|
|
for (i = 1; i < argc; ++i) {
|
|
if ((argv[i] != NULL) &&
|
|
(argv[i][0] != (int) hyphen_char) &&
|
|
((cp = strchr(argv[i], (int) equal_char)) != NULL) &&
|
|
((argv[i-1] == NULL) ||
|
|
(argv[i-1][0] != (int) hyphen_char))) {
|
|
while (isspace(*(cp-1))) {
|
|
cp--;
|
|
}
|
|
name = GETNAME(argv[i], cp-argv[i]);
|
|
maybe_append_prop(name, macro_prop)->
|
|
body.macro.exported = true;
|
|
while (*cp != (int) equal_char) {
|
|
cp++;
|
|
}
|
|
cp++;
|
|
while (isspace(*cp) && (*cp != (int) nul_char)) {
|
|
cp++;
|
|
}
|
|
if (*cp == (int) nul_char) {
|
|
SETVAR(name, (Name) NULL, false)->
|
|
body.macro.read_only = true;
|
|
} else {
|
|
SETVAR(name, GETNAME(cp, FIND_LENGTH), false)->
|
|
body.macro.read_only = true;
|
|
}
|
|
argv[i] = NULL;
|
|
}
|
|
}
|
|
|
|
/*
|
|
* Read command line "-f" arguments and ignore "-F" and "-M" arguments.
|
|
*/
|
|
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("No filename argument after -f flag");
|
|
}
|
|
(void) read_makefile(GETNAME(argv[++i], FIND_LENGTH),
|
|
true,
|
|
true,
|
|
true);
|
|
argv[i] = NULL; /* Remove filename */
|
|
makefile_read = true;
|
|
} else if (argv[i] &&
|
|
(argv[i][0] == (int) hyphen_char) &&
|
|
(argv[i][1] == 'F') &&
|
|
(argv[i][2] == (int) nul_char)) {
|
|
argv[i++] = NULL;
|
|
argv[i] = NULL;
|
|
} else if (argv[i] &&
|
|
(argv[i][0] == (int) hyphen_char) &&
|
|
(argv[i][1] == 'M') &&
|
|
(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,
|
|
(char *) NULL,
|
|
(Property) NULL,
|
|
(char *) NULL);
|
|
if (makefile_name->stat.is_file) {
|
|
if (Makefile->stat.is_file) {
|
|
warning("Both `makefile' and `Makefile' exists");
|
|
}
|
|
makefile_read = read_makefile(makefile_name,
|
|
false,
|
|
false,
|
|
true);
|
|
}
|
|
if (!makefile_read &&
|
|
Makefile->stat.is_file) {
|
|
makefile_read = read_makefile(Makefile,
|
|
false,
|
|
false,
|
|
true);
|
|
}
|
|
}
|
|
trace_reader = false;
|
|
do_not_exec_rule = save_do_not_exec_rule;
|
|
|
|
/*
|
|
* 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_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(read_only)
|
|
Boolean read_only;
|
|
{
|
|
register char **environment;
|
|
register char *value;
|
|
register char *name;
|
|
register Name macro;
|
|
Property val;
|
|
|
|
reading_environment = true;
|
|
environment = environ;
|
|
for (; *environment; environment++) {
|
|
name = *environment;
|
|
value = strchr(name, (int) equal_char);
|
|
if (IS_EQUALN(name, "SHELL=", 6)) {
|
|
continue;
|
|
}
|
|
if (IS_EQUALN(name, "MAKEFLAGS=", 6)) {
|
|
report_pwd = true;
|
|
}
|
|
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(macro, (Name) NULL, false);
|
|
} else {
|
|
val = SETVAR(macro,
|
|
GETNAME(value + 1, FIND_LENGTH),
|
|
false);
|
|
}
|
|
val->body.macro.read_only = read_only;
|
|
}
|
|
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(makefile, complain, must_exist, report_file)
|
|
register Name makefile;
|
|
Boolean complain;
|
|
Boolean must_exist;
|
|
Boolean report_file;
|
|
{
|
|
makefile_type = reading_makefile;
|
|
recursion_level = 0;
|
|
return read_simple_file(makefile,
|
|
true,
|
|
true,
|
|
complain,
|
|
must_exist,
|
|
report_file,
|
|
false);
|
|
}
|
|
|
|
/*
|
|
* 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(argc, argv, parallel_flag)
|
|
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
|
|
*/
|
|
#ifdef PARALLEL
|
|
if (!report_dependencies_only && 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;
|
|
}
|
|
default_target_to_build = GETNAME(cp,
|
|
FIND_LENGTH);
|
|
result = doname_check(default_target_to_build,
|
|
true,
|
|
false,
|
|
false);
|
|
if (!commands_done &&
|
|
(result == build_ok) &&
|
|
!quest &&
|
|
(exists(default_target_to_build) >
|
|
(int) file_doesnt_exist)) {
|
|
(void) printf("`%s' is up to date.\n",
|
|
default_target_to_build->
|
|
string);
|
|
}
|
|
}
|
|
}
|
|
/* Now wait for all of the targets to finish running */
|
|
finish_running();
|
|
}
|
|
#endif PARALLEL
|
|
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;
|
|
}
|
|
default_target_to_build = GETNAME(cp, FIND_LENGTH);
|
|
commands_done = false;
|
|
if (parallel) {
|
|
result = default_target_to_build->state;
|
|
} else {
|
|
result = doname_check(default_target_to_build,
|
|
true,
|
|
false,
|
|
false);
|
|
}
|
|
if (result != build_failed) {
|
|
report_recursion(default_target_to_build);
|
|
}
|
|
if (build_failed_seen) {
|
|
warning("Target `%s' not remade because of errors",
|
|
default_target_to_build->string);
|
|
}
|
|
build_failed_seen = false;
|
|
if (report_dependencies_only) {
|
|
print_dependencies(default_target_to_build,
|
|
get_prop(default_target_to_build->prop,
|
|
line_prop));
|
|
}
|
|
default_target_to_build->stat.time =
|
|
(int) 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_only &&
|
|
(exists(default_target_to_build) >
|
|
(int) file_doesnt_exist)) {
|
|
(void) printf("`%s' is up to date.\n",
|
|
default_target_to_build->string);
|
|
}
|
|
}
|
|
}
|
|
|
|
/*
|
|
* 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("No arguments to build");
|
|
}
|
|
commands_done = false;
|
|
#ifdef PARALLEL
|
|
result = doname_parallel(default_target_to_build, true, false);
|
|
#else
|
|
result = doname_check(default_target_to_build, true,
|
|
false, false);
|
|
#endif PARALLEL
|
|
report_recursion(default_target_to_build);
|
|
if (build_failed_seen) {
|
|
warning("Target `%s' not remade because of errors",
|
|
default_target_to_build->string);
|
|
}
|
|
build_failed_seen = false;
|
|
if (report_dependencies_only) {
|
|
print_dependencies(default_target_to_build,
|
|
get_prop(default_target_to_build->
|
|
prop,
|
|
line_prop));
|
|
}
|
|
default_target_to_build->stat.time = (int) 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_only &&
|
|
(exists(default_target_to_build) >
|
|
(int) file_doesnt_exist)) {
|
|
(void) printf("`%s' is up to date.\n",
|
|
default_target_to_build->string);
|
|
}
|
|
}
|
|
}
|
|
|
|
/*
|
|
* print_dependencies(target, line)
|
|
*
|
|
* Print all the dependencies of a target. First print all the Makefiles.
|
|
* Then print all the dependencies. Finally, print all the .INIT
|
|
* dependencies.
|
|
*
|
|
* Parameters:
|
|
* target The target we print dependencies for
|
|
* line We get the dependency list from here
|
|
*
|
|
* Global variables used:
|
|
* done The Name ".DONE"
|
|
* init The Name ".INIT"
|
|
* makefiles_used List of all makefiles read
|
|
*/
|
|
static void
|
|
print_dependencies(target, line)
|
|
register Name target;
|
|
register Property line;
|
|
{
|
|
register Dependency dependencies;
|
|
|
|
for (dependencies = makefiles_used; dependencies != NULL;
|
|
dependencies = dependencies->next) {
|
|
(void) printf("%s ", dependencies->name->string);
|
|
}
|
|
(void) printf("\n");
|
|
print_deps(target, line, true);
|
|
print_more_deps(target, init);
|
|
print_more_deps(target, done);
|
|
}
|
|
|
|
/*
|
|
* print_more_deps(target, name)
|
|
*
|
|
* Print some special dependencies.
|
|
* These are the dependencies for the .INIT and .DONE targets.
|
|
*
|
|
* Parameters:
|
|
* target Target built during make run
|
|
* name Special target to print dependencies for
|
|
*
|
|
* Global variables used:
|
|
*/
|
|
static void
|
|
print_more_deps(target, name)
|
|
Name target;
|
|
Name name;
|
|
{
|
|
Property line;
|
|
register Dependency dependencies;
|
|
|
|
line = get_prop(name->prop, line_prop);
|
|
if (line != NULL && line->body.line.dependencies != NULL) {
|
|
(void) printf("%s:\t", target->string);
|
|
for (dependencies = line->body.line.dependencies;
|
|
dependencies != NULL;
|
|
dependencies = dependencies->next) {
|
|
(void) printf("%s ", dependencies->name->string);
|
|
}
|
|
(void) printf("\n");
|
|
for (dependencies = line->body.line.dependencies;
|
|
dependencies != NULL;
|
|
dependencies = dependencies->next) {
|
|
print_deps(dependencies->name,
|
|
get_prop(dependencies->name->prop,
|
|
line_prop),
|
|
true);
|
|
}
|
|
}
|
|
}
|
|
|
|
/*
|
|
* print_deps(target, line, go_recursive)
|
|
*
|
|
* Print a regular dependency list.
|
|
*
|
|
* Parameters:
|
|
* target target to print dependencies for
|
|
* line We get the dependency list from here
|
|
* go_recursive Should we show all dependencies recursively?
|
|
*
|
|
* Global variables used:
|
|
* recursive_name The Name ".RECURSIVE", printed
|
|
*/
|
|
static void
|
|
print_deps(target, line, go_recursive)
|
|
register Name target;
|
|
register Property line;
|
|
register Boolean go_recursive;
|
|
{
|
|
register Dependency dependencies;
|
|
register Property recursive;
|
|
|
|
if (target->dependency_printed) {
|
|
return;
|
|
}
|
|
target->dependency_printed = true;
|
|
if (target->has_recursive_dependency) {
|
|
for (recursive = get_prop(target->prop, recursive_prop);
|
|
recursive != NULL;
|
|
recursive = get_prop(recursive->next, recursive_prop)) {
|
|
(void) printf("%s:\t%s %s %s",
|
|
target->string,
|
|
recursive_name->string,
|
|
recursive->body.
|
|
recursive.directory->string,
|
|
recursive->body.
|
|
recursive.target->string);
|
|
for (dependencies =
|
|
recursive->body.recursive.makefiles;
|
|
dependencies != NULL;
|
|
dependencies = dependencies->next) {
|
|
(void) printf(" %s",
|
|
dependencies->name->string);
|
|
}
|
|
(void) printf("\n");
|
|
}
|
|
}
|
|
/* only print entries that are actually derived and are not leaf
|
|
* files and are not the result of sccs get.
|
|
*/
|
|
if (should_print_dep(line)) {
|
|
(void) printf("%s:\t", target->string);
|
|
for (dependencies = line->body.line.dependencies;
|
|
dependencies != NULL;
|
|
dependencies = dependencies->next) {
|
|
(void) printf("%s ", dependencies->name->string);
|
|
}
|
|
(void) printf("\n");
|
|
if (go_recursive) {
|
|
for (dependencies = line->body.line.dependencies;
|
|
dependencies != NULL;
|
|
dependencies = dependencies->next) {
|
|
print_deps(dependencies->name,
|
|
get_prop(dependencies->name->prop,
|
|
line_prop),
|
|
go_recursive);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
/*
|
|
* should_print_dep(line)
|
|
*
|
|
* Test if we should print the dependencies of this target.
|
|
* The line must exist and either have children dependencies
|
|
* or have a command that is not an SCCS command.
|
|
*
|
|
* Return value:
|
|
* true if the dependencies should be printed
|
|
*
|
|
* Parameters:
|
|
* line We get the dependency list from here
|
|
*
|
|
* Global variables used:
|
|
*/
|
|
static Boolean
|
|
should_print_dep(line)
|
|
Property line;
|
|
{
|
|
if (line == NULL) {
|
|
return false;
|
|
}
|
|
if (line->body.line.dependencies != NULL) {
|
|
return true;
|
|
}
|
|
if (!line->body.line.sccs_command &&
|
|
(line->body.line.command_template != NULL)) {
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
/*
|
|
* 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(target)
|
|
register Name target;
|
|
{
|
|
register Dependency dp;
|
|
register FILE *report_file = get_report_file();
|
|
|
|
if ((report_file == NULL) || (report_file == (FILE*)-1)) {
|
|
return;
|
|
}
|
|
(void) fprintf(report_file,
|
|
"%s: %s ",
|
|
get_target_being_reported_for(),
|
|
recursive_name->string);
|
|
report_dependency(get_current_path());
|
|
report_dependency(target->string);
|
|
for (dp = makefiles_used; dp != NULL; dp = dp->next) {
|
|
report_dependency(dp->name->string);
|
|
}
|
|
(void) fprintf(report_file, "\n");
|
|
}
|
|
|