CMake/Source/cmVisualStudio10TargetGenerator.cxx
Brad King a608467180 ENH: Simpler cmTarget::GetLinkerLanguage signature
This method previously required the global generator to be passed, but
that was left from before cmTarget had its Makefile member.  Now the
global generator can be retrieved automatically, so we can drop the
method argument.
2009-07-07 07:44:12 -04:00

1018 lines
33 KiB
C++
Raw Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/*=========================================================================
Program: CMake - Cross-Platform Makefile Generator
Module: $RCSfile$
Language: C++
Date: $Date$
Version: $Revision$
Copyright (c) 2002 Kitware, Inc., Insight Consortium. All rights reserved.
See Copyright.txt or http://www.cmake.org/HTML/Copyright.html for details.
This software is distributed WITHOUT ANY WARRANTY; without even
the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
PURPOSE. See the above copyright notices for more information.
=========================================================================*/
#include "cmVisualStudio10TargetGenerator.h"
#include "cmGlobalVisualStudio7Generator.h"
#include "cmTarget.h"
#include "cmComputeLinkInformation.h"
#include "cmGeneratedFileStream.h"
#include "cmMakefile.h"
#include "cmSourceFile.h"
#include "cmVisualStudioGeneratorOptions.h"
#include "cmLocalVisualStudio7Generator.h"
#include "cmVS10CLFlagTable.h"
#include "cmVS10LinkFlagTable.h"
#include "cmVS10LibFlagTable.h"
cmVisualStudio10TargetGenerator::
cmVisualStudio10TargetGenerator(cmTarget* target,
cmGlobalVisualStudio7Generator* gg)
{
this->GlobalGenerator = gg;
this->GlobalGenerator->CreateGUID(target->GetName());
this->GUID = this->GlobalGenerator->GetGUID(target->GetName());
this->Target = target;
this->Makefile = target->GetMakefile();
this->LocalGenerator =
(cmLocalVisualStudio7Generator*)
this->Makefile->GetLocalGenerator();
this->Platform = "|Win32";
}
cmVisualStudio10TargetGenerator::~cmVisualStudio10TargetGenerator()
{
delete this->BuildFileStream;
}
void cmVisualStudio10TargetGenerator::WritePlatformConfigTag(
const char* tag,
const char* config,
int indentLevel,
const char* attribute,
const char* end,
std::ostream* stream)
{
if(!stream)
{
stream = this->BuildFileStream;
}
stream->fill(' ');
stream->width(indentLevel*2 );
(*stream ) << "";
(*stream ) << "<" << tag
<< " Condition=\"'$(Configuration)|$(Platform)'=='";
(*stream ) << config << this->Platform << "'\"";
if(attribute)
{
(*stream ) << attribute;
}
// close the tag
(*stream ) << ">";
if(end)
{
(*stream ) << end;
}
}
void cmVisualStudio10TargetGenerator::WriteString(const char* line,
int indentLevel)
{
this->BuildFileStream->fill(' ');
this->BuildFileStream->width(indentLevel*2 );
// write an empty string to get the fill level indent to print
(*this->BuildFileStream ) << "";
(*this->BuildFileStream ) << line;
}
void cmVisualStudio10TargetGenerator::Generate()
{
// Tell the global generator the name of the project file
this->Target->SetProperty("GENERATOR_FILE_NAME",this->Target->GetName());
this->Target->SetProperty("GENERATOR_FILE_NAME_EXT",
".vcxproj");
cmMakefile* mf = this->Target->GetMakefile();
std::string path = mf->GetStartOutputDirectory();
path += "/";
path += this->Target->GetName();
path += ".vcxproj";
this->BuildFileStream =
new cmGeneratedFileStream(path.c_str());
this->BuildFileStream->SetCopyIfDifferent(true);
// Write the encoding header into the file
char magic[] = {0xEF,0xBB, 0xBF};
this->BuildFileStream->write(magic, 3);
this->WriteString("<Project DefaultTargets=\"Build\" "
"ToolsVersion=\"4.0\" "
"xmlns=\"http://schemas.microsoft.com/"
"developer/msbuild/2003\">\n",
0);
this->WriteProjectConfigurations();
this->WriteString("<PropertyGroup Label=\"Globals\">\n", 1);
this->WriteString("<ProjectGUID>", 2);
(*this->BuildFileStream) << "{" << this->GUID << "}</ProjectGUID>\n";
this->WriteString("<SccProjectName />\n", 2);
this->WriteString("<SccLocalPath />\n", 2);
this->WriteString("<Keyword>Win32Proj</Keyword>\n", 2);
this->WriteString("</PropertyGroup>\n", 1);
this->WriteString("<Import Project="
"\"$(VCTargetsPath)\\Microsoft.Cpp.Default.props\" />\n",
1);
this->WriteProjectConfigurationValues();
this->WriteString(
"<Import Project=\"$(VCTargetsPath)\\Microsoft.Cpp.props\" />\n", 1);
this->WriteString("<ImportGroup Label=\"ExtensionSettings\">\n", 1);
this->WriteString("</ImportGroup>\n", 1);
this->WriteString("<ImportGroup Label=\"PropertySheets\">\n", 1);
this->WriteString("<Import Project="
"\"$(LocalAppData)\\Microsoft\\VisualStudio\\10.0\\"
"Microsoft.Cpp.$(Platform).user.props\" "
"Condition=\"exists('$(LocalAppData)\\Microsoft"
"\\VisualStudio\\10.0\\"
"Microsoft.Cpp.$(Platform).user.props')\" />\n", 2);
this->WriteString("</ImportGroup>\n", 1);
this->WriteString("<PropertyGroup Label=\"UserMacros\" />\n", 1);
this->WritePathAndIncrementalLinkOptions();
this->WriteItemDefinitionGroups();
this->WriteCustomCommands();
this->WriteObjSources();
this->WriteCLSources();
this->WriteProjectReferences();
this->WriteString(
"<Import Project=\"$(VCTargetsPath)\\Microsoft.Cpp.targets\""
" />\n", 1);
this->WriteString("<ImportGroup Label=\"ExtensionTargets\">\n", 1);
this->WriteString("</ImportGroup>\n", 1);
this->WriteString("</Project>", 0);
// The groups are stored in a separate file for VS 10
this->WriteGroups();
}
// ConfigurationType Application, Utility StaticLibrary DynamicLibrary
void cmVisualStudio10TargetGenerator::WriteProjectConfigurations()
{
this->WriteString("<ItemGroup Label=\"ProjectConfigurations\">\n", 1);
std::vector<std::string> *configs =
static_cast<cmGlobalVisualStudio7Generator *>
(this->GlobalGenerator)->GetConfigurations();
for(std::vector<std::string>::iterator i = configs->begin();
i != configs->end(); ++i)
{
this->WriteString("<ProjectConfiguration Include=\"", 2);
(*this->BuildFileStream ) << *i << this->Platform << "\">\n";
this->WriteString("<Configuration>", 3);
(*this->BuildFileStream ) << *i << "</Configuration>\n";
this->WriteString("<Platform>Win32</Platform>\n", 3);
this->WriteString("</ProjectConfiguration>\n", 2);
}
this->WriteString("</ItemGroup>\n", 1);
}
void cmVisualStudio10TargetGenerator::WriteProjectConfigurationValues()
{
std::vector<std::string> *configs =
static_cast<cmGlobalVisualStudio7Generator *>
(this->GlobalGenerator)->GetConfigurations();
for(std::vector<std::string>::iterator i = configs->begin();
i != configs->end(); ++i)
{
this->WritePlatformConfigTag("PropertyGroup",
i->c_str(),
1, " Label=\"Configuration\"", "\n");
std::string configType = "<ConfigurationType>";
switch(this->Target->GetType())
{
case cmTarget::SHARED_LIBRARY:
case cmTarget::MODULE_LIBRARY:
configType += "DynamicLibrary";
break;
case cmTarget::STATIC_LIBRARY:
configType += "StaticLibrary";
break;
case cmTarget::EXECUTABLE:
configType += "Application";
break;
case cmTarget::UTILITY:
configType += "Utility";
break;
}
configType += "</ConfigurationType>\n";
this->WriteString(configType.c_str(), 2);
const char* mfcFlag =
this->Target->GetMakefile()->GetDefinition("CMAKE_MFC_FLAG");
if(mfcFlag)
{
this->WriteString("<UseOfMfc>true</UseOfMfc>\n", 2);
}
else
{
this->WriteString("<UseOfMfc>false</UseOfMfc>\n", 2);
}
this->WriteString("<CharacterSet>MultiByte</CharacterSet>\n", 2);
this->WriteString("</PropertyGroup>\n", 1);
}
}
void cmVisualStudio10TargetGenerator::WriteCustomCommands()
{
this->WriteString("<ItemGroup>\n", 1);
std::vector<cmSourceFile*>const & sources = this->Target->GetSourceFiles();
for(std::vector<cmSourceFile*>::const_iterator source = sources.begin();
source != sources.end(); ++source)
{
if(cmCustomCommand const* command = (*source)->GetCustomCommand())
{
this->WriteCustomRule(*source, *command);
}
}
this->WriteString("</ItemGroup>\n", 1);
}
void
cmVisualStudio10TargetGenerator::WriteCustomRule(cmSourceFile* source,
cmCustomCommand const &
command)
{
std::string sourcePath = source->GetFullPath();
// the rule file seems to need to exist for vs10
if (source->GetExtension() == "rule")
{
if(!cmSystemTools::FileExists(sourcePath.c_str()))
{
std::ofstream fout(sourcePath.c_str());
if(fout)
{
fout << "# generated from CMake\n";
fout.flush();
fout.close();
}
}
}
cmLocalVisualStudio7Generator* lg = this->LocalGenerator;
std::string comment = lg->ConstructComment(command);
std::vector<std::string> *configs =
static_cast<cmGlobalVisualStudio7Generator *>
(this->GlobalGenerator)->GetConfigurations();
this->WriteString("<CustomBuild Include=\"", 2);
(*this->BuildFileStream ) <<
cmSystemTools::RelativePath(this->Makefile->GetCurrentOutputDirectory(),
sourcePath.c_str()) << "\">\n";
for(std::vector<std::string>::iterator i = configs->begin();
i != configs->end(); ++i)
{
std::string script =
lg->ConstructScript(command.GetCommandLines(),
command.GetWorkingDirectory(),
i->c_str(),
command.GetEscapeOldStyle(),
command.GetEscapeAllowMakeVars());
this->WritePlatformConfigTag("Message",i->c_str(), 3);
(*this->BuildFileStream ) << comment << "</Message>\n";
this->WritePlatformConfigTag("Command", i->c_str(), 3);
(*this->BuildFileStream ) << script << "</Command>\n";
this->WritePlatformConfigTag("AdditionalInputs", i->c_str(), 3);
(*this->BuildFileStream ) << source->GetFullPath();
for(std::vector<std::string>::const_iterator d =
command.GetDepends().begin();
d != command.GetDepends().end();
++d)
{
std::string dep = this->LocalGenerator->
GetRealDependency(d->c_str(), i->c_str());
this->ConvertToWindowsSlash(dep);
(*this->BuildFileStream ) << ";" << dep;
}
(*this->BuildFileStream ) << ";%(AdditionalInputs)</AdditionalInputs>\n";
this->WritePlatformConfigTag("Outputs", i->c_str(), 3);
const char* sep = "";
for(std::vector<std::string>::const_iterator o =
command.GetOutputs().begin();
o != command.GetOutputs().end();
++o)
{
std::string out = *o;
this->ConvertToWindowsSlash(out);
(*this->BuildFileStream ) << sep << out;
sep = ";";
}
(*this->BuildFileStream ) << ";%(Outputs)</Outputs>\n";
}
this->WriteString("</CustomBuild>\n", 2);
}
void cmVisualStudio10TargetGenerator::ConvertToWindowsSlash(std::string& s)
{
// first convert all of the slashes
std::string::size_type pos = 0;
while((pos = s.find('/', pos)) != std::string::npos)
{
s[pos] = '\\';
pos++;
}
}
void cmVisualStudio10TargetGenerator::WriteGroups()
{
// This should create a target.vcxproj.filters file
// something like this:
/*
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="4.0"
xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup>
<CustomBuild Include="..\CMakeLists.txt" />
</ItemGroup>
<ItemGroup>
<Filter Include="Source Files">
<UniqueIdentifier>{05072589-c7be-439a-8fd7-5db6ee5008a9}
</UniqueIdentifier>
</Filter>
</ItemGroup>
<ItemGroup>
<ClCompile Include="..\foo.c">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="..\testCCompiler.c">
<Filter>Source Files</Filter>
</ClCompile>
</ItemGroup>
</Project>
*/
}
void cmVisualStudio10TargetGenerator::WriteObjSources()
{
if(this->Target->GetType() > cmTarget::MODULE_LIBRARY)
{
return;
}
bool first = true;
std::vector<cmSourceFile*>const & sources = this->Target->GetSourceFiles();
for(std::vector<cmSourceFile*>::const_iterator source = sources.begin();
source != sources.end(); ++source)
{
if((*source)->GetExtension() == "obj")
{
if(first)
{
this->WriteString("<ItemGroup>\n", 1);
first = false;
}
this->WriteString("<None Include=\"", 2);
(*this->BuildFileStream ) << (*source)->GetFullPath() << "\" />\n";
}
}
if(!first)
{
this->WriteString("</ItemGroup>\n", 1);
}
}
void cmVisualStudio10TargetGenerator::WriteCLSources()
{
this->WriteString("<ItemGroup>\n", 1);
if(this->Target->GetType() > cmTarget::MODULE_LIBRARY)
{
this->WriteString("<None Include=\"", 2);
(*this->BuildFileStream ) << this->Target->GetDirectory()
<< "\\" << this->Target->GetName()
<< "\" />\n";
}
else
{
std::vector<cmSourceFile*>const& sources = this->Target->GetSourceFiles();
for(std::vector<cmSourceFile*>::const_iterator source = sources.begin();
source != sources.end(); ++source)
{
// if it is not a custom command then add it as a c/c++ file,
// TODO: need to check for idl or rc
if(!(*source)->GetCustomCommand()
&& !(*source)->GetPropertyAsBool("HEADER_FILE_ONLY")
&& !this->GlobalGenerator->IgnoreFile
((*source)->GetExtension().c_str()))
{
const char* lang = (*source)->GetLanguage();
if(lang && (strcmp(lang, "C") == 0 || strcmp(lang, "CXX") ==0))
{
std::string sourceFile = (*source)->GetFullPath();
// output the source file
this->WriteString("<ClCompile Include=\"", 2);
(*this->BuildFileStream ) << sourceFile << "\"";
// ouput any flags specific to this source file
if(this->OutputSourceSpecificFlags(*source))
{
// if the source file has specific flags the tag
// is ended on a new line
this->WriteString("</ClCompile>\n", 2);
}
else
{
(*this->BuildFileStream ) << " />\n";
}
}
}
}
}
this->WriteString("</ItemGroup>\n", 1);
}
bool cmVisualStudio10TargetGenerator::OutputSourceSpecificFlags(
cmSourceFile* source)
{
cmSourceFile& sf = *source;
std::string flags;
std::string defines;
if(const char* cflags = sf.GetProperty("COMPILE_FLAGS"))
{
flags += cflags;
}
if(const char* cdefs = sf.GetProperty("COMPILE_DEFINITIONS"))
{
defines += cdefs;
}
const char* lang =
this->GlobalGenerator->GetLanguageFromExtension
(sf.GetExtension().c_str());
const char* sourceLang = this->LocalGenerator->GetSourceFileLanguage(sf);
const char* linkLanguage = this->Target->GetLinkerLanguage();
bool needForceLang = false;
// source file does not match its extension language
if(lang && sourceLang && strcmp(lang, sourceLang) != 0)
{
needForceLang = true;
lang = sourceLang;
}
// if the source file does not match the linker language
// then force c or c++
if(needForceLang || (linkLanguage && lang
&& strcmp(lang, linkLanguage) != 0))
{
if(strcmp(lang, "CXX") == 0)
{
// force a C++ file type
flags += " /TP ";
}
else if(strcmp(lang, "C") == 0)
{
// force to c
flags += " /TC ";
}
}
// for the first time we need a new line if there is something
// produced here.
const char* firstString = ">\n";
std::vector<std::string> *configs =
static_cast<cmGlobalVisualStudio7Generator *>
(this->GlobalGenerator)->GetConfigurations();
bool hasFlags = false;
for( std::vector<std::string>::iterator config = configs->begin();
config != configs->end(); ++config)
{
std::string configUpper = cmSystemTools::UpperCase(*config);
std::string configDefines = defines;
std::string defPropName = "COMPILE_DEFINITIONS_";
defPropName += configUpper;
if(const char* ccdefs = sf.GetProperty(defPropName.c_str()))
{
if(configDefines.size())
{
configDefines += ",";
}
configDefines += ccdefs;
}
// if we have flags or defines for this config then
// use them
if(flags.size() || configDefines.size())
{
(*this->BuildFileStream ) << firstString;
firstString = ""; // only do firstString once
hasFlags = true;
cmVisualStudioGeneratorOptions
clOptions(this->LocalGenerator,
10, cmVisualStudioGeneratorOptions::Compiler,
cmVS10CLFlagTable, 0, this);
clOptions.Parse(flags.c_str());
clOptions.AddDefines(configDefines.c_str());
clOptions.SetConfiguration((*config).c_str());
clOptions.OutputAdditionalOptions(*this->BuildFileStream, " ", "");
clOptions.OutputFlagMap(*this->BuildFileStream, " ");
clOptions.OutputPreprocessorDefinitions(*this->BuildFileStream,
" ", "\n");
}
}
return hasFlags;
}
void cmVisualStudio10TargetGenerator::WritePathAndIncrementalLinkOptions()
{
this->WriteString("<PropertyGroup>\n", 2);
this->WriteString("<_ProjectFileVersion>10.0.20506.1"
"</_ProjectFileVersion>\n", 3);
std::vector<std::string> *configs =
static_cast<cmGlobalVisualStudio7Generator *>
(this->GlobalGenerator)->GetConfigurations();
for(std::vector<std::string>::iterator config = configs->begin();
config != configs->end(); ++config)
{
std::string targetNameFull =
this->Target->GetFullName(config->c_str());
std::string intermediateDir = this->LocalGenerator->
GetTargetDirectory(*this->Target);
intermediateDir += "/";
intermediateDir += *config;
intermediateDir += "/";
this->ConvertToWindowsSlash(intermediateDir);
std::string outDir = this->Target->GetDirectory(config->c_str());
this->ConvertToWindowsSlash(outDir);
this->WritePlatformConfigTag("OutDir", config->c_str(), 3);
*this->BuildFileStream << outDir
<< "\\"
<< "</OutDir>\n";
this->WritePlatformConfigTag("IntDir", config->c_str(), 3);
*this->BuildFileStream << intermediateDir
<< "</IntDir>\n";
this->WritePlatformConfigTag("TargetName", config->c_str(), 3);
*this->BuildFileStream << cmSystemTools::GetFilenameWithoutExtension(
targetNameFull.c_str())
<< "</TargetName>\n";
this->WritePlatformConfigTag("TargetExt", config->c_str(), 3);
*this->BuildFileStream << cmSystemTools::GetFilenameLastExtension(
targetNameFull.c_str())
<< "</TargetExt>\n";
this->OutputLinkIncremental(*config);
}
this->WriteString("</PropertyGroup>\n", 2);
}
void
cmVisualStudio10TargetGenerator::
OutputLinkIncremental(std::string const& configName)
{
std::string CONFIG = cmSystemTools::UpperCase(configName);
// static libraries and things greater than modules do not need
// to set this option
if(this->Target->GetType() == cmTarget::STATIC_LIBRARY
|| this->Target->GetType() > cmTarget::MODULE_LIBRARY)
{
return;
}
const char* linkType = "SHARED";
if(this->Target->GetType() == cmTarget::EXECUTABLE)
{
linkType = "EXE";
}
// assume incremental linking
const char* incremental = "true";
const char* linkLanguage = this->Target->GetLinkerLanguage();
if(!linkLanguage)
{
cmSystemTools::Error
("CMake can not determine linker language for target:",
this->Target->GetName());
return;
}
std::string linkFlagVarBase = "CMAKE_";
linkFlagVarBase += linkType;
linkFlagVarBase += "_LINKER_FLAGS";
std::string flags = this->
Target->GetMakefile()->GetRequiredDefinition(linkFlagVarBase.c_str());
std::string linkFlagVar = linkFlagVarBase + "_" + CONFIG;
flags += this->
Target->GetMakefile()->GetRequiredDefinition(linkFlagVar.c_str());
if(strcmp(linkLanguage, "C") == 0 || strcmp(linkLanguage, "CXX") == 0
|| strcmp(linkLanguage, "Fortran") == 0)
{
std::string baseFlagVar = "CMAKE_";
baseFlagVar += linkLanguage;
baseFlagVar += "_FLAGS";
flags += this->
Target->GetMakefile()->GetRequiredDefinition(baseFlagVar.c_str());
std::string flagVar = baseFlagVar + std::string("_") + CONFIG;
flags +=
Target->GetMakefile()->GetRequiredDefinition(flagVar.c_str());
}
if(flags.find("INCREMENTAL:NO") != flags.npos)
{
incremental = "false";
}
this->WritePlatformConfigTag("LinkIncremental", configName.c_str(), 3);
*this->BuildFileStream << incremental
<< "</LinkIncremental>\n";
}
void
cmVisualStudio10TargetGenerator::
WriteClOptions(std::string const& configName,
std::vector<std::string> const & includes)
{
// much of this was copied from here:
// copied from cmLocalVisualStudio7Generator.cxx 805
this->WriteString("<ClCompile>\n", 2);
cmVisualStudioGeneratorOptions
clOptions(this->LocalGenerator,
10, cmVisualStudioGeneratorOptions::Compiler,
cmVS10CLFlagTable);
std::string flags;
// collect up flags for
if(this->Target->GetType() < cmTarget::UTILITY)
{
const char* linkLanguage = this->Target->GetLinkerLanguage();
if(!linkLanguage)
{
cmSystemTools::Error
("CMake can not determine linker language for target:",
this->Target->GetName());
return;
}
if(strcmp(linkLanguage, "C") == 0 || strcmp(linkLanguage, "CXX") == 0
|| strcmp(linkLanguage, "Fortran") == 0)
{
std::string baseFlagVar = "CMAKE_";
baseFlagVar += linkLanguage;
baseFlagVar += "_FLAGS";
flags = this->
Target->GetMakefile()->GetRequiredDefinition(baseFlagVar.c_str());
std::string flagVar = baseFlagVar + std::string("_") +
cmSystemTools::UpperCase(configName);
flags += " ";
flags += this->
Target->GetMakefile()->GetRequiredDefinition(flagVar.c_str());
}
// set the correct language
if(strcmp(linkLanguage, "C") == 0)
{
flags += " /TC ";
}
if(strcmp(linkLanguage, "CXX") == 0)
{
flags += " /TP ";
}
}
std::string configUpper = cmSystemTools::UpperCase(configName);
std::string defPropName = "COMPILE_DEFINITIONS_";
defPropName += configUpper;
// Get preprocessor definitions for this directory.
std::string defineFlags = this->Target->GetMakefile()->GetDefineFlags();
clOptions.FixExceptionHandlingDefault();
clOptions.Parse(flags.c_str());
clOptions.Parse(defineFlags.c_str());
clOptions.AddDefines
(this->Makefile->GetProperty("COMPILE_DEFINITIONS"));
clOptions.AddDefines(this->Target->GetProperty("COMPILE_DEFINITIONS"));
clOptions.AddDefines(this->Makefile->GetProperty(defPropName.c_str()));
clOptions.AddDefines(this->Target->GetProperty(defPropName.c_str()));
clOptions.SetVerboseMakefile(
this->Makefile->IsOn("CMAKE_VERBOSE_MAKEFILE"));
// Add a definition for the configuration name.
std::string configDefine = "CMAKE_INTDIR=\"";
configDefine += configName;
configDefine += "\"";
clOptions.AddDefine(configDefine);
if(const char* exportMacro = this->Target->GetExportMacro())
{
clOptions.AddDefine(exportMacro);
}
clOptions.OutputAdditionalOptions(*this->BuildFileStream, " ", "");
this->OutputIncludes(includes);
clOptions.OutputFlagMap(*this->BuildFileStream, " ");
clOptions.OutputPreprocessorDefinitions(*this->BuildFileStream, " ",
"\n");
this->WriteString("<AssemblerListingLocation>", 3);
*this->BuildFileStream << configName
<< "</AssemblerListingLocation>\n";
this->WriteString("<ObjectFileName>$(IntDir)</ObjectFileName>\n", 3);
this->WriteString("<ProgramDataBaseFileName>", 3);
*this->BuildFileStream << this->Target->GetDirectory(configName.c_str())
<< "/"
<< this->Target->GetPDBName(configName.c_str())
<< "</ProgramDataBaseFileName>\n";
this->WriteString("</ClCompile>\n", 2);
}
void cmVisualStudio10TargetGenerator::
OutputIncludes(std::vector<std::string> const & includes)
{
this->WriteString("<AdditionalIncludeDirectories>", 3);
for(std::vector<std::string>::const_iterator i = includes.begin();
i != includes.end(); ++i)
{
*this->BuildFileStream << *i << ";";
}
this->WriteString("%(AdditionalIncludeDirectories)"
"</AdditionalIncludeDirectories>\n", 0);
}
void cmVisualStudio10TargetGenerator::
WriteRCOptions(std::string const& ,
std::vector<std::string> const & includes)
{
this->WriteString("<ResourceCompile>\n", 2);
this->OutputIncludes(includes);
this->WriteString("</ResourceCompile>\n", 2);
}
void cmVisualStudio10TargetGenerator::WriteLibOptions(std::string const&
)
{
if(this->Target->GetType() != cmTarget::STATIC_LIBRARY)
{
return;
}
if(const char* libflags = this->Target
->GetProperty("STATIC_LIBRARY_FLAGS"))
{
this->WriteString("<Lib>\n", 2);
cmVisualStudioGeneratorOptions
libOptions(this->LocalGenerator,
10, cmVisualStudioGeneratorOptions::Compiler,
cmVS10LibFlagTable, 0, this);
libOptions.Parse(libflags);
libOptions.OutputAdditionalOptions(*this->BuildFileStream, " ", "");
libOptions.OutputFlagMap(*this->BuildFileStream, " ");
this->WriteString("</Lib>\n", 2);
}
}
void cmVisualStudio10TargetGenerator::WriteLinkOptions(std::string const&
config)
{
// static libraries and things greater than modules do not need
// to set this option
if(this->Target->GetType() == cmTarget::STATIC_LIBRARY
|| this->Target->GetType() > cmTarget::MODULE_LIBRARY)
{
return;
}
const char* linkLanguage = this->Target->GetLinkerLanguage();
if(!linkLanguage)
{
cmSystemTools::Error
("CMake can not determine linker language for target:",
this->Target->GetName());
return;
}
this->WriteString("<Link>\n", 2);
std::string CONFIG = cmSystemTools::UpperCase(config);
const char* linkType = "SHARED";
if(this->Target->GetType() == cmTarget::MODULE_LIBRARY)
{
linkType = "MODULE";
}
if(this->Target->GetType() == cmTarget::EXECUTABLE)
{
linkType = "EXE";
}
std::string stackVar = "CMAKE_";
stackVar += linkLanguage;
stackVar += "_STACK_SIZE";
const char* stackVal = this->Makefile->GetDefinition(stackVar.c_str());
std::string flags;
if(stackVal)
{
flags += " ";
flags += stackVal;
}
// assume incremental linking
std::string linkFlagVarBase = "CMAKE_";
linkFlagVarBase += linkType;
linkFlagVarBase += "_LINKER_FLAGS";
flags += " ";
flags += this->
Target->GetMakefile()->GetRequiredDefinition(linkFlagVarBase.c_str());
std::string linkFlagVar = linkFlagVarBase + "_" + CONFIG;
flags += " ";
flags += this->
Target->GetMakefile()->GetRequiredDefinition(linkFlagVar.c_str());
const char* targetLinkFlags = this->Target->GetProperty("LINK_FLAGS");
if(targetLinkFlags)
{
flags += " ";
flags += targetLinkFlags;
}
cmVisualStudioGeneratorOptions
linkOptions(this->LocalGenerator,
10, cmVisualStudioGeneratorOptions::Compiler,
cmVS10LinkFlagTable);
if ( this->Target->GetPropertyAsBool("WIN32_EXECUTABLE") )
{
flags += " /SUBSYSTEM:WINDOWS";
}
else
{
flags += " /SUBSYSTEM:CONSOLE";
}
cmSystemTools::ReplaceString(flags, "/INCREMENTAL:YES", "");
cmSystemTools::ReplaceString(flags, "/INCREMENTAL:NO", "");
std::string standardLibsVar = "CMAKE_";
standardLibsVar += linkLanguage;
standardLibsVar += "_STANDARD_LIBRARIES";
std::string
libs = this->Makefile->GetSafeDefinition(standardLibsVar.c_str());
// Remove trailing spaces from libs
std::string::size_type pos = libs.size()-1;
if(libs.size() != 0)
{
while(libs[pos] == ' ')
{
pos--;
}
}
if(pos != libs.size()-1)
{
libs = libs.substr(0, pos+1);
}
// Replace spaces in libs with ;
cmSystemTools::ReplaceString(libs, " ", ";");
cmComputeLinkInformation* pcli =
this->Target->GetLinkInformation(config.c_str());
if(!pcli)
{
cmSystemTools::Error
("CMake can not compute cmComputeLinkInformation for target:",
this->Target->GetName());
return;
}
// add the libraries for the target to libs string
cmComputeLinkInformation& cli = *pcli;
this->AddLibraries(cli, libs);
linkOptions.AddFlag("AdditionalDependencies", libs.c_str());
std::vector<std::string> const& ldirs = cli.GetDirectories();
const char* sep = "";
std::string linkDirs;
for(std::vector<std::string>::const_iterator d = ldirs.begin();
d != ldirs.end(); ++d)
{
linkDirs += sep;
linkDirs += *d;
sep = ";";
}
linkDirs += "%(AdditionalLibraryDirectories)";
linkOptions.AddFlag("AdditionalLibraryDirectories", linkDirs.c_str());
linkOptions.AddFlag("AdditionalDependencies", libs.c_str());
linkOptions.AddFlag("Version", "0.0");
if(linkOptions.IsDebug() || flags.find("/debug") != flags.npos)
{
linkOptions.AddFlag("GenerateDebugInformation", "true");
}
else
{
linkOptions.AddFlag("GenerateDebugInformation", "false");
}
std::string targetName;
std::string targetNameSO;
std::string targetNameFull;
std::string targetNameImport;
std::string targetNamePDB;
if(this->Target->GetType() == cmTarget::EXECUTABLE)
{
this->Target->GetExecutableNames(targetName, targetNameFull,
targetNameImport, targetNamePDB,
config.c_str());
}
else
{
this->Target->GetLibraryNames(targetName, targetNameSO, targetNameFull,
targetNameImport, targetNamePDB,
config.c_str());
}
std::string dir = this->Target->GetDirectory(config.c_str());
dir += "/";
std::string imLib = dir;
imLib += targetNameImport;
std::string pdb = dir;
pdb += targetNamePDB;
linkOptions.AddFlag("ImportLibrary", imLib.c_str());
linkOptions.AddFlag("ProgramDataBaseFileName", pdb.c_str());
linkOptions.Parse(flags.c_str());
linkOptions.OutputAdditionalOptions(*this->BuildFileStream, " ", "");
linkOptions.OutputFlagMap(*this->BuildFileStream, " ");
this->WriteString("</Link>\n", 2);
}
void cmVisualStudio10TargetGenerator::AddLibraries(
cmComputeLinkInformation& cli,
std::string& libstring)
{
typedef cmComputeLinkInformation::ItemVector ItemVector;
ItemVector libs = cli.GetItems();
const char* sep = ";";
for(ItemVector::const_iterator l = libs.begin(); l != libs.end(); ++l)
{
if(l->IsPath)
{
std::string path = this->LocalGenerator->
Convert(l->Value.c_str(),
cmLocalGenerator::START_OUTPUT,
cmLocalGenerator::UNCHANGED);
libstring += sep;
libstring += path;
}
else
{
libstring += sep;
libstring += l->Value;
}
}
}
void cmVisualStudio10TargetGenerator::
WriteMidlOptions(std::string const& /*config*/,
std::vector<std::string> const & includes)
{
this->WriteString("<Midl>\n", 2);
this->OutputIncludes(includes);
// Need this stuff, but there is an midl.xml file...
// should we look for .idl language?, and flags?
/*
<MkTypLibCompatible>false</MkTypLibCompatible>
<TargetEnvironment>Win32</TargetEnvironment>
<GenerateStublessProxies>true</GenerateStublessProxies>
<TypeLibraryName>%(FileName).tlb</TypeLibraryName>
<OutputDirectory>$(IntDir)\</OutputDirectory>
<HeaderFileName>%(FileName).h</HeaderFileName>
<DllDataFileName>
</DllDataFileName>
<InterfaceIdentifierFileName>%(FileName)_i.c
</InterfaceIdentifierFileName>
<ProxyFileName>%(FileName)_p.c</ProxyFileName>
*/
this->WriteString("</Midl>\n", 2);
}
void cmVisualStudio10TargetGenerator::WriteItemDefinitionGroups()
{
std::vector<std::string> *configs =
static_cast<cmGlobalVisualStudio7Generator *>
(this->GlobalGenerator)->GetConfigurations();
std::vector<std::string> includes;
this->LocalGenerator->GetIncludeDirectories(includes);
for(std::vector<std::string>::iterator i = configs->begin();
i != configs->end(); ++i)
{
this->WritePlatformConfigTag("ItemDefinitionGroup", i->c_str(), 1);
*this->BuildFileStream << "\n";
// output cl compile flags <ClCompile></ClCompile>
if(this->Target->GetType() <= cmTarget::MODULE_LIBRARY)
{
this->WriteClOptions(*i, includes);
// output rc compile flags <ResourceCompile></ResourceCompile>
this->WriteRCOptions(*i, includes);
}
// output midl flags <Midl></Midl>
this->WriteMidlOptions(*i, includes);
// output link flags <Link></Link>
this->WriteLinkOptions(*i);
// output lib flags <Lib></Lib>
this->WriteLibOptions(*i);
this->WriteString("</ItemDefinitionGroup>\n", 1);
}
}
void cmVisualStudio10TargetGenerator::WriteProjectReferences()
{
// TODO
// This should have dependent targets listed like this:
/*
<ItemGroup>
<ProjectReference Include="ZERO_CHECK.vcxproj">
<Project>{2f1e4f3c-0a51-46c3-aaf9-e486599604f2}</Project>
</ProjectReference>
</ItemGroup>
*/
}