mcg@mipon2.intel.com (Steven McGeady) (05/23/89)
Here is a note I sent some time ago - I never saw it reflected onto the net. I am posting three messages - The first one, which contains changes I needed to make to the base, a second, which contains suggestions for improvements in the base, and this one, which contains mods for gcc.c to provide environment variable support for locating passes and files. I have not posted the machine-specific files for the 960. If anyone wants them they can write to me. (p.s - these diffs, like all others I have posted, a relative to 1.34, not 1.35). S. McGeady Intel Corp. (503) 696-4393 -------------- To: info-gnu@prep.ai.mit.edu Cc: rms@wheaties.ai.mit.edu Subject: Adding environment variables to gcc Date: Mon, 15 May 89 18:04:07 PDT From: mcg The following diffs demonstrate my addition to 'gcc' of support for environment variables which control where gcc finds its various directories, programs and support files. I have tried to make these as general-purpose as possible, and have not included features that I wouldn't think generally needed. However, it is clear to me that these features are of primary interest to people who are building or working in a cross-compilation environment, where the host is not the same as the target processor, although they also may be of some use to those who switch between the GNU assembler and linker and the standard system programs. Some explanation is in order. In every case, the environment variables names themselves are supplied by the user - there is an implication that they will be somewhat different for each target architecture, e.g. G68KBASE for the 68000 family, G386BASE for the 386 family, GVAXBASE for the VAX, etc. The environment variables are heirarchical. At the top level is a variable known generically as 'GNUBASE'. In the absence of any other environment variables, all files are found relative to this: binaries in $GNUBASE/bin, libraries and non-user-accessible programs in $GNUBASE/lib, and include files in $GNUBASE/include. Each of these directories can be individually overridden, i.e. if the variable GNUBIN is set, then it is used in place of $GNUBASE/bin. The same holds true for $GNULIB and $GNUINC. A full path to every program that gcc knows about may also be supplied: GNUAS - default $GNUBASE/bin/as, or $GNUBIN/as GNULD GNUCC1 GNUCC1PLUS GNUCPP GNUCRT GNUCRTM GNUCRTG If the full pathnames are not used, then the program names appended onto the GNUBASE, GNUBIN, etc, are not set from environment variables, but are set from the machine specification. Preprocessor definitions define these strings: GNUAS_DFLT (default "as") GNULD_DFLT (default "ld") GNUCC1_DFLT (default "cc1") GNUCPP_DFLT (default "gcc-cpp") GNUCRT_DFLT (default "crt.o") GNUCRTM_DFLT (default "crtm.o") GNUCRTG_DFLT (default "crtg.o") GNUINC_DFLT (default "include") Rather than set this mechanism up as another distinct standard, it is fit into the standard gcc specification mechanism as follows: %['e'] substitute environment variable 'e' %['e':X] substitute environment variable 'e' or X, if 'e' is not set %[~] substitute environment variable defined by ENV_GNUBASE, or the flag-specified value for the exec base %[B] substitute environment variable defined by ENV_GNUBIN %[L] substitute environment variable defined by ENV_GNULIB %[I] substitute environment variable defined by ENV_GNUINC %[a] substitute environment variable defined by ENV_GNUAS %[C] substitute environment variable defined by ENV_GNUCPP %[1] substitute environment variable defined by ENV_GNUCC1 %[l] substitute environment variable defined by ENV_GNULD %[+] substitute environment variable defined by ENV_GNUCC1PLUS %[S] substitute environment variable defined by ENV_GNUCRT %[M] substitute environment variable defined by ENV_GNUCRT_M %[G] substitute environment variable defined by ENV_GNUCRT_G *** all of the above come in the ':X' form also %[@a] substitute default name of assembler from GNUAS_DFLT %[@l] substitute default name of linker from GNULD_DFLT %[@1] substitite default name of compiler from GNUCC1_DFLT %[@c] substitute default name of cpp from GNUCPP_DFLT %[@S] substitute default name of crt from GNUCRT_DFLT %[@M] substitute default name of crtm from GNUCRTM_DFLT %[@G] substitute default name of crtg from GNUCRTG_DFLT %[@I] substitute default name of include dir from GNUINC_DFLT *** the following combine STANDARD_EXEC_PREFIX or STANDARD_LIB_PREFIX with the above to form a standard, default, last-gasp pathname %[?a] substitute the standard path to assembler %[?l] substitute the standard path to linker %[?1] substitute the standard path to compiler %[?c] substitute the standard path to cpp %[?S] substitute the standard path to crt.o %[?M] substitute the standard path to crtm.o %[?G] substitute the standard path to crtg.o %[?I] substitute the standard path to include dir Thus, the specification string to select the preprocessor becomes: %[C:%[L/%[@c]:%[~/lib/%[@c]:%[?c]]]] explained, this is: - first try $GNUCPP (or the target-defined environment variable) - if that's not set, try $GNULIB/cpp (where "cpp" is potentially the target-supplied CPP string) - if $GNULIB isn't set, the try $GNUBASE/lib/cpp (with the same caveat for the CPP string) - if $GNUBASE isn't set, then use a default path based on the define STANDARD_LIB_PREFIX This is fully compatible with gcc's current behaviour except for the ability to search multiple library directories for programs and files. Problems that this mechanism does not yet solve are the searching of multiple library and include directories. I feel that this is best left to the -I... switches for the preprocessor, and an equivalent (but unimplemented in many systems) -L... switch for the linker. Selection of 'crt' files is attempted by these patches, but I am not wholly happy with the result. In any case, I hope that something like this finds a permanent home in gcc.c. S. McGeady Intel Corp. --------------------------------------------------------------------------- *** ../gcc-1.34/gcc.c Tue Mar 7 08:59:28 1989 --- gcc960.c Sun May 14 16:57:40 1989 *************** *** 72,97 **** --- 72,146 ---- %s current argument is the name of a library or startup file of some sort. Search for that file in a standard list of directories and substitute the full pathname found. %eSTR Print STR as an error message. STR is terminated by a newline. Use this when inconsistent options are detected. + %a process ASM_SPEC as a spec. This allows config.h to specify part of the spec for running as. %l process LINK_SPEC as a spec. %L process LIB_SPEC as a spec. %S process STARTFILE_SPEC as a spec. A capital S is actually used here. %c process SIGNED_CHAR_SPEC as a spec. %C process CPP_SPEC as a spec. A capital C is actually used here. %1 process CC1_SPEC as a spec. + + *** + + %['e'] substitute environment variable 'e' + %['e':X] substitute environment variable 'e' or X, if 'e' is not set + + %[~] substitute environment variable defined by ENV_GNUBASE, + or the flag-specified value for the exec base + %[B] substitute environment variable defined by ENV_GNUBIN + %[L] substitute environment variable defined by ENV_GNULIB + %[I] substitute environment variable defined by ENV_GNUINC + + %[a] substitute environment variable defined by ENV_GNUAS + %[C] substitute environment variable defined by ENV_GNUCPP + %[1] substitute environment variable defined by ENV_GNUCC1 + %[l] substitute environment variable defined by ENV_GNULD + %[+] substitute environment variable defined by ENV_GNUCC1PLUS + %[S] substitute environment variable defined by ENV_GNUCRT + %[M] substitute environment variable defined by ENV_GNUCRT_M + %[G] substitute environment variable defined by ENV_GNUCRT_G + + *** all of the above come in the ':X' form also + + %[@a] substitute default name of assembler from GNUAS_DFLT + %[@l] substitute default name of linker from GNULD_DFLT + %[@1] substitite default name of compiler from GNUCC1_DFLT + %[@c] substitute default name of cpp from GNUCPP_DFLT + %[@S] substitute default name of crt from GNUCRT_DFLT + %[@M] substitute default name of crtm from GNUCRTM_DFLT + %[@G] substitute default name of crtg from GNUCRTG_DFLT + %[@I] substitute default name of include dir from GNUINC_DFLT + + *** the following combine STANDARD_EXEC_PREFIX or STANDARD_LIB_PREFIX + with the above to form a standard, default, last-gasp pathname + + %[?a] substitute the standard path to assembler + %[?l] substitute the standard path to linker + %[?1] substitute the standard path to compiler + %[?c] substitute the standard path to cpp + %[?S] substitute the standard path to crt.o + %[?M] substitute the standard path to crtm.o + %[?G] substitute the standard path to crtg.o + %[?I] substitute the standard path to include dir + + *** + %{S} substitutes the -S switch, if that switch was given to CC. If that switch was not specified, this substitutes nothing. Here S is a metasyntactic variable. %{S*} substitutes all the switches specified to CC whose names start with -S. This is used for -o, -D, -I, etc; switches that take arguments. CC considers `-o foo' as being one switch whose name starts with `o'. %{o*} would substitute this text, including the space; thus, two arguments would be generated. + %{~S*} substitutes the argument to switch 'S', but without the '-S' switch + itself %{S:X} substitutes X, but only if the -S switch was given to CC. %{!S:X} substitutes X, but only if the -S switch was NOT given to CC. %{|S:X} like %{S:X}, but if no S switch, substitute `-'. %{|!S:X} like %{!S:X}, but if there is an S switch, substitute `-'. *************** *** 113,127 **** */ /* This defines which switches take arguments. */ ! #define SWITCH_TAKES_ARG(CHAR) \ ! ((CHAR) == 'D' || (CHAR) == 'U' || (CHAR) == 'o' \ ! || (CHAR) == 'e' || (CHAR) == 'T' || (CHAR) == 'u' \ ! || (CHAR) == 'I' || (CHAR) == 'Y' || (CHAR) == 'm' \ ! || (CHAR) == 'L') #include <stdio.h> #include <sys/types.h> #include <signal.h> #include <sys/file.h> --- 162,177 ---- */ /* This defines which switches take arguments. */ ! #define SWITCH_TAKES_ARG(CHAR) ( \ ! (CHAR) == 'D' || (CHAR) == 'U' || (CHAR) == 'o' || \ ! (CHAR) == 'e' || (CHAR) == 'T' || (CHAR) == 'u' || \ ! (CHAR) == 'I' || (CHAR) == 'Y' || (CHAR) == 'm' || \ ! (CHAR) == 'L' || (CHAR) == 'C' \ ! ) #include <stdio.h> #include <sys/types.h> #include <signal.h> #include <sys/file.h> *************** *** 133,142 **** --- 183,195 ---- #define W_OK 2 #define X_OK 1 #define vfork fork #endif /* USG */ + extern char *strchr(); + extern char *getenv(); + #define obstack_chunk_alloc xmalloc #define obstack_chunk_free free extern int xmalloc (); extern void free (); *************** *** 148,157 **** --- 201,211 ---- /* This is the obstack which we use to allocate many strings. */ struct obstack obstack; char *handle_braces (); + char *handle_brackets (); char *save_string (); char *concat (); int do_spec (); int do_spec_1 (); char *find_file (); *************** *** 187,204 **** #endif /* config.h can define STARTFILE_SPEC to override the default crt0 files. */ #ifndef STARTFILE_SPEC #define STARTFILE_SPEC \ ! "%{pg:gcrt0.o%s}%{!pg:%{p:mcrt0.o%s}%{!p:crt0.o%s}}" #endif /* This spec is used for telling cpp whether char is signed or not. */ #define SIGNED_CHAR_SPEC \ (DEFAULT_SIGNED_CHAR ? "%{funsigned-char:-D__CHAR_UNSIGNED__}" \ : "%{!fsigned-char:-D__CHAR_UNSIGNED__}") /* This structure says how to run one compiler, and when to do so. */ struct compiler { char *suffix; /* Use this compiler for input files --- 241,337 ---- #endif /* config.h can define STARTFILE_SPEC to override the default crt0 files. */ #ifndef STARTFILE_SPEC #define STARTFILE_SPEC \ ! "%{!crt:%{pg:%[G:%[L/%[@G]:%[~/lib/gcrt0.o:%[?G]]]]}\ ! %{!pg:%{p:%[M:%[L/%[@M]:%[~/lib/mcrt0.o:%[?M]]]]}\ ! %{!p:%[S:%[L/%[@S]:%[~/crt0.o:%[?C]]]]}}}" #endif /* This spec is used for telling cpp whether char is signed or not. */ #define SIGNED_CHAR_SPEC \ (DEFAULT_SIGNED_CHAR ? "%{funsigned-char:-D__CHAR_UNSIGNED__}" \ : "%{!fsigned-char:-D__CHAR_UNSIGNED__}") + #ifndef STANDARD_EXEC_PREFIX + #define STANDARD_EXEC_PREFIX "/usr/local/bin/gnu" + #endif + + #ifndef STANDARD_LIB_PREFIX + #define STANDARD_LIB_PREFIX "/usr/local/lib/gnu" + #endif + + #ifndef STANDARD_INC_PREFIX + #define STANDARD_INC_PREFIX "/usr/local/lib/gnu/include" + #endif + + #ifndef GNUAS_DFLT + #define GNUAS_DFLT "as" + #endif + #ifndef GNULD_DFLT + #define GNULD_DFLT "ld" + #endif + #ifndef GNUCC1_DFLT + #define GNUCC1_DFLT "cc1" + #endif + #ifndef GNUCPP_DFLT + #define GNUCPP_DFLT "gcc-cpp" + #endif + #ifndef GNUCRT_DFLT + #define GNUCRT_DFLT "crt.o" + #endif + #ifndef GNUCRTM_DFLT + #define GNUCRTM_DFLT "crtm.o" + #endif + #ifndef GNUCRTG_DFLT + #define GNUCRTG_DFLT "crtg.o" + #endif + #ifndef GNUINC_DFLT + #define GNUINC_DFLT "include" + #endif + + #ifndef ENV_GNUAS + #define ENV_GNUAS "GNUAS" + #endif + #ifndef ENV_GNUCPP + #define ENV_GNUCPP "GNUCPP" + #endif + #ifndef ENV_GNUCC1 + #define ENV_GNUCC1 "GNUCC1" + #endif + #ifndef ENV_GNUCC1PLUS + #define ENV_GNUCC1PLUS "GNUCC1PLUS" + #endif + #ifndef ENV_GNULD + #define ENV_GNULD "GNULD" + #endif + #ifndef ENV_GNUCRT + #define ENV_GNUCRT "GNUCRT" + #endif + #ifndef ENV_GNUCRT_G + #define ENV_GNUCRT_G "GNUCRT_G" + #endif + #ifndef ENV_GNUCRT_M + #define ENV_GNUCRT_M "GNUCRT_M" + #endif + #ifndef ENV_GNUBASE + #define ENV_GNUBASE "GNUBASE" + #endif + #ifndef ENV_GNUBIN + #define ENV_GNUBIN "GNUBIN" + #endif + #ifndef ENV_GNULIB + #define ENV_GNULIB "GNULIB" + #endif + #ifndef ENV_GNUINC + #define ENV_GNUINC "GNUINC" + #endif + + char *user_exec_prefix; + + /* This structure says how to run one compiler, and when to do so. */ struct compiler { char *suffix; /* Use this compiler for input files *************** *** 212,277 **** unchanged to the loader and nothing else will be done to it. */ struct compiler compilers[] = { {".c", ! "cpp %{nostdinc} %{C} %{v} %{D*} %{U*} %{I*} %{M*} %{T} \ ! -undef -D__GNUC__ %{ansi:-T -$ -D__STRICT_ANSI__} %{!ansi:%p} %P\ %c %{O:-D__OPTIMIZE__} %{traditional} %{pedantic}\ %{Wcomment} %{Wtrigraphs} %{Wall} %C\ %i %{!M*:%{!E:%{!pipe:%g.cpp}}}%{E:%{o*}}%{M*:%{o*}} |\n\ ! %{!M*:%{!E:cc1 %{!pipe:%g.cpp} %1 \ %{!Q:-quiet} -dumpbase %i %{Y*} %{d*} %{m*} %{f*} %{a}\ %{g} %{O} %{W*} %{w} %{pedantic} %{ansi} %{traditional}\ %{v:-version} %{gg:-symout %g.sym} %{pg:-p} %{p}\ %{pg:%{fomit-frame-pointer:%e-pg and -fomit-frame-pointer are incompatible}}\ %{S:%{o*}%{!o*:-o %b.s}}%{!S:-o %{|!pipe:%g.s}} |\n\ ! %{!S:as %{R} %{j} %{J} %{h} %{d2} %a %{gg:-G %g.sym}\ ! %{!pipe:%g.s}\ %{c:%{o*}%{!o*:-o %w%b.o}}%{!c:-o %d%w%b.o}\n }}}"}, {".cc", ! "cpp -+ %{nostdinc} %{C} %{v} %{D*} %{U*} %{I*} %{M*} %{T}\ ! -undef -D__GNUC__ %p %P\ %c %{O:-D__OPTIMIZE__} %{traditional} %{pedantic}\ %{Wcomment} %{Wtrigraphs} %{Wall} %C\ %i %{!M*:%{!E:%{!pipe:%g.cpp}}}%{E:%{o*}}%{M*:%{o*}} |\n\ ! %{!M*:%{!E:cc1plus %{!pipe:%g.cpp} %1\ %{!Q:-quiet} -dumpbase %i %{Y*} %{d*} %{m*} %{f*} %{a}\ %{g} %{O} %{W*} %{w} %{pedantic} %{traditional}\ %{v:-version} %{gg:-symout %g.sym} %{pg:-p} %{p}\ %{pg:%{fomit-frame-pointer:%e-pg and -fomit-frame-pointer are incompatible}}\ %{S:%{o*}%{!o*:-o %b.s}}%{!S:-o %{|!pipe:%g.s}} |\n\ ! %{!S:as %{R} %{j} %{J} %{h} %{d2} %a %{gg:-G %g.sym}\ ! %{!pipe:%g.s}\ %{c:%{o*}%{!o*:-o %w%b.o}}%{!c:-o %d%w%b.o}\n }}}"}, {".i", ! "cc1 %i %1 %{!Q:-quiet} %{Y*} %{d*} %{m*} %{f*} %{a}\ %{g} %{O} %{W*} %{w} %{pedantic} %{ansi} %{traditional}\ %{v:-version} %{gg:-symout %g.sym} %{pg:-p} %{p}\ %{S:%{o*}%{!o*:-o %b.s}}%{!S:-o %{|!pipe:%g.s}} |\n\ ! %{!S:as %{R} %{j} %{J} %{h} %{d2} %a %{gg:-G %g.sym}\ %{!pipe:%g.s} %{c:%{o*}%{!o*:-o %w%b.o}}%{!c:-o %d%w%b.o}\n }"}, {".s", ! "%{!S:as %{R} %{j} %{J} %{h} %{d2} %a \ %i %{c:%{o*}%{!o*:-o %w%b.o}}%{!c:-o %d%w%b.o}\n }"}, {".S", ! "cpp %{nostdinc} %{C} %{v} %{D*} %{U*} %{I*} %{M*} %{T} \ ! -undef -D__GNUC__ -$ %p %P\ %c %{O:-D__OPTIMIZE__} %{traditional} %{pedantic}\ %{Wcomment} %{Wtrigraphs} %{Wall} %C\ %i %{!M*:%{!E:%{!pipe:%g.cpp}}}%{E:%{o*}}%{M*:%{o*}} |\n\ ! %{!M*:%{!E:%{!S:as %{R} %{j} %{J} %{h} %{d2} %a %{!pipe:%g.s} \ %{c:%{o*}%{!o*:-o %w%b.o}}%{!c:-o %d%w%b.o}\n }}}"}, /* Mark end of table */ {0, 0} }; /* Here is the spec for running the linker, after compiling all files. */ ! char *link_spec = "%{!c:%{!M*:%{!E:%{!S:ld %{o*} %l\ %{A} %{d} %{e*} %{N} %{n} %{r} %{s} %{S} %{T*} %{t} %{u*} %{X} %{x} %{z}\ %{y*} %{!nostdlib:%S} \ %{L*} %o %{!nostdlib:gnulib%s %{g:-lg} %L}\n }}}}"; /* Record the names of temporary files we tell compilers to write, and delete them at the end of the run. */ /* This is the common prefix we use to make temp file names. --- 345,413 ---- unchanged to the loader and nothing else will be done to it. */ struct compiler compilers[] = { {".c", ! "%[C:%[L/%[@c]:%[~/lib/%[@c]:%[?c]]]]\ ! %{nostdinc} %{C} %{v} %{D*} %{U*} %{I*} %{M*}\ ! %{T} -undef -D__GNUC__ %{ansi:-T -$ -D__STRICT_ANSI__}\ ! %{!ansi:%p} %P\ %c %{O:-D__OPTIMIZE__} %{traditional} %{pedantic}\ %{Wcomment} %{Wtrigraphs} %{Wall} %C\ %i %{!M*:%{!E:%{!pipe:%g.cpp}}}%{E:%{o*}}%{M*:%{o*}} |\n\ ! %{!M*:%{!E:%[1:%[L/%[@1]:%[~/lib/%[@1]:%[?1]]]] %{!pipe:%g.cpp} %1 \ %{!Q:-quiet} -dumpbase %i %{Y*} %{d*} %{m*} %{f*} %{a}\ %{g} %{O} %{W*} %{w} %{pedantic} %{ansi} %{traditional}\ %{v:-version} %{gg:-symout %g.sym} %{pg:-p} %{p}\ %{pg:%{fomit-frame-pointer:%e-pg and -fomit-frame-pointer are incompatible}}\ %{S:%{o*}%{!o*:-o %b.s}}%{!S:-o %{|!pipe:%g.s}} |\n\ ! %{!S:%[a:%[B/%[@a]:%[~/bin/%[@a]:%[?a]]]] %{R} %{j} %{J} %{h} %{d2} %a\ ! %{gg:-G %g.sym} %{!pipe:%g.s}\ %{c:%{o*}%{!o*:-o %w%b.o}}%{!c:-o %d%w%b.o}\n }}}"}, {".cc", ! "%[C:%[L/%[@c]:%[~/lib/%[@c]:%[?c]]]] -+ %{nostdinc} %{C} %{v} %{D*} %{U*} %{I*}\ ! %{M*} %{T} -undef -D__GNUC__ %p %P\ %c %{O:-D__OPTIMIZE__} %{traditional} %{pedantic}\ %{Wcomment} %{Wtrigraphs} %{Wall} %C\ %i %{!M*:%{!E:%{!pipe:%g.cpp}}}%{E:%{o*}}%{M*:%{o*}} |\n\ ! %{!M*:%{!E:%[+:%[L/%[@+]:%[~/lib/%[@+]:%[?+]]]] %{!pipe:%g.cpp} %1\ %{!Q:-quiet} -dumpbase %i %{Y*} %{d*} %{m*} %{f*} %{a}\ %{g} %{O} %{W*} %{w} %{pedantic} %{traditional}\ %{v:-version} %{gg:-symout %g.sym} %{pg:-p} %{p}\ %{pg:%{fomit-frame-pointer:%e-pg and -fomit-frame-pointer are incompatible}}\ %{S:%{o*}%{!o*:-o %b.s}}%{!S:-o %{|!pipe:%g.s}} |\n\ ! %{!S:%[a:%[B/%[@a]:%[~/bin/%[@a]:%[?a]]]] %{R} %{j} %{J} %{h} %{d2} %a\ ! %{gg:-G %g.sym} %{!pipe:%g.s}\ %{c:%{o*}%{!o*:-o %w%b.o}}%{!c:-o %d%w%b.o}\n }}}"}, {".i", ! "%[1:%[L/%[@1]:%[~/lib/%[@1]:%[?1]]]] %i %1 %{!Q:-quiet} %{Y*} %{d*} %{m*} %{f*} %{a}\ %{g} %{O} %{W*} %{w} %{pedantic} %{ansi} %{traditional}\ %{v:-version} %{gg:-symout %g.sym} %{pg:-p} %{p}\ %{S:%{o*}%{!o*:-o %b.s}}%{!S:-o %{|!pipe:%g.s}} |\n\ ! %{!S:%[a:%[B/%[@a]:%[~/bin/%[@a]:%[?a]]]] %{R} %{j} %{J} %{h} %{d2} %a %{gg:-G %g.sym}\ %{!pipe:%g.s} %{c:%{o*}%{!o*:-o %w%b.o}}%{!c:-o %d%w%b.o}\n }"}, {".s", ! "%{!S:%[a:%[B/%[@a]:%[~/bin/%[@a]:%[?a]]]] %{R} %{j} %{J} %{h} %{d2} %a \ %i %{c:%{o*}%{!o*:-o %w%b.o}}%{!c:-o %d%w%b.o}\n }"}, {".S", ! "%[C:%[L/%[@c]:%[~/lib/%[@c]:%[?c]]]] %{nostdinc} %{C} %{v} %{D*} %{U*} %{I*} %{M*}\ ! %{T} -undef -D__GNUC__ -$ %p %P\ %c %{O:-D__OPTIMIZE__} %{traditional} %{pedantic}\ %{Wcomment} %{Wtrigraphs} %{Wall} %C\ %i %{!M*:%{!E:%{!pipe:%g.cpp}}}%{E:%{o*}}%{M*:%{o*}} |\n\ ! %{!M*:%{!E:%{!S:%[a:%[B/%[@a]:%[~/bin/%[@a]:%[?a]]]] %{R} %{j} %{J} %{h} %{d2} %a %{!pipe:%g.s} \ %{c:%{o*}%{!o*:-o %w%b.o}}%{!c:-o %d%w%b.o}\n }}}"}, /* Mark end of table */ {0, 0} }; /* Here is the spec for running the linker, after compiling all files. */ ! char *link_spec = "%{!c:%{!M*:%{!E:%{!S:%[l:%[B/%[@l]:%[~/bin/%[@l]:%[?l]]]] %{o*} %l\ %{A} %{d} %{e*} %{N} %{n} %{r} %{s} %{S} %{T*} %{t} %{u*} %{X} %{x} %{z}\ %{y*} %{!nostdlib:%S} \ %{L*} %o %{!nostdlib:gnulib%s %{g:-lg} %L}\n }}}}"; + /* Record the names of temporary files we tell compilers to write, and delete them at the end of the run. */ /* This is the common prefix we use to make temp file names. *************** *** 381,416 **** /* Flag indicating whether we should print the command and arguments */ unsigned char vflag; - /* User-specified -B prefix to attach to command names, - or 0 if none specified. */ - - char *user_exec_prefix = 0; - - /* Environment-specified prefix to attach to command names, - or 0 if none specified. */ - - char *env_exec_prefix = 0; - /* Default prefixes to attach to command names. */ - #ifndef STANDARD_EXEC_PREFIX - #define STANDARD_EXEC_PREFIX "/usr/local/lib/gcc-" - #endif /* !defined STANDARD_EXEC_PREFIX */ - - char *standard_exec_prefix = STANDARD_EXEC_PREFIX; - char *standard_exec_prefix_1 = "/usr/lib/gcc-"; - - #ifndef STANDARD_STARTFILE_PREFIX - #define STANDARD_STARTFILE_PREFIX "/lib/" - #endif /* !defined STANDARD_STARTFILE_PREFIX */ - - char *standard_startfile_prefix = STANDARD_STARTFILE_PREFIX; - char *standard_startfile_prefix_1 = "/usr/lib/"; - /* Clear out the vector of arguments (after a command is executed). */ void clear_args () { --- 517,528 ---- *************** *** 441,505 **** if (tempnamep) record_temp_file (arg, tempnamep == 2, tempnamep == 3); } ! /* Search for an execute file through our search path. ! Return 0 if not found, otherwise return its name, allocated with malloc. */ static char * find_exec_file (prog) char *prog; { ! int win = 0; ! char *temp; ! int size; - size = strlen (standard_exec_prefix); - if (user_exec_prefix != 0 && strlen (user_exec_prefix) > size) - size = strlen (user_exec_prefix); - if (env_exec_prefix != 0 && strlen (env_exec_prefix) > size) - size = strlen (env_exec_prefix); - if (strlen (standard_exec_prefix_1) > size) - size = strlen (standard_exec_prefix_1); - size += strlen (prog) + 1; - temp = (char *) xmalloc (size); - - /* Determine the filename to execute. */ - - if (user_exec_prefix) - { - strcpy (temp, user_exec_prefix); - strcat (temp, prog); - win = (access (temp, X_OK) == 0); - } - - if (!win && env_exec_prefix) - { - strcpy (temp, env_exec_prefix); - strcat (temp, prog); - win = (access (temp, X_OK) == 0); - } - - if (!win) - { - strcpy (temp, standard_exec_prefix); - strcat (temp, prog); - win = (access (temp, X_OK) == 0); - } - - if (!win) - { - strcpy (temp, standard_exec_prefix_1); - strcat (temp, argbuf[0]); - win = (access (temp, X_OK) == 0); - } - - if (win) - return temp; - else - return 0; } /* stdin file number. */ #define STDIN_FILE_NO 0 --- 553,575 ---- if (tempnamep) record_temp_file (arg, tempnamep == 2, tempnamep == 3); } ! /* Validate the exec file path */ ! /* Return 0 if not found, otherwise return its name */ static char * find_exec_file (prog) char *prog; { ! if (access(prog,X_OK) != 0) { ! pfatal_with_name(prog); ! return 0; ! } ! return(prog); } /* stdin file number. */ #define STDIN_FILE_NO 0 *************** *** 779,795 **** void process_command (argc, argv) int argc; char **argv; { - extern char *getenv (); register int i; n_switches = 0; n_infiles = 0; - env_exec_prefix = getenv ("GCC_EXEC_PREFIX"); - /* Scan argv twice. Here, the first time, just count how many switches there will be in their vector, and how many input files in theirs. Here we also parse the switches that cc itself uses (e.g. -v). */ for (i = 1; i < argc; i++) --- 849,862 ---- *************** *** 1100,1109 **** --- 1167,1182 ---- p = handle_braces (p); if (p == 0) return -1; break; + case '[': + p = handle_brackets (p); + if (p == 0) + return -1; + break; + case '%': obstack_1grow (&obstack, '%'); break; /*** The rest just process a certain constant string as a spec. */ *************** *** 1198,1207 **** --- 1271,1281 ---- { register char *q; char *filter; int pipe = 0; int negate = 0; + int tilde = 0; if (*p == '|') /* A `|' after the open-brace means, if the test fails, output a single minus sign rather than nothing. This is used in %{|!pipe:...}. */ *************** *** 1210,1219 **** --- 1284,1297 ---- if (*p == '!') /* A `!' after the open-brace negates the condition: succeed if the specified switch is not present. */ negate = 1, ++p; + if (*p == '~') + /* A '~' means to substitute the argument, but not the switch itself */ + tilde++, ++p; + filter = p; while (*p != ':' && *p != '}') p++; if (*p != '}') { register int count = 1; *************** *** 1238,1248 **** register int i; --p; for (i = 0; i < n_switches; i++) if (!strncmp (switches[i].part1, filter, p - filter)) { ! give_switch (i); } } else { /* Test for presence of the specified switch. */ --- 1316,1326 ---- register int i; --p; for (i = 0; i < n_switches; i++) if (!strncmp (switches[i].part1, filter, p - filter)) { ! give_switch (i, tilde); } } else { /* Test for presence of the specified switch. */ *************** *** 1281,1291 **** conditional text. */ if (present != negate) { if (*p == '}') { ! give_switch (i); } else { if (do_spec_1 (save_string (p + 1, q - p - 2), 0) < 0) return 0; --- 1359,1369 ---- conditional text. */ if (present != negate) { if (*p == '}') { ! give_switch (i,tilde); } else { if (do_spec_1 (save_string (p + 1, q - p - 2), 0) < 0) return 0; *************** *** 1300,1321 **** } return q; } /* Pass a switch to the current accumulating command in the same form that we received it. SWITCHNUM identifies the switch; it is an index into the vector of switches gcc received, which is `switches'. This cannot fail since it never finishes a command line. */ ! give_switch (switchnum) int switchnum; { ! do_spec_1 ("-", 0); ! do_spec_1 (switches[switchnum].part1, 1); ! do_spec_1 (" ", 0); if (switches[switchnum].part2 != 0) { do_spec_1 (switches[switchnum].part2, 1); do_spec_1 (" ", 0); } --- 1378,1617 ---- } return q; } + char * + handle_brackets (p) + register char *p; + { + register char *q,*e,*end; + register char *spec,*alt; + static int toplevel = 0; + int depth; + int is_exec = 0; + + /* find matching close bracket */ + depth = 0; + for(q = p; *q != '\0'; q++) { + if (*q == '[') { + depth++; + } + if (*q == ']') { + if (depth == 0) { + end = q; + break; + } + depth--; + } + if (*q == ':' && depth == 0) { + alt = q; + } + } + if (depth != 0) { + abort(); + } + + spec = 0; + + switch (*p++) { + case '\'': + /* single-quote after '[' indicates a literal environment */ + /* variable name to look up */ + if ((q = strchr(p,'\'')) == 0) { + abort(); + } + e = save_string(p,q-p-1); + p = q++; /* point after closing '\'' */ + if (q = getenv(e)) { + spec = save_string(q,strlen(q)); + } + break; + + case '~': /* base of directories */ + if (user_exec_prefix) { + spec = user_exec_prefix; + } else if (q = getenv(ENV_GNUBASE)) { + spec = save_string(q,strlen(q)); + } + break; + + case 'B': /* bin directory */ + if (q = getenv(ENV_GNUBIN)) { + spec = save_string(q,strlen(q)); + } + break; + case 'L': /* lib directory */ + if (q = getenv(ENV_GNULIB)) { + spec = save_string(q,strlen(q)); + } + break; + case 'I': /* include directory */ + if (q = getenv(ENV_GNUINC)) { + spec = save_string(q,strlen(q)); + } + break; + + case 'a': /* assembler */ + if (q = getenv(ENV_GNUAS)) { + spec = save_string(q,strlen(q)); + } + break; + case 'S': /* crt0 */ + if (q = getenv(ENV_GNUCRT)) { + spec = save_string(q,strlen(q)); + } + break; + case 'M': /* mcrt0 */ + if (q = getenv(ENV_GNUCRT_M)) { + spec = save_string(q,strlen(q)); + } + break; + case 'G': /* gcrt0 */ + if (q = getenv(ENV_GNUCRT_G)) { + spec = save_string(q,strlen(q)); + } + break; + case 'C': /* cpp */ + if (q = getenv(ENV_GNUCPP)) { + spec = save_string(q,strlen(q)); + } + break; + case '1': /* cc1 */ + if (q = getenv(ENV_GNUCC1)) { + spec = save_string(q,strlen(q)); + } + break; + case 'l': /* ld */ + if (q = getenv(ENV_GNULD)) { + spec = save_string(q,strlen(q)); + } + break; + case '+': /* cc1plus */ + if (q = getenv(ENV_GNUCC1PLUS)) { + spec = save_string(q,strlen(q)); + } + break; + case '@': + switch (*p++) { + case 'a': + spec = GNUAS_DFLT; + break; + case 'l': + spec = GNULD_DFLT; + break; + case '1': + spec = GNUCC1_DFLT; + break; + case 'c': + spec = GNUCPP_DFLT; + break; + case 'S': + spec = GNUCRT_DFLT; + break; + case 'M': + spec = GNUCRTM_DFLT; + break; + case 'G': + spec = GNUCRTG_DFLT; + break; + case 'I': + spec = GNUINC_DFLT; + break; + } + break; + + case '?': + spec = (char *) xmalloc(strlen(STANDARD_BIN_PREFIX) + 100); + + switch (*p++) { + case 'a': + strcpy(spec,STANDARD_BIN_PREFIX); + strcat(spec,GNUAS_DFLT); + break; + case 'l': + strcpy(spec,STANDARD_BIN_PREFIX); + strcat(spec,GNULD_DFLT); + break; + case '1': + strcpy(spec,STANDARD_LIB_PREFIX); + strcat(spec,GNUCC1_DFLT); + break; + case 'c': + strcpy(spec,STANDARD_LIB_PREFIX); + strcat(spec,GNUCPP_DFLT); + break; + case 'S': + strcpy(spec,STANDARD_LIB_PREFIX); + strcat(spec,GNUCRT_DFLT); + break; + case 'M': + strcpy(spec,STANDARD_LIB_PREFIX); + strcat(spec,GNUCRTM_DFLT); + break; + case 'G': + strcpy(spec,STANDARD_LIB_PREFIX); + strcat(spec,GNUCRTG_DFLT); + break; + case 'I': + strcpy(spec,STANDARD_INC_PREFIX); + break; + default: + spec = 0; + } + break; + + default: + return 0; + } + + if (spec) { + /* append remainder of string to spec */ + if (*p != ']' && *p != ':') { + if ((e = strchr(p,':')) == 0) { + e = end; + } + q = (char *) xmalloc(strlen(spec)+(e-p)+1); + strcpy(q,spec); + strncat(q,p,e-p); + spec = q; + } + } + + if (spec == 0) { + /* getenv failed - see if there's another clause */ + if (alt && *alt == ':') { + spec = save_string(++alt,end-alt-1); + } else if (toplevel == 0) { + fatal("program/library lookup failed - set $%s\n",ENV_GNUBASE); + return 0; + } + } + toplevel++; + if (do_spec_1(spec,0) < 0) { + toplevel--; + return 0; + } + toplevel--; + return(end+1); + } + /* Pass a switch to the current accumulating command in the same form that we received it. SWITCHNUM identifies the switch; it is an index into the vector of switches gcc received, which is `switches'. This cannot fail since it never finishes a command line. */ ! give_switch (switchnum, omitswitch) int switchnum; + int omitswitch; { ! if (omitswitch == 0) { ! do_spec_1 ("-", 0); ! do_spec_1 (switches[switchnum].part1, 1); ! do_spec_1 (" ", 0); ! } if (switches[switchnum].part2 != 0) { do_spec_1 (switches[switchnum].part2, 1); do_spec_1 (" ", 0); } *************** *** 1327,1408 **** char * find_file (name) char *name; { - int size; - char *temp; - int win = 0; - - /* Compute maximum size of NAME plus any prefix we will try. */ - - size = strlen (standard_exec_prefix); - if (user_exec_prefix != 0 && strlen (user_exec_prefix) > size) - size = strlen (user_exec_prefix); - if (env_exec_prefix != 0 && strlen (env_exec_prefix) > size) - size = strlen (env_exec_prefix); - if (strlen (standard_exec_prefix_1) > size) - size = strlen (standard_exec_prefix_1); - if (strlen (standard_startfile_prefix) > size) - size = strlen (standard_startfile_prefix); - if (strlen (standard_startfile_prefix_1) > size) - size = strlen (standard_startfile_prefix_1); - size += strlen (name) + 1; - - temp = (char *) alloca (size); - - if (user_exec_prefix) - { - strcpy (temp, user_exec_prefix); - strcat (temp, name); - win = (access (temp, R_OK) == 0); - } - - if (!win && env_exec_prefix) - { - strcpy (temp, env_exec_prefix); - strcat (temp, name); - win = (access (temp, R_OK) == 0); - } - - if (!win) - { - strcpy (temp, standard_exec_prefix); - strcat (temp, name); - win = (access (temp, R_OK) == 0); - } - - if (!win) - { - strcpy (temp, standard_exec_prefix_1); - strcat (temp, name); - win = (access (temp, R_OK) == 0); - } - - if (!win) - { - strcpy (temp, standard_startfile_prefix); - strcat (temp, name); - win = (access (temp, R_OK) == 0); - } - - if (!win) - { - strcpy (temp, standard_startfile_prefix_1); - strcat (temp, name); - win = (access (temp, R_OK) == 0); - } - - if (!win) - { - strcpy (temp, "./"); - strcat (temp, name); - win = (access (temp, R_OK) == 0); - } - - if (win) - return save_string (temp, strlen (temp)); return name; } /* Name with which this program was invoked. */ --- 1623,1632 ---- ---------------------------------------------------------------------------
michael@garfield.MUN.EDU (Mike Rendell) (05/25/89)
In article <4463@omepd.UUCP> mcg@mipon2.intel.com (Steven McGeady) writes: >The following diffs demonstrate my addition to 'gcc' of support for >environment variables which control where gcc finds its various directories, >programs and support files. > >I have tried to make these as general-purpose as possible, and have not >included features that I wouldn't think generally needed. However, it >is clear to me that these features are of primary interest to people >who are building or working in a cross-compilation environment, where >the host is not the same as the target processor, although they also >may be of some use to those who switch between the GNU assembler and >linker and the standard system programs. I was thinking about doing the same thing for the same reasons. The solution I came up with is to move the "spec" strings into a configuration file. The config file used could be specified as a (single) environment variable (e.g. GCC_CONFIG=/usr/local/lib/gcc-config/{atari,sun2,etc}) or as a flag to gcc. Each line of the config file is either a spec or a path - the first word of the line indicates what spec/path is being specified (for compiler specs, the second word is the suffix). A config file would look something like: # config file for <whatever> compiler .c cpp %{nostdinc} %{C} ... compiler .cc cpp -+ ... compiler .i cc1 ... compiler .s %{!S:as ...} compiler .S cpp ... link %{!c: ...} asm-spec ... cpp-spec ... cc1-spec ... link-spec ... lib-spec ... startfile-spec ... signed-char-spec ... exec-prefix ... startfile-prefix ... multiple compiler, exec-prefix, and startfile-prefix values may be specified. The default values for the host machine could be compiled into gcc, or read from a `standard' location e.g. "/usr/local/lib/gcc-def-config" (there is a chicken-and-egg problem here). Anyone see any problems with doing this? The advantages over mcg's solution are that is more general (you get to specify everything) and uses fewer environment variables, the disadvantage is that it does not allow explicit specification of the path for a particular program (could be extended to have cpp-path, asm-path, etc). I will be trying this out on the weekend - if it works out well I will post the diffs. -- Mike Rendell - Dept. of Comp. Sci, Memorial University of Newfoundland
gnu@hoptoad.uucp (John Gilmore) (05/26/89)
I don't understand why people are proposing complicated additions to the 'gcc' driver program for this. The existing facilities handle it quite well. If you want a variant of "gcc" that overrides the include files, locations of passes, libraries, etc, just create a tiny shell script, that does something like: exec gcc -B/wherever -nostdlib -nostdinc -I. -I- -I/wherever/include \ /somewhere/crt0.o $* /somewhere/lib/libc.a This will handle 99% of the problem (I think the only catch is profiled crt0's). I used this to build 4.3BSD Unix with gcc (on a machine whose libraries & include files didn't match my source tree). The recent gcc feature that warns about unused arguments may thwart this approach -- in that case we need a way to turn that warning off. -- John Gilmore {sun,pacbell,uunet,pyramid,amdahl}!hoptoad!gnu gnu@toad.com A well-regulated militia, being necessary to the security of a free State, the right of the people to keep and bear arms, shall not be infringed.