3 IMPORT Kernel
, Files
, Log
, Strings
, DswOpts
, DswProcs
, DswDocuments
, DevCPM
, DevCPT
, DevCPR
, DevCPS
;
10 null
= 0; times
= 1; slash
= 2; div
= 3; mod
= 4;
11 and
= 5; plus
= 6; minus
= 7; or
= 8; eql
= 9;
12 neq
= 10; lss
= 11; leq
= 12; gtr
= 13; geq
= 14;
13 in
= 15; is
= 16; arrow
= 17; dollar
= 18; period
= 19;
14 comma
= 20; colon
= 21; upto
= 22; rparen
= 23; rbrak
= 24;
15 rbrace
= 25; of
= 26; then
= 27; do
= 28; to
= 29;
17 lparen
= 40; lbrak
= 41; lbrace
= 42; becomes
= 44;
18 number
= 45; nil
= 46; string
= 47; ident
= 48; semicolon
= 49;
19 bar
= 50; end
= 51; else
= 52; elsif
= 53; until
= 54;
20 if
= 55; case
= 56; while
= 57; repeat
= 58; for
= 59;
21 loop
= 60; with
= 61; exit
= 62; return
= 63; array
= 64;
22 record
= 65; pointer
= 66; begin
= 67; const
= 68; type
= 69;
23 var
= 70; out
= 71; procedure
= 72; close
= 73; import
= 74;
24 module
= 75; eof
= 76;
26 (* module state flags *)
27 imported
= 0; trace
= 1; hasObj
= 2; hasSym
= 3; hasErrors
= 4; library
= 5;
30 anymach
= 0; cmach
= 1; mach386
= 10; mach68k
= 20;
32 (* operation system types *)
33 anyos
= 0; linux
= 1; freebsd
= 2; openbsd
= 3; win32
= 4;
36 anycp
= 0; cpnative
= 1; cpfront
= 2;
38 (* internal linker types *)
46 String
= POINTER TO ARRAY OF CHAR;
48 Selector
= POINTER TO RECORD
54 Module
= POINTER TO RECORD
57 selectors
: Selector
; (* with head, list of selectors for this module *)
58 depth
: INTEGER; (* 0: leaf, MAX: root *)
60 imp
: ARRAY maxImps
OF Module
;
62 worker
: DswProcs
.Process
;
67 mno
, rno
: INTEGER; (* num modules *)
68 modList
, lnkList
, cmpList
: ARRAY maxImps
OF Module
;
69 def
: Selector
; (* with head, global list of selectors *)
70 processor
, compiler
, os
, linker
: INTEGER;
75 (* --------- options --------- *)
77 PROCEDURE IdentLen (IN s
: ARRAY OF CHAR): INTEGER;
81 IF Strings
.IsIdentStart(s
[0]) THEN
82 REPEAT INC(i
) UNTIL ~Strings
.IsIdent(s
[i
])
87 PROCEDURE Define (n
: ARRAY OF CHAR);
88 VAR i
: INTEGER; v
: BOOLEAN; s
: Selector
;
92 IF ~
((n
[i
] = 0X
) OR (((n
[i
] = "+") OR (n
[i
] = "-")) & (n
[i
+ 1] = 0X
))) THEN
93 Log
.String("option -D expect + or - after identifier"); Log
.Ln
; INC(err
)
95 v
:= n
[i
] # "-"; n
[i
] := 0X
; s
:= def
;
96 WHILE (s
.next
# NIL) & (s
.next
.name$
# n$
) DO s
:= s
.next
END;
99 Strings
.StringToUtf8(n
, s
.next
.name
, i
);
104 Log
.String("option -D expect identifier"); Log
.Ln
; INC(err
)
108 PROCEDURE Undefine (IN n
: ARRAY OF CHAR);
109 VAR i
: INTEGER; s
: Selector
;
112 IF (i
# 0) & (n
[i
] = 0X
) THEN
114 WHILE (s
.next
# NIL) & (s
.next
.name$
# n$
) DO s
:= s
.next
END;
115 IF s
.next
# NIL THEN s
.next
:= s
.next
.next
END
117 Log
.String("option -U expect identifier"); Log
.Ln
; INC(err
)
121 PROCEDURE CopySelectorList (base
: Selector
): Selector
;
122 VAR s
, t
, x
: Selector
;
124 ASSERT(base
# NIL, 20);
125 s
:= base
; NEW(t
); x
:= t
;
128 IF s
.next
# NIL THEN NEW(x
.next
); x
:= x
.next
END;
132 END CopySelectorList
;
134 PROCEDURE AddModule (IN n
: ARRAY OF CHAR; selectors
: Selector
);
135 VAR i
, res
: INTEGER; m
: Module
;
138 IF (i
# 0) & (n
[i
] = 0X
) THEN
140 WHILE (i
< mno
) & (modList
[i
].name$
# n$
) DO INC(i
) END;
143 Strings
.StringToUtf8(n
, m
.name
, res
);
145 m
.selectors
:= CopySelectorList(selectors
);
150 Log
.String("module name must be identifier"); Log
.Ln
; INC(err
)
154 PROCEDURE StrToInt (IN s
: ARRAY OF CHAR; def
: INTEGER): INTEGER;
157 Strings
.StringToInt(s
, x
, res
);
159 Log
.String("expected integer"); Log
.Ln
; INC(err
);
167 Log
.String("Usage: cpmake [options] module..."); Log
.Ln
;
168 Log
.String("Options:"); Log
.Ln
;
169 Log
.String(" -Tm cpu Generate code for specified processor"); Log
.Ln
;
170 Log
.String(" none Unknown processor (cpfront only)"); Log
.Ln
;
171 Log
.String(" 486 Intel 486"); Log
.Ln
;
172 Log
.String(" -Ts os Generate code for specified operation system"); Log
.Ln
;
173 Log
.String(" none Unknown operation system"); Log
.Ln
;
174 Log
.String(" linux Linux"); Log
.Ln
;
175 Log
.String(" -Tg compiler Specify Component Pascal compiler"); Log
.Ln
;
176 Log
.String(" native BlackBox based native code compiler"); Log
.Ln
;
177 Log
.String(" cpfront BlackBox based C code translator"); Log
.Ln
;
178 Log
.String(" -Ti linker Specify internal linker (native only)"); Log
.Ln
;
179 Log
.String(" dev2 Dev2 based ELF/PE linker"); Log
.Ln
;
181 Log.String(" -Fp path Add path with project"); Log.Ln;
182 Log.String(" -Fx path Add postfix for project directories"); Log.Ln;
183 Log.String(" -Xp path Use executable file for Component Pascal compiler"); Log.Ln;
184 Log.String(" -Xi path Use executable file for internal linker (native only)"); Log.Ln;
185 Log.String(" -Cp params Pass parameters to Component Pasacal compiler directly"); Log.Ln;
186 Log.String(" -Ci params Pass parameters to internal linker directly"); Log.Ln;
187 Log.String(" -a Enable automatic dependency resolution"); Log.Ln;
189 Log
.String(" -o name Generate executable file"); Log
.Ln
;
190 Log
.String(" -j num Specifies the number of jobs to run simultaneously"); Log
.Ln
;
191 Log
.String('
-D ident
["+"|
"-"] Add preprocessor selector'
); Log
.Ln
;
192 Log
.String('
-U ident Remove preprocessor selector'
); Log
.Ln
;
193 Log
.String(" -h Print help"); Log
.Ln
;
194 Log
.String(" -v Print version"); Log
.Ln
;
198 PROCEDURE ParseTargetOpts
;
199 VAR s
: DswOpts
.String
;
201 CASE DswOpts
.GetOpt("m:s:g:i:") OF
204 Strings
.ToLower(s
, s
);
205 IF s$
= "none" THEN processor
:= anymach
206 ELSIF s$
= "486" THEN processor
:= mach386
207 ELSIF s$
= "68k" THEN processor
:= mach68k
208 ELSE Log
.String("unknwon processor "); Log
.String(s
); Log
.Ln
; INC(err
)
212 Strings
.ToLower(s
, s
);
213 IF s$
= "none" THEN os
:= anyos
214 ELSIF s$
= "linux" THEN os
:= linux
215 ELSE Log
.String("unknwon os "); Log
.String(s
); Log
.Ln
; INC(err
)
219 Strings
.ToLower(s
, s
);
220 IF s$
= "native" THEN compiler
:= cpnative
221 ELSIF s$
= "cpfront" THEN compiler
:= cpfront
222 ELSE Log
.String("unknwon compiler "); Log
.String(s
); Log
.Ln
; INC(err
)
226 Strings
.ToLower(s
, s
);
227 IF s$
= "dev2" THEN linker
:= dev2
228 ELSE Log
.String("unknwon linker "); Log
.String(s
); Log
.Ln
; INC(err
)
230 |
":": Log
.String("missing argument for option -T"); Log
.String(DswOpts
.str
); Log
.Ln
; INC(err
)
231 |
"?": Log
.String("unknown option -T"); Log
.String(DswOpts
.str
); Log
.Ln
; INC(err
)
232 |
0X
: Log
.String("unknown option -T"); Log
.Ln
; INC(err
)
238 exe
:= NIL; auto
:= FALSE
; jobs
:= 1; def
.next
:= NIL; mno
:= 0; rno
:= 0;
239 processor
:= anymach
; os
:= anyos
; compiler
:= anycp
;
241 CASE DswOpts
.GetOpt("ao:j:D:U:Th") OF
243 |
"o": exe
:= DswOpts
.str
244 |
"j": jobs
:= MIN(MAX(StrToInt(DswOpts
.str
, 1), 1), maxJobs
)
246 |
"D": Define(DswOpts
.str
)
247 |
"U": Undefine(DswOpts
.str
)
248 |
"T": ParseTargetOpts
249 |
":": Log
.String("missing argument for option -"); Log
.String(DswOpts
.str
); Log
.Ln
; INC(err
)
250 |
"?": Log
.String("unknown option -"); Log
.String(DswOpts
.str
); Log
.Ln
; INC(err
)
251 |
"$": AddModule(DswOpts
.str
, def
)
257 PROCEDURE CheckParams
;
259 IF compiler
= anycp
THEN
260 Log
.String("compiler not selected"); Log
.Ln
; INC(err
)
261 ELSIF compiler
= cpnative
THEN
262 IF processor
= anymach
THEN
263 Log
.String("processor not selected"); Log
.Ln
; INC(err
)
264 ELSIF processor
# mach386
THEN
265 Log
.String("processor not supported by native compiler"); Log
.Ln
; INC(err
)
268 IF (compiler
= cpfront
) & (linker
# anyint
) THEN
269 Log
.String("internal linker not required for cpfront"); Log
.Ln
; INC(err
)
271 IF (compiler
= cpfront
) & (exe
# NIL) THEN
272 Log
.String("cpfront can't out executable file"); Log
.Ln
; INC(err
)
274 IF (exe
# NIL) & (compiler
= cpnative
) & (linker
= anyint
) THEN
275 Log
.String("linker not selected"); Log
.Ln
; INC(err
)
277 IF (linker
= dev2
) & (os
= anyos
) THEN
278 Log
.String("os not selected"); Log
.Ln
; INC(err
)
280 IF (exe
# NIL) & (exe^
= "") THEN
281 Log
.String("output file name can't be empty"); Log
.Ln
; INC(err
)
285 (* --------- loader --------- *)
287 PROCEDURE Import (m
: Module
; IN name
: DevCPT
.Name
);
288 VAR i
, j
: INTEGER; imp
: Module
;
291 ASSERT(name
# "", 21);
292 IF debugImport
THEN Log
.String(" import "); Log
.String(name$
) END;
293 IF name
= "SYSTEM" THEN INCL(DevCPM
.options
, DevCPM
.sysImp
)
294 ELSIF name
= "COM" THEN INCL(DevCPM
.options
, DevCPM
.com
)
295 ELSIF name
= "JAVA" THEN INCL(DevCPM
.options
, DevCPM
.java
)
297 IF debugImport
THEN Log
.Char(" ") END;
298 i
:= 0; (* find module in local list *)
299 WHILE (i
< m
.mno
) & (m
.imp
[i
].name$
# name$
) DO INC(i
) END;
301 j
:= 0; (* find module in global list *)
302 WHILE (j
< mno
) & (modList
[j
].name$
# name$
) DO INC(j
) END;
304 NEW(imp
); imp
.name
:= name$
; imp
.selectors
:= CopySelectorList(m
.selectors
);
305 modList
[mno
] := imp
; INC(mno
)
309 m
.imp
[m
.mno
] := imp
; INC(m
.mno
)
313 IF debugImport
THEN Log
.Ln
END;
316 PROCEDURE ParseModule (m
: Module
);
317 VAR sym
: BYTE; SelfName
, impName
, aliasName
: DevCPT
.Name
;
319 PROCEDURE err (n
: SHORTINT);
323 PROCEDURE CheckSym(s
: SHORTINT);
325 IF sym
= s
THEN DevCPS
.Get(sym
) ELSE DevCPM
.err(s
) END
329 IF debugImport
THEN Log
.String("module " + m
.name
); Log
.Ln
END;
330 DevCPS
.Init
; DevCPS
.Get(sym
);
331 IF sym
= module
THEN DevCPS
.Get(sym
) ELSE err(16) END;
333 SelfName
:= DevCPS
.name$
; DevCPS
.Get(sym
);
335 INCL(DevCPM
.options
, DevCPM
.interface
); DevCPS
.Get(sym
);
336 IF sym
= eql
THEN DevCPS
.Get(sym
)
337 ELSE INCL(DevCPM
.options
, DevCPM
.noCode
)
339 IF sym
= string
THEN INCL(m
.flags
, library
); DevCPS
.Get(sym
)
345 IF sym
= import
THEN DevCPS
.Get(sym
);
348 aliasName
:= DevCPS
.name$
; impName
:= aliasName$
; DevCPS
.Get(sym
);
349 IF sym
= becomes
THEN DevCPS
.Get(sym
);
350 IF sym
= ident
THEN impName
:= DevCPS
.name$
; DevCPS
.Get(sym
) ELSE err(ident
) END
355 IF sym
= comma
THEN DevCPS
.Get(sym
)
356 ELSIF sym
= ident
THEN err(comma
)
367 PROCEDURE CheckModule (m
: Module
; source
: String
; OUT ok
: BOOLEAN);
372 DevCPM.symList := m.insym;
373 DevCPM.codePath := m.outcode;
374 DevCPM.symPath := m.outsym;
376 DevCPM
.name
:= m
.name$
;
378 IF m.found THEN INCL(DevCPM.options, DevCPM.comAware) END;
379 IF errorTrap IN m.opts THEN INCL(DevCPM.options, DevCPM.trap) END;
380 IF oberon IN m.opts THEN INCL(DevCPM.options, DevCPM.oberon) END;
383 s
:= m
.selectors
.next
;
385 DevCPR
.Set(s
.name
, s
.value
);
397 PROCEDURE GetSource (IN modName
: ARRAY OF CHAR; OUT path
: Files
.Name
; OUT s
: String
);
398 CONST modDir
= "Mod"; sysDir
= "System";
399 VAR dir
, name
: Files
.Name
; loc
: Files
.Locator
;
400 text
: DswDocuments
.Model
; r
: DswDocuments
.Reader
; i
, res
: INTEGER;
402 PROCEDURE MakePath (dir
, name
: Files
.Name
; type
: Files
.Type
; OUT path
: Files
.Name
);
404 ASSERT(name
# "", 21);
405 IF dir
= "" THEN path
:= modDir
+ "/" + name
406 ELSE path
:= dir
+ "/" + modDir
+ "/" + name
408 Kernel
.MakeFileName(path
, type
)
412 s
:= NIL; path
:= "";
413 Kernel
.SplitName(modName
, dir
, name
);
414 loc
:= Files
.dir
.This(dir
).This(modDir
);
415 (* --> Kernel.MakeFileName(name, Kernel.docType); <-- *)
416 MakePath(dir
, name
, "cp", path
);
417 DswDocuments
.Open(loc
, name
+ ".cp", text
, res
);
419 MakePath(dir
, name
, "odc", path
);
420 DswDocuments
.Open(loc
, name
+ ".odc", text
, res
);
421 IF (text
= NIL) & (dir
= "") THEN
422 MakePath(sysDir
, name
, "cp", path
);
423 loc
:= Files
.dir
.This(sysDir
).This(modDir
);
424 DswDocuments
.Open(loc
, name
+ ".cp", text
, res
);
426 MakePath(sysDir
, name
, "odc", path
);
427 DswDocuments
.Open(loc
, name
+ ".odc", text
, res
);
435 NEW(s
, text
.Length() + 1);
437 r
:= text
.NewReader(NIL);
438 FOR i
:= 0 TO text
.Length() - 1 DO
439 r
.Read
; s
[i
] := r
.char
445 PROCEDURE Trace (m
, parent
: Module
; VAR lno
: INTEGER);
448 IF ~
(trace
IN m
.flags
) THEN
449 INCL(m
.flags
, trace
);
450 FOR i
:= 0 TO m
.mno
- 1 DO
451 Trace(m
.imp
[i
], m
, lno
);
452 m
.depth
:= MAX(m
.depth
, m
.imp
[i
].depth
+ 1)
454 IF ~
(imported
IN m
.flags
) THEN
455 INCL(m
.flags
, imported
);
461 Log
.String("recursive import of " + m
.name
+ " in " + parent
.name
); Log
.Ln
; INC(err
)
466 VAR i
, j
: INTEGER; m
: Module
;
468 ASSERT((mno
= 0) OR (lnkList
[0] # NIL), 20);
474 WHILE (j
>= 0) & (cmpList
[j
].depth
> m
.depth
) DO
475 cmpList
[j
+ 1] := cmpList
[j
];
484 VAR i
, j
, num
: INTEGER; m
: Module
; s
: String
; ok
: BOOLEAN;
487 WHILE (err
= 0) & (i
< mno
) DO
489 GetSource(m
.name$
, m
.path
, s
);
491 CheckModule(m
, s
, ok
);
492 IF ~ok
THEN INC(err
) END
494 Log
.String("unable to open module " + m
.name
); Log
.Ln
; INC(err
)
499 FOR i
:= 0 TO rno
- 1 DO
500 Trace(modList
[i
], modList
[i
], num
)
502 ASSERT((err
# 0) OR (num
= mno
), 100);
505 Log
.String("Parallel depth:"); Log
.Ln
;
506 FOR i
:= 0 TO mno
- 1 DO
507 Log
.String(" " + cmpList
[i
].name
); Log
.Int(cmpList
[i
].depth
); Log
.Ln
;
512 PROCEDURE IsCompiled (m
: Module
): BOOLEAN;
513 CONST target
= {hasSym
, hasObj
};
514 VAR i
: INTEGER; ready
: BOOLEAN;
518 ready
:= ~
(hasErrors
IN m
.flags
) & (m
.flags
* target
= target
);
519 WHILE ready
& (i
< m
.mno
) DO
520 ready
:= IsCompiled(m
.imp
[i
]);
526 PROCEDURE Ready (m
: Module
): BOOLEAN;
527 CONST target
= {hasSym
, hasObj
};
528 VAR i
: INTEGER; ready
: BOOLEAN;
531 ready
:= ~
(hasErrors
IN m
.flags
) & (m
.flags
* target
# target
) & (m
.worker
= NIL);
532 WHILE ready
& (i
< m
.mno
) DO
533 ready
:= IsCompiled(m
.imp
[i
]);
539 PROCEDURE ExecuteCompiler (m
: Module
): DswProcs
.Process
;
540 VAR w
: DswProcs
.Process
; ok
: BOOLEAN;
543 ASSERT(m
.path
# "", 21);
544 ASSERT(m
.worker
= NIL, 22);
545 w
:= DswProcs
.dir
.New();
547 | cpnative
: w
.Program("cpc486")
548 | cpfront
: w
.Program("cpfront")
550 w
.PutParam("-legacy");
554 Log
.String("Compile " + m
.name
+ " (" + m
.path
+ ")"); Log
.Ln
;
562 VAR i
, j
, num
: INTEGER; ok
: BOOLEAN; m
: Module
; w
: DswProcs
.Process
;
564 IF mno
= 0 THEN RETURN END;
566 WHILE (err
= 0) & (num
< mno
) OR (j
> 0) DO
568 WHILE (err
= 0) & (i
< mno
) & (j
< jobs
) DO
571 w
:= ExecuteCompiler(m
);
572 IF debugJobs
THEN Log
.String("Start job " + m
.name
) END;
574 IF debugJobs
THEN Log
.String(" ok") END;
578 IF debugJobs
THEN Log
.String(" fail") END;
579 INCL(m
.flags
, hasErrors
);
582 IF debugJobs
THEN Log
.Ln
END
586 WHILE (err
= 0) & (j
>= jobs
) OR (j
> 0) DO
588 WHILE (j
> 0) & (i
< mno
) DO
591 IF (w
# NIL) & w
.IsTerminated() THEN
592 IF debugJobs
THEN Log
.String("Stop job " + m
.name
); Log
.Int(w
.Result()); Log
.Ln
END;
593 IF w
.Result() = 0 THEN
594 INCL(m
.flags
, hasObj
);
595 INCL(m
.flags
, hasSym
);
598 INCL(m
.flags
, hasErrors
);
611 VAR p
: DswProcs
.Process
; i
, res
: INTEGER; ok
: BOOLEAN;
613 ASSERT((exe
# NIL) & (exe^
# ""), 20);
614 ASSERT(processor
= mach386
, 21);
615 ASSERT(compiler
= cpnative
, 22);
616 ASSERT(os
IN {linux
, freebsd
, openbsd
, win32
}, 23);
617 p
:= DswProcs
.dir
.New();
622 | linux
: p
.PutParam("linux")
623 | freebsd
: p
.PutParam("freebsd")
624 | openbsd
: p
.PutParam("openbsd")
625 | win32
: p
.PutParam("win32")
628 p
.PutParam("-kernel");
629 p
.PutParam("Kernel");
631 p
.PutParam("Kernel");
632 p
.PutParam("-legacycodedir");
638 IF ~
(library
IN lnkList
[i
].flags
) THEN
639 p
.PutParam(lnkList
[i
].name$
)
645 Log
.String("Link "); Log
.String(exe
); Log
.Ln
;
648 Log
.String("linker terminated with error"); Log
.Int(res
); Log
.Ln
;
652 Log
.String("unable to execute linker"); Log
.Int(i
); Log
.Ln
;
661 | anyint
: (* do not link *)
668 VAR m
: Module
; s
: Selector
; p
: DswProcs
.Process
; ok
: BOOLEAN; i
, res
: INTEGER;
670 IF Kernel
.trapCount
= 0 THEN
686 IF err
= 0 THEN Kernel
.Quit(0)
696 ==============================
699 cpmake
{options module
}
702 -a Enable automatic dependency resolution
703 -o name Generate executable file
704 -j num Specifies the number of jobs to run simultaneously
705 -D ident
["+"|
"-"] Add preprocessor selector
706 -U ident Remove proprocessor selector