<<>> <> <> <> <<>> DIRECTORY IO, PFS, PFSNames, BasicTime, Commander, CommanderOps, Convert, RefText, Rope, RopeList, SymTab, RefTab, MakoDependency; MakoCommands: CEDAR PROGRAM IMPORTS IO, PFS, PFSNames, Commander, CommanderOps, Convert, RefText, Rope, RopeList, SymTab, RefTab, MakoDependency ~ BEGIN ROPE: TYPE ~ Rope.ROPE; PATH: TYPE ~ PFSNames.PATH; SourceFile: TYPE ~ REF SourceFileRep; SourceFileRep: TYPE ~ RECORD [ pathName: PFSNames.PATH, arguments: Arguments, extension: ROPE ]; Registration: TYPE ~ RECORD [ extension: ROPE, dependencyProc: PROC [ROPE] RETURNS [LIST OF ROPE] ¬ NIL, dependencyExtension: ROPE ¬ NIL ]; ParseConfig: PROC [fileName: ROPE] RETURNS [LIST OF ROPE] ~ { c: MakoDependency.ConfigDependencies ¬ MakoDependency.ParseCMesaDirectory[fileName]; RETURN [RopeList.DAppend[c.interfaces, c.implementations]] }; registry: LIST OF Registration ¬ LIST[ ["mesa", MakoDependency.ParseMesaDirectory, "mob"], ["config", ParseConfig, "mob"], ["MakeIt", MakoDependency.ParseMakeItDependency, NIL], ["c", MakoDependency.ParseCDependency] ]; fileIDTab: SymTab.Ref ~ SymTab.Create[]; FileID: TYPE ~ REF FileIDRep; FileIDRep: TYPE ~ RECORD [ shortName: ROPE, uniqueID: PFS.UniqueID ]; DBEntry: TYPE ~ REF DBEntryRep; DBEntryRep: TYPE ~ RECORD [ fileID: FileID, commandName: ROPE, switches: ROPE ¬ NIL, using: LIST OF FileID ¬ NIL, out: LIST OF FileID ¬ NIL ]; Relativize: PROC [path: PFSNames.PATH] RETURNS [ROPE] ~ { isa: BOOL; suffix: PATH; [isa, suffix] ¬ PFSNames.IsAPrefix[prefix: PFS.GetWDir[], name: path]; RETURN [PFS.RopeFromPath[IF isa THEN suffix ELSE path]]; }; MakeFileID: PROC [fileName: ROPE] RETURNS [fileID: FileID] ~ { path: PFSNames.PATH ~ PFS.PathFromRope[fileName]; shortName: ROPE ~ Relativize[path]; uniqueID: PFS.UniqueID ~ PFS.FileInfo[path].uniqueID; RETURN [FileIDFromData[shortName, uniqueID]] }; FileIDFromData: PROC [shortName: ROPE, uniqueID: PFS.UniqueID] RETURNS [fileID: FileID] ~ { Action: SymTab.UpdateAction ~ { <> list: LIST OF FileID ¬ NARROW[val]; FOR tail: LIST OF FileID ¬ list, tail.rest UNTIL tail = NIL DO IF tail.first.uniqueID = uniqueID THEN { fileID ¬ tail.first; RETURN }; ENDLOOP; fileID ¬ NEW[FileIDRep ¬ [shortName, uniqueID]]; list ¬ CONS[fileID, list]; RETURN [store, list]; }; SymTab.Update[fileIDTab, shortName, Action]; }; MakeDBEntry: PROC [shortName: ROPE, commandName: ROPE, switches: ROPE] RETURNS [DBEntry] ~ { fileID: FileID ~ MakeFileID[shortName]; dbe: DBEntry ~ NEW[DBEntryRep ¬ [fileID: fileID, commandName: commandName, switches: switches]]; RETURN [dbe] }; Uses: PROC [dbe: DBEntry, shortName: ROPE] ~ { dbe.using ¬ CONS[MakeFileID[shortName], dbe.using]; }; Output: PROC [dbe: DBEntry, shortName: ROPE] ~ { dbe.out ¬ CONS[MakeFileID[shortName], dbe.out]; }; FilesExist: PROC [list: LIST OF FileID] RETURNS [BOOL ¬ FALSE] ~ { ENABLE PFS.Error => { IF error.group = user THEN CONTINUE }; FOR tail: LIST OF FileID ¬ list, tail.rest UNTIL tail = NIL DO IF PFS.FileInfo[PFS.PathFromRope[tail.first.shortName]].uniqueID # tail.first.uniqueID THEN RETURN [FALSE]; ENDLOOP; RETURN [TRUE] }; FileExists: PROC [fileID: FileID] RETURNS [BOOL ¬ FALSE] ~ { ENABLE PFS.Error => { IF error.group = user THEN CONTINUE }; RETURN [PFS.FileInfo[PFS.PathFromRope[fileID.shortName]].uniqueID = fileID.uniqueID] }; SourceExtension: PROC [rope: ROPE] RETURNS [ROPE] ~ { size: INT ~ Rope.Size[rope]; FOR tail: LIST OF Registration ¬ registry, tail.rest UNTIL tail = NIL DO x: ROPE ~ tail.first.extension; xl: INT ~ Rope.Size[x]; IF size >= xl + 1 AND Rope.Fetch[rope, size-xl-1] = '. AND Rope.Run[s1: rope, pos1: size-xl, s2: x, case: FALSE] = xl THEN { RETURN [Rope.Substr[rope, size-xl]] }; ENDLOOP; RETURN [NIL] }; MakePattern: PROC [rope: ROPE] RETURNS [ROPE] ~ { x: ROPE ~ SourceExtension[rope]; IF x # NIL THEN RETURN [rope] ELSE RETURN [Rope.Concat[rope, ".*"]] }; ReplaceStar: PROC [rope: ROPE, ext: ROPE] RETURNS [ROPE] ~ { size: INT ~ Rope.Size[rope]; IF size > 2 AND Rope.Run[rope, size-2, ".*"] = 2 THEN RETURN [Rope.Replace[rope, size-1, 1, ext]] ELSE RETURN [rope] }; EnumerateSourceFiles: PROC [rope: ROPE, switches: Arguments, sourceFileProc: PROC [SourceFile]] ~ { ENABLE PFS.Error => CommanderOps.Failed[error.explanation]; path: PATH ~ PFS.PathFromRope[rope]; shortName: ROPE ~ PFSNames.ComponentRope[PFSNames.ShortName[path]]; shortPattern: ROPE ~ MakePattern[shortName]; pattern: PATH ~ IF shortName=shortPattern THEN path ELSE PFSNames.ReplaceShortName[path, [[shortPattern, 0, Rope.Size[shortPattern]]]]; EachName: PFS.NameProc ~ { <> short: ROPE ~ PFSNames.ComponentRope[PFSNames.ShortName[name]]; ext: ROPE ~ SourceExtension[short]; IF ext # NIL AND Rope.Match[ReplaceStar[shortPattern, ext], short] THEN { a: Arguments ~ NEW[ArgumentsRep ¬ switches­]; a.name ¬ Rope.Substr[short, 0, Rope.Size[short] - Rope.Size[ext] - 1]; sourceFileProc[NEW[SourceFileRep ¬ [ pathName: name, arguments: a, extension: ext ]]]; }; }; PFS.EnumerateForNames[pattern: pattern, proc: EachName]; }; PutQ: PROC [stream: IO.STREAM, rope: ROPE] ~ { IO.PutF1[stream, "\"%g\" ", [rope[rope]]]; }; PutFileID: PROC [stream: IO.STREAM, fileID: FileID] ~ { IO.PutRope[stream, "("]; PutQ[stream, fileID.shortName]; IO.PutFL[stream, "%g %g %g %g", LIST[ [cardinal[LOOPHOLE[fileID.uniqueID.egmt.gmt]]], [cardinal[LOOPHOLE[fileID.uniqueID.egmt.usecs]]], [cardinal[LOOPHOLE[fileID.uniqueID.host.a]]], [cardinal[LOOPHOLE[fileID.uniqueID.host.b]]] ]]; IO.PutRope[stream, ")"]; }; PutFileIDs: PROC [stream: IO.STREAM, fileIDs: LIST OF FileID] ~ { IO.PutRope[stream, "("]; FOR tail: LIST OF FileID ¬ fileIDs, tail.rest UNTIL tail = NIL DO PutFileID[stream, tail.first]; IF tail.rest # NIL THEN IO.PutRope[stream, " "]; ENDLOOP; IO.PutRope[stream, ")"]; }; PutDB: PROC [stream: IO.STREAM, db: RefTab.Ref] ~ { Each: RefTab.EachPairAction ~ { WITH key SELECT FROM fileID: FileID => { WITH val SELECT FROM list: LIST OF DBEntry => { FOR tail: LIST OF DBEntry ¬ list, tail.rest UNTIL tail = NIL DO dbe: DBEntry ~ tail.first; IF fileID=dbe.fileID AND FileExists[dbe.fileID] AND FilesExist[dbe.out] THEN { IO.PutRope[stream, "\n ("]; PutFileID[stream, fileID]; IO.PutRope[stream, " "]; PutQ[stream, dbe.commandName]; PutQ[stream, dbe.switches]; PutFileIDs[stream, dbe.using]; IO.PutRope[stream, " "]; PutFileIDs[stream, dbe.out]; IO.PutRope[stream, ")"]; }; ENDLOOP; }; ENDCASE; }; ENDCASE; }; IO.PutRope[stream, "("]; [] ¬ RefTab.Pairs[db, Each]; IO.PutRope[stream, ")\n"]; }; WriteDB: PROC [fileName: ROPE, db: RefTab.Ref] ~ { stream: IO.STREAM ~ PFS.StreamOpen[PFS.PathFromRope[fileName], $create]; PutDB[stream, db]; IO.Close[stream]; }; InsertDBE: PROC [db: RefTab.Ref, dbe: DBEntry] ~ { Action: RefTab.UpdateAction ~ { newList: LIST OF DBEntry; WITH val SELECT FROM list: LIST OF DBEntry => newList ¬ CONS[dbe, list]; ENDCASE => newList ¬ LIST[dbe]; RETURN [store, newList] }; RefTab.Update[db, dbe.fileID, Action]; }; GetDB: PROC [stream: IO.STREAM, db: RefTab.Ref] ~ { token: REF TEXT ¬ RefText.ObtainScratch[100]; tokenKind: IO.TokenKind ¬ tokenERROR; SingleMatch: PROC [c: CHAR] RETURNS [BOOL] ~ { RETURN [tokenKind = tokenSINGLE AND token[0] = c]; }; Single: PROC [c: CHAR] ~ { IF tokenKind = tokenSINGLE AND token[0] = c THEN Get[] ELSE Syntax[]; }; Get: PROC ~ { [tokenKind: tokenKind, token: token] ¬ IO.GetCedarToken[stream, token]; }; Syntax: PROC ~ { CommanderOps.Failed[IO.PutFR1[".makodb syntax error at location %g", [integer[IO.GetIndex[stream]]]]]; }; GetRope: PROC RETURNS [rope: ROPE ¬ NIL] ~ { IF tokenKind = tokenROPE THEN { rope ¬ Convert.RopeFromLiteral[RefText.TrustTextAsRope[token]]; Get[] } ELSE Syntax[]; }; GetCard: PROC RETURNS [card: CARD ¬ 0] ~ { IF tokenKind = tokenDECIMAL THEN { card ¬ Convert.CardFromRope[RefText.TrustTextAsRope[token]]; Get[] } ELSE Syntax[]; }; GetFileID: PROC RETURNS [FileID]~ { Single['(]; { shortName: ROPE ~ GetRope[]; gmt: BasicTime.GMT ~ LOOPHOLE[GetCard[]]; usec: CARD ~ GetCard[]; a: CARD ~ GetCard[]; b: CARD ~ GetCard[]; Single[')]; RETURN [FileIDFromData[shortName, [[gmt, usec],[a, b]]]] }; }; GetFileIDs: PROC RETURNS [LIST OF FileID] ~ { head: LIST OF FileID ¬ LIST[NIL]; last: LIST OF FileID ¬ head; Single['(]; UNTIL SingleMatch[')] DO last ¬ last.rest ¬ LIST[GetFileID[]]; ENDLOOP; Get[]; RETURN [head.rest] }; Get[]; Single['(]; UNTIL SingleMatch[')] DO Single['(]; { fileID: FileID ¬ GetFileID[]; commandName: ROPE ¬ GetRope[]; switches: ROPE ¬ GetRope[]; using: LIST OF FileID ¬ GetFileIDs[]; out: LIST OF FileID ¬ GetFileIDs[]; dbe: DBEntry ~ NEW[DBEntryRep ¬ [fileID: fileID, commandName: commandName, switches: switches, using: using, out: out]]; Single[')]; InsertDBE[db, dbe]; }; ENDLOOP; }; LoadDB: PROC [fileName: ROPE, db: RefTab.Ref] ~ { ENABLE PFS.Error => IF error.group = user THEN CONTINUE; stream: IO.STREAM ~ PFS.StreamOpen[PFS.PathFromRope[fileName], $read]; GetDB[stream, db]; IO.Close[stream]; }; ReadDB: PROC [fileName: ROPE] RETURNS [RefTab.Ref] ~ { db: RefTab.Ref ¬ RefTab.Create[]; LoadDB[fileName, db]; RETURN [db] }; DoCommand: PROC [cmd: Commander.Handle, commandName: ROPE, switches: ROPE, baseName, extension: ROPE] RETURNS [result: REF ¬ NIL] ~ { db: RefTab.Ref ~ WITH CommanderOps.GetProp[cmd, $MakoDB] SELECT FROM x: RefTab.Ref => x, ENDCASE => ReadDB[".makodb"]; shortName: ROPE ~ Rope.Cat[baseName, ".", extension]; fileID: FileID ~ MakeFileID[shortName]; WITH RefTab.Fetch[db, fileID].val SELECT FROM list: LIST OF DBEntry => { FOR tail: LIST OF DBEntry ¬ list, tail.rest UNTIL tail = NIL DO dbe: DBEntry ¬ tail.first; IF dbe.fileID = fileID AND Rope.Equal[dbe.commandName, commandName, FALSE] AND Rope.Equal[dbe.switches, switches] AND FilesExist[dbe.using] AND FilesExist[dbe.out] THEN RETURN [$OK]; ENDLOOP; }; ENDCASE; result ¬ CommanderOps.DoCommand[Rope.Cat[commandName, " ", switches, " ", baseName], cmd]; WITH result SELECT FROM dbe: DBEntry => { InsertDBE[db, dbe] }; ENDCASE; CommanderOps.PutProp[cmd, $MakoDB, db]; }; MakoCommand: Commander.CommandProc ~ { head: LIST OF SourceFile = LIST[NIL]; last: LIST OF SourceFile ¬ head; dryrun: BOOL ¬ FALSE; EachSourceFile: PROC [s: SourceFile] ~ { last ¬ last.rest ¬ LIST[s] }; switches: Arguments ~ MakeDefaultArguments[]; FOR arg: ROPE ¬ CommanderOps.NextArgument[cmd], CommanderOps.NextArgument[cmd] UNTIL arg = NIL DO IF Rope.Match["-*", arg] THEN { IF Rope.Equal[arg, "-dryrun"] THEN dryrun ¬ TRUE ELSE ParseSwitch[arg, cmd, switches]; } ELSE { was: LIST OF SourceFile ¬ last; EnumerateSourceFiles[arg, switches, EachSourceFile]; IF was = last THEN CommanderOps.Failed[Rope.Concat["Missing source: ", arg]]; <> }; ENDLOOP; IF head.rest = NIL THEN CommanderOps.Failed[cmd.procData.doc]; FOR tail: LIST OF SourceFile ¬ head.rest, tail.rest UNTIL tail = NIL DO commandName: ROPE ~ Rope.Concat["Mako-", tail.first.extension]; IF dryrun THEN { IO.PutRope[cmd.out, commandName]; IO.PutRope[cmd.out, UnparseSwitches[tail.first.arguments]]; IO.PutRope[cmd.out, tail.first.arguments.name]; IO.PutRope[cmd.out, "\n"]; } ELSE { res: REF ~ DoCommand[cmd, commandName, UnparseSwitches[tail.first.arguments], tail.first.arguments.name, tail.first.extension]; IF res = $Failure THEN result ¬ res; }; ENDLOOP; IF NOT dryrun THEN WITH CommanderOps.GetProp[cmd, $MakoDB] SELECT FROM x: RefTab.Ref => WriteDB[".makodb", x]; ENDCASE; }; Arguments: TYPE ~ REF ArgumentsRep; ArgumentsRep: TYPE ~ PACKED RECORD [ makeboot: BOOL ¬ FALSE, debuggable: BOOL ¬ FALSE, optimize: BOOL ¬ TRUE, name: ROPE -- sans extension ]; MakeDefaultArguments: PROC RETURNS [Arguments] ~ { RETURN [NEW[ArgumentsRep ¬ []]] }; ParseSwitch: PROC [arg: ROPE, cmd: Commander.Handle, a: Arguments] ~ { sense: BOOL ¬ TRUE; FOR i: INT IN (0..Rope.Size[arg]) DO SELECT Rope.Lower[Rope.Fetch[arg, i]] FROM '~ => { sense ¬ NOT sense }; 'b => { a.makeboot ¬ sense; sense ¬ TRUE }; 'd => { a.debuggable ¬ sense; sense ¬ TRUE }; 'o => { a.optimize ¬ sense; sense ¬ TRUE }; 'u => { IF sense THEN a­ ¬ []; sense ¬ TRUE }; ENDCASE => CommanderOps.Failed[cmd.procData.doc]; ENDLOOP; }; UnparseSwitches: PROC [a: Arguments] RETURNS [ROPE] ~ { cmdbuf: REF TEXT ¬ RefText.New[20]; Emit: PROC [rope: ROPE] ~ {cmdbuf ¬ RefText.AppendRope[cmdbuf, rope]}; IF a.debuggable THEN Emit[" -d"]; IF a.makeboot THEN Emit[" -b"]; IF NOT a.optimize THEN Emit[" -~o"]; Emit[" "]; RETURN [Rope.FromRefText[cmdbuf]] }; MakeCommandLine: PROC [commandName: ROPE, a: Arguments, name: ROPE] RETURNS [ROPE] ~ { cmdbuf: REF TEXT ¬ RefText.New[200]; Emit: PROC [rope: ROPE] ~ {cmdbuf ¬ RefText.AppendRope[cmdbuf, rope]}; Emit[commandName]; Emit[UnparseSwitches[a]]; Emit[a.name]; RETURN [Rope.FromRefText[cmdbuf]] }; GetArguments: PROC [cmd: Commander.Handle] RETURNS [Arguments] ~ { a: Arguments ~ MakeDefaultArguments[]; FOR arg: ROPE ¬ CommanderOps.NextArgument[cmd], CommanderOps.NextArgument[cmd] UNTIL arg=NIL DO IF Rope.Match["-*", arg] THEN { ParseSwitch[arg, cmd, a] } ELSE { IF a.name # NIL THEN CommanderOps.Failed[cmd.procData.doc]; a.name ¬ arg; }; ENDLOOP; IF a.name = NIL THEN CommanderOps.Failed[cmd.procData.doc]; RETURN [a] }; MakoMakeItCommand: Commander.CommandProc ~ { ENABLE PFS.Error => CommanderOps.Failed[error.explanation]; arg: Arguments ~ GetArguments[cmd]; cmName: ROPE ~ Rope.Concat[arg.name, ".MakeIt"]; dbe: DBEntry ~ MakeDBEntry[cmName, "Mako-MakeIt", UnparseSwitches[arg]]; result ¬ CommanderOps.DoCommand[Rope.Concat["Source ", cmName], cmd]; IF result = $Failure THEN { IO.PutRope[cmd.err, cmName]; IO.PutRope[cmd.err, " failed.\n"] } ELSE { FOR tail: LIST OF ROPE ¬ MakoDependency.ParseMakeItDependency[cmName], tail.rest UNTIL tail = NIL DO Uses[dbe, tail.first]; ENDLOOP; Output[dbe, arg.name]; result ¬ dbe; }; }; MakoMesaCommand: Commander.CommandProc ~ { arg: Arguments ~ GetArguments[cmd]; dbe: DBEntry ~ MakeDBEntry[Rope.Concat[arg.name, ".mesa"], "Mako-mesa", UnparseSwitches[arg]]; result ¬ CommanderOps.DoCommand[Rope.Concat["Mimosa -c ", arg.name], cmd]; IF result # $Failure THEN { FOR tail: LIST OF ROPE ¬ MakoDependency.ParseMesaDirectory[arg.name], tail.rest UNTIL tail = NIL DO Uses[dbe, Rope.Concat[tail.first, ".mob"]]; ENDLOOP; Output[dbe, Rope.Concat[arg.name, ".mob"]]; }; IF result = $Implementation THEN { result ¬ DoCommand[cmd, "Mako-c", UnparseSwitches[arg], Rope.Concat[arg.name, ".c2c"], "c"]; Output[dbe, Rope.Cat["sun4/", arg.name, ".c2c.o"]]; }; IF result # $Failure THEN result ¬ dbe; }; MakoConfigCommand: Commander.CommandProc ~ { arg: Arguments ~ GetArguments[cmd]; dbe: DBEntry ~ MakeDBEntry[Rope.Concat[arg.name, ".config"], "Mako-config", UnparseSwitches[arg]]; cmdRope: ROPE ¬ "Cind -l -m "; IF arg.makeboot THEN cmdRope ¬ Rope.Concat[cmdRope, "-b "]; result ¬ CommanderOps.DoCommand[Rope.Concat[cmdRope, arg.name], cmd]; IF result # $Failure THEN { c: MakoDependency.ConfigDependencies ~ MakoDependency.ParseCMesaDirectory[arg.name]; result ¬ Cinderella[cmd, arg.name, c.implementations]; IF result # $Failure THEN { FOR tail: LIST OF ROPE ¬ c.interfaces, tail.rest UNTIL tail = NIL DO Uses[dbe, Rope.Concat[tail.first, ".mob"]]; ENDLOOP; FOR tail: LIST OF ROPE ¬ c.implementations, tail.rest UNTIL tail = NIL DO IF Rope.Match["*.o*", tail.first] THEN { Uses[dbe, Rope.Concat["sun4/", tail.first]]; } ELSE { Uses[dbe, Rope.Concat[tail.first, ".mob"]]; Uses[dbe, Rope.Cat["sun4/", tail.first, ".c2c.o"]]; }; ENDLOOP; Output[dbe, Rope.Concat[arg.name, ".mob"]]; Output[dbe, Rope.Cat["sun4/", arg.name, ".c2c.o"]]; result ¬ dbe; }; }; }; Cinderella: PROC [cmd: Commander.Handle, package: ROPE, impls: LIST OF ROPE] RETURNS [result: REF] ~ { class: ROPE ¬ "sun4"; dir: ROPE ¬ "sun4"; cSw: ROPE ¬ "-c -O2"; lSw: ROPE ¬ "-r"; cmdbuf: REF TEXT ¬ RefText.New[200]; Emit: PROC [rope: ROPE] ~ {cmdbuf ¬ RefText.AppendRope[cmdbuf, rope]}; Emit["ComplexCc -out "]; Emit[dir]; Emit["/"]; Emit[package]; Emit[".c2c.o"]; Emit[" -in "]; Emit[package]; Emit[".c2c.c"]; Emit[" -rload "]; FOR l: LIST OF ROPE ¬ impls, l.rest WHILE l # NIL DO name: ROPE ¬ l.first; IF NOT Rope.Match["*/*", name] THEN { Emit[dir]; Emit["/"] }; Emit[name]; IF NOT Rope.Match["*.o", name] THEN Emit[".c2c.o"]; Emit[" "]; ENDLOOP; Emit[" -class "]; Emit[class]; Emit[" -cSwitch \""]; Emit[cSw]; Emit["\""]; Emit[" -lSwitch \""]; Emit[lSw]; Emit["\""]; Emit[" -lib "]; result ¬ CommanderOps.DoCommand[Rope.FromRefText[cmdbuf], cmd]; }; MakoCCommand: Commander.CommandProc ~ { arg: Arguments ~ GetArguments[cmd]; fname: ROPE ~ Rope.Concat[arg.name, ".c"]; oname: ROPE ~ Rope.Cat["sun4/", arg.name, ".o"]; dbe: DBEntry ~ MakeDBEntry[fname, "Mako-c", UnparseSwitches[arg]]; cmdbuf: REF TEXT ¬ RefText.New[200]; Emit: PROC [rope: ROPE] ~ {cmdbuf ¬ RefText.AppendRope[cmdbuf, rope]}; FOR tail: LIST OF ROPE ¬ MakoDependency.ParseCDependency[fname], tail.rest UNTIL tail = NIL DO Uses[dbe, tail.first]; ENDLOOP; Emit["ComplexCc -out "]; Emit[oname]; Emit[" -in "]; Emit[fname]; Emit[" -class sparc -cSwitch \"-c "]; IF arg.debuggable THEN Emit[" -g"] ELSE IF arg.optimize THEN Emit[" -O2"]; Emit[" -fsingle\""]; result ¬ CommanderOps.DoCommand[Rope.FromRefText[cmdbuf], cmd]; IF result # $Failure THEN { Output[dbe, oname]; result ¬ dbe; }; }; Commander.Register["Mako", MakoCommand, "Compile a set of modules"]; Commander.Register["Mako-mesa", MakoMesaCommand, "Compile a mesa module"]; Commander.Register["Mako-config", MakoConfigCommand, "Compile a config module"]; Commander.Register["Mako-c", MakoCCommand, "Compile a c program"]; Commander.Register["Mako-MakeIt", MakoMakeItCommand, "Execute a .MakeIt script"]; END.