/* * b u i l d 0 . c */ #ifdef DOCUMENTATION title build Build compilation command files index Build compilation command files synopsis build -options files description Build is used to create command files for C programs and libraries. It reads the program source files to determine dependencies and writes a command file for the operating system indirect command processor. .s The following options are defined: .lm +16 .s.i-16;-a Set protection codes on the output file (program or library) so that all users may access the file. .s.i-16;-b Build (as a program) even if the "/*)BUILD" comment is not seen. .s.i-16;-d Do not delete .OBJ files after build. .s.i-16;-h header A header command file is copied to the output file before all processing. .s.i-16;-l library An object library of C programs is built. library is the (fully-qualified) name of the output file. (Note that the $(BIN) model is not appended). If unspecified, the filetype will be .OBJ for RT11 and .OLB for RSX and VAX libraries. Note that, on VAX/VMS, if you build both the RSX and native library, you must select different library names as they will generally have the same filetype. This is not available for unix. .s.i-16;-m model_file Command files are built by expanding macros in built-in model strings. The model file allows the user to specify default definitions for model strings. .s.i-16;-o output The output file is be changed from stdout to this file. .s.i-16;-s source This string is pre-pended to all source file references (and include copy operations are not commented out). .s.i-16;-t trailer A trailer command file is copied to the output file after all processing. .s.i-16;-v Verbose -- log files as they are processed. .s.i-16;-x system Specify the operating system on which the command file is to be run. If not specified, your current operating system is used. .s.lm -16 If the -x option is not specified, the output file will be built for the current operating system. The following operating systems are known: .lm +16 .s.i-16;vaxnative, vaxrsx, vax .br Vaxnative generates a command file that uses the Vax-11 C compiler only; vaxrsx (and vax) uses Decus-C only. .s.i-16;rstsrt11, rstsrsx, rsts .br RSTS defaults to rstsrt11. .s.i-16;rsxnative rt11native .br These are native-mode command files and may be abbreviated "rsx" and "rt11" respectively. .s.i-16;unix .br This generates a crude "makefile" using the $(FILE) and $(INCLUDE) definitions. Most of the capabilities of make (and build) are unavailable. This file will probably have to be edited before it can be used. .s.lm -16 When specifing an operating system, a non-ambiguous string is required. Thus, "rstsrt11" may be abbreviated to "rstsrt". .s For example, note the following examples: .s.nf build -l c:cu -s src: *.c >vxcubl.com build *.c -x rt11 >ttool.com .s.f The first builds the utility library for the current operating system, while the second builds tools for rt11 native mode. Header and trailer file format These files are written to the output file before (header) and after (trailer) the generated command files. They may be used to establish compilation defaults. C source file format To generate the command file, build reads each source file, searching for a build command. This appears as a comment (beginning in column 1) in the C source: .s.nf /*)BUILD arguments */ .s.f If a library is being built, build searches for "/*)LIBRARY". Thus libraries and programs may coexist in the same directory. .s Note that "/*)BUILD" or "/*)LIBRARY" must appear in upper-case at the beginning of a line. Also, the terminating "*/" must be the first non white-space characters on a line. .s A '#' outside of a model argument will cause the rest of the source line to be ignored, allowing comments in model strings. .s If no build arguments are given, the current file will be compiled. .s Arguments may be given to override model (or built-in) definitions. The format for an argument is as follows: .s.nf $X = Y .s.f where X may be either a single letter or a string enclosed in either parentheses or braces and Y may be either a single word or a string (which may contain blanks, newlines, etc.) bounded by braces. For example: .s.nf /*)BUILD $(PROGRAM) = kwik $(STACK) = 2000 $(FILES) = { kwik sortc } */ .s.f Within model definitions, the '$' character may appear as itself if it is doubled "$$" or followed by a blank "$ ". .s The following may be specified in build arguments or model files: .lm +16 .s.i-16;$(DTOA) This program requires the floating-point double-to-Ascii conversion routine. This should be written as: .s $(DTOA) = 1 .s $(DTOA) is ignored if unix or vax-native output is desired. .s.i-16;$(ATOF) This program requires the floating-point Ascii-to-double conversion routine. This should be written as: .s $(ATOF) = 1 .s $(ATOF) is ingored if unix or vax-native output is desired. .s.i-16;$(SRC) The account where the sources are. This overrides any -s option value. .s.i-16;$(BIN) The account where the image goes. .s.i-16;$(FILES) The list of files to be built. If not specified, the current file name is used. $(FILES) may be specified for programs and libraries. .s.i-16;$(MP) To preprocess program source files by the MP macro pre-processor, define this as: .s $(MP) = 1 .s As the MP preprocessor does not have a default filetype, the build command will append ".C" to any source file that does not have an explicit filetype. This may be overridden by providing the filetype in the $(FILES) command: .s $(FILES) = { prog.txt } .s .s.i-16;$(INCLUDE) The list of files to be included. If not specified, no include files will be copied. The copy is supressed if neither $(SRC) nor $(COPYINCLUDE) have been redefined as the file would be copied from the current disk/account to itself. These files are not deleted after compilation, even if they were copied. $(INCLUDE) may be specified for programs or libraries. .s.i-16;$(PROGRAM) The name of the program image to be generated. .s.i-16;$(STACK) A value for the RT11 /B[OTTOM] link specifier. If not specified, "$(STACK) = 2000" will be used. Note that the RSX task-builder STACK option is specified by the $(TKBOPTIONS) specifier below. .s.i-16;$(TKBOPTIONS) RSX task builder options (stack, units, task name, etc.) are specified by this argument as follows: .s.nf $(TKBOPTIONS) = { STACK = 1500 TASK = ...FOO ; ... etc } .f .s.i-16;$(OBJS) A string naming the actual object files. If specified, it overrides the default use of the files just compiled. .s.i-16;$(LIBS) A string naming additional libraries to be searched (before searching the C runtime library). .s.i-16;$(UTLIB) A user-specified utility library; appended to all link strings, but unspecified by BUILD. .s.i-16;$(DECUS_LIB) On native Vax-11C, the library "C:VAXLIB/LIB" which contains interface routines for Decus-C tools. .s.i-16;$(SUPORT) The RT11 runtime support routine: "C:SUPORT.OBJ". .s.i-16;$(??LIB) The C runtime library: .s.i -12;$(VXLIB) The VAX/VMS native runtime library, by default "SYS$LIBRARY:CRTLIB/LIB" .s.i -12;$(RXLIB) The RSX runtime library. The default depends on the operating system: on VAX/VMS and RSTS, it is "C:C/LB", while on native RSX-11M, it is "LB:[1,1]C/LB". .s.i -12;$(RTLIB) The RT11 runtime library. The default is "C:SUPORT,C:CLIB". .s.i-16;$(ODL) = {...} An RSX overlay description. If specified, a temporary file will be created (and subsequently deleted) containing a configured overlay file. Note that you should reference the run-time library by using $(RXLIB) to obtain the correct library designation. If $(ODL) is specified, $(OBJS) is ignored and $(LIBS) and $(RXLIB) will be processed only if present in the $(ODL) model. For example: .s.nf $(ODL) = { .ROOT MAIN1-MAIN2-$(RXLIB)-*(OV1,OV2) ; OV1: .FCTR SUB1-SUB1L SUB1L: .FCTR $(RXLIB):FWILD:FGETNA:RTIME ; OV2: .FCTR SUB2-SUB2L SUB2L: .FCTR $(RXLIB):ASL$$LI # (asl$li) ; .END } .s.f Note the use of $(RXLIB):XXX to select modules from the C library and the doubling of '$' in referencing subroutine ASL$LI. .s.i-16;$(OVR) = {...} An RT11 overlay description. If specified, $(OBJS) is ignored. For example: .s.nf $(OVR) = { root1,root2,$(SUPORT),$(RTLIB) over1/o:1 over2/o:2 } .f .s.i-16;$(COMMENT) A string that will comment a command line for the target operating system. .s.i-16;$(PREFIX) This model is expanded at the start of every compilation. The default is a comment in a format suitable for the particular operating system. .s.i-16;$(POSTFIX) This model is expanded after every program build. On VAX/VMS, the default defines the program as an external command. On other systems, the default does nothing. .s.i-16;$(FIRST) This model is expanded before the first program is built. By default, it does nothing. It may be defined by a user-specified model file. .s.i-16;$(LAST) This model is expanded after the last program is built. By default, it does nothing. It may be defined by a user-specified model file. .s.lm -16 For example, .s.nf /*)BUILD */ .s.f This is a "normal" build for e.g., grep or echo, signalling build that this file is a program, rather than a subroutine. .s.nf /*)BUILD $(PROGRAM) = xrf $(INCLUDE) = xrf.h $(FILES) = { xrf0 xrf1 xrf2 xrf3 xrfi xrfd } $(TKBOPTIONS) = { TASK = ...XRF } $(ODL) = { .ROOT XRF0-XRF2-XRFD-$(RXLIB)-*(X1,X2,X3) ; X1: .FCTR XRFI-X1L X1L: .FCTR $(RXLIB):CONCAT:CTIME:FWILD ; X2: .FCTR XRF1-X2L X2L: .FCTR $(RXLIB):ASL$$I ; X3: .FCTR XRF3-X3L X3L: .FCTR $(RXLIB):CPYSTR .END } $(OVR) = { xrf0,xrf2,xrfd,c:suport,c:clib xrfi,c:clib/o:1 xrf1,c:clib/o:1 xrf3,c:clib/o:1 } */ .s.f This slightly more complex build shows specification of an include file, the creation of a program whose name is different from its component files, task-builder options, and overlay files, including library module selection. .s.nf /*)LIBRARY $(INCLUDE) = chrtab.h */ .s.f This library build file shows the naming of an include file. Model file format Model files consist of strings of macros and their definitions. Each definition is separated by one or more blanks, tabs, or newlines. Definitions are in the same format as their )BUILD parameter counterparts. A model will (re)define defaults for the entire build. For example, the model file: .s.nf $(SRC) = DK1:[6,1] # source files $(BIN) = SY:[1,3] # image output .s.f Causes all program source to be taken from DK1:[6,1] and all compiled programs to be written to SY:[1,3]. .s Model file definitions replace operating-system specific defaults. Anything more elaborate than redefinition of, say, $(SRC) or $(BIN), will probably require understanding of the inner logic of the build program. You should be especially cautious of changing a link or library build string. bugs It will never replace make. It's not supposed to, anyways. The problem that build was written to solve is the extraordinary proliferation of tiny files -- each tool program requiring five or six command files: one or two for each operating system. author Martin Minow #endif /*)BUILD $(PROGRAM) = build $(INCLUDE) = build.h $(FILES) = { build0 build1 build2 build3 build4 build5 } $(STACK) = 4000 # the program is recursive $(TKBOPTIONS) = { TASK = ...BUI STACK = 2000 } */ #include #include "build.h" int debug = FALSE; int allow = FALSE; /* -a allow access */ int verbose = FALSE; /* -v verbosity */ int profile = FALSE; /* -p profile compile */ int build = FALSE; /* -b build anyways */ int delete = FALSE; /* -d don't delete .obj */ char *src_name = NULL; /* -s filename */ char *lib_name = NULL; /* -l library file */ char *out_name = NULL; /* -o output .com file */ char *opsys_name = NULL; /* -x operating system */ char *hdr_name = NULL; /* -h header file */ char *trail_name = NULL; /* -t trailer file */ char *model_name = NULL; /* -m model file */ char work[WORKSIZE]; char inline[INLINESIZE]; int mpinstall = FALSE; int opsys; /* Gets base operating system */ /* VAX, RSX, RT11, RSTS */ int op_type; /* Gets build "flavor" */ /* VNATIVE, etc. */ main(argc, argv) int argc; char *argv[]; /* * Here we go */ { #ifndef vms my_free = malloc(1); /* For myrealloc() */ #endif getopsys(); /* Base operating system */ settime(); /* Time of day */ getargs(argc, argv); /* Parse arg list */ if (out_name != NULL) { /* if -o option given */ if (freopen(out_name, "w", stdout) == NULL) { fatal("can't create -o file", out_name); } } opmatch(opsys_name); /* Check for -x options */ define(comm_model); /* Common model strings */ define(op_base[opsys], 0); /* Opsys we're running under */ define(op_model[op_type], 0); /* Opsys flavor for vax or rsts */ if (profile) { /* If -p option given */ sysave("RSXP", "-p", 0); syset("RT11P", "/p", 0); } if (src_name != NULL) { /* If -s option given */ sysave("SRC", src_name, 0); } if (allow) { sysave("ALLOWEXECUTE", "$(EXECUTABLE)"); sysave("ALLOWREAD", "$(READABLE)"); } setmodel(); /* If -m option given */ if (delete) syset("DELCOMMENT", "$(COMMENT)"); syperm(); /* Permantize the options */ if (debug) sydump(); docopy(hdr_name); /* If -h option given */ doprog(argc, argv, lib_name != NULL); /* Do the work */ docopy(trail_name); /* If -t option given */ #ifdef CHECKALLOC if (verbose || debug) fprintf(stderr, "%u bytes in free storage\n", hwmallo); #endif } setmodel() /* * Process model file */ { register FILE *fd; char *model; if ((fd = myfopen(model_name, "r")) == NULL) return; model = savest(""); while (getline(fd) != NULL) { model = csavest(model, inline); } fclose(fd); define(model, MODEL); myfree(model); } docopy(name) char *name; /* * Copy the named file */ { register FILE *fd; if ((fd = myfopen(name, "r")) != NULL) { while (getline(fd) != NULL) fputs(inline, stdout); fclose(fd); } } settime() /* * Store the time of day */ { register char *tp; extern char *ctime(); extern long time(); long tbuf; time(&tbuf); tp = ctime(&tbuf); tp[24] = EOS; syset("DATE", savest(tp), 0); } getopsys() /* * Sets the opsys variable */ { #ifdef rt11 extern int $$rsts; op_type = ($$rsts) ? RSTSRT : RT11NATIVE; #else #ifdef rsx extern int $$rsts; extern int $$vms; op_type = ($$rsts) ? RSTSRSX : ($$vms) ? VRSX : RSXNATIVE; #else #ifdef vms op_type = VNATIVE; #else #ifdef unix op_type = UNIXNATIVE; #else fprintf(stderr, "Don't know the operating system, default to vms\n"); op_type = VNATIVE; #endif #endif #endif #endif } static OPCODE optable[] = { { "vaxnative", 4, VNATIVE }, { "vaxrsx", 4, VRSX }, { "vax", 3, VRSX }, { "rsxnative", 3, RSXNATIVE }, { "rstsrsx", 6, RSTSRSX }, { "rstsrt11", 6, RSTSRT }, { "rsts", 4, RSTSRT }, { "rt11native", 4, RT11NATIVE }, { "unix", 4, UNIXNATIVE }, { NULL, 0, NONE }, }; static char typetable[] = { /* Maps op_type onto opsys */ /* NONE VNATIVE VRSX RSX RSTSRSX RSTSRT RT11 UNATIVE */ NONE, VAX, VAX, RSX, RSTS, RSTS, RT11, UNIX, }; opmatch(string) char *string; /* What to look for */ /* * Search the opcode table for a string that matches. If found, set * op_type and opsys. */ { register OPCODE *tp; if (string != NULL) { for (tp = optable; tp->o_name != NULL; tp++) { if (mmatch(string, tp->o_name, tp->o_minimum)) { op_type = tp->o_value & 0377; goto gotcha; } } fprintf(stderr, "?No operating system match for \"%s\"\n", string); } gotcha: opsys = typetable[op_type]; } struct flags { int fl_byte; /* Match this byte */ int *fl_value; /* Flag to increment */ }; struct flags simple_flag[] = { { 'a', &allow }, { 'b', &build }, { 'd', &delete }, { '?', &debug }, { 'p', &profile }, { 'v', &verbose }, { EOS, NULL }, }; struct flags name_flag[] = { { 'h', &hdr_name }, { 'l', &lib_name }, { 'm', &model_name }, { 'o', &out_name }, { 's', &src_name }, { 't', &trail_name }, { 'x', &opsys_name }, { EOS, NULL }, }; int getargs(argc, argv) int argc; char *argv[]; /* * Process the argument vector, setting global flags. * On return, entries in argv[] that have been processed have * been NULLified. * * Return TRUE on errors. */ { register char *ap; register char c; register struct flags *fl; int i; int flag; flag = FALSE; /* * mmatch wants lowercase */ for (i = 1; i < argc; i++) { for (ap = argv[i]; *ap != EOS; ap++) *ap = tolower(*ap); } for (i = 1; i < argc; i++) { ap = argv[i]; if ((c = *ap++) != '-') { #ifdef vms /* * Vms (currently) does not support * file redirection, so... */ if (c == '>') { if (*ap == '>') { if (freopen(++ap, "a", stdout) == NULL) { perror(ap); fatal("Can't append to stdout", ap); } } else { if (freopen(ap, "w", stdout) == NULL) { perror(ap); fatal("Can't create stdout", ap); } } argv[i] = NULL; } #endif continue; } /* * -[options] */ argv[i] = NULL; while ((c = tolower(*ap++)) != EOS) { fl = simple_flag; while (fl->fl_byte != EOS && fl->fl_byte != c) fl++; if (fl->fl_byte != EOS) { ++(*fl->fl_value); /* Set the flag */ } else if (++i >= argc || argv[i][0] == '-') { fprintf(stderr, "?No argument after '%c'\n", c); flag = TRUE; --i; } else { fl = name_flag; while (fl->fl_byte != EOS && fl->fl_byte != c) fl++; if (fl->fl_byte != EOS) { *((char **)(fl->fl_value)) = argv[i]; argv[i] = NULL; } else { fprintf(stderr, "?Illegal option '%c'\n", c); } } } } return (flag); } #ifdef unix /* * Unix doesn't support fwild. So we fake it. fwild_state has the * following values. * 0 before calling fwild * 1 after calling fwild, before calling fnext * 2 after first call of fnext. */ static int fwild_state = 0; FILE * fwild(name, mode) char *name; char *mode; { register FILE *fd; if (fwild_state != 0) { fprintf(stderr, "bug, fwild_state = %d\n", fwild_state); return (NULL); } if ((fd = fopen(name, mode) != NULL) fwild_state++; return (fd); } FILE * fnext(fd) register FILE *fd; { switch (fwild_state) { case 1: /* Just opened file */ fwild_state++; return (fd); case 2: /* Just processed file */ fclose (fd); fwild_state = 0; return (NULL); default: fprintf(stderr, "fnext bug, fwild_state = %d\n", fwild_state); fwild_state = 0; return (NULL); } } #endif