ENH: now target names can be used in add_custom_command() and

add_custom_target() as COMMAND, and cmake will recognize them and replace
them with the actual output path of these executables. Also the dependency
will be added automatically. Test included.
ENH: moved TraceVSDependencies() to the end of GlobalGenerator::Configure(),
so it is done now in one central place

Alex
This commit is contained in:
Alexander Neundorf 2007-05-09 08:25:45 -04:00
parent 5af3105021
commit 7f11536704
28 changed files with 400 additions and 205 deletions

View File

@ -69,8 +69,8 @@ public:
void SetEscapeAllowMakeVars(bool b);
/** set get the used status of the command */
void SetUsed() { this->Used = true;};
bool IsUsed() { return this->Used;};
void SetUsed() { this->Used = true;}
bool IsUsed() const { return this->Used;}
private:
std::vector<std::string> Outputs;

View File

@ -718,6 +718,13 @@ void cmGlobalGenerator::Configure()
// at this point this->LocalGenerators has been filled,
// so create the map from project name to vector of local generators
this->FillProjectMap();
// now create project to target map
// This will make sure that targets have all the
// targets they depend on as part of the build.
this->FillProjectToTargetMap();
// now trace all dependencies
this->TraceDependencies();
if ( !this->CMakeInstance->GetScriptMode() )
{
this->CMakeInstance->UpdateProgress("Configuring done", -1);
@ -1036,6 +1043,13 @@ const char* cmGlobalGenerator::GetLinkerPreference(const char* lang)
return "None";
}
void cmGlobalGenerator::TraceDependencies()
{
for (unsigned int i = 0; i < this->LocalGenerators.size(); ++i)
{
this->LocalGenerators[i]->TraceDependencies();
}
}
void cmGlobalGenerator::FillProjectMap()
{
@ -1057,10 +1071,6 @@ void cmGlobalGenerator::FillProjectMap()
}
while (lg);
}
// now create project to target map
// This will make sure that targets have all the
// targets they depend on as part of the build.
this->FillProjectToTargetMap();
}

View File

