.compile pragma supports patterns and actions
This commit is contained in:
parent
0e16d43196
commit
03a1c3b077
4 changed files with 141 additions and 102 deletions
|
|
@ -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)
|
||||
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 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)
|
||||
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()))
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue