From bb07bb62dfa28effc6a21a9014993664d3f726a5 Mon Sep 17 00:00:00 2001
From: Brian Bassett <bbassett@tibco.com>
Date: Fri, 27 Apr 2012 15:09:14 -0700
Subject: [PATCH 2/2] Correctly generate custom tool build entries for
 assembly files in Visual Studio projects (Bug #8170).

---
 Source/cmLocalVisualStudio7Generator.cxx   |  130 +++++++++++++++++++++++++++-
 Source/cmLocalVisualStudio7Generator.h     |    1 +
 Source/cmVisualStudio10TargetGenerator.cxx |    1 +
 3 files changed, 131 insertions(+), 1 deletions(-)

diff --git a/Source/cmLocalVisualStudio7Generator.cxx b/Source/cmLocalVisualStudio7Generator.cxx
index 9faf46d..d062a6c 100644
--- a/Source/cmLocalVisualStudio7Generator.cxx
+++ b/Source/cmLocalVisualStudio7Generator.cxx
@@ -92,6 +92,7 @@ void cmLocalVisualStudio7Generator::AddHelperCommands()
 
 
   this->FixGlobalTargets();
+  this->FixObjectCommands(lang);
 }
 
 void cmLocalVisualStudio7Generator::Generate()
@@ -158,6 +159,131 @@ void cmLocalVisualStudio7Generator::FixGlobalTargets()
     }
 }
 
+void cmLocalVisualStudio7Generator::FixObjectCommands(std::set<cmStdString> const& lang)
+{
+  cmTargets &tgts = this->Makefile->GetTargets();
+  for(cmTargets::iterator l = tgts.begin(); l != tgts.end(); l++)
+    {
+    cmTarget& target = l->second;
+    switch(target.GetType())
+      { 
+      case cmTarget::STATIC_LIBRARY:
+      case cmTarget::SHARED_LIBRARY:
+      case cmTarget::MODULE_LIBRARY:
+      case cmTarget::EXECUTABLE: 
+        {
+        const std::vector<cmSourceFile *> &sourceFiles = target.GetSourceFiles();
+        for(std::vector<cmSourceFile *>::const_iterator sf = sourceFiles.begin(); sf != sourceFiles.end(); sf++)
+          {
+          // If we already have a custom command, don't add a generalized one.
+          if((*sf)->GetCustomCommand() != 0)
+            continue;
+
+          // Check to see if the language of this file is already handled by the generator.
+          const char *sflang = (*sf)->GetLanguage();
+          if(sflang == 0)
+            continue;
+          bool found_sflang = false;
+          for(std::set<cmStdString>::const_iterator li = lang.begin(); li != lang.end(); li++)
+            {
+            if((*li) == sflang)
+              {
+              found_sflang = true;
+              break;
+              }
+            }
+
+          // Since it is not handled, we need to add a custom command based on the CMAKE_${sflang}_COMPILE_OBJECT variable
+          if(!found_sflang)
+            {
+            // Determine the object file
+            std::string outfile = this->Makefile->GetStartOutputDirectory();
+            outfile += "/";
+            outfile += this->GetTargetDirectory(target);
+            outfile += "/$<CONFIGURATION>/";
+            std::string outfilebase = (*sf)->GetLocation().GetName();
+            std::string::size_type outext = outfilebase.find_last_of('.');
+            if (std::string::npos != outext)
+              outfilebase.erase(outext);
+            std::string cmake_objext_var = "CMAKE_";
+            cmake_objext_var += sflang;
+            cmake_objext_var += "_OUTPUT_EXTENSION";
+            outfilebase += this->Makefile->GetRequiredDefinition(cmake_objext_var.c_str());
+            outfile += outfilebase;
+            std::vector<std::string> outfiles;
+            outfiles.push_back(outfile);
+
+            // Determine the commandline
+            cmCustomCommandLines lines;
+            cmCustomCommandLine line;
+            // Fetch the command line from the variable CMAKE_${sflang}_COMPILE_OBJECT
+            std::string cmake_compile_var = "CMAKE_";
+            cmake_compile_var += sflang;
+            cmake_compile_var += "_COMPILE_OBJECT";
+            std::string cmake_compile_line = this->Makefile->GetRequiredDefinition(cmake_compile_var.c_str());
+            // Now substitute variables of interest
+            RuleVariables vars;
+            vars.RuleLauncher = cmake_compile_var.c_str();
+            vars.CMTarget = &target;
+            // Object file (<OBJECT>)
+            if (outfile.find(" ") != std::string::npos)
+              outfile = "\"" + outfile + "\"";
+            vars.Object = outfile.c_str();
+            // Source file (<SOURCE>)
+            std::string sfpath = (*sf)->GetFullPath();
+            if (sfpath.find(" ") != std::string::npos)
+              sfpath = "\"" + sfpath + "\"";
+            vars.Source = sfpath.c_str();
+            // Flags (<FLAGS>)
+            std::string cmake_flags_var = "CMAKE_";
+            cmake_flags_var += sflang;
+            cmake_flags_var += "_FLAGS";
+            std::string cmake_flags;
+            // global language flags (CMAKE_${sflang}_FLAGS)
+            if(this->Makefile->IsDefinitionSet(cmake_flags_var.c_str()))
+              {
+              cmake_flags += this->Makefile->GetRequiredDefinition(cmake_flags_var.c_str());
+              cmake_flags += " ";
+              }
+            // config specific language flags (CMAKE_${sflang}_FLAGS_${config})
+            cmake_flags += "$<CONFIG_SPECIFIC:";
+            cmake_flags += cmake_flags_var;
+            cmake_flags += "> ";
+            // source file specific flags (COMPILE_FLAGS)
+            if(const char *cflags = (*sf)->GetProperty("COMPILE_FLAGS"))
+              {
+              cmake_flags += cflags;
+              cmake_flags += " ";
+              }
+            vars.Flags = cmake_flags.c_str();
+            this->ExpandRuleVariables(cmake_compile_line, vars);
+            // Now split up the command for insertion into the cmCustomCommandLine object
+            cmSystemTools::ParseWindowsCommandLine(cmake_compile_line.c_str(), line);
+            lines.push_back(line);
+
+            // Set the comment
+            std::string comment = "Building ";
+            comment += sflang;
+            comment += " object ";
+            comment += outfilebase;
+            comment += "...";
+
+            // Set the working directory
+            std::string workingdir;
+
+            // Build the command object and store it in the source file
+            cmCustomCommand *cmd = new cmCustomCommand(this->Makefile, outfiles, (*sf)->GetDepends(), lines, comment.c_str(), workingdir.c_str());
+            (*sf)->SetCustomCommand(cmd);
+            }
+          }
+        }
+        break; 
+      default:
+        break;
+      }
+    }
+}
+
 // TODO
 // for CommandLine= need to repleace quotes with &quot
 // write out configurations
