crc check for external files to compile; bugfix: os.parseCmdLine
This commit is contained in:
parent
b2ad7b30dc
commit
e90665bff2
7 changed files with 145 additions and 54 deletions
|
|
@ -926,28 +926,90 @@ proc createDir*(dir: string) =
|
||||||
rawCreateDir(dir)
|
rawCreateDir(dir)
|
||||||
|
|
||||||
proc parseCmdLine*(c: string): seq[string] =
|
proc parseCmdLine*(c: string): seq[string] =
|
||||||
## Splits a command line into several components; components are separated by
|
## Splits a command line into several components;
|
||||||
## whitespace unless the whitespace occurs within ``"`` or ``'`` quotes.
|
|
||||||
## This proc is only occassionally useful, better use the `parseopt` module.
|
## This proc is only occassionally useful, better use the `parseopt` module.
|
||||||
|
##
|
||||||
|
## On Windows, it uses the following parsing rules
|
||||||
|
## (see http://msdn.microsoft.com/en-us/library/17w5ykft.aspx):
|
||||||
|
##
|
||||||
|
## * Arguments are delimited by white space, which is either a space or a tab.
|
||||||
|
## * The caret character (^) is not recognized as an escape character or
|
||||||
|
## delimiter. The character is handled completely by the command-line parser
|
||||||
|
## in the operating system before being passed to the argv array in the
|
||||||
|
## program.
|
||||||
|
## * A string surrounded by double quotation marks ("string") is interpreted
|
||||||
|
## as a single argument, regardless of white space contained within. A
|
||||||
|
## quoted string can be embedded in an argument.
|
||||||
|
## * A double quotation mark preceded by a backslash (\") is interpreted as a
|
||||||
|
## literal double quotation mark character (").
|
||||||
|
## * Backslashes are interpreted literally, unless they immediately precede
|
||||||
|
## a double quotation mark.
|
||||||
|
## * If an even number of backslashes is followed by a double quotation mark,
|
||||||
|
## one backslash is placed in the argv array for every pair of backslashes,
|
||||||
|
## and the double quotation mark is interpreted as a string delimiter.
|
||||||
|
## * If an odd number of backslashes is followed by a double quotation mark,
|
||||||
|
## one backslash is placed in the argv array for every pair of backslashes,
|
||||||
|
## and the double quotation mark is "escaped" by the remaining backslash,
|
||||||
|
## causing a literal double quotation mark (") to be placed in argv.
|
||||||
|
##
|
||||||
|
## On Posix systems, it uses the following parsing rules:
|
||||||
|
## components are separated by
|
||||||
|
## whitespace unless the whitespace occurs within ``"`` or ``'`` quotes.
|
||||||
result = @[]
|
result = @[]
|
||||||
var i = 0
|
var i = 0
|
||||||
var a = ""
|
var a = ""
|
||||||
while true:
|
while true:
|
||||||
setLen(a, 0)
|
setLen(a, 0)
|
||||||
while c[i] >= '\1' and c[i] <= ' ': inc(i) # skip whitespace
|
while c[i] == ' ' or c[i] == '\t': inc(i)
|
||||||
case c[i]
|
when defined(windows):
|
||||||
of '\'', '\"':
|
# parse a single argument according to the above rules:
|
||||||
var delim = c[i]
|
var inQuote = false
|
||||||
inc(i) # skip ' or "
|
while true:
|
||||||
while c[i] != '\0' and c[i] != delim:
|
case c[i]
|
||||||
add a, c[i]
|
of '\0': break
|
||||||
inc(i)
|
of '\\':
|
||||||
if c[i] != '\0': inc(i)
|
var j = i
|
||||||
of '\0': break
|
while c[j] == '\\': inc(j)
|
||||||
|
if c[j] == '"':
|
||||||
|
for k in 0..(j-i) div 2: a.add('\\')
|
||||||
|
if (j-i) mod 2 == 0:
|
||||||
|
i = j
|
||||||
|
else:
|
||||||
|
a.add('"')
|
||||||
|
i = j+1
|
||||||
|
else:
|
||||||
|
a.add(c[i])
|
||||||
|
inc(i)
|
||||||
|
of '"':
|
||||||
|
inc(i)
|
||||||
|
if not inQuote: inQuote = true
|
||||||
|
elif c[i] == '"':
|
||||||
|
a.add(c[i])
|
||||||
|
inc(i)
|
||||||
|
else:
|
||||||
|
inQuote = false
|
||||||
|
break
|
||||||
|
of ' ', '\t':
|
||||||
|
if not inQuote: break
|
||||||
|
a.add(c[i])
|
||||||
|
inc(i)
|
||||||
|
else:
|
||||||
|
a.add(c[i])
|
||||||
|
inc(i)
|
||||||
else:
|
else:
|
||||||
while c[i] > ' ':
|
case c[i]
|
||||||
add(a, c[i])
|
of '\'', '\"':
|
||||||
inc(i)
|
var delim = c[i]
|
||||||
|
inc(i) # skip ' or "
|
||||||
|
while c[i] != '\0' and c[i] != delim:
|
||||||
|
add a, c[i]
|
||||||
|
inc(i)
|
||||||
|
if c[i] != '\0': inc(i)
|
||||||
|
of '\0': break
|
||||||
|
else:
|
||||||
|
while c[i] > ' ':
|
||||||
|
add(a, c[i])
|
||||||
|
inc(i)
|
||||||
add(result, a)
|
add(result, a)
|
||||||
|
|
||||||
type
|
type
|
||||||
|
|
|
||||||
|
|
@ -233,9 +233,9 @@ type
|
||||||
## that is too small to be represented as
|
## that is too small to be represented as
|
||||||
## a normal number
|
## a normal number
|
||||||
EFloatInexact* {.compilerproc.} =
|
EFloatInexact* {.compilerproc.} =
|
||||||
object of EFloatingPoint ## Inexact. Operation produces a result that cannot
|
object of EFloatingPoint ## Inexact. Operation produces a result
|
||||||
## be represented with infinite precision --
|
## that cannot be represented with infinite
|
||||||
## for example, 2.0 / 3.0, log(1.1)
|
## precision -- for example, 2.0 / 3.0, log(1.1)
|
||||||
## NOTE: Nimrod currently does not detect these!
|
## NOTE: Nimrod currently does not detect these!
|
||||||
|
|
||||||
TResult* = enum Failure, Success
|
TResult* = enum Failure, Success
|
||||||
|
|
@ -962,7 +962,7 @@ proc `$` *(x: Cstring): string {.magic: "CStrToStr", noSideEffect.}
|
||||||
proc `$` *(x: string): string {.magic: "StrToStr", noSideEffect.}
|
proc `$` *(x: string): string {.magic: "StrToStr", noSideEffect.}
|
||||||
## The stingify operator for a string argument. Returns `x`
|
## The stingify operator for a string argument. Returns `x`
|
||||||
## as it is. This operator is useful for generic code, so
|
## as it is. This operator is useful for generic code, so
|
||||||
## that ``$expr`` also works if ``expr`` is already a string.
|
## that ``$expr`` also works if ``expr`` already is a string.
|
||||||
|
|
||||||
proc `$` *[T](x: ordinal[T]): string {.magic: "EnumToStr", noSideEffect.}
|
proc `$` *[T](x: ordinal[T]): string {.magic: "EnumToStr", noSideEffect.}
|
||||||
## The stingify operator for an enumeration argument. This works for
|
## The stingify operator for an enumeration argument. This works for
|
||||||
|
|
|
||||||
|
|
@ -216,11 +216,10 @@ proc processPath(path: string): string =
|
||||||
result = UnixToNativePath(path % ["nimrod", getPrefixDir(), "lib", libpath])
|
result = UnixToNativePath(path % ["nimrod", getPrefixDir(), "lib", libpath])
|
||||||
|
|
||||||
proc processCompile(filename: string) =
|
proc processCompile(filename: string) =
|
||||||
var found, trunc: string
|
var found = findFile(filename)
|
||||||
found = findFile(filename)
|
|
||||||
if found == "": found = filename
|
if found == "": found = filename
|
||||||
trunc = changeFileExt(found, "")
|
var trunc = changeFileExt(found, "")
|
||||||
extccomp.addExternalFileToCompile(trunc)
|
extccomp.addExternalFileToCompile(found)
|
||||||
extccomp.addFileToLink(completeCFilePath(trunc, false))
|
extccomp.addFileToLink(completeCFilePath(trunc, false))
|
||||||
|
|
||||||
proc processSwitch(switch, arg: string, pass: TCmdlinePass, info: TLineInfo) =
|
proc processSwitch(switch, arg: string, pass: TCmdlinePass, info: TLineInfo) =
|
||||||
|
|
|
||||||
13
rod/crc.nim
13
rod/crc.nim
|
|
@ -1,7 +1,7 @@
|
||||||
#
|
#
|
||||||
#
|
#
|
||||||
# The Nimrod Compiler
|
# The Nimrod Compiler
|
||||||
# (c) Copyright 2008 Andreas Rumpf
|
# (c) Copyright 2010 Andreas Rumpf
|
||||||
#
|
#
|
||||||
# See the file "copying.txt", included in this
|
# See the file "copying.txt", included in this
|
||||||
# distribution, for details about the copyright.
|
# distribution, for details about the copyright.
|
||||||
|
|
@ -90,8 +90,7 @@ type
|
||||||
PByteArray = ref TByteArray
|
PByteArray = ref TByteArray
|
||||||
|
|
||||||
proc crcFromBuf(buf: Pointer, length: int): TCrc32 =
|
proc crcFromBuf(buf: Pointer, length: int): TCrc32 =
|
||||||
var p: PByteArray
|
var p = cast[PByteArray](buf)
|
||||||
p = cast[PByteArray](buf)
|
|
||||||
result = InitCrc32
|
result = InitCrc32
|
||||||
for i in countup(0, length - 1): result = updateCrc32(p[i], result)
|
for i in countup(0, length - 1): result = updateCrc32(p[i], result)
|
||||||
|
|
||||||
|
|
@ -117,10 +116,12 @@ proc crcFromFile(filename: string): TCrc32 =
|
||||||
|
|
||||||
const
|
const
|
||||||
base = int32(65521) # largest prime smaller than 65536
|
base = int32(65521) # largest prime smaller than 65536
|
||||||
#NMAX = 5552; original code with unsigned 32 bit integer
|
# NMAX = 5552; original code with unsigned 32 bit integer
|
||||||
# NMAX is the largest n such that 255n(n+1)/2 + (n+1)(BASE-1) <= 2^32-1
|
# NMAX is the largest n
|
||||||
|
# such that 255n(n+1)/2 + (n+1)(BASE-1) <= 2^32-1
|
||||||
nmax = 3854 # code with signed 32 bit integer
|
nmax = 3854 # code with signed 32 bit integer
|
||||||
# NMAX is the largest n such that 255n(n+1)/2 + (n+1)(BASE-1) <= 2^31-1
|
# NMAX is the largest n such that
|
||||||
|
# 255n(n+1)/2 + (n+1)(BASE-1) <= 2^31-1
|
||||||
# The penalty is the time loss in the extra MOD-calls.
|
# The penalty is the time loss in the extra MOD-calls.
|
||||||
|
|
||||||
proc updateAdler32(adler: int32, buf: pointer, length: int): int32 =
|
proc updateAdler32(adler: int32, buf: pointer, length: int): int32 =
|
||||||
|
|
|
||||||
|
|
@ -11,7 +11,7 @@
|
||||||
# some things are read in from the configuration file
|
# some things are read in from the configuration file
|
||||||
|
|
||||||
import
|
import
|
||||||
lists, ropes, os, strutils, osproc, platform, condsyms, options, msgs
|
lists, ropes, os, strutils, osproc, platform, condsyms, options, msgs, crc
|
||||||
|
|
||||||
type
|
type
|
||||||
TSystemCC* = enum
|
TSystemCC* = enum
|
||||||
|
|
@ -299,12 +299,30 @@ proc toObjFile(filenameWithoutExt: string): string =
|
||||||
proc addFileToCompile(filename: string) =
|
proc addFileToCompile(filename: string) =
|
||||||
appendStr(toCompile, filename)
|
appendStr(toCompile, filename)
|
||||||
|
|
||||||
|
proc externalFileChanged(filename: string): bool =
|
||||||
|
var crcFile = toGeneratedFile(filename, "crc")
|
||||||
|
var currentCrc = int(crcFromFile(filename))
|
||||||
|
var f: TFile
|
||||||
|
if open(f, crcFile, fmRead):
|
||||||
|
var line = f.readLine()
|
||||||
|
if isNil(line) or line.len == 0: line = "0"
|
||||||
|
close(f)
|
||||||
|
var oldCrc = parseInt(line)
|
||||||
|
result = oldCrc != currentCrc
|
||||||
|
else:
|
||||||
|
result = true
|
||||||
|
if result:
|
||||||
|
if open(f, crcFile, fmWrite):
|
||||||
|
f.writeln($currentCrc)
|
||||||
|
close(f)
|
||||||
|
|
||||||
proc addExternalFileToCompile(filename: string) =
|
proc addExternalFileToCompile(filename: string) =
|
||||||
appendStr(externalToCompile, filename)
|
if optForceFullMake in gGlobalOptions or externalFileChanged(filename):
|
||||||
|
appendStr(externalToCompile, changeFileExt(filename, ""))
|
||||||
|
|
||||||
proc addFileToLink(filename: string) =
|
proc addFileToLink(filename: string) =
|
||||||
prependStr(toLink, filename) # BUGFIX
|
prependStr(toLink, filename)
|
||||||
#appendStr(toLink, filename);
|
# BUGFIX: was ``appendStr``
|
||||||
|
|
||||||
proc execExternalProgram(cmd: string) =
|
proc execExternalProgram(cmd: string) =
|
||||||
if (optListCmd in gGlobalOptions) or (gVerbosity > 0): MessageOut(cmd)
|
if (optListCmd in gGlobalOptions) or (gVerbosity > 0): MessageOut(cmd)
|
||||||
|
|
@ -361,8 +379,8 @@ proc getCompileCFileCmd(cfilename: string, isExternal: bool = false): string =
|
||||||
key = cc[c].name & ".exe"
|
key = cc[c].name & ".exe"
|
||||||
if existsConfigVar(key): exe = getConfigVar(key)
|
if existsConfigVar(key): exe = getConfigVar(key)
|
||||||
if targetOS == osWindows: exe = addFileExt(exe, "exe")
|
if targetOS == osWindows: exe = addFileExt(exe, "exe")
|
||||||
if (optGenDynLib in gGlobalOptions) and
|
if optGenDynLib in gGlobalOptions and
|
||||||
(ospNeedsPIC in platform.OS[targetOS].props):
|
ospNeedsPIC in platform.OS[targetOS].props:
|
||||||
add(options, ' ' & cc[c].pic)
|
add(options, ' ' & cc[c].pic)
|
||||||
if targetOS == platform.hostOS:
|
if targetOS == platform.hostOS:
|
||||||
# compute include paths:
|
# compute include paths:
|
||||||
|
|
@ -383,11 +401,11 @@ proc getCompileCFileCmd(cfilename: string, isExternal: bool = false): string =
|
||||||
objfile, "options", options, "include", includeCmd, "nimrod",
|
objfile, "options", options, "include", includeCmd, "nimrod",
|
||||||
getPrefixDir(), "lib", libpath]))
|
getPrefixDir(), "lib", libpath]))
|
||||||
add(result, ' ')
|
add(result, ' ')
|
||||||
add(result, `%`(cc[c].compileTmpl, ["file", cfile, "objfile", objfile,
|
addf(result, cc[c].compileTmpl, [
|
||||||
"options", options, "include", includeCmd,
|
"file", cfile, "objfile", objfile,
|
||||||
"nimrod",
|
"options", options, "include", includeCmd,
|
||||||
quoteIfContainsWhite(getPrefixDir()),
|
"nimrod", quoteIfContainsWhite(getPrefixDir()),
|
||||||
"lib", quoteIfContainsWhite(libpath)]))
|
"lib", quoteIfContainsWhite(libpath)])
|
||||||
|
|
||||||
proc CompileCFile(list: TLinkedList, script: var PRope, cmds: var TStringSeq,
|
proc CompileCFile(list: TLinkedList, script: var PRope, cmds: var TStringSeq,
|
||||||
isExternal: bool) =
|
isExternal: bool) =
|
||||||
|
|
@ -396,7 +414,7 @@ proc CompileCFile(list: TLinkedList, script: var PRope, cmds: var TStringSeq,
|
||||||
inc(fileCounter) # call the C compiler for the .c file:
|
inc(fileCounter) # call the C compiler for the .c file:
|
||||||
var compileCmd = getCompileCFileCmd(it.data, isExternal)
|
var compileCmd = getCompileCFileCmd(it.data, isExternal)
|
||||||
if not (optCompileOnly in gGlobalOptions):
|
if not (optCompileOnly in gGlobalOptions):
|
||||||
add(cmds, compileCmd) #execExternalProgram(compileCmd);
|
add(cmds, compileCmd)
|
||||||
if (optGenScript in gGlobalOptions):
|
if (optGenScript in gGlobalOptions):
|
||||||
app(script, compileCmd)
|
app(script, compileCmd)
|
||||||
app(script, tnl)
|
app(script, tnl)
|
||||||
|
|
@ -405,7 +423,7 @@ proc CompileCFile(list: TLinkedList, script: var PRope, cmds: var TStringSeq,
|
||||||
proc CallCCompiler(projectfile: string) =
|
proc CallCCompiler(projectfile: string) =
|
||||||
var
|
var
|
||||||
linkCmd, buildgui, builddll: string
|
linkCmd, buildgui, builddll: string
|
||||||
if (gGlobalOptions * {optCompileOnly, optGenScript} == {optCompileOnly}):
|
if gGlobalOptions * {optCompileOnly, optGenScript} == {optCompileOnly}:
|
||||||
return # speed up that call if only compiling and no script shall be
|
return # speed up that call if only compiling and no script shall be
|
||||||
# generated
|
# generated
|
||||||
fileCounter = 0
|
fileCounter = 0
|
||||||
|
|
@ -414,7 +432,7 @@ proc CallCCompiler(projectfile: string) =
|
||||||
var cmds: TStringSeq = @[]
|
var cmds: TStringSeq = @[]
|
||||||
CompileCFile(toCompile, script, cmds, false)
|
CompileCFile(toCompile, script, cmds, false)
|
||||||
CompileCFile(externalToCompile, script, cmds, true)
|
CompileCFile(externalToCompile, script, cmds, true)
|
||||||
if not (optCompileOnly in gGlobalOptions):
|
if optCompileOnly notin gGlobalOptions:
|
||||||
if gNumberOfProcessors == 0: gNumberOfProcessors = countProcessors()
|
if gNumberOfProcessors == 0: gNumberOfProcessors = countProcessors()
|
||||||
var res = 0
|
var res = 0
|
||||||
if gNumberOfProcessors <= 1:
|
if gNumberOfProcessors <= 1:
|
||||||
|
|
@ -426,7 +444,7 @@ proc CallCCompiler(projectfile: string) =
|
||||||
res = execProcesses(cmds, {poUseShell, poParentStreams},
|
res = execProcesses(cmds, {poUseShell, poParentStreams},
|
||||||
gNumberOfProcessors)
|
gNumberOfProcessors)
|
||||||
if res != 0: rawMessage(errExecutionOfProgramFailed, [])
|
if res != 0: rawMessage(errExecutionOfProgramFailed, [])
|
||||||
if not (optNoLinking in gGlobalOptions):
|
if optNoLinking notin gGlobalOptions:
|
||||||
# call the linker:
|
# call the linker:
|
||||||
var linkerExe = getConfigVar(cc[c].name & ".linkerexe")
|
var linkerExe = getConfigVar(cc[c].name & ".linkerexe")
|
||||||
if len(linkerExe) == 0: linkerExe = cc[c].linkerExe
|
if len(linkerExe) == 0: linkerExe = cc[c].linkerExe
|
||||||
|
|
@ -448,22 +466,21 @@ proc CallCCompiler(projectfile: string) =
|
||||||
var it = PStrEntry(toLink.head)
|
var it = PStrEntry(toLink.head)
|
||||||
var objfiles = ""
|
var objfiles = ""
|
||||||
while it != nil:
|
while it != nil:
|
||||||
add(objfiles, " ")
|
add(objfiles, ' ')
|
||||||
if targetOS == platform.hostOS:
|
if targetOS == platform.hostOS:
|
||||||
add(objfiles, quoteIfContainsWhite(toObjfile(it.data)))
|
add(objfiles, quoteIfContainsWhite(toObjfile(it.data)))
|
||||||
else:
|
else:
|
||||||
add(objfiles, quoteIfContainsWhite(toObjfile(extractFileName(it.data))))
|
add(objfiles, quoteIfContainsWhite(toObjfile(extractFileName(it.data))))
|
||||||
it = PStrEntry(it.next)
|
it = PStrEntry(it.next)
|
||||||
linkCmd = quoteIfContainsWhite(`%`(linkCmd, ["builddll", builddll,
|
linkCmd = quoteIfContainsWhite(linkCmd % ["builddll", builddll,
|
||||||
"buildgui", buildgui, "options", linkOptions, "objfiles", objfiles,
|
"buildgui", buildgui, "options", linkOptions, "objfiles", objfiles,
|
||||||
"exefile", exefile, "nimrod", getPrefixDir(), "lib", libpath]))
|
"exefile", exefile, "nimrod", getPrefixDir(), "lib", libpath])
|
||||||
add(linkCmd, ' ')
|
add(linkCmd, ' ')
|
||||||
add(linkCmd, `%`(cc[c].linkTmpl, ["builddll", builddll, "buildgui",
|
addf(linkCmd, cc[c].linkTmpl, ["builddll", builddll,
|
||||||
buildgui, "options", linkOptions,
|
"buildgui", buildgui, "options", linkOptions,
|
||||||
"objfiles", objfiles, "exefile", exefile,
|
"objfiles", objfiles, "exefile", exefile,
|
||||||
"nimrod",
|
"nimrod", quoteIfContainsWhite(getPrefixDir()),
|
||||||
quoteIfContainsWhite(getPrefixDir()),
|
"lib", quoteIfContainsWhite(libpath)])
|
||||||
"lib", quoteIfContainsWhite(libpath)]))
|
|
||||||
if not (optCompileOnly in gGlobalOptions): execExternalProgram(linkCmd)
|
if not (optCompileOnly in gGlobalOptions): execExternalProgram(linkCmd)
|
||||||
else:
|
else:
|
||||||
linkCmd = ""
|
linkCmd = ""
|
||||||
|
|
|
||||||
|
|
@ -299,7 +299,7 @@ proc processCompile(c: PContext, n: PNode) =
|
||||||
var found = findFile(s)
|
var found = findFile(s)
|
||||||
if found == "": found = s
|
if found == "": found = s
|
||||||
var trunc = ChangeFileExt(found, "")
|
var trunc = ChangeFileExt(found, "")
|
||||||
extccomp.addExternalFileToCompile(trunc)
|
extccomp.addExternalFileToCompile(found)
|
||||||
extccomp.addFileToLink(completeCFilePath(trunc, false))
|
extccomp.addFileToLink(completeCFilePath(trunc, false))
|
||||||
|
|
||||||
proc processCommonLink(c: PContext, n: PNode, feature: TLinkFeature) =
|
proc processCommonLink(c: PContext, n: PNode, feature: TLinkFeature) =
|
||||||
|
|
|
||||||
12
web/news.txt
12
web/news.txt
|
|
@ -5,6 +5,12 @@ News
|
||||||
2010-XX-XX Version 0.8.10 released
|
2010-XX-XX Version 0.8.10 released
|
||||||
==================================
|
==================================
|
||||||
|
|
||||||
|
Bugfixes
|
||||||
|
--------
|
||||||
|
|
||||||
|
- Bugfix: Command line parsing on Windows and ``os.parseCmdLine`` now adheres
|
||||||
|
to the same parsing rules as Microsoft's C/C++ startup code.
|
||||||
|
|
||||||
|
|
||||||
Changes affecting backwards compatibility
|
Changes affecting backwards compatibility
|
||||||
-----------------------------------------
|
-----------------------------------------
|
||||||
|
|
@ -13,6 +19,12 @@ Changes affecting backwards compatibility
|
||||||
unless they are used in the same module.
|
unless they are used in the same module.
|
||||||
|
|
||||||
|
|
||||||
|
Additions
|
||||||
|
---------
|
||||||
|
|
||||||
|
- The ``{.compile: "file.c".}`` pragma uses a CRC check to see if the file
|
||||||
|
needs to be recompiled.
|
||||||
|
|
||||||
|
|
||||||
2010-03-14 Version 0.8.8 released
|
2010-03-14 Version 0.8.8 released
|
||||||
=================================
|
=================================
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue