Commit 7687d557 authored by David Cole's avatar David Cole Committed by Kitware Robot

Merge topic 'Ninja-EXPORT_COMPILE_COMMANDS'

3545645c Exclude the CompileCommandOutput test on WIN32.
fbaddf4e Escape the source file to be compiled if required.
db839bec Make the CMAKE_EXPORT_COMPILE_COMMANDS option work with Ninja.
87783578 Add newline to the output.
2c04bc00 Move the EscapeJSON method to a sharable location.
parents 80abbeb3 3545645c
......@@ -60,6 +60,12 @@ IF(CMAKE_GENERATOR MATCHES "Makefiles")
ENDIF(CMAKE_GENERATOR MATCHES "Unix Makefiles")
ENDIF(CMAKE_GENERATOR MATCHES "Makefiles")
IF(CMAKE_GENERATOR MATCHES "Ninja")
SET(CMAKE_EXPORT_COMPILE_COMMANDS OFF CACHE BOOL
"Enable/Disable output of compile commands during generation."
)
MARK_AS_ADVANCED(CMAKE_EXPORT_COMPILE_COMMANDS)
ENDIF(CMAKE_GENERATOR MATCHES "Ninja")
# GetDefaultWindowsPrefixBase
#
......
......@@ -2474,3 +2474,16 @@ void cmGlobalGenerator::WriteSummary(cmTarget* target)
cmSystemTools::RemoveFile(file.c_str());
}
}
//----------------------------------------------------------------------------
// static
std::string cmGlobalGenerator::EscapeJSON(const std::string& s) {
std::string result;
for (std::string::size_type i = 0; i < s.size(); ++i) {
if (s[i] == '"' || s[i] == '\\') {
result += '\\';
}
result += s[i];
}
return result;
}
......@@ -280,6 +280,8 @@ public:
/** Generate an <output>.rule file path for a given command output. */
virtual std::string GenerateRuleFile(std::string const& output) const;
static std::string EscapeJSON(const std::string& s);
protected:
typedef std::vector<cmLocalGenerator*> GeneratorVector;
// for a project collect all its targets by following depend
......
......@@ -341,6 +341,7 @@ cmGlobalNinjaGenerator::cmGlobalNinjaGenerator()
: cmGlobalGenerator()
, BuildFileStream(0)
, RulesFileStream(0)
, CompileCommandsStream(0)
, Rules()
, AllDependencies()
{
......@@ -390,6 +391,7 @@ void cmGlobalNinjaGenerator::Generate()
this->BuildFileStream->setstate(std::ios_base::failbit);
}
this->CloseCompileCommandsStream();
this->CloseRulesFileStream();
this->CloseBuildFileStream();
}
......@@ -623,6 +625,46 @@ void cmGlobalNinjaGenerator::CloseRulesFileStream()
}
}
void cmGlobalNinjaGenerator::AddCXXCompileCommand(
const std::string &commandLine,
const std::string &sourceFile)
{
// Compute Ninja's build file path.
std::string buildFileDir =
this->GetCMakeInstance()->GetHomeOutputDirectory();
if (!this->CompileCommandsStream)
{
std::string buildFilePath = buildFileDir + "/compile_commands.json";
// Get a stream where to generate things.
this->CompileCommandsStream =
new cmGeneratedFileStream(buildFilePath.c_str());
*this->CompileCommandsStream << "[";
} else {
*this->CompileCommandsStream << "," << std::endl;
}
*this->CompileCommandsStream << "\n{\n"
<< " \"directory\": \""
<< cmGlobalGenerator::EscapeJSON(buildFileDir) << "\",\n"
<< " \"command\": \""
<< cmGlobalGenerator::EscapeJSON(commandLine) << "\",\n"
<< " \"file\": \""
<< cmGlobalGenerator::EscapeJSON(sourceFile) << "\"\n"
<< "}";
}
void cmGlobalNinjaGenerator::CloseCompileCommandsStream()
{
if (this->CompileCommandsStream)
{
*this->CompileCommandsStream << "\n]";
delete this->CompileCommandsStream;
this->CompileCommandsStream = 0;
}
}
void cmGlobalNinjaGenerator::WriteDisclaimer(std::ostream& os)
{
os
......
......@@ -213,6 +213,9 @@ public:
cmGeneratedFileStream* GetRulesFileStream() const
{ return this->RulesFileStream; }
void AddCXXCompileCommand(const std::string &commandLine,
const std::string &sourceFile);
/**
* Add a rule to the generated build system.
* Call WriteRule() behind the scene but perform some check before like:
......@@ -254,6 +257,8 @@ private:
void OpenBuildFileStream();
void CloseBuildFileStream();
void CloseCompileCommandsStream();
void OpenRulesFileStream();
void CloseRulesFileStream();
......@@ -311,6 +316,7 @@ private:
/// The file containing the rule statements. (The action attached to each
/// edge of the compilation DAG).
cmGeneratedFileStream* RulesFileStream;
cmGeneratedFileStream* CompileCommandsStream;
/// The type used to store the set of rules added to the generated build
/// system.
......
......@@ -103,18 +103,6 @@ cmGlobalUnixMakefileGenerator3
}
}
//----------------------------------------------------------------------------
std::string EscapeJSON(const std::string& s) {
std::string result;
for (std::string::size_type i = 0; i < s.size(); ++i) {
if (s[i] == '"' || s[i] == '\\') {
result += '\\';
}
result += s[i];
}
return result;
}
void cmGlobalUnixMakefileGenerator3::Generate()
{
// first do superclass method
......@@ -179,11 +167,14 @@ void cmGlobalUnixMakefileGenerator3::AddCXXCompileCommand(
*this->CommandDatabase << "," << std::endl;
}
*this->CommandDatabase << "{" << std::endl
<< " \"directory\": \"" << EscapeJSON(workingDirectory) << "\","
<< " \"directory\": \""
<< cmGlobalGenerator::EscapeJSON(workingDirectory) << "\","
<< std::endl
<< " \"command\": \"" << EscapeJSON(compileCommand) << "\","
<< " \"command\": \"" <<
cmGlobalGenerator::EscapeJSON(compileCommand) << "\","
<< std::endl
<< " \"file\": \"" << EscapeJSON(sourceFile) << "\""
<< " \"file\": \"" <<
cmGlobalGenerator::EscapeJSON(sourceFile) << "\""
<< std::endl << "}";
}
......
......@@ -487,6 +487,39 @@ cmNinjaTargetGenerator
vars["TARGET_PDB"] = this->GetLocalGenerator()->ConvertToOutputFormat(
this->GetTargetPDB().c_str(), cmLocalGenerator::SHELL);
if(this->Makefile->IsOn("CMAKE_EXPORT_COMPILE_COMMANDS"))
{
cmLocalGenerator::RuleVariables compileObjectVars;
std::string lang = language;
compileObjectVars.Language = lang.c_str();
std::string escapedSourceFileName =
this->LocalGenerator->ConvertToOutputFormat(
sourceFileName.c_str(), cmLocalGenerator::SHELL);
compileObjectVars.Source = escapedSourceFileName.c_str();
compileObjectVars.Object = objectFileName.c_str();
compileObjectVars.Flags = vars["FLAGS"].c_str();
compileObjectVars.Defines = vars["DEFINES"].c_str();
// Rule for compiling object file.
std::string compileCmdVar = "CMAKE_";
compileCmdVar += language;
compileCmdVar += "_COMPILE_OBJECT";
std::string compileCmd =
this->GetMakefile()->GetRequiredDefinition(compileCmdVar.c_str());
std::vector<std::string> compileCmds;
cmSystemTools::ExpandListArgument(compileCmd, compileCmds);
for (std::vector<std::string>::iterator i = compileCmds.begin();
i != compileCmds.end(); ++i)
this->GetLocalGenerator()->ExpandRuleVariables(*i, compileObjectVars);
std::string cmdLine =
this->GetLocalGenerator()->BuildCommandLine(compileCmds);
this->GetGlobalGenerator()->AddCXXCompileCommand(cmdLine,
sourceFileName);
}
cmGlobalNinjaGenerator::WriteBuild(this->GetBuildFileStream(),
comment,
rule,
......
......@@ -35,7 +35,7 @@ private:
void ParseTranslationUnits()
{
this->TranslationUnits = TranslationUnitsType();
ExpectOrDie('[', "at start of compile command file");
ExpectOrDie('[', "at start of compile command file\n");
do
{
ParseTranslationUnit();
......
......@@ -47,7 +47,7 @@ CONFIGURE_FILE(${CMake_SOURCE_DIR}/Tests/EnforceConfig.cmake.in
# Testing
IF(BUILD_TESTING)
IF("${CMAKE_TEST_GENERATOR}" MATCHES "Unix Makefiles")
IF("${CMAKE_TEST_GENERATOR}" MATCHES "Unix Makefiles" OR ("${CMAKE_TEST_GENERATOR}" MATCHES Ninja AND NOT WIN32))
SET(TEST_CompileCommandOutput 1)
ENDIF()
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment