[gnu.gcc] adding environment variables to gcc.c for pass/file locations

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.