For your convenience, rebased onto current head and git format-patch'ed. Cheers, /Manuel
On Tue, Apr 5, 2011 at 9:14 AM, Manuel Klimek <kli...@google.com> wrote: > On Tue, Apr 5, 2011 at 5:33 AM, Brad King <brad.k...@kitware.com> wrote: >> On 04/04/2011 12:01 PM, Manuel Klimek wrote: >>> Done. >> >> Thanks! >> >>> I also have the previous patches ready (re-based with master). Let me >>> know how we'll go on about submitting all that. >> >> I still have them on a local topic branch. See below. >> Have you changed anything since then? > > Well, the git rebase led to conflicts which I resolved - otherwise I > didn't change anything on the other patches. So I can re-export the > changes to save you some work with merging, if you want :) > > Cheers, > /Manuel > >> If you prefer to send the new versions, please use "git format-patch" to >> construct the patch series. Then send the files by email. >> >> Thanks, >> -Brad >> >> >> commit c8ed16a373adf98cf21a619349de8c0bde6a0eed >> Author: Manuel Klimek <kli...@google.com> >> Date: Mon Jan 17 11:44:44 2011 -0500 >> >> Make compile line export optional >> >> Add option CMAKE_EXPORT_COMPILE_COMMANDS to control the behavior. >> >> Modules/CMakeGenericSystem.cmake | 3 +++ >> Source/cmGlobalUnixMakefileGenerator3.cxx | 2 +- >> Source/cmMakefileTargetGenerator.cxx | 3 ++- >> 3 files changed, 6 insertions(+), 2 deletions(-) >> >> commit 357fdbb1d7c472991323d36c6a431a36f16918bd >> Author: Manuel Klimek <kli...@google.com> >> Date: Thu Jan 13 16:15:54 2011 -0500 >> >> Export all compile command lines to json database >> >> Source/cmGlobalUnixMakefileGenerator3.cxx | 41 >> +++++++++++++++++++++++++++++ >> Source/cmGlobalUnixMakefileGenerator3.h | 6 ++++ >> Source/cmMakefileTargetGenerator.cxx | 21 +++++++++++++- >> 3 files changed, 66 insertions(+), 2 deletions(-) >> >> commit a75e21cadeb48c257d870db925131994f7da4995 >> Author: Manuel Klimek <kli...@google.com> >> Date: Thu Jan 13 16:06:20 2011 -0500 >> >> Factor Makefile flag and define lookup into methods >> >> Cache results over repeated calls. >> >> Source/cmMakefileTargetGenerator.cxx | 107 >> +++++++++++++++++++-------------- >> Source/cmMakefileTargetGenerator.h | 5 ++ >> 2 files changed, 67 insertions(+), 45 deletions(-) >> > > > > -- > Manuel Klimek (http://go/klimek)
From 8b304e3c4a111a242033d261adb9f02f116cfa96 Mon Sep 17 00:00:00 2001 From: Manuel Klimek <kli...@google.com> Date: Wed, 12 Jan 2011 20:06:25 -0800 Subject: [PATCH 1/5] refactor flags and defines --- Source/cmMakefileTargetGenerator.cxx | 120 ++++++++++++++++++--------------- Source/cmMakefileTargetGenerator.h | 3 + 2 files changed, 68 insertions(+), 55 deletions(-) diff --git a/Source/cmMakefileTargetGenerator.cxx b/Source/cmMakefileTargetGenerator.cxx index 69320da..01545fc 100644 --- a/Source/cmMakefileTargetGenerator.cxx +++ b/Source/cmMakefileTargetGenerator.cxx @@ -249,6 +249,66 @@ void cmMakefileTargetGenerator::WriteCommonCodeRules() } //---------------------------------------------------------------------------- +std::string cmMakefileTargetGenerator::GetFlags(const std::string &l) { + std::string flags; + const char *lang = l.c_str(); + + bool shared = ((this->Target->GetType() == cmTarget::SHARED_LIBRARY) || + (this->Target->GetType() == cmTarget::MODULE_LIBRARY)); + + // Add language feature flags. + this->AddFeatureFlags(flags, lang); + + this->LocalGenerator->AddArchitectureFlags(flags, this->Target, + lang, this->ConfigName); + + // Fortran-specific flags computed for this target. + if(l == "Fortran") + { + this->AddFortranFlags(flags); + } + + // Add shared-library flags if needed. + this->LocalGenerator->AddSharedFlags(flags, lang, shared); + + // Add include directory flags. + this->AddIncludeFlags(flags, lang); + + // Append old-style preprocessor definition flags. + this->LocalGenerator-> + AppendFlags(flags, this->Makefile->GetDefineFlags()); + + // Add include directory flags. + this->LocalGenerator-> + AppendFlags(flags,this->GetFrameworkFlags().c_str()); + + return flags; +} + +std::string cmMakefileTargetGenerator::GetDefines(const std::string &l) { + std::string defines; + const char *lang = l.c_str(); + // Add the export symbol definition for shared library objects. + if(const char* exportMacro = this->Target->GetExportMacro()) + { + this->LocalGenerator->AppendDefines(defines, exportMacro, lang); + } + + // Add preprocessor definitions for this target and configuration. + this->LocalGenerator->AppendDefines + (defines, this->Makefile->GetProperty("COMPILE_DEFINITIONS"), lang); + this->LocalGenerator->AppendDefines + (defines, this->Target->GetProperty("COMPILE_DEFINITIONS"), lang); + std::string defPropName = "COMPILE_DEFINITIONS_"; + defPropName += + cmSystemTools::UpperCase(this->LocalGenerator->ConfigurationName); + this->LocalGenerator->AppendDefines + (defines, this->Makefile->GetProperty(defPropName.c_str()), lang); + this->LocalGenerator->AppendDefines + (defines, this->Target->GetProperty(defPropName.c_str()), lang); + return defines; +} + void cmMakefileTargetGenerator::WriteTargetLanguageFlags() { // write language flags for target @@ -262,72 +322,22 @@ void cmMakefileTargetGenerator::WriteTargetLanguageFlags() cmStdString compiler = "CMAKE_"; compiler += *l; compiler += "_COMPILER"; - *this->FlagFileStream << "# compile " << l->c_str() << " with " << + *this->FlagFileStream << "# compile " << l->c_str() << " with " << this->Makefile->GetSafeDefinition(compiler.c_str()) << "\n"; } for(std::set<cmStdString>::const_iterator l = languages.begin(); l != languages.end(); ++l) { - const char *lang = l->c_str(); - std::string flags; - std::string defines; - bool shared = ((this->Target->GetType() == cmTarget::SHARED_LIBRARY) || - (this->Target->GetType() == cmTarget::MODULE_LIBRARY)); - - // Add the export symbol definition for shared library objects. - if(const char* exportMacro = this->Target->GetExportMacro()) - { - this->LocalGenerator->AppendDefines(defines, exportMacro, lang); - } - - // Add preprocessor definitions for this target and configuration. - this->LocalGenerator->AppendDefines - (defines, this->Makefile->GetProperty("COMPILE_DEFINITIONS"), lang); - this->LocalGenerator->AppendDefines - (defines, this->Target->GetProperty("COMPILE_DEFINITIONS"), lang); - std::string defPropName = "COMPILE_DEFINITIONS_"; - defPropName += - cmSystemTools::UpperCase(this->LocalGenerator->ConfigurationName); - this->LocalGenerator->AppendDefines - (defines, this->Makefile->GetProperty(defPropName.c_str()), lang); - this->LocalGenerator->AppendDefines - (defines, this->Target->GetProperty(defPropName.c_str()), lang); - - // Add language feature flags. - this->AddFeatureFlags(flags, lang); - - this->LocalGenerator->AddArchitectureFlags(flags, this->Target, - lang, this->ConfigName); - - // Fortran-specific flags computed for this target. - if(*l == "Fortran") - { - this->AddFortranFlags(flags); - } - - // Add shared-library flags if needed. - this->LocalGenerator->AddSharedFlags(flags, lang, shared); - - // Add include directory flags. - this->AddIncludeFlags(flags, lang); - - // Append old-style preprocessor definition flags. - this->LocalGenerator-> - AppendFlags(flags, this->Makefile->GetDefineFlags()); - - // Add include directory flags. - this->LocalGenerator-> - AppendFlags(flags,this->GetFrameworkFlags().c_str()); - - *this->FlagFileStream << lang << "_FLAGS = " << flags << "\n\n"; - *this->FlagFileStream << lang << "_DEFINES = " << defines << "\n\n"; + *this->FlagFileStream << *l << "_FLAGS = " << this->GetFlags(*l) << "\n\n"; + *this->FlagFileStream << *l << "_DEFINES = " << this->GetDefines(*l) << + "\n\n"; } // Add target-specific flags. if(this->Target->GetProperty("COMPILE_FLAGS")) { - std::string flags; + std::string flags; this->LocalGenerator->AppendFlags (flags, this->Target->GetProperty("COMPILE_FLAGS")); *this->FlagFileStream << "# TARGET_FLAGS = " << flags << "\n\n"; diff --git a/Source/cmMakefileTargetGenerator.h b/Source/cmMakefileTargetGenerator.h index bd26795..0005b48 100644 --- a/Source/cmMakefileTargetGenerator.h +++ b/Source/cmMakefileTargetGenerator.h @@ -216,6 +216,9 @@ protected: std::string MacContentDirectory; std::set<cmStdString> MacContentFolders; + std::string GetFlags(const std::string &l); + std::string GetDefines(const std::string &l); + // Target-wide Fortran module output directory. bool FortranModuleDirectoryComputed; std::string FortranModuleDirectory; -- 1.7.3.1
From 9e7681e1632c3bb04a3d9add8daaf99468b5a719 Mon Sep 17 00:00:00 2001 From: Manuel Klimek <kli...@google.com> Date: Fri, 14 Jan 2011 14:28:38 -0800 Subject: [PATCH 2/5] cache flags and defines --- Source/cmMakefileTargetGenerator.cxx | 97 ++++++++++++++++++---------------- Source/cmMakefileTargetGenerator.h | 2 + 2 files changed, 54 insertions(+), 45 deletions(-) diff --git a/Source/cmMakefileTargetGenerator.cxx b/Source/cmMakefileTargetGenerator.cxx index 01545fc..1c45f18 100644 --- a/Source/cmMakefileTargetGenerator.cxx +++ b/Source/cmMakefileTargetGenerator.cxx @@ -250,63 +250,70 @@ void cmMakefileTargetGenerator::WriteCommonCodeRules() //---------------------------------------------------------------------------- std::string cmMakefileTargetGenerator::GetFlags(const std::string &l) { - std::string flags; - const char *lang = l.c_str(); + std::pair<std::map<std::string, std::string>::iterator, bool> + insert_result = this->FlagsByLanguage.insert(std::make_pair(l, "")); + if (insert_result.second) { + std::string& flags = insert_result.first->second; + const char *lang = l.c_str(); - bool shared = ((this->Target->GetType() == cmTarget::SHARED_LIBRARY) || - (this->Target->GetType() == cmTarget::MODULE_LIBRARY)); + bool shared = ((this->Target->GetType() == cmTarget::SHARED_LIBRARY) || + (this->Target->GetType() == cmTarget::MODULE_LIBRARY)); - // Add language feature flags. - this->AddFeatureFlags(flags, lang); + // Add language feature flags. + this->AddFeatureFlags(flags, lang); - this->LocalGenerator->AddArchitectureFlags(flags, this->Target, - lang, this->ConfigName); + this->LocalGenerator->AddArchitectureFlags(flags, this->Target, + lang, this->ConfigName); - // Fortran-specific flags computed for this target. - if(l == "Fortran") - { - this->AddFortranFlags(flags); - } - - // Add shared-library flags if needed. - this->LocalGenerator->AddSharedFlags(flags, lang, shared); + // Fortran-specific flags computed for this target. + if(l == "Fortran") + { + this->AddFortranFlags(flags); + } - // Add include directory flags. - this->AddIncludeFlags(flags, lang); + // Add shared-library flags if needed. + this->LocalGenerator->AddSharedFlags(flags, lang, shared); - // Append old-style preprocessor definition flags. - this->LocalGenerator-> - AppendFlags(flags, this->Makefile->GetDefineFlags()); + // Add include directory flags. + this->AddIncludeFlags(flags, lang); - // Add include directory flags. - this->LocalGenerator-> - AppendFlags(flags,this->GetFrameworkFlags().c_str()); + // Append old-style preprocessor definition flags. + this->LocalGenerator-> + AppendFlags(flags, this->Makefile->GetDefineFlags()); - return flags; + // Add include directory flags. + this->LocalGenerator-> + AppendFlags(flags,this->GetFrameworkFlags().c_str()); + } + return insert_result.first->second; } std::string cmMakefileTargetGenerator::GetDefines(const std::string &l) { - std::string defines; - const char *lang = l.c_str(); - // Add the export symbol definition for shared library objects. - if(const char* exportMacro = this->Target->GetExportMacro()) - { - this->LocalGenerator->AppendDefines(defines, exportMacro, lang); - } + std::pair<std::map<std::string, std::string>::iterator, bool> + insert_result = this->DefinesByLanguage.insert(std::make_pair(l, "")); + if (insert_result.second) { + std::string &defines = insert_result.first->second; + const char *lang = l.c_str(); + // Add the export symbol definition for shared library objects. + if(const char* exportMacro = this->Target->GetExportMacro()) + { + this->LocalGenerator->AppendDefines(defines, exportMacro, lang); + } - // Add preprocessor definitions for this target and configuration. - this->LocalGenerator->AppendDefines - (defines, this->Makefile->GetProperty("COMPILE_DEFINITIONS"), lang); - this->LocalGenerator->AppendDefines - (defines, this->Target->GetProperty("COMPILE_DEFINITIONS"), lang); - std::string defPropName = "COMPILE_DEFINITIONS_"; - defPropName += - cmSystemTools::UpperCase(this->LocalGenerator->ConfigurationName); - this->LocalGenerator->AppendDefines - (defines, this->Makefile->GetProperty(defPropName.c_str()), lang); - this->LocalGenerator->AppendDefines - (defines, this->Target->GetProperty(defPropName.c_str()), lang); - return defines; + // Add preprocessor definitions for this target and configuration. + this->LocalGenerator->AppendDefines + (defines, this->Makefile->GetProperty("COMPILE_DEFINITIONS"), lang); + this->LocalGenerator->AppendDefines + (defines, this->Target->GetProperty("COMPILE_DEFINITIONS"), lang); + std::string defPropName = "COMPILE_DEFINITIONS_"; + defPropName += + cmSystemTools::UpperCase(this->LocalGenerator->ConfigurationName); + this->LocalGenerator->AppendDefines + (defines, this->Makefile->GetProperty(defPropName.c_str()), lang); + this->LocalGenerator->AppendDefines + (defines, this->Target->GetProperty(defPropName.c_str()), lang); + } + return insert_result.first->second; } void cmMakefileTargetGenerator::WriteTargetLanguageFlags() diff --git a/Source/cmMakefileTargetGenerator.h b/Source/cmMakefileTargetGenerator.h index 0005b48..db87ebc 100644 --- a/Source/cmMakefileTargetGenerator.h +++ b/Source/cmMakefileTargetGenerator.h @@ -217,7 +217,9 @@ protected: std::set<cmStdString> MacContentFolders; std::string GetFlags(const std::string &l); + std::map<std::string, std::string> FlagsByLanguage; std::string GetDefines(const std::string &l); + std::map<std::string, std::string> DefinesByLanguage; // Target-wide Fortran module output directory. bool FortranModuleDirectoryComputed; -- 1.7.3.1
From 77a1d4013307d31173bafc2491283ffd5349a147 Mon Sep 17 00:00:00 2001 From: Manuel Klimek <kli...@google.com> Date: Wed, 12 Jan 2011 20:39:13 -0800 Subject: [PATCH 3/5] implement cxx command output --- Source/cmGlobalUnixMakefileGenerator3.cxx | 41 +++++++++++++++++++++++++++++ Source/cmGlobalUnixMakefileGenerator3.h | 6 ++++ Source/cmMakefileTargetGenerator.cxx | 21 +++++++++++++- 3 files changed, 66 insertions(+), 2 deletions(-) diff --git a/Source/cmGlobalUnixMakefileGenerator3.cxx b/Source/cmGlobalUnixMakefileGenerator3.cxx index d9a341c..92f87c9 100644 --- a/Source/cmGlobalUnixMakefileGenerator3.cxx +++ b/Source/cmGlobalUnixMakefileGenerator3.cxx @@ -31,6 +31,7 @@ cmGlobalUnixMakefileGenerator3::cmGlobalUnixMakefileGenerator3() #else this->UseLinkScript = true; #endif + this->CommandDatabase = NULL; } void cmGlobalUnixMakefileGenerator3 @@ -139,6 +140,17 @@ void cmGlobalUnixMakefileGenerator3 } //---------------------------------------------------------------------------- +std::string EscapeJSON(const std::string& s) { + std::string result; + for (int i = 0; i < s.size(); ++i) { + if (s[i] == '"' || s[i] == '\\') { + result += '\\'; + } + result += s[i]; + } + return result; +} + void cmGlobalUnixMakefileGenerator3::Generate() { // first do superclass method @@ -189,6 +201,35 @@ void cmGlobalUnixMakefileGenerator3::Generate() // write the main makefile this->WriteMainMakefile2(); this->WriteMainCMakefile(); + + if (this->CommandDatabase != NULL) { + *this->CommandDatabase << std::endl << "]"; + delete this->CommandDatabase; + this->CommandDatabase = NULL; + } +} + +void cmGlobalUnixMakefileGenerator3::AddCXXCompileCommand( + const std::string &sourceFile, const std::string &workingDirectory, + const std::string &compileCommand) { + if (this->CommandDatabase == NULL) + { + std::string commandDatabaseName = + std::string(this->GetCMakeInstance()->GetHomeOutputDirectory()) + + "/cxx_commands.json"; + this->CommandDatabase = + new cmGeneratedFileStream(commandDatabaseName.c_str()); + *this->CommandDatabase << "[" << std::endl; + } else { + *this->CommandDatabase << "," << std::endl; + } + *this->CommandDatabase << "{" << std::endl + << " \"directory\": \"" << EscapeJSON(workingDirectory) << "\"," + << std::endl + << " \"command\": \"" << EscapeJSON(compileCommand) << "\"," + << std::endl + << " \"file\": \"" << EscapeJSON(sourceFile) << "\"" + << std::endl << "}"; } void cmGlobalUnixMakefileGenerator3::WriteMainMakefile2() diff --git a/Source/cmGlobalUnixMakefileGenerator3.h b/Source/cmGlobalUnixMakefileGenerator3.h index cdc9460..a152e01 100644 --- a/Source/cmGlobalUnixMakefileGenerator3.h +++ b/Source/cmGlobalUnixMakefileGenerator3.h @@ -112,6 +112,10 @@ public: /** Record per-target progress information. */ void RecordTargetProgress(cmMakefileTargetGenerator* tg); + void AddCXXCompileCommand(const std::string &sourceFile, + const std::string &workingDirectory, + const std::string &compileCommand); + protected: void WriteMainMakefile2(); void WriteMainCMakefile(); @@ -178,6 +182,8 @@ protected: size_t CountProgressMarksInTarget(cmTarget* target, std::set<cmTarget*>& emitted); size_t CountProgressMarksInAll(cmLocalUnixMakefileGenerator3* lg); + + cmGeneratedFileStream *CommandDatabase; }; #endif diff --git a/Source/cmMakefileTargetGenerator.cxx b/Source/cmMakefileTargetGenerator.cxx index 1c45f18..e5df2f4 100644 --- a/Source/cmMakefileTargetGenerator.cxx +++ b/Source/cmMakefileTargetGenerator.cxx @@ -658,6 +658,9 @@ cmMakefileTargetGenerator vars.Flags = flags.c_str(); vars.Defines = defines.c_str(); + bool lang_is_c_or_cxx = ((strcmp(lang, "C") == 0) || + (strcmp(lang, "CXX") == 0)); + // Construct the compile rules. { std::string compileRuleVar = "CMAKE_"; @@ -668,6 +671,22 @@ cmMakefileTargetGenerator std::vector<std::string> compileCommands; cmSystemTools::ExpandListArgument(compileRule, compileCommands); + if (lang_is_c_or_cxx && compileCommands.size() == 1) + { + std::string compileCommand = compileCommands[0]; + this->LocalGenerator->ExpandRuleVariables(compileCommand, vars); + std::string workingDirectory = + this->LocalGenerator->Convert( + this->Makefile->GetStartOutputDirectory(), cmLocalGenerator::FULL); + compileCommand.replace(compileCommand.find(langFlags), + langFlags.size(), this->GetFlags(lang)); + std::string langDefines = std::string("$(") + lang + "_DEFINES)"; + compileCommand.replace(compileCommand.find(langDefines), + langDefines.size(), this->GetDefines(lang)); + this->GlobalGenerator->AddCXXCompileCommand( + source.GetFullPath(), workingDirectory, compileCommand); + } + // Expand placeholders in the commands. for(std::vector<std::string>::iterator i = compileCommands.begin(); i != compileCommands.end(); ++i) @@ -708,8 +727,6 @@ cmMakefileTargetGenerator } } - bool lang_is_c_or_cxx = ((strcmp(lang, "C") == 0) || - (strcmp(lang, "CXX") == 0)); bool do_preprocess_rules = lang_is_c_or_cxx && this->LocalGenerator->GetCreatePreprocessedSourceRules(); bool do_assembly_rules = lang_is_c_or_cxx && -- 1.7.3.1
From 1b3f120d7aa3624ea645a5aa459eb461df41630a Mon Sep 17 00:00:00 2001 From: Manuel Klimek <kli...@google.com> Date: Fri, 14 Jan 2011 15:16:11 -0800 Subject: [PATCH 4/5] make compile command output optional --- Modules/CMakeGenericSystem.cmake | 3 +++ Source/cmGlobalUnixMakefileGenerator3.cxx | 2 +- Source/cmMakefileTargetGenerator.cxx | 3 ++- 3 files changed, 6 insertions(+), 2 deletions(-) diff --git a/Modules/CMakeGenericSystem.cmake b/Modules/CMakeGenericSystem.cmake index b5d3072..e64d0ba 100644 --- a/Modules/CMakeGenericSystem.cmake +++ b/Modules/CMakeGenericSystem.cmake @@ -50,6 +50,9 @@ IF(CMAKE_GENERATOR MATCHES "Makefiles") IF(DEFINED CMAKE_RULE_MESSAGES) SET_PROPERTY(GLOBAL PROPERTY RULE_MESSAGES ${CMAKE_RULE_MESSAGES}) ENDIF(DEFINED CMAKE_RULE_MESSAGES) + SET(CMAKE_EXPORT_COMPILE_COMMANDS OFF CACHE BOOL + "Enable/Disable output of compile commands during generation." + ) ENDIF(CMAKE_GENERATOR MATCHES "Makefiles") diff --git a/Source/cmGlobalUnixMakefileGenerator3.cxx b/Source/cmGlobalUnixMakefileGenerator3.cxx index 92f87c9..54f2b03 100644 --- a/Source/cmGlobalUnixMakefileGenerator3.cxx +++ b/Source/cmGlobalUnixMakefileGenerator3.cxx @@ -216,7 +216,7 @@ void cmGlobalUnixMakefileGenerator3::AddCXXCompileCommand( { std::string commandDatabaseName = std::string(this->GetCMakeInstance()->GetHomeOutputDirectory()) - + "/cxx_commands.json"; + + "/compile_commands.json"; this->CommandDatabase = new cmGeneratedFileStream(commandDatabaseName.c_str()); *this->CommandDatabase << "[" << std::endl; diff --git a/Source/cmMakefileTargetGenerator.cxx b/Source/cmMakefileTargetGenerator.cxx index e5df2f4..6d3fbe0 100644 --- a/Source/cmMakefileTargetGenerator.cxx +++ b/Source/cmMakefileTargetGenerator.cxx @@ -671,7 +671,8 @@ cmMakefileTargetGenerator std::vector<std::string> compileCommands; cmSystemTools::ExpandListArgument(compileRule, compileCommands); - if (lang_is_c_or_cxx && compileCommands.size() == 1) + if (this->Makefile->IsOn("CMAKE_EXPORT_COMPILE_COMMANDS") && + lang_is_c_or_cxx && compileCommands.size() == 1) { std::string compileCommand = compileCommands[0]; this->LocalGenerator->ExpandRuleVariables(compileCommand, vars); -- 1.7.3.1
From a1086a20227bd98c21462abcba3ff8c3d1cabde9 Mon Sep 17 00:00:00 2001 From: Manuel Klimek <kli...@google.com> Date: Thu, 31 Mar 2011 16:55:00 -0700 Subject: [PATCH 5/5] Adds a test for the compile command line output. --- Tests/CMakeLib/CMakeLists.txt | 3 + Tests/CMakeLib/run_compile_commands.cxx | 132 ++++++++++++++++++++ Tests/CMakeLists.txt | 3 + Tests/CompileCommandOutput/CMakeLists.txt | 11 ++ .../compile_command_output.cxx | 9 ++ Tests/CompileCommandOutput/file with spaces.cxx | 3 + Tests/CompileCommandOutput/file with spaces.h | 1 + Tests/CompileCommandOutput/relative.cxx | 3 + Tests/CompileCommandOutput/relative.h | 1 + 9 files changed, 166 insertions(+), 0 deletions(-) create mode 100644 Tests/CMakeLib/run_compile_commands.cxx create mode 100644 Tests/CompileCommandOutput/CMakeLists.txt create mode 100644 Tests/CompileCommandOutput/compile_command_output.cxx create mode 100644 Tests/CompileCommandOutput/file with spaces.cxx create mode 100644 Tests/CompileCommandOutput/file with spaces.h create mode 100644 Tests/CompileCommandOutput/relative.cxx create mode 100644 Tests/CompileCommandOutput/relative.h diff --git a/Tests/CMakeLib/CMakeLists.txt b/Tests/CMakeLib/CMakeLists.txt index bda2fa5..7815545 100644 --- a/Tests/CMakeLib/CMakeLists.txt +++ b/Tests/CMakeLib/CMakeLists.txt @@ -30,3 +30,6 @@ endif() foreach(test ${CMakeLib_TESTS}) add_test(CMakeLib.${test} CMakeLibTests ${test}) endforeach() + +ADD_EXECUTABLE(runcompilecommands run_compile_commands.cxx) +TARGET_LINK_LIBRARIES(runcompilecommands CMakeLib) diff --git a/Tests/CMakeLib/run_compile_commands.cxx b/Tests/CMakeLib/run_compile_commands.cxx new file mode 100644 index 0000000..c925167 --- /dev/null +++ b/Tests/CMakeLib/run_compile_commands.cxx @@ -0,0 +1,132 @@ +#include "cmSystemTools.h" + +class CompileCommandParser { +public: + typedef std::map<std::string, std::string> CommandType; + typedef std::vector<CommandType> TranslationUnitsType; + + CompileCommandParser(std::ifstream *input) + { + this->Input = input; + } + + void Parse() + { + NextNonWhitespace(); + ParseTranslationUnits(); + } + + const TranslationUnitsType& GetTranslationUnits() + { + return this->TranslationUnits; + } + +private: + void ParseTranslationUnits() + { + this->TranslationUnits = TranslationUnitsType(); + ExpectOrDie('[', "at start of compile command file"); + do + { + ParseTranslationUnit(); + this->TranslationUnits.push_back(this->Command); + } while(Expect(',')); + ExpectOrDie(']', "at end of array"); + } + + void ParseTranslationUnit() + { + this->Command = CommandType(); + if(!Expect('{')) return; + if(Expect('}')) return; + do + { + ParseString(); + std::string name = this->String; + ExpectOrDie(':', "between name and value"); + ParseString(); + std::string value = this->String; + this->Command[name] = value; + } while(Expect(',')); + ExpectOrDie('}', "at end of object"); + } + + void ParseString() + { + this->String.clear(); + if(!Expect('"')) return; + while (!Expect('"')) + { + Expect('\\'); + this->String.push_back(C); + Next(); + } + } + + bool Expect(char c) + { + if(this->C == c) + { + NextNonWhitespace(); + return true; + } + return false; + } + + void ExpectOrDie(char c, const std::string & message) + { + if (!Expect(c)) + ErrorExit(std::string("'") + c + "' expected " + message + "."); + } + + void NextNonWhitespace() + { + do { Next(); } while (IsWhitespace()); + } + + void Next() + { + this->C = Input->get(); + if (this->Input->bad()) ErrorExit("Unexpected end of file."); + } + + void ErrorExit(const std::string &message) { + std::cout << "ERROR: " << message; + exit(1); + } + + bool IsWhitespace() + { + return (this->C == ' ' || this->C == '\t' || + this->C == '\n' || this->C == '\r'); + } + + char C; + TranslationUnitsType TranslationUnits; + CommandType Command; + std::string String; + std::ifstream *Input; +}; + +int main () +{ + std::ifstream file("compile_commands.json"); + CompileCommandParser parser(&file); + parser.Parse(); + for(CompileCommandParser::TranslationUnitsType::const_iterator + it = parser.GetTranslationUnits().begin(), + end = parser.GetTranslationUnits().end(); it != end; ++it) + { + std::vector<std::string> std_command; + cmSystemTools::ParseUnixCommandLine(it->at("command").c_str(), std_command); + std::vector<cmStdString> command(std_command.begin(), std_command.end()); + if (!cmSystemTools::RunSingleCommand( + command, 0, 0, it->at("directory").c_str())) + { + std::cout << "ERROR: Failed to run command \"" + << command[0] << "\"" << std::endl; + exit(1); + } + } + return 0; +} diff --git a/Tests/CMakeLists.txt b/Tests/CMakeLists.txt index 157814e..126eadd 100644 --- a/Tests/CMakeLists.txt +++ b/Tests/CMakeLists.txt @@ -2031,6 +2031,9 @@ ${CMake_BINARY_DIR}/bin/cmake -DVERSION=master -P ${CMake_SOURCE_DIR}/Utilities/ ENDIF() SET_TESTS_PROPERTIES(Contracts.${project} PROPERTIES TIMEOUT ${timeout}) ENDFOREACH() + + ADD_TEST_MACRO(CompileCommandOutput + "${CMake_BINARY_DIR}/Tests/CMakeLib/runcompilecommands") ENDIF(BUILD_TESTING) SUBDIRS(CMakeTests) diff --git a/Tests/CompileCommandOutput/CMakeLists.txt b/Tests/CompileCommandOutput/CMakeLists.txt new file mode 100644 index 0000000..ac39b8b --- /dev/null +++ b/Tests/CompileCommandOutput/CMakeLists.txt @@ -0,0 +1,11 @@ +# a simple C only test case +cmake_minimum_required (VERSION 2.6) +project (CompileCommandOutput CXX) + +SET(CMAKE_EXPORT_COMPILE_COMMANDS ON) +set(CMAKE_DEBUG_POSTFIX "_test_debug_postfix") +ADD_LIBRARY(test1 STATIC "file with spaces.cxx") +ADD_LIBRARY(test2 SHARED "../CompileCommandOutput/relative.cxx") +INCLUDE_DIRECTORIES(${CompileCommandOutput_SOURCE_DIR}/../../Source) +ADD_EXECUTABLE(CompileCommandOutput compile_command_output.cxx) +TARGET_LINK_LIBRARIES(CompileCommandOutput test1 test2) diff --git a/Tests/CompileCommandOutput/compile_command_output.cxx b/Tests/CompileCommandOutput/compile_command_output.cxx new file mode 100644 index 0000000..9487c89 --- /dev/null +++ b/Tests/CompileCommandOutput/compile_command_output.cxx @@ -0,0 +1,9 @@ +#include "file with spaces.h" +#include "relative.h" + +int main (int argc, char** argv) +{ + file_with_spaces(); + relative(); + return 0; +} diff --git a/Tests/CompileCommandOutput/file with spaces.cxx b/Tests/CompileCommandOutput/file with spaces.cxx new file mode 100644 index 0000000..5759319 --- /dev/null +++ b/Tests/CompileCommandOutput/file with spaces.cxx @@ -0,0 +1,3 @@ +#include "file with spaces.h" + +void file_with_spaces() {} diff --git a/Tests/CompileCommandOutput/file with spaces.h b/Tests/CompileCommandOutput/file with spaces.h new file mode 100644 index 0000000..49b686c --- /dev/null +++ b/Tests/CompileCommandOutput/file with spaces.h @@ -0,0 +1 @@ +void file_with_spaces(); diff --git a/Tests/CompileCommandOutput/relative.cxx b/Tests/CompileCommandOutput/relative.cxx new file mode 100644 index 0000000..eae11e2 --- /dev/null +++ b/Tests/CompileCommandOutput/relative.cxx @@ -0,0 +1,3 @@ +#include "relative.h" + +void relative() {} diff --git a/Tests/CompileCommandOutput/relative.h b/Tests/CompileCommandOutput/relative.h new file mode 100644 index 0000000..2168035 --- /dev/null +++ b/Tests/CompileCommandOutput/relative.h @@ -0,0 +1 @@ +void relative(); -- 1.7.3.1
_______________________________________________ cmake-developers mailing list cmake-developers@cmake.org http://public.kitware.com/cgi-bin/mailman/listinfo/cmake-developers