In order to generate compile_commands.json for clangd Language Server, one can use -mode=GenerateClangDatabase flag in Unreal Build Tool (more details described here )
However, a problem with this mode is that it isn’t “incremental” which means it regenerates whole file every time, not only the part that requires it, resulting in very long execution times (around 45sec on my machine).
This makes it pretty hard to use since database needs to be regenerated when any #include directive has changed or when any source file has been added/removed/renamed. This should pretty much run every time when build process is invoked, just to make sure database is up to date.
Is there some hidden option/flag that makes it incremental?
Is there a reason why it’s NOT incremental?
Was it incremental in the past?
My engine version is 5.4.2, built from git on Linux
/// <summary>
/// Execute any actions which result in code generation (eg. ISPC compilation)
/// </summary>
[CommandLine("-ExecCodeGenActions")]
[CommandLine("-NoExecCodeGenActions", Value = "false")]
public bool bExecCodeGenActions = true;
which controls generation of *.generated.h files.
So adding -NoExecCodeGenActions fixes this issue for my use case.
Execution time is decreased from 45sec to roughly 3sec.
(but have in mind that whole Project and Engine must be compiled already)
I’m not sure if this is optimal though since 3 sec is still pretty long for something that should be run for each compilation attempt. For comparison, changing one .cpp file in my Project requires around 2-5sec for its recompilation. So additional 3sec would make noticeable difference.
I haven’t tested it for a while, but it seems they improved a lot of stuff in GenerateClangDatabase. Perhaps there was a bug that was always forcing full recompilation and -NoExecCodeGenActions was a simple workaround.
Looking through the code, it was always meant to be incremental, so I’m not sure why it wasn’t working for me back in 5.4.2:
if (bExecCodeGenActions)
{
// Filter all the actions to execute
HashSet<FileItem> PrerequisiteItems = new HashSet<FileItem>(Makefile.Actions.SelectMany(x => x.ProducedItems).Where(x => x.HasExtension(".h") || x.HasExtension(".cpp") || x.HasExtension(".cc") || x.HasExtension(".c")));
List<LinkedAction> PrerequisiteActions = ActionGraph.GatherPrerequisiteActions(Actions, PrerequisiteItems);
Utils.ExecuteCustomBuildSteps(Makefile.PreBuildScripts, Logger);
// Execute code generation actions
if (PrerequisiteActions.Any())
{
Logger.LogInformation("Executing actions that produce source files...");
await ActionGraph.ExecuteActionsAsync(BuildConfiguration, PrerequisiteActions, new List<TargetDescriptor> { TargetDescriptor }, Logger);
}
}
/// <summary>
/// Optional set of source files to include in the compile database. If this is empty, all files will be included by default and -Exclude can be used to exclude some.
/// Relative to the root directory, or to the project file.
/// </summary>
[CommandLine("-Include=")]
List<string> IncludeRules = new List<string>();
/// <summary>
/// Optional set of source files to exclude from the compile database.
/// Relative to the root directory, or to the project file.
/// </summary>
[CommandLine("-Exclude=")]
List<string> ExcludeRules = new List<string>();
/// <summary>
/// Execute any actions which result in code generation (eg. ISPC compilation)
/// </summary>
[CommandLine("-ExecCodeGenActions")]
[CommandLine("-NoExecCodeGenActions", Value = "false")]
public bool bExecCodeGenActions = true;
/// <summary>
/// Optionally override the output filename for handling multiple targets
/// </summary>
[CommandLine("-OutputFilename=")]
public string OutputFilename = "compile_commands.json";
/// <summary>
/// Optionally overrite the output directory for the compile_commands file.
/// </summary>
[CommandLine("-OutputDir=")]
public string OutputDir = Unreal.RootDirectory.ToString();