Skip to content

Commit edf0c88

Browse files
committed
honor user CMAKE_EXPORT_COMPILE_COMMANDS in cmake option
#feat fix #760
1 parent df29558 commit edf0c88

File tree

2 files changed

+110
-53
lines changed

2 files changed

+110
-53
lines changed

docs/modules/ROOT/pages/usage.adoc

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -134,6 +134,15 @@ If you want to use this feature, you need to have CMake installed on your system
134134
Parameters for cmake, such as `-D BUILDING_TEST=OFF -D MRDOCS_BUILD=ON` can also be specified with the `cmake` option in configuration file.
135135
MrDocs will always append the `CMAKE_EXPORT_COMPILE_COMMANDS=ON` flag to the cmake command.
136136

137+
[NOTE]
138+
====
139+
When the `cmake` option is provided, MrDocs will still adjust the CMake configure arguments to properly generate the compilation database file.
140+
141+
* MrDocs will set the `-S` and `-B` options to the proper directories determined by the `mrdocs.yml` file. If the user explicitly sets `-S` or `-B` in the `cmake` option, these arguments are ignored.
142+
* If the user explicitly sets the generator with `-G`, the user option will typically be honored. However, if the user explicitly sets the generator to `Visual Studio` or the option is not set and `Visual Studio` is still the default generator, MrDocs will override it to `-G Ninja` to ensure a `compile_commands.json` file is generated.
143+
* MrDocs will typically ensure the `CMAKE_EXPORT_COMPILE_COMMANDS` flag is set to `ON`. If the user explicitly sets `-D CMAKE_EXPORT_COMPILE_COMMANDS=OFF`, the user flag will be honored. This can be used to manually determine the logic to generate the `compile_commands.json` file in the `CMakeLists.txt` file.
144+
====
145+
137146
=== MrDocs Builds
138147

139148
In many projects, a common pattern is to define a special build configuration for the documentation generation such that:

src/lib/Lib/CMakeExecution.cpp

