1$ !
2$ !	Set up to compile GCC on VMS.
3$ !
4$ ! Set the def dir to proper place for use in batch. Works for interactive too.
5$flnm = f$enviroment("PROCEDURE")     ! get current procedure name
6$set default 'f$parse(flnm,,,"DEVICE")''f$parse(flnm,,,"DIRECTORY")'
7$ !
8$set symbol/scope=(nolocal,noglobal)
9$if f$trnlnm("IFILE$").nes."" then close/noLog ifile$
10$ !
11$ echo = "write sys$output"
12$ !
13$ arch_indx = 1 + ((f$getsyi("CPU").ge.128).and.1)	! vax==1, alpha==2
14$ arch = f$element(arch_indx,"|","|vax|alpha|")
15$ !
16$ if f$search("config.h") .nes. "" then delete config.h.*
17$ if arch .eqs. "vax"
18$ then
19$   copy [.config.'arch']xm-vms.h []config.h
20$   echo "Linked `config.h' to `[.config.''arch']xm-vms.h'."
21$else
22$   open/write cfile []config.h
23$   write cfile "#include "+"""config/"+arch+"/xm-"+arch+".h"+"""
24$   write cfile "#include "+"""config/"+arch+"/xm-vms.h"+"""
25$   close cfile
26$   echo "Created `config.h'."
27$ endif
28$ !
29$ if f$search("tconfig.h") .nes. "" then delete tconfig.h.*
30$ create []tconfig.h
31$DECK
32/* tconfig.h == config.h :: target and host configurations are the same */
33#include "config.h"
34$EOD
35$ echo "Created `tconfig.h'.
36$ !
37$ if f$search("hconfig.h") .nes. "" then delete hconfig.h.*
38$ create []hconfig.h
39$DECK
40/* hconfig.h == config.h :: host and target configurations are the same */
41#include "config.h"
42$EOD
43$ echo "Created `hconfig.h'.
44$ !
45$ if f$search("tm.h") .nes. "" then delete tm.h.*
46$ !
47$ edit/tpu/nojournal/nosection/nodisplay/command=sys$input -
48        [.config.'arch']vms.h /output=[]tm.h
49$DECK
50!
51!  Copy file, changing lines of the form
52!	#include "vax/*"
53!  or
54!	#include "alpha/*"
55!  into
56!	#include "config-*"
57!
58   file := CREATE_BUFFER("file", GET_INFO(COMMAND_LINE, "file_name"));
59   targ := LINE_BEGIN & '#include' & SPAN(ASCII(32)+ASCII(9))
60	   & '"' & ('vax' | 'alpha') & '/';
61   rang := CREATE_RANGE(BEGINNING_OF(file), END_OF(file));
62   LOOP
63      incl := SEARCH_QUIETLY(targ, FORWARD, EXACT, rang);
64      EXITIF incl = 0;
65      POSITION(BEGINNING_OF(incl));
66      ERASE(incl);
67      COPY_TEXT('#include "config-');
68      rang := CREATE_RANGE(END_OF(incl), END_OF(file));
69   ENDLOOP;
70   WRITE_FILE(file, GET_INFO(COMMAND_LINE, "output_file"));
71   QUIT
72$  EOD
73$ echo "Generated `tm.h' from `[.config.''arch']vms.h'."
74$ !
75$	!crude hack to allow compiling from [.cp] subdirectory
76$ if f$search("config-''arch'.h") .nes. "" then delete config-'arch'.h;*
77$ copy [.config.'arch']'arch'.h []config-'arch'.h
78$ echo "Linked `config-''arch'.h' to `[.config.''arch']''arch'.h' for `tm.h'."
79$ !
80$ call make_lang_incl "options.h"
81$ !
82$ call make_lang_incl "specs.h"
83$ !
84$ if arch .eqs. "vax"
85$ then
86$   if f$search("''arch'.md") .nes. "" then delete 'arch'.md;*
87$   copy [.config.'arch']'arch'.md []'arch'.md
88$   echo "Copied `''arch'.md' from `[.config.''arch']''arch'.md'."
89$ endif
90$ !
91$ if f$search("aux-output.c") .nes. "" then delete aux-output.c.*
92$ copy [.config.'arch']'arch'.c []aux-output.c
93$ echo "Linked `aux-output.c' to `[.config.''arch']''arch'.c'.
94$ !
95$ !
96$ !
97$ ! Create the file version.opt, which helps identify the executable.
98$ !
99$search version.c version_string,"="/match=and/output=t.tmp
100$open ifile$ t.tmp
101$read ifile$ line
102$close ifile$
103$delete t.tmp;
104$line=f$element(1,"""",line)	!extract the portion between 1st & 2nd quotes
105$! Format of 'line' is "name-nn.nn.nn[.nn] [date text]" (without the quotes).
106$! We want "name-nn.nn.nn[.nn][-date]"; "-date" suffix is optional.
107$id = f$element(1,"-",line)		!strip "name-" prefix
108$if id.eqs."-" then  id = line		!no prefix found?
109$id = f$element(0," ",id) + "-" + f$element(1," ",id)	!first two tokens
110$id = id - "- "		!in case 2nd token was empty
111$if f$length(id).gt.15 then  id = f$extract(0,15,id)	!length limitation
112$!
113$open/write ifile$ version.opt
114$write ifile$ "ident="+""""+id+""""
115$close ifile$
116$purge version.opt
117$!
118$!
119$! create linker options files that lists all of the components for all
120$! possible compilers.  We do this by editing the file Makefile.in, and 
121$! generating the relevant files from it.
122$!
123$!
124$! Make a copy of the makefile if the sources are on a disk that is NFS 
125$!    mounted on a unix machine.
126$if f$search("Makefile.in").eqs."" .and. f$search("$M$akefile.in").nes."" -
127	then copy $M$akefile.in Makefile.in
128$! This should be automated across all front-end subdirectories.
129$!    For now, it's hardcoded.
130$if f$search("[.cp]Makefile.in").eqs."" .and. f$search("[.cp]$M$akefile.in").nes."" -
131	then copy [.cp]$M$akefile.in [.cp]Makefile.in
132$!
133$!
134$echo "Now processing Makefile.in to generate linker option files."
135$edit/TPU/noJournal/noSection/noDisplay/Command=sys$input: Makefile.in -
136	/Start_Position=('arch_indx')		! 1 for vax, 2 for alpha
137!!
138VARIABLE makefile_buf, opt_file_buf, complist_buf, extra_compilers; ! Globals.
139VARIABLE arch;		! String 'vax' or 'alpha', set in configure_makefile().
140
141!!
142PROCEDURE process_makefile( )
143  !
144  ! Interpret Makefile.in and subsidiary Make-lang.in templates.
145  !
146  LOCAL range1, cmark, makefilename;
147
148  makefilename	  := GET_INFO (COMMAND_LINE, 'FILE_NAME'); ! "Makefile.in"
149  makefile_buf	  := CREATE_BUFFER ("makefile", makefilename);
150  opt_file_buf	  := CREATE_BUFFER ("opt_file");
151  complist_buf	  := CREATE_BUFFER ("complist");
152  extra_compilers := CREATE_ARRAY;
153  !
154  SET (NO_WRITE, makefile_buf, ON);	! Used as workspace; don't save it.
155  SET (OUTPUT_FILE, complist_buf, "compilers.list");
156  !
157  ! Make some textual substitutions.
158  !
159  configure_makefile ();
160  !
161  ! Collect a list of supported compilers (``COMPILERS=xxx'' macro).
162  !
163  identify_compilers ();
164  !
165  ! Plus other known compilers described by Make-lang.in makefile fragments.
166  ! Add new entries as needed; args are (target name, subdirectory name).
167  !
168  additional_compiler ("cc1plus", "cp");
169  !
170  WRITE_FILE (complist_buf);		! Now save "compilers.list".
171  !
172  ! Add to this list, as required.  The file "Makefile.in" is searched for
173  ! a tag that looks like "LINE_BEGIN + 'tag + (optional space) + "="".
174  ! The contents are assumed to be a list of object files, and from this
175  ! list a VMS linker options file is generated.
176  !
177  generate_option_file ("OBJS",		 "=", "independent.opt");
178  generate_option_file ("LIB2FUNCS",	 "=", "libgcc2.list");
179  generate_option_file ("CXX_LIB2FUNCS", "=", "libgcc2-cxx.list");
180  !
181  ! Now change OBJS in the Makefile, so each language specific options file
182  ! does not pick up all of the language independent files.
183  !
184  POSITION (BEGINNING_OF (makefile_buf));
185  COPY_TEXT ("OBJS=");	! New copy with empty value, seen before real OBJS.
186  SPLIT_LINE;
187  !
188  ! Lastly, process each compiler-specific object dependency list.
189  !
190  POSITION (BEGINNING_OF (complist_buf));
191  LOOP
192    cmark := MARK (NONE);
193    EXITIF (cmark = END_OF (complist_buf));
194    ! The current line contains the name of a compiler target, such as "cc1".
195    MESSAGE (CURRENT_LINE);	! Give some interactive feedback.
196    generate_option_file (CURRENT_LINE, ":", CURRENT_LINE + "-objs.opt");
197    POSITION (cmark);
198    MOVE_VERTICAL (1);		! Go to the next line.
199  ENDLOOP;
200ENDPROCEDURE; !process_makefile
201!!
202
203PROCEDURE process_objc_lib( )
204  !
205  ! Interpret objc/Makefile, after finishing the top makefile.
206  !
207  ON_ERROR
208    [TPU$_OPENIN]:
209      MESSAGE ("Cannot load objc/Makefile for ""ObjClib""; skipping it.");
210      RETURN;
211  ENDON_ERROR;
212
213  ERASE (makefile_buf);			!discard top Makefile
214  POSITION (END_OF (makefile_buf));
215  READ_FILE ("[.objc]Make-lang.in");	!load objc one
216  MESSAGE ("objclib");
217  pat_replace (ASCII(9), " ");		!change any <tab> to <space>
218  generate_option_file ("OBJC_O", "=", "objc-objs.opt");
219  POSITION (BEGINNING_OF (makefile_buf));
220  ! Join any continuation lines; we want the header list to be one line.
221  pat_replace ("\" & LINE_END, );
222  generate_option_file ("OBJC_H", "=", "objc-hdrs.list");
223ENDPROCEDURE; !process_objc_lib
224!!
225
226PROCEDURE configure_makefile( )
227  !
228  ! Plug in some values normally handled by `configure'.  Rather than
229  ! replacing the dummy entries, insert the real entries before them.
230  !
231  IF (GET_INFO (COMMAND_LINE, 'START_RECORD') <> 2) THEN
232    arch := 'vax';
233  ELSE
234    arch := 'alpha';
235  ENDIF;
236  POSITION (BEGINNING_OF (makefile_buf));
237  COPY_TEXT ("target=" + arch + "-vms");	SPLIT_LINE;
238  COPY_TEXT ("out_file=aux-output.c");		SPLIT_LINE;	! 'arch'/'arch'.c
239  COPY_TEXT ("out_object_file=aux-output.o");	SPLIT_LINE;	! aux-output.obj
240  COPY_TEXT ("md_file=" + arch + ".md");	SPLIT_LINE;	! 'arch'/'arch'.md
241  COPY_TEXT ("tm_file=tm.h");			SPLIT_LINE;	! 'arch'/tm-vms.h
242  pat_replace ("@" &
243    SPAN("abcdefghijklmnopqrstuvwxyz_ABCDEFGHIJKLMNOPQRSTUVWXYZ#~0123456789")
244		   & "@", );		! strip `configure' dummy values
245ENDPROCEDURE; !configure_makefile
246!!
247
248PROCEDURE identify_compilers( )
249  !
250  ! Retrieve the list of supported compilers from Makefile.in, and put them
251  ! into file "compilers.list", one per line, for subsequent access from DCL.
252  !
253  LOCAL range1;
254
255  ! Strip most comments from the makefile, to speed up subsequent processing.
256  POSITION (BEGINNING_OF (makefile_buf));
257  pat_replace (LINE_BEGIN & "#" & REMAIN & LINE_END, );
258  pat_replace ("$(exeext)", );
259  pat_replace ("@all_compilers@", );
260!#  ! Convert directory references to VMS syntax (actually, just strip it).
261!#  pat_replace (" $(srcdir)/", " ");
262  ! Look up the ``COMPILERS=cc1 xyzzy'' Makefile macro and put
263  ! its ``cc1 xyzzy'' value into the compilers buffer.
264  POSITION (BEGINNING_OF (complist_buf));
265!#--at some point we may want to add this--
266!#  recursive_fetch_tag ("CCCP", "=");	  ! Include the preprocessor.
267!#  POSITION (END_OF (complist_buf));
268  recursive_fetch_tag ("COMPILERS", "=");
269  ! Convert all spaces into newlines, then remove any blank lines.
270  pat_replace (SPAN(" "), LINE_END);
271  pat_replace (LINE_BEGIN & LINE_END, );
272ENDPROCEDURE; !identify_compilers
273!!
274
275PROCEDURE additional_compiler( cname, subdir )
276  !
277  ! Load Make-lang.in for compiler CNAME from SUBDIR and append it to the
278  ! end of Makefile.in's buffer.  Add CNAME to the "compilers.list" buffer.
279  !
280  ON_ERROR
281    ! Don't abort if user removes the supporting subdirectory for a
282    ! language she's not interested in.
283    [TPU$_OPENIN]:
284      MESSAGE ("Cannot load " + subdir + "/Make-lang.in for "
285	       + '"' + cname + '"' + "; skipping it.");
286      RETURN;
287  ENDON_ERROR;
288
289  POSITION (END_OF (makefile_buf));
290  SPLIT_LINE;	! Separate with a blank line.
291  READ_FILE ("[." + subdir + "]Make-lang.in");	! Load Makefile fragment.
292  ! Make sure that $(xxx_OTH_SRCS) expands to empty string by renaming $(it)
293  pat_replace ("_OTH_SRCS)", "_OTH_SRCS_dummy_)");
294  ! Convert subdirectory references into VMS syntax.
295  pat_replace ("$(srcdir)/" + subdir + "/", "[." + subdir + "]");
296
297    ! Temporary? hack for cp/Make-lang.in's mishandling of "input.c".
298    IF (subdir = 'cp') THEN
299      pat_replace ("[.cp]input.c", );	! Discard this text.
300    ENDIF;
301
302  ! Add this name to compilers.list.
303  POSITION (END_OF (complist_buf));
304  COPY_TEXT (cname);
305  ! Make array entry indexed by compiler's file name; its value is arbitrary.
306  extra_compilers{cname} := subdir;
307ENDPROCEDURE; !additional_compiler
308!!
309
310PROCEDURE generate_option_file( tag_name, punct, outfile_name )
311  !
312  ! Produce a file listing the names of particular object files, for use
313  ! as input to the linker and also for use in finding source names by
314  ! make-cc1.com.  Generally, any name suffix will be suppressed.
315  !
316  LOCAL range1, range2;
317
318  POSITION (BEGINNING_OF (opt_file_buf));
319  recursive_fetch_tag (tag_name, punct);
320  ! First fix up for subdirectory/Make-lang.in.
321  IF (pat_replace ("stamp-objlist" & (SPAN(" ")|LINE_END), " ") > 0) THEN
322    recursive_fetch_tag ("stamp-objlist", ":");
323  ENDIF;
324  ! Now fix up a few things in the output buffer.
325  pat_replace ("Makefile" & (SPAN(" ")|LINE_END), " ");
326!#  FILL (CURRENT_BUFFER, " ", 1, 80, 0);	! Condense things a bit.
327  pat_replace ("." & ("o"|"c"|"y") & ((SPAN(" ")&LINE_END)|LINE_END), LINE_END);
328  pat_replace ("." & ("o"|"c"|"y") & SPAN(" "), ",");
329  pat_replace (".h" & (SPAN(" ")|LINE_END), ".h,");
330  ! Remove trailing commas, if present.
331  pat_replace ("," & ((SPAN(" ")&LINE_END)|LINE_END), LINE_END);
332  ! Get rid of spaces and blank lines.
333  pat_replace (SPAN(" "), LINE_END);
334  pat_replace (LINE_BEGIN & LINE_END, );
335  ! Second fix up for subdirectory/Make-lang.in;
336  ! avoid "sticky defaults" when linker processes the resulting options file.
337  IF (extra_compilers{outfile_name - "-objs.opt"} <> TPU$K_UNSPECIFIED) THEN
338    POSITION (BEGINNING_OF (opt_file_buf));
339    range1 := CREATE_RANGE (MARK (NONE), END_OF (CURRENT_BUFFER), NONE);
340    LOOP
341      range2 := SEARCH_QUIETLY (LINE_BEGIN | ",", FORWARD, EXACT, range1);
342      EXITIF (range2 = 0);
343      POSITION (BEGINNING_OF (range2));
344      IF (CURRENT_CHARACTER = ",") THEN  MOVE_HORIZONTAL (1); ENDIF;
345      ! If it's not already "[.subdir]name", explicitly make it "[]name".
346      IF (CURRENT_CHARACTER <> "[") THEN  COPY_TEXT ("[]"); ENDIF;
347      MOVE_HORIZONTAL (1);
348      MODIFY_RANGE (range1, MARK (NONE), END_OF (range1));
349    ENDLOOP;
350  ENDIF;
351  ! Now write the output file.
352  SET (OUTPUT_FILE, opt_file_buf, outfile_name);
353  WRITE_FILE (opt_file_buf);
354  ERASE (opt_file_buf);		! Clear buffer out for next opt_file pass.
355ENDPROCEDURE; !generate_option_file
356!!
357
358PROCEDURE recursive_fetch_tag( tag_n, punct )
359  !
360  ! Look up TAG_N, copy it to OPT_FILE_BUF, and then translate any $(...)
361  ! definitions that appear.  The translation is put at the current point.
362  !
363  LOCAL mark1, mark2, range1, tag_range, tag_string;
364
365  fetch_tag (tag_n, punct);
366  ! Substitute any makefile symbols $(...).
367  POSITION (BEGINNING_OF (CURRENT_BUFFER));
368  LOOP
369    range1 := SEARCH_QUIETLY ("$(" &
370      SPAN("abcdefghijklmnopqrstuvwxyz_ABCDEFGHIJKLMNOPQRSTUVWXYZ#~0123456789")
371				   & ")", FORWARD, EXACT);
372    EXITIF (range1 = 0);
373    POSITION (BEGINNING_OF (range1));
374    MOVE_HORIZONTAL (2);	! Past opening "$(".
375    mark1 := MARK (NONE);
376    POSITION (END_OF (range1));
377    MOVE_HORIZONTAL (-1);	! In front of closing ")".
378    mark2 := MARK (NONE);
379    tag_range := CREATE_RANGE (mark1, mark2, NONE);
380    POSITION (END_OF (range1));
381    tag_string := STR (tag_range);
382    ERASE (range1);
383    fetch_tag (tag_string, "=");
384    POSITION (BEGINNING_OF (CURRENT_BUFFER));
385  ENDLOOP;
386ENDPROCEDURE; !recursive_fetch_tag
387!!
388
389PROCEDURE fetch_tag( tag_n, punct )
390  !
391  ! Looks up the translation of a tag, and inserts it at the current location
392  ! in the buffer.
393  !
394  LOCAL mark0, mark1, mark2, range2;
395
396  mark0 := MARK (NONE);     ! Remember where we started; restore before return.
397  POSITION (BEGINNING_OF (makefile_buf));
398  ! The tag definition always starts in the first column, and might have
399  ! optional space(es) before "=" or ":" punctuation.
400  range2 := SEARCH_QUIETLY (LINE_BEGIN & tag_n & ((SPAN(" ") & punct) | punct),
401			    FORWARD, EXACT);
402  IF (range2 = 0) THEN
403    POSITION (mark0);
404    RETURN;
405  ENDIF;
406  POSITION (END_OF (range2));
407  MOVE_HORIZONTAL (1);		! Move beyond "TAG=".
408  mark1 := MARK (NONE);
409  POSITION (BEGINNING_OF (range2));
410  LOOP
411    MOVE_VERTICAL (1);
412    MOVE_HORIZONTAL (-2);
413    EXITIF (CURRENT_CHARACTER <> "\");
414    ERASE_CHARACTER (1);
415    MOVE_HORIZONTAL (1);
416  ENDLOOP;
417  MOVE_HORIZONTAL (1);
418  mark2 := MARK (NONE);
419  range2 := CREATE_RANGE (mark1, mark2, NONE);
420  POSITION (mark0);
421  IF (LENGTH (range2) <> 0) THEN
422    COPY_TEXT (range2);
423  ENDIF;
424ENDPROCEDURE; !fetch_tag
425!!
426
427PROCEDURE pat_replace( oldstring, newstring )
428  !
429  ! Replace all occurrences of a pattern.
430  !
431  LOCAL range1, range2, kill_it, count;
432
433  count := 0;
434  kill_it := (GET_INFO (newstring, 'TYPE') = UNSPECIFIED);	! Omitted arg.
435  range1 := CREATE_RANGE (BEGINNING_OF (CURRENT_BUFFER),
436			  END_OF (CURRENT_BUFFER), NONE);
437  LOOP
438    range2 := SEARCH_QUIETLY (oldstring, FORWARD, EXACT, range1);
439    EXITIF (range2 = 0);
440    count := count + 1;
441    POSITION (BEGINNING_OF (range2));
442    ERASE (range2);
443    IF (newstring = LINE_END) THEN
444      SPLIT_LINE;
445    ELSE IF (NOT kill_it) THEN
446      COPY_TEXT (newstring);
447    ENDIF; ENDIF;
448    MODIFY_RANGE (range1, MARK (NONE), END_OF (range1));
449  ENDLOOP;
450  RETURN count;
451ENDPROCEDURE; !pat_replace
452!!
453
454!
455! This is the main routine.
456!
457process_makefile ();
458process_objc_lib ();	!this uses a different makefile
459QUIT;	! All done; don't write any modified buffers.
460!!
461$ echo ""
462$!
463$! Remove excessive versions of the option files...
464$!
465$ purge *.opt,*.list
466$!
467$!
468$!
469$ if f$search("config.status") .nes. "" then delete config.status.*
470$ create config.status
471$ open/append ifile$ config.status
472$ write ifile$ "Links are now set up for use with a ''arch' running VMS."
473$ close ifile$
474$ type config.status
475$ echo ""
476$!
477$ exit
478$
479$!
480$! Construct a header file based on subdirectory contents
481$!
482$make_lang_incl: subroutine
483$  if f$search(p1).nes."" then delete 'p1';*
484$  create 'p1'	!empty file with ordinary text-file attributes
485$  open/Append ifile$ 'p1'
486$  write ifile$ "/* ''p1' */"
487$  hfile = f$search("[]''p1'")
488$  topdir = f$parse(hfile,,,"DIRECTORY") - "]"
489$lang_incl_loop:
490$  hfile = f$search("[.*]lang-''p1'")
491$  if hfile.eqs."" then goto lang_incl_done
492$  dir = f$parse(hfile,,,"DIRECTORY") - "]"
493$! convert absolute path to relative one, yielding "[.subdir]"
494$  dir = "[" + f$edit(dir - topdir,"LOWERCASE") + "]"
495$  write ifile$ "#include ""''dir'lang-''p1'"""
496$  goto lang_incl_loop
497$lang_incl_done:
498$  close ifile$
499$  echo "Created `''p1''."
500$ endsubroutine !make_lang_incl
501