浏览代码

Merge branch 'master' of git://public.kitware.com/cmake into 12128_FindProtobuf_module_behavior_under_Windows_is_annoying

Philip Lowman 14 年之前
父节点
当前提交
162f3fb413
共有 37 个文件被更改,包括 628 次插入168 次删除
  1. 2 1
      Modules/CMakeDetermineFortranCompiler.cmake
  2. 5 2
      Modules/CMakeDetermineSystem.cmake
  3. 2 0
      Modules/CMakeFortranCompilerId.F.in
  4. 6 0
      Modules/CMakeGenericSystem.cmake
  5. 5 3
      Modules/CMakeParseImplicitLinkInfo.cmake
  6. 3 3
      Modules/CPackRPM.cmake
  7. 8 0
      Modules/Compiler/Absoft-Fortran.cmake
  8. 1 0
      Modules/Platform/Darwin-Absoft-Fortran.cmake
  9. 1 0
      Modules/Platform/Linux-Absoft-Fortran.cmake
  10. 27 0
      Source/CPack/cmCPackOSXX11Generator.cxx
  11. 1 1
      Source/cmDocumentVariables.cxx
  12. 11 4
      Source/cmExtraEclipseCDT4Generator.cxx
  13. 2 1
      Source/cmExtraEclipseCDT4Generator.h
  14. 114 91
      Source/cmGlobalUnixMakefileGenerator3.cxx
  15. 6 2
      Source/cmGlobalUnixMakefileGenerator3.h
  16. 7 3
      Source/cmLocalVisualStudio7Generator.cxx
  17. 88 45
      Source/cmMakefileTargetGenerator.cxx
  18. 6 0
      Source/cmMakefileTargetGenerator.h
  19. 11 2
      Source/cmOutputRequiredFilesCommand.h
  20. 3 3
      Source/cmStringCommand.cxx
  21. 86 0
      Source/cmSystemTools.cxx
  22. 5 0
      Source/cmSystemTools.h
  23. 5 5
      Source/cmVisualStudio10TargetGenerator.cxx
  24. 1 0
      Source/kwsys/EncodeExecutable.c
  25. 1 1
      Source/kwsys/kwsysDateStamp.cmake
  26. 5 0
      Tests/CMakeLib/CMakeLists.txt
  27. 141 0
      Tests/CMakeLib/run_compile_commands.cxx
  28. 12 0
      Tests/CMakeLists.txt
  29. 15 0
      Tests/CMakeTests/ImplicitLinkInfoTest.cmake.in
  30. 16 0
      Tests/CompileCommandOutput/CMakeLists.txt
  31. 9 0
      Tests/CompileCommandOutput/compile_command_output.cxx
  32. 1 0
      Tests/CompileCommandOutput/file with spaces.cxx
  33. 3 0
      Tests/CompileCommandOutput/file_with_underscores.cxx
  34. 1 0
      Tests/CompileCommandOutput/file_with_underscores.h
  35. 3 0
      Tests/CompileCommandOutput/relative.cxx
  36. 11 0
      Tests/CompileCommandOutput/relative.h
  37. 4 1
      Tests/Fortran/CMakeLists.txt

+ 2 - 1
Modules/CMakeDetermineFortranCompiler.cmake

@@ -64,7 +64,7 @@ IF(NOT CMAKE_Fortran_COMPILER)
     #  then 77 or older compilers, gnu is always last in the group,
     #  so if you paid for a compiler it is picked by default.
     SET(CMAKE_Fortran_COMPILER_LIST
-      ifort ifc efc f95 pathf2003 pathf95 pgf95 lf95 xlf95 fort
+      ifort ifc af95 af90 efc f95 pathf2003 pathf95 pgf95 lf95 xlf95 fort
       gfortran gfortran-4 g95 f90 pathf90 pgf90 xlf90 epcf90 fort77
       frt pgf77 xlf fl32 af77 g77 f77
       )
@@ -72,6 +72,7 @@ IF(NOT CMAKE_Fortran_COMPILER)
     # Vendor-specific compiler names.
     SET(_Fortran_COMPILER_NAMES_GNU       gfortran gfortran-4 g95 g77)
     SET(_Fortran_COMPILER_NAMES_Intel     ifort ifc efc)
+    SET(_Fortran_COMPILER_NAMES_Absoft    af95 af90 af77)
     SET(_Fortran_COMPILER_NAMES_PGI       pgf95 pgf90 pgf77)
     SET(_Fortran_COMPILER_NAMES_PathScale pathf2003 pathf95 pathf90)
     SET(_Fortran_COMPILER_NAMES_XL        xlf)

+ 5 - 2
Modules/CMakeDetermineSystem.cmake

@@ -50,14 +50,17 @@ IF(CMAKE_HOST_UNIX)
     IF(CMAKE_HOST_SYSTEM_NAME MATCHES "Linux|CYGWIN.*")
       EXEC_PROGRAM(uname ARGS -m OUTPUT_VARIABLE CMAKE_HOST_SYSTEM_PROCESSOR
         RETURN_VALUE val)
-    ELSE(CMAKE_HOST_SYSTEM_NAME MATCHES "Linux|CYGWIN.*")
+    ELSEIF(CMAKE_HOST_SYSTEM_NAME MATCHES "OpenBSD")
+      EXEC_PROGRAM(arch ARGS -s OUTPUT_VARIABLE CMAKE_HOST_SYSTEM_PROCESSOR
+        RETURN_VALUE val)
+    ELSE()
       EXEC_PROGRAM(uname ARGS -p OUTPUT_VARIABLE CMAKE_HOST_SYSTEM_PROCESSOR
         RETURN_VALUE val)
       IF("${val}" GREATER 0)
         EXEC_PROGRAM(uname ARGS -m OUTPUT_VARIABLE CMAKE_HOST_SYSTEM_PROCESSOR
           RETURN_VALUE val)
       ENDIF("${val}" GREATER 0)
-    ENDIF(CMAKE_HOST_SYSTEM_NAME MATCHES "Linux|CYGWIN.*")
+    ENDIF()
     # check the return of the last uname -m or -p 
     IF("${val}" GREATER 0)
         SET(CMAKE_HOST_SYSTEM_PROCESSOR "unknown")

+ 2 - 0
Modules/CMakeFortranCompilerId.F.in

@@ -12,6 +12,8 @@
         PRINT *, 'INFO:compiler[G95]'
 #elif defined(__PATHSCALE__)
         PRINT *, 'INFO:compiler[PathScale]'
+#elif defined(__ABSOFT__)
+        PRINT *, 'INFO:compiler[Absoft]'
 #elif defined(__GNUC__)
         PRINT *, 'INFO:compiler[GNU]'
 #elif defined(__IBMC__)

+ 6 - 0
Modules/CMakeGenericSystem.cmake

@@ -50,6 +50,12 @@ IF(CMAKE_GENERATOR MATCHES "Makefiles")
   IF(DEFINED CMAKE_RULE_MESSAGES)
     SET_PROPERTY(GLOBAL PROPERTY RULE_MESSAGES ${CMAKE_RULE_MESSAGES})
   ENDIF(DEFINED CMAKE_RULE_MESSAGES)
+  IF(CMAKE_GENERATOR MATCHES "Unix Makefiles")
+    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 "Unix Makefiles")
 ENDIF(CMAKE_GENERATOR MATCHES "Makefiles")
 
 

+ 5 - 3
Modules/CMakeParseImplicitLinkInfo.cmake

@@ -29,11 +29,13 @@ function(CMAKE_PARSE_IMPLICIT_LINK_INFO text lib_var dir_var log_var obj_regex)
   # Construct a regex to match linker lines.  It must match both the
   # whole line and just the command (argv[0]).
   set(linker_regex "^( *|.*[/\\])(${linker}|ld|collect2)[^/\\]*( |$)")
+  set(linker_exclude_regex "collect2 version ")
   set(log "${log}  link line regex: [${linker_regex}]\n")
   string(REGEX REPLACE "\r?\n" ";" output_lines "${text}")
   foreach(line IN LISTS output_lines)
     set(cmd)
-    if("${line}" MATCHES "${linker_regex}")
+    if("${line}" MATCHES "${linker_regex}" AND
+        NOT "${line}" MATCHES "${linker_exclude_regex}")
       if(UNIX)
         separate_arguments(args UNIX_COMMAND "${line}")
       else()
@@ -64,8 +66,8 @@ function(CMAKE_PARSE_IMPLICIT_LINK_INFO text lib_var dir_var log_var obj_regex)
           # Object file full path.
           list(APPEND implicit_libs_tmp ${arg})
           set(log "${log}    arg [${arg}] ==> obj [${arg}]\n")
-        elseif("${arg}" MATCHES "^-Y(P,)?")
-          # Sun search path.
+        elseif("${arg}" MATCHES "^-Y(P,)?[^0-9]")
+          # Sun search path ([^0-9] avoids conflict with Mac -Y<num>).
           string(REGEX REPLACE "^-Y(P,)?" "" dirs "${arg}")
           string(REPLACE ":" ";" dirs "${dirs}")
           list(APPEND implicit_dirs_tmp ${dirs})

+ 3 - 3
Modules/CPackRPM.cmake

@@ -489,9 +489,9 @@ ENDIF(CPACK_RPM_PACKAGE_COMPONENT)
 # file name by enclosing it between double quotes (thus the sed)
 # Then we must authorize any man pages extension (adding * at the end)
 # because rpmbuild may automatically compress those files
-EXECUTE_PROCESS(COMMAND find -type f -o -type l
-                COMMAND sed {s:.*/man.*/.*:&*:}
-                COMMAND sed {s/\\.\\\(.*\\\)/\"\\1\"/}
+EXECUTE_PROCESS(COMMAND find . -type f -o -type l
+                COMMAND sed s:.*/man.*/.*:&*:
+                COMMAND sed s/\\.\\\(.*\\\)/\"\\1\"/
                 WORKING_DIRECTORY "${WDIR}"
                 OUTPUT_VARIABLE CPACK_RPM_INSTALL_FILES)
 

+ 8 - 0
Modules/Compiler/Absoft-Fortran.cmake

@@ -0,0 +1,8 @@
+SET(CMAKE_Fortran_FLAGS_INIT "")
+SET(CMAKE_Fortran_FLAGS_DEBUG_INIT "-g")
+SET(CMAKE_Fortran_FLAGS_MINSIZEREL_INIT "")
+SET(CMAKE_Fortran_FLAGS_RELEASE_INIT "-O3")
+SET(CMAKE_Fortran_FLAGS_RELWITHDEBINFO_INIT "-O2 -g")
+SET(CMAKE_Fortran_MODDIR_FLAG "-YMOD_OUT_DIR=")
+SET(CMAKE_Fortran_MODPATH_FLAG "-p")
+SET(CMAKE_Fortran_VERBOSE_FLAG "-v")

+ 1 - 0
Modules/Platform/Darwin-Absoft-Fortran.cmake

@@ -0,0 +1 @@
+set(CMAKE_Fortran_VERBOSE_FLAG "-X -v") # Runs gcc under the hood.

+ 1 - 0
Modules/Platform/Linux-Absoft-Fortran.cmake

@@ -0,0 +1 @@
+set(CMAKE_Fortran_VERBOSE_FLAG "-X -v") # Runs gcc under the hood.

+ 27 - 0
Source/CPack/cmCPackOSXX11Generator.cxx

@@ -21,6 +21,7 @@
 
 #include <cmsys/SystemTools.hxx>
 #include <cmsys/Glob.hxx>
+#include <sys/stat.h>
 
 //----------------------------------------------------------------------
 cmCPackOSXX11Generator::cmCPackOSXX11Generator()
@@ -135,6 +136,32 @@ int cmCPackOSXX11Generator::PackageFiles()
     return 0;
     }
 
+  // Two of the files need to have execute permission, so ensure they do:
+  std::string runTimeScript = dir;
+  runTimeScript += "/";
+  runTimeScript += "RuntimeScript";
+
+  std::string appScriptName = appdir;
+  appScriptName += "/";
+  appScriptName += this->GetOption("CPACK_PACKAGE_FILE_NAME");
+
+  mode_t mode;
+  if (cmsys::SystemTools::GetPermissions(runTimeScript.c_str(), mode))
+    {
+    mode |= (S_IXUSR | S_IXGRP | S_IXOTH);
+    cmsys::SystemTools::SetPermissions(runTimeScript.c_str(), mode);
+    cmCPackLogger(cmCPackLog::LOG_OUTPUT, "Setting: " << runTimeScript
+      << " to permission: " << mode << std::endl);
+    }
+
+  if (cmsys::SystemTools::GetPermissions(appScriptName.c_str(), mode))
+    {
+    mode |= (S_IXUSR | S_IXGRP | S_IXOTH);
+    cmsys::SystemTools::SetPermissions(appScriptName.c_str(), mode);
+    cmCPackLogger(cmCPackLog::LOG_OUTPUT,  "Setting: " << appScriptName
+      << " to permission: " << mode << std::endl);
+    }
+
   std::string output;
   std::string tmpFile = this->GetOption("CPACK_TOPLEVEL_DIRECTORY");
   tmpFile += "/hdiutilOutput.log";

+ 1 - 1
Source/cmDocumentVariables.cxx

@@ -546,7 +546,7 @@ void cmDocumentVariables::DefineVariables(cmake* cm)
      "make based generators. If this variable is supported, "
      "then CMake will also provide initial values for the "
      "variables with the name "
-     " CMAKE_C_FLAGS_[Debug|Release|RelWithDebInfo|MinSizeRel]."
+     " CMAKE_C_FLAGS_[DEBUG|RELEASE|RELWITHDEBINFO|MINSIZEREL]."
      " For example, if CMAKE_BUILD_TYPE is Debug, then "
      "CMAKE_C_FLAGS_DEBUG will be added to the CMAKE_C_FLAGS.",false,
      "Variables That Change Behavior");

+ 11 - 4
Source/cmExtraEclipseCDT4Generator.cxx

@@ -403,7 +403,7 @@ void cmExtraEclipseCDT4Generator::CreateProjectFile()
   // for each sub project create a linked resource to the source dir
   // - only if it is an out-of-source build
   this->AppendLinkedResource(fout, "[Subprojects]",
-                             "virtual:/virtual");
+                             "virtual:/virtual", true);
 
   for (std::map<cmStdString, std::vector<cmLocalGenerator*> >::const_iterator
        it = this->GlobalGenerator->GetProjectMap().begin();
@@ -1082,17 +1082,24 @@ void cmExtraEclipseCDT4Generator
 void cmExtraEclipseCDT4Generator
 ::AppendLinkedResource (cmGeneratedFileStream& fout,
                         const std::string&     name,
-                        const std::string&     path)
+                        const std::string&     path,
+                        bool isVirtualFolder)
 {
+  const char* locationTag = "location";
+  if (isVirtualFolder) // ... and not a linked folder
+    {
+    locationTag = "locationURI";
+    }
+
   fout <<
     "\t\t<link>\n"
     "\t\t\t<name>"
     << cmExtraEclipseCDT4Generator::EscapeForXML(name)
     << "</name>\n"
     "\t\t\t<type>2</type>\n"
-    "\t\t\t<locationURI>"
+    "\t\t\t<" << locationTag << ">"
     << cmExtraEclipseCDT4Generator::EscapeForXML(path)
-    << "</locationURI>\n"
+    << "</" << locationTag << ">\n"
     "\t\t</link>\n"
     ;
 }

+ 2 - 1
Source/cmExtraEclipseCDT4Generator.h

@@ -87,7 +87,8 @@ private:
 
   static void AppendLinkedResource (cmGeneratedFileStream& fout,
                                     const std::string&     name,
-                                    const std::string&     path);
+                                    const std::string&     path,
+                                    bool isVirtualFolder = false);
 
   bool AppendOutLinkedResource(cmGeneratedFileStream& fout,
                                const std::string&     defname,

+ 114 - 91
Source/cmGlobalUnixMakefileGenerator3.cxx

@@ -24,13 +24,13 @@ cmGlobalUnixMakefileGenerator3::cmGlobalUnixMakefileGenerator3()
   this->ForceUnixPaths = true;
   this->FindMakeProgramFile = "CMakeUnixFindMake.cmake";
   this->ToolSupportsColor = true;
-  this->NoRuleMessages = false;
 
 #if defined(_WIN32) || defined(__VMS)
   this->UseLinkScript = false;
 #else
   this->UseLinkScript = true;
 #endif
+  this->CommandDatabase = NULL;
 }
 
 void cmGlobalUnixMakefileGenerator3
@@ -139,56 +139,87 @@ void 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
   this->cmGlobalGenerator::Generate();
 
-  cmake* cm = this->GetCMakeInstance();
-  if(const char* ruleStatus = cm->GetProperty("RULE_MESSAGES"))
+  // initialize progress
+  unsigned long total = 0;
+  for(ProgressMapType::const_iterator pmi = this->ProgressMap.begin();
+      pmi != this->ProgressMap.end(); ++pmi)
     {
-    this->NoRuleMessages = cmSystemTools::IsOff(ruleStatus);
+    total += pmi->second.NumberOfActions;
     }
 
-  if(!this->NoRuleMessages)
+  // write each target's progress.make this loop is done twice. Bascially the
+  // Generate pass counts all the actions, the first loop below determines
+  // how many actions have progress updates for each target and writes to
+  // corrrect variable values for everything except the all targets. The
+  // second loop actually writes out correct values for the all targets as
+  // well. This is because the all targets require more information that is
+  // computed in the first loop.
+  unsigned long current = 0;
+  for(ProgressMapType::iterator pmi = this->ProgressMap.begin();
+      pmi != this->ProgressMap.end(); ++pmi)
     {
-    // initialize progress
-    unsigned long total = 0;
-    for(ProgressMapType::const_iterator pmi = this->ProgressMap.begin();
-        pmi != this->ProgressMap.end(); ++pmi)
-      {
-      total += pmi->second.NumberOfActions;
-      }
-
-    // write each target's progress.make this loop is done twice. Bascially the
-    // Generate pass counts all the actions, the first loop below determines
-    // how many actions have progress updates for each target and writes to
-    // corrrect variable values for everything except the all targets. The
-    // second loop actually writes out correct values for the all targets as
-    // well. This is because the all targets require more information that is
-    // computed in the first loop.
-    unsigned long current = 0;
-    for(ProgressMapType::iterator pmi = this->ProgressMap.begin();
-        pmi != this->ProgressMap.end(); ++pmi)
-      {
-      pmi->second.WriteProgressVariables(total, current);
-      }
-    for(unsigned int i = 0; i < this->LocalGenerators.size(); ++i)
-      {
-      cmLocalUnixMakefileGenerator3 *lg =
-        static_cast<cmLocalUnixMakefileGenerator3 *>(this->LocalGenerators[i]);
-      std::string markFileName = lg->GetMakefile()->GetStartOutputDirectory();
-      markFileName += "/";
-      markFileName += cmake::GetCMakeFilesDirectory();
-      markFileName += "/progress.marks";
-      cmGeneratedFileStream markFile(markFileName.c_str());
-      markFile << this->CountProgressMarksInAll(lg) << "\n";
-      }
+    pmi->second.WriteProgressVariables(total, current);
+    }
+  for(unsigned int i = 0; i < this->LocalGenerators.size(); ++i)
+    {
+    cmLocalUnixMakefileGenerator3 *lg =
+      static_cast<cmLocalUnixMakefileGenerator3 *>(this->LocalGenerators[i]);
+    std::string markFileName = lg->GetMakefile()->GetStartOutputDirectory();
+    markFileName += "/";
+    markFileName += cmake::GetCMakeFilesDirectory();
+    markFileName += "/progress.marks";
+    cmGeneratedFileStream markFile(markFileName.c_str());
+    markFile << this->CountProgressMarksInAll(lg) << "\n";
     }
 
   // 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())