Lines changed: 101 additions & 53 deletions
Original file line numberDiff line numberDiff line change
@@ -386,74 +386,123 @@ parseBashArgs(std::string_view str)
386386
/* Pushes the CMake arguments to the `args` vector, replacing the
387387
* default generator with Ninja if Visual Studio is the default generator.
388388
*/
389-
Expected<void>
390-
pushCMakeArgs(
389+
Expected<llvm::SmallVector<llvm::SmallString<128>, 50>>
390+
generateCMakeArgs(
391391
std::string const& cmakePath,
392-
std::vector<llvm::StringRef> &args,
393-
std::vector<std::string> const& additionalArgs) {
394-
bool visualStudioFound = false;
395-
for (size_t i = 0; i < additionalArgs.size(); ++i)
392+
llvm::StringRef cmakeArgs,
393+
llvm::StringRef projectPath,
394+
llvm::StringRef buildDir)
395+
{
396+
auto const userArgs = parseBashArgs(cmakeArgs.str());
397+
llvm::SmallVector<llvm::SmallString<128>, 50> res;
398+
399+
res.emplace_back(cmakePath);
400+
res.emplace_back("-S");
401+
res.emplace_back(projectPath);
402+
res.emplace_back("-B");
403+
res.emplace_back(buildDir);
404+
405+
bool generatorSet = false;
406+
std::string_view generatorName = {};
407+
bool visualStudioSet = false;
408+
bool compileCommandsSet = false;
409+
410+
for (size_t i = 0; i < userArgs.size(); ++i)
396411
{
397-
auto const& arg = additionalArgs[i];
398-
if (arg.starts_with("-G"))
412+
// Compile commands
413+
if (userArgs[i].starts_with("-D"))
399414
{
400-
if (arg.size() == 2)
415+
std::string_view cacheValue;
416+
if (userArgs[i].size() == 2 &&
417+
i + 1 < userArgs.size())
401418
{
402-
if (i + 1 < additionalArgs.size())
403-
{
404-
auto const& generatorName = additionalArgs[i + 1];
405-
if (generatorName.starts_with("Visual Studio"))
406-
{
407-
args.emplace_back("-GNinja");
408-
visualStudioFound = true;
409-
++i;
410-
continue;
411-
}
412-
}
413-
} else {
414-
if (arg.find("Visual Studio", 2) != std::string::npos)
415-
{
416-
args.emplace_back("-GNinja");
417-
visualStudioFound = true;
418-
continue;
419-
}
419+
res.emplace_back(userArgs[i]);
420+
res.emplace_back(userArgs[i+1]);
421+
cacheValue = userArgs[i+1];
422+
++i;
420423
}
424+
else if (userArgs[i].size() > 2)
425+
{
426+
res.emplace_back(userArgs[i]);
427+
cacheValue = userArgs[i];
428+
cacheValue.remove_prefix(2);
429+
}
430+
if (cacheValue.starts_with("CMAKE_EXPORT_COMPILE_COMMANDS="))
431+
{
432+
compileCommandsSet = true;
433+
}
434+
continue;
421435
}
422436

423-
if (arg.starts_with("-D"))
437+
// Build dir or source dir
438+
if (userArgs[i] == "-B" ||
439+
userArgs[i] == "-S")
424440
{
425-
if (arg.size() == 2)
441+
// The build and source dirs will be set by MrDocs
442+
// Don't push the argument
443+
if (i + 1 < userArgs.size())
426444
{
427-
if (i + 1 < additionalArgs.size())
428-
{
429-
auto const& optionName = additionalArgs[i + 1];
430-
if (optionName.starts_with("CMAKE_EXPORT_COMPILE_COMMANDS"))
431-
{
432-
++i;
433-
continue;
434-
}
435-
}
436-
} else {
437-
if (arg.find("CMAKE_EXPORT_COMPILE_COMMANDS", 2) != std::string::npos)
438-
{
439-
continue;
440-
}
445+
++i;
441446
}
447+
continue;
442448
}
443-
args.emplace_back(arg);
449+
450+
// Generator
451+
if (userArgs[i].starts_with("-G"))
452+
{
453+
if (userArgs[i].size() == 2 &&
454+
i + 1 < userArgs.size())
455+
{
456+
generatorSet = true;
457+
generatorName = userArgs[i+1];
458+
++i;
459+
}
460+
else if (userArgs.size() > 2)
461+
{
462+
generatorSet = true;
463+
generatorName = userArgs[i+1];
464+
generatorName.remove_prefix(2);
465+
}
466+
if (generatorSet)
467+
{
468+
visualStudioSet = generatorName.starts_with("Visual Studio");
469+
}
470+
if (generatorSet && !visualStudioSet)
471+
{
472+
res.emplace_back("-G");
473+
res.emplace_back(generatorName);
474+
}
475+
continue;
476+
}
477+
478+
// Other args
479+
res.emplace_back(userArgs[i]);
480+
}
481+
482+
if (!compileCommandsSet)
483+
{
484+
res.emplace_back("-D");
485+
res.emplace_back("CMAKE_EXPORT_COMPILE_COMMANDS=ON");
444486
}
445487

446-
if (!visualStudioFound)
488+
if (visualStudioSet)
489+
{
490+
res.emplace_back("-G");
491+
res.emplace_back("Ninja");
492+
}
493+
else if (!generatorSet)
447494
{
448495
MRDOCS_TRY(
449496
bool const cmakeDefaultGeneratorIsVisualStudio,
450497
cmakeDefaultGeneratorIsVisualStudio(cmakePath));
451498
if (cmakeDefaultGeneratorIsVisualStudio)
452499
{
453-
args.emplace_back("-GNinja");
500+
res.emplace_back("-G");
501+
res.emplace_back("Ninja");
454502
}
455503
}
456-
return {};
504+
505+
return res;
457506
}
458507

459508
} // anonymous namespace
@@ -464,13 +513,12 @@ executeCmakeExportCompileCommands(llvm::StringRef projectPath, llvm::StringRef c
464513
MRDOCS_CHECK(llvm::sys::fs::exists(projectPath), "Project path does not exist");
465514
MRDOCS_TRY(auto const cmakePath, getCmakePath());
466515

467-
std::array<std::optional<llvm::StringRef>, 3> const redirects = {std::nullopt, std::nullopt, std::nullopt};
468-
std::vector<llvm::StringRef> args = {cmakePath, "-S", projectPath, "-B", buildDir, "-DCMAKE_EXPORT_COMPILE_COMMANDS=ON"};
516+
constexpr std::array<std::optional<llvm::StringRef>, 3>
517+
redirects = {std::nullopt, std::nullopt, std::nullopt};
518+
MRDOCS_TRY(auto args, generateCMakeArgs(cmakePath, cmakeArgs, projectPath, buildDir));
519+
std::vector<llvm::StringRef> argsRef(args.begin(), args.end());
469520

470-
auto const additionalArgs = parseBashArgs(cmakeArgs.str());
471-
MRDOCS_TRY(pushCMakeArgs(cmakePath, args, additionalArgs));
472-
473-
int const result = llvm::sys::ExecuteAndWait(cmakePath, args, std::nullopt, redirects);
521+
int const result = llvm::sys::ExecuteAndWait(cmakePath, argsRef, std::nullopt, redirects);
474522
if (result != 0) {
475523
return Unexpected(Error("CMake execution failed"));
476524
}

0 commit comments

Comments
 (0)