diff options
author | Araq <rumpf_a@web.de> | 2017-01-27 22:54:31 +0100 |
---|---|---|
committer | Andreas Rumpf <rumpf_a@web.de> | 2017-01-28 08:54:53 +0100 |
commit | 03a1c3b077f9f35d1b07b0f5990dececb35f52a2 (patch) | |
tree | f4f998b3adbc1ffb3e0306fbc188f51d2299be0f /compiler | |
parent | 0e16d43196efdf901f359744c24636ab2b18f325 (diff) | |
download | Nim-03a1c3b077f9f35d1b07b0f5990dececb35f52a2.tar.gz |
.compile pragma supports patterns and actions
Diffstat (limited to 'compiler')
-rw-r--r-- | compiler/cgen.nim | 67 | ||||
-rw-r--r-- | compiler/commands.nim | 4 | ||||
-rw-r--r-- | compiler/extccomp.nim | 142 | ||||
-rw-r--r-- | compiler/pragmas.nim | 32 |
4 files changed, 142 insertions, 103 deletions
diff --git a/compiler/cgen.nim b/compiler/cgen.nim index e478b07cb..476b1362f 100644 --- a/compiler/cgen.nim +++ b/compiler/cgen.nim @@ -849,15 +849,15 @@ proc addIntTypes(result: var Rope) {.inline.} = addf(result, "#define NIM_INTBITS $1" & tnl, [ platform.CPU[targetCPU].intSize.rope]) -proc getCopyright(cfile: string): Rope = +proc getCopyright(cfile: Cfile): Rope = if optCompileOnly in gGlobalOptions: result = ("/* Generated by Nim Compiler v$1 */$N" & - "/* (c) 2017 Andreas Rumpf */$N" & + "/* (c) " & CompileDate.substr(0, 3) & " Andreas Rumpf */$N" & "/* The generated code is subject to the original license. */$N") % [rope(VersionAsString)] else: result = ("/* Generated by Nim Compiler v$1 */$N" & - "/* (c) 2017 Andreas Rumpf */$N" & + "/* (c) " & CompileDate.substr(0, 3) & " Andreas Rumpf */$N" & "/* The generated code is subject to the original license. */$N" & "/* Compiled for: $2, $3, $4 */$N" & "/* Command for C compiler:$n $5 */$N") % @@ -867,7 +867,7 @@ proc getCopyright(cfile: string): Rope = rope(extccomp.CC[extccomp.cCompiler].name), rope(getCompileCFileCmd(cfile))] -proc getFileHeader(cfile: string): Rope = +proc getFileHeader(cfile: Cfile): Rope = result = getCopyright(cfile) addIntTypes(result) @@ -1096,7 +1096,7 @@ proc genInitCode(m: BModule) = [(i.ord - '0'.ord).rope, el] add(m.s[cfsInitProc], ex) -proc genModule(m: BModule, cfile: string): Rope = +proc genModule(m: BModule, cfile: Cfile): Rope = result = getFileHeader(cfile) result.add(genMergeInfo(m)) @@ -1227,7 +1227,11 @@ proc myOpen(graph: ModuleGraph; module: PSym; cache: IdentCache): PPassContext = incl g.generatedHeader.flags, isHeaderFile proc writeHeader(m: BModule) = - var result = getCopyright(m.filename) + var result = ("/* Generated by Nim Compiler v$1 */$N" & + "/* (c) " & CompileDate.substr(0, 3) & " Andreas Rumpf */$N" & + "/* The generated code is subject to the original license. */$N") % + [rope(VersionAsString)] + var guard = "__$1__" % [m.filename.splitFile.name.rope] result.addf("#ifndef $1$n#define $1$n", [guard]) addIntTypes(result) @@ -1281,20 +1285,19 @@ proc finishModule(m: BModule) = dec(m.g.forwardedProcsCounter, i) setLen(m.forwardedProcs, 0) -proc shouldRecompile(code: Rope, cfile: string): bool = +proc shouldRecompile(code: Rope, cfile: Cfile): bool = result = true if optForceFullMake notin gGlobalOptions: - var objFile = toObjFile(cfile) - - if not equalsFile(code, cfile): + if not equalsFile(code, cfile.cname): if isDefined("nimdiff"): - copyFile(cfile, cfile & ".backup") - echo "diff ", cfile, ".backup ", cfile - writeRope(code, cfile) + copyFile(cfile.cname, cfile.cname & ".backup") + echo "diff ", cfile.cname, ".backup ", cfile.cname + writeRope(code, cfile.cname) return - if existsFile(objFile) and os.fileNewer(objFile, cfile): result = false + if existsFile(cfile.obj) and os.fileNewer(cfile.obj, cfile.cname): + result = false else: - writeRope(code, cfile) + writeRope(code, cfile.cname) # We need 2 different logics here: pending modules (including # 'nim__dat') may require file merging for the combination of dead code @@ -1304,8 +1307,7 @@ proc shouldRecompile(code: Rope, cfile: string): bool = proc writeModule(m: BModule, pending: bool) = # generate code for the init statements of the module: - var cfile = getCFile(m) - var cfilenoext = changeFileExt(cfile, "") + let cfile = getCFile(m) if not m.fromCache or optForceFullMake in gGlobalOptions: genInitCode(m) @@ -1315,42 +1317,45 @@ proc writeModule(m: BModule, pending: bool) = add(m.s[cfsProcHeaders], m.g.mainModProcs) generateThreadVarsSize(m) - var code = genModule(m, cfile) + var cf = Cfile(cname: cfile, obj: completeCFilePath(toObjFile(cfile)), flags: {}) + var code = genModule(m, cf) when hasTinyCBackend: if gCmd == cmdRun: tccgen.compileCCode($code) return - if shouldRecompile(code, cfile): - addFileToCompile(cfile) + if not shouldRecompile(code, cf): cf.flags = {CfileFlag.Cached} + addFileToCompile(cf) elif pending and mergeRequired(m) and sfMainModule notin m.module.flags: + let cf = Cfile(cname: cfile, obj: completeCFilePath(toObjFile(cfile)), flags: {}) mergeFiles(cfile, m) genInitCode(m) finishTypeDescriptions(m) - var code = genModule(m, cfile) + var code = genModule(m, cf) writeRope(code, cfile) - addFileToCompile(cfile) - elif not existsFile(toObjFile(cfilenoext)): + addFileToCompile(cf) + else: # Consider: first compilation compiles ``system.nim`` and produces # ``system.c`` but then compilation fails due to an error. This means # that ``system.o`` is missing, so we need to call the C compiler for it: - addFileToCompile(cfile) - - addFileToLink(cfilenoext) + var cf = Cfile(cname: cfile, obj: completeCFilePath(toObjFile(cfile)), flags: {}) + if not existsFile(cf.obj): cf.flags = {CfileFlag.Cached} + addFileToCompile(cf) proc updateCachedModule(m: BModule) = let cfile = getCFile(m) - let cfilenoext = changeFileExt(cfile, "") + var cf = Cfile(cname: cfile, obj: completeCFilePath(toObjFile(cfile)), flags: {}) if mergeRequired(m) and sfMainModule notin m.module.flags: mergeFiles(cfile, m) genInitCode(m) finishTypeDescriptions(m) - var code = genModule(m, cfile) - writeRope(code, cfile) - addFileToCompile(cfile) - addFileToLink(cfilenoext) + var code = genModule(m, cf) + writeRope(code, cfile) + else: + cf.flags = {CfileFlag.Cached} + addFileToCompile(cf) proc myClose(b: PPassContext, n: PNode): PNode = result = n diff --git a/compiler/commands.nim b/compiler/commands.nim index 1ddc85b23..61189fba1 100644 --- a/compiler/commands.nim +++ b/compiler/commands.nim @@ -193,9 +193,7 @@ proc processSpecificNote*(arg: string, state: TSpecialWord, pass: TCmdLinePass, proc processCompile(filename: string) = var found = findFile(filename) if found == "": found = filename - var trunc = changeFileExt(found, "") extccomp.addExternalFileToCompile(found) - extccomp.addFileToLink(completeCFilePath(trunc, false)) proc testCompileOptionArg*(switch, arg: string, info: TLineInfo): bool = case switch.normalize @@ -370,7 +368,7 @@ proc processSwitch(switch, arg: string, pass: TCmdLinePass, info: TLineInfo) = if pass in {passCmd2, passPP}: processCompile(arg) of "link": expectArg(switch, arg, pass, info) - if pass in {passCmd2, passPP}: addFileToLink(arg) + if pass in {passCmd2, passPP}: addExternalFileToLink(arg) of "debuginfo": expectNoArg(switch, arg, pass, info) incl(gGlobalOptions, optCDebug) diff --git a/compiler/extccomp.nim b/compiler/extccomp.nim index cdd93f075..36097a172 100644 --- a/compiler/extccomp.nim +++ b/compiler/extccomp.nim @@ -379,11 +379,23 @@ const proc libNameTmpl(): string {.inline.} = result = if targetOS == osWindows: "$1.lib" else: "lib$1.a" +type + CfileFlag* {.pure.} = enum + Cached, ## no need to recompile this time + External ## file was introduced via .compile pragma + + Cfile* = object + cname*, obj*: string + flags*: set[CFileFlag] + CfileList = seq[Cfile] + var - toLink, toCompile, externalToCompile: TLinkedList + externalToLink: TLinkedList # files to link in addition to the file + # we compiled linkOptions: string = "" compileOptions: string = "" ccompilerpath: string = "" + toCompile: CfileList = @[] proc nameToCC*(name: string): TSystemCC = ## Returns the kind of compiler referred to by `name`, or ccNone @@ -452,22 +464,24 @@ proc completeCFilePath*(cfile: string, createSubDir: bool = true): string = proc toObjFile*(filename: string): string = # Object file for compilation + #if filename.endsWith(".cpp"): + # result = changeFileExt(filename, "cpp." & CC[cCompiler].objExt) + #else: result = changeFileExt(filename, CC[cCompiler].objExt) -proc addFileToCompile*(filename: string) = - appendStr(toCompile, filename) +proc addFileToCompile*(cf: Cfile) = + toCompile.add(cf) proc resetCompilationLists* = - initLinkedList(toCompile) + toCompile.setLen 0 ## XXX: we must associate these with their originating module # when the module is loaded/unloaded it adds/removes its items # That's because we still need to hash check the external files # Maybe we can do that in checkDep on the other hand? - initLinkedList(externalToCompile) - initLinkedList(toLink) + initLinkedList(externalToLink) -proc addFileToLink*(filename: string) = - prependStr(toLink, filename) +proc addExternalFileToLink*(filename: string) = + prependStr(externalToLink, filename) # BUGFIX: was ``appendStr`` proc execWithEcho(cmd: string, msg = hintExecuting): int = @@ -505,8 +519,6 @@ proc noAbsolutePaths: bool {.inline.} = # `optGenMapping` is included here for niminst. result = gGlobalOptions * {optGenScript, optGenMapping} != {} -var fileCounter: int - proc add(s: var string, many: openArray[string]) = s.add many.join @@ -553,9 +565,9 @@ proc getLinkerExe(compiler: TSystemCC): string = elif gMixedMode and gCmd != cmdCompileToCpp: CC[compiler].cppCompiler else: compiler.getCompilerExe -proc getCompileCFileCmd*(cfilename: string, isExternal = false): string = +proc getCompileCFileCmd*(cfile: Cfile): string = var c = cCompiler - if cfilename.endswith(".asm"): + if cfile.cname.endswith(".asm"): var customAssembler = getConfigVar("assembler") if customAssembler.len > 0: c = nameToCC(customAssembler) @@ -570,7 +582,7 @@ proc getCompileCFileCmd*(cfilename: string, isExternal = false): string = elif c notin cValidAssemblers: rawMessage(errExternalAssemblerNotValid, customAssembler) - var options = cFileSpecificOptions(cfilename) + var options = cFileSpecificOptions(cfile.cname) var exe = getConfigVar(c, ".exe") if exe.len == 0: exe = c.getCompilerExe @@ -592,40 +604,48 @@ proc getCompileCFileCmd*(cfilename: string, isExternal = false): string = includeCmd = "" compilePattern = c.getCompilerExe - var cfile = if noAbsolutePaths(): extractFilename(cfilename) - else: cfilename - var objfile = if not isExternal or noAbsolutePaths(): - toObjFile(cfile) - else: - completeCFilePath(toObjFile(cfile)) + var cf = if noAbsolutePaths(): extractFilename(cfile.cname) + else: cfile.cname + + var objfile = + if cfile.obj.len == 0: + if not cfile.flags.contains(CfileFlag.External) or noAbsolutePaths(): + toObjFile(cf) + else: + completeCFilePath(toObjFile(cf)) + elif noAbsolutePaths(): + extractFilename(cfile.obj) + else: + cfile.obj + objfile = quoteShell(objfile) - cfile = quoteShell(cfile) + cf = quoteShell(cf) result = quoteShell(compilePattern % [ - "file", cfile, "objfile", objfile, "options", options, + "file", cf, "objfile", objfile, "options", options, "include", includeCmd, "nim", getPrefixDir(), "nim", getPrefixDir(), "lib", libpath]) add(result, ' ') addf(result, CC[c].compileTmpl, [ - "file", cfile, "objfile", objfile, + "file", cf, "objfile", objfile, "options", options, "include", includeCmd, "nim", quoteShell(getPrefixDir()), "nim", quoteShell(getPrefixDir()), "lib", quoteShell(libpath)]) -proc footprint(filename: string): SecureHash = +proc footprint(cfile: Cfile): SecureHash = result = secureHash( - $secureHashFile(filename) & + $secureHashFile(cfile.cname) & platform.OS[targetOS].name & platform.CPU[targetCPU].name & extccomp.CC[extccomp.cCompiler].name & - getCompileCFileCmd(filename, true)) + getCompileCFileCmd(cfile)) -proc externalFileChanged(filename: string): bool = +proc externalFileChanged(cfile: Cfile): bool = if gCmd notin {cmdCompileToC, cmdCompileToCpp, cmdCompileToOC, cmdCompileToLLVM}: return false - var hashFile = toGeneratedFile(filename.withPackageName, "sha1") - var currentHash = footprint(filename) + var hashFile = toGeneratedFile(cfile.cname.withPackageName, "sha1") + var currentHash = footprint(cfile) var f: File if open(f, hashFile, fmRead): let oldHash = parseSecureHash(f.readLine()) @@ -639,23 +659,29 @@ proc externalFileChanged(filename: string): bool = close(f) proc addExternalFileToCompile*(filename: string) = - if optForceFullMake in gGlobalOptions or externalFileChanged(filename): - appendStr(externalToCompile, filename) - -proc compileCFile(list: TLinkedList, script: var Rope, cmds: var TStringSeq, - prettyCmds: var TStringSeq, isExternal: bool) = - var it = PStrEntry(list.head) - while it != nil: - inc(fileCounter) # call the C compiler for the .c file: - var compileCmd = getCompileCFileCmd(it.data, isExternal) + let c = Cfile(cname: filename, + obj: toObjFile(completeCFilePath(changeFileExt(filename, ""), false)), + flags: {CfileFlag.External}) + if optForceFullMake in gGlobalOptions or externalFileChanged(c): + toCompile.add(c) + +proc addExternalFileToCompile*(c: Cfile) = + if optForceFullMake in gGlobalOptions or externalFileChanged(c): + toCompile.add(c) + +proc compileCFile(list: CFileList, script: var Rope, cmds: var TStringSeq, + prettyCmds: var TStringSeq) = + for it in list: + # call the C compiler for the .c file: + if it.flags.contains(CfileFlag.Cached): continue + var compileCmd = getCompileCFileCmd(it) if optCompileOnly notin gGlobalOptions: add(cmds, compileCmd) - let (dir, name, ext) = splitFile(it.data) + let (_, name, _) = splitFile(it.cname) add(prettyCmds, "CC: " & name) if optGenScript in gGlobalOptions: add(script, compileCmd) add(script, tnl) - it = PStrEntry(it.next) proc getLinkCmd(projectfile, objfiles: string): string = if optGenStaticLib in gGlobalOptions: @@ -712,7 +738,6 @@ proc callCCompiler*(projectfile: string) = if gGlobalOptions * {optCompileOnly, optGenScript} == {optCompileOnly}: return # speed up that call if only compiling and no script shall be # generated - fileCounter = 0 #var c = cCompiler var script: Rope = nil var cmds: TStringSeq = @[] @@ -725,8 +750,7 @@ proc callCCompiler*(projectfile: string) = rawMessage(errGenerated, "execution of an external compiler program '" & cmds[idx] & "' failed with exit code: " & $exitCode & "\n\n" & p.outputStream.readAll.strip) - compileCFile(toCompile, script, cmds, prettyCmds, false) - compileCFile(externalToCompile, script, cmds, prettyCmds, true) + compileCFile(toCompile, script, cmds, prettyCmds) if optCompileOnly notin gGlobalOptions: if gNumberOfProcessors == 0: gNumberOfProcessors = countProcessors() var res = 0 @@ -748,7 +772,7 @@ proc callCCompiler*(projectfile: string) = rawMessage(errExecutionOfProgramFailed, cmds.join()) if optNoLinking notin gGlobalOptions: # call the linker: - var it = PStrEntry(toLink.head) + var it = PStrEntry(externalToLink.head) var objfiles = "" while it != nil: let objFile = if noAbsolutePaths(): it.data.extractFilename else: it.data @@ -756,6 +780,9 @@ proc callCCompiler*(projectfile: string) = add(objfiles, quoteShell( addFileExt(objFile, CC[cCompiler].objExt))) it = PStrEntry(it.next) + for x in toCompile: + add(objfiles, ' ') + add(objfiles, x.obj) linkCmd = getLinkCmd(projectfile, objfiles) if optCompileOnly notin gGlobalOptions: @@ -780,16 +807,17 @@ proc writeJsonBuildInstructions*(projectfile: string) = else: f.write escapeJson(x) - proc cfiles(f: File; buf: var string; list: TLinkedList, isExternal: bool) = - var it = PStrEntry(list.head) - while it != nil: - let compileCmd = getCompileCFileCmd(it.data, isExternal) + proc cfiles(f: File; buf: var string; list: CfileList, isExternal: bool) = + var i = 0 + for it in list: + if CfileFlag.Cached in it.flags: continue + let compileCmd = getCompileCFileCmd(it) lit "[" - str it.data + str it.cname lit ", " str compileCmd - it = PStrEntry(it.next) - if it == nil: + inc i + if i == list.len: lit "]\L" else: lit "],\L" @@ -816,28 +844,24 @@ proc writeJsonBuildInstructions*(projectfile: string) = if open(f, jsonFile, fmWrite): lit "{\"compile\":[\L" cfiles(f, buf, toCompile, false) - lit "],\L\"extcompile\":[\L" - cfiles(f, buf, externalToCompile, true) lit "],\L\"link\":[\L" var objfiles = "" - linkfiles(f, buf, objfiles, toLink) + # XXX add every file here that is to link + linkfiles(f, buf, objfiles, externalToLink) lit "],\L\"linkcmd\": " str getLinkCmd(projectfile, objfiles) lit "\L}\L" close(f) -proc genMappingFiles(list: TLinkedList): Rope = - var it = PStrEntry(list.head) - while it != nil: - addf(result, "--file:r\"$1\"$N", [rope(it.data)]) - it = PStrEntry(it.next) +proc genMappingFiles(list: CFileList): Rope = + for it in list: + addf(result, "--file:r\"$1\"$N", [rope(it.cname)]) proc writeMapping*(gSymbolMapping: Rope) = if optGenMapping notin gGlobalOptions: return var code = rope("[C_Files]\n") add(code, genMappingFiles(toCompile)) - add(code, genMappingFiles(externalToCompile)) add(code, "\n[C_Compiler]\nFlags=") add(code, strutils.escape(getCompileOptions())) diff --git a/compiler/pragmas.nim b/compiler/pragmas.nim index 3bed7fa03..3808b8f58 100644 --- a/compiler/pragmas.nim +++ b/compiler/pragmas.nim @@ -402,29 +402,41 @@ proc relativeFile(c: PContext; n: PNode; ext=""): string = if result.len == 0: result = s proc processCompile(c: PContext, n: PNode) = - var s = expectStrLit(c, n) - var found = parentDir(n.info.toFullPath) / s - if '*' in found: + + proc getStrLit(c: PContext, n: PNode; i: int): string = + n.sons[i] = c.semConstExpr(c, n.sons[i]) + case n.sons[i].kind + of nkStrLit, nkRStrLit, nkTripleStrLit: + shallowCopy(result, n.sons[i].strVal) + else: + localError(n.info, errStringLiteralExpected) + result = "" + + let it = if n.kind == nkExprColonExpr: n.sons[1] else: n + if it.kind == nkPar and it.len == 2: + let s = getStrLit(c, it, 0) + let dest = getStrLit(c, it, 1) + var found = parentDir(n.info.toFullPath) / s for f in os.walkFiles(found): - let trunc = f.changeFileExt("") - extccomp.addExternalFileToCompile(f) - extccomp.addFileToLink(completeCFilePath(trunc, false)) + let nameOnly = extractFilename(f) + extccomp.addExternalFileToCompile(Cfile(cname: f, + obj: dest % nameOnly, flags: {CfileFlag.External})) else: + let s = expectStrLit(c, n) + var found = parentDir(n.info.toFullPath) / s if not fileExists(found): if isAbsolute(s): found = s else: found = findFile(s) if found.len == 0: found = s - let trunc = found.changeFileExt("") extccomp.addExternalFileToCompile(found) - extccomp.addFileToLink(completeCFilePath(trunc, false)) proc processCommonLink(c: PContext, n: PNode, feature: TLinkFeature) = let found = relativeFile(c, n, CC[cCompiler].objExt) case feature - of linkNormal: extccomp.addFileToLink(found) + of linkNormal: extccomp.addExternalFileToLink(found) of linkSys: - extccomp.addFileToLink(libpath / completeCFilePath(found, false)) + extccomp.addExternalFileToLink(libpath / completeCFilePath(found, false)) else: internalError(n.info, "processCommonLink") proc pragmaBreakpoint(c: PContext, n: PNode) = |