Files
Arquivotheca.SunOS-4.1.4/lang/compile/compile.c
seta75D ff309bfe1c Init
2021-10-11 18:37:13 -03:00

2731 lines
62 KiB
C

#ifndef lint
static char sccsid[] = "@(#)compile.c 1.122 89/04/14 SMI";
#endif
/*
* Copyright (c) 1987 by Sun Microsystems, Inc.
*/
/*
* [ The comments which used to be here are probably 'way out of date;
* see the /lib/compile Internal Architecture document instead ]
*/
#include "driver.h"
#include <signal.h>
#include <sys/types.h>
#include <sys/stat.h>
#ifdef BROWSER
#include "../browser/cblib/src/cb_init.h"
#endif
#if RELEASE < 40
# ifdef sparc
# include <alloca.h>
# endif
#else /* RELEASE >= 40 */
# include <alloca.h>
#endif /* RELEASE < 40 */
#ifndef BROWSER
+++ -DBROWSER is to be left ON! +++
#endif
static Bool target_arch_set_from_processor_type = FALSE;
static OptionP processor_type_option; /* valid when above flag is TRUE. */
#ifdef PASCAL_105
Const_intP original_sw_rel_passes;
#endif /*PASCAL_105*/
#ifdef NSE
static char *ENV_nse_variant = NULL;
static char *ENV_target_arch = NULL;
static char *ENV_target_release = NULL;
static char TARGET_ARCH_varname[] = "TARGET_ARCH";
static char TARGET_RELEASE_varname[] = "TARGET_RELEASE";
# define IN_AN_NSE_VARIANT(ENV_nse_variant) (ENV_nse_variant != ((char*)NULL))
# ifdef DEBUG
static Bool consulted_NSE = FALSE;
# endif
#endif /*NSE*/
/*
* Allocate memory with error checking
*/
char *
get_memory(size)
int size;
{
register char *result= malloc((unsigned)size);
if (result == NULL)
fatal("Out of memory");
return result;
}
/*
* A set of simple functions that are used to determine if
* a particular OS, driver release and DRIVER are active
* i.e. if f77 and 4.0 and 1.2
*/
int
check_release_version_driver(release,version,driver_value)
int release;
char *version;
int driver_value;
{
return
( (target_sw_release[R_PASSES].value->value == release)
&&
( ! strcmp(base_driver_release,version))
&&
(driver.value->value == driver_value) );
}
/*
* Allocate right amount of memory and copy string to it
*/
char *
make_string(string)
register char *string;
{
return strcpy(get_memory(strlen(string)+1), string);
}
/*
* append_list_with_suffix
* Append one string to the end of the list
*/
void
append_list_with_suffix(list_head, value, suffix)
register ListP *list_head;
char *value;
SuffixP suffix;
{
register ListP new_list_cell= (ListP)get_memory(sizeof(List));
register ListP list_tail;
new_list_cell->value= value;
new_list_cell->next= (ListP)NULL;
new_list_cell->suffix= suffix;
if (*list_head == NULL)
*list_head= new_list_cell;
else
{
for ( list_tail= *list_head;
list_tail->next != NULL;
list_tail= list_tail->next
)
;
list_tail->next= new_list_cell;
}
}
/*
* get_file_suffix
* Extract the suffix from a string by locating the last '.'
*/
char *
get_file_suffix(name)
char *name;
{
register char *dot= rindex(name, '.');
if (dot == NULL)
return "";
return make_string(dot+1);
} /* get_file_suffix */
/*
* print_help_prefix
* Print the prefix for the "compile -help" command
*/
static void
print_help_prefix(drivers)
register int drivers;
{
register int help_prefix_width= 0;
if ((drivers & DRIVER_C) != 0)
{
(void)printf("C");
help_prefix_width++;
}
if ((drivers & DRIVER_F) != 0)
{
(void)printf("F");
help_prefix_width++;
}
if ((drivers & DRIVER_L) != 0)
{
(void)printf("L");
help_prefix_width++;
}
if ((drivers & DRIVER_M) != 0)
{
(void)printf("M");
help_prefix_width++;
}
if ((drivers & DRIVER_P) != 0)
{
(void)printf("P");
help_prefix_width++;
}
if ((drivers & HIDE_OPTION) != 0)
{
(void)printf("[H]");
help_prefix_width+= 3;
}
(void)printf("%*s", MAX_HELP_PREFIX_WIDTH - help_prefix_width, "");
}
/*
* print_help
*/
static void
print_help()
{
register OptionP op;
register int indent= HELP_STRING_INDENT_DEPTH;
register int head;
register SuffixP sp;
register char *rest;
register ProgramP pp;
register int mask;
for (op= options; op && (op->type != end_of_list); op++)
{
if (driver.value == &dummy)
{
print_help_prefix(op->drivers);
}
else
{
if (((op->drivers & driver.value->value) == 0) ||
((op->drivers & HIDE_OPTION) != 0))
continue;
}
switch (op->type)
{
case help_option:
(void)printf("%s:%*sPrints this message\n",
op->name, indent-strlen(op->name), "");
break;
case infile_option:
(void)printf("%sX:%*s%s\n",
op->name, indent-1-strlen(op->name),
"", op->help);
break;
case lint1_option:
case lint_i_option:
case lint_n_option:
(void)printf("%s:%*s%s\n", op->name,
indent-strlen(op->name), "", op->help);
break;
case make_lint_lib_option:
(void)printf("%s:%*sMake lint library\n",
op->name, indent-strlen(op->name), "");
break;
case module_option:
(void)printf("%s X:%*sForce module to load from specified file\n",
op->name, indent-2-strlen(op->name), "");
break;
case module_list_option:
(void)printf("%sX:%*sAdd directory to path used when looking for modules\n",
op->name, indent-1-strlen(op->name), "");
break;
case optimize_option:
(void)printf("%s:%*sGenerate optimized code\n",
op->name, indent-strlen(op->name), "");
break;
case outfile_option:
(void)printf("%s file:%*sSet name of output file\n",
op->name, indent-5-strlen(op->name), "");
break;
case pass_on_lint_option:
(void)printf("%s:%*s%s\n", op->name,
indent-strlen(op->name), "", op->help);
break;
case pass_on_select_option:
(void)printf("%*s The -Qoption group of options\n",
indent, "");
for ( pp= (ProgramP)&program;
pp != &program.sentinel_program_field;
pp++ )
{
if (pp->name == NULL)
{
continue;
}
mask= (op->drivers&pp->drivers)|
((op->drivers|pp->drivers)&HIDE_OPTION);
if (driver.value == &dummy)
{
print_help_prefix(mask);
}
else
{
if (((mask & driver.value->value) == 0)
|| ((mask & HIDE_OPTION) != 0))
continue;
}
(void)printf("%s %s X:%*sPass option X on to program %s\n",
op->name, pp->name,
indent-3-strlen(op->name)
-strlen(pp->name),
"",pp->name);
}
break;
case pass_on_1_option:
head= 1;
rest= "";
goto pass_on;
case pass_on_1t12_1t_option_pc:
case pass_on_1t12_1t_option:
case pass_on_1t_option:
head= 1;
rest= "X";
goto pass_on;
case pass_on_12_option:
head= 1;
rest= " X";
goto pass_on;
case pass_on_1to_option:
head= 0;
rest= "X";
goto pass_on;
pass_on:
(void)printf("%s%s:%*s",
op->name, rest,
indent-strlen(op->name)-strlen(rest), "");
if (op->help)
{
(void)printf("%s\n", op->help);
}
else
{
if (!head && (rest[0] == ' '))
{
rest++;
}
(void)printf("Pass option '%s%s' on to program %s\n",
head ? op->name : "",
rest, op->program->name);
}
break;
case produce_option:
(void)printf("%*s The -Qproduce group of options\n",
indent, "");
for ( sp= (SuffixP)&suffix;
sp != &suffix.sentinel_suffix_field;
sp++)
{
if (sp->suffix[0] == '\0')
{
continue;
}
mask= (op->drivers&sp->out_drivers) |
((op->drivers|sp->out_drivers)&HIDE_OPTION);
if (driver.value == &dummy)
{
print_help_prefix(mask);
}
else
{
if (((mask & driver.value->value) == 0)
|| ((mask & HIDE_OPTION) != 0))
{
continue;
}
}
(void)printf("%s .%s:%*sProduce type .%s file (%s)\n",
op->name, sp->suffix,
indent-2-strlen(op->name)
-strlen(sp->suffix),
"", sp->suffix, sp->help);
}
break;
case path_option:
(void)printf("%s X:%*sLook for compiler passes in directory X first\n",
op->name, indent-2-strlen(op->name),"");
break;
case run_m2l_option:
(void)printf("%s X:%*sRun the Modula-2 linker on the specified root module\n",
op->name, indent-2-strlen(op->name),"");
break;
case load_m2l_option:
(void)printf("%s X:%*sLoad the specified Modula-2 module\n",
op->name, indent-2-strlen(op->name),"");
break;
case set_int_arg_option:
(void)printf("%s:%*s", op->name,
indent-strlen(op->name), "");
if (op->help)
{
(void)printf("%s\n", op->help);
}
else
{
(void)printf("Sets %s\n",
op->variable->help, op->constant->name);
}
break;
case set_named_int_arg_option:
case set_target_arch_option1:
case set_target_proc_option1:
(void)printf("%s:%*s", op->name,
indent-strlen(op->name), "");
if (op->help)
{
(void)printf("%s\n", op->help);
}
else
{
(void)printf("Sets value of %s to %s\n",
op->variable->help, op->constant->name);
}
break;
case set_target_arch_option2:
(void)printf("%s arch-type:%*sSet target architecture to arch-type\n",
op->name, indent-11-strlen(op->name), "");
break;
case set_sw_release_option:
#ifdef TELL_ABOUT_SW_RELEASE_OPTION
(void)printf("%s release:%*sSet target s/w release #\n",
op->name, indent-9-strlen(op->name),
"");
#endif /*TELL_ABOUT_SW_RELEASE_OPTION*/
break;
case temp_dir_option:
(void)printf("%sdir:%*sSet directory for temporary files to <dir>\n",
op->name, indent-3-strlen(op->name), "");
break;
default:
fatal("Internal error: help optype %d?", (int)op->type);
}
}
if (driver.value != &xlint)
{
(void)printf("All other options are passed down to ld.\n");
}
for (sp= (SuffixP)&suffix; sp != &suffix.sentinel_suffix_field; sp++)
{
if (sp->suffix[0] == '\0')
{
continue;
}
if (driver.value == &dummy)
{
print_help_prefix(sp->in_drivers);
}
else
{
if (((sp->in_drivers & driver.value->value) == 0) ||
((sp->in_drivers & HIDE_OPTION) != 0))
{
continue;
}
}
(void)printf("Suffix '%s':%*s%s\n",
sp->suffix, indent-9-strlen(sp->suffix), "", sp->help);
}
(void)printf("'file.X=.Y' will read the file 'file.X' but treat it as if it had suffix 'Y'\n");
if (driver.value != &xlint)
{
(void)printf("%s:%*sEnvironment variable with floating point option\n",
FLOAT_OPTION, indent-strlen(FLOAT_OPTION), "");
}
} /* print_help */
/*
* lint_lib
* Transform "-lx" notation to corresponding lint library
*/
char *
lint_lib(lib)
char *lib;
{
char path[MAXPATHLEN];
char *lint_path;
switch (target_sw_release[R_PATHS].value->value)
{
case SW_REL_DFLT:
/* sw release is not yet defined, lets postpone
* setting the lint_path until after the sw release
* is determined. This will only happen for -lXXX
* options on the command line. We set the sw release
* after parsing the command line
*/
lint_path = DUMMY_FLAG;
break;
case SW_REL_3X:
case SW_REL_40:
if (is_on(sys5_flag))
{
/* system 5 and release 4.0 or 3.x */
lint_path = "/usr/5lib";
}
else
{
/* bsd and release 4.0 or 3.x */
lint_path = "/usr/lib";
}
break;
case SW_REL_41:
if (is_on(sys5_flag))
{
/* system 5 and release 4.1 */
lint_path = "/usr/5lib";
}
else
{
/* bsd and release 4.1 */
lint_path = "/usr/lib";
}
break;
default:
fatal("Invalid software release specified for lint library");
}
(void)sprintf(path, "%s/lint/llib%s.ln", lint_path, lib);
return scan_Qpath_and_vroot(path, FALSE);
} /* lint_lib */
/*
* handle_infile
* If argument cannot be recognized as an option handle_infile()
* gets it.
*/
static void
handle_infile(file, extra_drivers)
register char *file;
int extra_drivers;
{
register char *suffix_string;
register char *p;
register SuffixP suffixp;
if (file[0] == '-')
{
/* If this is an "-l" style infile we assign it a suffix. */
/* For lint it is translated to a proper filename. */
if (driver.value == &xlint)
{
file= lint_lib(file);
suffix_string= suffix.ln.suffix;
}
else
suffix_string= suffix.a.suffix;
}
else
{
/* else we get the suffix from the filename itself */
suffix_string= get_file_suffix(file);
/* Remove "foo.x=.o" type options */
if ((p= index(file, '=')) != NULL) *p= '\0';
}
/* Inline files are filtered out.
* The inline program is activated with them as args.
*/
if (STR_EQUAL(suffix_string, suffix.il.suffix))
{
set_flag(do_inline);
append_list(&program.inline.permanent_options, "-i");
append_list(&program.inline.permanent_options, file);
append_list(&report, file);
return;
}
/* Check if the suffix of the file is known to the driver */
for (suffixp= (SuffixP)&suffix; suffixp->suffix != NULL; suffixp++)
{
if ( (STR_EQUAL(suffixp->suffix, suffix_string)) &&
( ( (suffixp->in_drivers|extra_drivers) &
driver.value->value) != 0 )
)
{
/* If we know about the suffix we add the file to the
* infile list.
*/
append_list_with_suffix(&infile, file, suffixp);
infile_count++;
if ((suffixp->in_drivers&SOURCE_SUFFIX) == SOURCE_SUFFIX)
{
source_infile_count++;
}
return;
}
}
/* We pass unknown files to one of: cpp, lint1, or ld. */
/* If this is the "cc" driver, and we've already seen the -P or -E
* flag, then pass all filenames with unknown suffixes to CPP.
* The user is on his/her own if he/she requests it.
* E.g.: cc -E foo.y
*/
if ( (driver.value == &cc) &&
( (product.value == &preprocessed) ||
(product.value == &preprocessed2) )
)
{
/* Treat it as if it had a ".c" suffix to start with,
* and wish the user "Good Luck".
*/
append_list_with_suffix(&infile, file, &suffix.c);
infile_count++;
source_infile_count++;
}
else
{
if (driver.value == &xlint)
{
warning("File with unknown suffix (%s) passed to lint1",
file);
append_list_with_suffix(&infile, file, &suffix.c);
infile_count++;
source_infile_count++;
}
else
{
warning("File with unknown suffix (%s) passed to ld",
file);
append_list_with_suffix(&infile, file, &suffix.o);
infile_count++;
}
}
} /* handle_infile */
static void
check_for_redefinition(named_intp, constp, arg1, arg2, arg3)
register Named_intP named_intp;
register Const_intP constp;
char *arg1; /* first argument from command line */
char *arg2; /* second argument from command line */
char *arg3; /* third argument from command line */
{
/* If the given Named_int is about to be redefined, issue a warning. */
if ( named_intp->touched &&
!named_intp->redefine_ok &&
(named_intp->value != constp) )
{
warning("\"%s%s%s\" redefines %s from \"%s\" to \"%s\"",
arg1,
(arg2 == (char *)NULL) ?"" : arg2,
(arg3 == (char *)NULL) ?"" : arg3,
named_intp->help,
named_intp->value->name,
constp->name);
}
}
static void
set_named_int_option(options, argument)
register Option *options;
char *argument;
{
/* Handle options that set state which has multiple values.
* Warn about redefinitions.
*/
check_for_redefinition(options->variable, options->constant,
argument, (char *)NULL, (char *)NULL );
set_named_int(*(options->variable), options->constant);
}
/*
* sw_release_lookup()
* Lookup the software release number given among the known
* Const_int's, and return a pointer to one of them.
*/
Const_intP
sw_release_lookup(string)
register char *string;
{
register int i;
for (i = 0; known_sw_releases[i] != NULL; i++)
{
if ( STR_EQUAL(string, known_sw_releases[i]->name))
{
return known_sw_releases[i];
}
}
fatal("Unknown target software release \"%s\"", string);
/*NOTREACHED*/
}
static void
illegal_optimize_option(opt_level)
char opt_level;
{
fatal("Illegal optimization option \"-O%c\"", opt_level);
}
static ProgramP
lookup_program(program_name)
char *program_name;
{
register ProgramP pp;
for ( pp= (ProgramP)&program;
pp != &program.sentinel_program_field;
pp++)
{
if ((pp->name != NULL) && strcmp(program_name, pp->name) == 0)
{
return pp;
}
}
/* didn't find it. */
return (ProgramP)NULL;
}
static void
set_a_target_sw_release_value(which, release_name, arg1, arg2, arg3)
register int which;
register char *release_name;
char *arg1; /* first argument from command line */
char *arg2; /* second argument from command line */
char *arg3; /* third argument from command line */
{
register Const_intP constp;
constp = sw_release_lookup(release_name);
check_for_redefinition(&target_sw_release[which], constp,
arg1, arg2, arg3);
set_named_int(target_sw_release[which], constp);
if (is_on(debug))
{
fprintf(stderr, "[rel[%d]=\"%s\" (%s%s%s)]\n",
which, target_sw_release[which].value->name,
arg1, arg2, arg3);
}
}
static void
set_all_target_sw_release_values(release_name, arg1, arg2, arg3)
register char *release_name;
char *arg1; /* first argument from command line */
char *arg2; /* second argument from command line */
char *arg3; /* third argument from command line */
{
register int i;
/* Set all "R_elements" components of the target S/W release to
* the given value.
*/
for ( i = 0; i < R_elements; i++)
{
set_a_target_sw_release_value(i, release_name,
arg1, arg2, arg3);
}
}
static void
set_all_defaulted_target_sw_release_values(release_name, arg1, arg2, arg3)
register char *release_name;
char *arg1; /* first argument from command line */
char *arg2; /* second argument from command line */
char *arg3; /* third argument from command line */
{
register int i;
/* Set all "R_elements" components of the target S/W release to
* the given value.
*/
for ( i = 0; i < R_elements; i++)
{
if (target_sw_release[i].value->value == SW_REL_DFLT)
{
set_a_target_sw_release_value(i, release_name,
arg1, arg2, arg3);
}
}
}
/*
* skip_leading_minus()
*/
static char *
skip_leading_minus(arch_name)
char *arch_name;
{
/* This is mostly used to skip the leading '-' from target
* architecture names. A minus, if present, is probably a historical
* artifact, present because "make"'s TARGET_ARCH variable carries
* around a '-' prefix.
*/
if (*arch_name == '-') return arch_name + 1;
else return arch_name;
}
/*
* lookup_architecuture()
*/
static Const_intP
lookup_architecture(arch_name)
char *arch_name;
{
register int i;
register int len;
char buffer[LOCAL_STRING_LENGTH];
for (i = 0; known_architectures[i] != NULL; i++)
{
len = strlen(known_architectures[i]->extra);
if ( STR_EQUAL_N(arch_name, known_architectures[i]->extra, len)
)
{
switch (arch_name[len])
{
case '\0': /* the names were an exact match. */
return known_architectures[i];
default:
fatal("Unknown Sun target architecture \"%s\"",
arch_name);
break;
}
}
}
#ifdef CROSS
/* Didn't find it. Assume it's a foreign architecture type. */
sprintf(buffer, "-target %s", arch_name);
arch_foreign.name = make_string(buffer);
arch_foreign.extra = make_string(arch_name);
return &arch_foreign;
#else /*!CROSS*/
fatal("Cross-compilers required for target architecture \"%s\"",
arch_name);
#endif /*CROSS*/
}
/*
* set_target_architecture()
*/
static void
set_target_architecture(targ_arch_variable, arch_name, from_processor_type)
Named_intP targ_arch_variable;
char *arch_name;
Bool from_processor_type;
{
register Const_intP arch_constp;
register int length;
/* Flag whether we are setting the target architecture type from a real
* architecture type (e.g. sun3), or a processor type (e.g. mc68020).
*/
target_arch_set_from_processor_type = from_processor_type;
arch_constp = lookup_architecture(arch_name);
/* Set the target architecture type. */
set_named_int(*targ_arch_variable, arch_constp);
if (is_on(debug))
{
fprintf(stderr, "[target_arch=\"%s\"]\n",
target_arch.value->extra);
}
}
static void
request_default_opt_level(arg)
char *arg;
{
/* arg[0] is "-".
* arg[1] is "O" or "P".
*/
switch (arg[1])
{
case 'P':
optimizer_level= OPTIM_IROPT_P;
break;
case 'O':
/* Set the optimizer level later, based on the language type
* and the target architecture (which we don't necessarily
* know yet when we see the -O/-P).
*/
use_default_optimizer_level = TRUE;
break;
}
}
/*
* lookup_option
* Scan the options list for one particular option and process it
*/
static int
lookup_option(options, argc, argv, infile_ok, extra_drivers)
register Option *options; /* list of valid options. */
int *argc; /* the count of options given.*/
char *argv[]; /* text of the options given. */
register int infile_ok;
register int extra_drivers;
{
register int args_used= 1;
register int length;
register char *p;
register SuffixP sp;
register ProgramP pp;
if (*argc <= 0)
{
fatal("No more arguments");
}
/* Scan the list of options and try to find the current one */
for ( ; options && (options->type != end_of_list); options++)
{
if ((driver.value != NULL) &&
(driver.value->value != 0) &&
((options->drivers|extra_drivers) & driver.value->value) == 0)
{
continue;
}
if ((strncmp(argv[0], options->name,
length= strlen(options->name)) == 0))
{
/* Some options takes extra argments that may not start with
* a "-".
*/
if (((options->drivers&NO_MINUS_OPTION) != 0) && (*argc > 1)
&& (argv[1][0] == '-'))
{
warning("Extra argument for %s starts with '-'",
options->name);
}
/* Go to the action routine now that the option has been
* identified.
*/
switch (options->type)
{
case help_option:
print_help();
exit(0);
case infile_option:
/* This handles "-l" type options */
/* Special case "pc -l" */
if ((argv[0][0] == '-') && (argv[0][1] == 'l') &&
(argv[0][2] == '\0') && (driver.value == &pc))
{
append_list(&program.pc0.permanent_options,
"-l");
break;
}
handle_infile(argv[0], extra_drivers);
goto exit_fn;
case lint1_option:
append_list(&program.lint1.trailing_options, argv[0]);
break;
case lint_i_option:
if (length == strlen(argv[0]))
{
set_named_int(product, &lint1_file);
}
else args_used= 0;
break;
case lint_n_option:
if (length == strlen(argv[0]))
{
set_flag(ignore_lc);
}
else args_used= 0;
break;
case make_lint_lib_option:
/* This handles "lint -Cfoo" type options */
append_list(&program.lint1.permanent_options, "-L");
p= get_memory(strlen(argv[0])+8);
(void)sprintf(p, "-Cllib-l%s", argv[0]+2);
append_list(&program.lint1.permanent_options, p);
p= get_memory(strlen(argv[0])+8);
(void)sprintf(p, "llib-l%s.ln", argv[0]+2);
outfile= p;
requested_suffix= &suffix.ln;
if (make_lint_lib_fd++ > 0)
{
fatal("Multiple -C options");
}
break;
case module_option:
/* This handles "m2c -m X" type options */
if (*argc <= 1)
{
fatal("-m option with no argument");
}
args_used++;
append_list(&program.m2cfe.permanent_options, argv[0]);
append_list(&program.m2cfe.permanent_options, argv[1]);
append_list(&program.m2l.permanent_options, argv[0]);
append_list(&program.m2l.permanent_options, argv[1]);
break;
case module_list_option:
/* This handles "m2c -MX" type options */
/* If X is empty we clear the list */
if (argv[0][2] == '\0')
{
module_list= NULL;
set_flag(no_default_module_list);
}
else
{
append_list(&module_list, argv[0]);
}
break;
case optimize_option:
/* This handles the "-OX" and "-PX" type options */
/* Pickup the X */
if (argv[0][2] == '\0')
{
/* No optimization level was specified in this
* optimization option (just plain "-O"/"-P").
*/
if (optimizer_level == OPTIM_NONE)
{
/*
* Set <level> to a default value.
*/
request_default_opt_level(argv[0]);
}
else
{
/* -O<level> was previously specified;
* retain the previous value of <level>.
* This allows the user to raise the
* optimization level without changing
* makefiles (e.g. make CC="cc -O2",
* where "${CC} -O foo.c" was already
* in the Makefile).
*/
}
}
else
{
optimizer_level= argv[0][2];
}
/* Validity of the optimization level is checked at
* in main(), after the host & target architectures
* are known to be set.
*/
break;
case outfile_option:
if (*argc <= 1)
{
fatal("-o option but no filename");
}
args_used++;
outfile= argv[1];
break;
case pass_on_lint_option:
if (length == strlen(argv[0]))
{
append_list(&program.lint1.permanent_options,
argv[0]);
append_list(&program.lint2.permanent_options,
argv[0]);
}
else args_used= 0;
break;
case pass_on_select_option:
/* Handle "-Qoption" type options */
if (*argc <= 2)
{
fatal("%s option without arguments", argv[0]);
}
args_used+= 2;
/* Find the program the option is intended for */
if ( (pp = lookup_program(argv[1])) == NULL )
{
fatal("%s option with unknown program %s",
argv[0], argv[1]);
}
else
{
append_list(&pp->trailing_options, argv[2]);
}
break;
case pass_on_1_option:
/* cc -x => prog -x */
if (length != strlen(argv[0]))
{
fatal("Unknown option \"%s\"", argv[0]);
}
/* Fall into */
case pass_on_1t_option:
/* cc -xREST => prog -xREST */
switch ( options->subtype )
{
case PASS_OPT_AS_FLAG:
append_list(
&options->program->permanent_options,
argv[0]);
/* special hack for XL_FLAG
* we need to also add -Q flag
* and run cppas instead of cpp
*/
if (! strcmp(argv[0], XL_FLAG))
{
append_list(
&options->program->permanent_options,"-Q");
set_flag(do_cppas);
}
break;
case PASS_OPT_AS_INFILE:
handle_infile(argv[0], extra_drivers);
break;
default:
fatal("1t subtype %d?", options->subtype);
}
break;
case pass_on_1t12_1t_option:
/* cc -xREST => prog -xREST
* [or] cc -x REST => prog -xREST
* [but] cc -x -REST => [-x is ignored]
*
* Used for Sys-V compatibility, for -U and -D.
*/
p = NULL;
switch ( strlen(argv[0]) )
{
case 2: /* -x REST; make into -xREST, unless the next
* REST begins with "-", which makes it the
* next argument.
*/
if (*argc <= 1)
{
fatal("%s option without arguments",
argv[0]);
}
/* if there are only two arguments
* the command line arguments are
* wrong, could be -D t.c or
* -D xxxxx
*/
if (*argc == 2)
{
fatal("Invalid combination of command line arguments");
}
if (*argv[1] != '-')
{
args_used++;
p = get_memory(2 + strlen(argv[1])
+ 1/*'\0'*/ );
strcpy(p, argv[0]);
strcpy(p+2, argv[1]);
}
break;
default:/* -xREST; use as-is. */
p = argv[0];
break;
}
if (p != NULL)
{
append_list(&options->program->trailing_options, p);
}
break;
case pass_on_1t12_1t_option_pc:
/* cc -configREST => prog -xREST
* [or] cc -config REST => prog -xREST
* [but] cc -config -REST => [-x is ignored]
*
* used to pass option ro pc0 in pascal
*/
p = NULL;
switch (strlen(argv[0]) )
{
case 7:
if (*argc <= 1)
{
fatal("%s option without arguments", argv[0]);
}
if (*argv[1] != '-')
{
args_used++;
p = get_memory(7 + strlen(argv[1]) + 1/*'0'*/ );
strcpy(p, argv[0]);
strcpy(p+7, argv[1]);
}
break;
default: /* -xREST; use as-is. */
p = argv[0];
break;
}
if (p != NULL)
{
append_list(&options->program->trailing_options, p);
}
break;
case pass_on_12_option:
/* cc -x REST => prog -x REST */
if (*argc <= 1)
{
fatal("%s option without arguments", argv[0]);
}
args_used++;
append_list(&options->program->permanent_options,
argv[0]);
append_list(&options->program->permanent_options,
argv[1]);
break;
case pass_on_1to_option:
/* cc -xREST => prog REST */
if (argv[0][length] != '\0')
{
append_list(&options->program->permanent_options,
argv[0]+length);
}
break;
case produce_option:
/* Handle "-Qproduce" type options */
if (*argc <= 1)
{
fatal("%s option without argument", argv[0]);
}
args_used++;
/* Scan the legal suffixes to find the one specified */
for (sp= (SuffixP)&suffix; sp->suffix != NULL; sp++)
{
if (strncmp(argv[1]+1, sp->suffix,
strlen(sp->suffix)) == 0)
{
set_named_int(product, NULL);
requested_suffix= sp;
goto found_suffix;
}
}
fatal("Don't know how to produce %s", argv[1]);
found_suffix:
break;
case path_option:
/* Handle "-Qpath" type options */
if (*argc <= 1)
{
fatal("%s option without argument", argv[0]);
}
args_used++;
add_dir_to_path(argv[1], &program_path, -1);
last_program_path++;
break;
case run_m2l_option:
/* Handle "m2c -e" type options */
if (is_on(root_module_seen))
{
fatal("Multiple %s options", argv[0]);
}
set_flag(root_module_seen);
/* Fall into !!! */
case load_m2l_option:
/* Handle "m2c -E" type options */
if (*argc <= 1)
{
fatal("%s option without argument", argv[0]);
}
if (product.touched &&
!product.redefine_ok &&
(product.value != &executable))
{
warning("%s: %s redefines %s from %s to %s",
program_name,
argv[0],
product.help,
product.value->name,
executable.name);
}
set_named_int(product, &executable);
/* Pass option to "m2l" in sequence with other infiles*/
append_list_with_suffix(&infile, argv[0], &suffix.o);
append_list_with_suffix(&infile, argv[1], &suffix.o);
args_used++;
set_flag(do_m2l);
break;
case set_int_arg_option:
/* Handle options that only set some binary state in
* the driver.
*/
if ( (options->constant) != (Const_intP)NULL )
{
*((char *)(options->variable))= 1;
}
else
{
*((char *)(options->variable))= 0;
}
break;
case set_named_int_arg_option:
/* Handle options that set state that has multiple
* values. Warn about redefinitions.
*/
set_named_int_option(options, argv[0]);
break;
case set_target_arch_option1:
/* Handle 1-arg target-architecture-setting option. */
/* Set the target architecture type. */
set_target_architecture(options->variable, &argv[0][1],
FALSE);
break;
case set_target_arch_option2:
/* Handle 2-arg target-architecture-setting option. */
if (*argc <= 1)
{
fatal("missing architecture after \"-target\"");
}
args_used++;
/* Set the target architecture type. */
/* The reference to skip_leading_minus() below is to
* handle the possible instance of a historical artifact
* (leading '-' on target architecture name). See that
* routine for more comments.
*/
set_target_architecture(options->variable,
skip_leading_minus(argv[1]),
FALSE);
break;
case set_target_proc_option1:
/* Handle target-processor-setting option. */
processor_type_option = options;
/* Set the target architecture type. */
set_target_architecture(options->variable,
options->constant->extra, TRUE);
break;
case set_sw_release_option:
if (*argc <= 1)
{
fatal("missing release# after \"-release\"");
}
args_used++;
if ( options->subtype == R_all )
{
/* Set all of the options. */
set_all_target_sw_release_values(argv[1],
argv[0], " ", argv[1]);
}
else
{
set_a_target_sw_release_value( options->subtype,
argv[1], argv[0], " ", argv[1]);
}
break;
case temp_dir_option:
/* Handle "-temp=" type options */
if (argv[0][length] == '\0')
{
fatal("Bad %s option", argv[0]);
}
temp_dir= make_string(argv[0]+length);
break;
default:
fatal("Internal error");
}
goto exit_fn;
}
}
/* We couldn't find that option. Maybe it is an input file name? */
if (!infile_ok || (argv[0][0] == '-'))
{
/* Unknown option. Pass to ld */
append_list(&program.ld.permanent_options, argv[0]);
if (driver.value == &xlint)
{
fatal("Option %s not recognized", argv[0]);
}
else
{
warning("Option %s passed to ld", argv[0]);
}
}
else
{
/* We assume it is an input file name. */
handle_infile(argv[0], extra_drivers);
}
exit_fn:
*argc -= args_used;
return args_used;
} /* lookup_option */
/*
* lookup_lint_option
* Split bundled options then
* scan the options list for one particular option and process it
*/
static int
lookup_lint_option(options, argc, argv, infile_ok, extra_drivers)
Option *options;
int *argc;
char *argv[];
int infile_ok;
int extra_drivers;
{
int args_used;
char **new_argv;
int new_argc= 0;
char **ap;
char *p;
if ((args_used= lookup_option(options, argc, argv, infile_ok,
extra_drivers)) > 0)
{
return args_used;
}
/* Split option word into a list of single char options */
ap= new_argv= (char **)alloca(sizeof(char *)*((strlen(argv[0])*2)+1));
for (p= argv[0]+1; *p != '\0'; p++)
{
*ap= get_memory(3);
ap[0][0]= '-';
ap[0][1]= *p;
ap[0][2]= '\0';
ap++;
new_argc++;
}
*ap= NULL;
while (new_argc > 0)
{
new_argv+= lookup_option(options, &new_argc, new_argv,
infile_ok, extra_drivers);
}
*argc-= 1;
return 1;
/*
a
b
c
h
i set product
n set ignore_lc
u
v
x
z
*/
}
/*
* lookup_one_flag_option
* Lookup a single option using lookup_option().
*/
static void
lookup_one_flag_option(option_name, prepend_minus)
char *option_name;
Bool prepend_minus;
{
char option[LOCAL_STRING_LENGTH];
char *argv[2];
int argc;
if (prepend_minus)
{
option[0]= '-';
(void)strcpy(&option[1], option_name);
argv[0] = option;
}
else
{
argv[0] = option_name;
}
argv[1] = NULL;
argc = 1;
(void)lookup_option(options, &argc, argv, 0, 0);
}
/*
* default_float_mode
* Figure out what to use as the default float mode
* Use the FLOAT_OPTION environment variable
*/
static Const_intP
default_float_mode()
{
register char *float_option= getenv(FLOAT_OPTION);
if (float_option && (driver.value != &xlint))
{
lookup_one_flag_option(float_option, (float_option[0] != '-'));
if (float_mode.value == NULL)
fatal("%s value not ok:%s", FLOAT_OPTION, float_option);
return float_mode.value;
}
return &fsoft;
} /* default_float_mode */
/*
* check_float_arguments
* Check if the float mode/target_arch combination is legal
*/
static void
check_float_arguments()
{
if (float_mode.value == NULL)
{
float_mode.value = default_float_mode();
}
if ( ( (target_arch.value->value == ARCH_SUN2) &&
(float_mode.value == &ffpa) )
||
( (target_arch.value->value == ARCH_SUN3X) &&
(float_mode.value == &fsky) )
||
( (target_arch.value->value == ARCH_SUN3) &&
(float_mode.value == &fsky) )
||
( (target_arch.value->value == ARCH_SUN386) &&
(float_mode.value != &fsoft) )
||
( (target_arch.value->value == ARCH_SUN4C) &&
(float_mode.value != &fsoft) )
||
( (target_arch.value->value == ARCH_SUN4) &&
(float_mode.value != &fsoft) )
)
{
(void)fprintf(stderr,
"%s: \"%s\" is invalid for the %s target architecture\n",
program_name,
float_mode.value->name,
target_arch.value->extra);
cleanup(0);
exit(1);
}
} /* check_float_arguments */
/*
* cleanup
* Remove temp files before we exit
*/
void
cleanup(abort)
int abort;
{
register ListP cp;
/* We saved our reports till now to avoid conflicts with other
* reporters.
*/
for (cp= report; cp != NULL; cp= cp->next)
{
report_dependency(cp->value);
#ifdef NSE
report_libdep(cp->value, "COMP");
#endif /*NSE*/
}
if (is_on(remove_tmp_files))
{
for (cp= files_to_unlink; cp != NULL; cp= cp->next)
{
if (cp->value != NULL)
{
if ( ( is_on(verbose) || is_on(dryrun) ) &&
is_on(show_rm_commands)
)
{
(void)fprintf(stderr,
"rm %s\n", cp->value);
}
if (abort)
{
(void)truncate(cp->value, 0);
}
/* if dryrun is on DO NOT remove
* any files
*/
if ( is_off(dryrun) )
{
(void)unlink(cp->value);
}
}
}
}
} /* cleanup */
/*
* fatal error reporting routine
*/
/*VARARGS1*/
void
warning(msg, a, b, c, d, e, f, g)
char *msg;
{
(void)fprintf(stderr, "%s: Warning: ", program_name);
(void)fprintf(stderr, msg, a, b, c, d, e, f, g);
(void)fprintf(stderr, "\n");
}
/*
* fatal error reporting routine
*/
/*VARARGS1*/
void
fatal(msg, a, b, c, d, e)
char *msg;
{
(void)fprintf(stderr, "%s: ", program_name);
(void)fprintf(stderr, msg, a, b, c, d, e);
(void)fprintf(stderr, "\n");
cleanup(0);
exit(1);
}
/*
* abort_program
*/
static void
abort_program()
{
cleanup(1);
exit(1);
} /* abort_program */
#if RELEASE == 32
# define SIGNAL_TYPE int
#else /* RELEASE != 32 */
# define SIGNAL_TYPE void
#endif /* RELEASE == 32 */
/*
* set_signal sets a handler for a signal if the signal is not ignored
*/
void
set_signal(sig, handler)
int sig;
SIGNAL_TYPE (*handler)();
{
SIGNAL_TYPE (*old_handler)();
old_handler= signal(sig, handler);
if (old_handler == SIG_IGN)
{
(void)signal(sig, SIG_IGN);
}
}
/*
* Divine the target processor type from the target architecture type.
*/
char *
get_processor_type(archvalue)
Const_intP archvalue;
{
switch (archvalue->value)
{
case ARCH_SUN2: return "mc68010";
case ARCH_SUN3X: return "mc68020"; /* Really! 020, not 030! */
case ARCH_SUN3: return "mc68020";
case ARCH_SUN386: return "i386";
case ARCH_SUN4C: return "sparc";
case ARCH_SUN4: return "sparc";
}
}
/*
* Get the target processor flag for the given target architecture type.
*/
char *
get_processor_flag(archvalue)
Const_intP archvalue;
{
char buffer[LOCAL_STRING_LENGTH];
/* The target processor flag is just "-" plus the processor type. */
buffer[0] = '-';
strcpy(&buffer[1], get_processor_type(archvalue));
return make_string(buffer);
}
enum ShellType { SHELL_SH, SHELL_CSH };
static enum ShellType
guess_shell_type()
{
/* To make an educated guess as to which shell the user is using,
* we examine the SHELL environment variable.
* If it ends in "sh" but not "csh", we'll assume that the user
* is using a Bourne or Bourne-compatible Shell (ksh, etc).
* Otherwise, we'll assume that it's a C-Shell, since it is
* probably still in more common use (by non-AT&T UNIX users,
* anyway).
* This method is NOT foolproof, but does provide a reasonable guess.
*/
register char *shell_name;
register int len;
shell_name = getenv("SHELL");
if ( (shell_name != NULL) &&
( (len = strlen(shell_name)) >= 2 ) &&
( strcmp(&shell_name[len-2], "sh") == 0 ) &&
( (len < 3) ||
(strcmp(&shell_name[len-3], "csh") != 0) )
)
{
return SHELL_SH;
}
else return SHELL_CSH;
}
/*
* Returns TRUE if the path given is to a directory; FALSE otherwise.
*/
static Bool
is_existing_directory(path)
char *path;
{
struct stat statbuf;
return ( (stat(path, &statbuf) == 0) &&
((statbuf.st_mode & S_IFMT) == S_IFDIR));
}
/*
* Figure out what host we are on.
*/
static void
set_host()
{
/* Set the host architecture type.
* On m68k machines, this used to be done with a routine
* that could tell a 68020 from a 68010. This is unnecessary
* since we always ship separate binaries for 68010s and 68020s.
*/
#if defined(sun4c)
host_arch.value= &arch_sun4c;
#elif defined(sun4)
host_arch.value= &arch_sun4;
#elif defined(sun3x)
host_arch.value= &arch_sun3x;
#elif defined(sun3)
host_arch.value= &arch_sun3;
#elif defined(sun386)
host_arch.value= &arch_sun386;
#elif defined(sun2)
host_arch.value= &arch_sun2;
#else
@@@ error -- missing case @@@
#endif
if (is_on(debug))
{
fprintf(stderr, "[host_arch = \"%s\"]\n",
host_arch.value->extra);
}
}
static void
set_target()
{
/* Set the target architecture type.
* If it was specified on the command line, we'll use the one given.
* If not, and we're in an NSE "variant", use the target architecture
* which it specifies. Otherwise, we assume that the target
* architecture is the same as the host architecture (i.e. this is a
* native compilation).
*/
if (target_arch.value == NULL)
{
/* Target architecture was NOT specified explicitly by user,
* or by an NSE environment.
*/
target_arch = host_arch;
set_target_architecture(&target_arch,
host_arch.value->extra, FALSE);
}
else
{
/* Target architecture was specified explicitly on the command
* line or by the containing NSE environment; use the one given.
*/
}
}
static void
set_host_and_target()
{
set_host();
set_target();
}
/*
* Set a couple of the s/w release types, if defaulted.
*/
static void
set_lib_paths_and_option_types(root_path)
char *root_path;
{
Const_intP target_base_OS_release;
target_base_OS_release =
get_target_base_OS_version(root_path, driver.value);
/* "base_driver_release" is a global variable telling what
* driver release we are using.
*/
base_driver_release =
get_base_driver_version(root_path, driver.value);
/* This is here just for the sake of debug info... */
if (is_on(debug))
{
fprintf(stderr,"[driver version = %s (%s)]\n",
base_driver_release, debug_info_filename);
fprintf(stderr, "[rel[%d]=\"%s\" /*vroot */]\n", R_VROOT,
target_sw_release[R_VROOT].value->name);
}
/* This is necessary so we know where to look for the various compiler
* passes and libraries, as different S/W releases put them in
* different places.
*/
if (target_sw_release[R_PATHS].value->value == SW_REL_DFLT)
{
target_sw_release[R_PATHS].value = target_base_OS_release;
}
if (is_on(debug))
{
fprintf(stderr, "[rel[%d]=\"%s\" /*paths */]\n", R_PATHS,
target_sw_release[R_PATHS].value->name);
}
/* And this is needed so we know what options to pass to the various
* compiler passes; as compiler passes in different S/W releases expect
* different options.
*/
if (target_sw_release[R_PASSES].value->value == SW_REL_DFLT)
{
target_sw_release[R_PASSES].value = target_base_OS_release;
}
if (is_on(debug))
{
fprintf(stderr, "[rel[%d]=\"%s\" /*passes*/]\n", R_PASSES,
target_sw_release[R_PASSES].value->name);
}
}
/*
* Setup the environment required for native compilation.
*/
setup_for_native_compile()
{
set_lib_paths_and_option_types("");
}
#ifdef CROSS
/*
* Setup the environment required for cross compilation.
*/
setup_for_cross_compile()
{
char *old_vroot_path;
int len;
char *arch_dir;
char *cross_vroot;
if ( (old_vroot_path = getenv(get_vroot_name())) == NULL )
{
old_vroot_path = "";
}
if ( (arch_dir = getenv("CROSS_COMPILATION_HOME")) == NULL )
{
arch_dir = "/usr/arch";
}
cross_vroot = (char *)alloca( strlen(arch_dir)
+ 1 /*"/"*/
+ strlen(host_arch.value->extra)
+ 1 /*"/"*/
+ strlen(target_arch.value->extra)
+ strlen(target_sw_release[R_VROOT].value->extra)
+ 1 /*'\0'*/
);
(void)sprintf(cross_vroot, "%s/%s/%s%s",
arch_dir,
host_arch.value->extra,
target_arch.value->extra,
target_sw_release[R_VROOT].value->extra);
if ( is_existing_directory(cross_vroot) )
{
/* <whew> -- the cross-tools for the target_arch the user has
* requested are (probably) installed.
* Go ahead and set up VIRTUAL_ROOT for cross-compilation.
*/
register char *new_vroot_path;
new_vroot_path = get_memory( strlen(cross_vroot)
+ 1 /*":"*/
+ strlen(old_vroot_path)
+ 1 /*'\0'*/
);
(void)sprintf(new_vroot_path, "%s:%s",
cross_vroot, old_vroot_path);
/* If we are insisting on pure cross-compilation (i.e., no
* files from our regular root filesystem are to be used),
* then cut off any trailing ":" from the VIRTUAL_ROOT.
*/
if ( is_on(pure_cross) &&
(new_vroot_path[strlen(new_vroot_path)-1]==':')
)
{
new_vroot_path[strlen(new_vroot_path)-1] = '\0';
}
setenv(get_vroot_name(), new_vroot_path);
if (is_on(verbose) || is_on(dryrun))
{
/* The C-Shell and the Bourne Shell (and its variants)
* use different commands to set environment variables.
* In order for us to print the Shell command(s) to set
* the VIRTUAL_ROOT environment variable, we should
* take an educated guess as to which shell the user is
* using.
*
* For SH, we'll use "<var>=<value>; export <var>".
* For CSH, we'll use "setenv <var> <value>".
*/
switch ( guess_shell_type() )
{
case SHELL_CSH:
(void)fprintf(stderr, "setenv %s \"%s\"\n",
get_vroot_name(), new_vroot_path);
break;
case SHELL_SH:
(void)fprintf(stderr, "%s=\"%s\"; export %s\n",
get_vroot_name(),
new_vroot_path,
get_vroot_name());
break;
}
}
set_lib_paths_and_option_types(cross_vroot);
}
else
{
/* Hmmm... the user has requested cross-compilation, yet the
* directory which would have become the head of the
* VIRTUAL_ROOT path doesn't even exist. The user must be
* attempting a cross-compilation without even having any
* cross-tools installed for that target_arch. Stop now,
* or we will end up doing a native compilation and the user
* probably won't know until he/she tries to execute the linked
* object file.
*
* There are a couple of exceptions to this; see below.
*
*/
if ( ( (host_arch.value->value == ARCH_SUN3X) ||
(host_arch.value->value == ARCH_SUN3 ) )
&&
(target_arch.value->value == ARCH_SUN2)
&&
target_arch_set_from_processor_type )
{
/*
* This is the first exception to the above.
*
* The user is on a Sun3 or Sun3x host, and requested
* by using the -mc68010 flag that we generate code for
* an MC68010 target processor. In this case, he/she
* may not have actually wanted full cross-compilation,
* but just to generate 68010 code for the modules being
* compiled. The native compiler can handle this, so
* give him/her the benefit of the doubt.
* We allow this exception as a form of backward
* compatibility.
*/
set_lib_paths_and_option_types("");
/* If the user was trying to get an MC68010 executable,
* we'd better warn him/her, and force a "-c" option,
* i.e. force the "product" to be relocatable ".o"
* files, since there is no way we can generate a real
* mc68010 executable without the cross-compiler's
* mc68010 libraries.
*/
if (product.value->value == GOAL_EXE)
{
warning("\"-mc68010\" implies \"-c\"");
product.value = &object;
}
} else if (driver.value == &xlint)
{
/* The second exception to this is "lint"; it has
* cross-lint'ing builtin via its "-target=<TARGET>"
* option. So, if there is no appropriate virtual root
* directory, try to use the native lint.
*/
set_lib_paths_and_option_types("");
}
else
{
fatal("Cannot cross-compile for \"%s%s\"; directory \"%s\" doesn't exist.",
target_arch.value->extra,
target_sw_release[R_VROOT].value->extra,
cross_vroot);
}
}
if ((driver.value == &xlint) && (target_arch.value != &arch_foreign))
{
char option[LOCAL_STRING_LENGTH];
sprintf(option, "-host=%s", target_arch.value->extra);
append_list(&program.lint1.permanent_options,
make_string(option));
sprintf(option, "-target=%s", target_arch.value->extra);
append_list(&program.lint1.permanent_options,
make_string(option));
}
}
#endif /*CROSS*/
/*
* Check for conflict in the arguments given (besides the float/
* target_arch conflicts).
*/
static void
check_for_option_conflicts()
{
static char *OptionConflict = "%s conflicts with %s. %s turned off.";
/* Check for option conflicts */
check_float_arguments();
if (target_arch.value->value != ARCH_SUN4 && target_arch.value->value != ARCH_SUN4C)
{
/* The misalignment-handling and "trust me that doubles are
* all aligned on doubleword boundaries" flags are currently
* only for the Sun-4 target architecture, and must be ignored
* for all other architectures. Simply turning them off here
* for non-Sun4 targets is more direct than checking the target
* architecture everywhere in the code the flags are checked.
*/
if ( is_on(handle_misalignment) )
{
reset_flag(handle_misalignment);
}
if ( is_on(doubleword_aligned_doubles) )
{
reset_flag(doubleword_aligned_doubles);
}
}
if (debugger.touched)
{
if (is_on(statement_count))
{
warning(OptionConflict, "-a", "-g", "-a");
reset_flag(statement_count);
}
if (optimizer_level > OPTIM_NONE)
{
warning(OptionConflict, "-O", "-g", "-O");
optimizer_level= OPTIM_NONE;
}
if (is_on(as_R))
{
warning(OptionConflict, "-R", "-g", "-R");
reset_flag(as_R);
}
}
if (is_on(statement_count))
{
/* This conflict is no longer a conflice in 4.1 */
/* per request by aoki */
if (optimizer_level > OPTIM_NONE)
{
warning(OptionConflict, "-O", "-a", "-O");
optimizer_level= OPTIM_NONE;
}
if (is_on(as_R))
{
warning(OptionConflict, "-R", "-a", "-R");
reset_flag(as_R);
}
}
if ( target_arch_set_from_processor_type )
{
/* If we have to guess the target architecture type from a
* target processor type which is non-unique, then give 'em
* a warning.
*/
switch (target_arch.value->value)
{
case ARCH_SUN2:
break;
case ARCH_SUN3:
case ARCH_SUN3X:
case ARCH_SUN386:
case ARCH_SUN4:
case ARCH_SUN4C:
if (product.value->value == GOAL_EXE)
{
warning("target architecture option \"%s\" assumed, from \"%s\".",
target_arch.value->name,
processor_type_option->name);
}
break;
default:
/* We had to guess at the target architecture type
* by looking at the target processor type.
* This is worth a warning.
*/
warning("target architecture option \"%s\" assumed, from \"%s\".",
target_arch.value->name,
processor_type_option->name);
break;
}
}
/* Naming "an" output file makes no sense, if this compilation is
* going to result in multiple output files (e.g., a ".o" for each
* input ".c").
*/
if ((outfile != NULL) && (source_infile_count > 1) &&
(product.value != &executable))
{
warning("-o option ignored");
outfile= NULL;
}
}
/*
* Make any changes necessary to our data structures, so that we can
* access the target files properly under Release 3.x file organization.
*/
static void
setup_for_R3X_file_paths()
{
/* Under 3.x, floating-point "crt1" routines are under /lib. */
f68881.extra = "/lib/Mcrt1.o";
ffpa.extra = "/lib/Wcrt1.o";
fsky.extra = "/lib/Scrt1.o";
fsoft.extra = "/lib/Fcrt1.o";
if (is_off(sys5_flag)) /* is bsd version */
{
/* Under 3.x, "crt0" routines are under /lib. */
gprof.extra = "/lib/gcrt0.o";
no_prof.extra = "/lib/crt0.o" ;
prof.extra = "/lib/mcrt0.o";
}
else /* is sys5 version */
{
/* Under 3.x and System 5, "crt0" routines are under /usr/5lib. */
gprof.extra = "/usr/5lib/gcrt0.o";
no_prof.extra = "/usr/5lib/crt0.o" ;
prof.extra = "/usr/5lib/mcrt0.o";
}
}
static void
setup_for_R4X_file_paths()
{
/* Under 4.0, floating-point "crt1" routines are under /usr/lib. */
f68881.extra = "/usr/lib/Mcrt1.o";
ffpa.extra = "/usr/lib/Wcrt1.o";
fsky.extra = "/usr/lib/Scrt1.o";
fsoft.extra = "/usr/lib/Fcrt1.o";
/* Under 4.0, "crt0" routines are under /usr/lib. */
gprof.extra = "/usr/lib/gcrt0.o";
no_prof.extra = "/usr/lib/crt0.o";
prof.extra = "/usr/lib/mcrt0.o";
}
static OptimLevel
default_optimization_level(sw_release_passes, targ_arch_type, driver_type)
int sw_release_passes;
int targ_arch_type;
int driver_type;
{
OptimLevel opt_level;
/* pascal 4.X should default to -O2 */
if ((driver_type == DRIVER_P) && (sw_release_passes >= SW_REL_40))
{
opt_level= OPTIM_IROPT_P;
}
/* modula2 4.X should default to -O3 */
else if ((driver_type == DRIVER_M) && (sw_release_passes >= SW_REL_40))
{
opt_level= OPTIM_IROPT_O;
}
/* fortran should default to -O3 */
else if (driver_type == DRIVER_F)
{
opt_level= OPTIM_IROPT_O;
}
/* sun4 or sw release >= 4.1 should default to -O2 */
else if ( (targ_arch_type == ARCH_SUN4) ||
(targ_arch_type == ARCH_SUN4C) ||
(sw_release_passes >= SW_REL_41) )
{
opt_level = OPTIM_IROPT_P;
}
else opt_level = OPTIM_C2;
return opt_level;
}
static OptimLevel
legal_optimization_level(opt_level, sw_release_passes, targ_arch_type,
driver_type)
OptimLevel opt_level;
int sw_release_passes;
int targ_arch_type;
int driver_type;
{
switch (opt_level)
{
case OPTIM_NONE: /* (0) NO opt */
case OPTIM_C2: /* (1) c2 opt, only */
break;
case OPTIM_IROPT_P: /* (2) iropt -P opt */
case OPTIM_IROPT_O: /* (3) iropt -O opt */
/* for sun386 and the c compiler use only 01 level */
if (targ_arch_type == ARCH_SUN386 && driver_type == DRIVER_C)
{
opt_level = OPTIM_C2;
break;
}
#ifndef FORCE_ACCEPT_O2O3O4 /* do the following checks, only if we are not */
/* forcing the host to allow -O2, -O3, and -O4 */
/* (the "force" mode is used for debugging). */
/* These levels are allowable for Fortran on any S/W release,
* for any language under 4.0, and for any language on a Sun4
* under any version of the operating system.
*/
if ( (driver_type == DRIVER_F)
||
#ifdef PASCAL_105
/* also allow higher optimization levels for Pascal 1.05 */
( ((driver_type == DRIVER_C)||(driver_type == DRIVER_P)) &&
(targ_arch_type == ARCH_SUN4) )
#else /*!PASCAL_105*/
( (driver_type == DRIVER_C) &&
((targ_arch_type == ARCH_SUN4C) ||
(targ_arch_type == ARCH_SUN4)) )
#endif /*PASCAL_105*/
||
(sw_release_passes != SW_REL_3X) )
{
/* These optimization levels are OK for these. */
}
else
{
/* Back down to the default 3.x optimization level. */
opt_level = OPTIM_C2;
}
#endif /*!FORCE_ACCEPT_O2O3O4*/
break;
case OPTIM_IROPT_O_TRACK_PTRS: /* (4) iropt -O, with pointer-tracking*/
/* for sun386 and the c compiler use only 01 level */
if (targ_arch_type == ARCH_SUN386 && driver_type == DRIVER_C)
{
opt_level = OPTIM_C2;
break;
}
#ifndef FORCE_ACCEPT_O2O3O4
/* This level is allowable only on post-3.x (i.e. 4.0)
* compilers, or on 3.2 (i.e. Sys4-3.2L or Sys4-3.2+)
* compilers on a Sun4.
*/
if ( (sw_release_passes != SW_REL_3X) ||
(targ_arch_type == ARCH_SUN4C) ||
(targ_arch_type == ARCH_SUN4)
)
{
/* All OK. */
}
else
{
/* Back down to the default optimization level. */
opt_level =
default_optimization_level(sw_release_passes,
targ_arch_type, driver_type);
}
#endif /*!FORCE_ACCEPT_O2O3O4*/
break;
default:
illegal_optimize_option(opt_level);
}
return opt_level;
}
static void
set_global_flag_defaults()
{
/* All are OFF by default; so only turn ON the exceptions. */
set_flag(show_rm_commands); /* OK to echo "rm" cmds */
set_flag(remove_tmp_files); /* remove all /tmp files, by default. */
#if defined(FORCE_SYS5)
set_flag(sys5_flag); /* Force SysV default orientation. */
# ifdef DEBUG
if (is_on(debug)) fprintf(stderr, "[orientation=sys5(forced)]\n");
# endif /*DEBUG*/
#elif defined(FORCE_UCB)
reset_flag(sys5_flag); /* Force UCB default orientation. */
# ifdef DEBUG
if (is_on(debug)) fprintf(stderr, "[orientation=ucb(forced)]\n");
# endif /*DEBUG*/
#else
uninitialize_flag(sys5_flag); /* Leave uninitialized until we know
* the target software release number.
*/
#endif /* forced UCB or SYS5 orientations */
}
#ifdef NSE
static void
consult_NSE_environment()
{
static char NSE_env_variable_not_set[] =
"env variable %s not set, in NSE variant \"%s\"";
ENV_nse_variant = getenv("NSE_VARIANT");
if (IN_AN_NSE_VARIANT(ENV_nse_variant))
{
/* We're in an NSE variant. */
/* Get the target architecture type and target release number
* specified by NSE -- if any.
*/
if ( (ENV_target_arch = getenv(TARGET_ARCH_varname)) == NULL )
{
fatal(NSE_env_variable_not_set,
TARGET_ARCH_varname, ENV_nse_variant);
}
else
{
/* If the target architecture starts with '-' in the
* environment, drop the '-' (which is a historical
* artifact).
*/
ENV_target_arch = skip_leading_minus(ENV_target_arch);
if (target_arch.value == NULL)
{
/* Target architecture was NOT specified
* explicitly by user. Use the NSE TARGET_ARCH
* target architecture.
*/
set_target_architecture(&target_arch,
ENV_target_arch, FALSE);
}
}
if ( (ENV_target_release = getenv(TARGET_RELEASE_varname))
== NULL)
{
fatal(NSE_env_variable_not_set,
TARGET_RELEASE_varname, ENV_nse_variant);
}
else
{
/* Set all target s/w release values which are (so far)
* defaulted, i.e. NOT specified explicitly by the user,
* to the NSE TARGET_RELEASE value.
*/
set_all_defaulted_target_sw_release_values(
ENV_target_release,
TARGET_RELEASE_varname,"=",ENV_target_release);
}
}
else
{
/* We're in a normal, non-NSE environment. Use the regular
* defaults for target architecture and release number.
*/
}
# ifdef DEBUG
consulted_NSE = TRUE;
# endif
}
#endif NSE
static void
define_arch_and_sw_release()
{
Const_intP arch_of_tools_in_root_filesystem;
#ifdef NSE
/* Consult the NSE environment for default target architecture and
* target software release -- if it sets them at all.
*/
consult_NSE_environment();
#endif
set_host_and_target();
#ifdef PASCAL_105
/* Save the initial target s/w release. If it was given on the
* command line, it's as given. If not, it is the default value,
* BEFORE we end up setting it via get_target_base_OS_version()
* in setup_for_*_compile(). */
original_sw_rel_passes = target_sw_release[R_PASSES].value;
#endif /*PASCAL_105*/
#ifdef CROSS
# ifdef NSE
# ifdef DEBUG
if (!consulted_NSE) internal_fatal("skipped NSE check!");
# endif
/* If we're in an activated NSE environment, then the tools which
* appear to be in the root filesystem are actually cross-tools for
* the target architecture.
*
* If we're not in an activated NSE environment,the tools in the root
* filesystem are actually the native tools.
*/
if ( IN_AN_NSE_VARIANT(ENV_nse_variant) )
{
arch_of_tools_in_root_filesystem =
lookup_architecture(ENV_target_arch);
}
else
{
arch_of_tools_in_root_filesystem = host_arch.value;
}
# else /*!NSE*/
arch_of_tools_in_root_filesystem = host_arch.value;
# endif /*NSE*/
/* We have native compilation only if:
* the tools in the root filesystem are those needed for the
* target architecture,
* AND the S/W release for which the tools in the root filesystem are
* intended match the target S/W release.
*
* Otherwise, we have cross-compilation.
*/
if ( (arch_of_tools_in_root_filesystem->value ==
target_arch.value->value)
&&
( (target_sw_release[R_VROOT].value->value == SW_REL_DFLT) ||
(target_sw_release[R_VROOT].value->value ==
get_target_base_OS_version("", driver.value)->value) )
)
{
setup_for_native_compile();
}
else
{
/* We're doing a cross-compilation. */
setup_for_cross_compile();
}
#else /*!CROSS*/
setup_for_native_compile();
#endif /*CROSS*/
} /* define_arch_and_sw_release() */
void
check_sys5_flag_status()
{
if is_initialized(sys5_flag)
{
#ifdef DEBUG
if (is_on(debug))
{
fprintf(stderr,"[orientation=%s]\n",
(is_on(sys5_flag) ? "sys5" : "ucb") );
}
#endif /*DEBUG*/
}
else
{
/* we'll use the default orientation based on the
* target software release.
*/
if (target_sw_release[R_PATHS].value->value <= SW_REL_40)
{
reset_flag(sys5_flag); /* bsd, for 4.0 and previous.*/
# ifdef DEBUG
if (is_on(debug))
{
fprintf(stderr,"[orientation=ucb(rel<=4.0)]\n");
}
# endif /*DEBUG*/
}
else
{
reset_flag(sys5_flag); /* ucb for 4.1 */
# ifdef DEBUG
if (is_on(debug))
{
fprintf(stderr,"[orientation=ucb(rel>=4.1)]\n");
}
# endif /*DEBUG*/
}
}
} /* check_sys5_flag_status */
/*
* main()
*/
void
main(argc, argv)
int argc;
char *argv[];
{
char *p;
set_signal(SIGINT, abort_program);
set_signal(SIGTERM, abort_program);
set_signal(SIGQUIT, abort_program);
set_signal(SIGHUP, abort_program);
set_global_flag_defaults();
/* Do not buffer output */
(void)setlinebuf(stdout);
(void)setlinebuf(stderr);
scan_vroot_first();
argv_for_passes= (char **)get_memory(
(argc+MAX_NUMBER_OF_DRIVER_SUPPLIED_ARGS)*sizeof(char *));
#ifdef BROWSER
if (getenv(CB_INIT_ENV_VAR) != NULL) {
set_flag(code_browser_seen);
}
#endif
/* Strip path from program name */
if ((p= rindex(argv[0], '/')) != NULL)
{
argv[0]= p+1;
}
program_name= argv[0];
/* If the program name starts with "x" we provide "-dryrun";
* if it starts with "X" or "-" we provide "-dryrun -normcmds" (which
* dryrun's without showing the file-removal lines).
* These are debugging aids for the /lib/compile maintainer, not
* features for users.
*/
switch (argv[0][0])
{
case 'X':
case '-':
reset_flag(show_rm_commands); /* don't echo "rm" cmds */
/* fall through to 'x' case! */
case 'x':
set_flag(dryrun);
(argv[0])++;
break;
default:
/* The usual case -- nothing to do, here. */
break;
}
/* Lookup the program name */
argv+= lookup_option(drivers, &argc, argv, 0, DRIVER_all);
if (driver.value == NULL)
{
fatal("Unknown driver %s", argv[-1]);
}
/* Process all the command line options */
while (argc > 0)
{
if (driver.value == &xlint)
argv+= lookup_lint_option(options, &argc, argv, 1, 0);
else
argv+= lookup_option(options, &argc, argv, 1, 0);
}
if (driver.value == &dummy)
{
exit(0);
}
if (is_on(do_dependency))
{
set_named_int(product, &preprocessed);
}
/* OK, now that we have parsed all the command line
* options, lets set the target sw architecture and sw release
*/
define_arch_and_sw_release();
check_sys5_flag_status();
switch (target_sw_release[R_PATHS].value->value)
{
case SW_REL_3X:
setup_for_R3X_file_paths();
break;
case SW_REL_40:
case SW_REL_41:
setup_for_R4X_file_paths();
break;
default:
fatal("Invalid target sw release %d",target_sw_release[R_PATHS].value->value);
}
if (use_default_optimizer_level)
{
/* Plain "-O" was specified, and no specific optimization
* level (such as "-O2") was given. Use the default level
* for this combination of S/W release, target architecture,
* and driver type.
*/
optimizer_level =
default_optimization_level(
target_sw_release[R_PASSES].value->value,
target_arch.value->value,
driver.value->value );
}
else
{
optimizer_level =
legal_optimization_level(
optimizer_level,
target_sw_release[R_PASSES].value->value,
target_arch.value->value,
driver.value->value);
}
check_for_option_conflicts();
/* Call action routine for this driver */
if (driver.value->name != NULL)
(*((int (*)())(driver.value->name)))();
cleanup(0);
exit(exit_status);
} /* main */