1 (***********************************************************************)
2 (* Component Pascal Make Tool *)
4 (* Diane Corney, 20th July 1999 *)
8 (***********************************************************************)
34 ArgString
= ARRAY 256 OF CHAR;
36 args
: POINTER TO ARRAY OF ArgString
;
44 startT
, endT
: LONGINT;
47 toDoList
, compList
: MH
.ModList
;
57 PROCEDURE Chuck(IN msg
: ARRAY OF CHAR);
59 Error
.WriteString('CPMake
: "');
60 Error.WriteString(msg);
61 Error.WriteString('" Halting
...'
);
62 Error
.WriteLn
; HALT(1);
65 PROCEDURE Warn(IN msg
: ARRAY OF CHAR);
67 Console
.WriteString('CPMake
: '
);
68 Console
.WriteString(msg
); Console
.WriteLn
;
72 CONST jPre
= "cprun ";
73 str1
= "Usage: CPMake [";
74 str2
= "all] [gpcp-options] <ModuleName>";
75 str3
= " For gpcp-options, type: ";
80 Console
.WriteString("gardens point CPMake: " + GPCPcopyright
.verStr
);
82 isNt
:= RTS
.defaultTarget
= "net";
83 IF ~isNt
THEN Console
.WriteString(jPre
) END;
84 Console
.WriteString(str1
);
85 Console
.Write(GPFiles
.optChar
);
86 Console
.WriteString(str2
);
88 Console
.WriteString(str3
);
89 IF ~isNt
THEN Console
.WriteString(jPre
) END;
90 Console
.WriteString(str4
);
91 Console
.Write(GPFiles
.optChar
);
92 Console
.WriteString(str5
);
96 PROCEDURE ReadModuleName(VAR name
: ARRAY OF CHAR);
98 i
, pos
, parNum
, numArgs
: INTEGER;
101 numArgs
:= ProgArgs
.ArgNumber();
103 CompState
.InitOptions();
109 NEW(args
.args
, numArgs
-1);
110 FOR parNum
:= 0 TO numArgs
-2 DO
111 ProgArgs
.GetArg(parNum
,opt
);
112 IF (opt
[0] = '
-'
) OR (opt
[0] = GPFiles
.optChar
) THEN
117 CPascal
.DoOption(opt
);
118 args
.args
[args
.argNum
] := opt
;
122 Console
.WriteString("Unknown option: " + opt
);
127 ProgArgs
.GetArg(numArgs
-1,name
);
128 IF (name
[0] = '
-'
) OR (name
[0] = GPFiles
.optChar
) THEN
133 WHILE (name
[i
] # '
.'
) & (name
[i
] # 0X
) & (i
< LEN(name
)) DO INC(i
); END;
134 IF (i
< LEN(name
)) & (name
[i
] = '
.'
) THEN
135 WHILE (name
[i
] # 0X
) & (i
< LEN(name
)) DO
136 name
[i
] := 0X
; INC(i
);
141 PROCEDURE Check (sym
: INTEGER; mod
: MH
.ModInfo
);
143 IF token
.sym
# sym
THEN
144 S
.ParseErr
.Report(sym
,token
.lin
,token
.col
);
145 GPBinFiles
.CloseFile(S
.src
);
146 CPascal
.FixListing();
148 Chuck("Parse error(s) in module <" + mod
.name^
+ ">");
152 PROCEDURE DoImport(mod
: MH
.ModInfo
; VAR mainImported
: BOOLEAN);
157 strng
, impNm
: MH
.ModName
;
159 Check(G
.identSym
,mod
);
161 token
:= S
.get(); (* read past ident *)
162 IF (token
.sym
= G
.colonequalSym
) THEN
163 last
:= S
.get(); (* read past ":=" *)
164 token
:= S
.get(); (* read past ident *)
166 IF last
.sym
= G
.identSym
THEN
167 mName
:= LitValue
.subStrToCharOpen(last
.pos
, last
.len
);
168 ELSIF last
.sym
= G
.stringSym
THEN
169 strng
:= LitValue
.subStrToCharOpen(last
.pos
+1, last
.len
-2);
170 ForeignName
.ParseModuleString(strng
, impNm
);
174 Chuck("Bad module name for alias import");
176 IF (NameHash
.enterSubStr(last
.pos
, last
.len
) = NameHash
.mainBkt
) OR
177 (NameHash
.enterSubStr(last
.pos
, last
.len
) = NameHash
.winMain
) THEN
178 mainImported
:= TRUE
;
180 aMod
:= MH
.GetModule(mName
);
181 MH
.Add(mod
.imports
,aMod
);
182 MH
.Add(aMod
.importedBy
,mod
);
183 IF ~aMod
.importsLinked
THEN MH
.Add(toDoList
,aMod
); END;
187 PROCEDURE LinkImports(mod
: MH
.ModInfo
);
189 mName
: FileNames
.NameString
;
190 cpmainImported
: BOOLEAN;
193 CompState
.InitCompState(mod
.name^
+ ".cp");
194 mod
.importsLinked
:= TRUE
;
195 cpmainImported
:= FALSE
;
198 IF (token
.sym
= G
.identSym
) THEN
199 hsh
:= NameHash
.enterSubStr(token
.pos
,token
.len
);
200 IF (hsh
= sysBkt
) OR (hsh
= frnBkt
) THEN
201 mod
.isForeign
:= TRUE
;
205 Check(G
.MODULESym
,mod
); token
:= S
.get();
206 Check(G
.identSym
,mod
);
207 S
.GetString(token
.pos
,token
.len
,mName
);
208 IF (mName
# mod
.name^
) THEN
209 Chuck("File " + mod
.name^
+ ".cp does not contain MODULE " + mName
);
212 IF token
.sym
= G
.lbrackSym
THEN
213 (* mod.isForeign := TRUE; *)
214 token
:= S
.get(); (* skip string and rbracket *)
218 Check(G
.semicolonSym
,mod
); token
:= S
.get();
219 IF (token
.sym
= G
.IMPORTSym
) THEN
221 DoImport(mod
,cpmainImported
);
222 WHILE (token
.sym
= G
.commaSym
) DO
224 DoImport(mod
,cpmainImported
);
227 IF (mod
= graph
) & ~cpmainImported
THEN
228 Warn("WARNING: " + mod
.name^
+ " is not a base module.");
229 Warn("Modules that " + mod
.name^
+ " depends on will be checked for consistency");
230 Warn("Modules that depend on " + mod
.name^
+ " will not be checked or recompiled");
234 PROCEDURE BuildGraph() : BOOLEAN;
236 name
: FileNames
.NameString
;
238 nextModule
: MH
.ModInfo
;
242 ReadModuleName(name
);
243 graph
:= MH
.GetModule(BOX(name$
));
244 S
.src
:= GPBinFiles
.findLocal(graph
.name^
+ ".cp");
246 Chuck("Could not find base file <" + graph
.name^
+ ".cp>");
248 GPBinFiles
.CloseFile(S
.src
);
250 MH
.Add(toDoList
,graph
);
252 WHILE (nextIx
< toDoList
.tide
) DO
253 nextModule
:= toDoList
.list
[nextIx
]; INC(nextIx
);
254 S
.src
:= GPBinFiles
.findLocal(nextModule
.name^
+ ".cp");
255 SF
.OpenSymbolFile(nextModule
.name
, S
.src
= NIL);
257 IF SF
.file
= NIL THEN
258 Chuck("Cannot find source file <" + nextModule
.name^
+
259 ".cp> or symbol file <" + nextModule
.name^
+
260 ".cps> on CPSYM path.");
262 SF
.ReadSymbolFile(nextModule
,FALSE
);
265 LinkImports(nextModule
);
266 IF force
OR (SF
.file
= NIL) OR ~GPFiles
.isOlder(S
.src
,SF
.file
) THEN
267 nextModule
.compile
:= TRUE
;
270 * Console.WriteString("force: Setting compile flag on ");
271 * Console.WriteString(nextModule.name);
273 * ELSIF (SF.file = NIL) THEN
274 * Console.WriteString("file=NIL: Setting compile flag on ");
275 * Console.WriteString(nextModule.name);
277 * ELSIF ~GPFiles.isOlder(S.src,SF.file) THEN
278 * Console.WriteString("isOlder: Setting compile flag on ");
279 * Console.WriteString(nextModule.name);
284 SF
.ReadSymbolFile(nextModule
,TRUE
);
286 SF
.CloseSymFile(); (* or .NET barfs! *)
291 Console
.WriteString("#cpmake: ");
292 Console
.WriteString(RTS
.getStr(buildX
));
297 PROCEDURE CompileModule(mod
: MH
.ModInfo
; VAR retVal
: INTEGER);
301 CompState
.InitOptions();
302 FOR i
:= 0 TO args
.argNum
-1 DO
303 CPascal
.DoOption(args
.args
[i
]);
305 IF mod
.isForeign
THEN
306 IF ~CompState
.quiet
THEN
308 "#cpmake: " + mod
.name^
+ " is foreign, compiling with -special.");
311 "#cpmake: Foreign implementation may need recompilation.");
314 CPascal
.DoOption("-special");
315 ELSIF ~CompState
.quiet
THEN
316 Console
.WriteString("#cpmake: compiling " + mod
.name^
);
319 CPascal
.Compile(mod
.name^
+ ".cp",retVal
);
320 mod
.key
:= NewSymFileRW
.GetLastKeyVal();
324 PROCEDURE DFS(VAR node
: MH
.ModInfo
);
331 FOR ix
:= 0 TO node
.imports
.tide
-1 DO
332 DFS(node
.imports
.list
[ix
]);
336 CompileModule(node
,retVal
);
338 Chuck("Compile errors in module <" + node
.name^
+ ">");
341 FOR ix
:= 0 TO node
.importedBy
.tide
-1 DO
342 imp
:= node
.importedBy
.list
[ix
];
343 IF (~imp
.compile
) & (node
.key
# MH
.GetKey(imp
,node
)) THEN
344 node
.importedBy
.list
[ix
].compile
:= TRUE
;
350 PROCEDURE WalkGraph(VAR node
: MH
.ModInfo
);
354 Console
.WriteString("#cpmake: ");
355 Console
.WriteString(RTS
.getStr(compX
));
362 NameHash
.InitNameHash(0);
363 sysBkt
:= NameHash
.enterStr("SYSTEM");
364 frnBkt
:= NameHash
.enterStr("FOREIGN");
365 CPascalErrors
.Init();
366 buildOK
:= BuildGraph();
368 startT
:= RTS
.GetMillis();
370 endT
:= RTS
.GetMillis();
371 Console
.WriteString("#cpmake: ");
372 IF compCount
= 0 THEN
373 Console
.WriteString("no re-compilation required.");
374 ELSIF compCount
= 1 THEN
375 Console
.WriteString("one module compiled.");
377 Console
.WriteInt(compCount
,1);
378 Console
.WriteString(" modules compiled.");
381 CompState
.TimeMsg("Total Compilation Time ", endT
- startT
);