From 035c7fabc3b82cbc9a346c11abe2e9462b4c0379 Mon Sep 17 00:00:00 2001 From: Anas Nashif Date: Tue, 30 Oct 2012 15:39:57 -0700 Subject: Imported Upstream version 2.8.9 --- Source/cmLocalVisualStudio6Generator.cxx | 1904 ++++++++++++++++++++++++++++++ 1 file changed, 1904 insertions(+) create mode 100644 Source/cmLocalVisualStudio6Generator.cxx (limited to 'Source/cmLocalVisualStudio6Generator.cxx') diff --git a/Source/cmLocalVisualStudio6Generator.cxx b/Source/cmLocalVisualStudio6Generator.cxx new file mode 100644 index 000000000..5ab223b7e --- /dev/null +++ b/Source/cmLocalVisualStudio6Generator.cxx @@ -0,0 +1,1904 @@ +/*============================================================================ + CMake - Cross Platform Makefile Generator + Copyright 2000-2009 Kitware, Inc., Insight Software Consortium + + Distributed under the OSI-approved BSD License (the "License"); + see accompanying file Copyright.txt for details. + + This software is distributed WITHOUT ANY WARRANTY; without even the + implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + See the License for more information. +============================================================================*/ +#include "cmGlobalGenerator.h" +#include "cmLocalVisualStudio6Generator.h" +#include "cmMakefile.h" +#include "cmSystemTools.h" +#include "cmSourceFile.h" +#include "cmCacheManager.h" +#include "cmGeneratorTarget.h" +#include "cmake.h" + +#include "cmComputeLinkInformation.h" + +#include + +cmLocalVisualStudio6Generator::cmLocalVisualStudio6Generator(): + cmLocalVisualStudioGenerator(VS6) +{ +} + +cmLocalVisualStudio6Generator::~cmLocalVisualStudio6Generator() +{ +} + +//---------------------------------------------------------------------------- +// Helper class to write build events. +class cmLocalVisualStudio6Generator::EventWriter +{ +public: + EventWriter(cmLocalVisualStudio6Generator* lg, + const char* config, std::string& code): + LG(lg), Config(config), Code(code), First(true) {} + void Start(const char* event) + { + this->First = true; + this->Event = event; + } + void Finish() + { + this->Code += (this->First? "" : "\n"); + } + void Write(std::vector const& ccs) + { + for(std::vector::const_iterator ci = ccs.begin(); + ci != ccs.end(); ++ci) + { + this->Write(*ci); + } + } + void Write(cmCustomCommand const& cc) + { + if(this->First) + { + this->Code += this->Event + "_Cmds="; + this->First = false; + } + else + { + this->Code += "\\\n\t"; + } + this->Code += this->LG->ConstructScript(cc, this->Config, "\\\n\t"); + } +private: + cmLocalVisualStudio6Generator* LG; + const char* Config; + std::string& Code; + bool First; + std::string Event; +}; + +void cmLocalVisualStudio6Generator::AddHelperCommands() +{ + std::set lang; + lang.insert("C"); + lang.insert("CXX"); + this->CreateCustomTargetsAndCommands(lang); +} + +void cmLocalVisualStudio6Generator::AddCMakeListsRules() +{ + cmTargets &tgts = this->Makefile->GetTargets(); + for(cmTargets::iterator l = tgts.begin(); + l != tgts.end(); l++) + { + // Add a rule to regenerate the build system when the target + // specification source changes. + const char* suppRegenRule = + this->Makefile->GetDefinition("CMAKE_SUPPRESS_REGENERATION"); + if (!cmSystemTools::IsOn(suppRegenRule)) + { + this->AddDSPBuildRule(l->second); + } + } +} + +void cmLocalVisualStudio6Generator::Generate() +{ + this->OutputDSPFile(); +} + +void cmLocalVisualStudio6Generator::OutputDSPFile() +{ + // If not an in source build, then create the output directory + if(strcmp(this->Makefile->GetStartOutputDirectory(), + this->Makefile->GetHomeDirectory()) != 0) + { + if(!cmSystemTools::MakeDirectory + (this->Makefile->GetStartOutputDirectory())) + { + cmSystemTools::Error("Error creating directory ", + this->Makefile->GetStartOutputDirectory()); + } + } + + // Create the DSP or set of DSP's for libraries and executables + + cmTargets &tgts = this->Makefile->GetTargets(); + + // build any targets + for(cmTargets::iterator l = tgts.begin(); + l != tgts.end(); l++) + { + switch(l->second.GetType()) + { + case cmTarget::STATIC_LIBRARY: + case cmTarget::OBJECT_LIBRARY: + this->SetBuildType(STATIC_LIBRARY, l->first.c_str(), l->second); + break; + case cmTarget::SHARED_LIBRARY: + case cmTarget::MODULE_LIBRARY: + this->SetBuildType(DLL, l->first.c_str(), l->second); + break; + case cmTarget::EXECUTABLE: + this->SetBuildType(EXECUTABLE,l->first.c_str(), l->second); + break; + case cmTarget::UTILITY: + case cmTarget::GLOBAL_TARGET: + this->SetBuildType(UTILITY, l->first.c_str(), l->second); + break; + default: + cmSystemTools::Error("Bad target type", l->first.c_str()); + break; + } + // INCLUDE_EXTERNAL_MSPROJECT command only affects the workspace + // so don't build a projectfile for it + const char* path = + l->second.GetProperty("EXTERNAL_MSPROJECT"); + if(!path) + { + // check to see if the dsp is going into a sub-directory + std::string::size_type pos = l->first.rfind('/'); + if(pos != std::string::npos) + { + std::string dir = this->Makefile->GetStartOutputDirectory(); + dir += "/"; + dir += l->first.substr(0, pos); + if(!cmSystemTools::MakeDirectory(dir.c_str())) + { + cmSystemTools::Error("Error creating directory ", dir.c_str()); + } + } + this->CreateSingleDSP(l->first.c_str(),l->second); + } + } +} + +// Utility function to make a valid VS6 *.dsp filename out +// of a CMake target name: +// +extern std::string GetVS6TargetName(const std::string& targetName); + +void cmLocalVisualStudio6Generator::CreateSingleDSP(const char *lname, + cmTarget &target) +{ + // add to the list of projects + std::string pname = GetVS6TargetName(lname); + + // create the dsp.cmake file + std::string fname; + fname = this->Makefile->GetStartOutputDirectory(); + fname += "/"; + fname += pname; + fname += ".dsp"; + // save the name of the real dsp file + std::string realDSP = fname; + fname += ".cmake"; + std::ofstream fout(fname.c_str()); + if(!fout) + { + cmSystemTools::Error("Error Writing ", fname.c_str()); + cmSystemTools::ReportLastSystemError(""); + } + this->WriteDSPFile(fout,pname.c_str(),target); + fout.close(); + // if the dsp file has changed, then write it. + cmSystemTools::CopyFileIfDifferent(fname.c_str(), realDSP.c_str()); +} + + +void cmLocalVisualStudio6Generator::AddDSPBuildRule(cmTarget& tgt) +{ + std::string dspname = GetVS6TargetName(tgt.GetName()); + dspname += ".dsp.cmake"; + const char* dsprule = + this->Makefile->GetRequiredDefinition("CMAKE_COMMAND"); + cmCustomCommandLine commandLine; + commandLine.push_back(dsprule); + std::string makefileIn = this->Makefile->GetStartDirectory(); + makefileIn += "/"; + makefileIn += "CMakeLists.txt"; + if(!cmSystemTools::FileExists(makefileIn.c_str())) + { + return; + } + std::string comment = "Building Custom Rule "; + comment += makefileIn; + std::string args; + args = "-H"; + args += this->Convert(this->Makefile->GetHomeDirectory(), + START_OUTPUT, UNCHANGED, true); + commandLine.push_back(args); + args = "-B"; + args += + this->Convert(this->Makefile->GetHomeOutputDirectory(), + START_OUTPUT, UNCHANGED, true); + commandLine.push_back(args); + + std::vector const& listFiles = this->Makefile->GetListFiles(); + + cmCustomCommandLines commandLines; + commandLines.push_back(commandLine); + const char* no_working_directory = 0; + this->Makefile->AddCustomCommandToOutput(dspname.c_str(), listFiles, + makefileIn.c_str(), commandLines, + comment.c_str(), + no_working_directory, true); + if(cmSourceFile* file = this->Makefile->GetSource(makefileIn.c_str())) + { + tgt.AddSourceFile(file); + } + else + { + cmSystemTools::Error("Error adding rule for ", makefileIn.c_str()); + } +} + + +void cmLocalVisualStudio6Generator::WriteDSPFile(std::ostream& fout, + const char *libName, + cmTarget &target) +{ + // For utility targets need custom command since pre- and post- + // build does not do anything in Visual Studio 6. In order for the + // rules to run in the correct order as custom commands, we need + // special care for dependencies. The first rule must depend on all + // the dependencies of all the rules. The later rules must each + // depend only on the previous rule. + if ((target.GetType() == cmTarget::UTILITY || + target.GetType() == cmTarget::GLOBAL_TARGET) && + (!target.GetPreBuildCommands().empty() || + !target.GetPostBuildCommands().empty())) + { + // Accumulate the dependencies of all the commands. + std::vector depends; + for (std::vector::const_iterator cr = + target.GetPreBuildCommands().begin(); + cr != target.GetPreBuildCommands().end(); ++cr) + { + depends.insert(depends.end(), + cr->GetDepends().begin(), cr->GetDepends().end()); + } + for (std::vector::const_iterator cr = + target.GetPostBuildCommands().begin(); + cr != target.GetPostBuildCommands().end(); ++cr) + { + depends.insert(depends.end(), + cr->GetDepends().begin(), cr->GetDepends().end()); + } + + // Add the pre- and post-build commands in order. + int count = 1; + for (std::vector::const_iterator cr = + target.GetPreBuildCommands().begin(); + cr != target.GetPreBuildCommands().end(); ++cr) + { + this->AddUtilityCommandHack(target, count++, depends, *cr); + } + for (std::vector::const_iterator cr = + target.GetPostBuildCommands().begin(); + cr != target.GetPostBuildCommands().end(); ++cr) + { + this->AddUtilityCommandHack(target, count++, depends, *cr); + } + } + + // We may be modifying the source groups temporarily, so make a copy. + std::vector sourceGroups = this->Makefile->GetSourceGroups(); + + // get the classes from the source lists then add them to the groups + std::vector const & classes = target.GetSourceFiles(); + + // now all of the source files have been properly assigned to the target + // now stick them into source groups using the reg expressions + for(std::vector::const_iterator i = classes.begin(); + i != classes.end(); i++) + { + // Add the file to the list of sources. + std::string source = (*i)->GetFullPath(); + cmSourceGroup& sourceGroup = + this->Makefile->FindSourceGroup(source.c_str(), sourceGroups); + sourceGroup.AssignSource(*i); + // while we are at it, if it is a .rule file then for visual studio 6 we + // must generate it + if ((*i)->GetPropertyAsBool("__CMAKE_RULE")) + { + if(!cmSystemTools::FileExists(source.c_str())) + { + cmSystemTools::ReplaceString(source, "$(IntDir)/", ""); +#if defined(_WIN32) || defined(__CYGWIN__) + std::ofstream fout(source.c_str(), + std::ios::binary | std::ios::out + | std::ios::trunc); +#else + std::ofstream fout(source.c_str(), + std::ios::out | std::ios::trunc); +#endif + if(fout) + { + fout.write("# generated from CMake",22); + fout.flush(); + fout.close(); + } + } + } + } + + // Write the DSP file's header. + this->WriteDSPHeader(fout, libName, target, sourceGroups); + + + // Loop through every source group. + for(std::vector::const_iterator sg = sourceGroups.begin(); + sg != sourceGroups.end(); ++sg) + { + this->WriteGroup(&(*sg), target, fout, libName); + } + + // Write the DSP file's footer. + this->WriteDSPFooter(fout); +} + +void cmLocalVisualStudio6Generator +::WriteGroup(const cmSourceGroup *sg, cmTarget& target, + std::ostream &fout, const char *libName) +{ + cmGeneratorTarget* gt = + this->GlobalGenerator->GetGeneratorTarget(&target); + const std::vector &sourceFiles = + sg->GetSourceFiles(); + // If the group is empty, don't write it at all. + + if(sourceFiles.empty() && sg->GetGroupChildren().empty()) + { + return; + } + + // If the group has a name, write the header. + std::string name = sg->GetName(); + if(name != "") + { + this->WriteDSPBeginGroup(fout, name.c_str(), ""); + } + + // Loop through each source in the source group. + for(std::vector::const_iterator sf = + sourceFiles.begin(); sf != sourceFiles.end(); ++sf) + { + std::string source = (*sf)->GetFullPath(); + const cmCustomCommand *command = + (*sf)->GetCustomCommand(); + std::string compileFlags; + std::vector depends; + std::string objectNameDir; + if(gt->ExplicitObjectName.find(*sf) != gt->ExplicitObjectName.end()) + { + objectNameDir = cmSystemTools::GetFilenamePath(gt->Objects[*sf]); + } + + // Add per-source file flags. + if(const char* cflags = (*sf)->GetProperty("COMPILE_FLAGS")) + { + compileFlags += cflags; + } + + const char* lang = this->GetSourceFileLanguage(*(*sf)); + if(lang) + { + if(strcmp(lang, "CXX") == 0) + { + // force a C++ file type + compileFlags += " /TP "; + } + else if(strcmp(lang, "C") == 0) + { + // force to c file type + compileFlags += " /TC "; + } + } + + // Add per-source and per-configuration preprocessor definitions. + std::map cdmap; + this->AppendDefines(compileFlags, + (*sf)->GetProperty("COMPILE_DEFINITIONS"), lang); + if(const char* cdefs = (*sf)->GetProperty("COMPILE_DEFINITIONS_DEBUG")) + { + this->AppendDefines(cdmap["DEBUG"], cdefs, lang); + } + if(const char* cdefs = (*sf)->GetProperty("COMPILE_DEFINITIONS_RELEASE")) + { + this->AppendDefines(cdmap["RELEASE"], cdefs, lang); + } + if(const char* cdefs = + (*sf)->GetProperty("COMPILE_DEFINITIONS_MINSIZEREL")) + { + this->AppendDefines(cdmap["MINSIZEREL"], cdefs, lang); + } + if(const char* cdefs = + (*sf)->GetProperty("COMPILE_DEFINITIONS_RELWITHDEBINFO")) + { + this->AppendDefines(cdmap["RELWITHDEBINFO"], cdefs, lang); + } + + bool excludedFromBuild = + (lang && (*sf)->GetPropertyAsBool("HEADER_FILE_ONLY")); + + // Check for extra object-file dependencies. + const char* dependsValue = (*sf)->GetProperty("OBJECT_DEPENDS"); + if(dependsValue) + { + cmSystemTools::ExpandListArgument(dependsValue, depends); + } + if (GetVS6TargetName(source) != libName || + target.GetType() == cmTarget::UTILITY || + target.GetType() == cmTarget::GLOBAL_TARGET) + { + fout << "# Begin Source File\n\n"; + + // Tell MS-Dev what the source is. If the compiler knows how to + // build it, then it will. + fout << "SOURCE=" << + this->ConvertToOptionallyRelativeOutputPath(source.c_str()) << "\n\n"; + if(!depends.empty()) + { + // Write out the dependencies for the rule. + fout << "USERDEP__HACK="; + for(std::vector::const_iterator d = depends.begin(); + d != depends.end(); ++d) + { + fout << "\\\n\t" << + this->ConvertToOptionallyRelativeOutputPath(d->c_str()); + } + fout << "\n"; + } + if (command) + { + const char* flags = compileFlags.size() ? compileFlags.c_str(): 0; + this->WriteCustomRule(fout, source.c_str(), *command, flags); + } + else if(!compileFlags.empty() || !objectNameDir.empty() || + excludedFromBuild || !cdmap.empty()) + { + for(std::vector::iterator i + = this->Configurations.begin(); + i != this->Configurations.end(); ++i) + { + // Strip the subdirectory name out of the configuration name. + std::string config = this->GetConfigName(*i); + if (i == this->Configurations.begin()) + { + fout << "!IF \"$(CFG)\" == " << i->c_str() << std::endl; + } + else + { + fout << "!ELSEIF \"$(CFG)\" == " << i->c_str() << std::endl; + } + if(excludedFromBuild) + { + fout << "# PROP Exclude_From_Build 1\n"; + } + if(!compileFlags.empty()) + { + fout << "\n# ADD CPP " << compileFlags << "\n\n"; + } + std::map::iterator cdi = + cdmap.find(cmSystemTools::UpperCase(config)); + if(cdi != cdmap.end() && !cdi->second.empty()) + { + fout << "\n# ADD CPP " << cdi->second << "\n\n"; + } + if(!objectNameDir.empty()) + { + // Setup an alternate object file directory. + fout << "\n# PROP Intermediate_Dir \"" + << config << "/" << objectNameDir << "\"\n\n"; + } + } + fout << "!ENDIF\n\n"; + } + fout << "# End Source File\n"; + } + } + + std::vector const& children = sg->GetGroupChildren(); + + for(unsigned int i=0;iWriteGroup(&children[i], target, fout, libName); + } + + + + + // If the group has a name, write the footer. + if(name != "") + { + this->WriteDSPEndGroup(fout); + } + +} + + +void +cmLocalVisualStudio6Generator +::AddUtilityCommandHack(cmTarget& target, int count, + std::vector& depends, + const cmCustomCommand& origCommand) +{ + // Create a fake output that forces the rule to run. + char* output = new char[(strlen(this->Makefile->GetStartOutputDirectory()) + + strlen(target.GetName()) + 30)]; + sprintf(output,"%s/%s_force_%i", this->Makefile->GetStartOutputDirectory(), + target.GetName(), count); + std::string comment = this->ConstructComment(origCommand, ""); + + // Add the rule with the given dependencies and commands. + const char* no_main_dependency = 0; + this->Makefile->AddCustomCommandToOutput(output, + depends, + no_main_dependency, + origCommand.GetCommandLines(), + comment.c_str(), + origCommand.GetWorkingDirectory()); + + // Replace the dependencies with the output of this rule so that the + // next rule added will run after this one. + depends.clear(); + depends.push_back(output); + + // Add a source file representing this output to the project. + cmSourceFile* outsf = this->Makefile->GetSourceFileWithOutput(output); + target.AddSourceFile(outsf); + + // Free the fake output name. + delete [] output; +} + +void +cmLocalVisualStudio6Generator +::WriteCustomRule(std::ostream& fout, + const char* source, + const cmCustomCommand& command, + const char* flags) +{ + std::string comment = + this->ConstructComment(command, "Building Custom Rule $(InputPath)"); + if(comment == "") + { + comment = ""; + } + + // Write the rule for each configuration. + std::vector::iterator i; + for(i = this->Configurations.begin(); i != this->Configurations.end(); ++i) + { + std::string config = this->GetConfigName(*i); + std::string script = + this->ConstructScript(command, config.c_str(), "\\\n\t"); + + if (i == this->Configurations.begin()) + { + fout << "!IF \"$(CFG)\" == " << i->c_str() << std::endl; + } + else + { + fout << "!ELSEIF \"$(CFG)\" == " << i->c_str() << std::endl; + } + if(flags) + { + fout << "\n# ADD CPP " << flags << "\n\n"; + } + // Write out the dependencies for the rule. + fout << "USERDEP__HACK="; + for(std::vector::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; + if(this->GetRealDependency(d->c_str(), config.c_str(), dep)) + { + fout << "\\\n\t" << + this->ConvertToOptionallyRelativeOutputPath(dep.c_str()); + } + } + fout << "\n"; + + fout << "# PROP Ignore_Default_Tool 1\n"; + fout << "# Begin Custom Build -"; + if(!comment.empty()) + { + fout << " " << comment.c_str(); + } + fout << "\n\n"; + if(command.GetOutputs().empty()) + { + fout << source + << "_force : \"$(SOURCE)\" \"$(INTDIR)\" \"$(OUTDIR)\"\n\t"; + fout << script.c_str() << "\n\n"; + } + else + { + for(std::vector::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 << script.c_str() << "\n\n"; + } + } + fout << "# End Custom Build\n\n"; + } + + fout << "!ENDIF\n\n"; +} + + +void cmLocalVisualStudio6Generator::WriteDSPBeginGroup(std::ostream& fout, + const char* group, + const char* filter) +{ + fout << "# Begin Group \"" << group << "\"\n" + "# PROP Default_Filter \"" << filter << "\"\n"; +} + + +void cmLocalVisualStudio6Generator::WriteDSPEndGroup(std::ostream& fout) +{ + fout << "# End Group\n"; +} + + + + +void cmLocalVisualStudio6Generator::SetBuildType(BuildType b, + const char* libName, + cmTarget& target) +{ + std::string root= this->Makefile->GetRequiredDefinition("CMAKE_ROOT"); + const char *def= + this->Makefile->GetDefinition( "MSPROJECT_TEMPLATE_DIRECTORY"); + + if( def) + { + root = def; + } + else + { + root += "/Templates"; + } + + switch(b) + { + case STATIC_LIBRARY: + this->DSPHeaderTemplate = root; + this->DSPHeaderTemplate += "/staticLibHeader.dsptemplate"; + this->DSPFooterTemplate = root; + this->DSPFooterTemplate += "/staticLibFooter.dsptemplate"; + break; + case DLL: + this->DSPHeaderTemplate = root; + this->DSPHeaderTemplate += "/DLLHeader.dsptemplate"; + this->DSPFooterTemplate = root; + this->DSPFooterTemplate += "/DLLFooter.dsptemplate"; + break; + case EXECUTABLE: + if ( target.GetPropertyAsBool("WIN32_EXECUTABLE") ) + { + this->DSPHeaderTemplate = root; + this->DSPHeaderTemplate += "/EXEWinHeader.dsptemplate"; + this->DSPFooterTemplate = root; + this->DSPFooterTemplate += "/EXEFooter.dsptemplate"; + } + else + { + this->DSPHeaderTemplate = root; + this->DSPHeaderTemplate += "/EXEHeader.dsptemplate"; + this->DSPFooterTemplate = root; + this->DSPFooterTemplate += "/EXEFooter.dsptemplate"; + } + break; + case UTILITY: + this->DSPHeaderTemplate = root; + this->DSPHeaderTemplate += "/UtilityHeader.dsptemplate"; + this->DSPFooterTemplate = root; + this->DSPFooterTemplate += "/UtilityFooter.dsptemplate"; + break; + } + + // once the build type is set, determine what configurations are + // possible + std::ifstream fin(this->DSPHeaderTemplate.c_str()); + + cmsys::RegularExpression reg("# Name "); + if(!fin) + { + cmSystemTools::Error("Error Reading ", this->DSPHeaderTemplate.c_str()); + } + + // reset this->Configurations + this->Configurations.erase(this->Configurations.begin(), + this->Configurations.end()); + + // now add all the configurations possible + std::string vs6name = GetVS6TargetName(libName); + std::string line; + while(cmSystemTools::GetLineFromStream(fin, line)) + { + cmSystemTools::ReplaceString(line, "OUTPUT_LIBNAME", vs6name.c_str()); + if (reg.find(line)) + { + this->Configurations.push_back(line.substr(reg.end())); + } + } +} + +//---------------------------------------------------------------------------- +cmsys::auto_ptr +cmLocalVisualStudio6Generator::MaybeCreateOutputDir(cmTarget& target, + const char* config) +{ + cmsys::auto_ptr pcc; + + // VS6 forgets to create the output directory for archives if it + // differs from the intermediate directory. + if(target.GetType() != cmTarget::STATIC_LIBRARY) { return pcc; } + std::string outDir = target.GetDirectory(config, false); + + // Add a pre-link event to create the directory. + cmCustomCommandLine command; + command.push_back(this->Makefile->GetRequiredDefinition("CMAKE_COMMAND")); + command.push_back("-E"); + command.push_back("make_directory"); + command.push_back(outDir); + std::vector no_output; + std::vector no_depends; + cmCustomCommandLines commands; + commands.push_back(command); + pcc.reset(new cmCustomCommand(0, no_output, no_depends, commands, 0, 0)); + pcc->SetEscapeOldStyle(false); + pcc->SetEscapeAllowMakeVars(true); + return pcc; +} + +// look for custom rules on a target and collect them together +std::string +cmLocalVisualStudio6Generator::CreateTargetRules(cmTarget &target, + const char* configName, + const char * /* libName */) +{ + if (target.GetType() >= cmTarget::UTILITY ) + { + return ""; + } + + std::string customRuleCode = "# Begin Special Build Tool\n"; + EventWriter event(this, configName, customRuleCode); + + // Write the pre-build and pre-link together (VS6 does not support both). + event.Start("PreLink"); + event.Write(target.GetPreBuildCommands()); + event.Write(target.GetPreLinkCommands()); + cmsys::auto_ptr pcc( + this->MaybeCreateImplibDir(target, configName, false)); + if(pcc.get()) + { + event.Write(*pcc); + } + pcc = this->MaybeCreateOutputDir(target, configName); + if(pcc.get()) + { + event.Write(*pcc); + } + event.Finish(); + + // Write the post-build rules. + event.Start("PostBuild"); + event.Write(target.GetPostBuildCommands()); + event.Finish(); + + customRuleCode += "# End Special Build Tool\n"; + return customRuleCode; +} + + +inline std::string removeQuotes(const std::string& s) +{ + if(s[0] == '\"' && s[s.size()-1] == '\"') + { + return s.substr(1, s.size()-2); + } + return s; +} + + +std::string +cmLocalVisualStudio6Generator::GetTargetIncludeOptions(cmTarget &target) +{ + std::string includeOptions; + + // Setup /I and /LIBPATH options for the resulting DSP file. VS 6 + // truncates long include paths so make it as short as possible if + // the length threatens this problem. + unsigned int maxIncludeLength = 3000; + bool useShortPath = false; + for(int j=0; j < 2; ++j) + { + std::vector includes; + this->GetIncludeDirectories(includes, &target); + + std::vector::iterator i; + for(i = includes.begin(); i != includes.end(); ++i) + { + std::string tmp = + this->ConvertToOptionallyRelativeOutputPath(i->c_str()); + if(useShortPath) + { + cmSystemTools::GetShortPath(tmp.c_str(), tmp); + } + includeOptions += " /I "; + + // quote if not already quoted + if (tmp[0] != '"') + { + includeOptions += "\""; + includeOptions += tmp; + includeOptions += "\""; + } + else + { + includeOptions += tmp; + } + } + + if(j == 0 && includeOptions.size() > maxIncludeLength) + { + includeOptions = ""; + useShortPath = true; + } + else + { + break; + } + } + + return includeOptions; +} + + +// Code in blocks surrounded by a test for this definition is needed +// only for compatibility with user project's replacement DSP +// templates. The CMake templates no longer use them. +#define CM_USE_OLD_VS6 + +void cmLocalVisualStudio6Generator +::WriteDSPHeader(std::ostream& fout, + const char *libName, cmTarget &target, + std::vector &) +{ + bool targetBuilds = (target.GetType() >= cmTarget::EXECUTABLE && + target.GetType() <= cmTarget::MODULE_LIBRARY); +#ifdef CM_USE_OLD_VS6 + // Lookup the library and executable output directories. + std::string libPath; + if(this->Makefile->GetDefinition("LIBRARY_OUTPUT_PATH")) + { + libPath = this->Makefile->GetDefinition("LIBRARY_OUTPUT_PATH"); + } + std::string exePath; + if(this->Makefile->GetDefinition("EXECUTABLE_OUTPUT_PATH")) + { + exePath = this->Makefile->GetDefinition("EXECUTABLE_OUTPUT_PATH"); + } + + // Make sure there are trailing slashes. + if(!libPath.empty()) + { + if(libPath[libPath.size()-1] != '/') + { + libPath += "/"; + } + } + if(!exePath.empty()) + { + if(exePath[exePath.size()-1] != '/') + { + exePath += "/"; + } + } + + std::set pathEmitted; + + // determine the link directories + std::string libOptions; + std::string libDebugOptions; + std::string libOptimizedOptions; + + std::string libMultiLineOptions; + std::string libMultiLineOptionsForDebug; + std::string libMultiLineDebugOptions; + std::string libMultiLineOptimizedOptions; + + if(libPath.size()) + { + std::string lpath = + this->ConvertToOptionallyRelativeOutputPath(libPath.c_str()); + if(lpath.size() == 0) + { + lpath = "."; + } + std::string lpathIntDir = libPath + "$(INTDIR)"; + lpathIntDir = + this->ConvertToOptionallyRelativeOutputPath(lpathIntDir.c_str()); + if(pathEmitted.insert(lpath).second) + { + libOptions += " /LIBPATH:"; + libOptions += lpathIntDir; + libOptions += " "; + libOptions += " /LIBPATH:"; + libOptions += lpath; + libOptions += " "; + libMultiLineOptions += "# ADD LINK32 /LIBPATH:"; + libMultiLineOptions += lpathIntDir; + libMultiLineOptions += " "; + libMultiLineOptions += " /LIBPATH:"; + libMultiLineOptions += lpath; + libMultiLineOptions += " \n"; + libMultiLineOptionsForDebug += "# ADD LINK32 /LIBPATH:"; + libMultiLineOptionsForDebug += lpathIntDir; + libMultiLineOptionsForDebug += " "; + libMultiLineOptionsForDebug += " /LIBPATH:"; + libMultiLineOptionsForDebug += lpath; + libMultiLineOptionsForDebug += " \n"; + } + } + if(exePath.size()) + { + std::string lpath = + this->ConvertToOptionallyRelativeOutputPath(exePath.c_str()); + if(lpath.size() == 0) + { + lpath = "."; + } + std::string lpathIntDir = exePath + "$(INTDIR)"; + lpathIntDir = + this->ConvertToOptionallyRelativeOutputPath(lpathIntDir.c_str()); + + if(pathEmitted.insert(lpath).second) + { + libOptions += " /LIBPATH:"; + libOptions += lpathIntDir; + libOptions += " "; + libOptions += " /LIBPATH:"; + libOptions += lpath; + libOptions += " "; + libMultiLineOptions += "# ADD LINK32 /LIBPATH:"; + libMultiLineOptions += lpathIntDir; + libMultiLineOptions += " "; + libMultiLineOptions += " /LIBPATH:"; + libMultiLineOptions += lpath; + libMultiLineOptions += " \n"; + libMultiLineOptionsForDebug += "# ADD LINK32 /LIBPATH:"; + libMultiLineOptionsForDebug += lpathIntDir; + libMultiLineOptionsForDebug += " "; + libMultiLineOptionsForDebug += " /LIBPATH:"; + libMultiLineOptionsForDebug += lpath; + libMultiLineOptionsForDebug += " \n"; + } + } + std::vector::const_iterator i; + const std::vector& libdirs = target.GetLinkDirectories(); + for(i = libdirs.begin(); i != libdirs.end(); ++i) + { + std::string path = *i; + if(path[path.size()-1] != '/') + { + path += "/"; + } + std::string lpath = + this->ConvertToOptionallyRelativeOutputPath(path.c_str()); + if(lpath.size() == 0) + { + lpath = "."; + } + std::string lpathIntDir = path + "$(INTDIR)"; + lpathIntDir = + this->ConvertToOptionallyRelativeOutputPath(lpathIntDir.c_str()); + if(pathEmitted.insert(lpath).second) + { + libOptions += " /LIBPATH:"; + libOptions += lpathIntDir; + libOptions += " "; + libOptions += " /LIBPATH:"; + libOptions += lpath; + libOptions += " "; + + libMultiLineOptions += "# ADD LINK32 /LIBPATH:"; + libMultiLineOptions += lpathIntDir; + libMultiLineOptions += " "; + libMultiLineOptions += " /LIBPATH:"; + libMultiLineOptions += lpath; + libMultiLineOptions += " \n"; + libMultiLineOptionsForDebug += "# ADD LINK32 /LIBPATH:"; + libMultiLineOptionsForDebug += lpathIntDir; + libMultiLineOptionsForDebug += " "; + libMultiLineOptionsForDebug += " /LIBPATH:"; + libMultiLineOptionsForDebug += lpath; + libMultiLineOptionsForDebug += " \n"; + } + } + // find link libraries + const cmTarget::LinkLibraryVectorType& libs = target.GetLinkLibraries(); + cmTarget::LinkLibraryVectorType::const_iterator j; + for(j = libs.begin(); j != libs.end(); ++j) + { + // add libraries to executables and dlls (but never include + // a library in a library, bad recursion) + // NEVER LINK STATIC LIBRARIES TO OTHER STATIC LIBRARIES + if ((target.GetType() != cmTarget::SHARED_LIBRARY + && target.GetType() != cmTarget::STATIC_LIBRARY + && target.GetType() != cmTarget::MODULE_LIBRARY) || + (target.GetType()==cmTarget::SHARED_LIBRARY + && libName != GetVS6TargetName(j->first)) || + (target.GetType()==cmTarget::MODULE_LIBRARY + && libName != GetVS6TargetName(j->first))) + { + // Compute the proper name to use to link this library. + std::string lib; + std::string libDebug; + cmTarget* tgt = this->GlobalGenerator->FindTarget(0, j->first.c_str()); + if(tgt) + { + lib = cmSystemTools::GetFilenameWithoutExtension + (tgt->GetFullName().c_str()); + libDebug = cmSystemTools::GetFilenameWithoutExtension + (tgt->GetFullName("Debug").c_str()); + lib += ".lib"; + libDebug += ".lib"; + } + else + { + lib = j->first.c_str(); + libDebug = j->first.c_str(); + if(j->first.find(".lib") == std::string::npos) + { + lib += ".lib"; + libDebug += ".lib"; + } + } + lib = this->ConvertToOptionallyRelativeOutputPath(lib.c_str()); + libDebug = + this->ConvertToOptionallyRelativeOutputPath(libDebug.c_str()); + + if (j->second == cmTarget::GENERAL) + { + libOptions += " "; + libOptions += lib; + libMultiLineOptions += "# ADD LINK32 "; + libMultiLineOptions += lib; + libMultiLineOptions += "\n"; + libMultiLineOptionsForDebug += "# ADD LINK32 "; + libMultiLineOptionsForDebug += libDebug; + libMultiLineOptionsForDebug += "\n"; + } + if (j->second == cmTarget::DEBUG) + { + libDebugOptions += " "; + libDebugOptions += lib; + + libMultiLineDebugOptions += "# ADD LINK32 "; + libMultiLineDebugOptions += libDebug; + libMultiLineDebugOptions += "\n"; + } + if (j->second == cmTarget::OPTIMIZED) + { + libOptimizedOptions += " "; + libOptimizedOptions += lib; + + libMultiLineOptimizedOptions += "# ADD LINK32 "; + libMultiLineOptimizedOptions += lib; + libMultiLineOptimizedOptions += "\n"; + } + } + } +#endif + + // Get include options for this target. + std::string includeOptions = this->GetTargetIncludeOptions(target); + + // Get extra linker options for this target type. + std::string extraLinkOptions; + std::string extraLinkOptionsDebug; + std::string extraLinkOptionsRelease; + std::string extraLinkOptionsMinSizeRel; + std::string extraLinkOptionsRelWithDebInfo; + if(target.GetType() == cmTarget::EXECUTABLE) + { + extraLinkOptions = + this->Makefile->GetRequiredDefinition("CMAKE_EXE_LINKER_FLAGS"); + } + if(target.GetType() == cmTarget::SHARED_LIBRARY) + { + extraLinkOptions = + this->Makefile->GetRequiredDefinition("CMAKE_SHARED_LINKER_FLAGS"); + } + if(target.GetType() == cmTarget::MODULE_LIBRARY) + { + extraLinkOptions = + this->Makefile->GetRequiredDefinition("CMAKE_MODULE_LINKER_FLAGS"); + } + + // Get extra linker options for this target. + if(const char* targetLinkFlags = target.GetProperty("LINK_FLAGS")) + { + extraLinkOptions += " "; + extraLinkOptions += targetLinkFlags; + } + + if(const char* targetLinkFlags = target.GetProperty("LINK_FLAGS_DEBUG")) + { + extraLinkOptionsDebug += " "; + extraLinkOptionsDebug += targetLinkFlags; + } + + if(const char* targetLinkFlags = target.GetProperty("LINK_FLAGS_RELEASE")) + { + extraLinkOptionsRelease += " "; + extraLinkOptionsRelease += targetLinkFlags; + } + + if(const char* targetLinkFlags = target.GetProperty("LINK_FLAGS_MINSIZEREL")) + { + extraLinkOptionsMinSizeRel += " "; + extraLinkOptionsMinSizeRel += targetLinkFlags; + } + + if(const char* targetLinkFlags = + target.GetProperty("LINK_FLAGS_RELWITHDEBINFO")) + { + extraLinkOptionsRelWithDebInfo += " "; + extraLinkOptionsRelWithDebInfo += targetLinkFlags; + } + + + + + // Get standard libraries for this language. + if(targetBuilds) + { + // Get the language to use for linking. + const char* linkLanguage = target.GetLinkerLanguage(); + if(!linkLanguage) + { + cmSystemTools::Error + ("CMake can not determine linker language for target:", + target.GetName()); + return; + } + + // Compute the variable name to lookup standard libraries for this + // language. + std::string standardLibsVar = "CMAKE_"; + standardLibsVar += linkLanguage; + standardLibsVar += "_STANDARD_LIBRARIES"; + + // Add standard libraries. + if(const char* stdLibs = + this->Makefile->GetDefinition(standardLibsVar.c_str())) + { + extraLinkOptions += " "; + extraLinkOptions += stdLibs; + } + } + + // Compute version number information. + std::string targetVersionFlag; + if(target.GetType() == cmTarget::EXECUTABLE || + target.GetType() == cmTarget::SHARED_LIBRARY || + target.GetType() == cmTarget::MODULE_LIBRARY) + { + int major; + int minor; + target.GetTargetVersion(major, minor); + cmOStringStream targetVersionStream; + targetVersionStream << "/version:" << major << "." << minor; + targetVersionFlag = targetVersionStream.str(); + } + + // Compute the real name of the target. + std::string outputName = + "(OUTPUT_NAME is for libraries and executables only)"; + std::string outputNameDebug = outputName; + std::string outputNameRelease = outputName; + std::string outputNameMinSizeRel = outputName; + std::string outputNameRelWithDebInfo = outputName; + if(target.GetType() == cmTarget::EXECUTABLE || + target.GetType() == cmTarget::STATIC_LIBRARY || + target.GetType() == cmTarget::SHARED_LIBRARY || + target.GetType() == cmTarget::MODULE_LIBRARY) + { + outputName = target.GetFullName(); + outputNameDebug = target.GetFullName("Debug"); + outputNameRelease = target.GetFullName("Release"); + outputNameMinSizeRel = target.GetFullName("MinSizeRel"); + outputNameRelWithDebInfo = target.GetFullName("RelWithDebInfo"); + } + else if(target.GetType() == cmTarget::OBJECT_LIBRARY) + { + outputName = target.GetName(); + outputName += ".lib"; + outputNameDebug = outputName; + outputNameRelease = outputName; + outputNameMinSizeRel = outputName; + outputNameRelWithDebInfo = outputName; + } + + // Compute the output directory for the target. + std::string outputDirOld; + std::string outputDirDebug; + std::string outputDirRelease; + std::string outputDirMinSizeRel; + std::string outputDirRelWithDebInfo; + if(target.GetType() == cmTarget::EXECUTABLE || + target.GetType() == cmTarget::STATIC_LIBRARY || + target.GetType() == cmTarget::SHARED_LIBRARY || + target.GetType() == cmTarget::MODULE_LIBRARY) + { +#ifdef CM_USE_OLD_VS6 + outputDirOld = + removeQuotes(this->ConvertToOptionallyRelativeOutputPath + (target.GetDirectory().c_str())); +#endif + outputDirDebug = + removeQuotes(this->ConvertToOptionallyRelativeOutputPath( + target.GetDirectory("Debug").c_str())); + outputDirRelease = + removeQuotes(this->ConvertToOptionallyRelativeOutputPath( + target.GetDirectory("Release").c_str())); + outputDirMinSizeRel = + removeQuotes(this->ConvertToOptionallyRelativeOutputPath( + target.GetDirectory("MinSizeRel").c_str())); + outputDirRelWithDebInfo = + removeQuotes(this->ConvertToOptionallyRelativeOutputPath( + target.GetDirectory("RelWithDebInfo").c_str())); + } + else if(target.GetType() == cmTarget::OBJECT_LIBRARY) + { + std::string outputDir = cmake::GetCMakeFilesDirectoryPostSlash(); + outputDirDebug = outputDir + "Debug"; + outputDirRelease = outputDir + "Release"; + outputDirMinSizeRel = outputDir + "MinSizeRel"; + outputDirRelWithDebInfo = outputDir + "RelWithDebInfo"; + } + + // Compute the proper link information for the target. + std::string optionsDebug; + std::string optionsRelease; + std::string optionsMinSizeRel; + std::string optionsRelWithDebInfo; + if(target.GetType() == cmTarget::EXECUTABLE || + target.GetType() == cmTarget::SHARED_LIBRARY || + target.GetType() == cmTarget::MODULE_LIBRARY) + { + extraLinkOptionsDebug = + extraLinkOptions + " " + extraLinkOptionsDebug; + extraLinkOptionsRelease = + extraLinkOptions + " " + extraLinkOptionsRelease; + extraLinkOptionsMinSizeRel = + extraLinkOptions + " " + extraLinkOptionsMinSizeRel; + extraLinkOptionsRelWithDebInfo = + extraLinkOptions + " " + extraLinkOptionsRelWithDebInfo; + this->ComputeLinkOptions(target, "Debug", extraLinkOptionsDebug, + optionsDebug); + this->ComputeLinkOptions(target, "Release", extraLinkOptionsRelease, + optionsRelease); + this->ComputeLinkOptions(target, "MinSizeRel", extraLinkOptionsMinSizeRel, + optionsMinSizeRel); + this->ComputeLinkOptions(target, "RelWithDebInfo", + extraLinkOptionsRelWithDebInfo, + optionsRelWithDebInfo); + } + + // Compute the path of the import library. + std::string targetImplibFlagDebug; + std::string targetImplibFlagRelease; + std::string targetImplibFlagMinSizeRel; + std::string targetImplibFlagRelWithDebInfo; + if(target.GetType() == cmTarget::SHARED_LIBRARY || + target.GetType() == cmTarget::MODULE_LIBRARY || + target.GetType() == cmTarget::EXECUTABLE) + { + std::string fullPathImpDebug = target.GetDirectory("Debug", true); + std::string fullPathImpRelease = target.GetDirectory("Release", true); + std::string fullPathImpMinSizeRel = + target.GetDirectory("MinSizeRel", true); + std::string fullPathImpRelWithDebInfo = + target.GetDirectory("RelWithDebInfo", true); + fullPathImpDebug += "/"; + fullPathImpRelease += "/"; + fullPathImpMinSizeRel += "/"; + fullPathImpRelWithDebInfo += "/"; + fullPathImpDebug += target.GetFullName("Debug", true); + fullPathImpRelease += target.GetFullName("Release", true); + fullPathImpMinSizeRel += target.GetFullName("MinSizeRel", true); + fullPathImpRelWithDebInfo += target.GetFullName("RelWithDebInfo", true); + + targetImplibFlagDebug = "/implib:"; + targetImplibFlagRelease = "/implib:"; + targetImplibFlagMinSizeRel = "/implib:"; + targetImplibFlagRelWithDebInfo = "/implib:"; + targetImplibFlagDebug += + this->ConvertToOptionallyRelativeOutputPath(fullPathImpDebug.c_str()); + targetImplibFlagRelease += + this->ConvertToOptionallyRelativeOutputPath(fullPathImpRelease.c_str()); + targetImplibFlagMinSizeRel += + this->ConvertToOptionallyRelativeOutputPath( + fullPathImpMinSizeRel.c_str()); + targetImplibFlagRelWithDebInfo += + this->ConvertToOptionallyRelativeOutputPath( + fullPathImpRelWithDebInfo.c_str()); + } + +#ifdef CM_USE_OLD_VS6 + // Compute link information for the target. + if(extraLinkOptions.size()) + { + libOptions += " "; + libOptions += extraLinkOptions; + libOptions += " "; + libMultiLineOptions += "# ADD LINK32 "; + libMultiLineOptions += extraLinkOptions; + libMultiLineOptions += " \n"; + libMultiLineOptionsForDebug += "# ADD LINK32 "; + libMultiLineOptionsForDebug += extraLinkOptions; + libMultiLineOptionsForDebug += " \n"; + } +#endif + + // are there any custom rules on the target itself + // only if the target is a lib or exe + 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) + { + cmSystemTools::Error("Error Reading ", this->DSPHeaderTemplate.c_str()); + } + std::string staticLibOptions; + std::string staticLibOptionsDebug; + std::string staticLibOptionsRelease; + std::string staticLibOptionsMinSizeRel; + std::string staticLibOptionsRelWithDebInfo; + if(target.GetType() == cmTarget::STATIC_LIBRARY ) + { + if(const char* libflags = target.GetProperty("STATIC_LIBRARY_FLAGS")) + { + staticLibOptions = libflags; + staticLibOptionsDebug = libflags; + staticLibOptionsRelease = libflags; + staticLibOptionsMinSizeRel = libflags; + staticLibOptionsRelWithDebInfo = libflags; + } + if(const char* libflagsDebug = + target.GetProperty("STATIC_LIBRARY_FLAGS_DEBUG")) + { + staticLibOptionsDebug += " "; + staticLibOptionsDebug = libflagsDebug; + } + if(const char* libflagsRelease = + target.GetProperty("STATIC_LIBRARY_FLAGS_RELEASE")) + { + staticLibOptionsRelease += " "; + staticLibOptionsRelease = libflagsRelease; + } + if(const char* libflagsMinSizeRel = + target.GetProperty("STATIC_LIBRARY_FLAGS_MINSIZEREL")) + { + staticLibOptionsMinSizeRel += " "; + staticLibOptionsMinSizeRel = libflagsMinSizeRel; + } + if(const char* libflagsRelWithDebInfo = + target.GetProperty("STATIC_LIBRARY_FLAGS_RELWITHDEBINFO")) + { + staticLibOptionsRelWithDebInfo += " "; + staticLibOptionsRelWithDebInfo = libflagsRelWithDebInfo; + } + std::string objects; + this->OutputObjects(target, "LIB", objects); + if(!objects.empty()) + { + objects = "\n" + objects; + staticLibOptionsDebug += objects; + staticLibOptionsRelease += objects; + staticLibOptionsMinSizeRel += objects; + staticLibOptionsRelWithDebInfo += objects; + } + } + + // Add the export symbol definition for shared library objects. + std::string exportSymbol; + if(const char* exportMacro = target.GetExportMacro()) + { + exportSymbol = exportMacro; + } + + std::string line; + std::string libnameExports; + if(exportSymbol.size()) + { + libnameExports = "/D \""; + libnameExports += exportSymbol; + libnameExports += "\""; + } + while(cmSystemTools::GetLineFromStream(fin, line)) + { + const char* mfcFlag = this->Makefile->GetDefinition("CMAKE_MFC_FLAG"); + if(!mfcFlag) + { + mfcFlag = "0"; + } + cmSystemTools::ReplaceString(line, "OUTPUT_LIBNAME_EXPORTS", + libnameExports.c_str()); + cmSystemTools::ReplaceString(line, "CMAKE_MFC_FLAG", + mfcFlag); + if(target.GetType() == cmTarget::STATIC_LIBRARY || + target.GetType() == cmTarget::OBJECT_LIBRARY) + { + cmSystemTools::ReplaceString(line, "CM_STATIC_LIB_ARGS_DEBUG", + staticLibOptionsDebug.c_str()); + cmSystemTools::ReplaceString(line, "CM_STATIC_LIB_ARGS_RELEASE", + staticLibOptionsRelease.c_str()); + cmSystemTools::ReplaceString(line, "CM_STATIC_LIB_ARGS_MINSIZEREL", + staticLibOptionsMinSizeRel.c_str()); + cmSystemTools::ReplaceString(line, "CM_STATIC_LIB_ARGS_RELWITHDEBINFO", + staticLibOptionsRelWithDebInfo.c_str()); + cmSystemTools::ReplaceString(line, "CM_STATIC_LIB_ARGS", + staticLibOptions.c_str()); + } + if(this->Makefile->IsOn("CMAKE_VERBOSE_MAKEFILE")) + { + cmSystemTools::ReplaceString(line, "/nologo", ""); + } + +#ifdef CM_USE_OLD_VS6 + cmSystemTools::ReplaceString(line, "CM_LIBRARIES", + libOptions.c_str()); + cmSystemTools::ReplaceString(line, "CM_DEBUG_LIBRARIES", + libDebugOptions.c_str()); + cmSystemTools::ReplaceString(line, "CM_OPTIMIZED_LIBRARIES", + libOptimizedOptions.c_str()); + cmSystemTools::ReplaceString(line, "CM_MULTILINE_LIBRARIES_FOR_DEBUG", + libMultiLineOptionsForDebug.c_str()); + cmSystemTools::ReplaceString(line, "CM_MULTILINE_LIBRARIES", + libMultiLineOptions.c_str()); + cmSystemTools::ReplaceString(line, "CM_MULTILINE_DEBUG_LIBRARIES", + libMultiLineDebugOptions.c_str()); + cmSystemTools::ReplaceString(line, "CM_MULTILINE_OPTIMIZED_LIBRARIES", + 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()); + cmSystemTools::ReplaceString(line, "OUTPUT_NAME_RELEASE", + outputNameRelease.c_str()); + cmSystemTools::ReplaceString(line, "OUTPUT_NAME_MINSIZEREL", + outputNameMinSizeRel.c_str()); + cmSystemTools::ReplaceString(line, "OUTPUT_NAME_RELWITHDEBINFO", + outputNameRelWithDebInfo.c_str()); + cmSystemTools::ReplaceString(line, "OUTPUT_NAME", outputName.c_str()); + + // Substitute the proper link information into the template. + cmSystemTools::ReplaceString(line, "CM_MULTILINE_OPTIONS_DEBUG", + optionsDebug.c_str()); + cmSystemTools::ReplaceString(line, "CM_MULTILINE_OPTIONS_RELEASE", + optionsRelease.c_str()); + cmSystemTools::ReplaceString(line, "CM_MULTILINE_OPTIONS_MINSIZEREL", + optionsMinSizeRel.c_str()); + cmSystemTools::ReplaceString(line, "CM_MULTILINE_OPTIONS_RELWITHDEBINFO", + optionsRelWithDebInfo.c_str()); + + cmSystemTools::ReplaceString(line, "BUILD_INCLUDES", + includeOptions.c_str()); + cmSystemTools::ReplaceString(line, "TARGET_VERSION_FLAG", + targetVersionFlag.c_str()); + cmSystemTools::ReplaceString(line, "TARGET_IMPLIB_FLAG_DEBUG", + targetImplibFlagDebug.c_str()); + cmSystemTools::ReplaceString(line, "TARGET_IMPLIB_FLAG_RELEASE", + targetImplibFlagRelease.c_str()); + cmSystemTools::ReplaceString(line, "TARGET_IMPLIB_FLAG_MINSIZEREL", + targetImplibFlagMinSizeRel.c_str()); + cmSystemTools::ReplaceString(line, "TARGET_IMPLIB_FLAG_RELWITHDEBINFO", + targetImplibFlagRelWithDebInfo.c_str()); + + std::string vs6name = GetVS6TargetName(libName); + cmSystemTools::ReplaceString(line, "OUTPUT_LIBNAME", vs6name.c_str()); + +#ifdef CM_USE_OLD_VS6 + // because LIBRARY_OUTPUT_PATH and EXECUTABLE_OUTPUT_PATH + // are already quoted in the template file, + // we need to remove the quotes here, we still need + // to convert to output path for unix to win32 conversion + cmSystemTools::ReplaceString + (line, "LIBRARY_OUTPUT_PATH", + removeQuotes(this->ConvertToOptionallyRelativeOutputPath + (libPath.c_str())).c_str()); + cmSystemTools::ReplaceString + (line, "EXECUTABLE_OUTPUT_PATH", + removeQuotes(this->ConvertToOptionallyRelativeOutputPath + (exePath.c_str())).c_str()); +#endif + + if(targetBuilds || target.GetType() == cmTarget::OBJECT_LIBRARY) + { + cmSystemTools::ReplaceString(line, "OUTPUT_DIRECTORY_DEBUG", + outputDirDebug.c_str()); + cmSystemTools::ReplaceString(line, "OUTPUT_DIRECTORY_RELEASE", + outputDirRelease.c_str()); + cmSystemTools::ReplaceString(line, "OUTPUT_DIRECTORY_MINSIZEREL", + outputDirMinSizeRel.c_str()); + cmSystemTools::ReplaceString(line, "OUTPUT_DIRECTORY_RELWITHDEBINFO", + outputDirRelWithDebInfo.c_str()); + if(!outputDirOld.empty()) + { + cmSystemTools::ReplaceString(line, "OUTPUT_DIRECTORY", + outputDirOld.c_str()); + } + } + + cmSystemTools::ReplaceString(line, + "EXTRA_DEFINES", + this->Makefile->GetDefineFlags()); + const char* debugPostfix + = this->Makefile->GetDefinition("CMAKE_DEBUG_POSTFIX"); + cmSystemTools::ReplaceString(line, "DEBUG_POSTFIX", + debugPostfix?debugPostfix:""); + // store flags for each configuration + std::string flags = " "; + std::string flagsRelease = " "; + std::string flagsMinSize = " "; + std::string flagsDebug = " "; + std::string flagsDebugRel = " "; + if(target.GetType() >= cmTarget::EXECUTABLE && + target.GetType() <= cmTarget::OBJECT_LIBRARY) + { + const char* linkLanguage = target.GetLinkerLanguage(); + if(!linkLanguage) + { + cmSystemTools::Error + ("CMake can not determine linker language for target:", + target.GetName()); + return; + } + // if CXX is on and the target contains cxx code then add the cxx flags + std::string baseFlagVar = "CMAKE_"; + baseFlagVar += linkLanguage; + baseFlagVar += "_FLAGS"; + flags = this->Makefile->GetSafeDefinition(baseFlagVar.c_str()); + + std::string flagVar = baseFlagVar + "_RELEASE"; + flagsRelease = this->Makefile->GetSafeDefinition(flagVar.c_str()); + flagsRelease += " -DCMAKE_INTDIR=\\\"Release\\\" "; + + flagVar = baseFlagVar + "_MINSIZEREL"; + flagsMinSize = this->Makefile->GetSafeDefinition(flagVar.c_str()); + flagsMinSize += " -DCMAKE_INTDIR=\\\"MinSizeRel\\\" "; + + flagVar = baseFlagVar + "_DEBUG"; + flagsDebug = this->Makefile->GetSafeDefinition(flagVar.c_str()); + flagsDebug += " -DCMAKE_INTDIR=\\\"Debug\\\" "; + + flagVar = baseFlagVar + "_RELWITHDEBINFO"; + flagsDebugRel = this->Makefile->GetSafeDefinition(flagVar.c_str()); + flagsDebugRel += " -DCMAKE_INTDIR=\\\"RelWithDebInfo\\\" "; + } + + // if _UNICODE and _SBCS are not found, then add -D_MBCS + std::string defs = this->Makefile->GetDefineFlags(); + if(flags.find("D_UNICODE") == flags.npos && + defs.find("D_UNICODE") == flags.npos && + flags.find("D_SBCS") == flags.npos && + defs.find("D_SBCS") == flags.npos) + { + flags += " /D \"_MBCS\""; + } + + // Add per-target flags. + if(const char* targetFlags = target.GetProperty("COMPILE_FLAGS")) + { + flags += " "; + flags += targetFlags; + } + + // Add per-target and per-configuration preprocessor definitions. + std::string defines = " "; + std::string debugDefines = " "; + std::string releaseDefines = " "; + std::string minsizeDefines = " "; + std::string debugrelDefines = " "; + + this->AppendDefines( + defines, + this->Makefile->GetProperty("COMPILE_DEFINITIONS"), 0); + this->AppendDefines( + debugDefines, + this->Makefile->GetProperty("COMPILE_DEFINITIONS_DEBUG"),0); + this->AppendDefines( + releaseDefines, + this->Makefile->GetProperty("COMPILE_DEFINITIONS_RELEASE"), 0); + this->AppendDefines( + minsizeDefines, + this->Makefile->GetProperty("COMPILE_DEFINITIONS_MINSIZEREL"), 0); + this->AppendDefines( + debugrelDefines, + this->Makefile->GetProperty("COMPILE_DEFINITIONS_RELWITHDEBINFO"), 0); + + this->AppendDefines( + defines, + target.GetProperty("COMPILE_DEFINITIONS"), 0); + this->AppendDefines( + debugDefines, + target.GetProperty("COMPILE_DEFINITIONS_DEBUG"), 0); + this->AppendDefines( + releaseDefines, + target.GetProperty("COMPILE_DEFINITIONS_RELEASE"), 0); + this->AppendDefines( + minsizeDefines, + target.GetProperty("COMPILE_DEFINITIONS_MINSIZEREL"), 0); + this->AppendDefines( + debugrelDefines, + target.GetProperty("COMPILE_DEFINITIONS_RELWITHDEBINFO"), 0); + flags += defines; + flagsDebug += debugDefines; + flagsRelease += releaseDefines; + flagsMinSize += minsizeDefines; + flagsDebugRel += debugrelDefines; + + // The template files have CXX FLAGS in them, that need to be replaced. + // There are not separate CXX and C template files, so we use the same + // variable names. The previous code sets up flags* variables to contain + // the correct C or CXX flags + cmSystemTools::ReplaceString(line, "CMAKE_CXX_FLAGS_MINSIZEREL", + flagsMinSize.c_str()); + cmSystemTools::ReplaceString(line, "CMAKE_CXX_FLAGS_DEBUG", + flagsDebug.c_str()); + cmSystemTools::ReplaceString(line, "CMAKE_CXX_FLAGS_RELWITHDEBINFO", + flagsDebugRel.c_str()); + cmSystemTools::ReplaceString(line, "CMAKE_CXX_FLAGS_RELEASE", + flagsRelease.c_str()); + cmSystemTools::ReplaceString(line, "CMAKE_CXX_FLAGS", flags.c_str()); + + cmSystemTools::ReplaceString(line, "COMPILE_DEFINITIONS_MINSIZEREL", + minsizeDefines.c_str()); + cmSystemTools::ReplaceString(line, "COMPILE_DEFINITIONS_DEBUG", + debugDefines.c_str()); + cmSystemTools::ReplaceString(line, "COMPILE_DEFINITIONS_RELWITHDEBINFO", + debugrelDefines.c_str()); + cmSystemTools::ReplaceString(line, "COMPILE_DEFINITIONS_RELEASE", + releaseDefines.c_str()); + cmSystemTools::ReplaceString(line, "COMPILE_DEFINITIONS", defines.c_str()); + + fout << line.c_str() << std::endl; + } +} + +void cmLocalVisualStudio6Generator::WriteDSPFooter(std::ostream& fout) +{ + std::ifstream fin(this->DSPFooterTemplate.c_str()); + if(!fin) + { + cmSystemTools::Error("Error Reading ", + this->DSPFooterTemplate.c_str()); + } + std::string line; + while(cmSystemTools::GetLineFromStream(fin, line)) + { + fout << line << std::endl; + } +} + +//---------------------------------------------------------------------------- +void cmLocalVisualStudio6Generator +::ComputeLinkOptions(cmTarget& target, + const char* configName, + const std::string extraOptions, + std::string& options) +{ + // Compute the link information for this configuration. + cmComputeLinkInformation* pcli = target.GetLinkInformation(configName); + if(!pcli) + { + return; + } + cmComputeLinkInformation& cli = *pcli; + typedef cmComputeLinkInformation::ItemVector ItemVector; + ItemVector const& linkLibs = cli.GetItems(); + std::vector const& linkDirs = cli.GetDirectories(); + + this->OutputObjects(target, "LINK", options); + + // Build the link options code. + for(std::vector::const_iterator d = linkDirs.begin(); + d != linkDirs.end(); ++d) + { + std::string dir = *d; + if(!dir.empty()) + { + if(dir[dir.size()-1] != '/') + { + dir += "/"; + } + dir += "$(IntDir)"; + options += "# ADD LINK32 /LIBPATH:"; + options += this->ConvertToOptionallyRelativeOutputPath(dir.c_str()); + options += " /LIBPATH:"; + options += this->ConvertToOptionallyRelativeOutputPath(d->c_str()); + options += "\n"; + } + } + for(ItemVector::const_iterator l = linkLibs.begin(); + l != linkLibs.end(); ++l) + { + options += "# ADD LINK32 "; + if(l->IsPath) + { + options += + this->ConvertToOptionallyRelativeOutputPath(l->Value.c_str()); + } + else + { + options += l->Value; + } + options += "\n"; + } + + // Add extra options if any. + if(!extraOptions.empty()) + { + options += "# ADD LINK32 "; + options += extraOptions; + options += "\n"; + } +} + +//---------------------------------------------------------------------------- +void cmLocalVisualStudio6Generator +::OutputObjects(cmTarget& target, const char* tool, + std::string& options) +{ + // VS 6 does not support per-config source locations so we + // list object library content on the link line instead. + cmGeneratorTarget* gt = + this->GlobalGenerator->GetGeneratorTarget(&target); + std::vector objs; + gt->UseObjectLibraries(objs); + for(std::vector::const_iterator + oi = objs.begin(); oi != objs.end(); ++oi) + { + options += "# ADD "; + options += tool; + options += "32 "; + options += this->ConvertToOptionallyRelativeOutputPath(oi->c_str()); + options += "\n"; + } +} + +std::string +cmLocalVisualStudio6Generator +::GetTargetDirectory(cmTarget const&) const +{ + // No per-target directory for this generator (yet). + return ""; +} + +//---------------------------------------------------------------------------- +std::string +cmLocalVisualStudio6Generator +::ComputeLongestObjectDirectory(cmTarget&) const +{ + // Compute the maximum length configuration name. + std::string config_max; + for(std::vector::const_iterator + i = this->Configurations.begin(); + i != this->Configurations.end(); ++i) + { + // Strip the subdirectory name out of the configuration name. + std::string config = this->GetConfigName(*i); + if(config.size() > config_max.size()) + { + config_max = config; + } + } + + // Compute the maximum length full path to the intermediate + // files directory for any configuration. This is used to construct + // object file names that do not produce paths that are too long. + std::string dir_max; + dir_max += this->Makefile->GetCurrentOutputDirectory(); + dir_max += "/"; + dir_max += config_max; + dir_max += "/"; + return dir_max; +} + +std::string +cmLocalVisualStudio6Generator +::GetConfigName(std::string const& configuration) const +{ + // Strip the subdirectory name out of the configuration name. + std::string config = configuration; + std::string::size_type pos = config.find_last_of(" "); + config = config.substr(pos+1, std::string::npos); + config = config.substr(0, config.size()-1); + return config; +} + +//---------------------------------------------------------------------------- +bool +cmLocalVisualStudio6Generator +::CheckDefinition(std::string const& define) const +{ + // Perform the standard check first. + if(!this->cmLocalGenerator::CheckDefinition(define)) + { + return false; + } + + // Now do the VS6-specific check. + if(define.find_first_of(" ") != define.npos && + define.find_first_of("\"$;") != define.npos) + { + cmOStringStream e; + e << "WARNING: The VS6 IDE does not support preprocessor definition " + << "values with spaces and '\"', '$', or ';'.\n" + << "CMake is dropping a preprocessor definition: " << define << "\n" + << "Consider defining the macro in a (configured) header file.\n"; + cmSystemTools::Message(e.str().c_str()); + return false; + } + + // Assume it is supported. + return true; +} -- cgit v1.2.3