DEADSOFTWARE

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