From ce4d75cbc2527cc22c56ee85cd084e19c0d280a3 Mon Sep 17 00:00:00 2001 From: araq Date: Tue, 2 Dec 2025 09:25:17 +0100 Subject: [PATCH] bring back the 'm' switch for development --- compiler/ast2nif.nim | 19 +++++++++++++------ compiler/commands.nim | 3 +++ compiler/pipelines.nim | 28 ++++++++++++++++++++-------- 3 files changed, 36 insertions(+), 14 deletions(-) diff --git a/compiler/ast2nif.nim b/compiler/ast2nif.nim index cac2743a1e..34eabd81cf 100644 --- a/compiler/ast2nif.nim +++ b/compiler/ast2nif.nim @@ -11,6 +11,7 @@ import std / [assertions, tables, sets] from std / strutils import startsWith +from std / os import fileExists import astdef, idents, msgs, options import lineinfos as astli import pathutils #, modulegraphs @@ -495,12 +496,14 @@ proc writeNifModule*(config: ConfigRef; thisModule: int32; n: PNode) = writeFile(dest, d) createIndex(d, false, dest[0].info) - # Unload all written types and symbols from memory after the entire module is written - # This handles cyclic references correctly since everything is written before unloading - for typ in w.writtenTypes: - forcePartial(typ) - for sym in w.writtenSyms: - forcePartial(sym) + # Don't unload symbols/types yet - they may be needed by other modules that haven't + # had their NIF files written. For recursive module dependencies (like system.nim), + # we need all NIFs to exist before we can safely unload and reload. + # TODO: Implement deferred unloading at end of compilation for memory savings. + #for typ in w.writtenTypes: + # forcePartial(typ) + #for sym in w.writtenSyms: + # forcePartial(sym) # --------------------------- Loader (lazy!) ----------------------------------------------- @@ -589,6 +592,10 @@ proc moduleId(c: var DecodeContext; suffix: string): FileIndex = if not isKnownFile: let modFile = (getNimcacheDir(c.infos.config) / RelativeFile(suffix & ".nif")).string let idxFile = (getNimcacheDir(c.infos.config) / RelativeFile(suffix & ".s.idx.nif")).string + if not fileExists(modFile): + raiseAssert "NIF file not found for module suffix '" & suffix & "': " & modFile & + ". This can happen when loading a module from NIF that references another module " & + "whose NIF file hasn't been written yet." if result.int >= c.mods.len: c.mods.setLen(result.int + 1) c.mods[result.int] = NifModule(stream: nifstreams.open(modFile), index: readIndex(idxFile)) diff --git a/compiler/commands.nim b/compiler/commands.nim index 415fe6b352..8c3de1c174 100644 --- a/compiler/commands.nim +++ b/compiler/commands.nim @@ -510,6 +510,9 @@ proc setCmd*(conf: ConfigRef, cmd: Command) = of cmdCompileToOC: conf.backend = backendObjc of cmdCompileToJS: conf.backend = backendJs of cmdCompileToNif: conf.backend = backendNif + of cmdM: + # cmdM requires optCompress for proper IC handling (include files, etc.) + conf.globalOptions.incl optCompress else: discard proc setCommandEarly*(conf: ConfigRef, command: string) = diff --git a/compiler/pipelines.nim b/compiler/pipelines.nim index f00d0a3196..ac17160aa3 100644 --- a/compiler/pipelines.nim +++ b/compiler/pipelines.nim @@ -160,7 +160,7 @@ proc processPipelineModule*(graph: ModuleGraph; module: PSym; idgen: IdGenerator s = stream graph.interactive = stream.kind == llsStdIn var topLevelStmts = - if optCompress in graph.config.globalOptions: + if optCompress in graph.config.globalOptions or graph.config.cmd == cmdM: newNodeI(nkStmtList, module.info) else: nil @@ -235,14 +235,16 @@ proc processPipelineModule*(graph: ModuleGraph; module: PSym; idgen: IdGenerator raiseAssert "use setPipeLinePass to set a proper PipelinePass" when not defined(nimKochBootstrap): - if optCompress in graph.config.globalOptions and not graph.config.isDefined("nimscript"): + if (optCompress in graph.config.globalOptions or graph.config.cmd == cmdM) and + not graph.config.isDefined("nimscript"): topLevelStmts.add finalNode writeNifModule(graph.config, module.position.int32, topLevelStmts) - if graph.config.backend notin {backendC, backendCpp, backendObjc}: + if graph.config.backend notin {backendC, backendCpp, backendObjc} and graph.config.cmd != cmdM: # We only write rod files here if no C-like backend is active. # The C-like backends have been patched to support the IC mechanism. # They are responsible for closing the rod files. See `cbackend.nim`. + # cmdM uses NIF files only, not ROD files. closeRodFile(graph, module) result = true @@ -261,11 +263,20 @@ proc compilePipelineModule*(graph: ModuleGraph; fileIdx: FileIndex; flags: TSymF if result == nil: var cachedModules: seq[FileIndex] = @[] when not defined(nimKochBootstrap): - # Try loading from NIF file first if optCompress is enabled - if optCompress in graph.config.globalOptions and not graph.config.isDefined("nimscript"): + # For cmdM: load imports from NIF files (but compile the main module from source) + # Skip when withinSystem is true (compiling system.nim itself) + if graph.config.cmd == cmdM and + sfMainModule notin flags and + not graph.withinSystem and + not graph.config.isDefined("nimscript"): result = moduleFromNifFile(graph, fileIdx, cachedModules) - if result == nil: - # Fall back to ROD file loading + if result == nil: + let nifPath = toNifFilename(graph.config, fileIdx) + localError(graph.config, unknownLineInfo, + "nim m requires precompiled NIF for import: " & toFullPath(graph.config, fileIdx) & + " (expected: " & nifPath & ")") + if result == nil and graph.config.cmd != cmdM: + # Fall back to ROD file loading (not used for cmdM which uses NIF only) result = moduleFromRodFile(graph, fileIdx, cachedModules) let path = toFullPath(graph.config, fileIdx) let filename = AbsoluteFile path @@ -287,7 +298,8 @@ proc compilePipelineModule*(graph: ModuleGraph; fileIdx: FileIndex; flags: TSymF partialInitModule(result, graph, fileIdx, filename) for m in cachedModules: registerModuleById(graph, m) - if sfMainModule in flags and graph.config.cmd == cmdM: + if graph.config.cmd == cmdM: + # cmdM uses NIF files, not ROD files - skip ROD-specific replay discard else: replayStateChanges(graph.packed.pm[m.int].module, graph)