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

Reply via email to