@ -202,6 +202,8 @@ protected:
void FillProjectMap();
bool IsExcluded(cmLocalGenerator* root, cmLocalGenerator* gen);
void FillProjectToTargetMap();
// Calls TraceVSDependencies() on all targets
void TraceDependencies();
void CreateDefaultGlobalTargets(cmTargets* targets);
cmTarget CreateGlobalTarget(const char* name, const char* message,
const cmCustomCommandLines* commandLines,

View File

@ -208,9 +208,8 @@ void cmGlobalVisualStudio6Generator
static_cast<cmLocalVisualStudio6Generator *>(generators[i])
->GetCreatedProjectNames();
cmTargets &tgts = generators[i]->GetMakefile()->GetTargets();
cmTargets::iterator l = tgts.begin();
for(std::vector<std::string>::iterator si = dspnames.begin();
l != tgts.end(); ++l)
std::vector<std::string>::iterator si = dspnames.begin();
for(cmTargets::iterator l = tgts.begin(); l != tgts.end(); ++l)
{
// special handling for the current makefile
if(mf == generators[0]->GetMakefile())

View File

@ -294,8 +294,7 @@ void cmGlobalVisualStudio7Generator
// than one dsp could have been created per input CMakeLists.txt file
// for each target
cmTargets &tgts = generators[i]->GetMakefile()->GetTargets();
cmTargets::iterator l = tgts.begin();
for(; l != tgts.end(); ++l)
for (cmTargets::iterator l = tgts.begin(); l != tgts.end(); ++l)
{
// special handling for the current makefile
if(mf == generators[0]->GetMakefile())

View File

@ -577,16 +577,17 @@ cmGlobalXCodeGenerator::CreateXCodeTargets(cmLocalGenerator* gen,
{
continue;
}
if(cmtarget.GetType() == cmTarget::UTILITY ||
cmtarget.GetType() == cmTarget::GLOBAL_TARGET ||
cmtarget.GetType() == cmTarget::INSTALL_FILES ||
cmtarget.GetType() == cmTarget::INSTALL_PROGRAMS)
{
if(cmtarget.GetType() == cmTarget::UTILITY ||
cmtarget.GetType() == cmTarget::GLOBAL_TARGET)
{
targets.push_back(this->CreateUtilityTarget(cmtarget));
}
if(cmtarget.GetType() == cmTarget::UTILITY ||
cmtarget.GetType() == cmTarget::GLOBAL_TARGET ||
cmtarget.GetType() == cmTarget::INSTALL_FILES ||
cmtarget.GetType() == cmTarget::INSTALL_PROGRAMS)
{
continue;
}
@ -849,6 +850,7 @@ std::string cmGlobalXCodeGenerator::ExtractFlag(const char* flag,
}
return retFlag;
}
//----------------------------------------------------------------------------
void
cmGlobalXCodeGenerator::AddCommandsToBuildPhase(cmXCodeObject* buildphase,
@ -872,7 +874,30 @@ cmGlobalXCodeGenerator::AddCommandsToBuildPhase(cmXCodeObject* buildphase,
return;
}
// collect multiple outputs of custom commands into a set
// which will be used for every configuration
std::map<cmStdString, cmStdString> multipleOutputPairs;
for(std::vector<cmCustomCommand>::const_iterator i = commands.begin();
i != commands.end(); ++i)
{
cmCustomCommand const& cc = *i;
if(!cc.GetCommandLines().empty())
{
const std::vector<std::string>& outputs = cc.GetOutputs();
if(!outputs.empty())
{
// If there are more than one outputs treat the
// first as the primary output and make the rest depend on it.
std::vector<std::string>::const_iterator o = outputs.begin();
std::string primaryOutput = this->ConvertToRelativeForMake(o->c_str());
for(++o; o != outputs.end(); ++o)
{
std::string currentOutput =this->ConvertToRelativeForMake(o->c_str());
multipleOutputPairs[currentOutput] = primaryOutput;
}
}
}
}
std::string dir = this->CurrentMakefile->GetCurrentOutputDirectory();
dir += "/CMakeScripts";
@ -883,7 +908,48 @@ cmGlobalXCodeGenerator::AddCommandsToBuildPhase(cmXCodeObject* buildphase,
makefile += "_";
makefile += name;
makefile += ".make";
cmGeneratedFileStream makefileStream(makefile.c_str());
for (std::vector<std::string>::const_iterator currentConfig=
this->CurrentConfigurationTypes.begin();
currentConfig!=this->CurrentConfigurationTypes.end();
currentConfig++ )
{
this->CreateCustomRulesMakefile(makefile.c_str(),
target,
commands,
currentConfig->c_str(),
multipleOutputPairs);
}
std::string cdir = this->CurrentMakefile->GetCurrentOutputDirectory();
cdir = this->ConvertToRelativeForXCode(cdir.c_str());
std::string makecmd = "make -C ";
makecmd += cdir;
makecmd += " -f ";
makecmd += this->ConvertToRelativeForMake((makefile+"$CONFIGURATION").c_str());
if(!multipleOutputPairs.empty())
{
makecmd += " cmake_check_multiple_outputs";
}
makecmd += " all";
cmSystemTools::ReplaceString(makecmd, "\\ ", "\\\\ ");
buildphase->AddAttribute("shellScript",
this->CreateString(makecmd.c_str()));
}
//----------------------------------------------------------------------------
void cmGlobalXCodeGenerator
::CreateCustomRulesMakefile(const char* makefileBasename,
cmTarget& target,
std::vector<cmCustomCommand>
const & commands,
const char* configName,
const std::map<cmStdString, cmStdString>& multipleOutputPairs
)
{
std::string makefileName=makefileBasename;
makefileName+=configName;
cmGeneratedFileStream makefileStream(makefileName.c_str());
if(!makefileStream)
{
return;
@ -939,21 +1005,9 @@ cmGlobalXCodeGenerator::AddCommandsToBuildPhase(cmXCodeObject* buildphase,
const std::vector<std::string>& outputs = cc.GetOutputs();
if(!outputs.empty())
{
// There is at least one output. If there is more than one treat the
// first as the primary output and make the rest depend on it.
std::vector<std::string>::const_iterator o = outputs.begin();
// There is at least one output, start the rule for it
std::string primary_output =
this->ConvertToRelativeForMake(o->c_str());
for(++o; o != outputs.end(); ++o)
{
std::string current_output =
this->ConvertToRelativeForMake(o->c_str());
makefileStream << current_output << ": "
<< primary_output << "\n";
multipleOutputPairs[current_output] = primary_output;
}
// Start the rule for the primary output.
this->ConvertToRelativeForMake(outputs.begin()->c_str());
makefileStream << primary_output << ": ";
}
else
@ -994,7 +1048,9 @@ cmGlobalXCodeGenerator::AddCommandsToBuildPhase(cmXCodeObject* buildphase,
{
// Build the command line in a single string.
const cmCustomCommandLine& commandLine = *cl;
std::string cmd2 = commandLine[0];
std::string cmd2 = this->CurrentLocalGenerator
->GetRealLocation(commandLine[0].c_str(), configName);
cmSystemTools::ReplaceString(cmd2, "/./", "/");
cmd2 = this->ConvertToRelativeForMake(cmd2.c_str());
std::string cmd;
@ -1025,9 +1081,18 @@ cmGlobalXCodeGenerator::AddCommandsToBuildPhase(cmXCodeObject* buildphase,
}
}
// Add a rule to deal with multiple outputs of custom commands.
// Add rules to deal with multiple outputs of custom commands.
if(!multipleOutputPairs.empty())
{
makefileStream <<
"\n# Dependencies of multiple outputs to their primary outputs \n";
for(std::map<cmStdString, cmStdString>::const_iterator o =
multipleOutputPairs.begin(); o != multipleOutputPairs.end(); ++o)
{
makefileStream << o->first << ": " << o->second << "\n";
}
makefileStream <<
"\n"
"cmake_check_multiple_outputs:\n";
@ -1039,24 +1104,8 @@ cmGlobalXCodeGenerator::AddCommandsToBuildPhase(cmXCodeObject* buildphase,
<< o->second << "; fi\n";
}
}
std::string cdir = this->CurrentMakefile->GetCurrentOutputDirectory();
cdir = this->ConvertToRelativeForXCode(cdir.c_str());
std::string makecmd = "make -C ";
makecmd += cdir;
makecmd += " -f ";
makecmd += this->ConvertToRelativeForMake(makefile.c_str());
if(!multipleOutputPairs.empty())
{
makecmd += " cmake_check_multiple_outputs";
}
makecmd += " all";
cmSystemTools::ReplaceString(makecmd, "\\ ", "\\\\ ");
buildphase->AddAttribute("shellScript",
this->CreateString(makecmd.c_str()));
}
//----------------------------------------------------------------------------
void cmGlobalXCodeGenerator::CreateBuildSettings(cmTarget& target,
cmXCodeObject* buildSettings,
@ -2406,20 +2455,6 @@ cmGlobalXCodeGenerator::OutputXCodeProject(cmLocalGenerator* root,
cmMakefile* mf = (*g)->GetMakefile();
std::vector<cmSourceGroup> sourceGroups = mf->GetSourceGroups();
cmTargets &tgts = mf->GetTargets();
// Call TraceVSDependencies on all targets
for(cmTargets::iterator l = tgts.begin();
l != tgts.end(); l++)
{
// INCLUDE_EXTERNAL_MSPROJECT command only affects the workspace
// so don't build a projectfile for it
if ((l->second.GetType() != cmTarget::INSTALL_FILES)
&& (l->second.GetType() != cmTarget::INSTALL_PROGRAMS)
&& (strncmp(l->first.c_str(), "INCLUDE_EXTERNAL_MSPROJECT", 26) != 0))
{
cmTarget& target = l->second;
target.TraceVSDependencies(target.GetName(), mf);
}
}
// now for all custom commands that are not used directly in a
// target, add them to all targets in the current directory or
// makefile

View File

@ -106,6 +106,15 @@ private:
std::vector<cmCustomCommand>
const & commands,
const char* commandFileName);
void CreateCustomRulesMakefile(const char* makefileBasename,
cmTarget& target,
std::vector<cmCustomCommand> const & commands,
const char* configName,
const std::map<cmStdString, cmStdString>&
multipleOutputPairs
);
cmXCodeObject* FindXCodeTarget(cmTarget*);
// create cmXCodeObject from these functions so that memory can be managed
// correctly. All objects created are stored in this->XCodeObjects.

View File

@ -52,6 +52,7 @@ cmLocalGenerator::cmLocalGenerator()
this->UseRelativePaths = false;
this->Configured = false;
this->EmitUniversalBinaryFlags = true;
this->IsMakefileGenerator = false;
this->RelativePathsConfigured = false;
this->PathConversionsSetup = false;
}
@ -135,6 +136,30 @@ void cmLocalGenerator::ConfigureFinalPass()
this->Makefile->ConfigureFinalPass();
}
void cmLocalGenerator::TraceDependencies()
{
// Generate the rule files for each target.
cmTargets& targets = this->Makefile->GetTargets();
for(cmTargets::iterator t = targets.begin(); t != targets.end(); ++t)
{
// INCLUDE_EXTERNAL_MSPROJECT command only affects the workspace
// so don't build a projectfile for it
if ((t->second.GetType() != cmTarget::INSTALL_FILES)
&& (t->second.GetType() != cmTarget::INSTALL_PROGRAMS)
&& (t->second.GetType() != cmTarget::INSTALL_DIRECTORY)
&& (strncmp(t->first.c_str(), "INCLUDE_EXTERNAL_MSPROJECT", 26) != 0)
&& (t->second.GetPropertyAsBool("IMPORTED") == false))
{
std::string projectFilename;
if (this->IsMakefileGenerator == false) // only use of this variable
{
projectFilename=t->second.GetName();
}
t->second.TraceVSDependencies(projectFilename, this->Makefile);
}
}
}
void cmLocalGenerator::GenerateTestFiles()
{
if ( !this->Makefile->IsOn("CMAKE_TESTING_ENABLED") )
@ -1986,6 +2011,20 @@ std::string cmLocalGenerator::GetRealDependency(const char* inName,
return name;
}
//----------------------------------------------------------------------------
std::string cmLocalGenerator::GetRealLocation(const char* inName,
const char* config)
{
std::string outName=inName;
// Look for a CMake target with the given name.
cmTarget* target = this->GlobalGenerator->FindTarget(0, inName);
if ((target!=0) && (target->GetType()==cmTarget::EXECUTABLE))
{
outName = target->GetLocation( config );
}
return outName;
}
//----------------------------------------------------------------------------
void cmLocalGenerator::AddSharedFlags(std::string& flags,
const char* lang,

View File

@ -42,7 +42,7 @@ public:
/**
* Generate the makefile for this directory.
*/
virtual void Generate() {};
virtual void Generate() {}
/**
* Process the CMakeLists files for this directory to fill in the
@ -50,6 +50,11 @@ public:
*/
virtual void Configure();
/**
* Calls TraceVSDependencies() on all targets of this generator.
*/
virtual void TraceDependencies();
/**
* Perform any final calculations prior to generation
*/
@ -138,6 +143,11 @@ public:
used for dependencies of custom commands. */
std::string GetRealDependency(const char* name, const char* config);
/** Translate a command as given in CMake code to the location of the
executable if the command is the name of a CMake executable target.
If that's not the case, just return the original name. */
std::string GetRealLocation(const char* inName, const char* config);
///! for existing files convert to output path and short path if spaces
std::string ConvertToOutputForExisting(const char* p);
@ -298,6 +308,8 @@ protected:
bool IgnoreLibPrefix;
bool Configured;
bool EmitUniversalBinaryFlags;
// A type flag is not nice. It's used only in TraceDependencies().
bool IsMakefileGenerator;
// Hack for ExpandRuleVariable until object-oriented version is
// committed.
std::string TargetImplib;

View File

@ -54,6 +54,7 @@ cmLocalUnixMakefileGenerator3::cmLocalUnixMakefileGenerator3()
this->NativeEchoCommand = "@echo ";
this->NativeEchoWindows = true;
this->MakeCommandEscapeTargetTwice = false;
this->IsMakefileGenerator = true;
}
//----------------------------------------------------------------------------
@ -112,7 +113,7 @@ void cmLocalUnixMakefileGenerator3::Generate()
if (tg)
{
this->TargetGenerators.push_back(tg);
t->second.TraceVSDependencies(empty, this->Makefile);
// t->second.TraceVSDependencies(empty, this->Makefile);
tg->WriteRuleFiles();
}
}
@ -885,7 +886,8 @@ cmLocalUnixMakefileGenerator3
{
// Build the command line in a single string.
const cmCustomCommandLine& commandLine = *cl;
std::string cmd = commandLine[0];
std::string cmd = GetRealLocation(commandLine[0].c_str(),
this->ConfigurationName.c_str());
if (cmd.size())
{
cmSystemTools::ReplaceString(cmd, "/./", "/");

View File

@ -116,16 +116,6 @@ void cmLocalVisualStudio6Generator::OutputDSPFile()
{
this->AddDSPBuildRule(l->second);
}
// INCLUDE_EXTERNAL_MSPROJECT command only affects the workspace
// so don't build a projectfile for it
if ((l->second.GetType() != cmTarget::INSTALL_FILES)
&& (l->second.GetType() != cmTarget::INSTALL_PROGRAMS)
&& (strncmp(l->first.c_str(), "INCLUDE_EXTERNAL_MSPROJECT", 26) != 0))
{
cmTarget& target = l->second;
target.TraceVSDependencies(target.GetName(), this->Makefile);
}
}
// build any targets
@ -490,23 +480,8 @@ void cmLocalVisualStudio6Generator
}
if (command)
{
std::string script =
this->ConstructScript(command->GetCommandLines(),
command->GetWorkingDirectory(),
command->GetEscapeOldStyle(),
command->GetEscapeAllowMakeVars(),
"\\\n\t");
std::string comment =
this->ConstructComment(*command,
"Building Custom Rule $(InputPath)");
if(comment == "<hack>")
{
comment = "";
}
const char* flags = compileFlags.size() ? compileFlags.c_str(): 0;
this->WriteCustomRule(fout, source.c_str(), script.c_str(),
comment.c_str(), command->GetDepends(),
command->GetOutputs(), flags);
this->WriteCustomRule(fout, source.c_str(), *command, flags);
}
else if(!compileFlags.empty() || !objectNameDir.empty())
{
@ -603,16 +578,29 @@ void
cmLocalVisualStudio6Generator
::WriteCustomRule(std::ostream& fout,
const char* source,
const char* command,
const char* comment,
const std::vector<std::string>& depends,
const std::vector<std::string>& outputs,
const cmCustomCommand& command,
const char* flags)
{
std::string comment =
this->ConstructComment(command, "Building Custom Rule $(InputPath)");
if(comment == "<hack>")
{
comment = "";
}
// Write the rule for each configuration.
std::vector<std::string>::iterator i;
for(i = this->Configurations.begin(); i != this->Configurations.end(); ++i)
{
std::string script =
this->ConstructScript(command.GetCommandLines(),
command.GetWorkingDirectory(),
i->c_str(),
command.GetEscapeOldStyle(),
command.GetEscapeAllowMakeVars(),
"\\\n\t");
if (i == this->Configurations.begin())
{
fout << "!IF \"$(CFG)\" == " << i->c_str() << std::endl;
@ -627,8 +615,9 @@ cmLocalVisualStudio6Generator
}
// Write out the dependencies for the rule.
fout << "USERDEP__HACK=";
for(std::vector<std::string>::const_iterator d = depends.begin();
d != depends.end(); ++d)
for(std::vector<std::string>::const_iterator d=command.GetDepends().begin();
d != command.GetDepends().end();
++d)
{
// Lookup the real name of the dependency in case it is a CMake target.
std::string dep = this->GetRealDependency(d->c_str(), i->c_str());
@ -639,26 +628,28 @@ cmLocalVisualStudio6Generator
fout << "# PROP Ignore_Default_Tool 1\n";
fout << "# Begin Custom Build -";
if(comment && *comment)
if(!comment.empty())
{
fout << " " << comment;
fout << " " << comment.c_str();
}
fout << "\n\n";
if(outputs.empty())
if(command.GetOutputs().empty())
{
fout << source
<< "_force : \"$(SOURCE)\" \"$(INTDIR)\" \"$(OUTDIR)\"\n\t";
fout << command << "\n\n";
fout << script.c_str() << "\n\n";
}
else
{
for(std::vector<std::string>::const_iterator o = outputs.begin();
o != outputs.end(); ++o)
for(std::vector<std::string>::const_iterator o =
command.GetOutputs().begin();
o != command.GetOutputs().end();
++o)
{
// Write a rule for every output generated by this command.
fout << this->ConvertToOptionallyRelativeOutputPath(o->c_str())
<< " : \"$(SOURCE)\" \"$(INTDIR)\" \"$(OUTDIR)\"\n\t";
fout << command << "\n\n";
fout << script.c_str() << "\n\n";
}
}
fout << "# End Custom Build\n\n";
@ -768,6 +759,7 @@ void cmLocalVisualStudio6Generator::SetBuildType(BuildType b,
// look for custom rules on a target and collect them together
std::string
cmLocalVisualStudio6Generator::CreateTargetRules(cmTarget &target,
const char* configName,
const char * /* libName */)
{
std::string customRuleCode = "";
@ -808,6 +800,7 @@ cmLocalVisualStudio6Generator::CreateTargetRules(cmTarget &target,
}
customRuleCode += this->ConstructScript(cr->GetCommandLines(),
cr->GetWorkingDirectory(),
configName,
cr->GetEscapeOldStyle(),
cr->GetEscapeAllowMakeVars(),
"\\\n\t");
@ -822,6 +815,7 @@ cmLocalVisualStudio6Generator::CreateTargetRules(cmTarget &target,
}
customRuleCode += this->ConstructScript(cr->GetCommandLines(),
cr->GetWorkingDirectory(),
configName,
cr->GetEscapeOldStyle(),
cr->GetEscapeAllowMakeVars(),
"\\\n\t");
@ -850,6 +844,7 @@ cmLocalVisualStudio6Generator::CreateTargetRules(cmTarget &target,
}
customRuleCode += this->ConstructScript(cr->GetCommandLines(),
cr->GetWorkingDirectory(),
configName,
cr->GetEscapeOldStyle(),
cr->GetEscapeAllowMakeVars(),
"\\\n\t");
@ -1274,7 +1269,14 @@ void cmLocalVisualStudio6Generator
// are there any custom rules on the target itself
// only if the target is a lib or exe
std::string customRuleCode = this->CreateTargetRules(target, libName);
std::string customRuleCodeRelease
= this->CreateTargetRules(target, "RELEASE", libName);
std::string customRuleCodeDebug
= this->CreateTargetRules(target, "DEBUG", libName);
std::string customRuleCodeMinSizeRel
= this->CreateTargetRules(target, "MINSIZEREL", libName);
std::string customRuleCodeRelWithDebInfo
= this->CreateTargetRules(target, "RELWITHDEBINFO", libName);
std::ifstream fin(this->DSPHeaderTemplate.c_str());
if(!fin)
@ -1307,8 +1309,6 @@ void cmLocalVisualStudio6Generator
}
cmSystemTools::ReplaceString(line, "OUTPUT_LIBNAME_EXPORTS",
exportSymbol.c_str());
cmSystemTools::ReplaceString(line, "CMAKE_CUSTOM_RULE_CODE",
customRuleCode.c_str());
cmSystemTools::ReplaceString(line, "CMAKE_MFC_FLAG",
mfcFlag);
if(target.GetType() == cmTarget::STATIC_LIBRARY )
@ -1338,6 +1338,18 @@ void cmLocalVisualStudio6Generator
libMultiLineOptimizedOptions.c_str());
#endif
// Substitute the rules for custom command. When specifying just the
// target name for the command the command can be different for
// different configs
cmSystemTools::ReplaceString(line, "CMAKE_CUSTOM_RULE_CODE_RELEASE",
customRuleCodeRelease.c_str());
cmSystemTools::ReplaceString(line, "CMAKE_CUSTOM_RULE_CODE_DEBUG",
customRuleCodeDebug.c_str());
cmSystemTools::ReplaceString(line, "CMAKE_CUSTOM_RULE_CODE_MINSIZEREL",
customRuleCodeMinSizeRel.c_str());
cmSystemTools::ReplaceString(line, "CMAKE_CUSTOM_RULE_CODE_RELWITHDEBINFO",
customRuleCodeRelWithDebInfo.c_str());
// Substitute the real output name into the template.
cmSystemTools::ReplaceString(line, "OUTPUT_NAME_DEBUG",
outputNameDebug.c_str());

View File

@ -84,10 +84,7 @@ private:
void AddDSPBuildRule(cmTarget& tgt);
void WriteCustomRule(std::ostream& fout,
const char* source,
const char* command,
const char* comment,
const std::vector<std::string>& depends,
const std::vector<std::string>& outputs,
const cmCustomCommand& command,
const char* flags);
void AddUtilityCommandHack(cmTarget& target, int count,
std::vector<std::string>& depends,
@ -95,6 +92,7 @@ private:
void WriteGroup(const cmSourceGroup *sg, cmTarget target,
std::ostream &fout, const char *libName);
std::string CreateTargetRules(cmTarget &target,
const char* configName,
const char *libName);
void ComputeLinkOptions(cmTarget& target, const char* configName,
const std::string extraOptions,

View File

@ -124,16 +124,6 @@ void cmLocalVisualStudio7Generator::OutputVCProjFile()
{
this->AddVCProjBuildRule(l->second);
}
// INCLUDE_EXTERNAL_MSPROJECT command only affects the workspace
// so don't build a projectfile for it
if ((l->second.GetType() != cmTarget::INSTALL_FILES)
&& (l->second.GetType() != cmTarget::INSTALL_PROGRAMS)
&& (strncmp(l->first.c_str(), "INCLUDE_EXTERNAL_MSPROJECT", 26) != 0))
{
cmTarget& target = l->second;
target.TraceVSDependencies(target.GetName(), this->Makefile);
}
}
for(cmTargets::iterator l = tgts.begin();
@ -623,7 +613,7 @@ void cmLocalVisualStudio7Generator::WriteConfiguration(std::ostream& fout,
<< "\t\t\t/>\n";
}
this->OutputTargetRules(fout, target, libName);
this->OutputTargetRules(fout, configName, target, libName);
this->OutputBuildTool(fout, configName, target);
fout << "\t\t</Configuration>\n";
}
@ -1141,17 +1131,8 @@ void cmLocalVisualStudio7Generator
fout << "\t\t\t\tRelativePath=\"" << d << "\">\n";
if (command)
{
// Construct the entire set of commands in one string.
std::string script =
this->ConstructScript(command->GetCommandLines(),
command->GetWorkingDirectory(),
command->GetEscapeOldStyle(),
command->GetEscapeAllowMakeVars());
std::string comment = this->ConstructComment(*command);
const char* flags = compileFlags.size() ? compileFlags.c_str(): 0;
this->WriteCustomRule(fout, source.c_str(), script.c_str(),
comment.c_str(), command->GetDepends(),
command->GetOutputs(), flags);
this->WriteCustomRule(fout, source.c_str(), *command, flags);
}
else if(compileFlags.size() || additionalDeps.length()
|| objectName.size() || excludedFromBuild)
@ -1228,12 +1209,11 @@ void cmLocalVisualStudio7Generator
void cmLocalVisualStudio7Generator::
WriteCustomRule(std::ostream& fout,
const char* source,
const char* command,
const char* comment,
const std::vector<std::string>& depends,
const std::vector<std::string>& outputs,
const cmCustomCommand& command,
const char* compileFlags)
{
std::string comment = this->ConstructComment(command);
// Write the rule for each configuration.
std::vector<std::string>::iterator i;
std::vector<std::string> *configs =
@ -1251,14 +1231,21 @@ WriteCustomRule(std::ostream& fout,
<< "\t\t\t\t\tAdditionalOptions=\""
<< this->EscapeForXML(compileFlags) << "\"/>\n";
}
std::string script =
this->ConstructScript(command.GetCommandLines(),
command.GetWorkingDirectory(),
i->c_str(),
command.GetEscapeOldStyle(),
command.GetEscapeAllowMakeVars());
fout << "\t\t\t\t\t<Tool\n"
<< "\t\t\t\t\tName=\"VCCustomBuildTool\"\n"
<< "\t\t\t\t\tDescription=\""
<< this->EscapeForXML(comment) << "\"\n"
<< this->EscapeForXML(comment.c_str()) << "\"\n"
<< "\t\t\t\t\tCommandLine=\""
<< this->EscapeForXML(command) << "\"\n"
<< this->EscapeForXML(script.c_str()) << "\"\n"
<< "\t\t\t\t\tAdditionalDependencies=\"";
if(depends.empty())
if(command.GetDepends().empty())
{
// There are no real dependencies. Produce an artificial one to
// make sure the rule runs reliably.
@ -1272,8 +1259,10 @@ WriteCustomRule(std::ostream& fout,
else
{
// Write out the dependencies for the rule.
for(std::vector<std::string>::const_iterator d = depends.begin();
d != depends.end(); ++d)
for(std::vector<std::string>::const_iterator d =
command.GetDepends().begin();
d != command.GetDepends().end();
++d)
{
// Get the real name of the dependency in case it is a CMake target.
std::string dep = this->GetRealDependency(d->c_str(), i->c_str());
@ -1283,7 +1272,7 @@ WriteCustomRule(std::ostream& fout,
}
fout << "\"\n";
fout << "\t\t\t\t\tOutputs=\"";
if(outputs.empty())
if(command.GetOutputs().empty())
{
fout << source << "_force";
}
@ -1291,8 +1280,9 @@ WriteCustomRule(std::ostream& fout,
{
// Write a rule for the output generated by this command.
const char* sep = "";
for(std::vector<std::string>::const_iterator o = outputs.begin();
o != outputs.end(); ++o)
for(std::vector<std::string>::const_iterator o = command.GetOutputs().begin();
o != command.GetOutputs().end();
++o)
{
fout << sep << this->ConvertToXMLOutputPathSingle(o->c_str());
sep = ";";
@ -1323,6 +1313,7 @@ void cmLocalVisualStudio7Generator::WriteVCProjEndGroup(std::ostream& fout)
// look for custom rules on a target and collect them together
void cmLocalVisualStudio7Generator
::OutputTargetRules(std::ostream& fout,
const char* configName,
cmTarget &target,
const char * /*libName*/)
{
@ -1350,6 +1341,7 @@ void cmLocalVisualStudio7Generator
std::string script =
this->ConstructScript(cr->GetCommandLines(),
cr->GetWorkingDirectory(),
configName,
cr->GetEscapeOldStyle(),
cr->GetEscapeAllowMakeVars());
fout << this->EscapeForXML(script.c_str()).c_str();
@ -1379,6 +1371,7 @@ void cmLocalVisualStudio7Generator
std::string script =
this->ConstructScript(cr->GetCommandLines(),
cr->GetWorkingDirectory(),
configName,
cr->GetEscapeOldStyle(),
cr->GetEscapeAllowMakeVars());
fout << this->EscapeForXML(script.c_str()).c_str();
@ -1408,6 +1401,7 @@ void cmLocalVisualStudio7Generator
std::string script =
this->ConstructScript(cr->GetCommandLines(),
cr->GetWorkingDirectory(),
configName,
cr->GetEscapeOldStyle(),
cr->GetEscapeAllowMakeVars());
fout << this->EscapeForXML(script.c_str()).c_str();

View File

@ -89,8 +89,8 @@ private:
std::string EscapeForXML(const char* s);
std::string ConvertToXMLOutputPath(const char* path);
std::string ConvertToXMLOutputPathSingle(const char* path);
void OutputTargetRules(std::ostream& fout, cmTarget &target,
const char *libName);
void OutputTargetRules(std::ostream& fout, const char* configName,
cmTarget &target, const char *libName);
void OutputBuildTool(std::ostream& fout, const char* configName,
cmTarget& t);
void OutputLibraries(std::ostream& fout,
@ -104,12 +104,10 @@ private:
const char* group,
const char* filter);
void WriteVCProjEndGroup(std::ostream& fout);
void WriteCustomRule(std::ostream& fout,
const char* source,
const char* command,
const char* comment,
const std::vector<std::string>& depends,
const std::vector<std::string>& outputs,
const cmCustomCommand& command,
const char* extraFlags);
void WriteTargetVersionAttribute(std::ostream& fout, cmTarget& target);

View File

@ -111,6 +111,7 @@ std::string
cmLocalVisualStudioGenerator
::ConstructScript(const cmCustomCommandLines& commandLines,
const char* workingDirectory,
const char* configName,
bool escapeOldStyle,
bool escapeAllowMakeVars,
const char* newline_text)
@ -152,13 +153,15 @@ cmLocalVisualStudioGenerator
// Start with the command name.
const cmCustomCommandLine& commandLine = *cl;
std::string commandName = this->GetRealLocation(commandLine[0].c_str(),
configName);
if(!workingDirectory)
{
script += this->Convert(commandLine[0].c_str(),START_OUTPUT,SHELL);
script += this->Convert(commandName.c_str(),START_OUTPUT,SHELL);
}
else
{
script += this->Convert(commandLine[0].c_str(),NONE,SHELL);
script += this->Convert(commandName.c_str(),NONE,SHELL);
}
// Add the arguments.

View File

@ -41,6 +41,7 @@ protected:
/** Construct a script from the given list of command lines. */
std::string ConstructScript(const cmCustomCommandLines& commandLines,
const char* workingDirectory,
const char* configName,
bool escapeOldStyle,
bool escapeAllowMakeVars,
const char* newline = "\n");

View File

@ -578,18 +578,6 @@ cmMakefile::AddCustomCommandToTarget(const char* target,
ti->second.GetPostBuildCommands().push_back(cc);
break;
}
// Add dependencies on commands CMake knows how to build.
for(cmCustomCommandLines::const_iterator cli = commandLines.begin();
cli != commandLines.end(); ++cli)
{
std::string cacheCommand = *cli->begin();
if(const char* knownTarget =
this->GetCacheManager()->GetCacheValue(cacheCommand.c_str()))
{
ti->second.AddUtility(knownTarget);
}
}
}
}

View File

@ -408,6 +408,31 @@ void cmTarget::SetMakefile(cmMakefile* mf)
}
}
void
cmTarget::checkForTargetsAsCommand(const std::vector<cmCustomCommand>& commands)
{
for ( std::vector<cmCustomCommand>::const_iterator cli = commands.begin();
cli != commands.end();
++cli )
{
for ( cmCustomCommandLines::const_iterator cit=cli->GetCommandLines().begin();
cit!=cli->GetCommandLines().end();
++cit )
{
std::string command = *cit->begin();
// see if we can find a target with this name
cmTarget* t = this->Makefile->GetLocalGenerator()->
GetGlobalGenerator()->FindTarget ( 0, command.c_str() );
if ( ( t ) && ( t->GetType() ==cmTarget::EXECUTABLE ) )
{
this->AddUtility ( command.c_str() );
}
}
}
}
void cmTarget::TraceVSDependencies(std::string projFile,
cmMakefile *makefile)
{
@ -504,6 +529,11 @@ void cmTarget::TraceVSDependencies(std::string projFile,
}
}
}
checkForTargetsAsCommand(this->GetPreBuildCommands());
checkForTargetsAsCommand(this->GetPreLinkCommands());
checkForTargetsAsCommand(this->GetPostBuildCommands());
while (!srcFilesToProcess.empty())
{
// is this source the output of a custom command
@ -533,9 +563,28 @@ void cmTarget::TraceVSDependencies(std::string projFile,
srcFilesQueued.insert(temp);
}
}
// check if commands for this custom commands are names of targets and
// if that's the case add these targets as dependencies
std::vector<std::string> automaticTargetDepends;
for(cmCustomCommandLines::const_iterator it=
outsf->GetCustomCommand()->GetCommandLines().begin();
it!=outsf->GetCustomCommand()->GetCommandLines().end();
++it)
{
const std::string& currentCommand = (*it)[0];
// see if we can find a target with this name
cmTarget* t = this->Makefile->GetLocalGenerator()->
GetGlobalGenerator()->FindTarget(0, currentCommand.c_str());
if (( t) && (t->GetType()==cmTarget::EXECUTABLE))
{
automaticTargetDepends.push_back(currentCommand);
}
}
outsf->GetCustomCommand()->AppendDepends(automaticTargetDepends);
// add its dependencies to the list to check
unsigned int i;
for (i = 0; i < outsf->GetCustomCommand()->GetDepends().size(); ++i)
for (unsigned int i = 0; i < outsf->GetCustomCommand()->GetDepends().size(); ++i)
{
const std::string& fullName
= outsf->GetCustomCommand()->GetDepends()[i];
@ -590,6 +639,7 @@ void cmTarget::TraceVSDependencies(std::string projFile,
}
}
}
}
// finished with this SF move to the next
srcFilesToProcess.pop();

View File

@ -55,7 +55,7 @@ public:
void SetType(TargetType f, const char* name);
///! Set/Get the name of the target
const char* GetName() {return this->Name.c_str();}
const char* GetName() const {return this->Name.c_str();}
///! Set the cmMakefile that owns this target
void SetMakefile(cmMakefile *mf);
@ -180,7 +180,7 @@ public:
/**
* Trace through the source files in this target and add al source files
* that they depend on, used by the visual studio generators
* that they depend on, used by all generators
*/
void TraceVSDependencies(std::string projName, cmMakefile *mf);
@ -291,6 +291,13 @@ private:
const LibraryID& lib,
const LibraryID& dep);
/*
* Checks the prebuild, prelink and postbuild custom commands for known
* targets and adds them to the dependencies.
*/
void checkForTargetsAsCommand(const std::vector<cmCustomCommand>& commands);
/**
* Emits the library \a lib and all its dependencies into link_line.
* \a emitted keeps track of the libraries that have been emitted to

View File

@ -74,7 +74,7 @@ LINK32=link.exe
# ADD LINK32 /nologo /dll TARGET_VERSION_FLAG /machine:I386 /out:"OUTPUT_DIRECTORY\Release/OUTPUT_NAME_RELEASE" TARGET_IMPLIB_FLAG_RELEASE
CM_MULTILINE_OPTIONS_RELEASE
CMAKE_CUSTOM_RULE_CODE
CMAKE_CUSTOM_RULE_CODE_RELEASE
!ELSEIF "$(CFG)" == "OUTPUT_LIBNAME - Win32 Debug"
@ -106,7 +106,7 @@ LINK32=link.exe
# ADD LINK32 /nologo /dll TARGET_VERSION_FLAG /debug /machine:I386 /out:"OUTPUT_DIRECTORY\Debug/OUTPUT_NAME_DEBUG" /pdbtype:sept TARGET_IMPLIB_FLAG_DEBUG
CM_MULTILINE_OPTIONS_DEBUG
CMAKE_CUSTOM_RULE_CODE
CMAKE_CUSTOM_RULE_CODE_DEBUG
!ELSEIF "$(CFG)" == "OUTPUT_LIBNAME - Win32 MinSizeRel"
@ -140,7 +140,7 @@ LINK32=link.exe
# ADD LINK32 /nologo /dll TARGET_VERSION_FLAG /machine:I386 /out:"OUTPUT_DIRECTORY\MinSizeRel/OUTPUT_NAME_MINSIZEREL" TARGET_IMPLIB_FLAG_MINSIZEREL
CM_MULTILINE_OPTIONS_MINSIZEREL
CMAKE_CUSTOM_RULE_CODE
CMAKE_CUSTOM_RULE_CODE_MINSIZEREL
!ELSEIF "$(CFG)" == "OUTPUT_LIBNAME - Win32 RelWithDebInfo"
@ -172,7 +172,7 @@ LINK32=link.exe
# ADD LINK32 /nologo /dll TARGET_VERSION_FLAG /debug /machine:I386 /pdbtype:sept /out:"OUTPUT_DIRECTORY\RelWithDebInfo/OUTPUT_NAME_RELWITHDEBINFO" TARGET_IMPLIB_FLAG_RELWITHDEBINFO
CM_MULTILINE_OPTIONS_RELWITHDEBINFO
CMAKE_CUSTOM_RULE_CODE
CMAKE_CUSTOM_RULE_CODE_RELWITHDEBINFO
!ENDIF

View File

@ -72,7 +72,7 @@ LINK32=link.exe
# ADD LINK32 /out:"OUTPUT_DIRECTORY\Release\OUTPUT_NAME_RELEASE" TARGET_IMPLIB_FLAG_RELEASE
CM_MULTILINE_OPTIONS_RELEASE
CMAKE_CUSTOM_RULE_CODE
CMAKE_CUSTOM_RULE_CODE_RELEASE
!ELSEIF "$(CFG)" == "OUTPUT_LIBNAME - Win32 Debug"
@ -104,7 +104,7 @@ LINK32=link.exe
# ADD LINK32 /out:"OUTPUT_DIRECTORY\Debug\OUTPUT_NAME_DEBUG" TARGET_IMPLIB_FLAG_DEBUG
CM_MULTILINE_OPTIONS_DEBUG
CMAKE_CUSTOM_RULE_CODE
CMAKE_CUSTOM_RULE_CODE_DEBUG
!ELSEIF "$(CFG)" == "OUTPUT_LIBNAME - Win32 MinSizeRel"
# PROP BASE Use_MFC CMAKE_MFC_FLAG
@ -133,7 +133,7 @@ LINK32=link.exe
# ADD LINK32 /out:"OUTPUT_DIRECTORY\MinSizeRel\OUTPUT_NAME_MINSIZEREL" TARGET_IMPLIB_FLAG_MINSIZEREL
CM_MULTILINE_OPTIONS_MINSIZEREL
CMAKE_CUSTOM_RULE_CODE
CMAKE_CUSTOM_RULE_CODE_MINSIZEREL
!ELSEIF "$(CFG)" == "OUTPUT_LIBNAME - Win32 RelWithDebInfo"
@ -163,7 +163,7 @@ LINK32=link.exe
# ADD LINK32 /out:"OUTPUT_DIRECTORY\RelWithDebInfo\OUTPUT_NAME_RELWITHDEBINFO" TARGET_IMPLIB_FLAG_RELWITHDEBINFO
CM_MULTILINE_OPTIONS_RELWITHDEBINFO
CMAKE_CUSTOM_RULE_CODE
CMAKE_CUSTOM_RULE_CODE_RELWITHDEBINFO
!ENDIF

View File

@ -74,7 +74,7 @@ LINK32=link.exe
# ADD LINK32 /out:"OUTPUT_DIRECTORY\Release\OUTPUT_NAME_RELEASE"
CM_MULTILINE_OPTIONS_RELEASE
CMAKE_CUSTOM_RULE_CODE
CMAKE_CUSTOM_RULE_CODE_RELEASE
!ELSEIF "$(CFG)" == "OUTPUT_LIBNAME - Win32 Debug"
@ -106,7 +106,7 @@ LINK32=link.exe
# ADD LINK32 /out:"OUTPUT_DIRECTORY\Debug\OUTPUT_NAME_DEBUG"
CM_MULTILINE_OPTIONS_DEBUG
CMAKE_CUSTOM_RULE_CODE
CMAKE_CUSTOM_RULE_CODE_DEBUG
!ELSEIF "$(CFG)" == "OUTPUT_LIBNAME - Win32 MinSizeRel"
# PROP BASE Use_MFC CMAKE_MFC_FLAG
@ -135,7 +135,7 @@ LINK32=link.exe
# ADD LINK32 /out:"OUTPUT_DIRECTORY\MinSizeRel\OUTPUT_NAME_MINSIZEREL"
CM_MULTILINE_OPTIONS_MINSIZEREL
CMAKE_CUSTOM_RULE_CODE
CMAKE_CUSTOM_RULE_CODE_MINSIZEREL
!ELSEIF "$(CFG)" == "OUTPUT_LIBNAME - Win32 RelWithDebInfo"
@ -167,7 +167,7 @@ LINK32=link.exe
# ADD LINK32 /out:"OUTPUT_DIRECTORY\RelWithDebInfo\OUTPUT_NAME_RELWITHDEBINFO"
CM_MULTILINE_OPTIONS_RELWITHDEBINFO
CMAKE_CUSTOM_RULE_CODE
CMAKE_CUSTOM_RULE_CODE_RELWITHDEBINFO
!ENDIF

View File

@ -42,7 +42,7 @@ MTL=midl.exe
# PROP Intermediate_Dir "Release"
# PROP Target_Dir ""
CMAKE_CUSTOM_RULE_CODE
CMAKE_CUSTOM_RULE_CODE_RELEASE
!ELSEIF "$(CFG)" == "OUTPUT_LIBNAME - Win32 Debug"
@ -57,7 +57,7 @@ CMAKE_CUSTOM_RULE_CODE
# PROP Intermediate_Dir "Debug"
# PROP Target_Dir ""
CMAKE_CUSTOM_RULE_CODE
CMAKE_CUSTOM_RULE_CODE_DEBUG
!ELSEIF "$(CFG)" == "OUTPUT_LIBNAME - Win32 MinSizeRel"
@ -72,7 +72,7 @@ CMAKE_CUSTOM_RULE_CODE
# PROP Intermediate_Dir "MinSizeRel"
# PROP Target_Dir ""
CMAKE_CUSTOM_RULE_CODE
CMAKE_CUSTOM_RULE_CODE_MINSIZEREL
!ELSEIF "$(CFG)" == "OUTPUT_LIBNAME - Win32 RelWithDebInfo"
@ -87,7 +87,7 @@ CMAKE_CUSTOM_RULE_CODE
# PROP Intermediate_Dir "RelWithDebInfo"
# PROP Target_Dir ""
CMAKE_CUSTOM_RULE_CODE
CMAKE_CUSTOM_RULE_CODE_RELWITHDEBINFO
!ENDIF

View File

@ -67,7 +67,7 @@ LIB32=link.exe -lib
# ADD BASE LIB32 /nologo
# ADD LIB32 /nologo /out:"OUTPUT_DIRECTORY\Release/OUTPUT_NAME_RELEASE" CM_STATIC_LIB_ARGS
CMAKE_CUSTOM_RULE_CODE
CMAKE_CUSTOM_RULE_CODE_RELEASE
!ELSEIF "$(CFG)" == "OUTPUT_LIBNAME - Win32 Debug"
@ -95,7 +95,7 @@ LIB32=link.exe -lib
# ADD BASE LIB32 /nologo
# ADD LIB32 /nologo /out:"OUTPUT_DIRECTORY\Debug/OUTPUT_NAME_DEBUG" CM_STATIC_LIB_ARGS
CMAKE_CUSTOM_RULE_CODE
CMAKE_CUSTOM_RULE_CODE_DEBUG
!ELSEIF "$(CFG)" == "OUTPUT_LIBNAME - Win32 MinSizeRel"
@ -124,7 +124,7 @@ LIB32=link.exe -lib
# ADD BASE LIB32 /nologo
# ADD LIB32 /nologo /out:"OUTPUT_DIRECTORY\MinSizeRel/OUTPUT_NAME_MINSIZEREL" CM_STATIC_LIB_ARGS
CMAKE_CUSTOM_RULE_CODE
CMAKE_CUSTOM_RULE_CODE_MINSIZEREL
!ELSEIF "$(CFG)" == "OUTPUT_LIBNAME - Win32 RelWithDebInfo"
@ -152,7 +152,7 @@ LIB32=link.exe -lib
# ADD BASE LIB32 /nologo
# ADD LIB32 /nologo /out:"OUTPUT_DIRECTORY\RelWithDebInfo/OUTPUT_NAME_RELWITHDEBINFO" CM_STATIC_LIB_ARGS
CMAKE_CUSTOM_RULE_CODE
CMAKE_CUSTOM_RULE_CODE_RELWITHDEBINFO
!ENDIF

View File

@ -167,6 +167,31 @@ TARGET_LINK_LIBRARIES(CustomCommand GeneratedHeader)
# the CustomCommand executable really needs doc1.h
ADD_DEPENDENCIES(CustomCommand TDocument)
##############################################################################
# Test for using just the target name as executable in the COMMAND
# section. Has to be recognized and replaced by CMake with the output
# actual location of the executable.
# Additionally the generator is created in an extra subdir after the
# ADD_CUSTOM_COMMAND() is used.
#
# Test the same for ADD_CUSTOM_TARGET()
ADD_CUSTOM_COMMAND(OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/generated_extern.cxx
COMMAND generator_extern ${CMAKE_CURRENT_BINARY_DIR}/generated_extern.cxx
)
ADD_EXECUTABLE(CustomCommandUsingTargetTest main.cxx ${CMAKE_CURRENT_BINARY_DIR}/generated_extern.cxx )
ADD_CUSTOM_TARGET(RunTarget
COMMAND generator_extern ${CMAKE_CURRENT_BINARY_DIR}/run_target.cxx
)
ADD_CUSTOM_COMMAND(TARGET CustomCommandUsingTargetTest POST_BUILD
COMMAND dummy_generator ${CMAKE_CURRENT_BINARY_DIR}/generated_dummy.cxx)
ADD_SUBDIRECTORY(GeneratorInExtraDir)
##############################################################################
# Test non-trivial command line arguments in custom commands.
SET(EXPECTED_ARGUMENTS)

View File

@ -0,0 +1,6 @@
# add the executable which will be used for generating files
ADD_EXECUTABLE(generator_extern ../generator.cxx)
SET_TARGET_PROPERTIES(generator_extern PROPERTIES OUTPUT_NAME the_external_generator)
# add an executable which will be called from ADD_CUSTOM_COMMAND( ... POST_BUILD)
ADD_EXECUTABLE(dummy_generator ../generator.cxx)

View File

@ -0,0 +1,6 @@
extern int generated();
int main()
{
return generated();
}