DEADSOFTWARE

57822e50c0aadd47b80e43f1e390754bda226996
[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 maxImps = 127;
9 maxJobs = maxImps;
11 (* symbol values *)
12 null = 0; times = 1; slash = 2; div = 3; mod = 4;
13 and = 5; plus = 6; minus = 7; or = 8; eql = 9;
14 neq = 10; lss = 11; leq = 12; gtr = 13; geq = 14;
15 in = 15; is = 16; arrow = 17; dollar = 18; period = 19;
16 comma = 20; colon = 21; upto = 22; rparen = 23; rbrak = 24;
17 rbrace = 25; of = 26; then = 27; do = 28; to = 29;
18 by = 30; not = 33;
19 lparen = 40; lbrak = 41; lbrace = 42; becomes = 44;
20 number = 45; nil = 46; string = 47; ident = 48; semicolon = 49;
21 bar = 50; end = 51; else = 52; elsif = 53; until = 54;
22 if = 55; case = 56; while = 57; repeat = 58; for = 59;
23 loop = 60; with = 61; exit = 62; return = 63; array = 64;
24 record = 65; pointer = 66; begin = 67; const = 68; type = 69;
25 var = 70; out = 71; procedure = 72; close = 73; import = 74;
26 module = 75; eof = 76;
28 (* module state flags *)
29 imported = 0; trace = 1; hasObj = 2; hasSym = 3; hasErrors = 4; library = 5;
31 (* procesor types *)
32 anymach = 0; cmach = 1; mach386 = 10; mach68k = 20;
34 (* operation system types *)
35 anyos = 0; linux = 1; freebsd = 2; openbsd = 3; win32 = 4;
37 (* compiler types *)
38 anycp = 0; cpnative = 1; cpfront = 2;
40 (* internal linker types *)
41 anyint = 0; dev2 = 1;
43 debugImport = FALSE;
44 debugOrder = FALSE;
45 debugJobs = FALSE;
46 debugArgs = FALSE;
48 TYPE
49 String = POINTER TO ARRAY OF CHAR;
50 StringList = POINTER TO ARRAY OF String;
52 Selector = POINTER TO RECORD
53 name: DevCPT.Name;
54 value: BOOLEAN;
55 next: Selector
56 END;
58 Module = POINTER TO RECORD
59 name: DevCPT.Name;
60 path: Files.Name;
61 selectors: Selector; (* with head, list of selectors for this module *)
62 depth: INTEGER; (* 0: leaf, MAX: root *)
63 mno: INTEGER;
64 imp: ARRAY maxImps OF Module;
65 flags: SET;
66 worker: DswProcs.Process;
67 END;
69 VAR
70 err: INTEGER;
71 mno, rno: INTEGER; (* num modules *)
72 modList, lnkList, cmpList: ARRAY maxImps OF Module;
73 def: Selector; (* with head, global list of selectors *)
74 processor, compiler, os, linker: INTEGER;
75 cpcExe, cplExe: String;
76 cpcArgs, cplArgs: StringList;
77 auto: BOOLEAN;
78 jobs: INTEGER;
79 exe: String;
81 (* --------- options --------- *)
83 PROCEDURE IdentLen (IN s: ARRAY OF CHAR): INTEGER;
84 VAR i: INTEGER;
85 BEGIN
86 i := 0;
87 IF Strings.IsIdentStart(s[0]) THEN
88 REPEAT INC(i) UNTIL ~Strings.IsIdent(s[i])
89 END;
90 RETURN i
91 END IdentLen;
93 PROCEDURE Define (n: ARRAY OF CHAR);
94 VAR i: INTEGER; v: BOOLEAN; s: Selector;
95 BEGIN
96 i := IdentLen(n);
97 IF i # 0 THEN
98 IF ~((n[i] = 0X) OR (((n[i] = "+") OR (n[i] = "-")) & (n[i + 1] = 0X))) THEN
99 Log.String("option -D expect + or - after identifier"); Log.Ln; INC(err)
100 END;
101 v := n[i] # "-"; n[i] := 0X; s := def;
102 WHILE (s.next # NIL) & (s.next.name$ # n$) DO s := s.next END;
103 IF s.next = NIL THEN
104 NEW(s.next);
105 Strings.StringToUtf8(n, s.next.name, i);
106 ASSERT(i = 0)
107 END;
108 s.next.value := v
109 ELSE
110 Log.String("option -D expect identifier"); Log.Ln; INC(err)
111 END
112 END Define;
114 PROCEDURE Undefine (IN n: ARRAY OF CHAR);
115 VAR i: INTEGER; s: Selector;
116 BEGIN
117 i := IdentLen(n);
118 IF (i # 0) & (n[i] = 0X) THEN
119 s := def;
120 WHILE (s.next # NIL) & (s.next.name$ # n$) DO s := s.next END;
121 IF s.next # NIL THEN s.next := s.next.next END
122 ELSE
123 Log.String("option -U expect identifier"); Log.Ln; INC(err)
124 END
125 END Undefine;
127 PROCEDURE CopySelectorList (base: Selector): Selector;
128 VAR s, t, x: Selector;
129 BEGIN
130 ASSERT(base # NIL, 20);
131 s := base; NEW(t); x := t;
132 WHILE s # NIL DO
133 x^ := s^;
134 IF s.next # NIL THEN NEW(x.next); x := x.next END;
135 s := s.next
136 END;
137 RETURN t
138 END CopySelectorList;
140 PROCEDURE AddModule (IN n: ARRAY OF CHAR; selectors: Selector);
141 VAR i, res: INTEGER; m: Module;
142 BEGIN
143 i := IdentLen(n);
144 IF (i # 0) & (n[i] = 0X) THEN
145 i := 0;
146 WHILE (i < mno) & (modList[i].name$ # n$) DO INC(i) END;
147 IF i >= mno THEN
148 NEW(m);
149 Strings.StringToUtf8(n, m.name, res);
150 ASSERT(res = 0);
151 m.selectors := CopySelectorList(selectors);
152 modList[i] := m;
153 INC(mno)
154 END
155 ELSE
156 Log.String("module name must be identifier"); Log.Ln; INC(err)
157 END
158 END AddModule;
160 PROCEDURE StrToInt (IN s: ARRAY OF CHAR; def: INTEGER): INTEGER;
161 VAR x, res: INTEGER;
162 BEGIN
163 Strings.StringToInt(s, x, res);
164 IF res # 0 THEN
165 Log.String("expected integer"); Log.Ln; INC(err);
166 x := def
167 END;
168 RETURN x
169 END StrToInt;
171 PROCEDURE NewStr (IN s: ARRAY OF CHAR): String;
172 VAR p: String;
173 BEGIN
174 NEW(p, LEN(s$) + 1); p^ := s$;
175 RETURN p
176 END NewStr;
178 PROCEDURE ToStringList (IN s: ARRAY OF CHAR): StringList;
179 VAR i: INTEGER; ch, term: CHAR; pars: StringList;
181 PROCEDURE AddChar (c: CHAR);
182 VAR i, n, len: INTEGER; str: String;
183 BEGIN
184 IF pars = NIL THEN
185 NEW(pars, 1); NEW(pars[0], 2); pars[0, 0] := c
186 ELSE
187 n := LEN(pars) - 1;
188 len := LEN(pars[n]$);
189 NEW(str, len + 2);
190 FOR i := 0 TO len - 1 DO
191 str[i] := pars[n, i]
192 END;
193 str[i] := c;
194 pars[n] := str
195 END
196 END AddChar;
198 PROCEDURE AddLine;
199 VAR i, len: INTEGER; p: StringList;
200 BEGIN
201 IF pars = NIL THEN
202 NEW(pars, 1); i := 0;
203 ELSE
204 len := LEN(pars);
205 NEW(p, len + 1);
206 FOR i := 0 TO len - 1 DO
207 p[i] := pars[i]
208 END;
209 pars := p
210 END;
211 NEW(pars[i], 1)
212 END AddLine;
214 BEGIN
215 i := 0;
216 REPEAT ch := s[i]; INC(i) UNTIL ch # " ";
217 WHILE ch # 0X DO
218 CASE ch OF
219 | '"', "'":
220 term := ch; ch := s[i]; INC(i);
221 WHILE (ch # term) & (ch # 0X) DO
222 AddChar(ch); ch := s[i]; INC(i)
223 END;
224 IF ch # 0X THEN ch := s[i]; INC(i)
225 ELSE Log.String("unterminated string"); Log.Ln; INC(err)
226 END
227 | " ":
228 REPEAT ch := s[i]; INC(i) UNTIL ch # " ";
229 IF ch # 0X THEN AddLine END
230 ELSE
231 AddChar(ch); ch := s[i]; INC(i)
232 END
233 END;
234 RETURN pars
235 END ToStringList;
237 PROCEDURE Help;
238 BEGIN
239 Log.String("Usage: cpmake [options] module..."); Log.Ln;
240 Log.String("Options:"); Log.Ln;
241 Log.String(" -Tm cpu Generate code for specified processor"); Log.Ln;
242 Log.String(" none Unknown processor (cpfront only)"); Log.Ln;
243 Log.String(" 486 Intel 486"); Log.Ln;
244 Log.String(" -Ts os Generate code for specified operation system"); Log.Ln;
245 Log.String(" none Unknown operation system"); Log.Ln;
246 Log.String(" linux Linux"); Log.Ln;
247 Log.String(" -Tg compiler Specify Component Pascal compiler"); Log.Ln;
248 Log.String(" native BlackBox based native code compiler"); Log.Ln;
249 Log.String(" cpfront BlackBox based C code translator"); Log.Ln;
250 Log.String(" -Ti linker Specify internal linker (native only)"); Log.Ln;
251 Log.String(" dev2 Dev2 based ELF/PE linker"); Log.Ln;
252 (*
253 Log.String(" -Fp path Add path with project"); Log.Ln;
254 Log.String(" -Fx path Add postfix for project directories"); Log.Ln;
255 *)
256 Log.String(" -Xp path Use executable file for Component Pascal compiler"); Log.Ln;
257 Log.String(" -Xi path Use executable file for internal linker (native only)"); Log.Ln;
258 Log.String(" -Cg params Pass parameters to Component Pasacal compiler directly"); Log.Ln;
259 Log.String(" -Ci params Pass parameters to internal linker directly"); Log.Ln;
260 (*
261 Log.String(" -a Enable automatic dependency resolution"); Log.Ln;
262 *)
263 Log.String(" -o name Generate executable file"); Log.Ln;
264 Log.String(" -j num Specifies the number of jobs to run simultaneously"); Log.Ln;
265 Log.String(' -D ident["+"|"-"] Add preprocessor selector'); Log.Ln;
266 Log.String(' -U ident Remove preprocessor selector'); Log.Ln;
267 Log.String(" -h Print help and quit"); Log.Ln;
268 Log.String(" -V Print version and quit"); Log.Ln;
269 Kernel.Quit(1)
270 END Help;
272 PROCEDURE Version;
273 BEGIN
274 Log.String(version); Log.Ln;
275 Kernel.Quit(0)
276 END Version;
278 PROCEDURE ParseTargetOpts;
279 VAR s: DswOpts.String;
280 BEGIN
281 CASE DswOpts.GetOpt("m:s:g:i:") OF
282 | "m":
283 s := DswOpts.str;
284 Strings.ToLower(s, s);
285 IF s$ = "none" THEN processor := anymach
286 ELSIF s$ = "486" THEN processor := mach386
287 ELSIF s$ = "68k" THEN processor := mach68k
288 ELSE Log.String("unknwon processor "); Log.String(s); Log.Ln; INC(err)
289 END
290 | "s":
291 s := DswOpts.str;
292 Strings.ToLower(s, s);
293 IF s$ = "none" THEN os := anyos
294 ELSIF s$ = "linux" THEN os := linux
295 ELSE Log.String("unknwon os "); Log.String(s); Log.Ln; INC(err)
296 END
297 | "g":
298 s := DswOpts.str;
299 Strings.ToLower(s, s);
300 IF s$ = "native" THEN compiler := cpnative
301 ELSIF s$ = "cpfront" THEN compiler := cpfront
302 ELSE Log.String("unknwon compiler "); Log.String(s); Log.Ln; INC(err)
303 END
304 | "i":
305 s := DswOpts.str;
306 Strings.ToLower(s, s);
307 IF s$ = "dev2" THEN linker := dev2
308 ELSE Log.String("unknwon linker "); Log.String(s); Log.Ln; INC(err)
309 END
310 | ":": Log.String("missing argument for option -T"); Log.String(DswOpts.str); Log.Ln; INC(err)
311 | "?": Log.String("unknown option -T"); Log.String(DswOpts.str); Log.Ln; INC(err)
312 | 0X: Log.String("unknown option -T"); Log.Ln; INC(err)
313 END
314 END ParseTargetOpts;
316 PROCEDURE ParseCommandOpts;
317 BEGIN
318 CASE DswOpts.GetOpt("g:i:") OF
319 | "g": cpcArgs := ToStringList(DswOpts.str);
320 | "i": cplArgs := ToStringList(DswOpts.str);
321 | ":": Log.String("missing argument for option -C"); Log.String(DswOpts.str); Log.Ln; INC(err)
322 | "?": Log.String("unknown option -C"); Log.String(DswOpts.str); Log.Ln; INC(err)
323 | 0X: Log.String("unknown option -C"); Log.Ln; INC(err)
324 END
325 END ParseCommandOpts;
327 PROCEDURE ParseExternalOpts;
328 BEGIN
329 CASE DswOpts.GetOpt("g:i:") OF
330 | "g": cpcExe := DswOpts.str;
331 | "i": cplExe := DswOpts.str;
332 | ":": Log.String("missing argument for option -X"); Log.String(DswOpts.str); Log.Ln; INC(err)
333 | "?": Log.String("unknown option -X"); Log.String(DswOpts.str); Log.Ln; INC(err)
334 | 0X: Log.String("unknown option -X"); Log.Ln; INC(err)
335 END
336 END ParseExternalOpts;
338 PROCEDURE ParseArgs;
339 BEGIN
340 exe := NIL; auto := FALSE; jobs := 1; def.next := NIL; mno := 0; rno := 0;
341 processor := anymach; os := anyos; compiler := anycp;
342 LOOP
343 CASE DswOpts.GetOpt("ao:j:D:U:TCXhV") OF
344 | "a": auto := TRUE
345 | "o": exe := DswOpts.str
346 | "j": jobs := MIN(MAX(StrToInt(DswOpts.str, 1), 1), maxJobs)
347 | "h": Help
348 | "V": Version
349 | "D": Define(DswOpts.str)
350 | "U": Undefine(DswOpts.str)
351 | "T": ParseTargetOpts
352 | "C": ParseCommandOpts
353 | "X": ParseExternalOpts
354 | ":": Log.String("missing argument for option -"); Log.String(DswOpts.str); Log.Ln; INC(err)
355 | "?": Log.String("unknown option -"); Log.String(DswOpts.str); Log.Ln; INC(err)
356 | "$": AddModule(DswOpts.str, def)
357 | 0X: EXIT
358 END
359 END;
360 END ParseArgs;
362 PROCEDURE CheckParams;
363 BEGIN
364 IF compiler = anycp THEN
365 Log.String("compiler not selected"); Log.Ln; INC(err)
366 ELSIF compiler = cpnative THEN
367 IF processor = anymach THEN
368 Log.String("processor not selected"); Log.Ln; INC(err)
369 ELSIF processor # mach386 THEN
370 Log.String("processor not supported by native compiler"); Log.Ln; INC(err)
371 END
372 END;
373 IF (compiler = cpfront) & (linker # anyint) THEN
374 Log.String("internal linker not required for cpfront"); Log.Ln; INC(err)
375 END;
376 IF (compiler = cpfront) & (exe # NIL) THEN
377 Log.String("cpfront can't out executable file"); Log.Ln; INC(err)
378 END;
379 IF (exe # NIL) & (compiler = cpnative) & (linker = anyint) THEN
380 Log.String("linker not selected"); Log.Ln; INC(err)
381 END;
382 IF (linker = dev2) & (os = anyos) THEN
383 Log.String("os not selected"); Log.Ln; INC(err)
384 END;
385 IF (exe # NIL) & (exe^ = "") THEN
386 Log.String("output file name can't be empty"); Log.Ln; INC(err)
387 END;
388 IF cpcExe = NIL THEN
389 IF compiler = cpnative THEN cpcExe := NewStr("cpc486")
390 ELSIF compiler = cpfront THEN cpcExe := NewStr("cpfront")
391 END
392 END;
393 IF cplExe = NIL THEN
394 IF linker = dev2 THEN cplExe := NewStr("cpl486") END
395 END
396 END CheckParams;
398 (* --------- loader --------- *)
400 PROCEDURE Import (m: Module; IN name: DevCPT.Name);
401 VAR i, j: INTEGER; imp: Module;
402 BEGIN
403 ASSERT(m # NIL, 20);
404 ASSERT(name # "", 21);
405 IF debugImport THEN Log.String(" import "); Log.String(name$) END;
406 IF name = "SYSTEM" THEN INCL(DevCPM.options, DevCPM.sysImp)
407 ELSIF name = "COM" THEN INCL(DevCPM.options, DevCPM.com)
408 ELSIF name = "JAVA" THEN INCL(DevCPM.options, DevCPM.java)
409 ELSE
410 IF debugImport THEN Log.Char(" ") END;
411 i := 0; (* find module in local list *)
412 WHILE (i < m.mno) & (m.imp[i].name$ # name$) DO INC(i) END;
413 IF i >= m.mno THEN
414 j := 0; (* find module in global list *)
415 WHILE (j < mno) & (modList[j].name$ # name$) DO INC(j) END;
416 IF j >= mno THEN
417 NEW(imp); imp.name := name$; imp.selectors := CopySelectorList(m.selectors);
418 modList[mno] := imp; INC(mno)
419 ELSE
420 imp := modList[j]
421 END;
422 m.imp[m.mno] := imp; INC(m.mno)
423 ELSE DevCPM.err(1)
424 END
425 END;
426 IF debugImport THEN Log.Ln END;
427 END Import;
429 PROCEDURE ParseModule (m: Module);
430 VAR sym: BYTE; SelfName, impName, aliasName: DevCPT.Name;
432 PROCEDURE err (n: SHORTINT);
433 BEGIN DevCPM.err(n)
434 END err;
436 PROCEDURE CheckSym(s: SHORTINT);
437 BEGIN
438 IF sym = s THEN DevCPS.Get(sym) ELSE DevCPM.err(s) END
439 END CheckSym;
441 BEGIN
442 IF debugImport THEN Log.String("module " + m.name); Log.Ln END;
443 DevCPS.Init; DevCPS.Get(sym);
444 IF sym = module THEN DevCPS.Get(sym) ELSE err(16) END;
445 IF sym = ident THEN
446 SelfName := DevCPS.name$; DevCPS.Get(sym);
447 IF sym = lbrak THEN
448 INCL(DevCPM.options, DevCPM.interface); DevCPS.Get(sym);
449 IF sym = eql THEN DevCPS.Get(sym)
450 ELSE INCL(DevCPM.options, DevCPM.noCode)
451 END;
452 IF sym = string THEN INCL(m.flags, library); DevCPS.Get(sym)
453 ELSE err(string)
454 END;
455 CheckSym(rbrak)
456 END;
457 CheckSym(semicolon);
458 IF sym = import THEN DevCPS.Get(sym);
459 LOOP
460 IF sym = ident THEN
461 aliasName := DevCPS.name$; impName := aliasName$; DevCPS.Get(sym);
462 IF sym = becomes THEN DevCPS.Get(sym);
463 IF sym = ident THEN impName := DevCPS.name$; DevCPS.Get(sym) ELSE err(ident) END
464 END;
465 Import(m, impName)
466 ELSE err(ident)
467 END;
468 IF sym = comma THEN DevCPS.Get(sym)
469 ELSIF sym = ident THEN err(comma)
470 ELSE EXIT
471 END
472 END;
473 CheckSym(semicolon)
474 END
475 ELSE err(ident)
476 END;
477 DevCPS.str := NIL
478 END ParseModule;
480 PROCEDURE CheckModule (m: Module; source: String; OUT ok: BOOLEAN);
481 VAR s: Selector;
482 BEGIN
483 DevCPM.Init(source);
484 (*
485 DevCPM.symList := m.insym;
486 DevCPM.codePath := m.outcode;
487 DevCPM.symPath := m.outsym;
488 *)
489 DevCPM.name := m.name$;
490 (*
491 IF m.found THEN INCL(DevCPM.options, DevCPM.comAware) END;
492 IF errorTrap IN m.opts THEN INCL(DevCPM.options, DevCPM.trap) END;
493 IF oberon IN m.opts THEN INCL(DevCPM.options, DevCPM.oberon) END;
494 *)
495 DevCPR.Init;
496 s := m.selectors.next;
497 WHILE s # NIL DO
498 DevCPR.Set(s.name, s.value);
499 s := s.next
500 END;
501 ParseModule(m);
502 DevCPR.Check;
503 ok := DevCPM.noerr;
504 DevCPR.Close;
505 DevCPM.InsertMarks;
506 DevCPM.Close;
507 Kernel.FastCollect
508 END CheckModule;
510 PROCEDURE GetSource (IN modName: ARRAY OF CHAR; OUT path: Files.Name; OUT s: String);
511 CONST modDir = "Mod"; sysDir = "System";
512 VAR dir, name: Files.Name; loc: Files.Locator;
513 text: DswDocuments.Model; r: DswDocuments.Reader; i, res: INTEGER;
515 PROCEDURE MakePath (dir, name: Files.Name; type: Files.Type; OUT path: Files.Name);
516 BEGIN
517 ASSERT(name # "", 21);
518 IF dir = "" THEN path := modDir + "/" + name
519 ELSE path := dir + "/" + modDir + "/" + name
520 END;
521 Kernel.MakeFileName(path, type)
522 END MakePath;
524 BEGIN
525 s := NIL; path := "";
526 Kernel.SplitName(modName, dir, name);
527 loc := Files.dir.This(dir).This(modDir);
528 (* --> Kernel.MakeFileName(name, Kernel.docType); <-- *)
529 MakePath(dir, name, "cp", path);
530 DswDocuments.Open(loc, name + ".cp", text, res);
531 IF text = NIL THEN
532 MakePath(dir, name, "odc", path);
533 DswDocuments.Open(loc, name + ".odc", text, res);
534 IF (text = NIL) & (dir = "") THEN
535 MakePath(sysDir, name, "cp", path);
536 loc := Files.dir.This(sysDir).This(modDir);
537 DswDocuments.Open(loc, name + ".cp", text, res);
538 IF text = NIL THEN
539 MakePath(sysDir, name, "odc", path);
540 DswDocuments.Open(loc, name + ".odc", text, res);
541 IF text = NIL THEN
542 path := ""
543 END
544 END
545 END
546 END;
547 IF text # NIL THEN
548 NEW(s, text.Length() + 1);
549 IF s # NIL THEN
550 r := text.NewReader(NIL);
551 FOR i := 0 TO text.Length() - 1 DO
552 r.Read; s[i] := r.char
553 END
554 END
555 END
556 END GetSource;
558 PROCEDURE Trace (m, parent: Module; VAR lno: INTEGER);
559 VAR i: INTEGER;
560 BEGIN
561 IF ~(trace IN m.flags) THEN
562 INCL(m.flags, trace);
563 FOR i := 0 TO m.mno - 1 DO
564 Trace(m.imp[i], m, lno);
565 m.depth := MAX(m.depth, m.imp[i].depth + 1)
566 END;
567 IF ~(imported IN m.flags) THEN
568 INCL(m.flags, imported);
569 lnkList[lno] := m;
570 INC(lno)
571 END;
572 EXCL(m.flags, trace)
573 ELSE
574 Log.String("recursive import of " + m.name + " in " + parent.name); Log.Ln; INC(err)
575 END
576 END Trace;
578 PROCEDURE Sort;
579 VAR i, j: INTEGER; m: Module;
580 BEGIN
581 ASSERT((mno = 0) OR (lnkList[0] # NIL), 20);
582 cmpList := lnkList;
583 i := 1;
584 WHILE i < mno DO
585 m := cmpList[i];
586 j := i - 1;
587 WHILE (j >= 0) & (cmpList[j].depth > m.depth) DO
588 cmpList[j + 1] := cmpList[j];
589 DEC(j)
590 END;
591 cmpList[j + 1] := m;
592 INC(i)
593 END
594 END Sort;
596 PROCEDURE CheckDeps;
597 VAR i, j, num: INTEGER; m: Module; s: String; ok: BOOLEAN;
598 BEGIN
599 i := 0; rno := mno;
600 WHILE (err = 0) & (i < mno) DO
601 m := modList[i];
602 GetSource(m.name$, m.path, s);
603 IF s # NIL THEN
604 CheckModule(m, s, ok);
605 IF ~ok THEN INC(err) END
606 ELSE
607 Log.String("unable to open module " + m.name); Log.Ln; INC(err)
608 END;
609 INC(i)
610 END;
611 num := 0;
612 FOR i := 0 TO rno - 1 DO
613 Trace(modList[i], modList[i], num)
614 END;
615 ASSERT((err # 0) OR (num = mno), 100);
616 Sort;
617 IF debugOrder THEN
618 Log.String("Parallel depth:"); Log.Ln;
619 FOR i := 0 TO mno - 1 DO
620 Log.String(" " + cmpList[i].name); Log.Int(cmpList[i].depth); Log.Ln;
621 END
622 END
623 END CheckDeps;
625 PROCEDURE IsCompiled (m: Module): BOOLEAN;
626 CONST target = {hasSym, hasObj};
627 VAR i: INTEGER; ready: BOOLEAN;
628 BEGIN
629 ASSERT(m # NIL, 20);
630 i := 0;
631 ready := ~(hasErrors IN m.flags) & (m.flags * target = target);
632 WHILE ready & (i < m.mno) DO
633 ready := IsCompiled(m.imp[i]);
634 INC(i)
635 END;
636 RETURN ready
637 END IsCompiled;
639 PROCEDURE Ready (m: Module): BOOLEAN;
640 CONST target = {hasSym, hasObj};
641 VAR i: INTEGER; ready: BOOLEAN;
642 BEGIN
643 i := 0;
644 ready := ~(hasErrors IN m.flags) & (m.flags * target # target) & (m.worker = NIL);
645 WHILE ready & (i < m.mno) DO
646 ready := IsCompiled(m.imp[i]);
647 INC(i)
648 END;
649 RETURN ready
650 END Ready;
652 PROCEDURE PutParams (w: DswProcs.Process; p: StringList);
653 VAR i: INTEGER;
654 BEGIN
655 ASSERT(w # NIL, 20);
656 IF debugArgs THEN Log.String("PutParams") END;
657 IF p # NIL THEN
658 IF debugArgs THEN Log.String(":[" + p[0]) END;
659 w.PutParam(p[0]);
660 FOR i := 1 TO LEN(p) - 1 DO
661 IF debugArgs THEN Log.String("|" + p[i]) END;
662 w.PutParam(p[i])
663 END;
664 IF debugArgs THEN Log.Char("]") END
665 END;
666 IF debugArgs THEN Log.Ln END
667 END PutParams;
669 PROCEDURE ExecuteCompiler (m: Module): DswProcs.Process;
670 VAR w: DswProcs.Process; ok: BOOLEAN;
671 BEGIN
672 ASSERT(m # NIL, 20);
673 ASSERT(m.path # "", 21);
674 ASSERT(m.worker = NIL, 22);
675 w := DswProcs.dir.New();
676 w.Program(cpcExe);
677 w.PutParam("-legacy");
678 PutParams(w, cpcArgs);
679 w.PutParam(m.path);
680 w.Execute(ok);
681 IF ok THEN
682 Log.String("Compile " + m.name + " (" + m.path + ")"); Log.Ln;
683 ELSE
684 w := NIL
685 END;
686 RETURN w
687 END ExecuteCompiler;
689 PROCEDURE Compile;
690 VAR i, j, num: INTEGER; ok: BOOLEAN; m: Module; w: DswProcs.Process;
691 BEGIN
692 IF mno = 0 THEN RETURN END;
693 num := 0; j := 0;
694 WHILE (err = 0) & (num < mno) OR (j > 0) DO
695 i := 0;
696 WHILE (err = 0) & (i < mno) & (j < jobs) DO
697 m := cmpList[i];
698 IF Ready(m) THEN
699 w := ExecuteCompiler(m);
700 IF debugJobs THEN Log.String("Start job " + m.name) END;
701 IF w # NIL THEN
702 IF debugJobs THEN Log.String(" ok") END;
703 m.worker := w;
704 INC(j)
705 ELSE
706 IF debugJobs THEN Log.String(" fail") END;
707 INCL(m.flags, hasErrors);
708 INC(err)
709 END;
710 IF debugJobs THEN Log.Ln END
711 END;
712 INC(i)
713 END;
714 WHILE (err = 0) & (j >= jobs) OR (j > 0) DO
715 i := 0;
716 WHILE (j > 0) & (i < mno) DO
717 m := cmpList[i];
718 w := m.worker;
719 IF (w # NIL) & w.IsTerminated() THEN
720 IF debugJobs THEN Log.String("Stop job " + m.name); Log.Int(w.Result()); Log.Ln END;
721 IF w.Result() = 0 THEN
722 INCL(m.flags, hasObj);
723 INCL(m.flags, hasSym);
724 INC(num)
725 ELSE
726 INCL(m.flags, hasErrors);
727 INC(err)
728 END;
729 m.worker := NIL;
730 DEC(j)
731 END;
732 INC(i)
733 END
734 END
735 END
736 END Compile;
738 PROCEDURE LinkDev2;
739 VAR p: DswProcs.Process; i, res: INTEGER; ok: BOOLEAN;
740 BEGIN
741 ASSERT((exe # NIL) & (exe^ # ""), 20);
742 ASSERT(processor = mach386, 21);
743 ASSERT(compiler = cpnative, 22);
744 ASSERT(os IN {linux, freebsd, openbsd, win32}, 23);
745 p := DswProcs.dir.New();
746 p.Program(cplExe);
747 IF os # anyos THEN
748 p.PutParam("-os");
749 CASE os OF
750 | linux: p.PutParam("linux")
751 | freebsd: p.PutParam("freebsd")
752 | openbsd: p.PutParam("openbsd")
753 | win32: p.PutParam("win32")
754 END
755 END;
756 p.PutParam("-kernel");
757 p.PutParam("Kernel");
758 p.PutParam("-main");
759 p.PutParam("Kernel");
760 p.PutParam("-legacycodedir");
761 p.PutParam(".");
762 p.PutParam("-o");
763 p.PutParam(exe);
764 PutParams(p, cplArgs);
765 i := 0;
766 WHILE i < mno DO
767 IF ~(library IN lnkList[i].flags) THEN
768 p.PutParam(lnkList[i].name$)
769 END;
770 INC(i)
771 END;
772 p.Execute(ok);
773 IF ok THEN
774 Log.String("Link "); Log.String(exe); Log.Ln;
775 res := p.Result();
776 IF res # 0 THEN
777 Log.String("linker terminated with error"); Log.Int(res); Log.Ln;
778 INC(err)
779 END
780 ELSE
781 Log.String("unable to execute linker"); Log.Int(i); Log.Ln;
782 INC(err)
783 END
784 END LinkDev2;
786 PROCEDURE Link;
787 BEGIN
788 IF exe # NIL THEN
789 CASE linker OF
790 | anyint: (* do not link *)
791 | dev2: LinkDev2
792 END
793 END
794 END Link;
796 PROCEDURE Main;
797 VAR m: Module; s: Selector; p: DswProcs.Process; ok: BOOLEAN; i, res: INTEGER;
798 BEGIN
799 IF Kernel.trapCount = 0 THEN
800 ParseArgs;
801 IF err = 0 THEN
802 CheckParams;
803 IF err = 0 THEN
804 CheckDeps;
805 IF err = 0 THEN
806 Compile;
807 IF err = 0 THEN
808 Link
809 END
810 END
811 END
812 END
813 ELSE INC(err)
814 END;
815 IF err = 0 THEN Kernel.Quit(0)
816 ELSE Kernel.Quit(1)
817 END;
818 END Main;
820 BEGIN
821 NEW(def);
822 Kernel.Start(Main)
823 END DswMakeMain.