+      + "/compile_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()
@@ -747,34 +778,30 @@ cmGlobalUnixMakefileGenerator3
       // Write the rule.
       localName += "/all";
       depends.clear();
-      std::string progressDir;
 
-      if(!this->NoRuleMessages)
+      std::string progressDir =
+        lg->GetMakefile()->GetHomeOutputDirectory();
+      progressDir += cmake::GetCMakeFilesDirectory();
         {
-        progressDir =
-          lg->GetMakefile()->GetHomeOutputDirectory();
-        progressDir += cmake::GetCMakeFilesDirectory();
+        cmOStringStream progCmd;
+        progCmd << "$(CMAKE_COMMAND) -E cmake_progress_report ";
+        // all target counts
+        progCmd << lg->Convert(progressDir.c_str(),
+                                cmLocalGenerator::FULL,
+                                cmLocalGenerator::SHELL);
+        progCmd << " ";
+        std::vector<unsigned long>& progFiles =
+          this->ProgressMap[&t->second].Marks;
+        for (std::vector<unsigned long>::iterator i = progFiles.begin();
+              i != progFiles.end(); ++i)
           {
-          cmOStringStream progCmd;
-          progCmd << "$(CMAKE_COMMAND) -E cmake_progress_report ";
-          // all target counts
-          progCmd << lg->Convert(progressDir.c_str(),
-                                  cmLocalGenerator::FULL,
-                                  cmLocalGenerator::SHELL);
-          progCmd << " ";
-          std::vector<unsigned long>& progFiles =
-            this->ProgressMap[&t->second].Marks;
-          for (std::vector<unsigned long>::iterator i = progFiles.begin();
-                i != progFiles.end(); ++i)
-            {
-            progCmd << " " << *i;
-            }
-          commands.push_back(progCmd.str());
+          progCmd << " " << *i;
           }
-        progressDir = "Built target ";
-        progressDir += t->first;
-        lg->AppendEcho(commands,progressDir.c_str());
+        commands.push_back(progCmd.str());
         }
+      progressDir = "Built target ";
+      progressDir += t->first;
+      lg->AppendEcho(commands,progressDir.c_str());
 
       this->AppendGlobalTargetDepends(depends,t->second);
       lg->WriteMakeRule(ruleFileStream, "All Build rule for target.",
@@ -790,42 +817,38 @@ cmGlobalUnixMakefileGenerator3
                           "all", depends, commands, true);
         }
 
-      if(!this->NoRuleMessages)
-        {
-        // Write the rule.
-        commands.clear();
-        progressDir = lg->GetMakefile()->GetHomeOutputDirectory();
-        progressDir += cmake::GetCMakeFilesDirectory();
+      // Write the rule.
+      commands.clear();
+      progressDir = lg->GetMakefile()->GetHomeOutputDirectory();
+      progressDir += cmake::GetCMakeFilesDirectory();
 
-        {
-        // TODO: Convert the total progress count to a make variable.
-        cmOStringStream progCmd;
-        progCmd << "$(CMAKE_COMMAND) -E cmake_progress_start ";
-        // # in target
-        progCmd << lg->Convert(progressDir.c_str(),
-                                cmLocalGenerator::FULL,
-                                cmLocalGenerator::SHELL);
-        //
-        std::set<cmTarget *> emitted;
-        progCmd << " "
-                << this->CountProgressMarksInTarget(&t->second, emitted);
-        commands.push_back(progCmd.str());
-        }
-        }
+      {
+      // TODO: Convert the total progress count to a make variable.
+      cmOStringStream progCmd;
+      progCmd << "$(CMAKE_COMMAND) -E cmake_progress_start ";
+      // # in target
+      progCmd << lg->Convert(progressDir.c_str(),
+                              cmLocalGenerator::FULL,
+                              cmLocalGenerator::SHELL);
+      //
+      std::set<cmTarget *> emitted;
+      progCmd << " "
+              << this->CountProgressMarksInTarget(&t->second, emitted);
+      commands.push_back(progCmd.str());
+      }
       std::string tmp = cmake::GetCMakeFilesDirectoryPostSlash();
       tmp += "Makefile2";
       commands.push_back(lg->GetRecursiveMakeCall
                           (tmp.c_str(),localName.c_str()));
-      if(!this->NoRuleMessages)
-        {
-        cmOStringStream progCmd;
-        progCmd << "$(CMAKE_COMMAND) -E cmake_progress_start "; // # 0
-        progCmd << lg->Convert(progressDir.c_str(),
-                                cmLocalGenerator::FULL,
-                                cmLocalGenerator::SHELL);
-        progCmd << " 0";
-        commands.push_back(progCmd.str());
-        }
+      {
+      cmOStringStream progCmd;
+      progCmd << "$(CMAKE_COMMAND) -E cmake_progress_start "; // # 0
+      progCmd << lg->Convert(progressDir.c_str(),
+                              cmLocalGenerator::FULL,
+                              cmLocalGenerator::SHELL);
+      progCmd << " 0";
+      commands.push_back(progCmd.str());
+      }
       depends.clear();
       depends.push_back("cmake_check_build_system");
       localName = lg->GetRelativeTargetDirectory(t->second);

+ 6 - 2
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();
@@ -159,8 +163,6 @@ protected:
   // in the rule to satisfy the make program.
   std::string EmptyRuleHackCommand;
 
-  bool NoRuleMessages;
-
   // Store per-target progress counters.
   struct TargetProgress
   {
@@ -178,6 +180,8 @@ protected:
   size_t CountProgressMarksInTarget(cmTarget* target,
                                     std::set<cmTarget*>& emitted);
   size_t CountProgressMarksInAll(cmLocalUnixMakefileGenerator3* lg);
+
+  cmGeneratedFileStream *CommandDatabase;
 };
 
 #endif

+ 7 - 3
Source/cmLocalVisualStudio7Generator.cxx

@@ -1770,10 +1770,14 @@ cmLocalVisualStudio7Generator
   vskey += "\\Packages\\" CM_INTEL_PLUGIN_GUID ";ProductVersion";
   cmSystemTools::ReadRegistryValue(vskey.c_str(), intelVersion,
                                    cmSystemTools::KeyWOW64_32);
-
-  // Version 10.1 actually uses 9.10 in project files!
-  if(intelVersion == "10.1")
+  if (intelVersion == "12.0")
+    {
+    // Version 12 actually uses 11.0 in project files!
+    intelVersion = "11.0" ;
+    }
+  else if(intelVersion == "10.1")
     {
+    // Version 10.1 actually uses 9.10 in project files!
     intelVersion = "9.10";
     }
 

+ 88 - 45
Source/cmMakefileTargetGenerator.cxx

@@ -249,51 +249,17 @@ void cmMakefileTargetGenerator::WriteCommonCodeRules()
 }
 
 //----------------------------------------------------------------------------
-void cmMakefileTargetGenerator::WriteTargetLanguageFlags()
+std::string cmMakefileTargetGenerator::GetFlags(const std::string &l)
 {
-  // write language flags for target
-  std::set<cmStdString> languages;
-  this->Target->GetLanguages(languages);
-    // put the compiler in the rules.make file so that if it changes
-  // things rebuild
-  for(std::set<cmStdString>::const_iterator l = languages.begin();
-      l != languages.end(); ++l)
-    {
-    cmStdString compiler = "CMAKE_";
-    compiler += *l;
-    compiler += "_COMPILER";
-    *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)
+  ByLanguageMap::iterator i = this->FlagsByLanguage.find(l);
+  if (i == this->FlagsByLanguage.end())
     {
-    const char *lang = l->c_str();
     std::string flags;
-    std::string defines;
+    const char *lang = l.c_str();
+
     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);
 
@@ -301,7 +267,7 @@ void cmMakefileTargetGenerator::WriteTargetLanguageFlags()
                                                lang, this->ConfigName);
 
     // Fortran-specific flags computed for this target.
-    if(*l == "Fortran")
+    if(l == "Fortran")
       {
       this->AddFortranFlags(flags);
       }
@@ -320,14 +286,73 @@ void cmMakefileTargetGenerator::WriteTargetLanguageFlags()
     this->LocalGenerator->
       AppendFlags(flags,this->GetFrameworkFlags().c_str());
 
-    *this->FlagFileStream << lang << "_FLAGS = " << flags << "\n\n";
-    *this->FlagFileStream << lang << "_DEFINES = " << defines << "\n\n";
+    ByLanguageMap::value_type entry(l, flags);
+    i = this->FlagsByLanguage.insert(entry).first;
+    }
+  return i->second;
+}
+
+std::string cmMakefileTargetGenerator::GetDefines(const std::string &l)
+{
+  ByLanguageMap::iterator i = this->DefinesByLanguage.find(l);
+  if (i == this->DefinesByLanguage.end())
+    {
+    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);
+
+    ByLanguageMap::value_type entry(l, defines);
+    i = this->DefinesByLanguage.insert(entry).first;
+    }
+  return i->second;
+}
+
+void cmMakefileTargetGenerator::WriteTargetLanguageFlags()
+{
+  // write language flags for target
+  std::set<cmStdString> languages;
+  this->Target->GetLanguages(languages);
+    // put the compiler in the rules.make file so that if it changes
+  // things rebuild
+  for(std::set<cmStdString>::const_iterator l = languages.begin();
+      l != languages.end(); ++l)
+    {
+    cmStdString compiler = "CMAKE_";
+    compiler += *l;
+    compiler += "_COMPILER";
+    *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)
+    {
+    *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";
@@ -641,6 +666,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_";
@@ -651,6 +679,23 @@ cmMakefileTargetGenerator
   std::vector<std::string> compileCommands;
   cmSystemTools::ExpandListArgument(compileRule, compileCommands);
 
+  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);
+    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)
@@ -691,8 +736,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 &&

+ 6 - 0
Source/cmMakefileTargetGenerator.h

@@ -216,6 +216,12 @@ protected:
   std::string MacContentDirectory;
   std::set<cmStdString> MacContentFolders;
 
+  typedef std::map<cmStdString, cmStdString> ByLanguageMap;
+  std::string GetFlags(const std::string &l);
+  ByLanguageMap FlagsByLanguage;
+  std::string GetDefines(const std::string &l);
+  ByLanguageMap DefinesByLanguage;
+
   // Target-wide Fortran module output directory.
   bool FortranModuleDirectoryComputed;
   std::string FortranModuleDirectory;

+ 11 - 2
Source/cmOutputRequiredFilesCommand.h

@@ -47,8 +47,7 @@ public:
    */
   virtual const char* GetTerseDocumentation() 
     {
-    return 
-      "Output a list of required source files for a specified source file.";
+    return "Deprecated.  Approximate C preprocessor dependency scanning.";
     }
   
   /**
@@ -57,12 +56,22 @@ public:
   virtual const char* GetFullDocumentation()
     {
     return
+      "This command exists only because ancient CMake versions provided it.  "
+      "CMake handles preprocessor dependency scanning automatically using a "
+      "more advanced scanner.\n"
       "  output_required_files(srcfile outputfile)\n"
       "Outputs a list of all the source files that are required by the "
       "specified srcfile. This list is written into outputfile. This is "
       "similar to writing out the dependencies for srcfile except that it "
       "jumps from .h files into .cxx, .c and .cpp files if possible.";
     }
+
+  /** This command is kept for compatibility with older CMake versions. */
+  virtual bool IsDiscouraged()
+    {
+    return true;
+    }
+
   
   cmTypeMacro(cmOutputRequiredFilesCommand, cmCommand);
   void ListDependencies(cmDependInformation const *info,

+ 3 - 3
Source/cmStringCommand.cxx

@@ -770,7 +770,7 @@ bool cmStringCommand
 
   static bool seeded = false;
   bool force_seed = false;
-  int seed = (int) time(NULL);
+  unsigned int seed = 0;
   int length = 5;
   const char cmStringCommandDefaultAlphabet[] = "qwertyuiopasdfghjklzxcvbnm"
     "QWERTYUIOPASDFGHJKLZXCVBNM"
@@ -797,7 +797,7 @@ bool cmStringCommand
       else if ( args[i] == "RANDOM_SEED" )
         {
         ++i;
-        seed = atoi(args[i].c_str());
+        seed = static_cast<unsigned int>(atoi(args[i].c_str()));
         force_seed = true;
         }
       }
@@ -825,7 +825,7 @@ bool cmStringCommand
   if (!seeded || force_seed)
     {
     seeded = true;
-    srand(seed);
+    srand(force_seed? seed : cmSystemTools::RandomSeed());
     }
 
   const char* alphaPtr = alphabet.c_str();

+ 86 - 0
Source/cmSystemTools.cxx

@@ -9,6 +9,9 @@
   implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
   See the License for more information.
 ============================================================================*/
+#if defined(_MSC_VER) && _MSC_VER < 1300
+# define _WIN32_WINNT 0x0400 /* for wincrypt.h */
+#endif
 #include "cmSystemTools.h"   
 #include <ctype.h>
 #include <errno.h>
@@ -31,7 +34,9 @@
 
 #if defined(_WIN32)
 # include <windows.h>
+# include <wincrypt.h>
 #else
+# include <sys/time.h>
 # include <sys/types.h>
 # include <unistd.h>
 # include <utime.h>
@@ -440,6 +445,13 @@ public:
       args.push_back(*arg);
       }
     }
+  void Store(std::vector<cmStdString>& args) const
+    {
+    for(char** arg = this->ArgV; arg && *arg; ++arg)
+      {
+      args.push_back(*arg);
+      }
+    }
 };
 
 //----------------------------------------------------------------------------
@@ -451,6 +463,15 @@ void cmSystemTools::ParseUnixCommandLine(const char* command,
   argv.Store(args);
 }
 
+//----------------------------------------------------------------------------
+void cmSystemTools::ParseUnixCommandLine(const char* command,
+                                         std::vector<cmStdString>& args)
+{
+  // Invoke the underlying parser.
+  cmSystemToolsArgV argv = cmsysSystem_Parse_CommandForUnix(command, 0);
+  argv.Store(args);
+}
+
 std::string cmSystemTools::EscapeWindowsShellArgument(const char* arg,
                                                       int shell_flags)
 {
@@ -2232,6 +2253,71 @@ bool cmSystemTools::FileTimeSet(const char* fname, cmSystemToolsFileTime* t)
   return true;
 }
 
+//----------------------------------------------------------------------------
+#ifdef _WIN32
+# ifndef CRYPT_SILENT
+#  define CRYPT_SILENT 0x40 /* Not defined by VS 6 version of header.  */
+# endif
+static int WinCryptRandom(void* data, size_t size)
+{
+  int result = 0;
+  HCRYPTPROV hProvider = 0;
+  if(CryptAcquireContextW(&hProvider, 0, 0, PROV_RSA_FULL,
+                          CRYPT_VERIFYCONTEXT | CRYPT_SILENT))
+    {
+    result = CryptGenRandom(hProvider, (DWORD)size, (BYTE*)data)? 1:0;
+    CryptReleaseContext(hProvider, 0);
+    }
+  return result;
+}
+#endif
+
+//----------------------------------------------------------------------------
+unsigned int cmSystemTools::RandomSeed()
+{
+#if defined(_WIN32) && !defined(__CYGWIN__)
+  unsigned int seed = 0;
+
+  // Try using a real random source.
+  if(WinCryptRandom(&seed, sizeof(seed)))
+    {
+    return seed;
+    }
+
+  // Fall back to the time and pid.
+  FILETIME ft;
+  GetSystemTimeAsFileTime(&ft);
+  unsigned int t1 = static_cast<unsigned int>(ft.dwHighDateTime);
+  unsigned int t2 = static_cast<unsigned int>(ft.dwLowDateTime);
+  unsigned int pid = static_cast<unsigned int>(GetCurrentProcessId());
+  return t1 ^ t2 ^ pid;
+#else
+  union
+  {
+    unsigned int integer;
+    char bytes[sizeof(unsigned int)];
+  } seed;
+
+  // Try using a real random source.
+  std::ifstream fin("/dev/urandom");
+  if(fin && fin.read(seed.bytes, sizeof(seed)) &&
+     fin.gcount() == sizeof(seed))
+    {
+    return seed.integer;
+    }
+
+  // Fall back to the time and pid.
+  struct timeval t;
+  gettimeofday(&t, 0);
+  unsigned int pid = static_cast<unsigned int>(getpid());
+  unsigned int tv_sec = static_cast<unsigned int>(t.tv_sec);
+  unsigned int tv_usec = static_cast<unsigned int>(t.tv_usec);
+  // Since tv_usec never fills more than 11 bits we shift it to fill
+  // in the slow-changing high-order bits of tv_sec.
+  return tv_sec ^ (tv_usec << 21) ^ pid;
+#endif
+}
+
 //----------------------------------------------------------------------------
 static std::string cmSystemToolsExecutableDirectory;
 void cmSystemTools::FindExecutableDirectory(const char* argv0)

+ 5 - 0
Source/cmSystemTools.h

@@ -237,6 +237,8 @@ public:
   /** Parse arguments out of a unix command line string.  */
   static void ParseUnixCommandLine(const char* command,
                                    std::vector<std::string>& args);
+  static void ParseUnixCommandLine(const char* command,
+                                   std::vector<cmStdString>& args);
 
   /** Compute an escaped version of the given argument for use in a
       windows shell.  See kwsys/System.h.in for details.  */
