CMake/Source/cmGlobalVisualStudio6Generator.cxx
Brad King 79a88c35f8 Refactor VS <= 7.1 utility-depends workaround
Commit 438a7e2f (Fix utility dependencies for static libraries in VS
generators, 2007-04-04) implemented utility-only dependencies between
linkable targets by introducing an intermediate non-linkable target.
We convert a dependency of the form

  foo -> bar

to the form

  foo -> bar_UTILITY -> bar

to prevent foo from including bar on its link line.  Previously we added
the extra "_UTILITY" targets explicitly among the project targets before
dependency analysis was performed.  Now we generate them separately at
the last moment so that cmGlobalGenerator need not be aware of them.
2010-08-24 18:47:56 -04:00

427 lines
13 KiB
C++

/*============================================================================
CMake - Cross Platform Makefile Generator
Copyright 2000-2009 Kitware, Inc., Insight Software Consortium
Distributed under the OSI-approved BSD License (the "License");
see accompanying file Copyright.txt for details.
This software is distributed WITHOUT ANY WARRANTY; without even the
implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
See the License for more information.
============================================================================*/
#include "cmGlobalVisualStudio6Generator.h"
#include "cmLocalVisualStudio6Generator.h"
#include "cmMakefile.h"
#include "cmake.h"
#include "cmGeneratedFileStream.h"
// Utility function to make a valid VS6 *.dsp filename out
// of a CMake target name:
//
std::string GetVS6TargetName(const std::string& targetName)
{
std::string name(targetName);
// Eliminate hyphens. VS6 cannot handle hyphens in *.dsp filenames...
// Replace them with underscores.
//
cmSystemTools::ReplaceString(name, "-", "_");
return name;
}
cmGlobalVisualStudio6Generator::cmGlobalVisualStudio6Generator()
{
this->FindMakeProgramFile = "CMakeVS6FindMake.cmake";
}
void cmGlobalVisualStudio6Generator
::EnableLanguage(std::vector<std::string>const& lang,
cmMakefile *mf,
bool optional)
{
mf->AddDefinition("CMAKE_GENERATOR_CC", "cl");
mf->AddDefinition("CMAKE_GENERATOR_CXX", "cl");
mf->AddDefinition("CMAKE_GENERATOR_RC", "rc");
mf->AddDefinition("CMAKE_GENERATOR_NO_COMPILER_ENV", "1");
mf->AddDefinition("CMAKE_GENERATOR_Fortran", "ifort");
mf->AddDefinition("MSVC_C_ARCHITECTURE_ID", "X86");
mf->AddDefinition("MSVC_CXX_ARCHITECTURE_ID", "X86");
mf->AddDefinition("MSVC60", "1");
this->GenerateConfigurations(mf);
this->cmGlobalGenerator::EnableLanguage(lang, mf, optional);
}
void cmGlobalVisualStudio6Generator::GenerateConfigurations(cmMakefile* mf)
{
std::string fname= mf->GetRequiredDefinition("CMAKE_ROOT");
const char* def= mf->GetDefinition( "MSPROJECT_TEMPLATE_DIRECTORY");
if(def)
{
fname = def;
}
else
{
fname += "/Templates";
}
fname += "/CMakeVisualStudio6Configurations.cmake";
if(!mf->ReadListFile(mf->GetCurrentListFile(), fname.c_str()))
{
cmSystemTools::Error("Cannot open ", fname.c_str(),
". Please copy this file from the main "
"CMake/Templates directory and edit it for "
"your build configurations.");
}
else if(!mf->GetDefinition("CMAKE_CONFIGURATION_TYPES"))
{
cmSystemTools::Error("CMAKE_CONFIGURATION_TYPES not set by ",
fname.c_str(),
". Please copy this file from the main "
"CMake/Templates directory and edit it for "
"your build configurations.");
}
}
std::string cmGlobalVisualStudio6Generator
::GenerateBuildCommand(const char* makeProgram,
const char *projectName,
const char* additionalOptions,
const char *targetName,
const char* config,
bool ignoreErrors,
bool)
{
// Ingoring errors is not implemented in visual studio 6
(void) ignoreErrors;
// now build the test
std::vector<std::string> mp;
mp.push_back("[HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\VisualStudio"
"\\6.0\\Setup;VsCommonDir]/MSDev98/Bin");
cmSystemTools::ExpandRegistryValues(mp[0]);
std::string originalCommand = makeProgram;
std::string makeCommand =
cmSystemTools::FindProgram(makeProgram, mp);
if(makeCommand.size() == 0)
{
std::string e = "Generator cannot find Visual Studio 6 msdev program \"";
e += originalCommand;
e += "\" specified by CMAKE_MAKE_PROGRAM cache entry. ";
e += "Please fix the setting.";
cmSystemTools::Error(e.c_str());
return "";
}
makeCommand = cmSystemTools::ConvertToOutputPath(makeCommand.c_str());
// if there are spaces in the makeCommand, assume a full path
// and convert it to a path with no spaces in it as the
// RunSingleCommand does not like spaces
#if defined(_WIN32) && !defined(__CYGWIN__)
if(makeCommand.find(' ') != std::string::npos)
{
cmSystemTools::GetShortPath(makeCommand.c_str(), makeCommand);
}
#endif
makeCommand += " ";
makeCommand += projectName;
makeCommand += ".dsw /MAKE \"";
bool clean = false;
if ( targetName && strcmp(targetName, "clean") == 0 )
{
clean = true;
targetName = "ALL_BUILD";
}
if (targetName && strlen(targetName))
{
makeCommand += targetName;
}
else
{
makeCommand += "ALL_BUILD";
}
makeCommand += " - ";
if(config && strlen(config))
{
makeCommand += config;
}
else
{
makeCommand += "Debug";
}
if(clean)
{
makeCommand += "\" /CLEAN";
}
else
{
makeCommand += "\" /BUILD";
}
if ( additionalOptions )
{
makeCommand += " ";
makeCommand += additionalOptions;
}
return makeCommand;
}
///! Create a local generator appropriate to this Global Generator
cmLocalGenerator *cmGlobalVisualStudio6Generator::CreateLocalGenerator()
{
cmLocalGenerator *lg = new cmLocalVisualStudio6Generator;
lg->SetGlobalGenerator(this);
return lg;
}
void cmGlobalVisualStudio6Generator::Generate()
{
// first do the superclass method
this->cmGlobalVisualStudioGenerator::Generate();
// Now write out the DSW
this->OutputDSWFile();
}
// Write a DSW file to the stream
void cmGlobalVisualStudio6Generator
::WriteDSWFile(std::ostream& fout,cmLocalGenerator* root,
std::vector<cmLocalGenerator*>& generators)
{
// Write out the header for a DSW file
this->WriteDSWHeader(fout);
// Collect all targets under this root generator and the transitive
// closure of their dependencies.
TargetDependSet projectTargets;
TargetDependSet originalTargets;
this->GetTargetSets(projectTargets, originalTargets, root, generators);
OrderedTargetDependSet orderedProjectTargets(projectTargets);
std::string rootdir = root->GetMakefile()->GetStartOutputDirectory();
rootdir += "/";
for(OrderedTargetDependSet::const_iterator
tt = orderedProjectTargets.begin();
tt != orderedProjectTargets.end(); ++tt)
{
cmTarget* target = *tt;
cmMakefile* mf = target->GetMakefile();
// Write the project into the DSW file
const char* expath = target->GetProperty("EXTERNAL_MSPROJECT");
if(expath)
{
std::string project = target->GetName();
std::string location = expath;
this->WriteExternalProject(fout, project.c_str(),
location.c_str(), target->GetUtilities());
}
else
{
std::string dspname = GetVS6TargetName(target->GetName());
std::string dir = target->GetMakefile()->GetStartOutputDirectory();
dir = root->Convert(dir.c_str(), cmLocalGenerator::START_OUTPUT);
this->WriteProject(fout, dspname.c_str(), dir.c_str(), *target);
}
}
// Write the footer for the DSW file
this->WriteDSWFooter(fout);
}
void cmGlobalVisualStudio6Generator
::OutputDSWFile(cmLocalGenerator* root,
std::vector<cmLocalGenerator*>& generators)
{
if(generators.size() == 0)
{
return;
}
std::string fname = root->GetMakefile()->GetStartOutputDirectory();
fname += "/";
fname += root->GetMakefile()->GetProjectName();
fname += ".dsw";
std::ofstream fout(fname.c_str());
if(!fout)
{
cmSystemTools::Error("Error can not open DSW file for write: ",
fname.c_str());
cmSystemTools::ReportLastSystemError("");
return;
}
this->WriteDSWFile(fout, root, generators);
}
// output the DSW file
void cmGlobalVisualStudio6Generator::OutputDSWFile()
{
std::map<cmStdString, std::vector<cmLocalGenerator*> >::iterator it;
for(it = this->ProjectMap.begin(); it!= this->ProjectMap.end(); ++it)
{
this->OutputDSWFile(it->second[0], it->second);
}
}
// Write a dsp file into the DSW file,
// Note, that dependencies from executables to
// the libraries it uses are also done here
void cmGlobalVisualStudio6Generator::WriteProject(std::ostream& fout,
const char* dspname,
const char* dir,
cmTarget& target)
{
fout << "#########################################################"
"######################\n\n";
fout << "Project: \"" << dspname << "\"="
<< dir << "\\" << dspname << ".dsp - Package Owner=<4>\n\n";
fout << "Package=<5>\n{{{\n}}}\n\n";
fout << "Package=<4>\n";
fout << "{{{\n";
VSDependSet const& depends = this->VSTargetDepends[&target];
for(VSDependSet::const_iterator di = depends.begin();
di != depends.end(); ++di)
{
const char* name = di->c_str();
fout << "Begin Project Dependency\n";
fout << "Project_Dep_Name " << GetVS6TargetName(name) << "\n";
fout << "End Project Dependency\n";
}
fout << "}}}\n\n";
UtilityDependsMap::iterator ui = this->UtilityDepends.find(&target);
if(ui != this->UtilityDepends.end())
{
const char* uname = ui->second.c_str();
fout << "Project: \"" << uname << "\"="
<< dir << "\\" << uname << ".dsp - Package Owner=<4>\n\n";
fout <<
"Package=<5>\n{{{\n}}}\n\n"
"Package=<4>\n"
"{{{\n"
"Begin Project Dependency\n"
"Project_Dep_Name " << dspname << "\n"
"End Project Dependency\n"
"}}}\n\n";
;
}
}
// Write a dsp file into the DSW file,
// Note, that dependencies from executables to
// the libraries it uses are also done here
void cmGlobalVisualStudio6Generator::WriteExternalProject(std::ostream& fout,
const char* name,
const char* location,
const std::set<cmStdString>& dependencies)
{
fout << "#########################################################"
"######################\n\n";
fout << "Project: \"" << name << "\"="
<< location << " - Package Owner=<4>\n\n";
fout << "Package=<5>\n{{{\n}}}\n\n";
fout << "Package=<4>\n";
fout << "{{{\n";
std::set<cmStdString>::const_iterator i, end;
// write dependencies.
i = dependencies.begin();
end = dependencies.end();
for(;i!= end; ++i)
{
fout << "Begin Project Dependency\n";
fout << "Project_Dep_Name " << GetVS6TargetName(*i) << "\n";
fout << "End Project Dependency\n";
}
fout << "}}}\n\n";
}
// Standard end of dsw file
void cmGlobalVisualStudio6Generator::WriteDSWFooter(std::ostream& fout)
{
fout << "######################################################"
"#########################\n\n";
fout << "Global:\n\n";
fout << "Package=<5>\n{{{\n}}}\n\n";
fout << "Package=<3>\n{{{\n}}}\n\n";
fout << "#####################################################"
"##########################\n\n";
}
// ouput standard header for dsw file
void cmGlobalVisualStudio6Generator::WriteDSWHeader(std::ostream& fout)
{
fout << "Microsoft Developer Studio Workspace File, Format Version 6.00\n";
fout << "# WARNING: DO NOT EDIT OR DELETE THIS WORKSPACE FILE!\n\n";
}
//----------------------------------------------------------------------------
std::string
cmGlobalVisualStudio6Generator::WriteUtilityDepend(cmTarget* target)
{
std::string pname = target->GetName();
pname += "_UTILITY";
pname = GetVS6TargetName(pname.c_str());
std::string fname = target->GetMakefile()->GetStartOutputDirectory();
fname += "/";
fname += pname;
fname += ".dsp";
cmGeneratedFileStream fout(fname.c_str());
fout.SetCopyIfDifferent(true);
fout <<
"# Microsoft Developer Studio Project File - Name=\""
<< pname << "\" - Package Owner=<4>\n"
"# Microsoft Developer Studio Generated Build File, Format Version 6.00\n"
"# ** DO NOT EDIT **\n"
"\n"
"# TARGTYPE \"Win32 (x86) Generic Project\" 0x010a\n"
"\n"
"CFG=" << pname << " - Win32 Debug\n"
"!MESSAGE \"" << pname << " - Win32 Debug\""
" (based on \"Win32 (x86) Generic Project\")\n"
"!MESSAGE \"" << pname << " - Win32 Release\" "
"(based on \"Win32 (x86) Generic Project\")\n"
"!MESSAGE \"" << pname << " - Win32 MinSizeRel\" "
"(based on \"Win32 (x86) Generic Project\")\n"
"!MESSAGE \"" << pname << " - Win32 RelWithDebInfo\" "
"(based on \"Win32 (x86) Generic Project\")\n"
"\n"
"# Begin Project\n"
"# Begin Target\n"
"# Name \"" << pname << " - Win32 Debug\"\n"
"# Name \"" << pname << " - Win32 Release\"\n"
"# Name \"" << pname << " - Win32 MinSizeRel\"\n"
"# Name \"" << pname << " - Win32 RelWithDebInfo\"\n"
"# End Target\n"
"# End Project\n"
;
return pname;
}
//----------------------------------------------------------------------------
void cmGlobalVisualStudio6Generator
::GetDocumentation(cmDocumentationEntry& entry) const
{
entry.Name = this->GetName();
entry.Brief = "Generates Visual Studio 6 project files.";
entry.Full = "";
}
//----------------------------------------------------------------------------
void
cmGlobalVisualStudio6Generator
::AppendDirectoryForConfig(const char* prefix,
const char* config,
const char* suffix,
std::string& dir)
{
if(config)
{
dir += prefix;
dir += config;
dir += suffix;
}
}