From 2c04bc00a4e38fc1b8f15bf950c8c2191ba24eac Mon Sep 17 00:00:00 2001 From: Stephen Kelly Date: Sun, 6 May 2012 15:07:19 +0200 Subject: Move the EscapeJSON method to a sharable location. --- Source/cmGlobalGenerator.cxx | 13 +++++++++++++ Source/cmGlobalGenerator.h | 2 ++ Source/cmGlobalUnixMakefileGenerator3.cxx | 21 ++++++--------------- 3 files changed, 21 insertions(+), 15 deletions(-) diff --git a/Source/cmGlobalGenerator.cxx b/Source/cmGlobalGenerator.cxx index b06cdb4..f883041 100644 --- a/Source/cmGlobalGenerator.cxx +++ b/Source/cmGlobalGenerator.cxx @@ -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; +} diff --git a/Source/cmGlobalGenerator.h b/Source/cmGlobalGenerator.h index 5254b89..8535edc 100644 --- a/Source/cmGlobalGenerator.h +++ b/Source/cmGlobalGenerator.h @@ -280,6 +280,8 @@ public: /** Generate an .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 GeneratorVector; // for a project collect all its targets by following depend diff --git a/Source/cmGlobalUnixMakefileGenerator3.cxx b/Source/cmGlobalUnixMakefileGenerator3.cxx index e63de9c..ebd8219 100644 --- a/Source/cmGlobalUnixMakefileGenerator3.cxx +++ b/Source/cmGlobalUnixMakefileGenerator3.cxx @@ -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 << "}"; } -- cgit v0.12 From 8778357898327c1e4893d8dc140fc0e63331e36b Mon Sep 17 00:00:00 2001 From: Stephen Kelly Date: Wed, 9 May 2012 22:55:51 +0200 Subject: Add newline to the output. --- Tests/CMakeLib/run_compile_commands.cxx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Tests/CMakeLib/run_compile_commands.cxx b/Tests/CMakeLib/run_compile_commands.cxx index 3f141c5..434cbee 100644 --- a/Tests/CMakeLib/run_compile_commands.cxx +++ b/Tests/CMakeLib/run_compile_commands.cxx @@ -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(); -- cgit v0.12 From db839bec7d076b54c5e9ad0d19386a26557a509e Mon Sep 17 00:00:00 2001 From: Stephen Kelly Date: Wed, 9 May 2012 23:47:37 +0200 Subject: Make the CMAKE_EXPORT_COMPILE_COMMANDS option work with Ninja. --- Modules/CMakeGenericSystem.cmake | 6 ++++++ Source/cmGlobalNinjaGenerator.cxx | 42 +++++++++++++++++++++++++++++++++++++++ Source/cmGlobalNinjaGenerator.h | 6 ++++++ Source/cmNinjaTargetGenerator.cxx | 30 ++++++++++++++++++++++++++++ Tests/CMakeLists.txt | 2 +- 5 files changed, 85 insertions(+), 1 deletion(-) diff --git a/Modules/CMakeGenericSystem.cmake b/Modules/CMakeGenericSystem.cmake index c733969..0ccbfac 100644 --- a/Modules/CMakeGenericSystem.cmake +++ b/Modules/CMakeGenericSystem.cmake @@ -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 # diff --git a/Source/cmGlobalNinjaGenerator.cxx b/Source/cmGlobalNinjaGenerator.cxx index 328706c..0e89fab 100644 --- a/Source/cmGlobalNinjaGenerator.cxx +++ b/Source/cmGlobalNinjaGenerator.cxx @@ -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 diff --git a/Source/cmGlobalNinjaGenerator.h b/Source/cmGlobalNinjaGenerator.h index e652972..7b6b9b7 100644 --- a/Source/cmGlobalNinjaGenerator.h +++ b/Source/cmGlobalNinjaGenerator.h @@ -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. diff --git a/Source/cmNinjaTargetGenerator.cxx b/Source/cmNinjaTargetGenerator.cxx index 80007f1..7c58154 100644 --- a/Source/cmNinjaTargetGenerator.cxx +++ b/Source/cmNinjaTargetGenerator.cxx @@ -487,6 +487,36 @@ 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(); + compileObjectVars.Source = sourceFileName.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 compileCmds; + cmSystemTools::ExpandListArgument(compileCmd, compileCmds); + + for (std::vector::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, diff --git a/Tests/CMakeLists.txt b/Tests/CMakeLists.txt index 5972c19..ffa5bcb 100644 --- a/Tests/CMakeLists.txt +++ b/Tests/CMakeLists.txt @@ -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) SET(TEST_CompileCommandOutput 1) ENDIF() -- cgit v0.12 From fbaddf4e403af327d263e347e666396a08fbdd10 Mon Sep 17 00:00:00 2001 From: Stephen Kelly Date: Wed, 23 May 2012 18:08:23 +0200 Subject: Escape the source file to be compiled if required. Whitespaces in paths can otherwise cause invalid command lines to be generated. --- Source/cmNinjaTargetGenerator.cxx | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/Source/cmNinjaTargetGenerator.cxx b/Source/cmNinjaTargetGenerator.cxx index 7c58154..e419a4d 100644 --- a/Source/cmNinjaTargetGenerator.cxx +++ b/Source/cmNinjaTargetGenerator.cxx @@ -492,7 +492,10 @@ cmNinjaTargetGenerator cmLocalGenerator::RuleVariables compileObjectVars; std::string lang = language; compileObjectVars.Language = lang.c_str(); - compileObjectVars.Source = sourceFileName.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(); -- cgit v0.12 From 3545645c1b01f609496a4fc41e20419dedbbd98d Mon Sep 17 00:00:00 2001 From: Stephen Kelly Date: Tue, 5 Jun 2012 00:12:16 +0200 Subject: Exclude the CompileCommandOutput test on WIN32. --- Tests/CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Tests/CMakeLists.txt b/Tests/CMakeLists.txt index ffa5bcb..ef707e4 100644 --- a/Tests/CMakeLists.txt +++ b/Tests/CMakeLists.txt @@ -47,7 +47,7 @@ CONFIGURE_FILE(${CMake_SOURCE_DIR}/Tests/EnforceConfig.cmake.in # Testing IF(BUILD_TESTING) - IF("${CMAKE_TEST_GENERATOR}" MATCHES "Unix Makefiles" OR "${CMAKE_TEST_GENERATOR}" MATCHES Ninja) + IF("${CMAKE_TEST_GENERATOR}" MATCHES "Unix Makefiles" OR ("${CMAKE_TEST_GENERATOR}" MATCHES Ninja AND NOT WIN32)) SET(TEST_CompileCommandOutput 1) ENDIF() -- cgit v0.12