@@ -402,6 +404,9 @@ public:
   static bool FileTimeGet(const char* fname, cmSystemToolsFileTime* t);
   static bool FileTimeSet(const char* fname, cmSystemToolsFileTime* t);
 
+  /** Random seed generation.  */
+  static unsigned int RandomSeed();
+
   /** Find the directory containing the running executable.  Save it
    in a global location to be queried by GetExecutableDirectory
    later.  */

+ 5 - 5
Source/cmVisualStudio10TargetGenerator.cxx

@@ -455,7 +455,11 @@ void cmVisualStudio10TargetGenerator::WriteGroups()
       {
       lang = "None";
       }
-    if(lang[0] == 'C')
+    if(header)
+      {
+      headers.push_back(sf);
+      }
+    else if(lang[0] == 'C')
       {
       clCompile.push_back(sf);
       }
@@ -467,10 +471,6 @@ void cmVisualStudio10TargetGenerator::WriteGroups()
       {
       customBuild.push_back(sf);
       }
-    else if(header)
-      {
-      headers.push_back(sf);
-      }
     else if(ext == "idl")
       {
       idls.push_back(sf);

+ 1 - 0
Source/kwsys/EncodeExecutable.c

@@ -41,6 +41,7 @@ int main(int argc, char* argv[])
   if(!ofp)
     {
     fprintf(stderr, "Cannot open output file: \"%s\"\n", argv[2]);
+    fclose(ifp);
     return 2;
     }
   

+ 1 - 1
Source/kwsys/kwsysDateStamp.cmake

@@ -18,4 +18,4 @@ SET(KWSYS_DATE_STAMP_YEAR  2011)
 SET(KWSYS_DATE_STAMP_MONTH 05)
 
 # KWSys version date day component.  Format is DD.
-SET(KWSYS_DATE_STAMP_DAY   01)
+SET(KWSYS_DATE_STAMP_DAY   25)

+ 5 - 0
Tests/CMakeLib/CMakeLists.txt

@@ -30,3 +30,8 @@ endif()
 foreach(test ${CMakeLib_TESTS})
   add_test(CMakeLib.${test} CMakeLibTests ${test})
 endforeach()
+
+if(TEST_CompileCommandOutput)
+  add_executable(runcompilecommands run_compile_commands.cxx)
+  target_link_libraries(runcompilecommands CMakeLib)
+endif()

+ 141 - 0
Tests/CMakeLib/run_compile_commands.cxx

@@ -0,0 +1,141 @@
+#include "cmSystemTools.h"
+
+class CompileCommandParser {
+public:
+  class CommandType: public std::map<cmStdString, cmStdString>
+  {
+  public:
+    cmStdString const& at(cmStdString const& k) const
+      {
+      const_iterator i = this->find(k);
+      if(i != this->end()) { return i->second; }
+      static cmStdString emptyString;
+      return emptyString;
+      }
+  };
+  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 = char(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<cmStdString> command;
+    cmSystemTools::ParseUnixCommandLine(it->at("command").c_str(), command);
+    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;
+}

+ 12 - 0
Tests/CMakeLists.txt

@@ -11,6 +11,7 @@ MACRO(ADD_TEST_MACRO NAME COMMAND)
     --build-generator ${CMAKE_TEST_GENERATOR}
     --build-makeprogram ${CMAKE_TEST_MAKEPROGRAM}
     --build-project ${proj}
+    ${${NAME}_EXTRA_OPTIONS}
     --test-command ${COMMAND} ${ARGN})
   LIST(APPEND TEST_BUILD_DIRS "${CMake_BINARY_DIR}/Tests/${dir}")
 ENDMACRO(ADD_TEST_MACRO)
@@ -39,6 +40,10 @@ CONFIGURE_FILE(${CMake_SOURCE_DIR}/Tests/EnforceConfig.cmake.in
 
 # Testing
 IF(BUILD_TESTING)
+  IF("${CMAKE_TEST_GENERATOR}" MATCHES "Unix Makefiles")
+    SET(TEST_CompileCommandOutput 1)
+  ENDIF()
+
   ADD_SUBDIRECTORY(CMakeLib)
 
   # Collect a list of all test build directories.
@@ -2031,6 +2036,13 @@ ${CMake_BINARY_DIR}/bin/cmake -DVERSION=master -P ${CMake_SOURCE_DIR}/Utilities/
     ENDIF()
     SET_TESTS_PROPERTIES(Contracts.${project} PROPERTIES TIMEOUT ${timeout})
   ENDFOREACH()
+
+  IF(TEST_CompileCommandOutput)
+    SET(CompileCommandOutput_EXTRA_OPTIONS
+      --build-options -DMAKE_SUPPORTS_SPACES=${MAKE_IS_GNU})
+    ADD_TEST_MACRO(CompileCommandOutput
+      "${CMake_BINARY_DIR}/Tests/CMakeLib/runcompilecommands")
+  ENDIF()
 ENDIF(BUILD_TESTING)
 
 SUBDIRS(CMakeTests)

+ 15 - 0
Tests/CMakeTests/ImplicitLinkInfoTest.cmake.in

@@ -84,6 +84,13 @@ set(linux64_nagfor_dirs "/usr/lib/gcc/x86_64-redhat-linux/4.4.5;/usr/lib64;/lib6
 set(linux64_nagfor_obj_regex "^/usr/local/NAG/lib")
 list(APPEND platforms linux64_nagfor)
 
+# absoft dummy.f -X -v
+set(linux64_absoft_text "collect2 version 4.4.5 (x86-64 Linux/ELF)
+/usr/bin/ld --build-id --eh-frame-hdr -m elf_x86_64 --hash-style=both -dynamic-linker /lib64/ld-linux-x86-64.so.2 /usr/lib/gcc/x86_64-linux-gnu/4.4.5/../../../../lib/crt1.o /usr/lib/gcc/x86_64-linux-gnu/4.4.5/../../../../lib/crti.o /usr/lib/gcc/x86_64-linux-gnu/4.4.5/crtbegin.o -L/opt/absoft11.1/lib64 -L/usr/lib/gcc/x86_64-linux-gnu/4.4.5 -L/usr/lib/gcc/x86_64-linux-gnu/4.4.5 -L/usr/lib/gcc/x86_64-linux-gnu/4.4.5/../../../../lib -L/lib/../lib -L/usr/lib/../lib -L/usr/lib/gcc/x86_64-linux-gnu/4.4.5/../../.. /tmp/E3Bii1/dummy.o -v -laf90math -lafio -lamisc -labsoftmain -laf77math -lm -lmv -lpthread -lgcc --as-needed -lgcc_s --no-as-needed -lc -lgcc --as-needed -lgcc_s --no-as-needed /usr/lib/gcc/x86_64-linux-gnu/4.4.5/crtend.o /usr/lib/gcc/x86_64-linux-gnu/4.4.5/../../../../lib/crtn.o")
+set(linux64_absoft_libs "af90math;afio;amisc;absoftmain;af77math;m;mv;pthread;c")
+set(linux64_absoft_dirs "/opt/absoft11.1/lib64;/usr/lib/gcc/x86_64-linux-gnu/4.4.5;/usr/lib;/lib")
+list(APPEND platforms linux64_absoft)
+
 # gcc dummy.c -v # in strange path
 set(linux64_test1_text "
 /this/might/match/as/a/linker/ld/but/it/is/not because the ld is not the last path component
@@ -125,6 +132,14 @@ set(mac_ppc_g++_libs "stdc++")
 set(mac_ppc_g++_dirs "/usr/lib/powerpc-apple-darwin10/4.2.1;/usr/lib/gcc/powerpc-apple-darwin10/4.2.1;/usr/lib")
 list(APPEND platforms mac_ppc_g++)
 
+# absoft dummy.f -X -v
+set(mac_absoft_text "collect2 version 4.2.1 (Apple Inc. build 5664) (i686 Darwin)
+/usr/libexec/gcc/i686-apple-darwin10/4.2.1/ld -dynamic -arch i386 -macosx_version_min 10.6.6 -weak_reference_mismatches non-weak -o a.out -lcrt1.10.6.o -L/Applications/Absoft11.1/lib -L/usr/lib/i686-apple-darwin10/4.2.1 -L/usr/lib/gcc/i686-apple-darwin10/4.2.1 -L/usr/lib/gcc/i686-apple-darwin10/4.2.1 -L/usr/lib/gcc/i686-apple-darwin10/4.2.1/../../../i686-apple-darwin10/4.2.1 -L/usr/lib/gcc/i686-apple-darwin10/4.2.1/../../.. /var/folders/04/04+Djjm8GZWBmuEdp2Gsw++++TM/-Tmp-//bTAoJc/dummy.o -v -Y 10 -laf90math -lafio -lamisc -labsoftmain -laf77math -lm -lmv -lSystem -lgcc -lSystem
+")
+set(mac_absoft_libs "af90math;afio;amisc;absoftmain;af77math;m;mv")
+set(mac_absoft_dirs "/Applications/Absoft11.1/lib;/usr/lib/i686-apple-darwin10/4.2.1;/usr/lib/gcc/i686-apple-darwin10/4.2.1;/usr/lib")
+list(APPEND platforms mac_absoft)
+
 #-----------------------------------------------------------------------------
 # Sun
 

+ 16 - 0
Tests/CompileCommandOutput/CMakeLists.txt

@@ -0,0 +1,16 @@
+# 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")
+IF(MAKE_SUPPORTS_SPACES)
+  SET(test1_srcs "file with spaces.cxx")
+ELSE()
+  SET(test1_srcs "file_with_underscores.cxx")
+ENDIF()
+ADD_LIBRARY(test1 STATIC ${test1_srcs})
+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)

+ 9 - 0
Tests/CompileCommandOutput/compile_command_output.cxx

@@ -0,0 +1,9 @@
+#include "file_with_underscores.h"
+#include "relative.h"
+
+int main (int argc, char** argv)
+{
+  file_with_underscores();
+  relative();
+  return 0;
+}

+ 1 - 0
Tests/CompileCommandOutput/file with spaces.cxx

@@ -0,0 +1 @@
+#include "file_with_underscores.cxx"

+ 3 - 0
Tests/CompileCommandOutput/file_with_underscores.cxx

@@ -0,0 +1,3 @@
+#include "file_with_underscores.h"
+
+void file_with_underscores() {}

+ 1 - 0
Tests/CompileCommandOutput/file_with_underscores.h

@@ -0,0 +1 @@
+void file_with_underscores();

+ 3 - 0
Tests/CompileCommandOutput/relative.cxx

@@ -0,0 +1,3 @@
+#include "relative.h"
+
+void relative() {}

+ 11 - 0
Tests/CompileCommandOutput/relative.h

@@ -0,0 +1,11 @@
+#if defined(_WIN32)
+# ifdef test2_EXPORTS
+#  define TEST2_EXPORT __declspec(dllexport)
+# else
+#  define TEST2_EXPORT __declspec(dllimport)
+# endif
+#else
+# define TEST2_EXPORT
+#endif
+
+TEST2_EXPORT void relative();

+ 4 - 1
Tests/Fortran/CMakeLists.txt

@@ -45,7 +45,7 @@ function(test_fortran_c_interface_module)
   FortranCInterface_VERIFY()
   FortranCInterface_VERIFY(CXX)
   if(CMAKE_Fortran_COMPILER_SUPPORTS_F90)
-    if(NOT CMAKE_Fortran_COMPILER_ID MATCHES "SunPro|MIPSpro|PathScale")
+    if(NOT CMAKE_Fortran_COMPILER_ID MATCHES "SunPro|MIPSpro|PathScale|Absoft")
       set(module_expected 1)
     endif()
     if(FortranCInterface_MODULE_FOUND OR module_expected)
@@ -119,6 +119,9 @@ if(("${CMAKE_Fortran_COMPILER_ID}" MATCHES "Intel")
     )
   set(COMPATABLE_COMPILERS TRUE)
 endif()
+if("${CMAKE_Fortran_COMPILER_ID}:${CMAKE_C_COMPILER_ID}" MATCHES "Absoft:GNU")
+  set(COMPATABLE_COMPILERS TRUE)
+endif()
 if(COMPATABLE_COMPILERS
     OR ("${CMAKE_Fortran_COMPILER_ID}" MATCHES "${CMAKE_C_COMPILER_ID}" ))
   test_fortran_c_interface_module()