ENH: Reimplemented parsing and mapping of flags into vcproj file attribute options. This cleans up and centralizes a few things. It is in preparation for dealing with precompiled header flags for bug #3512 since they require some special handling.
This commit is contained in:
parent
d37abb6b5d
commit
d8aa12178d
@ -24,8 +24,11 @@
|
|||||||
#include "cmCacheManager.h"
|
#include "cmCacheManager.h"
|
||||||
#include "cmake.h"
|
#include "cmake.h"
|
||||||
|
|
||||||
|
#include <cmsys/System.h>
|
||||||
|
|
||||||
#include <ctype.h> // for isspace
|
#include <ctype.h> // for isspace
|
||||||
|
|
||||||
|
//----------------------------------------------------------------------------
|
||||||
cmLocalVisualStudio7Generator::cmLocalVisualStudio7Generator()
|
cmLocalVisualStudio7Generator::cmLocalVisualStudio7Generator()
|
||||||
{
|
{
|
||||||
this->Version = 7;
|
this->Version = 7;
|
||||||
@ -290,6 +293,11 @@ struct cmVS7FlagTable
|
|||||||
const char* value; // string value
|
const char* value; // string value
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// A statically allocated string so that user value options can be
|
||||||
|
// identified with a single pointer comparison and can never be
|
||||||
|
// confused with actual values.
|
||||||
|
static const char CMFLAG_USER_VALUE[] = "<USER_VALUE>";
|
||||||
|
|
||||||
// fill the table here currently the comment field is not used for
|
// fill the table here currently the comment field is not used for
|
||||||
// anything other than documentation NOTE: Make sure the longer
|
// anything other than documentation NOTE: Make sure the longer
|
||||||
// commandFlag comes FIRST!
|
// commandFlag comes FIRST!
|
||||||
@ -368,22 +376,47 @@ cmVS7FlagTable cmLocalVisualStudio7GeneratorLinkFlagTable[] =
|
|||||||
{"GenerateManifest", "MANIFEST", "enable manifest generation", "TRUE"},
|
{"GenerateManifest", "MANIFEST", "enable manifest generation", "TRUE"},
|
||||||
{"LinkIncremental", "INCREMENTAL:NO", "link incremental", "1"},
|
{"LinkIncremental", "INCREMENTAL:NO", "link incremental", "1"},
|
||||||
{"LinkIncremental", "INCREMENTAL:YES", "link incremental", "2"},
|
{"LinkIncremental", "INCREMENTAL:YES", "link incremental", "2"},
|
||||||
{"IgnoreDefaultLibraryNames", "NODEFAULTLIB:", "USER_VALUE", ""},
|
{"IgnoreDefaultLibraryNames", "NODEFAULTLIB:", "default libs to ignore",
|
||||||
|
CMFLAG_USER_VALUE},
|
||||||
{0,0,0,0 }
|
{0,0,0,0 }
|
||||||
};
|
};
|
||||||
|
|
||||||
|
//----------------------------------------------------------------------------
|
||||||
|
class cmLocalVisualStudio7GeneratorOptions
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
void cmLocalVisualStudio7Generator::WriteConfiguration(std::ostream& fout,
|
|
||||||
const char* configName,
|
|
||||||
const char *libName,
|
|
||||||
cmTarget &target)
|
|
||||||
{
|
{
|
||||||
|
public:
|
||||||
|
// Construct an options table for a given tool.
|
||||||
|
enum Tool
|
||||||
|
{
|
||||||
|
Compiler,
|
||||||
|
Linker
|
||||||
|
};
|
||||||
|
cmLocalVisualStudio7GeneratorOptions(Tool tool);
|
||||||
|
|
||||||
|
// Store options from command line flags.
|
||||||
|
void Parse(const char* flags);
|
||||||
|
|
||||||
|
// Store options for verbose builds.
|
||||||
|
void SetVerboseMakefile(bool verbose);
|
||||||
|
|
||||||
|
// Store definitions and flags.
|
||||||
|
void AddDefine(const std::string& define);
|
||||||
|
void AddFlag(const char* flag, const char* value);
|
||||||
|
|
||||||
|
// Check for specific options.
|
||||||
|
bool UsingUnicode();
|
||||||
|
bool UsingDebugPDB();
|
||||||
|
|
||||||
|
// Write options to output.
|
||||||
|
void OutputPreprocessorDefinitions(std::ostream& fout,
|
||||||
|
const char* prefix,
|
||||||
|
const char* suffix);
|
||||||
|
void OutputFlagMap(std::ostream& fout, const char* indent);
|
||||||
|
void OutputAdditionalOptions(std::ostream& fout,
|
||||||
|
const char* prefix,
|
||||||
|
const char* suffix);
|
||||||
|
|
||||||
|
private:
|
||||||
// create a map of xml tags to the values they should have in the output
|
// create a map of xml tags to the values they should have in the output
|
||||||
// for example, "BufferSecurityCheck" = "TRUE"
|
// for example, "BufferSecurityCheck" = "TRUE"
|
||||||
// first fill this table with the values for the configuration
|
// first fill this table with the values for the configuration
|
||||||
@ -391,11 +424,24 @@ void cmLocalVisualStudio7Generator::WriteConfiguration(std::ostream& fout,
|
|||||||
// Then parse the command line flags specified in CMAKE_CXX_FLAGS
|
// Then parse the command line flags specified in CMAKE_CXX_FLAGS
|
||||||
// and CMAKE_C_FLAGS
|
// and CMAKE_C_FLAGS
|
||||||
// and overwrite or add new values to this map
|
// and overwrite or add new values to this map
|
||||||
std::map<cmStdString, cmStdString> flagMap;
|
std::map<cmStdString, cmStdString> FlagMap;
|
||||||
// since the default is on for this, but if /EHsc is found
|
|
||||||
// in the flags it will be turned on and we have /EHSC on by
|
// Preprocessor definitions.
|
||||||
// default in the CXX flags, then this is the only way to turn this off
|
std::vector<cmStdString> Defines;
|
||||||
flagMap["ExceptionHandling"] = "FALSE";
|
|
||||||
|
// Unrecognized flags that get no special handling.
|
||||||
|
cmStdString FlagString;
|
||||||
|
|
||||||
|
bool DoingDefine;
|
||||||
|
cmVS7FlagTable const* FlagTable;
|
||||||
|
void HandleFlag(const char* flag);
|
||||||
|
};
|
||||||
|
|
||||||
|
void cmLocalVisualStudio7Generator::WriteConfiguration(std::ostream& fout,
|
||||||
|
const char* configName,
|
||||||
|
const char *libName,
|
||||||
|
cmTarget &target)
|
||||||
|
{
|
||||||
const char* mfcFlag = this->Makefile->GetDefinition("CMAKE_MFC_FLAG");
|
const char* mfcFlag = this->Makefile->GetDefinition("CMAKE_MFC_FLAG");
|
||||||
if(!mfcFlag)
|
if(!mfcFlag)
|
||||||
{
|
{
|
||||||
@ -470,6 +516,51 @@ void cmLocalVisualStudio7Generator::WriteConfiguration(std::ostream& fout,
|
|||||||
flags += targetFlags;
|
flags += targetFlags;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Get preprocessor definitions for this directory.
|
||||||
|
std::string defineFlags = this->Makefile->GetDefineFlags();
|
||||||
|
|
||||||
|
// Construct a set of build options for this target.
|
||||||
|
Options targetOptions(Options::Compiler);
|
||||||
|
targetOptions.Parse(flags.c_str());
|
||||||
|
targetOptions.Parse(defineFlags.c_str());
|
||||||
|
targetOptions.SetVerboseMakefile(
|
||||||
|
this->Makefile->IsOn("CMAKE_VERBOSE_MAKEFILE"));
|
||||||
|
|
||||||
|
// Add a definition for the configuration name.
|
||||||
|
std::string configDefine = "CMAKE_INTDIR=\\\"";
|
||||||
|
configDefine += configName;
|
||||||
|
configDefine += "\\\"";
|
||||||
|
targetOptions.AddDefine(configDefine);
|
||||||
|
|
||||||
|
// Add a definition for the export macro.
|
||||||
|
if(target.GetType() == cmTarget::SHARED_LIBRARY ||
|
||||||
|
target.GetType() == cmTarget::MODULE_LIBRARY)
|
||||||
|
{
|
||||||
|
std::string exportSymbol;
|
||||||
|
if(const char* custom_export_name = target.GetProperty("DEFINE_SYMBOL"))
|
||||||
|
{
|
||||||
|
exportSymbol = custom_export_name;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
std::string id = libName;
|
||||||
|
id += "_EXPORTS";
|
||||||
|
exportSymbol = cmSystemTools::MakeCindentifier(id.c_str());
|
||||||
|
}
|
||||||
|
targetOptions.AddDefine(exportSymbol);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Override the flag map with cmake-specific settings.
|
||||||
|
if(this->Makefile->IsOn("CMAKE_CXX_USE_RTTI"))
|
||||||
|
{
|
||||||
|
targetOptions.AddFlag("RuntimeTypeInfo", "TRUE");
|
||||||
|
}
|
||||||
|
if(const char* warningLevel =
|
||||||
|
this->Makefile->GetDefinition("CMAKE_CXX_WARNING_LEVEL"))
|
||||||
|
{
|
||||||
|
targetOptions.AddFlag("WarningLevel", warningLevel);
|
||||||
|
}
|
||||||
|
|
||||||
// The intermediate directory name consists of a directory for the
|
// The intermediate directory name consists of a directory for the
|
||||||
// target and a subdirectory for the configuration name.
|
// target and a subdirectory for the configuration name.
|
||||||
std::string intermediateDir = this->GetTargetDirectory(target);
|
std::string intermediateDir = this->GetTargetDirectory(target);
|
||||||
@ -481,12 +572,10 @@ void cmLocalVisualStudio7Generator::WriteConfiguration(std::ostream& fout,
|
|||||||
<< "\t\t\tConfigurationType=\"" << configType << "\"\n"
|
<< "\t\t\tConfigurationType=\"" << configType << "\"\n"
|
||||||
<< "\t\t\tUseOfMFC=\"" << mfcFlag << "\"\n"
|
<< "\t\t\tUseOfMFC=\"" << mfcFlag << "\"\n"
|
||||||
<< "\t\t\tATLMinimizesCRunTimeLibraryUsage=\"FALSE\"\n";
|
<< "\t\t\tATLMinimizesCRunTimeLibraryUsage=\"FALSE\"\n";
|
||||||
// if -D_UNICODE or /D_UNICODE is found in the flags
|
|
||||||
// change the character set to unicode, if not then
|
// If unicode is enabled change the character set to unicode, if not
|
||||||
// default to MBCS
|
// then default to MBCS.
|
||||||
std::string defs = this->Makefile->GetDefineFlags();
|
if(targetOptions.UsingUnicode())
|
||||||
if(flags.find("D_UNICODE") != flags.npos ||
|
|
||||||
defs.find("D_UNICODE") != flags.npos)
|
|
||||||
{
|
{
|
||||||
fout << "\t\t\tCharacterSet=\"1\">\n";
|
fout << "\t\t\tCharacterSet=\"1\">\n";
|
||||||
}
|
}
|
||||||
@ -496,25 +585,8 @@ void cmLocalVisualStudio7Generator::WriteConfiguration(std::ostream& fout,
|
|||||||
}
|
}
|
||||||
|
|
||||||
fout << "\t\t\t<Tool\n"
|
fout << "\t\t\t<Tool\n"
|
||||||
<< "\t\t\t\tName=\"VCCLCompilerTool\"\n"
|
<< "\t\t\t\tName=\"VCCLCompilerTool\"\n";
|
||||||
<< "\t\t\t\tAdditionalOptions=\"";
|
targetOptions.OutputAdditionalOptions(fout, "\t\t\t\t", "\n");
|
||||||
// now fill the flagMap from the command line flags, and
|
|
||||||
// if a flag is used, it will be removed from the flags string by
|
|
||||||
// this function call
|
|
||||||
this->FillFlagMapFromCommandFlags
|
|
||||||
(flagMap, &cmLocalVisualStudio7GeneratorFlagTable[0], flags);
|
|
||||||
std::string defineFlags = this->Makefile->GetDefineFlags();
|
|
||||||
|
|
||||||
// now check the define flags for flags other than -D and
|
|
||||||
// put them in the map, the -D flags will be left in the defineFlags
|
|
||||||
// variable as -D is not in the flagMap
|
|
||||||
this->FillFlagMapFromCommandFlags
|
|
||||||
(flagMap, &cmLocalVisualStudio7GeneratorFlagTable[0], defineFlags);
|
|
||||||
|
|
||||||
// output remaining flags that were not mapped to anything
|
|
||||||
fout << this->EscapeForXML(flags.c_str()).c_str();
|
|
||||||
fout << " -DCMAKE_INTDIR=\\"" << configName << "\\""
|
|
||||||
<< "\"\n";
|
|
||||||
fout << "\t\t\t\tAdditionalIncludeDirectories=\"";
|
fout << "\t\t\t\tAdditionalIncludeDirectories=\"";
|
||||||
std::vector<std::string> includes;
|
std::vector<std::string> includes;
|
||||||
this->GetIncludeDirectories(includes);
|
this->GetIncludeDirectories(includes);
|
||||||
@ -525,48 +597,11 @@ void cmLocalVisualStudio7Generator::WriteConfiguration(std::ostream& fout,
|
|||||||
fout << ipath << ";";
|
fout << ipath << ";";
|
||||||
}
|
}
|
||||||
fout << "\"\n";
|
fout << "\"\n";
|
||||||
// set a few cmake specific flags
|
targetOptions.OutputFlagMap(fout, "\t\t\t\t");
|
||||||
if(this->Makefile->IsOn("CMAKE_CXX_USE_RTTI"))
|
targetOptions.OutputPreprocessorDefinitions(fout, "\t\t\t\t", "\n");
|
||||||
{
|
|
||||||
flagMap["RuntimeTypeInfo"] = "TRUE";
|
|
||||||
}
|
|
||||||
if ( this->Makefile->GetDefinition("CMAKE_CXX_WARNING_LEVEL") )
|
|
||||||
{
|
|
||||||
flagMap["WarningLevel"] =
|
|
||||||
this->Makefile->GetDefinition("CMAKE_CXX_WARNING_LEVEL");
|
|
||||||
}
|
|
||||||
|
|
||||||
// Now copy the flag map into the xml for the file
|
|
||||||
for(std::map<cmStdString, cmStdString>::iterator m = flagMap.begin();
|
|
||||||
m != flagMap.end(); ++m)
|
|
||||||
{
|
|
||||||
fout << "\t\t\t\t" << m->first << "=\"" << m->second << "\"\n";
|
|
||||||
}
|
|
||||||
fout << "\t\t\t\tPreprocessorDefinitions=\"";
|
|
||||||
if(target.GetType() == cmTarget::SHARED_LIBRARY
|
|
||||||
|| target.GetType() == cmTarget::MODULE_LIBRARY)
|
|
||||||
{
|
|
||||||
std::string exportSymbol;
|
|
||||||
if (const char* custom_export_name =
|
|
||||||
target.GetProperty("DEFINE_SYMBOL"))
|
|
||||||
{
|
|
||||||
exportSymbol = custom_export_name;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
std::string id = libName;
|
|
||||||
id += "_EXPORTS";
|
|
||||||
exportSymbol = cmSystemTools::MakeCindentifier(id.c_str());
|
|
||||||
}
|
|
||||||
fout << "," << exportSymbol;
|
|
||||||
}
|
|
||||||
this->OutputDefineFlags(defineFlags.c_str(), fout);
|
|
||||||
fout << "\"\n";
|
|
||||||
fout << "\t\t\t\tAssemblerListingLocation=\"" << configName << "\"\n";
|
fout << "\t\t\t\tAssemblerListingLocation=\"" << configName << "\"\n";
|
||||||
fout << "\t\t\t\tObjectFile=\"$(IntDir)\\\"\n";
|
fout << "\t\t\t\tObjectFile=\"$(IntDir)\\\"\n";
|
||||||
std::map<cmStdString, cmStdString>::iterator mi =
|
if(targetOptions.UsingDebugPDB())
|
||||||
flagMap.find("DebugInformationFormat");
|
|
||||||
if(mi != flagMap.end() && mi->second != "1")
|
|
||||||
{
|
{
|
||||||
if(target.GetType() == cmTarget::EXECUTABLE)
|
if(target.GetType() == cmTarget::EXECUTABLE)
|
||||||
{
|
{
|
||||||
@ -605,15 +640,12 @@ void cmLocalVisualStudio7Generator::WriteConfiguration(std::ostream& fout,
|
|||||||
fout << ipath << ";";
|
fout << ipath << ";";
|
||||||
}
|
}
|
||||||
// add the -D flags to the RC tool
|
// add the -D flags to the RC tool
|
||||||
fout << "\"\n"
|
fout << "\"";
|
||||||
<< "\t\t\t\tPreprocessorDefinitions=\"";
|
targetOptions.OutputPreprocessorDefinitions(fout, "\n\t\t\t\t", "");
|
||||||
this->OutputDefineFlags(defineFlags.c_str(), fout);
|
fout << "/>\n";
|
||||||
fout << "\" />\n";
|
|
||||||
|
|
||||||
fout << "\t\t\t<Tool\n\t\t\t\tName=\"VCMIDLTool\"\n";
|
fout << "\t\t\t<Tool\n\t\t\t\tName=\"VCMIDLTool\"\n";
|
||||||
fout << "\t\t\t\tPreprocessorDefinitions=\"";
|
targetOptions.OutputPreprocessorDefinitions(fout, "\t\t\t\t", "\n");
|
||||||
this->OutputDefineFlags(defineFlags.c_str(), fout);
|
|
||||||
fout << "\"\n";
|
|
||||||
fout << "\t\t\t\tMkTypLibCompatible=\"FALSE\"\n";
|
fout << "\t\t\t\tMkTypLibCompatible=\"FALSE\"\n";
|
||||||
if( this->PlatformName == "x64" )
|
if( this->PlatformName == "x64" )
|
||||||
{
|
{
|
||||||
@ -651,84 +683,6 @@ void cmLocalVisualStudio7Generator::WriteConfiguration(std::ostream& fout,
|
|||||||
this->OutputBuildTool(fout, configName, target);
|
this->OutputBuildTool(fout, configName, target);
|
||||||
fout << "\t\t</Configuration>\n";
|
fout << "\t\t</Configuration>\n";
|
||||||
}
|
}
|
||||||
void cmLocalVisualStudio7Generator::ReplaceFlagSetMap(std::string& flags,
|
|
||||||
cmVS7FlagTable*
|
|
||||||
flagTable,
|
|
||||||
std::map<cmStdString,
|
|
||||||
cmStdString>& flagMap,
|
|
||||||
std::string& option,
|
|
||||||
std::string::size_type
|
|
||||||
pos)
|
|
||||||
{
|
|
||||||
std::string value = flagTable->value;
|
|
||||||
if(strcmp(flagTable->comment, "USER_VALUE") == 0)
|
|
||||||
{
|
|
||||||
std::string::size_type len = flags.find(" ", pos);
|
|
||||||
if(len != flags.npos)
|
|
||||||
{
|
|
||||||
len -= option.size();
|
|
||||||
}
|
|
||||||
value = flags.substr(pos+option.size(), len);
|
|
||||||
std::string fullflag = option;
|
|
||||||
fullflag += value;
|
|
||||||
// remove everything
|
|
||||||
cmSystemTools::ReplaceString(flags, fullflag.c_str(), "");
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
cmSystemTools::ReplaceString(flags, option.c_str(), "");
|
|
||||||
}
|
|
||||||
// now put value into flag map
|
|
||||||
|
|
||||||
flagMap[flagTable->IDEName] = value;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
void cmLocalVisualStudio7Generator::FillFlagMapFromCommandFlags(
|
|
||||||
std::map<cmStdString, cmStdString>& flagMap,
|
|
||||||
cmVS7FlagTable* flagTable,
|
|
||||||
std::string& flags)
|
|
||||||
{
|
|
||||||
std::string replace;
|
|
||||||
std::string option;
|
|
||||||
while(flagTable->IDEName)
|
|
||||||
{
|
|
||||||
option.reserve(strlen(flagTable->commandFlag)+2);
|
|
||||||
// first do the - version
|
|
||||||
option = "-";
|
|
||||||
option += flagTable->commandFlag;
|
|
||||||
std::string::size_type pos = flags.find(option);
|
|
||||||
while(pos != flags.npos)
|
|
||||||
{
|
|
||||||
this->ReplaceFlagSetMap(flags, flagTable, flagMap,
|
|
||||||
option, pos);
|
|
||||||
pos = flags.find(option);
|
|
||||||
}
|
|
||||||
// now do the / version
|
|
||||||
option[0] = '/';
|
|
||||||
pos = flags.find(option);
|
|
||||||
while(pos != flags.npos)
|
|
||||||
{
|
|
||||||
this->ReplaceFlagSetMap(flags, flagTable, flagMap,
|
|
||||||
option, pos);
|
|
||||||
pos = flags.find(option);
|
|
||||||
}
|
|
||||||
// move to next flag
|
|
||||||
flagTable++;
|
|
||||||
}
|
|
||||||
|
|
||||||
// If verbose makefiles have been requested and the /nologo option
|
|
||||||
// was not given explicitly in the flags we want to add an attribute
|
|
||||||
// to the generated project to disable logo suppression. Otherwise
|
|
||||||
// the GUI default is to enable suppression.
|
|
||||||
if(this->Makefile->IsOn("CMAKE_VERBOSE_MAKEFILE"))
|
|
||||||
{
|
|
||||||
if(flagMap.find("SuppressStartupBanner") == flagMap.end())
|
|
||||||
{
|
|
||||||
flagMap["SuppressStartupBanner"] = "FALSE";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
//----------------------------------------------------------------------------
|
//----------------------------------------------------------------------------
|
||||||
std::string
|
std::string
|
||||||
@ -789,10 +743,8 @@ void cmLocalVisualStudio7Generator::OutputBuildTool(std::ostream& fout,
|
|||||||
extraLinkOptions += " ";
|
extraLinkOptions += " ";
|
||||||
extraLinkOptions += targetLinkFlags;
|
extraLinkOptions += targetLinkFlags;
|
||||||
}
|
}
|
||||||
std::map<cmStdString, cmStdString> flagMap;
|
Options linkOptions(Options::Linker);
|
||||||
this->FillFlagMapFromCommandFlags
|
linkOptions.Parse(extraLinkOptions.c_str());
|
||||||
(flagMap, &cmLocalVisualStudio7GeneratorLinkFlagTable[0],
|
|
||||||
extraLinkOptions);
|
|
||||||
switch(target.GetType())
|
switch(target.GetType())
|
||||||
{
|
{
|
||||||
case cmTarget::STATIC_LIBRARY:
|
case cmTarget::STATIC_LIBRARY:
|
||||||
@ -855,17 +807,11 @@ void cmLocalVisualStudio7Generator::OutputBuildTool(std::ostream& fout,
|
|||||||
standardLibsVar += "_STANDARD_LIBRARIES";
|
standardLibsVar += "_STANDARD_LIBRARIES";
|
||||||
|
|
||||||
fout << "\t\t\t<Tool\n"
|
fout << "\t\t\t<Tool\n"
|
||||||
<< "\t\t\t\tName=\"VCLinkerTool\"\n"
|
<< "\t\t\t\tName=\"VCLinkerTool\"\n";
|
||||||
<< "\t\t\t\tAdditionalOptions=\"/MACHINE:I386";
|
linkOptions.OutputAdditionalOptions(fout, "\t\t\t\t", "\n");
|
||||||
if(extraLinkOptions.size())
|
|
||||||
{
|
|
||||||
fout << " " << cmLocalVisualStudio7Generator::EscapeForXML(
|
|
||||||
extraLinkOptions.c_str()).c_str();
|
|
||||||
}
|
|
||||||
// Use the NOINHERIT macro to avoid getting VS project default
|
// Use the NOINHERIT macro to avoid getting VS project default
|
||||||
// libraries which may be set by the user to something bad.
|
// libraries which may be set by the user to something bad.
|
||||||
fout << "\"\n"
|
fout << "\t\t\t\tAdditionalDependencies=\"$(NOINHERIT) "
|
||||||
<< "\t\t\t\tAdditionalDependencies=\"$(NOINHERIT) "
|
|
||||||
<< this->Makefile->GetSafeDefinition(standardLibsVar.c_str())
|
<< this->Makefile->GetSafeDefinition(standardLibsVar.c_str())
|
||||||
<< " ";
|
<< " ";
|
||||||
this->OutputLibraries(fout, linkLibs);
|
this->OutputLibraries(fout, linkLibs);
|
||||||
@ -877,11 +823,7 @@ void cmLocalVisualStudio7Generator::OutputBuildTool(std::ostream& fout,
|
|||||||
fout << "\t\t\t\tOutputFile=\""
|
fout << "\t\t\t\tOutputFile=\""
|
||||||
<< this->ConvertToXMLOutputPathSingle(temp.c_str()) << "\"\n";
|
<< this->ConvertToXMLOutputPathSingle(temp.c_str()) << "\"\n";
|
||||||
this->WriteTargetVersionAttribute(fout, target);
|
this->WriteTargetVersionAttribute(fout, target);
|
||||||
for(std::map<cmStdString, cmStdString>::iterator i = flagMap.begin();
|
linkOptions.OutputFlagMap(fout, "\t\t\t\t");
|
||||||
i != flagMap.end(); ++i)
|
|
||||||
{
|
|
||||||
fout << "\t\t\t\t" << i->first << "=\"" << i->second << "\"\n";
|
|
||||||
}
|
|
||||||
fout << "\t\t\t\tAdditionalLibraryDirectories=\"";
|
fout << "\t\t\t\tAdditionalLibraryDirectories=\"";
|
||||||
this->OutputLibraryDirectories(fout, linkDirs);
|
this->OutputLibraryDirectories(fout, linkDirs);
|
||||||
fout << "\"\n";
|
fout << "\"\n";
|
||||||
@ -943,17 +885,11 @@ void cmLocalVisualStudio7Generator::OutputBuildTool(std::ostream& fout,
|
|||||||
standardLibsVar += "_STANDARD_LIBRARIES";
|
standardLibsVar += "_STANDARD_LIBRARIES";
|
||||||
|
|
||||||
fout << "\t\t\t<Tool\n"
|
fout << "\t\t\t<Tool\n"
|
||||||
<< "\t\t\t\tName=\"VCLinkerTool\"\n"
|
<< "\t\t\t\tName=\"VCLinkerTool\"\n";
|
||||||
<< "\t\t\t\tAdditionalOptions=\"";
|
linkOptions.OutputAdditionalOptions(fout, "\t\t\t\t", "\n");
|
||||||
if(extraLinkOptions.size())
|
|
||||||
{
|
|
||||||
fout << " " << cmLocalVisualStudio7Generator::EscapeForXML(
|
|
||||||
extraLinkOptions.c_str()).c_str();
|
|
||||||
}
|
|
||||||
// Use the NOINHERIT macro to avoid getting VS project default
|
// Use the NOINHERIT macro to avoid getting VS project default
|
||||||
// libraries which may be set by the user to something bad.
|
// libraries which may be set by the user to something bad.
|
||||||
fout << "\"\n"
|
fout << "\t\t\t\tAdditionalDependencies=\"$(NOINHERIT) "
|
||||||
<< "\t\t\t\tAdditionalDependencies=\"$(NOINHERIT) "
|
|
||||||
<< this->Makefile->GetSafeDefinition(standardLibsVar.c_str())
|
<< this->Makefile->GetSafeDefinition(standardLibsVar.c_str())
|
||||||
<< " ";
|
<< " ";
|
||||||
this->OutputLibraries(fout, linkLibs);
|
this->OutputLibraries(fout, linkLibs);
|
||||||
@ -965,11 +901,7 @@ void cmLocalVisualStudio7Generator::OutputBuildTool(std::ostream& fout,
|
|||||||
fout << "\t\t\t\tOutputFile=\""
|
fout << "\t\t\t\tOutputFile=\""
|
||||||
<< this->ConvertToXMLOutputPathSingle(temp.c_str()) << "\"\n";
|
<< this->ConvertToXMLOutputPathSingle(temp.c_str()) << "\"\n";
|
||||||
this->WriteTargetVersionAttribute(fout, target);
|
this->WriteTargetVersionAttribute(fout, target);
|
||||||
for(std::map<cmStdString, cmStdString>::iterator i = flagMap.begin();
|
linkOptions.OutputFlagMap(fout, "\t\t\t\t");
|
||||||
i != flagMap.end(); ++i)
|
|
||||||
{
|
|
||||||
fout << "\t\t\t\t" << i->first << "=\"" << i->second << "\"\n";
|
|
||||||
}
|
|
||||||
fout << "\t\t\t\tAdditionalLibraryDirectories=\"";
|
fout << "\t\t\t\tAdditionalLibraryDirectories=\"";
|
||||||
this->OutputLibraryDirectories(fout, linkDirs);
|
this->OutputLibraryDirectories(fout, linkDirs);
|
||||||
fout << "\"\n";
|
fout << "\"\n";
|
||||||
@ -1087,63 +1019,6 @@ cmLocalVisualStudio7Generator
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//----------------------------------------------------------------------------
|
|
||||||
void cmLocalVisualStudio7Generator::OutputDefineFlags(const char* flags,
|
|
||||||
std::ostream& fout)
|
|
||||||
{
|
|
||||||
std::string defs = flags;
|
|
||||||
cmSystemTools::ReplaceString(defs, "/D","-D");
|
|
||||||
std::string::size_type pos = defs.find("-D");
|
|
||||||
bool done = pos == std::string::npos;
|
|
||||||
if(!done)
|
|
||||||
{
|
|
||||||
fout << ",";
|
|
||||||
}
|
|
||||||
while(!done)
|
|
||||||
{
|
|
||||||
std::string::size_type nextpos = defs.find("-D", pos+2);
|
|
||||||
std::string define;
|
|
||||||
if(nextpos != std::string::npos)
|
|
||||||
{
|
|
||||||
define = defs.substr(pos+2, nextpos - pos -3);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
define = defs.substr(pos+2);
|
|
||||||
done = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Remove trailing whitespace from the definition.
|
|
||||||
while(!define.empty() && isspace(define[define.size()-1]))
|
|
||||||
{
|
|
||||||
define = define.substr(0, define.size()-1);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Double-quotes in the value of the definition must be escaped
|
|
||||||
// with a backslash. The entire definition should be quoted in
|
|
||||||
// the generated xml attribute to avoid confusing the VS parser.
|
|
||||||
define = this->EscapeForXML(define.c_str());
|
|
||||||
// if the define has something in it that is not a letter or a number
|
|
||||||
// then quote it
|
|
||||||
if(define.
|
|
||||||
find_first_not_of(
|
|
||||||
"-_abcdefghigklmnopqrstuvwxyz1234567890ABCDEFGHIGKLMNOPQRSTUVWXYZ")
|
|
||||||
!= define.npos)
|
|
||||||
{
|
|
||||||
fout << """ << define << "",";
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
fout << define << ",";
|
|
||||||
}
|
|
||||||
if(!done)
|
|
||||||
{
|
|
||||||
pos = defs.find("-D", nextpos);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
void cmLocalVisualStudio7Generator::WriteVCProjFile(std::ostream& fout,
|
void cmLocalVisualStudio7Generator::WriteVCProjFile(std::ostream& fout,
|
||||||
const char *libName,
|
const char *libName,
|
||||||
cmTarget &target)
|
cmTarget &target)
|
||||||
@ -1342,28 +1217,14 @@ void cmLocalVisualStudio7Generator
|
|||||||
fout << ">\n";
|
fout << ">\n";
|
||||||
fout << "\t\t\t\t\t<Tool\n"
|
fout << "\t\t\t\t\t<Tool\n"
|
||||||
<< "\t\t\t\t\tName=\"" << aCompilerTool << "\"\n";
|
<< "\t\t\t\t\tName=\"" << aCompilerTool << "\"\n";
|
||||||
if(compileFlags.size())
|
if(!compileFlags.empty())
|
||||||
{
|
{
|
||||||
std::string compileFlagsCopy = compileFlags;
|
Options fileOptions(Options::Compiler);
|
||||||
std::map<cmStdString, cmStdString> fileFlagMap;
|
fileOptions.Parse(compileFlags.c_str());
|
||||||
this->FillFlagMapFromCommandFlags
|
fileOptions.OutputAdditionalOptions(fout, "\t\t\t\t\t", "\n");
|
||||||
(fileFlagMap,
|
fileOptions.OutputFlagMap(fout, "\t\t\t\t\t");
|
||||||
&cmLocalVisualStudio7GeneratorFlagTable[0],
|
fileOptions.OutputPreprocessorDefinitions(fout,
|
||||||
compileFlagsCopy);
|
"\t\t\t\t\t", "\n");
|
||||||
if(compileFlagsCopy.size() &&
|
|
||||||
compileFlagsCopy.find_first_not_of(" ")
|
|
||||||
!= compileFlagsCopy.npos)
|
|
||||||
{
|
|
||||||
fout << "\t\t\t\t\tAdditionalOptions=\""
|
|
||||||
<< this->EscapeForXML(compileFlagsCopy.c_str()) << "\"\n";
|
|
||||||
}
|
|
||||||
for(std::map<cmStdString,
|
|
||||||
cmStdString>::iterator m = fileFlagMap.begin();
|
|
||||||
m != fileFlagMap.end(); ++m)
|
|
||||||
{
|
|
||||||
fout << "\t\t\t\t\t" << m->first << "=\""
|
|
||||||
<< m->second << "\"\n";
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
if(additionalDeps.length())
|
if(additionalDeps.length())
|
||||||
{
|
{
|
||||||
@ -1649,8 +1510,7 @@ void cmLocalVisualStudio7Generator::WriteVCProjFooter(std::ostream& fout)
|
|||||||
<< "</VisualStudioProject>\n";
|
<< "</VisualStudioProject>\n";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::string cmLocalVisualStudio7GeneratorEscapeForXML(const char* s)
|
||||||
std::string cmLocalVisualStudio7Generator::EscapeForXML(const char* s)
|
|
||||||
{
|
{
|
||||||
std::string ret = s;
|
std::string ret = s;
|
||||||
cmSystemTools::ReplaceString(ret, "&", "&");
|
cmSystemTools::ReplaceString(ret, "&", "&");
|
||||||
@ -1661,6 +1521,11 @@ std::string cmLocalVisualStudio7Generator::EscapeForXML(const char* s)
|
|||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::string cmLocalVisualStudio7Generator::EscapeForXML(const char* s)
|
||||||
|
{
|
||||||
|
return cmLocalVisualStudio7GeneratorEscapeForXML(s);
|
||||||
|
}
|
||||||
|
|
||||||
std::string cmLocalVisualStudio7Generator
|
std::string cmLocalVisualStudio7Generator
|
||||||
::ConvertToXMLOutputPath(const char* path)
|
::ConvertToXMLOutputPath(const char* path)
|
||||||
{
|
{
|
||||||
@ -1794,3 +1659,233 @@ std::string cmLocalVisualStudio7Generator
|
|||||||
dir += ".dir";
|
dir += ".dir";
|
||||||
return dir;
|
return dir;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//----------------------------------------------------------------------------
|
||||||
|
cmLocalVisualStudio7GeneratorOptions
|
||||||
|
::cmLocalVisualStudio7GeneratorOptions(Tool tool):
|
||||||
|
DoingDefine(false), FlagTable(0)
|
||||||
|
{
|
||||||
|
// Choose the flag table for the requested tool.
|
||||||
|
switch(tool)
|
||||||
|
{
|
||||||
|
case Compiler:
|
||||||
|
this->FlagTable = cmLocalVisualStudio7GeneratorFlagTable; break;
|
||||||
|
case Linker:
|
||||||
|
this->FlagTable = cmLocalVisualStudio7GeneratorLinkFlagTable; break;
|
||||||
|
default: break;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Exception handling is on by default because the platform file has
|
||||||
|
// "/EHsc" in the flags. Normally, that will override this
|
||||||
|
// initialization to off, but the user has the option of removing
|
||||||
|
// the flag to disable exception handling. When the user does
|
||||||
|
// remove the flag we need to override the IDE default of on.
|
||||||
|
this->FlagMap["ExceptionHandling"] = "FALSE";
|
||||||
|
}
|
||||||
|
|
||||||
|
//----------------------------------------------------------------------------
|
||||||
|
void cmLocalVisualStudio7GeneratorOptions::SetVerboseMakefile(bool verbose)
|
||||||
|
{
|
||||||
|
// If verbose makefiles have been requested and the /nologo option
|
||||||
|
// was not given explicitly in the flags we want to add an attribute
|
||||||
|
// to the generated project to disable logo suppression. Otherwise
|
||||||
|
// the GUI default is to enable suppression.
|
||||||
|
if(verbose &&
|
||||||
|
this->FlagMap.find("SuppressStartupBanner") == this->FlagMap.end())
|
||||||
|
{
|
||||||
|
this->FlagMap["SuppressStartupBanner"] = "FALSE";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//----------------------------------------------------------------------------
|
||||||
|
void cmLocalVisualStudio7GeneratorOptions::AddDefine(const std::string& def)
|
||||||
|
{
|
||||||
|
this->Defines.push_back(def);
|
||||||
|
}
|
||||||
|
|
||||||
|
//----------------------------------------------------------------------------
|
||||||
|
void cmLocalVisualStudio7GeneratorOptions::AddFlag(const char* flag,
|
||||||
|
const char* value)
|
||||||
|
{
|
||||||
|
this->FlagMap[flag] = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
//----------------------------------------------------------------------------
|
||||||
|
bool cmLocalVisualStudio7GeneratorOptions::UsingUnicode()
|
||||||
|
{
|
||||||
|
// Look for the a _UNICODE definition.
|
||||||
|
bool use_unicode = false;
|
||||||
|
for(std::vector<cmStdString>::const_iterator di = this->Defines.begin();
|
||||||
|
di != this->Defines.end(); ++di)
|
||||||
|
{
|
||||||
|
if(*di == "_UNICODE")
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
//----------------------------------------------------------------------------
|
||||||
|
bool cmLocalVisualStudio7GeneratorOptions::UsingDebugPDB()
|
||||||
|
{
|
||||||
|
std::map<cmStdString, cmStdString>::iterator mi =
|
||||||
|
this->FlagMap.find("DebugInformationFormat");
|
||||||
|
if(mi != this->FlagMap.end() && mi->second != "1")
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//----------------------------------------------------------------------------
|
||||||
|
void cmLocalVisualStudio7GeneratorOptions::Parse(const char* flags)
|
||||||
|
{
|
||||||
|
// Parse the input string as a windows command line since the string
|
||||||
|
// is intended for writing directly into the build files.
|
||||||
|
std::vector<std::string> args;
|
||||||
|
cmSystemTools::ParseWindowsCommandLine(flags, args);
|
||||||
|
|
||||||
|
// Process flags that need to be represented specially in the IDE
|
||||||
|
// project file.
|
||||||
|
for(std::vector<std::string>::iterator ai = args.begin();
|
||||||
|
ai != args.end(); ++ai)
|
||||||
|
{
|
||||||
|
this->HandleFlag(ai->c_str());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//----------------------------------------------------------------------------
|
||||||
|
void cmLocalVisualStudio7GeneratorOptions::HandleFlag(const char* flag)
|
||||||
|
{
|
||||||
|
// If the last option was -D then this option is the definition.
|
||||||
|
if(this->DoingDefine)
|
||||||
|
{
|
||||||
|
this->DoingDefine = false;
|
||||||
|
this->Defines.push_back(flag);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Look for known arguments.
|
||||||
|
if(flag[0] == '-' || flag[0] == '/')
|
||||||
|
{
|
||||||
|
if(flag[1] == 'D')
|
||||||
|
{
|
||||||
|
if(flag[2] == '\0')
|
||||||
|
{
|
||||||
|
// The next argument will have the definition.
|
||||||
|
this->DoingDefine = true;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// Store this definition.
|
||||||
|
this->Defines.push_back(flag+2);
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
else if(this->FlagTable)
|
||||||
|
{
|
||||||
|
// Look for an entry in the flag table matching this flag.
|
||||||
|
for(cmVS7FlagTable const* entry = this->FlagTable;
|
||||||
|
entry->IDEName; ++entry)
|
||||||
|
{
|
||||||
|
if(entry->value == CMFLAG_USER_VALUE)
|
||||||
|
{
|
||||||
|
// This flag table entry accepts a user value.
|
||||||
|
int n = static_cast<int>(strlen(entry->commandFlag));
|
||||||
|
if(strncmp(flag+1, entry->commandFlag, n) == 0)
|
||||||
|
{
|
||||||
|
this->FlagMap[entry->IDEName] = flag+1+n;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if(strcmp(flag+1, entry->commandFlag) == 0)
|
||||||
|
{
|
||||||
|
// This flag table entry provides a fixed value.
|
||||||
|
this->FlagMap[entry->IDEName] = entry->value;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// This option is not known. Store it in the output flags.
|
||||||
|
this->FlagString += " ";
|
||||||
|
this->FlagString +=
|
||||||
|
cmSystemTools::EscapeWindowsShellArgument(flag,
|
||||||
|
cmsysSystem_Shell_Flag_VSIDE);
|
||||||
|
}
|
||||||
|
|
||||||
|
//----------------------------------------------------------------------------
|
||||||
|
void
|
||||||
|
cmLocalVisualStudio7GeneratorOptions
|
||||||
|
::OutputPreprocessorDefinitions(std::ostream& fout,
|
||||||
|
const char* prefix,
|
||||||
|
const char* suffix)
|
||||||
|
{
|
||||||
|
if(this->Defines.empty())
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
fout << prefix << "PreprocessorDefinitions=\"";
|
||||||
|
const char* comma = "";
|
||||||
|
for(std::vector<cmStdString>::const_iterator di = this->Defines.begin();
|
||||||
|
di != this->Defines.end(); ++di)
|
||||||
|
{
|
||||||
|
// Escape this flag for the IDE.
|
||||||
|
std::string define =
|
||||||
|
cmLocalVisualStudio7GeneratorEscapeForXML(di->c_str());
|
||||||
|
|
||||||
|
// Old comment:
|
||||||
|
// Double-quotes in the value of the definition must be escaped
|
||||||
|
// with a backslash. The entire definition should be quoted in
|
||||||
|
// the generated xml attribute to avoid confusing the VS parser.
|
||||||
|
|
||||||
|
// Write this flag. Quote it if the definition is not
|
||||||
|
// alphanumeric.
|
||||||
|
if(define.find_first_not_of(
|
||||||
|
"-_abcdefghigklmnopqrstuvwxyz1234567890ABCDEFGHIGKLMNOPQRSTUVWXYZ")
|
||||||
|
!= define.npos)
|
||||||
|
{
|
||||||
|
fout << comma << """ << define << """;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
fout << comma << define;
|
||||||
|
}
|
||||||
|
comma = ",";
|
||||||
|
}
|
||||||
|
fout << "\"" << suffix;
|
||||||
|
}
|
||||||
|
|
||||||
|
//----------------------------------------------------------------------------
|
||||||
|
void
|
||||||
|
cmLocalVisualStudio7GeneratorOptions
|
||||||
|
::OutputFlagMap(std::ostream& fout, const char* indent)
|
||||||
|
{
|
||||||
|
for(std::map<cmStdString, cmStdString>::iterator m = this->FlagMap.begin();
|
||||||
|
m != this->FlagMap.end(); ++m)
|
||||||
|
{
|
||||||
|
fout << indent << m->first << "=\"" << m->second << "\"\n";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//----------------------------------------------------------------------------
|
||||||
|
void
|
||||||
|
cmLocalVisualStudio7GeneratorOptions
|
||||||
|
::OutputAdditionalOptions(std::ostream& fout,
|
||||||
|
const char* prefix,
|
||||||
|
const char* suffix)
|
||||||
|
{
|
||||||
|
if(!this->FlagString.empty())
|
||||||
|
{
|
||||||
|
fout << prefix << "AdditionalOptions=\"";
|
||||||
|
fout <<
|
||||||
|
cmLocalVisualStudio7GeneratorEscapeForXML(this->FlagString.c_str());
|
||||||
|
fout << "\"" << suffix;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -26,6 +26,8 @@ class cmCustomCommand;
|
|||||||
class cmSourceGroup;
|
class cmSourceGroup;
|
||||||
struct cmVS7FlagTable;
|
struct cmVS7FlagTable;
|
||||||
|
|
||||||
|
class cmLocalVisualStudio7GeneratorOptions;
|
||||||
|
|
||||||
/** \class cmLocalVisualStudio7Generator
|
/** \class cmLocalVisualStudio7Generator
|
||||||
* \brief Write Visual Studio .NET project files.
|
* \brief Write Visual Studio .NET project files.
|
||||||
*
|
*
|
||||||
@ -65,6 +67,7 @@ public:
|
|||||||
void SetPlatformName(const char* n) { this->PlatformName = n;}
|
void SetPlatformName(const char* n) { this->PlatformName = n;}
|
||||||
virtual void ConfigureFinalPass();
|
virtual void ConfigureFinalPass();
|
||||||
private:
|
private:
|
||||||
|
typedef cmLocalVisualStudio7GeneratorOptions Options;
|
||||||
void ReadAndStoreExternalGUID(const char* name,
|
void ReadAndStoreExternalGUID(const char* name,
|
||||||
const char* path);
|
const char* path);
|
||||||
void ReplaceFlagSetMap(std::string& flags,
|
void ReplaceFlagSetMap(std::string& flags,
|
||||||
@ -96,8 +99,6 @@ private:
|
|||||||
std::string EscapeForXML(const char* s);
|
std::string EscapeForXML(const char* s);
|
||||||
std::string ConvertToXMLOutputPath(const char* path);
|
std::string ConvertToXMLOutputPath(const char* path);
|
||||||
std::string ConvertToXMLOutputPathSingle(const char* path);
|
std::string ConvertToXMLOutputPathSingle(const char* path);
|
||||||
void OutputDefineFlags(const char* flags,
|
|
||||||
std::ostream& fout);
|
|
||||||
void OutputTargetRules(std::ostream& fout, cmTarget &target,
|
void OutputTargetRules(std::ostream& fout, cmTarget &target,
|
||||||
const char *libName);
|
const char *libName);
|
||||||
void OutputBuildTool(std::ostream& fout, const char* configName,
|
void OutputBuildTool(std::ostream& fout, const char* configName,
|
||||||
|
Loading…
x
Reference in New Issue
Block a user