diff options
Diffstat (limited to 'compiler/extccomp.nim')
-rw-r--r-- | compiler/extccomp.nim | 142 |
1 files changed, 83 insertions, 59 deletions
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())) |