IC: run nifmake automatically (#25415)

This commit is contained in:
Andreas Rumpf
2026-01-07 13:45:26 +01:00
committed by GitHub
parent 89c8f0aa49
commit 251b4a23c3
6 changed files with 81 additions and 28 deletions

View File

@@ -499,7 +499,7 @@ proc parseCommand*(command: string): Command =
of "nop", "help": cmdNop
of "jsonscript": cmdJsonscript
of "nifc": cmdNifC # generate C from NIF files
of "deps": cmdDeps # generate .build.nif for nifmake
of "ic": cmdIc # generate .build.nif for nifmake
else: cmdUnknown
proc setCmd*(conf: ConfigRef, cmd: Command) =

View File

@@ -11,7 +11,7 @@
## This enables incremental and parallel compilation using the `m` switch.
import std / [os, tables, sets, times, osproc, strutils]
import options, msgs, lineinfos
import options, msgs, lineinfos, pathutils
import "../dist/nimony/src/lib" / [nifstreams, nifcursors, bitabs, nifreader, nifbuilder]
import "../dist/nimony/src/gear2" / modnames
@@ -47,15 +47,18 @@ proc semmedFile(c: DepContext; f: FilePair): string =
proc findNifler(): string =
# Look for nifler in common locations
result = findExe("nifler")
if result.len == 0:
# Try relative to nim executable
let nimDir = getAppDir()
result = nimDir / "nifler"
if not fileExists(result):
result = nimDir / ".." / "nimony" / "bin" / "nifler"
if not fileExists(result):
result = ""
let nimDir = getAppDir()
result = nimDir / "nifler"
if not fileExists(result):
result = findExe("nifler")
proc findNifmake(): string =
# Look for nifmake in common locations
# Try relative to nim executable
let nimDir = getAppDir()
result = nimDir / "nifmake"
if not fileExists(result):
result = findExe("nifmake")
proc runNifler(c: DepContext; nimFile: string): bool =
## Run nifler deps on a file if needed. Returns true on success.
@@ -220,12 +223,14 @@ proc traverseDeps(c: var DepContext; pair: FilePair; current: Node) =
proc generateBuildFile(c: DepContext): string =
## Generate the .build.nif file for nifmake
result = getNimcacheDir(c.config).string / c.nodes[0].files[0].modname & ".build.nif"
createDir("nifcache")
result = "nifcache" / c.nodes[0].files[0].modname & ".build.nif"
#getNimcacheDir(c.config).string / c.nodes[0].files[0].modname & ".build.nif"
var b = nifbuilder.open(result)
defer: b.close()
b.addHeader("nim deps", "nifmake")
b.addHeader("nim ic", "nifmake")
b.addTree "stmts"
# Define nifler command
@@ -245,6 +250,22 @@ proc generateBuildFile(c: DepContext): string =
b.addSymbolDef "nim_m"
b.addStrLit getAppFilename()
b.addStrLit "m"
b.addStrLit "--nimcache:nifcache"
# Add search paths
for p in c.config.searchPaths:
b.addStrLit "--path:" & p.string
b.addTree "args"
b.endTree()
b.withTree "input":
b.addIntLit 0 # main parsed file
b.endTree()
# Define nim nifc command
b.addTree "cmd"
b.addSymbolDef "nim_nifc"
b.addStrLit getAppFilename()
b.addStrLit "nifc"
b.addStrLit "--nimcache:nifcache"
# Add search paths
for p in c.config.searchPaths:
b.addStrLit "--path:" & p.string
@@ -279,6 +300,8 @@ proc generateBuildFile(c: DepContext): string =
b.addTree "do"
b.addIdent "nim_m"
# Input: all parsed files for this module
b.withTree "input":
b.addStrLit node.files[0].nimFile
for f in node.files:
b.addTree "input"
b.addStrLit c.parsedFile(f)
@@ -292,15 +315,26 @@ proc generateBuildFile(c: DepContext): string =
b.addTree "output"
b.addStrLit c.semmedFile(pair)
b.endTree()
b.addTree "args"
b.addStrLit pair.nimFile
b.endTree()
b.endTree()
# Final compilation step: generate executable from main module
let mainNif = c.nodes[0].files[0].nimFile
let exeFile = changeFileExt(c.nodes[0].files[0].nimFile, ExeExt)
b.addTree "do"
b.addIdent "nim_nifc"
# Input: .nim file (expanded as argument) and .nif file (dependency)
b.addTree "input"
b.addStrLit mainNif
b.endTree()
b.addTree "output"
b.addStrLit exeFile
b.endTree()
b.endTree()
b.endTree() # stmts
proc commandDeps*(conf: ConfigRef) =
## Main entry point for `nim deps`
proc commandIc*(conf: ConfigRef) =
## Main entry point for `nim ic`
when not defined(nimKochBootstrap):
let nifler = findNifler()
if nifler.len == 0:
@@ -329,12 +363,27 @@ proc commandDeps*(conf: ConfigRef) =
c.nodes.add rootNode
c.processedModules[rootPair.modname] = 0
# model the system.nim dependency:
let sysNode = Node(files: @[toPair(c, (conf.libpath / RelativeFile"system.nim").string)], id: 1)
c.nodes.add sysNode
rootNode.deps.add sysNode.id
# Process dependencies
traverseDeps(c, rootPair, rootNode)
# Generate build file
let buildFile = generateBuildFile(c)
rawMessage(conf, hintSuccess, "generated: " & buildFile)
rawMessage(conf, hintSuccess, "run: nifmake run " & buildFile)
# Automatically run nifmake
let nifmake = findNifmake()
if nifmake.len == 0:
rawMessage(conf, hintSuccess, "run: nifmake run " & buildFile)
else:
let cmd = quoteShell(nifmake) & " run " & quoteShell(buildFile)
rawMessage(conf, hintExecuting, cmd)
let exitCode = execShellCmd(cmd)
if exitCode != 0:
rawMessage(conf, errGenerated, "nifmake failed with exit code: " & $exitCode)
else:
rawMessage(conf, errGenerated, "nim deps not available in bootstrap build")
rawMessage(conf, errGenerated, "nim ic not available in bootstrap build")

View File

@@ -442,18 +442,20 @@ proc mainCommand*(graph: ModuleGraph) =
of cmdM:
# cmdM uses NIF files, not ROD files
graph.config.symbolFiles = disabledSf
setUseIc(false)
setUseIc(true)
commandCheck(graph)
of cmdNifC:
setUseIc(true)
# Generate C code from NIF files
wantMainModule(conf)
setOutFile(conf)
commandNifC(graph)
of cmdDeps:
of cmdIc:
# Generate .build.nif for nifmake
setUseIc(true)
wantMainModule(conf)
when not defined(nimKochBootstrap):
commandDeps(conf)
commandIc(conf)
else:
rawMessage(conf, errGenerated, "nim deps not available in bootstrap build")
of cmdParse:

View File

@@ -118,7 +118,7 @@ proc handleCmdLine(cache: IdentCache; conf: ConfigRef) =
if conf.selectedGC == gcUnselected:
if conf.backend in {backendC, backendCpp, backendObjc} or
(conf.cmd in cmdDocLike and conf.backend != backendJs) or
conf.cmd in {cmdGendepend, cmdNifC, cmdDeps, cmdM}:
conf.cmd in {cmdGendepend, cmdNifC, cmdIc, cmdM}:
initOrcDefines(conf)
mainCommand(graph)

View File

@@ -177,7 +177,7 @@ type
# old unused: cmdInterpret, cmdDef: def feature (find definition for IDEs)
cmdCompileToNif
cmdNifC # generate C code from NIF files
cmdDeps # generate .build.nif for nifmake
cmdIc # generate .build.nif for nifmake
const
cmdBackends* = {cmdCompileToC, cmdCompileToCpp, cmdCompileToOC,

View File

@@ -16,7 +16,7 @@ const
ChecksumsStableCommit = "0b8e46379c5bc1bf73d8b3011908389c60fb9b98" # 2.0.1
SatStableCommit = "faf1617f44d7632ee9601ebc13887644925dcc01"
NimonyStableCommit = "e2cd6eadcaa68eb8ab380cb4d3bdd7fd260677b4" # unversioned \
NimonyStableCommit = "fc8baa61b9911caf4666685a5f5ed41b9c04f6f8" # unversioned \
# Note that Nimony uses Nim as a git submodule but we don't want to install
# Nimony's dependency to Nim as we are Nim. So a `git clone` without --recursive
# is **required** here.
@@ -188,8 +188,10 @@ proc bundleChecksums(latest: bool) =
let nimonyCommit = if latest: "HEAD" else: NimonyStableCommit
cloneDependency(distDir, "https://github.com/nim-lang/nimony.git", nimonyCommit, allowBundled = true)
nimCompileFold("Compile nifler", "dist/nimony/src/nifler/nifler.nim", options = "-d:release")
nimCompileFold("Compile nifmake", "dist/nimony/src/nifmake/nifmake.nim", options = "-d:release")
if not fileExists("bin/nifler".exe):
nimCompileFold("Compile nifler", "dist/nimony/src/nifler/nifler.nim", options = "-d:release")
if not fileExists("bin/nifmake".exe):
nimCompileFold("Compile nifmake", "dist/nimony/src/nifmake/nifmake.nim", options = "-d:release")
proc bundleNimsuggest(args: string) =
bundleChecksums(false)