Created
March 23, 2025 00:00
-
-
Save miguelmartin75/298a8b39664a89a69abd8b23a5a805a8 to your computer and use it in GitHub Desktop.
compile commands json generation for nim in nimscript
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import std/[ | |
os, | |
json, | |
tables, | |
options, | |
strformat, | |
strutils, | |
sugar, | |
sequtils, | |
] | |
const compileCommandIndent = 2 | |
proc nimCompileJsonToCompileCommands(compileJson: JsonNode, buildDir: string): JsonNode = | |
# see https://clang.llvm.org/docs/JSONCompilationDatabase.html | |
result = %*[] | |
# assert absDir.isAbsolute | |
for x in compileJson["compile"]: | |
assert x.len == 2 | |
result.add %*{ | |
"file": x[0].getStr, | |
"command": x[1].getStr, | |
"directory": buildDir, | |
} | |
proc srcAbsDir(path: string): string = | |
if path.startsWith("/"): | |
path | |
else: | |
&"{getCurrentDir()}/{path}" | |
proc mergeCompileCommands(ccs: seq[JsonNode]): JsonNode = | |
var cmdByFilename: Table[string, JsonNode] | |
for xs in ccs: | |
assert xs.kind == JArray | |
for x in xs: | |
let fn = x["file"].getStr.srcAbsDir | |
if fn notin cmdByFilename: | |
cmdByFilename[fn] = x | |
elif "IMPL" in x["command"].getStr: | |
cmdByFilename[fn] = x | |
result = %*[] | |
for x in cmdByFilename.values: | |
result.add x | |
proc createMergedCompileCommands*( | |
paths: seq[string], | |
outPath: string, | |
debugInfo: bool = false, | |
) = | |
let | |
ccs = collect: | |
for x in paths: | |
if x.fileExists: | |
x.readFile.parseJson | |
cc = mergeCompileCommands(ccs) | |
outputJson = cc.pretty(indent=compileCommandIndent) | |
writeFile(outPath, outputJson) | |
proc createCompileCommands( | |
inPath: string, | |
buildDir: string, | |
outPath: string, | |
existingCompileCommands: seq[string], | |
) = | |
let compileJson = inPath.readFile.parseJson | |
var | |
compileCommands = nimCompileJsonToCompileCommands(compileJson, buildDir) | |
existingCompileCommands = existingCompileCommands.map(x => x.readFile.parseJson) | |
if outPath.fileExists: | |
echo "combining outPath: ", outPath | |
let oldCmds = outPath.readFile.parseJson | |
existingCompileCommands.add(oldCmds) | |
existingCompileCommands.add(compileCommands) | |
compileCommands = mergeCompileCommands(existingCompileCommands) | |
writeFile(outPath, compileCommands.pretty(indent=compileCommandIndent)) | |
proc createCompileCommands*( | |
projectName: string, | |
nimcachedir: string, | |
outPath: Option[string] = string.none, | |
existingCompileCommands: seq[string] = @[], | |
debugInfo: bool = true, | |
) = | |
let | |
compileJsonPath = &"{nimcachedir}/{projectName}.json" | |
outPath = if outPath.isSome: | |
outPath.get | |
else: | |
&"{nimcachedir}/compile_commands.json" | |
if debugInfo: | |
echo &"Converting {compileJsonPath} -> {outPath}" | |
createCompileCommands( | |
inPath = compileJsonPath, | |
buildDir = nimcachedir, | |
outPath = outPath, | |
existingCompileCommands = existingCompileCommands, | |
) | |
if debugInfo: | |
echo "Done" |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
const | |
pwd = getCurrentDir() | |
outdir = &"{pwd}/build" | |
nimcachedir = &"{pwd}/build/cache" | |
buildDir = outdir | |
import src/[buildsupport] | |
proc build*( | |
module: string, | |
srcDir: string = "src", | |
backend: string = "c", | |
run: bool = false, | |
compileOpts: string = "", | |
runOpts: string = "", | |
compileCommandPath: Option[string] = string.none, | |
withCompileCommands: bool = true, | |
debugInfo: bool = hasDebugInfo, | |
) = | |
let | |
runStr = if run: | |
"-r" | |
else: | |
"" | |
allCmdParams: seq[string] = commandLineParams()[1..^1].join(" ").split(" -- ") | |
cmdParams = allCmdParams[0] & " " & compileOpts | |
runParams = if allCmdParams.len >= 2: | |
assert allCmdParams.len == 2, "-- cannot be supplied twice!" | |
allCmdParams[1] & runOpts | |
else: | |
runOpts | |
cmd = &"{backend} {runStr} {cmdParams} {srcDir}/{module}.nim {runParams}" | |
projectName = block: | |
var projectName = module | |
for cmd in cmdParams.split(" "): | |
let cmd = cmd.strip | |
if cmd.startsWith("--out:") or cmd.startsWith("-o:"): | |
projectName = cmd.split(":")[1].splitFile.name | |
# assert projectName.fileExists, &"{projectName} does not exist" | |
projectName | |
compileCommandJsonPath = &"{nimcachedir}/{projectName}_compile_commands.json" | |
if debugInfo: | |
echo &"executing: nim {cmd}" | |
echo "projectName= ", projectName | |
selfExec cmd | |
if withCompileCommands: | |
echo "-- createCompileCommands" | |
createCompileCommands( | |
projectName=projectName, | |
nimcachedir=nimcachedir, | |
outPath=compileCommandJsonPath.some, | |
debugInfo=debugInfo, | |
) | |
# create a merged compile_commands.json | |
createMergedCompileCommands( | |
@[ | |
&"{buildDir}/compile_commands.json", | |
&"{buildDir}/combined_compile_commands.json", | |
compileCommandJsonPath, | |
], | |
&"{buildDir}/combined_compile_commands.json", | |
debugInfo=true, | |
) | |
task app, "Build app": | |
build( | |
"app", | |
srcDir="src", | |
backend="c", | |
withCompileCommands=true, | |
) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment