diff --git a/compiler/commands.nim b/compiler/commands.nim index 879a995882b6..bdac041e2fce 100644 --- a/compiler/commands.nim +++ b/compiler/commands.nim @@ -1154,6 +1154,18 @@ proc processSwitch*(switch, arg: string, pass: TCmdLinePass, info: TLineInfo; handleStdinInput(conf) of "nilseqs", "nilchecks", "symbol", "taintmode", "cs", "deadcodeelim": warningOptionNoop(switch) of "nimmainprefix": conf.nimMainPrefix = arg + of "compilecmdsjson": + # TODO + # processOnOffSwitch(conf, {optCursorInference}, arg, pass, info) + conf.compileCommandsJson = true + of "projectcompilecmdjson": + # TODO + # processOnOffSwitch(conf, {optCursorInference}, arg, pass, info) + conf.projectCompileCommandJsons = true + of "rootcompilecmdsjson": + # TODO + # processOnOffSwitch(conf, {optCursorInference}, arg, pass, info) + conf.copyCompileCommandsJsonToCurDir = true else: if strutils.find(switch, '.') >= 0: options.setConfigVar(conf, switch, arg) else: invalidCmdLineOption(conf, pass, switch, info) diff --git a/compiler/extccomp.nim b/compiler/extccomp.nim index 4bae400dc013..78ad245857ef 100644 --- a/compiler/extccomp.nim +++ b/compiler/extccomp.nim @@ -1003,6 +1003,18 @@ proc callCCompiler*(conf: ConfigRef) = template hashNimExe(): string = $secureHashFile(os.getAppFilename()) +iterator compileCommandsJsonFiles*(conf: ConfigRef): AbsoluteFile = + var rf = if conf.projectCompileCommandJsons: + ("compile_commands_" & conf.outFile.changeFileExt("json").string).RelativeFile + else: + "compile_commands".RelativeFile + + yield getNimcacheDir(conf) / rf + + if conf.copyCompileCommandsJsonToCurDir: + yield conf.projectPath / rf + + proc jsonBuildInstructionsFile*(conf: ConfigRef): AbsoluteFile = # `outFile` is better than `projectName`, as it allows having different json # files for a given source file compiled with different options; it also @@ -1027,6 +1039,16 @@ type BuildCache = object depfiles: seq[(string, string)] nimexe: string +proc jsonCompileCommands*(conf: ConfigRef): JsonNode = + # ref: https://clang.llvm.org/docs/JSONCompilationDatabase.html + result = %*[] + for it in conf.toCompile: + result.add %*{ + "file": it.cname.string, + "command": getCompileCFileCmd(conf, it), + "directory": conf.outDir.string, + } + proc writeJsonBuildInstructions*(conf: ConfigRef; deps: StringTableRef) = var linkFiles = collect(for it in conf.externalToLink: var it = it @@ -1060,8 +1082,15 @@ proc writeJsonBuildInstructions*(conf: ConfigRef; deps: StringTableRef) = if fileExists(bcache.outputFile): bcache.outputLastModificationTime = $getLastModificationTime(bcache.outputFile) conf.jsonBuildFile = conf.jsonBuildInstructionsFile + conf.jsonBuildFile.string.writeFile(bcache.toJson.pretty) + if conf.compileCommandsJson: + # NOTE: compile_commands.json uses indent of 2 by convention + let compileCmds = conf.jsonCompileCommands.pretty(2) + for p in conf.compileCommandsJsonFiles: + p.writeFile(compileCmds) + proc changeDetectedViaJsonBuildInstructions*(conf: ConfigRef; jsonFile: AbsoluteFile): bool = result = false if not fileExists(jsonFile) or not fileExists(conf.absOutFile): return true diff --git a/compiler/options.nim b/compiler/options.nim index ea75a6848756..4abd5aa10084 100644 --- a/compiler/options.nim +++ b/compiler/options.nim @@ -448,6 +448,10 @@ type currentConfigDir*: string # used for passPP only; absolute dir clientProcessId*: int + compileCommandsJson*: bool + projectCompileCommandJsons*: bool + copyCompileCommandsJsonToCurDir*: bool + proc assignIfDefault*[T](result: var T, val: T, def = default(T)) = diff --git a/tests/compile_commands_json/foo.cpp b/tests/compile_commands_json/foo.cpp new file mode 100644 index 000000000000..a65c8a70ea58 --- /dev/null +++ b/tests/compile_commands_json/foo.cpp @@ -0,0 +1,7 @@ +#include + +#ifdef ENABLE_FOO +extern "C" void foo() { + std::cout << "hello world\n"; +} +#endif diff --git a/tests/compile_commands_json/foo.nim b/tests/compile_commands_json/foo.nim new file mode 100644 index 000000000000..fd71a8b57db7 --- /dev/null +++ b/tests/compile_commands_json/foo.nim @@ -0,0 +1,6 @@ +{.compile("foo.cpp", "-DENABLE_FOO").} + +proc foo() {.importc.} + +when isMainModule: + foo() diff --git a/tests/compile_commands_json/foo.nims b/tests/compile_commands_json/foo.nims new file mode 100644 index 000000000000..550313a81f17 --- /dev/null +++ b/tests/compile_commands_json/foo.nims @@ -0,0 +1,2 @@ +--nimcache:"./nimcache" +--compileCmdsJson:on