DEADSOFTWARE

cpmake: make commonly used options shorter with help update
[cpc.git] / src / generic / Dsw / Mod / MakeMain.cp
1 MODULE DswMakeMain;
3 IMPORT Kernel, Files, Log, Strings, DswOpts, DswProcs, DswDocuments, DevCPM, DevCPT, DevCPR, DevCPS;
5 CONST
6 version = "0.3";
8 modDir = "Mod";
9 sysDir = "System";
11 maxImps = 127;
12 maxJobs = maxImps;
14 (* symbol values *)
15 null = 0; times = 1; slash = 2; div = 3; mod = 4;
16 and = 5; plus = 6; minus = 7; or = 8; eql = 9;
17 neq = 10; lss = 11; leq = 12; gtr = 13; geq = 14;
18 in = 15; is = 16; arrow = 17; dollar = 18; period = 19;
19 comma = 20; colon = 21; upto = 22; rparen = 23; rbrak = 24;
20 rbrace = 25; of = 26; then = 27; do = 28; to = 29;
21 by = 30; not = 33;
22 lparen = 40; lbrak = 41; lbrace = 42; becomes = 44;
23 number = 45; nil = 46; string = 47; ident = 48; semicolon = 49;
24 bar = 50; end = 51; else = 52; elsif = 53; until = 54;
25 if = 55; case = 56; while = 57; repeat = 58; for = 59;
26 loop = 60; with = 61; exit = 62; return = 63; array = 64;
27 record = 65; pointer = 66; begin = 67; const = 68; type = 69;
28 var = 70; out = 71; procedure = 72; close = 73; import = 74;
29 module = 75; eof = 76;
31 (* module state flags *)
32 imported = 0; trace = 1; hasObj = 2; hasSym = 3; hasErrors = 4; library = 5;
34 (* procesor types *)
35 anymach = 0; cmach = 1; mach386 = 10; mach68k = 20;
37 (* operation system types *)
38 anyos = 0; linux = 1; freebsd = 2; openbsd = 3; win32 = 4; cygwin = 5; darwin = 6;
40 (* compiler types *)
41 anycp = 0; cpnative = 1; cpfront = 2;
43 (* internal linker types *)
44 anyint = 0; dev2 = 1;
46 debugImport = FALSE;
47 debugOrder = FALSE;
48 debugJobs = FALSE;
49 debugArgs = FALSE;
51 TYPE
52 String = POINTER TO ARRAY OF CHAR;
53 StringList = POINTER TO ARRAY OF String;
55 Selector = POINTER TO RECORD
56 name: DevCPT.Name;
57 value: BOOLEAN;
58 next: Selector
59 END;
61 Module = POINTER TO RECORD
62 name: DevCPT.Name;
63 odc: Files.Name;
64 depth: INTEGER; (* 0: leaf, MAX: root *)
65 dir: DevCPM.Directory;
66 mno: INTEGER;
67 imp: ARRAY maxImps OF Module;
68 flags: SET;
69 worker: DswProcs.Process;
70 END;
72 VAR
73 werr, err: INTEGER;
74 mno, rno: INTEGER; (* num modules *)
75 modList, lnkList, cmpList: ARRAY maxImps OF Module;
76 def: Selector; (* with head, global list of selectors *)
77 processor, compiler, os, linker: INTEGER;
78 cpcExe, cplExe: String;
79 cpcArgs, cplArgs: StringList;
80 dirList: DevCPM.Directory;
81 auto: BOOLEAN;
82 trap: BOOLEAN;
83 jobs: INTEGER;
84 exe: String;
85 printCompileModList: BOOLEAN;
86 printLinkModList: BOOLEAN;
87 printCompileFileList: BOOLEAN;
89 PROCEDURE Error (e: INTEGER; IN p0, p1: ARRAY OF CHAR; i2: INTEGER);
90 VAR msg, p2: ARRAY 128 OF CHAR;
91 BEGIN
92 CASE e OF
93 | 0: msg := "option -D expect + or - after identifier"
94 | 1: msg := "option -D expect identifier"
95 | 2: msg := "option -U expect identifier" (* rm *)
96 | 3: msg := "invalid module name"
97 | 4: msg := "invalid integer value"
98 | 5: msg := "unterminated string"
99 | 6: msg := "unknown processor ^0"
100 | 7: msg := "unknown os ^0"
101 | 8: msg := "unknown compiler ^0"
102 | 9: msg := "unknown linker ^0"
103 | 10: msg := "missing argument for option ^0"
104 | 11: msg := "unknown option ^0"
105 | 12: msg := "compiler not selected (use option -g<compiler>)"
106 | 13: msg := "processor not selected (use option -m<processor>)"
107 | 14: msg := "selected processor not supported by native compiler"
108 | 15: msg := "internal linker not required for cpfront"
109 | 16: msg := "cpfront can't produce executable file"
110 | 17: msg := "linker not selected (use option -i<linker>)"
111 | 18: msg := "os not selected (use option -s<system>)"
112 | 19: msg := "specified empty file name"
113 | 20: msg := "recursive import of ^0 in ^1"
114 | 21: msg := "unable to open module ^1"
115 | 22: msg := "linker terminated with code ^2"
116 | 23: msg := "unable to execute linker"
117 | 24: msg := "trap occured"
118 | 25: msg := "compiler not installed (use option -Xg<path> to select executable)"
119 | 26: msg := "linker not installed (use option -Xi<path> to select executable)"
120 ELSE
121 Strings.IntToString(err, msg)
122 END;
123 Strings.IntToString(i2, p2);
124 Log.String(Kernel.argv[0]$); Log.String(": ");
125 Log.ParamMsg(msg, p0, p1, p2); Log.Ln;
126 INC(err);
127 IF trap THEN
128 HALT(100)
129 END
130 END Error;
132 (* --------- options --------- *)
134 PROCEDURE IdentLen (IN s: ARRAY OF CHAR): INTEGER;
135 VAR i: INTEGER;
136 BEGIN
137 i := 0;
138 IF Strings.IsIdentStart(s[0]) THEN
139 REPEAT INC(i) UNTIL ~Strings.IsIdent(s[i])
140 END;
141 RETURN i
142 END IdentLen;
144 PROCEDURE Define (n: ARRAY OF CHAR; overwrite: BOOLEAN);
145 VAR i: INTEGER; v: BOOLEAN; s: Selector;
146 BEGIN
147 i := IdentLen(n);
148 IF i # 0 THEN
149 IF ~((n[i] = 0X) OR (((n[i] = "+") OR (n[i] = "-")) & (n[i + 1] = 0X))) THEN
150 Error(0, "", "", 0)
151 END;
152 v := n[i] # "-"; n[i] := 0X; s := def;
153 WHILE (s.next # NIL) & (s.next.name$ # n$) DO s := s.next END;
154 IF s.next = NIL THEN
155 NEW(s.next);
156 Strings.StringToUtf8(n, s.next.name, i);
157 ASSERT(i = 0);
158 s.next.value := v
159 ELSIF overwrite THEN
160 s.next.value := v
161 END
162 ELSE
163 Error(1, "", "", 0)
164 END
165 END Define;
167 PROCEDURE AddModule (IN n: ARRAY OF CHAR; selectors: Selector; dir: DevCPM.Directory);
168 VAR i, res: INTEGER; m: Module;
169 BEGIN
170 i := IdentLen(n);
171 IF (i # 0) & (n[i] = 0X) THEN
172 i := 0;
173 WHILE (i < mno) & (modList[i].name$ # n$) DO INC(i) END;
174 IF i >= mno THEN
175 NEW(m);
176 Strings.StringToUtf8(n, m.name, res);
177 ASSERT(res = 0);
178 m.dir := dir;
179 modList[i] := m;
180 INC(mno)
181 END
182 ELSE
183 Error(3, "", "", 0)
184 END
185 END AddModule;
187 PROCEDURE StrToInt (IN s: ARRAY OF CHAR; def: INTEGER): INTEGER;
188 VAR x, res: INTEGER;
189 BEGIN
190 Strings.StringToInt(s, x, res);
191 IF res # 0 THEN
192 Error(4, s, "", 0);
193 x := def
194 END;
195 RETURN x
196 END StrToInt;
198 PROCEDURE NewStr (IN s: ARRAY OF CHAR): String;
199 VAR p: String;
200 BEGIN
201 NEW(p, LEN(s$) + 1); p^ := s$;
202 RETURN p
203 END NewStr;
205 PROCEDURE ToStringList (IN s: ARRAY OF CHAR): StringList;
206 VAR i: INTEGER; ch, term: CHAR; pars: StringList;
208 PROCEDURE AddChar (c: CHAR);
209 VAR i, n, len: INTEGER; str: String;
210 BEGIN
211 IF pars = NIL THEN
212 NEW(pars, 1); NEW(pars[0], 2); pars[0, 0] := c
213 ELSE
214 n := LEN(pars) - 1;
215 len := LEN(pars[n]$);
216 NEW(str, len + 2);
217 FOR i := 0 TO len - 1 DO
218 str[i] := pars[n, i]
219 END;
220 str[i] := c;
221 pars[n] := str
222 END
223 END AddChar;
225 PROCEDURE AddLine;
226 VAR i, len: INTEGER; p: StringList;
227 BEGIN
228 IF pars = NIL THEN
229 NEW(pars, 1); i := 0;
230 ELSE
231 len := LEN(pars);
232 NEW(p, len + 1);
233 FOR i := 0 TO len - 1 DO
234 p[i] := pars[i]
235 END;
236 pars := p
237 END;
238 NEW(pars[i], 1)
239 END AddLine;
241 BEGIN
242 i := 0;
243 REPEAT ch := s[i]; INC(i) UNTIL ch # " ";
244 WHILE ch # 0X DO
245 CASE ch OF
246 | '"', "'":
247 term := ch; ch := s[i]; INC(i);
248 WHILE (ch # term) & (ch # 0X) DO
249 AddChar(ch); ch := s[i]; INC(i)
250 END;
251 IF ch # 0X THEN ch := s[i]; INC(i)
252 ELSE Error(5, "", "", 0)
253 END
254 | " ":
255 REPEAT ch := s[i]; INC(i) UNTIL ch # " ";
256 IF ch # 0X THEN AddLine END
257 ELSE
258 AddChar(ch); ch := s[i]; INC(i)
259 END
260 END;
261 RETURN pars
262 END ToStringList;
264 PROCEDURE Help;
265 BEGIN
266 Log.String("Usage: cpmake [options] module..."); Log.Ln;
267 Log.String("Options:"); Log.Ln;
268 Log.String(" -a Enable automatic dependency resolution"); Log.Ln;
269 Log.String(" -Cg params Pass parameters to Component Pasacal compiler directly"); Log.Ln;
270 Log.String(" -Ci params Pass parameters to internal linker directly"); Log.Ln;
271 Log.String(' -D ident["+"|"-"] Add preprocessor selector'); Log.Ln;
272 Log.String(" -g compiler Specify Component Pascal compiler"); Log.Ln;
273 Log.String(" cpfront BlackBox based C code translator"); Log.Ln;
274 Log.String(" native BlackBox based native code compiler"); Log.Ln;
275 Log.String(" -h Print help and quit"); Log.Ln;
276 Log.String(" -i linker Specify internal linker (native only)"); Log.Ln;
277 Log.String(" dev2 Dev2 based ELF/PE linker"); Log.Ln;
278 Log.String(" -II Trap on user interrupt (debug)"); Log.Ln;
279 Log.String(" -IT Trap on first error (debug)"); Log.Ln;
280 Log.String(" -IC Print module list for compilation and quit"); Log.Ln;
281 Log.String(" -IL Print module list for linking and quit"); Log.Ln;
282 Log.String(" -Ic Print file list for compilation and quit"); Log.Ln;
283 Log.String(" -j num Specifies the number of jobs to run simultaneously"); Log.Ln;
284 Log.String(" -m cpu Generate code for specified processor"); Log.Ln;
285 Log.String(" none Unknown processor (cpfront only)"); Log.Ln;
286 Log.String(" 486 Intel 486+"); Log.Ln;
287 Log.String(" -o name Generate executable file (native only)"); Log.Ln;
288 Log.String(" -s os Generate code for specified operation system"); Log.Ln;
289 Log.String(" none Unknown operation system"); Log.Ln;
290 Log.String(" freebsd FreeBSD"); Log.Ln;
291 Log.String(" linux Linux"); Log.Ln;
292 Log.String(" openbsd OpenBSD"); Log.Ln;
293 Log.String(" win32 Windows"); Log.Ln;
294 Log.String(" -V Print version and quit"); Log.Ln;
295 Log.String(" -Xp path Use executable file for Component Pascal compiler"); Log.Ln;
296 Log.String(" -Xi path Use executable file for internal linker (native only)"); Log.Ln;
297 Kernel.Quit(1)
298 END Help;
300 PROCEDURE Version;
301 BEGIN
302 Log.String(version); Log.Ln;
303 Kernel.Quit(0)
304 END Version;
306 PROCEDURE ParseCommandOpts;
307 BEGIN
308 CASE DswOpts.GetOpt("g:i:") OF
309 | "g": cpcArgs := ToStringList(DswOpts.str);
310 | "i": cplArgs := ToStringList(DswOpts.str);
311 | ":": Error(10, "-C" + DswOpts.str, "", 0)
312 | "?": Error(11, "-C" + DswOpts.str, "", 0)
313 | 0X: Error(11, "-C", "", 0)
314 END
315 END ParseCommandOpts;
317 PROCEDURE ParseExternalOpts;
318 BEGIN
319 CASE DswOpts.GetOpt("g:i:") OF
320 | "g": cpcExe := DswOpts.str;
321 | "i": cplExe := DswOpts.str;
322 | ":": Error(10, "-X" + DswOpts.str, "", 0)
323 | "?": Error(11, "-X" + DswOpts.str, "", 0)
324 | 0X: Error(11, "-X", "", 0)
325 END
326 END ParseExternalOpts;
328 PROCEDURE ParseInfoOpts;
329 BEGIN
330 CASE DswOpts.GetOpt("CLcIT") OF
331 | "T": trap := TRUE
332 | "I": Kernel.intTrap := TRUE
333 | "C": printCompileModList := TRUE
334 | "L": printLinkModList := TRUE
335 | "c": printCompileFileList := TRUE
336 | ":": Error(10, "-I" + DswOpts.str, "", 0)
337 | "?": Error(11, "-I" + DswOpts.str, "", 0)
338 | 0X: Error(11, "-I", "", 0)
339 END
340 END ParseInfoOpts;
342 PROCEDURE ParseFileOpts;
343 VAR d: DevCPM.Directory;
344 BEGIN
345 CASE DswOpts.GetOpt("p:") OF
346 | "p": NEW(d); d.path := DswOpts.str$; d.legacy := TRUE; d.next := dirList; dirList := d
347 | ":": Error(10, "-F" + DswOpts.str, "", 0)
348 | "?": Error(11, "-F" + DswOpts.str, "", 0)
349 | 0X: Error(11, "-F", "", 0)
350 END
351 END ParseFileOpts;
353 PROCEDURE ParseArgs;
354 VAR s: String;
355 BEGIN
356 exe := NIL; auto := FALSE; jobs := 1; def.next := NIL; mno := 0; rno := 0;
357 processor := anymach; os := anyos; compiler := anycp;
358 LOOP
359 CASE DswOpts.GetOpt("ao:j:D:m:s:g:i:TCXIFhV") OF
360 | "a": auto := TRUE
361 | "o": exe := DswOpts.str
362 | "j": jobs := MIN(MAX(StrToInt(DswOpts.str, 1), 1), maxJobs)
363 | "m":
364 s := DswOpts.str;
365 Strings.ToLower(s, s);
366 IF s$ = "none" THEN processor := anymach
367 ELSIF s$ = "486" THEN processor := mach386
368 ELSIF s$ = "68k" THEN processor := mach68k
369 ELSE Error(6, s, "", 0)
370 END
371 | "s":
372 s := DswOpts.str;
373 Strings.ToLower(s, s);
374 IF s$ = "none" THEN os := anyos
375 ELSIF s$ = "linux" THEN os := linux
376 ELSIF s$ = "freebsd" THEN os := freebsd
377 ELSIF s$ = "openbsd" THEN os := openbsd
378 ELSIF s$ = "win32" THEN os := win32
379 ELSIF s$ = "cygwin" THEN os := cygwin
380 ELSIF s$ = "darwin" THEN os := darwin
381 ELSE Error(7, s, "", 0)
382 END
383 | "g":
384 s := DswOpts.str;
385 Strings.ToLower(s, s);
386 IF s$ = "native" THEN compiler := cpnative
387 ELSIF s$ = "cpfront" THEN compiler := cpfront
388 ELSE Error(8, s, "", 0)
389 END
390 | "i":
391 s := DswOpts.str;
392 Strings.ToLower(s, s);
393 IF s$ = "dev2" THEN linker := dev2
394 ELSE Error(9, s, "", 0)
395 END
396 | "h": Help
397 | "V": Version
398 | "D": Define(DswOpts.str, TRUE)
399 | "C": ParseCommandOpts
400 | "X": ParseExternalOpts
401 | "I": ParseInfoOpts
402 | "F": ParseFileOpts
403 | ":": Error(10, "-" + DswOpts.str, "", 0)
404 | "?": Error(11, "-" + DswOpts.str, "", 0)
405 | "$": AddModule(DswOpts.str, def, dirList)
406 | 0X: EXIT
407 END
408 END;
409 END ParseArgs;
411 PROCEDURE CheckParams;
413 PROCEDURE Default (IN name: ARRAY OF CHAR; value: BOOLEAN);
414 BEGIN
415 IF value = TRUE THEN
416 Define(name + "+", FALSE)
417 ELSE
418 Define(name + "-", FALSE)
419 END
420 END Default;
422 BEGIN
423 IF compiler = anycp THEN
424 Error(12, "", "", 0)
425 ELSIF compiler = cpnative THEN
426 IF processor = anymach THEN
427 Error(13, "", "", 0)
428 ELSIF processor # mach386 THEN
429 Error(14, "", "", 0)
430 END
431 END;
432 IF (compiler = cpfront) & (linker # anyint) THEN
433 Error(15, "", "", 0)
434 END;
435 IF (compiler = cpfront) & (exe # NIL) THEN
436 Error(16, "", "", 0)
437 END;
438 IF (exe # NIL) & (compiler = cpnative) & (linker = anyint) THEN
439 Error(17, "", "", 0)
440 END;
441 IF (linker = dev2) & (os = anyos) THEN
442 Error(18, "", "", 0)
443 END;
444 IF (exe # NIL) & (exe^ = "") THEN
445 Error(19, "", "", 0)
446 END;
447 IF (cpcExe = NIL) & (compiler # anycp) THEN
448 IF compiler = cpnative THEN cpcExe := DswProcs.dir.GetPath("cpc486")
449 ELSIF compiler = cpfront THEN cpcExe := DswProcs.dir.GetPath("cpfront")
450 END;
451 IF cpcExe = NIL THEN
452 Error(25, "", "", 0)
453 END
454 END;
455 IF (cplExe = NIL) & (linker # anyint) THEN
456 cplExe := DswProcs.dir.GetPath("cpl486");
457 IF cplExe = NIL THEN
458 Error(26, "", "", 0)
459 END
460 END;
461 (* cpompiler *)
462 Default("NATIVE", compiler = cpnative);
463 Default("CPFRONT", compiler = cpfront);
464 (* processor *)
465 Default("I486", processor = mach386);
466 Default("I386", processor = mach386);
467 Default("M68K", processor = mach68k);
468 (* operating system *)
469 Default("LINUX", os = linux);
470 Default("FREEBSD", os = freebsd);
471 Default("OPENBSD", os = openbsd);
472 Default("DARWIN", os = darwin);
473 Default("WIN32", os = win32);
474 Default("CYGWIN", os = cygwin);
475 Default("POSIX", os IN {linux, freebsd, openbsd, darwin, cygwin});
476 (* linker *)
477 Default("DEV2", linker = dev2);
478 END CheckParams;
480 (* --------- loader --------- *)
482 PROCEDURE Import (m: Module; IN name: DevCPT.Name);
483 VAR i, j: INTEGER; imp: Module;
484 BEGIN
485 ASSERT(m # NIL, 20);
486 ASSERT(name # "", 21);
487 IF debugImport THEN Log.String(" import "); Log.String(name$) END;
488 IF name = "SYSTEM" THEN INCL(DevCPM.options, DevCPM.sysImp)
489 ELSIF name = "COM" THEN INCL(DevCPM.options, DevCPM.com)
490 ELSIF name = "JAVA" THEN INCL(DevCPM.options, DevCPM.java)
491 ELSE
492 IF debugImport THEN Log.Char(" ") END;
493 i := 0; (* find module in local list *)
494 WHILE (i < m.mno) & (m.imp[i].name$ # name$) DO INC(i) END;
495 IF i >= m.mno THEN
496 j := 0; (* find module in global list *)
497 WHILE (j < mno) & (modList[j].name$ # name$) DO INC(j) END;
498 IF j >= mno THEN
499 IF ~auto THEN
500 Log.String("module " + name + " required before " + m.name); Log.Ln; INC(werr)
501 END;
502 NEW(imp); imp.name := name$;
503 modList[mno] := imp; INC(mno)
504 ELSE
505 imp := modList[j]
506 END;
507 m.imp[m.mno] := imp; INC(m.mno)
508 ELSE DevCPM.err(1)
509 END
510 END;
511 IF debugImport THEN Log.Ln END;
512 END Import;
514 PROCEDURE ParseModule (m: Module);
515 VAR sym: BYTE; SelfName, impName, aliasName: DevCPT.Name;
517 PROCEDURE err (n: SHORTINT);
518 BEGIN DevCPM.err(n)
519 END err;
521 PROCEDURE CheckSym(s: SHORTINT);
522 BEGIN
523 IF sym = s THEN DevCPS.Get(sym) ELSE DevCPM.err(s) END
524 END CheckSym;
526 BEGIN
527 IF debugImport THEN Log.String("module " + m.name); Log.Ln END;
528 DevCPS.Init; DevCPS.Get(sym);
529 IF sym = module THEN DevCPS.Get(sym) ELSE err(16) END;
530 IF sym = ident THEN
531 SelfName := DevCPS.name$; DevCPS.Get(sym);
532 IF sym = lbrak THEN
533 INCL(DevCPM.options, DevCPM.interface); DevCPS.Get(sym);
534 IF sym = eql THEN DevCPS.Get(sym)
535 ELSE INCL(DevCPM.options, DevCPM.noCode)
536 END;
537 IF sym = string THEN INCL(m.flags, library); DevCPS.Get(sym)
538 ELSE err(string)
539 END;
540 CheckSym(rbrak)
541 END;
542 CheckSym(semicolon);
543 IF sym = import THEN DevCPS.Get(sym);
544 LOOP
545 IF sym = ident THEN
546 aliasName := DevCPS.name$; impName := aliasName$; DevCPS.Get(sym);
547 IF sym = becomes THEN DevCPS.Get(sym);
548 IF sym = ident THEN impName := DevCPS.name$; DevCPS.Get(sym) ELSE err(ident) END
549 END;
550 Import(m, impName)
551 ELSE err(ident)
552 END;
553 IF sym = comma THEN DevCPS.Get(sym)
554 ELSIF sym = ident THEN err(comma)
555 ELSE EXIT
556 END
557 END;
558 CheckSym(semicolon)
559 END;
560 LOOP (* preprocessor must read module fully *)
561 IF sym = end THEN
562 DevCPS.Get(sym);
563 IF sym = ident THEN
564 DevCPS.Get(sym);
565 IF sym = period THEN
566 IF DevCPS.name # SelfName THEN err(4) END;
567 EXIT
568 ELSIF sym = eof THEN
569 err(period);
570 EXIT
571 END
572 ELSIF sym = eof THEN
573 err(ident);
574 EXIT
575 END;
576 ELSIF sym = eof THEN
577 err(end);
578 EXIT
579 ELSE
580 DevCPS.Get(sym);
581 END
582 END
583 ELSE err(ident)
584 END;
585 DevCPS.str := NIL
586 END ParseModule;
588 PROCEDURE CheckModule (m: Module; source: String; OUT ok: BOOLEAN);
589 VAR s: Selector;
590 BEGIN
591 DevCPM.Init(source);
592 DevCPM.symList := m.dir;
593 (*DevCPM.codePath := m.outcode;*)
594 (*DevCPM.symPath := m.outsym;*)
595 DevCPM.name := m.name$;
596 INCL(DevCPM.options, DevCPM.comAware);
597 IF trap THEN
598 INCL(DevCPM.options, DevCPM.trap)
599 END;
600 (*IF oberon IN m.opts THEN INCL(DevCPM.options, DevCPM.oberon) END;*)
601 DevCPR.Init;
602 s := def.next;
603 WHILE s # NIL DO
604 DevCPR.Set(s.name, s.value);
605 s := s.next
606 END;
607 ParseModule(m);
608 DevCPR.Check;
609 ok := DevCPM.noerr;
610 DevCPR.Close;
611 DevCPM.InsertMarks;
612 DevCPM.Close;
613 Kernel.FastCollect
614 END CheckModule;
616 PROCEDURE MakePath (IN dir, name: Files.Name; IN type: Files.Type; OUT path: Files.Name);
617 BEGIN
618 ASSERT(name # "", 21);
619 IF dir = "" THEN path := modDir + "/" + name
620 ELSE path := dir + "/" + modDir + "/" + name
621 END;
622 Kernel.MakeFileName(path, type)
623 END MakePath;
625 PROCEDURE Open (loc: Files.Locator; IN sub, name: Files.Name; OUT path: Files.Name; OUT text: DswDocuments.Model);
626 VAR res: INTEGER;
627 BEGIN
628 ASSERT(loc # NIL, 20);
629 ASSERT(name # "", 21);
630 (* !!! use Kernel.MakeFileName instead ".ext" concat !!! *)
631 MakePath(sub, name, "cp", path);
632 DswDocuments.Open(loc, name + ".cp", text, res);
633 IF text = NIL THEN
634 MakePath(sub, name, "odc", path);
635 DswDocuments.Open(loc, name + ".odc", text, res);
636 IF (text = NIL) & (sub = "") THEN
637 MakePath(sysDir, name, "cp", path);
638 loc := Files.dir.This(sysDir).This(modDir);
639 DswDocuments.Open(loc, name + ".cp", text, res);
640 IF text = NIL THEN
641 MakePath(sysDir, name, "odc", path);
642 DswDocuments.Open(loc, name + ".odc", text, res);
643 IF text = NIL THEN
644 path := ""
645 END
646 END
647 END
648 END
649 END Open;
651 PROCEDURE GetSource (IN modName: ARRAY OF CHAR; list: DevCPM.Directory; OUT path: Files.Name; OUT s: String);
652 VAR
653 sub, name: Files.Name; loc: Files.Locator; base: DevCPM.Directory;
654 text: DswDocuments.Model; r: DswDocuments.Reader; i, res: INTEGER;
655 BEGIN
656 s := NIL; path := ""; base := list;
657 Kernel.SplitName(modName, sub, name);
658 loc := Files.dir.This(sub).This(modDir);
659 Open(loc, sub, name, path, text);
660 WHILE (text = NIL) & (base # NIL) DO
661 ASSERT(base.legacy, 100);
662 loc := Files.dir.This(base.path).This(sub).This(modDir);
663 Open(loc, sub, name, path, text);
664 base := base.next
665 END;
666 IF text # NIL THEN
667 NEW(s, text.Length() + 1);
668 IF s # NIL THEN
669 r := text.NewReader(NIL);
670 FOR i := 0 TO text.Length() - 1 DO
671 r.Read; s[i] := r.char
672 END
673 END
674 END
675 END GetSource;
677 PROCEDURE Trace (m, parent: Module; VAR lno: INTEGER);
678 VAR i: INTEGER;
679 BEGIN
680 IF ~(trace IN m.flags) THEN
681 INCL(m.flags, trace);
682 FOR i := 0 TO m.mno - 1 DO
683 Trace(m.imp[i], m, lno);
684 m.depth := MAX(m.depth, m.imp[i].depth + 1)
685 END;
686 IF ~(imported IN m.flags) THEN
687 INCL(m.flags, imported);
688 lnkList[lno] := m;
689 INC(lno)
690 END;
691 EXCL(m.flags, trace)
692 ELSE
693 Error(20, m.name$, parent.name$, 0)
694 END
695 END Trace;
697 PROCEDURE Sort;
698 VAR i, j: INTEGER; m: Module;
699 BEGIN
700 ASSERT((mno = 0) OR (lnkList[0] # NIL), 20);
701 cmpList := lnkList;
702 i := 1;
703 WHILE i < mno DO
704 m := cmpList[i];
705 j := i - 1;
706 WHILE (j >= 0) & (cmpList[j].depth > m.depth) DO
707 cmpList[j + 1] := cmpList[j];
708 DEC(j)
709 END;
710 cmpList[j + 1] := m;
711 INC(i)
712 END
713 END Sort;
715 PROCEDURE CheckDeps;
716 VAR i, j, num: INTEGER; m: Module; src: String; ok: BOOLEAN;
717 BEGIN
718 i := 0; rno := mno;
719 WHILE (err = 0) & (i < mno) DO
720 m := modList[i];
721 GetSource(m.name$, m.dir, m.odc, src);
722 IF src # NIL THEN
723 CheckModule(m, src, ok);
724 IF ~ok THEN INC(err) END
725 ELSE
726 Error(21, m.name$, "", 0)
727 END;
728 INC(i)
729 END;
730 INC(err, werr);
731 num := 0;
732 FOR i := 0 TO rno - 1 DO
733 Trace(modList[i], modList[i], num)
734 END;
735 ASSERT((err # 0) OR (num = mno), 100);
736 Sort;
737 IF debugOrder THEN
738 Log.String("Parallel depth:"); Log.Ln;
739 FOR i := 0 TO mno - 1 DO
740 Log.String(" " + cmpList[i].name); Log.Int(cmpList[i].depth); Log.Ln;
741 END
742 END
743 END CheckDeps;
745 PROCEDURE IsCompiled (m: Module): BOOLEAN;
746 CONST target = {hasSym, hasObj};
747 VAR i: INTEGER; ready: BOOLEAN;
748 BEGIN
749 ASSERT(m # NIL, 20);
750 i := 0;
751 ready := ~(hasErrors IN m.flags) & (m.flags * target = target);
752 WHILE ready & (i < m.mno) DO
753 ready := IsCompiled(m.imp[i]);
754 INC(i)
755 END;
756 RETURN ready
757 END IsCompiled;
759 PROCEDURE Ready (m: Module): BOOLEAN;
760 CONST target = {hasSym, hasObj};
761 VAR i: INTEGER; ready: BOOLEAN;
762 BEGIN
763 i := 0;
764 ready := ~(hasErrors IN m.flags) & (m.flags * target # target) & (m.worker = NIL);
765 WHILE ready & (i < m.mno) DO
766 ready := IsCompiled(m.imp[i]);
767 INC(i)
768 END;
769 RETURN ready
770 END Ready;
772 PROCEDURE PutParams (w: DswProcs.Process; p: StringList);
773 VAR i: INTEGER;
774 BEGIN
775 ASSERT(w # NIL, 20);
776 IF debugArgs THEN Log.String("PutParams") END;
777 IF p # NIL THEN
778 IF debugArgs THEN Log.String(":[" + p[0]) END;
779 w.PutParam(p[0]);
780 FOR i := 1 TO LEN(p) - 1 DO
781 IF debugArgs THEN Log.String("|" + p[i]) END;
782 w.PutParam(p[i])
783 END;
784 IF debugArgs THEN Log.Char("]") END
785 END;
786 IF debugArgs THEN Log.Ln END
787 END PutParams;
789 PROCEDURE PutPathList (w: DswProcs.Process; IN par: ARRAY OF CHAR; base: DevCPM.Directory);
790 BEGIN
791 IF base # NIL THEN
792 PutPathList(w, par, base.next); (* in revese order *)
793 w.PutParam(par);
794 w.PutParam(base.path);
795 END
796 END PutPathList;
798 PROCEDURE ExecuteCompiler (m: Module): DswProcs.Process;
799 VAR w: DswProcs.Process; ok: BOOLEAN; s: Selector;
800 BEGIN
801 ASSERT(m # NIL, 20);
802 ASSERT(m.odc # "", 21);
803 ASSERT(m.worker = NIL, 22);
804 w := DswProcs.dir.New();
805 w.Program(cpcExe);
806 IF trap THEN
807 w.PutParam("-trap")
808 END;
809 w.PutParam("-legacy");
810 PutPathList(w, "-legacysymdir", m.dir);
811 s := def.next;
812 WHILE s # NIL DO
813 IF s.value = TRUE THEN w.PutParam("-define+")
814 ELSE w.PutParam("-define-")
815 END;
816 w.PutParam(s.name$);
817 s := s.next
818 END;
819 PutParams(w, cpcArgs);
820 w.PutParam(m.odc);
821 w.Execute(ok);
822 IF ok THEN
823 Log.String("Compile " + m.name + " (" + m.odc + ")"); Log.Ln;
824 ELSE
825 w := NIL
826 END;
827 RETURN w
828 END ExecuteCompiler;
830 PROCEDURE Compile;
831 VAR i, j, num: INTEGER; ok: BOOLEAN; m: Module; w: DswProcs.Process;
832 BEGIN
833 IF mno = 0 THEN RETURN END;
834 num := 0; j := 0;
835 WHILE (err = 0) & (num < mno) OR (j > 0) DO
836 i := 0;
837 WHILE (err = 0) & (i < mno) & (j < jobs) DO
838 m := cmpList[i];
839 IF Ready(m) THEN
840 w := ExecuteCompiler(m);
841 IF debugJobs THEN Log.String("Start job " + m.name) END;
842 IF w # NIL THEN
843 IF debugJobs THEN Log.String(" ok") END;
844 m.worker := w;
845 INC(j)
846 ELSE
847 IF debugJobs THEN Log.String(" fail") END;
848 INCL(m.flags, hasErrors);
849 INC(err)
850 END;
851 IF debugJobs THEN Log.Ln END
852 END;
853 INC(i)
854 END;
855 WHILE (err = 0) & (j >= jobs) OR (j > 0) DO
856 i := 0;
857 WHILE (j > 0) & (i < mno) DO
858 m := cmpList[i];
859 w := m.worker;
860 IF (w # NIL) & w.IsTerminated() THEN
861 IF debugJobs THEN Log.String("Stop job " + m.name); Log.Int(w.Result()); Log.Ln END;
862 IF w.Result() = 0 THEN
863 INCL(m.flags, hasObj);
864 INCL(m.flags, hasSym);
865 INC(num)
866 ELSE
867 INCL(m.flags, hasErrors);
868 INC(err)
869 END;
870 m.worker := NIL;
871 DEC(j)
872 END;
873 INC(i)
874 END
875 END
876 END
877 END Compile;
879 PROCEDURE LinkDev2;
880 VAR p: DswProcs.Process; i, res: INTEGER; ok: BOOLEAN;
881 BEGIN
882 ASSERT((exe # NIL) & (exe^ # ""), 20);
883 ASSERT(processor = mach386, 21);
884 ASSERT(compiler = cpnative, 22);
885 p := DswProcs.dir.New();
886 p.Program(cplExe);
887 IF trap THEN
888 p.PutParam("-trap")
889 END;
890 PutPathList(p, "-legacycodedir", dirList);
891 IF os # anyos THEN
892 p.PutParam("-os");
893 CASE os OF
894 | linux: p.PutParam("linux")
895 | freebsd: p.PutParam("freebsd")
896 | openbsd: p.PutParam("openbsd")
897 | win32, cygwin: p.PutParam("win32")
898 | darwin: p.PutParam("darwin")
899 END
900 END;
901 p.PutParam("-kernel");
902 p.PutParam("Kernel");
903 p.PutParam("-main");
904 p.PutParam("Kernel");
905 p.PutParam("-legacycodedir");
906 p.PutParam(".");
907 p.PutParam("-o");
908 p.PutParam(exe);
909 PutParams(p, cplArgs);
910 i := 0;
911 WHILE i < mno DO
912 IF ~(library IN lnkList[i].flags) THEN
913 p.PutParam(lnkList[i].name$)
914 END;
915 INC(i)
916 END;
917 p.Execute(ok);
918 IF ok THEN
919 Log.String("Link "); Log.String(exe); Log.Ln;
920 res := p.Result();
921 IF res # 0 THEN
922 Error(22, "", "", res)
923 END
924 ELSE
925 Error(23, "", "", 0)
926 END
927 END LinkDev2;
929 PROCEDURE Link;
930 BEGIN
931 IF exe # NIL THEN
932 CASE linker OF
933 | anyint: (* do not link *)
934 | dev2: LinkDev2
935 END
936 END
937 END Link;
939 PROCEDURE PrintInfo;
940 VAR i: INTEGER;
941 BEGIN
942 IF printCompileModList THEN
943 FOR i := 0 TO mno - 1 DO
944 Log.String(cmpList[i].name$); Log.Char(" ")
945 END;
946 Log.Ln
947 ELSIF printLinkModList THEN
948 FOR i := 0 TO mno - 1 DO
949 IF ~(library IN lnkList[i].flags) THEN
950 Log.String(lnkList[i].name$); Log.Char(" ")
951 END
952 END;
953 Log.Ln
954 ELSIF printCompileFileList THEN
955 FOR i := 0 TO mno - 1 DO
956 Log.String(cmpList[i].odc); Log.Char(" ")
957 END;
958 Log.Ln
959 (*
960 ELSIF printLinkFileList THEN
961 FOR i := 0 TO mno - 1 DO
962 IF ~(library IN lnkList[i].flags) THEN
963 Log.String(lnkList[i].ocf); Log.Char(" ")
964 END
965 END;
966 Log.Ln
967 *)
968 END
969 END PrintInfo;
971 PROCEDURE Main;
972 BEGIN
973 IF Kernel.trapCount = 0 THEN
974 ParseArgs;
975 IF err = 0 THEN
976 IF printCompileModList OR printLinkModList OR printCompileFileList THEN
977 auto := TRUE
978 END;
979 CheckParams;
980 IF err = 0 THEN
981 CheckDeps;
982 IF err = 0 THEN
983 IF printCompileModList OR printLinkModList OR printCompileFileList THEN
984 PrintInfo
985 ELSE
986 Compile;
987 IF err = 0 THEN
988 Link
989 END
990 END
991 END
992 END
993 END
994 ELSE Error(24, "", "", 0)
995 END;
996 IF err = 0 THEN Kernel.Quit(0)
997 ELSE Kernel.Quit(1)
998 END
999 END Main;
1001 BEGIN
1002 NEW(def);
1003 ASSERT(def # NIL, 100);
1004 Kernel.intTrap := FALSE;
1005 Kernel.Start(Main)
1006 END DswMakeMain.