the linking step doesn't mind Windows' 8K command line limit anymore

This commit is contained in:
Araq 2018-12-08 22:34:42 +01:00
commit 46820b94a6

View file

@ -652,13 +652,13 @@ proc compileCFile(conf: ConfigRef; list: CFileList, script: var Rope, cmds: var
add(script, compileCmd) add(script, compileCmd)
add(script, "\n") add(script, "\n")
proc getLinkCmd(conf: ConfigRef; projectfile: AbsoluteFile, objfiles: string; base: AbsoluteDir): string = proc getLinkCmd(conf: ConfigRef; projectfile: AbsoluteFile, objfiles: string): string =
if optGenStaticLib in conf.globalOptions: if optGenStaticLib in conf.globalOptions:
var libname: string var libname: string
if not conf.outFile.isEmpty: if not conf.outFile.isEmpty:
libname = conf.outFile.string.expandTilde libname = conf.outFile.string.expandTilde
if not libname.isAbsolute(): if not libname.isAbsolute():
libname = base.string / libname libname = getCurrentDir() / libname
else: else:
libname = (libNameTmpl(conf) % splitFile(conf.projectName).name) libname = (libNameTmpl(conf) % splitFile(conf.projectName).name)
result = CC[conf.cCompiler].buildLib % ["libfile", quoteShell(libname), result = CC[conf.cCompiler].buildLib % ["libfile", quoteShell(libname),
@ -683,11 +683,11 @@ proc getLinkCmd(conf: ConfigRef; projectfile: AbsoluteFile, objfiles: string; ba
builddll = "" builddll = ""
if not conf.outFile.isEmpty: if not conf.outFile.isEmpty:
exefile = conf.outFile.string.expandTilde exefile = conf.outFile.string.expandTilde
if not exefile.isAbsolute():
exefile = getCurrentDir() / exefile
if not noAbsolutePaths(conf): if not noAbsolutePaths(conf):
if not exefile.isAbsolute(): if not exefile.isAbsolute():
exefile = string(splitFile(projectfile).dir / RelativeFile(exefile)) exefile = string(splitFile(projectfile).dir / RelativeFile(exefile))
if not exefile.isAbsolute():
exefile = base.string / exefile
when false: when false:
if optCDebug in conf.globalOptions: if optCDebug in conf.globalOptions:
writeDebugInfo(exefile.changeFileExt("ndb")) writeDebugInfo(exefile.changeFileExt("ndb"))
@ -763,12 +763,31 @@ proc execCmdsInParallel(conf: ConfigRef; cmds: seq[string]; prettyCb: proc (idx:
rawMessage(conf, errGenerated, "execution of an external program failed: '$1'" % rawMessage(conf, errGenerated, "execution of an external program failed: '$1'" %
cmds.join()) cmds.join())
proc minimizeObjfileNameLen(fullObjName: AbsoluteFile, conf: ConfigRef): string = proc linkViaResponseFile(conf: ConfigRef; cmd: string) =
# For OSes with command line length limitations we try to use relative # Extracting the linker.exe here is a bit hacky but the best solution
# paths over absolute ones: # given ``buildLib``'s design.
result = relativeTo(fullObjName, getNimcacheDir(conf)).string var i = 0
if result.len >= fullObjName.string.len: var last = 0
result = fullObjName.string if cmd.len > 0 and cmd[0] == '"':
inc i
while i < cmd.len and cmd[i] != '"': inc i
last = i
inc i
else:
while i < cmd.len and cmd[i] != ' ': inc i
last = i
while i < cmd.len and cmd[i] == ' ': inc i
let linkerArgs = conf.projectName & "_" & "linkerArgs.txt"
let args = cmd.substr(i)
# GCC's response files don't support backslashes. Junk.
if conf.cCompiler == ccGcc:
writeFile(linkerArgs, args.replace('\\', '/'))
else:
writeFile(linkerArgs, args)
try:
execLinkCmd(conf, cmd.substr(0, last) & " @" & linkerArgs)
finally:
removeFile(linkerArgs)
proc callCCompiler*(conf: ConfigRef; projectfile: AbsoluteFile) = proc callCCompiler*(conf: ConfigRef; projectfile: AbsoluteFile) =
var var
@ -790,24 +809,25 @@ proc callCCompiler*(conf: ConfigRef; projectfile: AbsoluteFile) =
if optNoLinking notin conf.globalOptions: if optNoLinking notin conf.globalOptions:
# call the linker: # call the linker:
var objfiles = "" var objfiles = ""
let oldCwd = getCurrentDir() for it in conf.externalToLink:
try: let objFile = if noAbsolutePaths(conf): it.extractFilename else: it
setCurrentDir(getNimcacheDir(conf).string) add(objfiles, ' ')
for it in conf.externalToLink: add(objfiles, quoteShell(
let objFile = if noAbsolutePaths(conf): it.extractFilename else: it addFileExt(objFile, CC[conf.cCompiler].objExt)))
add(objfiles, ' ') for x in conf.toCompile:
let fullObjName = AbsoluteFile addFileExt(objFile, CC[conf.cCompiler].objExt) let objFile = if noAbsolutePaths(conf): x.obj.extractFilename else: x.obj.string
add(objfiles, quoteShell(minimizeObjfileNameLen(fullObjName, conf))) add(objfiles, ' ')
for x in conf.toCompile: add(objfiles, quoteShell(objFile))
let objFile = if noAbsolutePaths(conf): x.obj.extractFilename.AbsoluteFile else: x.obj
add(objfiles, ' ')
add(objfiles, quoteShell(minimizeObjfileNameLen(objFile, conf)))
linkCmd = getLinkCmd(conf, projectfile, objfiles, AbsoluteDir oldCwd) linkCmd = getLinkCmd(conf, projectfile, objfiles)
if optCompileOnly notin conf.globalOptions: if optCompileOnly notin conf.globalOptions:
if defined(windows) and linkCmd.len > 8_000:
# Windows's command line limit is about 8K (don't laugh...) so C compilers on
# Windows support a feature where the command line can be passed via ``@linkcmd``
# to them.
linkViaResponseFile(conf, linkCmd)
else:
execLinkCmd(conf, linkCmd) execLinkCmd(conf, linkCmd)
finally:
setCurrentDir(oldCwd)
else: else:
linkCmd = "" linkCmd = ""
if optGenScript in conf.globalOptions: if optGenScript in conf.globalOptions:
@ -877,7 +897,7 @@ proc writeJsonBuildInstructions*(conf: ConfigRef; projectfile: AbsoluteFile) =
linkfiles(conf, f, buf, objfiles, conf.toCompile, conf.externalToLink) linkfiles(conf, f, buf, objfiles, conf.toCompile, conf.externalToLink)
lit "],\L\"linkcmd\": " lit "],\L\"linkcmd\": "
str getLinkCmd(conf, projectfile, objfiles, AbsoluteDir getCurrentDir()) str getLinkCmd(conf, projectfile, objfiles)
lit "\L}\L" lit "\L}\L"
close(f) close(f)