#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 #include #include #ifdef BROWSER #include "../browser/cblib/src/cb_init.h" #endif #if RELEASE < 40 # ifdef sparc # include # endif #else /* RELEASE >= 40 */ # include #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 \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 to a default value. */ request_default_opt_level(argv[0]); } else { /* -O was previously specified; * retain the previous value of . * 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) ) { /* -- 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 "=; export ". * For CSH, we'll use "setenv ". */ 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=" * 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 */