CcCommandsImpl.Mesa
Copyright Ó 1988, 1991 by Xerox Corporation. All rights reserved.
Eduardo Pelegri-Llopart, February 7, 1990 9:34:12 am PST
Carl Hauser, May 23, 1988 2:42:05 pm PDT
Bill Jackson (bj) July 5, 1988 8:36:20 pm PDT
The module should be reorganized to be more rational.
Spreitze, March 13, 1990 1:17 pm PST
DIRECTORY
Args USING [ Arg, ArgRope, Error, GetRope, NArgs ],
Ascii,
BasicTime USING [ GMT ],
Commander USING [ CommandProc, Register ],
CommandTool USING [ CurrentWorkingDirectory ],
Convert,
ExtendADotOut USING [ ActionID, ActionIDFromAction, DependencyInfo, DependencyInfoRep, ObjectClassFromFileName, ObjectIDFromFile, ObjectID, PutDependencyInfo, StampFromIDs, VersionStamp ],
FS USING [ ComponentPositions, Delete, Error, ExpandName, Rename, StreamOpen ],
IO USING [ card, Close, Flush, GetRope, int, PutF, PutFR, PutRope, rope, STREAM ],
PBasics USING [LowHalf, LowByte, HighByte, BITAND, endianBitsInBytes],
PFS, PFSNames, PFSPrefixMap,
Process USING [ CheckForAbort, EnableAborts, InitializeCondition, SecondsToTicks ],
Rope USING [ Cat, Concat, Equal, Fetch, FindBackward, Flatten, Length, ROPE, Substr, Translate],
SymTab,
SystemVersion USING [machineType, MachineType],
ThisMachine USING [ ProcessorID ],
UnixErrno,
UnixStat,
UnixSysCalls USING [ GetPID, SymLink, Unlink ],
UnixSysCallExtensions USING [Spawn],
UnixTypes USING [CHARPtr, SysCallResult],
UserProfile USING [Token],
UXStrings;
CcCommandsImpl: CEDAR MONITOR
IMPORTS Args, Ascii, Commander, CommandTool, Convert, ExtendADotOut, FS, IO, PBasics, PFS, PFSNames, PFSPrefixMap, Process, Rope, SymTab, SystemVersion, ThisMachine, UnixErrno, UnixSysCalls, UnixSysCallExtensions, UserProfile, UXStrings ~ {
ROPE: TYPE ~ Rope.ROPE;
LOR: TYPE ~ LIST OF ROPE;
ShouldNotHappen: ERROR [message: ROPE] ~ CODE;
ForkTrouble: ERROR ~ CODE;
NYI: ERROR ~ CODE;
DeleteFiles: BOOL ~ TRUE;
Temporarily until I change SystemVersion.MachineType;
mot88000: SystemVersion.MachineType ~ LOOPHOLE[SystemVersion.MachineType[14]];
amd29000: SystemVersion.MachineType ~ LOOPHOLE[20, SystemVersion.MachineType];
r2000: SystemVersion.MachineType ~ LOOPHOLE[SystemVersion.MachineType[30]];
r3000: SystemVersion.MachineType ~ LOOPHOLE[SystemVersion.MachineType[31]];
i386: SystemVersion.MachineType ~ LOOPHOLE[SystemVersion.MachineType[40]];
i486: SystemVersion.MachineType ~ LOOPHOLE[SystemVersion.MachineType[41]];
i860: SystemVersion.MachineType ~ LOOPHOLE[SystemVersion.MachineType[42]];
i960: SystemVersion.MachineType ~ LOOPHOLE[SystemVersion.MachineType[43]];
Unique names for temporary (unix-host) files
uid: CARD32 ¬ 0;
processID: INT ~ UnixSysCalls.GetPID[];
processorID: ROPE ~ ThisMachine.ProcessorID[$Octal];
CshCommandString: UXStrings.UnixString ~ UXStrings.Create[from: "/bin/csh -s"];
MACHINECLASS: ROPE ~ "ComplexCc.MachineClass";
NewName: ENTRY PROC [suffix: ROPE ¬ ".o", wDir: ROPE] RETURNS [ fName: ROPE ] ~ {
ENABLE { UNWIND => NULL };
fName ¬ IO.PutFR["cedarCc%gFrom%g%g", IO.card[uid], IO.int[processID], IO.rope[processorID], IO.rope[suffix]];
IF NOT Rope.Equal[wDir, NIL] THEN {
IF wDir.Fetch[wDir.Length[]-1] # '/ THEN wDir ¬ wDir.Cat["/"];
fName ¬ wDir.Cat[fName];
};
uid ¬ uid.SUCC;
};
Making filenames acceptable to UNIX
ViewFix: PROC [cedar, insert: ROPE, isDir, simpleExt, create: BOOL, otherUnlink: LOR] RETURNS [unix: ROPE ¬ NIL, unlink: LOR ¬ NIL] ~ {
ENABLE PFS.Error => ERROR ShouldNotHappen[IO.PutFR["Got PFS.Error[%g, %g] while UXifying %g", [atom[error.code]], [rope[error.explanation]], [rope[cedar]] ]];
given: PFS.PATH ~ PFS.PathFromRope[cedar];
translated: PFS.PATH ~ PFSPrefixMap.Translate[ PFS.AbsoluteName[given]];
cedarPath: PFS.PATH ~ IF isDir THEN PFSNames.EnsureDirectory[translated] ELSE translated; --EnsureDirectory only required because Translate bogusly drops that bit (MJS March 13, 1990)
rawRope: ROPE ~ PFS.RopeFromPath[cedarPath].Flatten[]; --for debugging
viewComp: PFSNames.Component ~ cedarPath.Fetch[0];
view: ROPE ~ viewComp.ComponentRope[];
IF isDir # given.IsADirectory[] THEN ERROR ShouldNotHappen[IO.PutFR[IF isDir THEN "%g not a directory" ELSE "%g is a directory", [rope[cedar]] ]];
IF isDir AND (insert#NIL OR create OR simpleExt) THEN ERROR--not implemented because not needed--;
SELECT TRUE FROM
view.Equal["-ux", FALSE] => {
viewless: PFS.PATH ~ cedarPath.ReplaceComponent[0, emptyComponent];
parent: PFS.PATH ~ viewless.Parent[];
parentRope: ROPE ~ PFS.RopeFromPath[parent];
last: PFSNames.Component ~ viewless.ShortName[];
lastRope: ROPE ~ last.ComponentRope[--PFS doesn't put in version info--];
original: ROPE ~ parentRope.Concat[lastRope];
IF insert#NIL THEN {
new: ROPE ~ parentRope.Cat[insert, lastRope];
GetLink[original, new];
RETURN [new, CONS[new, otherUnlink]]};
RETURN [original, otherUnlink]};
view.Equal["-vux", FALSE] => {
full, parent: PFS.PATH;
fullLast: PFSNames.Component;
fullRope, parentRope, verfulLast, verlessLast, vuxrepRope, uxishRope: ROPE;
IF create THEN {
out: IO.STREAM ~ PFS.StreamOpen[fileName: cedarPath, accessOptions: create];
file: PFS.OpenFile ~ PFS.OpenFileFromStream[out];
modeProp: ROPE;
dm: UnixStat.Mode;
full ¬ PFS.GetInfo[file].fullFName;
modeProp ¬ PFS.GetClientProperty[file, "UnixMode"];
dm ¬ LOOPHOLE[Convert.CardFromRope[modeProp]];
dm.owner.write ¬ true;
PFS.SetClientProperty[file, "UnixMode", Convert.RopeFromCard[LOOPHOLE[dm, CARD16], 8]];
out.Close[]}
ELSE IF isDir THEN {
full ¬ cedarPath.ReplaceComponent[0, emptyComponent];
unix ¬ PFS.RopeFromPath[full].Translate[translator: Lower];
RETURN [unix, otherUnlink]}
ELSE full ¬ PFS.FileInfo[cedarPath].fullFName;
fullRope ¬ PFS.RopeFromPath[full].Flatten[]; --for debugging
fullLast ¬ full.ShortName[];
parent ¬ full.Parent[].ReplaceComponent[0, emptyComponent];
parentRope ¬ PFS.RopeFromPath[parent].Translate[translator: Lower];
IF NOT parent.IsADirectory[] THEN ERROR ShouldNotHappen["PFS shouldn't be crocky!"];
IF fullLast.version.versionKind # numeric THEN ERROR ShouldNotHappen[
IO.PutFR["Didn't expect to find %g in file system (note version!)",
[rope[PFS.RopeFromPath[full]]] ]];
verlessLast ¬ fullLast.ComponentRope[--PFS doesn't put in version info--];
verfulLast ¬ IO.PutFR["%g.~%g~", [rope[verlessLast.Translate[translator: Lower]]], [integer[fullLast.version.version]]];
vuxrepRope ¬ parentRope.Cat[verfulLast];
IF simpleExt OR insert#NIL THEN {
uxishRope ¬ parentRope.Cat[insert, verlessLast];
GetLink[vuxrepRope, uxishRope];
RETURN [uxishRope, CONS[uxishRope, otherUnlink]]}
ELSE RETURN [vuxrepRope, otherUnlink];
};
ENDCASE => ERROR ShouldNotHappen[
IO.PutFR["Can't apply UNIX tools to %g because of its view",
IO.rope[PFS.RopeFromPath[cedarPath]] ]];
};
emptyComponent: PFSNames.Component ~ [];
Lower: PROC [old: CHAR] RETURNS [CHAR] ~ {RETURN Ascii.Lower[old]};
LinkData: TYPE ~ REF LinkDataRec;
LinkDataRec: TYPE ~ RECORD [
from: ROPE,
count: NAT,
toCP: UnixTypes.CHARPtr ¬ [],
change: CONDITION];
GetLink: ENTRY PROC [from, to: ROPE] ~ {
ENABLE UNWIND => NULL;
ld: LinkData ¬ NARROW[linkTab.Fetch[to].val];
IF ld=NIL THEN {
ld ¬ NEW [LinkDataRec ¬ [NIL, 0]];
TRUSTED {
Process.InitializeCondition[@ld.change, Process.SecondsToTicks[10]];
Process.EnableAborts[@ld.change]};
IF NOT linkTab.Insert[to, ld] THEN ERROR};
DO SELECT TRUE FROM
ld.count=0 => {
fromCP: UnixTypes.CHARPtr ~ UXStrings.Create[from];
toCP: UnixTypes.CHARPtr ¬ ld.toCP ¬ UXStrings.Create[to];
res: UnixTypes.SysCallResult ¬ UnixSysCalls.SymLink[fromCP, toCP];
IF res=failure THEN RETURN WITH ERROR ShouldNotHappen[
IO.PutFR["Link from %g to %g failed; errno is %g",
IO.rope[from],
IO.rope[to],
IO.card[LOOPHOLE[UnixErrno.GetErrno[], CARD]]]];
ld.count ¬ ld.count.SUCC;
ld.from ¬ ld.from;
RETURN};
ld.from.Equal[from] => {ld.count ¬ ld.count.SUCC; RETURN};
ENDCASE => WAIT ld.change ENDLOOP;
};
linkTab: SymTab.Ref ~ SymTab.Create[case: TRUE];
DropLink: ENTRY PROC [to: ROPE] ~ {
ENABLE UNWIND => NULL;
ld: LinkData ¬ NARROW[linkTab.Fetch[to].val];
IF ld=NIL OR ld.count=0 THEN RETURN WITH ERROR ShouldNotHappen[IO.PutFR["Excess dropping of link to %g", [rope[to]] ]];
ld.count ¬ ld.count.PRED;
BROADCAST ld.change;
IF ld.count=0 THEN {
res: UnixTypes.SysCallResult ~ UnixSysCalls.Unlink[ld.toCP];
IF NOT linkTab.Delete[to] THEN ERROR;
IF res = failure THEN RETURN WITH ERROR ShouldNotHappen[
IO.PutFR["Unlink failed for %g; errno is %g",
IO.rope[to],
IO.card[LOOPHOLE[UnixErrno.GetErrno[], CARD]]]];
};
RETURN};
UnlinkList: PROC [list: LOR] ~ {
FOR list ¬ list, list.rest WHILE list#NIL DO
DropLink[list.first];
ENDLOOP;
RETURN};
ConsComponent: PROC [name: ROPE, version: PFSNames.Version] RETURNS [PFSNames.Component] ~ {
RETURN [[name: [base: name, start: 0, len: name.Length[]], version: version]]};
Auxiliary Execution Procs.
MachineTypeFromMachineClass: PROC [ machineClass: ROPE ]
RETURNS [ machineType: SystemVersion.MachineType ] ~ {
SELECT TRUE FROM
Rope.Equal[machineClass, "sparc", FALSE] => machineType ¬ sun4;
Rope.Equal[machineClass, "mc68020", FALSE] => machineType ¬ sun3;
Rope.Equal[machineClass, "sun4", FALSE] => machineType ¬ sun4;
Rope.Equal[machineClass, "sun3", FALSE] => machineType ¬ sun3;
Rope.Equal[machineClass, "amd29000", FALSE] => machineType ¬ amd29000;
ENDCASE => ERROR;
};
MachineClassFromMachineType: PROC [ machineType: SystemVersion.MachineType ]
RETURNS [ machineClass: ROPE ] ~ {
SELECT machineType FROM
sun4 => machineClass ¬ "sun4";
sun3 => machineClass ¬ "sun3";
amd29000 => machineClass ¬ "amd29000";
ENDCASE => machineClass ¬ "I don't know";
};
GetCommandNames: PROC [host, target: SystemVersion.MachineType] RETURNS [compiler, loader, move, csh: ROPE ¬ NIL] ~ {
CompilerDefault: ROPE ~ "/usr/local/bin/ccc";
MoveDefault: ROPE ~ "/bin/mv";
LoadDefault: ROPE ~ "/bin/ld";
CshDefault: ROPE ~ "/bin/csh -s";
targetName: ROPE ~ MachineClassFromMachineType[ target ];
IF host # sun4 THEN ERROR ShouldNotHappen ["host is not a sun4"];
compiler ¬ UserProfile.Token["ComplexCc.cc", CompilerDefault];
loader ¬ UserProfile.Token["ComplexCc.ld", LoadDefault];
move ¬ UserProfile.Token["ComplexCc.mv", MoveDefault];
csh ¬ UserProfile.Token["ComplexCc.csh", CshDefault];
compiler ¬ UserProfile.Token[Rope.Cat["ComplexCc.", targetName, ".cc"], compiler];
loader ¬ UserProfile.Token[Rope.Cat["ComplexCc.", targetName, ".ld"], loader];
move ¬ UserProfile.Token[Rope.Cat["ComplexCc.", targetName, ".mv"], move];
csh ¬ UserProfile.Token[Rope.Cat["ComplexCc.", targetName, ".csh"], csh];
};
UnixNil: UnixTypes.CHARPtr ~ LOOPHOLE[NIL];
MsgFromExitError: PROC [status: INT, command: ROPE] RETURNS [msg: ROPE] ~ {
lowHalf: CARD16 ~ PBasics.LowHalf[LOOPHOLE[status, CARD32]];
lowByte: BYTE ~ PBasics.LowByte[lowHalf];
nextLowByte: BYTE ~ PBasics.HighByte[lowHalf];
low7: BYTE;
IF lowByte = 177B THEN {
msg ¬ IO.PutFR["execution of %g stopped by signal %g\n", IO.rope[command], IO.int[nextLowByte]];
RETURN [msg];
};
IF lowByte = 0 THEN {
msg ¬ IO.PutFR["execution of %g exited with %g\n", IO.rope[command], IO.int[nextLowByte]];
RETURN [msg];
};
SELECT PBasics.endianBitsInBytes FROM
big => low7 ¬ PBasics.BITAND[lowByte, 077B];
little => low7 ¬ PBasics.BITAND[lowByte, 176B];
ENDCASE => ERROR;
msg ¬ IO.PutFR["execution of %g terminated due to signal %g\n", IO.rope[command], IO.int[low7]];
};
MsgFromFile: PROC [fileName: ROPE, delete: BOOL ¬ TRUE] RETURNS [msg: ROPE] ~ {
stream: IO.STREAM;
stream ¬ FS.StreamOpen[fileName: fileName !FS.Error => { stream ¬ NIL; CONTINUE }];
IF stream # NIL THEN {
msg ¬ stream.GetRope[];
stream.Close[];
IF delete THEN FS.Delete[name: fileName !FS.Error => CONTINUE];
};
};
<<HideNamesThroughLink: PROC [dir: ROPE, files: LIST OF ROPE] ~ {
Strictly speaking this operation should be monitored against other concurrent operations; in practice, the problem should never arise
FOR list: LIST OF ROPE ¬ files, list.rest WHILE list # NIL DO
file: ROPE ~ list.first;
sourceRope: ROPE ~ Rope.Cat[dir, file];
destinationRope: ROPE ~ Rope.Cat[dir, "FILE-", file];
source: UnixTypes.CHARPtr ~ UXStrings.Create[sourceRope];
destination: UnixTypes.CHARPtr ~ UXStrings.Create[destinationRope];
res: UnixTypes.SysCallResult ~ UnixSysCalls.SymLink[source, destination];
IF res = failure THEN
ERROR ShouldNotHappen[
IO.PutFR["Link from %g to %g failed; errno is %g",
IO.rope[destinationRope],
IO.rope[sourceRope],
IO.card[LOOPHOLE[UnixErrno.GetErrno[], CARD]]]];
ENDLOOP;
};
UnlinkNames: PROC [dir: ROPE, files: LIST OF ROPE] ~ {
FOR list: LIST OF ROPE ¬ files, list.rest WHILE list # NIL DO
file: ROPE ~ list.first;
sourceRope: ROPE ~ Rope.Cat[dir, "FILE-", file];
source: UnixTypes.CHARPtr ~ UXStrings.Create[sourceRope];
res: UnixTypes.SysCallResult ~ UnixSysCalls.Unlink[source];
IF res = failure THEN
ERROR ShouldNotHappen[
IO.PutFR["Unlink failed for %g; errno is %g",
IO.rope[sourceRope],
IO.card[LOOPHOLE[UnixErrno.GetErrno[], CARD]]]];
ENDLOOP;
};>>
Execute: PROC [command: ROPE, wDir: ROPE ¬ NIL] RETURNS [status: INT, msg: ROPE ¬ NIL] ~ {
newCommand: ROPE ~ IF wDir.Equal[NIL] THEN command ELSE Rope.Cat["cd ", wDir, " ; ", command];
string: UXStrings.UnixString ~ UXStrings.Create[from: newCommand];
ropeStdErr: ROPE ~ NewName[".stderr", wDir];
stringStdErr: UXStrings.UnixString ~ UXStrings.Create[from: ropeStdErr];
ropeStdOut: ROPE ~ NewName[".stdout",wDir];
stringStdOut: UXStrings.UnixString ~ UXStrings.Create[from: ropeStdOut];
status ¬ UnixSysCallExtensions.Spawn[string, UnixNil, stringStdOut, stringStdErr];
IF status # 0 THEN msg ¬ MsgFromExitError[status: status, command: command];
msg ¬ Rope.Cat[msg, MsgFromFile[fileName: ropeStdErr, delete: DeleteFiles]];
msg ¬ Rope.Cat[msg, MsgFromFile[fileName: ropeStdOut, delete: DeleteFiles]];
};
ExecuteCsh: PROC [hostType, targetType: SystemVersion.MachineType, commandLines: ROPE, wDir: ROPE ¬ NIL] RETURNS [status: INT, msg: ROPE ¬ NIL] ~ {
cshCommandRope: ROPE ~ GetCommandNames[ host: hostType, target: targetType].csh;
cshCommandString: UnixTypes.CHARPtr ~ UXStrings.Create[cshCommandRope].string;
IF cshCommandRope = NIL
THEN ERROR ShouldNotHappen[IO.PutFR[
"Cshell execution on target of class %g cannot be done from host of class %g", IO.rope[MachineClassFromMachineType[targetType]],
IO.rope[MachineClassFromMachineType[hostType]],
]];
{
ropeStdIn: ROPE ~ NewName[".stdin", wDir];
stringStdIn: UXStrings.UnixString ~ UXStrings.Create[from: ropeStdIn];
ropeStdErr: ROPE ~ NewName[".stderr", wDir];
stringStdErr: UXStrings.UnixString ~ UXStrings.Create[from: ropeStdErr];
ropeStdOut: ROPE ~ NewName[".stdout", wDir];
stringStdOut: UXStrings.UnixString ~ UXStrings.Create[from: ropeStdOut];
streamIn: IO.STREAM ~ FS.StreamOpen[fileName: ropeStdIn, accessOptions: $create];
IF NOT wDir.Equal[NIL]
THEN streamIn.PutF["cd %g\n", IO.rope[wDir]];
streamIn.PutF["%g\n", IO.rope[commandLines]];
streamIn.Close[];
status ¬ UnixSysCallExtensions.Spawn[cshCommandString, stringStdIn, stringStdOut, stringStdErr];
IF status # 0 THEN msg ¬ MsgFromExitError[status: status, command: cshCommandRope];
msg ¬ Rope.Cat[msg, MsgFromFile[fileName: ropeStdErr, delete: DeleteFiles]];
msg ¬ Rope.Cat[msg, MsgFromFile[fileName: ropeStdOut, delete: DeleteFiles]];
FS.Delete[name: ropeStdIn !FS.Error => CONTINUE];
}
};
OutFilename: PROC [ template: ROPE ] RETURNS [ name: ROPE ] ~ {
fullName: ROPE; cp: FS.ComponentPositions;
[fullFName: fullName, cp: cp] ¬ FS.ExpandName[template];
{
shortName: ROPE ~ fullName.Substr[cp.base.start, cp.base.length];
name ¬ shortName.Cat[".o"];
};
};
FixPath: PROC [ origName: ROPE ]
RETURNS [ newName: ROPE ¬ NIL ] ~ {
IF Rope.Equal[origName, NIL] THEN RETURN;
newName ¬ origName.Translate[translator: BrackToSlash];
};
BrackToSlash: PROC [old: CHAR] RETURNS [new: CHAR] ~ {
new ¬ IF ( old = '> ) THEN '/ ELSE old};
FixDirectory: PROC [ origName: ROPE ]
RETURNS [ newName: ROPE ¬ NIL ] ~ {
length: INT ~ Rope.Length[origName];
IF length = 0 THEN RETURN;
newName ¬ FixPath[origName];
IF newName.Fetch[length-1] # '/ THEN newName ¬ newName.Cat["/"];
RETURN [newName];
};
GetDirAndFixPath: PROC [ origDir, origName: ROPE ]
RETURNS [ dir, basename: ROPE ¬ NIL ] ~ {
basename is filename portion
dir is the directory portion using "/" notation
dir ¬ origDir;
IF Rope.Equal[origName, NIL] THEN RETURN;
basename ¬ FixPath[origName];
{
pos: INT32 ~ basename.FindBackward["/"].SUCC;
IF ( pos # 0 ) THEN {
dir ¬ origDir.Concat[basename.Substr[0, pos]];
basename ¬ basename.Substr[pos];
RETURN};
};
};
Commander Procs.
CommandSyntaxError: ERROR ~ CODE;
ComplexCCProc: Commander.CommandProc ~ {
ENABLE {
Args.Error => { msg ¬ ComplexCCUsage; GOTO Failed };
ShouldNotHappen => { msg ¬ message; GOTO Failed };
CommandSyntaxError => { msg ¬ ComplexCCUsage; GOTO Failed };
FS.Error => { msg ¬ error.explanation; GOTO Failed };
};
binDir: ROPE ¬ NIL;
srcDir: ROPE ¬ NIL;
ccSwitches: ROPE;
ldSwitches: ROPE;
libSwitches: ROPE;
doALoad: BOOL ¬ FALSE;
xFlag: BOOL ¬ FALSE;
inFilename: ROPE;
intFileList: LIST OF ROPE; -- list of file names for intermediate files
loadFileList: LIST OF ROPE; -- list of file names for loading
outFilename: ROPE;
currentDir: ROPE ~ ViewFix[CommandTool.CurrentWorkingDirectory[], NIL, TRUE, FALSE, FALSE, NIL].unix; --a UXIO name
InnerDoIt: PROC [hostType, targetType: SystemVersion.MachineType] ~ {
Side Effects msg and result in the enclosing procedure. Host is currently unused.
ENABLE {
FS.Error => {
msg ¬ error.explanation;
GOTO Failed;
};
ABORTED => {
msg ¬ "-- Aborted!";
GOTO Failed;
}
};
compilerName: ROPE;
loaderName: ROPE;
moveName: ROPE;
links: LOR ¬ NIL;
ccSrc, ccOut, intFudge, ldOut, ldOutUX: ROPE;
ldCommand: ROPE ¬ NIL;
[compiler: compilerName, loader: loaderName] ¬ GetCommandNames[host: hostType, target: targetType];
IF compilerName.Equal[NIL] OR loaderName.Equal[NIL] THEN {
msg ¬ IO.PutFR["Compilation from host type %g to target type %g is not valid", IO.rope[MachineClassFromMachineType[hostType]],
IO.rope[MachineClassFromMachineType[targetType]],
];
GOTO Failed;
};
Step One: tame the file view problems
{ENABLE UNWIND => UnlinkList[links];
[ccSrc, links] ¬ ViewFix[srcDir.Concat[inFilename], NIL, FALSE, TRUE, FALSE, links];
[ccOut, links] ¬ ViewFix[binDir.Cat[outFilename], NIL, FALSE, TRUE, TRUE, links];
IF doALoad THEN {
inputDir: ROPE ~ currentDir.Cat[binDir];
ldOut ¬ binDir.Concat[NewName[".o", NIL]];
[ldOutUX, links] ¬ ViewFix[ldOut, NIL, FALSE, FALSE, TRUE, links];
FOR tail: LIST OF ROPE ¬ loadFileList, tail.rest WHILE ( tail # NIL ) DO
renamed: ROPE;
[renamed, links] ¬ ViewFix[binDir.Concat[tail.first], "FILE-", FALSE, FALSE, FALSE, links];
ldCommand ¬ ldCommand.Cat[" ", renamed];
ENDLOOP;
ldCommand ¬ ldCommand.Cat[" ", libSwitches];
};
Step Two: do a Cc
{
status: INT;
localMsg, command: ROPE ¬ NIL;
command ¬ IO.PutFR["%g %g -o %g %g -I./%g", IO.rope[compilerName], IO.rope[ccSwitches], IO.rope[ccOut], IO.rope[ccSrc], IO.rope[srcDir]];
[status: status, msg: localMsg] ¬ Execute[command: command, wDir: currentDir];
IF ( NOT localMsg.Equal[NIL] )
THEN {
IF ( status # 0 ) THEN {
msg ¬ IO.PutFR["Compilation failed; error: %g, msg: %g", IO.int[status], IO.rope[localMsg]];
UnlinkList[links];
GOTO Failed;
};
msg ¬ IO.PutFR[".\nCompilation warnings: %g\n", IO.rope[localMsg]];
}
ELSE {
msg ¬ ".";
};
cmd.err.PutRope[msg];
cmd.err.Flush[];
};
Process.CheckForAbort[];
Step Three: do an Ld (renaming if necessary, after removing links)
IF ( doALoad ) THEN {
status: INT;
localMsg: ROPE;
[intFudge, links] ¬ ViewFix[binDir.Cat[outFilename], "FILE-", FALSE, TRUE, FALSE, links];
ldCommand ¬ IO.PutFR["%g %g -o %g %g %g", IO.rope[loaderName], IO.rope[ldSwitches], IO.rope[ldOutUX], IO.rope[intFudge], IO.rope[ldCommand] ];
[status: status, msg: localMsg] ¬ Execute[command: ldCommand, wDir: currentDir];
IF ( NOT localMsg.Equal[NIL] )
THEN {
IF ( status # 0 ) THEN {
msg ¬ IO.PutFR["Load failed; error: %g, msg: %g", IO.int[status], IO.rope[localMsg]];
UnlinkList[links];
GOTO Failed;
};
msg ¬ IO.PutFR[".\nLoad warnings: %g\n", IO.rope[localMsg]];
}
ELSE {
msg ¬ ".";
};
cmd.err.PutRope[msg];
cmd.err.Flush[];
Process.CheckForAbort[];
};
}; UnlinkList[links];
IF ( doALoad ) THEN {
FS.Rename[from: ldOut, to: binDir.Concat[outFilename] !FS.Error => {
msg ¬ IO.PutFR["FS.Error[%g, %g] while trying to rename %g to %g", [atom[error.code]], [rope[error.explanation]], [rope[ldOut]], [rope[binDir.Concat[outFilename]]]];
GOTO Failed}];
};
Process.CheckForAbort[];
Step Four: process the file adding extra symbols and dependecy info.
IF ( xFlag ) THEN {
self: ExtendADotOut.ObjectID;
action: ExtendADotOut.ActionID ~ ExtendADotOut.ActionIDFromAction["CC"];
dependList: LIST OF ExtendADotOut.ObjectID ¬ NIL;
deps: ExtendADotOut.DependencyInfo;
depFileList: LIST OF ROPE ¬ NIL;
depFileList ¬ CONS[Rope.Cat[srcDir, inFilename], depFileList];
FOR list: LIST OF ROPE ¬ intFileList, list.rest WHILE list # NIL DO
fileName: ROPE ~ list.first;
depFileList ¬ CONS[Rope.Cat[srcDir, fileName], depFileList];
ENDLOOP;
FOR list: LIST OF ROPE ¬ loadFileList, list.rest WHILE list # NIL DO
fileName: ROPE ~ list.first;
depFileList ¬ CONS[Rope.Cat[binDir, fileName], depFileList];
ENDLOOP;
FOR list: LIST OF ROPE ¬ depFileList, list.rest WHILE list # NIL DO
fileName: ROPE ~ list.first;
dependList ¬ CONS[ExtendADotOut.ObjectIDFromFile[fileName], dependList];
ENDLOOP;
self.class ¬ ExtendADotOut.ObjectClassFromFileName[outFilename];
self.name ¬ Rope.Cat[binDir, outFilename];
self.stamp ¬ ExtendADotOut.StampFromIDs[action, dependList];
deps ¬ NEW [ExtendADotOut.DependencyInfoRep ¬ [
self: self,
action: action,
dependList: dependList
]];
ExtendADotOut.PutDependencyInfo[Rope.Cat[binDir, outFilename], deps];
};
msg ¬ " no errors.";
EXITS
Failed => { result ¬ $Failure };
};
targetClass: ROPE ¬ UserProfile.Token[key: MACHINECLASS, default: "sun4"];
hostClass: ROPE ¬ MachineClassFromMachineType[ SystemVersion.machineType ];
userHost: ROPENIL; -- unused
ProcessCommandLine: PROC ~ {
nArgs: INT32 ~ Args.NArgs[cmd];
i: NAT;
FOR i ¬ 0, i.SUCC WHILE ( i < nArgs ) DO
NextRope: PROC RETURNS [ r: ROPE ] ~ INLINE {
ropeArg: Args.Arg ~ Args.ArgRope[cmd, i.SUCC];
r ¬ ropeArg.rope;
i ¬ i.SUCC;
};
NextList: PROC RETURNS [ l: LIST OF ROPE ¬ NIL ] ~ INLINE {
FOR j: INT32 ¬ i.SUCC, j.SUCC WHILE ( j < nArgs ) DO
anArg: ROPE ~ Args.GetRope[cmd, j];
IF ( anArg.Fetch[0] = '- ) THEN { i ¬ j.PRED; EXIT} ;
l ¬ CONS[anArg, l];
REPEAT
FINISHED => { i ¬ nArgs }
ENDLOOP;
};
anArg: ROPE ~ Args.GetRope[cmd, i];
SELECT TRUE FROM
anArg.Equal[s2: "-in", case: FALSE] => { inFilename ¬ NextRope[] };
anArg.Equal[s2: "-out", case: FALSE] => { outFilename ¬ NextRope[] };
anArg.Equal[s2: "-binDir", case: FALSE] => { binDir ¬ NextRope[] };
anArg.Equal[s2: "-srcDir", case: FALSE] => { srcDir ¬ NextRope[] };
anArg.Equal[s2: "-lSwitch", case: FALSE] => { ldSwitches ¬ NextRope[] };
anArg.Equal[s2: "-cSwitch", case: FALSE] => { ccSwitches ¬ NextRope[] };
anArg.Equal[s2: "-host", case: FALSE] => { userHost ← NextRope[] };
anArg.Equal[s2: "-class", case: FALSE] => { targetClass ¬ NextRope[] };
anArg.Equal[s2: "-lib", case: FALSE] => { libSwitches ¬ NextRope[] };
anArg.Equal[s2: "-int", case: FALSE] => { intFileList ¬ NextList[] };
anArg.Equal[s2: "-X", case: FALSE] => { xFlag ¬ TRUE };
anArg.Equal[s2: "-load", case: FALSE] =>
{ doALoad ¬ TRUE; loadFileList ¬ NextList[] };
ENDCASE => ERROR CommandSyntaxError;
ENDLOOP;
};
ProcessCommandLine[];
binDir ¬ FixDirectory[binDir];
srcDir ¬ FixDirectory[srcDir];
inFilename ¬ FixPath[inFilename];
IF ( outFilename = NIL ) THEN outFilename ¬ OutFilename[inFilename];
[binDir, outFilename] ¬ GetDirAndFixPath[binDir, outFilename];
cmd.err.PutF[" [localhost] "];
cmd.err.PutRope["C compiling "];
cmd.err.Flush[];
InnerDoIt[
hostType: MachineTypeFromMachineClass[hostClass],
targetType: MachineTypeFromMachineClass[targetClass]];
That's all!
EXITS
Failed => { result ¬ $Failure };
};
ComplexRshProc: Commander.CommandProc ~ {
ENABLE {
Args.Error => { msg ¬ ComplexRshUsage; GOTO Failed };
ShouldNotHappen => { msg ¬ message; GOTO Failed };
CommandSyntaxError => { msg ¬ ComplexRshUsage; GOTO Failed };
FS.Error => { msg ¬ error.explanation; GOTO Failed };
};
xFlag: BOOL ¬ FALSE;
xClassName: ROPE ¬ NIL; -- The name of the class for this action
srcDir: ROPE;
binDir: ROPE ¬ NIL;
srcInFileList: LIST OF ROPE; -- Source files that will be transfered FROM Cedar
binInFileList: LIST OF ROPE; -- Binary files that will be transfered FROM Cedar
srcOutFileList: LIST OF ROPE; -- Source files that will be copied TO Cedar back
binOutFileList: LIST OF ROPE; -- Binary files that will be copied TO Cedar back
unlinkList: LOR ¬ NIL; --files to unlink later
rshCmd: ROPE;
currentDir: ROPE ~ CommandTool.CurrentWorkingDirectory[];
InnerDoIt: PROC [hostType, targetType: SystemVersion.MachineType] ~ {
Side Effects msg and result in the enclosing procedure.
ENABLE {
FS.Error => {
msg ¬ error.explanation;
GOTO Failed;
};
ABORTED => {
msg ¬ "-- Aborted!";
GOTO Failed;
}
};
Step One: tame the file view mess
What if the command does something (like mv) that would break links?
{ENABLE UNWIND => UnlinkList[unlinkList];
FOR list: LIST OF ROPE ¬ srcInFileList, list.rest WHILE list # NIL DO
fileName: ROPE ~ list.first;
[, unlinkList] ¬ ViewFix[srcDir.Cat[fileName], NIL, FALSE, TRUE, FALSE, unlinkList];
ENDLOOP;
FOR list: LIST OF ROPE ¬ binInFileList, list.rest WHILE list # NIL DO
fileName: ROPE ~ list.first;
[, unlinkList] ¬ ViewFix[binDir.Cat[fileName], NIL, FALSE, TRUE, FALSE, unlinkList];
ENDLOOP;
FOR list: LIST OF ROPE ¬ srcInFileList, list.rest WHILE list # NIL DO
fileName: ROPE ~ list.first;
[, unlinkList] ¬ ViewFix[srcDir.Cat[fileName], NIL, FALSE, TRUE, TRUE, unlinkList];
ENDLOOP;
FOR list: LIST OF ROPE ¬ binInFileList, list.rest WHILE list # NIL DO
fileName: ROPE ~ list.first;
[, unlinkList] ¬ ViewFix[binDir.Cat[fileName], NIL, FALSE, TRUE, TRUE, unlinkList];
ENDLOOP;
Step Two: do the Rsh on host
{
status: INT;
localMsg: ROPE ¬ NIL;
realDir: ROPE ¬ currentDir;
IF NOT srcDir.Equal[NIL]
THEN
IF srcDir.Fetch[0] = '/
THEN realDir ¬ srcDir
ELSE realDir ¬ currentDir.Cat["/", srcDir]
ELSE
realDir ¬ currentDir;
[status: status, msg: localMsg] ¬ ExecuteCsh[hostType: hostType, targetType: targetType, commandLines: rshCmd, wDir: realDir];
IF ( NOT localMsg.Equal[NIL] )
THEN {
IF ( status # 0 ) THEN {
msg ¬ IO.PutFR["Command failed; error: %g, msg: %g", IO.int[status], IO.rope[localMsg]];
GOTO Failed;
};
msg ¬ IO.PutFR[".\nCommand warnings: %g", IO.rope[localMsg]];
}
ELSE {
msg ¬ ".";
};
cmd.err.PutRope[msg];
cmd.err.Flush[];
};
Process.CheckForAbort[];
Step Three: remove the links.
}; UnlinkList[unlinkList];
Step Four: process the file adding extra symbols and dependecy info.
IF ( xFlag ) THEN {
self: ExtendADotOut.ObjectID;
action: ExtendADotOut.ActionID ~ ExtendADotOut.ActionIDFromAction[xClassName];
dependList: LIST OF ExtendADotOut.ObjectID ¬ NIL;
deps: ExtendADotOut.DependencyInfo;
depFileList: LIST OF ROPE ¬ NIL;
stamp: ExtendADotOut.VersionStamp;
FOR list: LIST OF ROPE ¬ srcInFileList, list.rest WHILE list # NIL DO
fileName: ROPE ~ list.first;
depFileList ¬ CONS[Rope.Cat[srcDir, fileName], depFileList];
ENDLOOP;
FOR list: LIST OF ROPE ¬ binInFileList, list.rest WHILE list # NIL DO
fileName: ROPE ~ list.first;
depFileList ¬ CONS[Rope.Cat[binDir, fileName], depFileList];
ENDLOOP;
FOR list: LIST OF ROPE ¬ depFileList, list.rest WHILE list # NIL DO
fileName: ROPE ~ list.first;
dependList ¬ CONS[ExtendADotOut.ObjectIDFromFile[fileName], dependList];
ENDLOOP;
stamp ¬ ExtendADotOut.StampFromIDs[action, dependList];
FOR list: LIST OF ROPE ¬ binOutFileList, list.rest WHILE list # NIL DO
outFilename: ROPE ~ list.first;
self.class ¬ ExtendADotOut.ObjectClassFromFileName[outFilename];
self.stamp ¬ stamp;
self.name ¬ Rope.Cat[binDir, outFilename];
deps ¬ NEW [ExtendADotOut.DependencyInfoRep ¬ [
self: self,
action: action,
dependList: dependList
]];
ExtendADotOut.PutDependencyInfo[Rope.Cat[binDir, outFilename], deps];
ENDLOOP;
};
msg ¬ " no errors.";
EXITS
Failed => { result ¬ $Failure };
};
targetClass: ROPE ¬ UserProfile.Token[key: MACHINECLASS, default: "sun4"];
hostClass: ROPE ¬ MachineClassFromMachineType[ SystemVersion.machineType ];
userHost: ROPENIL;
ProcessCommandLine: PROC ~ {
nArgs: INT32 ~ Args.NArgs[cmd];
i: NAT;
FOR i ¬ 0, i.SUCC WHILE ( i < nArgs ) DO
NextRope: PROC RETURNS [ r: ROPE ] ~ INLINE {
ropeArg: Args.Arg ~ Args.ArgRope[cmd, i.SUCC];
r ¬ ropeArg.rope;
i ¬ i.SUCC;
};
FixNextList: PROC RETURNS [ l: LIST OF ROPE ¬ NIL ] ~ INLINE {
Warning, Warning!!! create list in reverse order!
FOR j: INT32 ¬ i.SUCC, j.SUCC WHILE ( j < nArgs ) DO
anArg: ROPE ~ Args.GetRope[cmd, j];
IF ( anArg.Fetch[0] = '- ) THEN { i ¬ j.PRED; EXIT} ;
l ¬ CONS[FixPath[anArg], l];
REPEAT
FINISHED => { i ¬ nArgs }
ENDLOOP;
};
anArg: ROPE ~ Args.GetRope[cmd, i];
SELECT TRUE FROM
anArg.Equal[s2: "-binIn", case: FALSE] => { binInFileList ¬ FixNextList[] };
anArg.Equal[s2: "-srcIn", case: FALSE] => { srcInFileList ¬ FixNextList[] };
anArg.Equal[s2: "-binOut", case: FALSE] => { binOutFileList ¬ FixNextList[] };
anArg.Equal[s2: "-srcOut", case: FALSE] => { srcOutFileList ¬ FixNextList[] };
anArg.Equal[s2: "-srcDir", case: FALSE] => { srcDir ¬ NextRope[] };
anArg.Equal[s2: "-binDir", case: FALSE] => { binDir ¬ NextRope[] };
anArg.Equal[s2: "-host", case: FALSE] => { userHost ← NextRope[] };
anArg.Equal[s2: "-class", case: FALSE] => { targetClass ¬ NextRope[] };
anArg.Equal[s2: "-cmd", case: FALSE] => { rshCmd ¬ NextRope[] };
anArg.Equal[s2: "-XClass", case: FALSE] => { xFlag ¬ TRUE; xClassName ¬ NextRope[] };
ENDCASE => ERROR CommandSyntaxError;
ENDLOOP;
IF binDir.Equal[NIL] THEN binDir ¬ srcDir;
};
ProcessCommandLine[];
srcDir ¬ FixDirectory[srcDir];
binDir ¬ FixDirectory[binDir];
cmd.err.PutRope["Starting Rsh"];
cmd.err.Flush[];
InnerDoIt[
hostType: MachineTypeFromMachineClass[hostClass],
targetType: MachineTypeFromMachineClass[targetClass]];
That's all!
EXITS
Failed => { result ¬ $Failure };
};
Documentation
ComplexCC: ROPE ~ "ComplexCC";
ComplexCCDoc: ROPE ~ " - cc with all the frills. Switches are:
-in <file>
-out <file>
-class <as in SystemVersion.MachineTypes>
-host <host>
-cSwitch <cc switches>
-load <file list> => load compiled file together with <file list>
-X => eXtend the resulting binary file with fast symbol and dependecy info
-lSwitch <ld switches>
-Lib libstring => string with the libraries to load
-int <file list> => files to copy to the host before compiling
-srcDir <dir> => remote source directory
-binDir <dir> => remote object file directory
(overridden by directory part specified in -out)
";
ComplexCCUsage: ROPE ~ Rope.Concat["Usage: ComplexCC ", ComplexCCDoc];
ComplexRsh: ROPE ~ "ComplexRsh";
ComplexRshDoc: ROPE ~ " - Rsh with all the frills. Switches are:
-class <as in SystemVersion.MachineTypes>
-host <host>
-srcIn <file list> => source files to copy to the host before doing Rsh
-binIn <file list> => binary files to copy to the host before doing Rsh
-srcOut <file list> => source files to copy from the host after doing Rsh
-binOut <file list> => binary files to copy from the host after doing Rsh
-srcDir <dir> => remote source directory (command will execute in srcDir)
-binDir <dir> => remote binary directory (equal to -srcDir by default)
-XClass <className> => eXtend the resulting binary files with fast symbol and dependency information; use <className> to identify the action performed.
-cmd <command> => command to execute remotely
";
ComplexRshUsage: ROPE ~ Rope.Concat["Usage: ComplexRsh ", ComplexRshDoc];
ComplexRshUsageHostMissing: ROPE ~ Rope.Concat["No host has been specified\nUsage: ComplexRsh ", ComplexRshDoc];
ComplexErrorProc: Commander.CommandProc ~ {ERROR};
Init: PROC ~ {
Commander.Register[ComplexCC, ComplexCCProc, ComplexCCDoc];
Commander.Register[ComplexRsh, ComplexRshProc, ComplexRshDoc];
Commander.Register["ComplexError", ComplexErrorProc, "raises ERROR, for debugging"];
};
Init[];
}.
Changes:
Added -X and -XClass flags
Added encoding of dependencies
Added binDir to ComplexRsh; note: command still executes in srcDir until I chase clients around. CC version has not been changed yet.
To Change:
Encoding of boundaries for Howard