From:	CRDGW2::CRDGW2::MRGATE::"SMTP::CRVAX.SRI.COM::RELAY-INFO-VAX" 23-MAY-1989 10:03
To:	MRGATE::"ARISIA::EVERHART"
Subj:	Re: make utility for vms

Received: From KL.SRI.COM by CRVAX.SRI.COM with TCP; Tue, 23 MAY 89 05:38:10 PDT
Received: from ucbvax.Berkeley.EDU by KL.SRI.COM with TCP; Tue, 23 May 89 05:32:41 PDT
Received: by ucbvax.Berkeley.EDU (5.61/1.36)
	id AA12031; Tue, 23 May 89 05:02:27 -0700
Received: from USENET by ucbvax.Berkeley.EDU with netnews
	for info-vax@kl.sri.com (info-vax@kl.sri.com)
	(contact usenet@ucbvax.Berkeley.EDU if you have questions)
Date: 23 May 89 11:44:46 GMT
From: gjc@bu-cs.bu.edu  (George J. Carrette)
Organization: Boston U. Comp. Sci.
Subject: Re: make utility for vms
Message-Id: <31637@bu-cs.BU.EDU>
References: <3694@udccvax1.acs.udel.EDU>
Sender: info-vax-request@kl.sri.com
To: info-vax@kl.sri.com

Here is a make utility provided as a DCL procedure, it is small enough
so you can take it anywhere, and since it is in DCL you can use it anywhere.
Your "makefiles" will be simple .COM files, so you can use symbol
substitution, F$SEARCH, F$ELEMENT, and other useful subroutines.
I have also found that most unix "makefiles" can be converted for use
in a few minutes. Example usage:

 $ cflags = "/debug/nooptimize"
 $ lflags = "/debug"
 $ to_make foo.obj foo.c,foo.h "cc''cflags' foo"
 $ to_make foo.exe foo.obj,foo.opt "link''lflags' foo,foo.opt/opt"

"to_make.com" follows:

$! March 1, 1988. George Carrette. MiTECH Corporation. gjc@bu-it.bu.edu
$!
$! A general DCL make functionality for VMS, see the doc at the end
$! of this file.
$!
$ IF P1 .EQS. "" .and. P2 .EQS. "" .and. P3 .eqs. "" THEN GOTO DOHELP
$!
$ IF P4 .NES. "" THEN GOTO TOO_MARGS
$ s_cpu = f$getjpi("","CPUTIM")
$ s_pft = f$getjpi("","PAGEFLTS")
$ refdatep = "NO"
$ if f$extract(0,1,p1) .eqs. "@" then goto refdate
$ if f$search(p1) .eqs. "" then goto make_it
$ t = f$cvtime(f$file(p1,"RDT"))
$ goto inputs
$ refdate:
$ refdatep = "YES"
$ t = f$cvtime(f$extract(1,f$length(p1)-1,p1))
$ inputs:
$ j = 0
$ loop:
$ elem = f$element(j,",",p2)
$ if elem .eqs. "," then exit
$ if f$cvtime(f$file(elem,"RDT")) .gts. t then goto make_it
$ j = j + 1
$ goto loop
$ make_it:
$ write sys$output "''elem'%''p3'"
$! on control_y then goto abort_w_control_y
$ 'p3'
$ s_cpu = f$getjpi("","CPUTIM") - s_cpu
$ s_pft = f$getjpi("","PAGEFLTS") - s_pft
$ s_cpu_i = s_cpu/100
$ s_cpu_t = s_cpu/10
$ s_cpu_t = s_cpu_t - s_cpu_t/10*10
$ s_cpu_h = s_cpu - s_cpu/10*10
$ write sys$output -
   "''s_cpu_i'.''s_cpu_t'''s_cpu_h' cpu seconds ''s_pft' page faults"
$ exit
$ too_margs:
$ write sys$output "Too many arguments to to_make:"
$ write sys$output -
  "to_make ''p1' ''p2' ''p3' ''p4' ''p5' ''p6' ''p7' ''p8'"
$ write sys$output "The second and third arguments should be strings"
$ exit
$DOHELP:
$ ON CONTROL_Y THEN EXIT
$ TYPE/PAGE SYS$INPUT:
March 1, 1988. George Carrette. MiTECH Corporation.

 $ to_make "outputfile" "input1,input2,...,inputN" "Command-to-Execute"
 
 $ to_make "@ref_date" "input1,input2,...,inputN" "Command-to-Execute"

The objective is to be able to write a simple command procedure
for building a program, such that the commands used to
build the program and its subparts are executed only if the input files to
those commands have changed since the outputs were created or updated.

This objective is similar to that of the Unix(tm) "make" command, except
that the "make" command does *not* implement a general purpose sequential
programming language, while the "to_make" command is a convenient
procedural extension to the general purpose vms command language.

As such, "to_make" is more powerful than "make" but cannot be used to
generate a sequential set of commands from a non-sequential or declarative
set of dependencies.

A further difference is that even though unix "make" in a sense manipulates
times, it does so only through times attached to files, a "time" itself is
not an object which can be manipulated. In contrast, the "@" construct
in "to_make" allows a calculated time to be used in the dependency
calculation.

Example:
The command procedure hello.com keeps track of 3 primary input files,
hello.c, hello.h, and hello.opt.

  $ cflags = "/debug"
  $ lflags = "/debug/map"
  $ to_make hello.obj "hello.c,hello.h" -
            "cc''cflags' hello.c"
  $ to_make hello.exe "hello.obj,hello.opt" -
           "link''lflags' hello.obj,hello/opt"

The file has been formated to look somewhat like a "make" file. The first
argument to "to_make" is the output file. The second argument is the set of
input files as a string with individual files delimited by commas. The third
argument is the string which is evaluated if any of the input files are
more recent then the output file.

Hello.c:

  #include "hello.h"
  main()
  {printf("HELLO\n");exit(1);}

Hello.h:

  #include <stdio.h>

Hello.opt:

  sys$library:vaxcrtl/share


This example shows the use of the "@refdate" construct in order to update
a library file with all modules which have changed since the library
was last updated. The refdate must be computed outside the loop of course,
which is the whole point of having the "@refdate" construct.

 $ lisplib_objs == -
   "repl.obj,prims.obj,gc.obj,io_util.obj,load.obj,l_util.obj," + -
   "eval.obj,error.obj,arith.obj,subr.obj,interrupt.obj"
 $!
 $ libfile = "lisplib.olb"
 $!
 $ to_make 'libfile' 'libfile' "library/create ''libfile' ''lisplib_objs'"
 $!
 $ refdate = f$file(libfile,"RDT")
 $ j = 0
 $ loop:
 $ e = f$element(j,",",lisplib_objs)
 $ if e .eqs. "," then exit
 $ to_make "@''refdate'" 'e' "library ''libfile' ''e'"
 $ j = j + 1
 $ goto loop