@@ -1828,7 +1954,9 @@ WriteCustomRule(std::ostream& fout,
           o != command.GetOutputs().end(); 
           ++o)
         {
-        fout << sep << this->ConvertToXMLOutputPathSingle(o->c_str());
+        std::string ostr = *o;
+        cmSystemTools::ReplaceString(ostr, "$<CONFIGURATION>", i->c_str());
+        fout << sep << this->ConvertToXMLOutputPathSingle(ostr.c_str());
         sep = ";";
         }
       }
diff --git a/Source/cmLocalVisualStudio7Generator.h b/Source/cmLocalVisualStudio7Generator.h
index 9aa408e..c4a07ba 100644
--- a/Source/cmLocalVisualStudio7Generator.h
+++ b/Source/cmLocalVisualStudio7Generator.h
@@ -73,6 +73,7 @@ private:
   std::string GetBuildTypeLinkerFlags(std::string rootLinkerFlags,
                                       const char* configName);
   void FixGlobalTargets();
+  void FixObjectCommands(std::set<cmStdString> const& lang);
   void WriteProjectFiles();
   void WriteVCProjHeader(std::ostream& fout, const char *libName,
                          cmTarget &tgt, std::vector<cmSourceGroup> &sgs);
diff --git a/Source/cmVisualStudio10TargetGenerator.cxx b/Source/cmVisualStudio10TargetGenerator.cxx
index 6caaad1..167091a 100644
--- a/Source/cmVisualStudio10TargetGenerator.cxx
+++ b/Source/cmVisualStudio10TargetGenerator.cxx
@@ -532,6 +532,7 @@ cmVisualStudio10TargetGenerator::WriteCustomRule(cmSourceFile* source,
       {
       std::string out = *o;
       this->ConvertToWindowsSlash(out);
+      cmSystemTools::ReplaceString(out, "$<CONFIGURATION>", i->c_str());
       (*this->BuildFileStream ) << sep << out;
       sep = ";";
       }
-- 
1.7.6.msysgit.0

