Fix Xcode project references to the source tree
[cmake.git] / Source / cmLocalVisualStudio6Generator.cxx
blobc2c515168b340301c250ccd0df6434c896202ab1
1 /*=========================================================================
3 Program: CMake - Cross-Platform Makefile Generator
4 Module: $RCSfile: cmLocalVisualStudio6Generator.cxx,v $
5 Language: C++
6 Date: $Date: 2009-09-02 20:07:10 $
7 Version: $Revision: 1.159 $
9 Copyright (c) 2002 Kitware, Inc., Insight Consortium. All rights reserved.
10 See Copyright.txt or http://www.cmake.org/HTML/Copyright.html for details.
12 This software is distributed WITHOUT ANY WARRANTY; without even
13 the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
14 PURPOSE. See the above copyright notices for more information.
16 =========================================================================*/
17 #include "cmGlobalGenerator.h"
18 #include "cmLocalVisualStudio6Generator.h"
19 #include "cmMakefile.h"
20 #include "cmSystemTools.h"
21 #include "cmSourceFile.h"
22 #include "cmCacheManager.h"
23 #include "cmake.h"
25 #include "cmComputeLinkInformation.h"
27 #include <cmsys/RegularExpression.hxx>
29 cmLocalVisualStudio6Generator::cmLocalVisualStudio6Generator()
33 cmLocalVisualStudio6Generator::~cmLocalVisualStudio6Generator()
37 //----------------------------------------------------------------------------
38 // Helper class to write build events.
39 class cmLocalVisualStudio6Generator::EventWriter
41 public:
42 EventWriter(cmLocalVisualStudio6Generator* lg,
43 const char* config, std::string& code):
44 LG(lg), Config(config), Code(code), First(true) {}
45 void Start(const char* event)
47 this->First = true;
48 this->Event = event;
50 void Finish()
52 this->Code += (this->First? "" : "\n");
54 void Write(std::vector<cmCustomCommand> const& ccs)
56 for(std::vector<cmCustomCommand>::const_iterator ci = ccs.begin();
57 ci != ccs.end(); ++ci)
59 this->Write(*ci);
62 void Write(cmCustomCommand const& cc)
64 if(this->First)
66 this->Code += this->Event + "_Cmds=";
67 this->First = false;
69 else
71 this->Code += "\\\n\t";
73 this->Code +=
74 this->LG->ConstructScript(cc.GetCommandLines(),
75 cc.GetWorkingDirectory(),
76 this->Config,
77 cc.GetEscapeOldStyle(),
78 cc.GetEscapeAllowMakeVars(),
79 "\\\n\t");
81 private:
82 cmLocalVisualStudio6Generator* LG;
83 const char* Config;
84 std::string& Code;
85 bool First;
86 std::string Event;
89 void cmLocalVisualStudio6Generator::AddHelperCommands()
91 std::set<cmStdString> lang;
92 lang.insert("C");
93 lang.insert("CXX");
94 this->CreateCustomTargetsAndCommands(lang);
97 void cmLocalVisualStudio6Generator::Generate()
99 this->OutputDSPFile();
102 void cmLocalVisualStudio6Generator::OutputDSPFile()
104 // If not an in source build, then create the output directory
105 if(strcmp(this->Makefile->GetStartOutputDirectory(),
106 this->Makefile->GetHomeDirectory()) != 0)
108 if(!cmSystemTools::MakeDirectory
109 (this->Makefile->GetStartOutputDirectory()))
111 cmSystemTools::Error("Error creating directory ",
112 this->Makefile->GetStartOutputDirectory());
116 // Setup /I and /LIBPATH options for the resulting DSP file. VS 6
117 // truncates long include paths so make it as short as possible if
118 // the length threatens this problem.
119 unsigned int maxIncludeLength = 3000;
120 bool useShortPath = false;
121 for(int j=0; j < 2; ++j)
123 std::vector<std::string> includes;
124 this->GetIncludeDirectories(includes);
125 std::vector<std::string>::iterator i;
126 for(i = includes.begin(); i != includes.end(); ++i)
128 std::string tmp =
129 this->ConvertToOptionallyRelativeOutputPath(i->c_str());
130 if(useShortPath)
132 cmSystemTools::GetShortPath(tmp.c_str(), tmp);
134 this->IncludeOptions += " /I ";
136 // quote if not already quoted
137 if (tmp[0] != '"')
139 this->IncludeOptions += "\"";
140 this->IncludeOptions += tmp;
141 this->IncludeOptions += "\"";
143 else
145 this->IncludeOptions += tmp;
148 if(j == 0 && this->IncludeOptions.size() > maxIncludeLength)
150 this->IncludeOptions = "";
151 useShortPath = true;
153 else
155 break;
159 // Create the DSP or set of DSP's for libraries and executables
161 // clear project names
162 this->CreatedProjectNames.clear();
163 cmTargets &tgts = this->Makefile->GetTargets();
164 for(cmTargets::iterator l = tgts.begin();
165 l != tgts.end(); l++)
167 // Add a rule to regenerate the build system when the target
168 // specification source changes.
169 const char* suppRegenRule =
170 this->Makefile->GetDefinition("CMAKE_SUPPRESS_REGENERATION");
171 if (!cmSystemTools::IsOn(suppRegenRule))
173 this->AddDSPBuildRule(l->second);
177 // build any targets
178 for(cmTargets::iterator l = tgts.begin();
179 l != tgts.end(); l++)
181 switch(l->second.GetType())
183 case cmTarget::STATIC_LIBRARY:
184 this->SetBuildType(STATIC_LIBRARY, l->first.c_str(), l->second);
185 break;
186 case cmTarget::SHARED_LIBRARY:
187 case cmTarget::MODULE_LIBRARY:
188 this->SetBuildType(DLL, l->first.c_str(), l->second);
189 break;
190 case cmTarget::EXECUTABLE:
191 this->SetBuildType(EXECUTABLE,l->first.c_str(), l->second);
192 break;
193 case cmTarget::UTILITY:
194 case cmTarget::GLOBAL_TARGET:
195 this->SetBuildType(UTILITY, l->first.c_str(), l->second);
196 break;
197 default:
198 cmSystemTools::Error("Bad target type", l->first.c_str());
199 break;
201 // INCLUDE_EXTERNAL_MSPROJECT command only affects the workspace
202 // so don't build a projectfile for it
203 const char* path =
204 l->second.GetProperty("EXTERNAL_MSPROJECT");
205 if(!path)
207 // check to see if the dsp is going into a sub-directory
208 std::string::size_type pos = l->first.rfind('/');
209 if(pos != std::string::npos)
211 std::string dir = this->Makefile->GetStartOutputDirectory();
212 dir += "/";
213 dir += l->first.substr(0, pos);
214 if(!cmSystemTools::MakeDirectory(dir.c_str()))
216 cmSystemTools::Error("Error creating directory ", dir.c_str());
219 this->CreateSingleDSP(l->first.c_str(),l->second);
224 // Utility function to make a valid VS6 *.dsp filename out
225 // of a CMake target name:
227 extern std::string GetVS6TargetName(const std::string& targetName);
229 void cmLocalVisualStudio6Generator::CreateSingleDSP(const char *lname,
230 cmTarget &target)
232 // add to the list of projects
233 std::string pname = GetVS6TargetName(lname);
235 this->CreatedProjectNames.push_back(pname);
236 // create the dsp.cmake file
237 std::string fname;
238 fname = this->Makefile->GetStartOutputDirectory();
239 fname += "/";
240 fname += pname;
241 fname += ".dsp";
242 // save the name of the real dsp file
243 std::string realDSP = fname;
244 fname += ".cmake";
245 std::ofstream fout(fname.c_str());
246 if(!fout)
248 cmSystemTools::Error("Error Writing ", fname.c_str());
249 cmSystemTools::ReportLastSystemError("");
251 this->WriteDSPFile(fout,pname.c_str(),target);
252 fout.close();
253 // if the dsp file has changed, then write it.
254 cmSystemTools::CopyFileIfDifferent(fname.c_str(), realDSP.c_str());
258 void cmLocalVisualStudio6Generator::AddDSPBuildRule(cmTarget& tgt)
260 std::string dspname = GetVS6TargetName(tgt.GetName());
261 dspname += ".dsp.cmake";
262 const char* dsprule =
263 this->Makefile->GetRequiredDefinition("CMAKE_COMMAND");
264 cmCustomCommandLine commandLine;
265 commandLine.push_back(dsprule);
266 std::string makefileIn = this->Makefile->GetStartDirectory();
267 makefileIn += "/";
268 makefileIn += "CMakeLists.txt";
269 if(!cmSystemTools::FileExists(makefileIn.c_str()))
271 return;
273 std::string comment = "Building Custom Rule ";
274 comment += makefileIn;
275 std::string args;
276 args = "-H";
277 args += this->Convert(this->Makefile->GetHomeDirectory(),
278 START_OUTPUT, UNCHANGED, true);
279 commandLine.push_back(args);
280 args = "-B";
281 args +=
282 this->Convert(this->Makefile->GetHomeOutputDirectory(),
283 START_OUTPUT, UNCHANGED, true);
284 commandLine.push_back(args);
286 std::vector<std::string> const& listFiles = this->Makefile->GetListFiles();
288 cmCustomCommandLines commandLines;
289 commandLines.push_back(commandLine);
290 const char* no_working_directory = 0;
291 this->Makefile->AddCustomCommandToOutput(dspname.c_str(), listFiles,
292 makefileIn.c_str(), commandLines,
293 comment.c_str(),
294 no_working_directory, true);
295 if(cmSourceFile* file = this->Makefile->GetSource(makefileIn.c_str()))
297 tgt.AddSourceFile(file);
299 else
301 cmSystemTools::Error("Error adding rule for ", makefileIn.c_str());
306 void cmLocalVisualStudio6Generator::WriteDSPFile(std::ostream& fout,
307 const char *libName,
308 cmTarget &target)
310 // For utility targets need custom command since pre- and post-
311 // build does not do anything in Visual Studio 6. In order for the
312 // rules to run in the correct order as custom commands, we need
313 // special care for dependencies. The first rule must depend on all
314 // the dependencies of all the rules. The later rules must each
315 // depend only on the previous rule.
316 if ((target.GetType() == cmTarget::UTILITY ||
317 target.GetType() == cmTarget::GLOBAL_TARGET) &&
318 (!target.GetPreBuildCommands().empty() ||
319 !target.GetPostBuildCommands().empty()))
321 // Accumulate the dependencies of all the commands.
322 std::vector<std::string> depends;
323 for (std::vector<cmCustomCommand>::const_iterator cr =
324 target.GetPreBuildCommands().begin();
325 cr != target.GetPreBuildCommands().end(); ++cr)
327 depends.insert(depends.end(),
328 cr->GetDepends().begin(), cr->GetDepends().end());
330 for (std::vector<cmCustomCommand>::const_iterator cr =
331 target.GetPostBuildCommands().begin();
332 cr != target.GetPostBuildCommands().end(); ++cr)
334 depends.insert(depends.end(),
335 cr->GetDepends().begin(), cr->GetDepends().end());
338 // Add the pre- and post-build commands in order.
339 int count = 1;
340 for (std::vector<cmCustomCommand>::const_iterator cr =
341 target.GetPreBuildCommands().begin();
342 cr != target.GetPreBuildCommands().end(); ++cr)
344 this->AddUtilityCommandHack(target, count++, depends, *cr);
346 for (std::vector<cmCustomCommand>::const_iterator cr =
347 target.GetPostBuildCommands().begin();
348 cr != target.GetPostBuildCommands().end(); ++cr)
350 this->AddUtilityCommandHack(target, count++, depends, *cr);
354 // We may be modifying the source groups temporarily, so make a copy.
355 std::vector<cmSourceGroup> sourceGroups = this->Makefile->GetSourceGroups();
357 // get the classes from the source lists then add them to the groups
358 std::vector<cmSourceFile*> const & classes = target.GetSourceFiles();
360 // now all of the source files have been properly assigned to the target
361 // now stick them into source groups using the reg expressions
362 for(std::vector<cmSourceFile*>::const_iterator i = classes.begin();
363 i != classes.end(); i++)
365 // Add the file to the list of sources.
366 std::string source = (*i)->GetFullPath();
367 cmSourceGroup& sourceGroup =
368 this->Makefile->FindSourceGroup(source.c_str(), sourceGroups);
369 sourceGroup.AssignSource(*i);
370 // while we are at it, if it is a .rule file then for visual studio 6 we
371 // must generate it
372 if ((*i)->GetExtension() == "rule")
374 if(!cmSystemTools::FileExists(source.c_str()))
376 cmSystemTools::ReplaceString(source, "$(IntDir)/", "");
377 #if defined(_WIN32) || defined(__CYGWIN__)
378 std::ofstream fout(source.c_str(),
379 std::ios::binary | std::ios::out
380 | std::ios::trunc);
381 #else
382 std::ofstream fout(source.c_str(),
383 std::ios::out | std::ios::trunc);
384 #endif
385 if(fout)
387 fout.write("# generated from CMake",22);
388 fout.flush();
389 fout.close();
395 // Compute which sources need unique object computation.
396 this->ComputeObjectNameRequirements(sourceGroups);
398 // Write the DSP file's header.
399 this->WriteDSPHeader(fout, libName, target, sourceGroups);
402 // Loop through every source group.
403 for(std::vector<cmSourceGroup>::const_iterator sg = sourceGroups.begin();
404 sg != sourceGroups.end(); ++sg)
406 this->WriteGroup(&(*sg), target, fout, libName);
409 // Write the DSP file's footer.
410 this->WriteDSPFooter(fout);
413 void cmLocalVisualStudio6Generator
414 ::WriteGroup(const cmSourceGroup *sg, cmTarget& target,
415 std::ostream &fout, const char *libName)
417 const std::vector<const cmSourceFile *> &sourceFiles =
418 sg->GetSourceFiles();
419 // If the group is empty, don't write it at all.
421 if(sourceFiles.empty() && sg->GetGroupChildren().empty())
423 return;
426 // If the group has a name, write the header.
427 std::string name = sg->GetName();
428 if(name != "")
430 this->WriteDSPBeginGroup(fout, name.c_str(), "");
433 // Compute the maximum length configuration name.
434 std::string config_max;
435 for(std::vector<std::string>::iterator i = this->Configurations.begin();
436 i != this->Configurations.end(); ++i)
438 // Strip the subdirectory name out of the configuration name.
439 std::string config = this->GetConfigName(*i);
440 if(config.size() > config_max.size())
442 config_max = config;
446 // Compute the maximum length full path to the intermediate
447 // files directory for any configuration. This is used to construct
448 // object file names that do not produce paths that are too long.
449 std::string dir_max;
450 dir_max += this->Makefile->GetCurrentOutputDirectory();
451 dir_max += "/";
452 dir_max += config_max;
453 dir_max += "/";
455 // Loop through each source in the source group.
456 for(std::vector<const cmSourceFile *>::const_iterator sf =
457 sourceFiles.begin(); sf != sourceFiles.end(); ++sf)
459 std::string source = (*sf)->GetFullPath();
460 const cmCustomCommand *command =
461 (*sf)->GetCustomCommand();
462 std::string compileFlags;
463 std::vector<std::string> depends;
464 std::string objectNameDir;
465 if(this->NeedObjectName.find(*sf) != this->NeedObjectName.end())
467 objectNameDir =
468 cmSystemTools::GetFilenamePath(
469 this->GetObjectFileNameWithoutTarget(*(*sf), dir_max));
472 // Add per-source file flags.
473 if(const char* cflags = (*sf)->GetProperty("COMPILE_FLAGS"))
475 compileFlags += cflags;
478 const char* lang = this->GetSourceFileLanguage(*(*sf));
479 if(lang)
481 if(strcmp(lang, "CXX") == 0)
483 // force a C++ file type
484 compileFlags += " /TP ";
486 else if(strcmp(lang, "C") == 0)
488 // force to c file type
489 compileFlags += " /TC ";
493 // Add per-source and per-configuration preprocessor definitions.
494 std::map<cmStdString, cmStdString> cdmap;
495 this->AppendDefines(compileFlags,
496 (*sf)->GetProperty("COMPILE_DEFINITIONS"), lang);
497 if(const char* cdefs = (*sf)->GetProperty("COMPILE_DEFINITIONS_DEBUG"))
499 this->AppendDefines(cdmap["DEBUG"], cdefs, lang);
501 if(const char* cdefs = (*sf)->GetProperty("COMPILE_DEFINITIONS_RELEASE"))
503 this->AppendDefines(cdmap["RELEASE"], cdefs, lang);
505 if(const char* cdefs =
506 (*sf)->GetProperty("COMPILE_DEFINITIONS_MINSIZEREL"))
508 this->AppendDefines(cdmap["MINSIZEREL"], cdefs, lang);
510 if(const char* cdefs =
511 (*sf)->GetProperty("COMPILE_DEFINITIONS_RELWITHDEBINFO"))
513 this->AppendDefines(cdmap["RELWITHDEBINFO"], cdefs, lang);
516 bool excludedFromBuild =
517 (lang && (*sf)->GetPropertyAsBool("HEADER_FILE_ONLY"));
519 // Check for extra object-file dependencies.
520 const char* dependsValue = (*sf)->GetProperty("OBJECT_DEPENDS");
521 if(dependsValue)
523 cmSystemTools::ExpandListArgument(dependsValue, depends);
525 if (GetVS6TargetName(source) != libName ||
526 target.GetType() == cmTarget::UTILITY ||
527 target.GetType() == cmTarget::GLOBAL_TARGET)
529 fout << "# Begin Source File\n\n";
531 // Tell MS-Dev what the source is. If the compiler knows how to
532 // build it, then it will.
533 fout << "SOURCE=" <<
534 this->ConvertToOptionallyRelativeOutputPath(source.c_str()) << "\n\n";
535 if(!depends.empty())
537 // Write out the dependencies for the rule.
538 fout << "USERDEP__HACK=";
539 for(std::vector<std::string>::const_iterator d = depends.begin();
540 d != depends.end(); ++d)
542 fout << "\\\n\t" <<
543 this->ConvertToOptionallyRelativeOutputPath(d->c_str());
545 fout << "\n";
547 if (command)
549 const char* flags = compileFlags.size() ? compileFlags.c_str(): 0;
550 this->WriteCustomRule(fout, source.c_str(), *command, flags);
552 else if(!compileFlags.empty() || !objectNameDir.empty() ||
553 excludedFromBuild || !cdmap.empty())
555 for(std::vector<std::string>::iterator i
556 = this->Configurations.begin();
557 i != this->Configurations.end(); ++i)
559 // Strip the subdirectory name out of the configuration name.
560 std::string config = this->GetConfigName(*i);
561 if (i == this->Configurations.begin())
563 fout << "!IF \"$(CFG)\" == " << i->c_str() << std::endl;
565 else
567 fout << "!ELSEIF \"$(CFG)\" == " << i->c_str() << std::endl;
569 if(excludedFromBuild)
571 fout << "# PROP Exclude_From_Build 1\n";
573 if(!compileFlags.empty())
575 fout << "\n# ADD CPP " << compileFlags << "\n\n";
577 std::map<cmStdString, cmStdString>::iterator cdi =
578 cdmap.find(cmSystemTools::UpperCase(config));
579 if(cdi != cdmap.end() && !cdi->second.empty())
581 fout << "\n# ADD CPP " << cdi->second << "\n\n";
583 if(!objectNameDir.empty())
585 // Setup an alternate object file directory.
586 fout << "\n# PROP Intermediate_Dir \""
587 << config << "/" << objectNameDir << "\"\n\n";
590 fout << "!ENDIF\n\n";
592 fout << "# End Source File\n";
596 std::vector<cmSourceGroup> const& children = sg->GetGroupChildren();
598 for(unsigned int i=0;i<children.size();++i)
600 this->WriteGroup(&children[i], target, fout, libName);
606 // If the group has a name, write the footer.
607 if(name != "")
609 this->WriteDSPEndGroup(fout);
615 void
616 cmLocalVisualStudio6Generator
617 ::AddUtilityCommandHack(cmTarget& target, int count,
618 std::vector<std::string>& depends,
619 const cmCustomCommand& origCommand)
621 // Create a fake output that forces the rule to run.
622 char* output = new char[(strlen(this->Makefile->GetStartOutputDirectory()) +
623 strlen(target.GetName()) + 30)];
624 sprintf(output,"%s/%s_force_%i", this->Makefile->GetStartOutputDirectory(),
625 target.GetName(), count);
626 std::string comment = this->ConstructComment(origCommand, "<hack>");
628 // Add the rule with the given dependencies and commands.
629 const char* no_main_dependency = 0;
630 this->Makefile->AddCustomCommandToOutput(output,
631 depends,
632 no_main_dependency,
633 origCommand.GetCommandLines(),
634 comment.c_str(),
635 origCommand.GetWorkingDirectory());
637 // Replace the dependencies with the output of this rule so that the
638 // next rule added will run after this one.
639 depends.clear();
640 depends.push_back(output);
642 // Add a source file representing this output to the project.
643 cmSourceFile* outsf = this->Makefile->GetSourceFileWithOutput(output);
644 target.AddSourceFile(outsf);
646 // Free the fake output name.
647 delete [] output;
650 void
651 cmLocalVisualStudio6Generator
652 ::WriteCustomRule(std::ostream& fout,
653 const char* source,
654 const cmCustomCommand& command,
655 const char* flags)
657 std::string comment =
658 this->ConstructComment(command, "Building Custom Rule $(InputPath)");
659 if(comment == "<hack>")
661 comment = "";
664 // Write the rule for each configuration.
665 std::vector<std::string>::iterator i;
666 for(i = this->Configurations.begin(); i != this->Configurations.end(); ++i)
668 std::string config = this->GetConfigName(*i);
669 std::string script =
670 this->ConstructScript(command.GetCommandLines(),
671 command.GetWorkingDirectory(),
672 config.c_str(),
673 command.GetEscapeOldStyle(),
674 command.GetEscapeAllowMakeVars(),
675 "\\\n\t");
677 if (i == this->Configurations.begin())
679 fout << "!IF \"$(CFG)\" == " << i->c_str() << std::endl;
681 else
683 fout << "!ELSEIF \"$(CFG)\" == " << i->c_str() << std::endl;
685 if(flags)
687 fout << "\n# ADD CPP " << flags << "\n\n";
689 // Write out the dependencies for the rule.
690 fout << "USERDEP__HACK=";
691 for(std::vector<std::string>::const_iterator d =
692 command.GetDepends().begin();
693 d != command.GetDepends().end();
694 ++d)
696 // Lookup the real name of the dependency in case it is a CMake target.
697 std::string dep = this->GetRealDependency(d->c_str(),
698 config.c_str());
699 fout << "\\\n\t" <<
700 this->ConvertToOptionallyRelativeOutputPath(dep.c_str());
702 fout << "\n";
704 fout << "# PROP Ignore_Default_Tool 1\n";
705 fout << "# Begin Custom Build -";
706 if(!comment.empty())
708 fout << " " << comment.c_str();
710 fout << "\n\n";
711 if(command.GetOutputs().empty())
713 fout << source
714 << "_force : \"$(SOURCE)\" \"$(INTDIR)\" \"$(OUTDIR)\"\n\t";
715 fout << script.c_str() << "\n\n";
717 else
719 for(std::vector<std::string>::const_iterator o =
720 command.GetOutputs().begin();
721 o != command.GetOutputs().end();
722 ++o)
724 // Write a rule for every output generated by this command.
725 fout << this->ConvertToOptionallyRelativeOutputPath(o->c_str())
726 << " : \"$(SOURCE)\" \"$(INTDIR)\" \"$(OUTDIR)\"\n\t";
727 fout << script.c_str() << "\n\n";
730 fout << "# End Custom Build\n\n";
733 fout << "!ENDIF\n\n";
737 void cmLocalVisualStudio6Generator::WriteDSPBeginGroup(std::ostream& fout,
738 const char* group,
739 const char* filter)
741 fout << "# Begin Group \"" << group << "\"\n"
742 "# PROP Default_Filter \"" << filter << "\"\n";
746 void cmLocalVisualStudio6Generator::WriteDSPEndGroup(std::ostream& fout)
748 fout << "# End Group\n";
754 void cmLocalVisualStudio6Generator::SetBuildType(BuildType b,
755 const char* libName,
756 cmTarget& target)
758 std::string root= this->Makefile->GetRequiredDefinition("CMAKE_ROOT");
759 const char *def=
760 this->Makefile->GetDefinition( "MSPROJECT_TEMPLATE_DIRECTORY");
762 if( def)
764 root = def;
766 else
768 root += "/Templates";
771 switch(b)
773 case STATIC_LIBRARY:
774 this->DSPHeaderTemplate = root;
775 this->DSPHeaderTemplate += "/staticLibHeader.dsptemplate";
776 this->DSPFooterTemplate = root;
777 this->DSPFooterTemplate += "/staticLibFooter.dsptemplate";
778 break;
779 case DLL:
780 this->DSPHeaderTemplate = root;
781 this->DSPHeaderTemplate += "/DLLHeader.dsptemplate";
782 this->DSPFooterTemplate = root;
783 this->DSPFooterTemplate += "/DLLFooter.dsptemplate";
784 break;
785 case EXECUTABLE:
786 if ( target.GetPropertyAsBool("WIN32_EXECUTABLE") )
788 this->DSPHeaderTemplate = root;
789 this->DSPHeaderTemplate += "/EXEWinHeader.dsptemplate";
790 this->DSPFooterTemplate = root;
791 this->DSPFooterTemplate += "/EXEFooter.dsptemplate";
793 else
795 this->DSPHeaderTemplate = root;
796 this->DSPHeaderTemplate += "/EXEHeader.dsptemplate";
797 this->DSPFooterTemplate = root;
798 this->DSPFooterTemplate += "/EXEFooter.dsptemplate";
800 break;
801 case UTILITY:
802 this->DSPHeaderTemplate = root;
803 this->DSPHeaderTemplate += "/UtilityHeader.dsptemplate";
804 this->DSPFooterTemplate = root;
805 this->DSPFooterTemplate += "/UtilityFooter.dsptemplate";
806 break;
809 // once the build type is set, determine what configurations are
810 // possible
811 std::ifstream fin(this->DSPHeaderTemplate.c_str());
813 cmsys::RegularExpression reg("# Name ");
814 if(!fin)
816 cmSystemTools::Error("Error Reading ", this->DSPHeaderTemplate.c_str());
819 // reset this->Configurations
820 this->Configurations.erase(this->Configurations.begin(),
821 this->Configurations.end());
823 // now add all the configurations possible
824 std::string vs6name = GetVS6TargetName(libName);
825 std::string line;
826 while(cmSystemTools::GetLineFromStream(fin, line))
828 cmSystemTools::ReplaceString(line, "OUTPUT_LIBNAME", vs6name.c_str());
829 if (reg.find(line))
831 this->Configurations.push_back(line.substr(reg.end()));
836 // look for custom rules on a target and collect them together
837 std::string
838 cmLocalVisualStudio6Generator::CreateTargetRules(cmTarget &target,
839 const char* configName,
840 const char * /* libName */)
842 if (target.GetType() >= cmTarget::UTILITY )
844 return "";
847 std::string customRuleCode = "# Begin Special Build Tool\n";
848 EventWriter event(this, configName, customRuleCode);
850 // Write the pre-build and pre-link together (VS6 does not support both).
851 event.Start("PreLink");
852 event.Write(target.GetPreBuildCommands());
853 event.Write(target.GetPreLinkCommands());
854 cmsys::auto_ptr<cmCustomCommand> pcc(
855 this->MaybeCreateImplibDir(target, configName));
856 if(pcc.get())
858 event.Write(*pcc);
860 event.Finish();
862 // Write the post-build rules.
863 event.Start("PostBuild");
864 event.Write(target.GetPostBuildCommands());
865 event.Finish();
867 customRuleCode += "# End Special Build Tool\n";
868 return customRuleCode;
872 inline std::string removeQuotes(const std::string& s)
874 if(s[0] == '\"' && s[s.size()-1] == '\"')
876 return s.substr(1, s.size()-2);
878 return s;
881 // Code in blocks surrounded by a test for this definition is needed
882 // only for compatibility with user project's replacement DSP
883 // templates. The CMake templates no longer use them.
884 #define CM_USE_OLD_VS6
886 void cmLocalVisualStudio6Generator
887 ::WriteDSPHeader(std::ostream& fout,
888 const char *libName, cmTarget &target,
889 std::vector<cmSourceGroup> &)
891 bool targetBuilds = (target.GetType() >= cmTarget::EXECUTABLE &&
892 target.GetType() <= cmTarget::MODULE_LIBRARY);
893 #ifdef CM_USE_OLD_VS6
894 // Lookup the library and executable output directories.
895 std::string libPath;
896 if(this->Makefile->GetDefinition("LIBRARY_OUTPUT_PATH"))
898 libPath = this->Makefile->GetDefinition("LIBRARY_OUTPUT_PATH");
900 std::string exePath;
901 if(this->Makefile->GetDefinition("EXECUTABLE_OUTPUT_PATH"))
903 exePath = this->Makefile->GetDefinition("EXECUTABLE_OUTPUT_PATH");
906 // Make sure there are trailing slashes.
907 if(!libPath.empty())
909 if(libPath[libPath.size()-1] != '/')
911 libPath += "/";
914 if(!exePath.empty())
916 if(exePath[exePath.size()-1] != '/')
918 exePath += "/";
922 std::set<std::string> pathEmitted;
924 // determine the link directories
925 std::string libOptions;
926 std::string libDebugOptions;
927 std::string libOptimizedOptions;
929 std::string libMultiLineOptions;
930 std::string libMultiLineOptionsForDebug;
931 std::string libMultiLineDebugOptions;
932 std::string libMultiLineOptimizedOptions;
934 if(libPath.size())
936 std::string lpath =
937 this->ConvertToOptionallyRelativeOutputPath(libPath.c_str());
938 if(lpath.size() == 0)
940 lpath = ".";
942 std::string lpathIntDir = libPath + "$(INTDIR)";
943 lpathIntDir =
944 this->ConvertToOptionallyRelativeOutputPath(lpathIntDir.c_str());
945 if(pathEmitted.insert(lpath).second)
947 libOptions += " /LIBPATH:";
948 libOptions += lpathIntDir;
949 libOptions += " ";
950 libOptions += " /LIBPATH:";
951 libOptions += lpath;
952 libOptions += " ";
953 libMultiLineOptions += "# ADD LINK32 /LIBPATH:";
954 libMultiLineOptions += lpathIntDir;
955 libMultiLineOptions += " ";
956 libMultiLineOptions += " /LIBPATH:";
957 libMultiLineOptions += lpath;
958 libMultiLineOptions += " \n";
959 libMultiLineOptionsForDebug += "# ADD LINK32 /LIBPATH:";
960 libMultiLineOptionsForDebug += lpathIntDir;
961 libMultiLineOptionsForDebug += " ";
962 libMultiLineOptionsForDebug += " /LIBPATH:";
963 libMultiLineOptionsForDebug += lpath;
964 libMultiLineOptionsForDebug += " \n";
967 if(exePath.size())
969 std::string lpath =
970 this->ConvertToOptionallyRelativeOutputPath(exePath.c_str());
971 if(lpath.size() == 0)
973 lpath = ".";
975 std::string lpathIntDir = exePath + "$(INTDIR)";
976 lpathIntDir =
977 this->ConvertToOptionallyRelativeOutputPath(lpathIntDir.c_str());
979 if(pathEmitted.insert(lpath).second)
981 libOptions += " /LIBPATH:";
982 libOptions += lpathIntDir;
983 libOptions += " ";
984 libOptions += " /LIBPATH:";
985 libOptions += lpath;
986 libOptions += " ";
987 libMultiLineOptions += "# ADD LINK32 /LIBPATH:";
988 libMultiLineOptions += lpathIntDir;
989 libMultiLineOptions += " ";
990 libMultiLineOptions += " /LIBPATH:";
991 libMultiLineOptions += lpath;
992 libMultiLineOptions += " \n";
993 libMultiLineOptionsForDebug += "# ADD LINK32 /LIBPATH:";
994 libMultiLineOptionsForDebug += lpathIntDir;
995 libMultiLineOptionsForDebug += " ";
996 libMultiLineOptionsForDebug += " /LIBPATH:";
997 libMultiLineOptionsForDebug += lpath;
998 libMultiLineOptionsForDebug += " \n";
1001 std::vector<std::string>::const_iterator i;
1002 const std::vector<std::string>& libdirs = target.GetLinkDirectories();
1003 for(i = libdirs.begin(); i != libdirs.end(); ++i)
1005 std::string path = *i;
1006 if(path[path.size()-1] != '/')
1008 path += "/";
1010 std::string lpath =
1011 this->ConvertToOptionallyRelativeOutputPath(path.c_str());
1012 if(lpath.size() == 0)
1014 lpath = ".";
1016 std::string lpathIntDir = path + "$(INTDIR)";
1017 lpathIntDir =
1018 this->ConvertToOptionallyRelativeOutputPath(lpathIntDir.c_str());
1019 if(pathEmitted.insert(lpath).second)
1021 libOptions += " /LIBPATH:";
1022 libOptions += lpathIntDir;
1023 libOptions += " ";
1024 libOptions += " /LIBPATH:";
1025 libOptions += lpath;
1026 libOptions += " ";
1028 libMultiLineOptions += "# ADD LINK32 /LIBPATH:";
1029 libMultiLineOptions += lpathIntDir;
1030 libMultiLineOptions += " ";
1031 libMultiLineOptions += " /LIBPATH:";
1032 libMultiLineOptions += lpath;
1033 libMultiLineOptions += " \n";
1034 libMultiLineOptionsForDebug += "# ADD LINK32 /LIBPATH:";
1035 libMultiLineOptionsForDebug += lpathIntDir;
1036 libMultiLineOptionsForDebug += " ";
1037 libMultiLineOptionsForDebug += " /LIBPATH:";
1038 libMultiLineOptionsForDebug += lpath;
1039 libMultiLineOptionsForDebug += " \n";
1042 // find link libraries
1043 const cmTarget::LinkLibraryVectorType& libs = target.GetLinkLibraries();
1044 cmTarget::LinkLibraryVectorType::const_iterator j;
1045 for(j = libs.begin(); j != libs.end(); ++j)
1047 // add libraries to executables and dlls (but never include
1048 // a library in a library, bad recursion)
1049 // NEVER LINK STATIC LIBRARIES TO OTHER STATIC LIBRARIES
1050 if ((target.GetType() != cmTarget::SHARED_LIBRARY
1051 && target.GetType() != cmTarget::STATIC_LIBRARY
1052 && target.GetType() != cmTarget::MODULE_LIBRARY) ||
1053 (target.GetType()==cmTarget::SHARED_LIBRARY
1054 && libName != GetVS6TargetName(j->first)) ||
1055 (target.GetType()==cmTarget::MODULE_LIBRARY
1056 && libName != GetVS6TargetName(j->first)))
1058 // Compute the proper name to use to link this library.
1059 std::string lib;
1060 std::string libDebug;
1061 cmTarget* tgt = this->GlobalGenerator->FindTarget(0, j->first.c_str());
1062 if(tgt)
1064 lib = cmSystemTools::GetFilenameWithoutExtension
1065 (tgt->GetFullName().c_str());
1066 libDebug = cmSystemTools::GetFilenameWithoutExtension
1067 (tgt->GetFullName("Debug").c_str());
1068 lib += ".lib";
1069 libDebug += ".lib";
1071 else
1073 lib = j->first.c_str();
1074 libDebug = j->first.c_str();
1075 if(j->first.find(".lib") == std::string::npos)
1077 lib += ".lib";
1078 libDebug += ".lib";
1081 lib = this->ConvertToOptionallyRelativeOutputPath(lib.c_str());
1082 libDebug =
1083 this->ConvertToOptionallyRelativeOutputPath(libDebug.c_str());
1085 if (j->second == cmTarget::GENERAL)
1087 libOptions += " ";
1088 libOptions += lib;
1089 libMultiLineOptions += "# ADD LINK32 ";
1090 libMultiLineOptions += lib;
1091 libMultiLineOptions += "\n";
1092 libMultiLineOptionsForDebug += "# ADD LINK32 ";
1093 libMultiLineOptionsForDebug += libDebug;
1094 libMultiLineOptionsForDebug += "\n";
1096 if (j->second == cmTarget::DEBUG)
1098 libDebugOptions += " ";
1099 libDebugOptions += lib;
1101 libMultiLineDebugOptions += "# ADD LINK32 ";
1102 libMultiLineDebugOptions += libDebug;
1103 libMultiLineDebugOptions += "\n";
1105 if (j->second == cmTarget::OPTIMIZED)
1107 libOptimizedOptions += " ";
1108 libOptimizedOptions += lib;
1110 libMultiLineOptimizedOptions += "# ADD LINK32 ";
1111 libMultiLineOptimizedOptions += lib;
1112 libMultiLineOptimizedOptions += "\n";
1116 #endif
1118 // Get extra linker options for this target type.
1119 std::string extraLinkOptions;
1120 if(target.GetType() == cmTarget::EXECUTABLE)
1122 extraLinkOptions =
1123 this->Makefile->GetRequiredDefinition("CMAKE_EXE_LINKER_FLAGS");
1125 if(target.GetType() == cmTarget::SHARED_LIBRARY)
1127 extraLinkOptions =
1128 this->Makefile->GetRequiredDefinition("CMAKE_SHARED_LINKER_FLAGS");
1130 if(target.GetType() == cmTarget::MODULE_LIBRARY)
1132 extraLinkOptions =
1133 this->Makefile->GetRequiredDefinition("CMAKE_MODULE_LINKER_FLAGS");
1136 // Get extra linker options for this target.
1137 if(const char* targetLinkFlags = target.GetProperty("LINK_FLAGS"))
1139 extraLinkOptions += " ";
1140 extraLinkOptions += targetLinkFlags;
1143 // Get standard libraries for this language.
1144 if(targetBuilds)
1146 // Get the language to use for linking.
1147 const char* linkLanguage = target.GetLinkerLanguage();
1148 if(!linkLanguage)
1150 cmSystemTools::Error
1151 ("CMake can not determine linker language for target:",
1152 target.GetName());
1153 return;
1156 // Compute the variable name to lookup standard libraries for this
1157 // language.
1158 std::string standardLibsVar = "CMAKE_";
1159 standardLibsVar += linkLanguage;
1160 standardLibsVar += "_STANDARD_LIBRARIES";
1162 // Add standard libraries.
1163 if(const char* stdLibs =
1164 this->Makefile->GetDefinition(standardLibsVar.c_str()))
1166 extraLinkOptions += " ";
1167 extraLinkOptions += stdLibs;
1171 // Compute version number information.
1172 std::string targetVersionFlag;
1173 if(target.GetType() == cmTarget::EXECUTABLE ||
1174 target.GetType() == cmTarget::SHARED_LIBRARY ||
1175 target.GetType() == cmTarget::MODULE_LIBRARY)
1177 int major;
1178 int minor;
1179 target.GetTargetVersion(major, minor);
1180 cmOStringStream targetVersionStream;
1181 targetVersionStream << "/version:" << major << "." << minor;
1182 targetVersionFlag = targetVersionStream.str();
1185 // Compute the real name of the target.
1186 std::string outputName =
1187 "(OUTPUT_NAME is for libraries and executables only)";
1188 std::string outputNameDebug = outputName;
1189 std::string outputNameRelease = outputName;
1190 std::string outputNameMinSizeRel = outputName;
1191 std::string outputNameRelWithDebInfo = outputName;
1192 if(target.GetType() == cmTarget::EXECUTABLE ||
1193 target.GetType() == cmTarget::STATIC_LIBRARY ||
1194 target.GetType() == cmTarget::SHARED_LIBRARY ||
1195 target.GetType() == cmTarget::MODULE_LIBRARY)
1197 outputName = target.GetFullName();
1198 outputNameDebug = target.GetFullName("Debug");
1199 outputNameRelease = target.GetFullName("Release");
1200 outputNameMinSizeRel = target.GetFullName("MinSizeRel");
1201 outputNameRelWithDebInfo = target.GetFullName("RelWithDebInfo");
1204 // Compute the proper link information for the target.
1205 std::string optionsDebug;
1206 std::string optionsRelease;
1207 std::string optionsMinSizeRel;
1208 std::string optionsRelWithDebInfo;
1209 if(target.GetType() == cmTarget::EXECUTABLE ||
1210 target.GetType() == cmTarget::SHARED_LIBRARY ||
1211 target.GetType() == cmTarget::MODULE_LIBRARY)
1213 this->ComputeLinkOptions(target, "Debug", extraLinkOptions,
1214 optionsDebug);
1215 this->ComputeLinkOptions(target, "Release", extraLinkOptions,
1216 optionsRelease);
1217 this->ComputeLinkOptions(target, "MinSizeRel", extraLinkOptions,
1218 optionsMinSizeRel);
1219 this->ComputeLinkOptions(target, "RelWithDebInfo", extraLinkOptions,
1220 optionsRelWithDebInfo);
1223 // Compute the path of the import library.
1224 std::string targetImplibFlagDebug;
1225 std::string targetImplibFlagRelease;
1226 std::string targetImplibFlagMinSizeRel;
1227 std::string targetImplibFlagRelWithDebInfo;
1228 if(target.GetType() == cmTarget::SHARED_LIBRARY ||
1229 target.GetType() == cmTarget::MODULE_LIBRARY ||
1230 target.GetType() == cmTarget::EXECUTABLE)
1232 std::string fullPathImpDebug = target.GetDirectory("Debug", true);
1233 std::string fullPathImpRelease = target.GetDirectory("Release", true);
1234 std::string fullPathImpMinSizeRel =
1235 target.GetDirectory("MinSizeRel", true);
1236 std::string fullPathImpRelWithDebInfo =
1237 target.GetDirectory("RelWithDebInfo", true);
1238 fullPathImpDebug += "/";
1239 fullPathImpRelease += "/";
1240 fullPathImpMinSizeRel += "/";
1241 fullPathImpRelWithDebInfo += "/";
1242 fullPathImpDebug += target.GetFullName("Debug", true);
1243 fullPathImpRelease += target.GetFullName("Release", true);
1244 fullPathImpMinSizeRel += target.GetFullName("MinSizeRel", true);
1245 fullPathImpRelWithDebInfo += target.GetFullName("RelWithDebInfo", true);
1247 targetImplibFlagDebug = "/implib:";
1248 targetImplibFlagRelease = "/implib:";
1249 targetImplibFlagMinSizeRel = "/implib:";
1250 targetImplibFlagRelWithDebInfo = "/implib:";
1251 targetImplibFlagDebug +=
1252 this->ConvertToOptionallyRelativeOutputPath(fullPathImpDebug.c_str());
1253 targetImplibFlagRelease +=
1254 this->ConvertToOptionallyRelativeOutputPath(fullPathImpRelease.c_str());
1255 targetImplibFlagMinSizeRel +=
1256 this->ConvertToOptionallyRelativeOutputPath(
1257 fullPathImpMinSizeRel.c_str());
1258 targetImplibFlagRelWithDebInfo +=
1259 this->ConvertToOptionallyRelativeOutputPath(
1260 fullPathImpRelWithDebInfo.c_str());
1263 #ifdef CM_USE_OLD_VS6
1264 // Compute link information for the target.
1265 if(extraLinkOptions.size())
1267 libOptions += " ";
1268 libOptions += extraLinkOptions;
1269 libOptions += " ";
1270 libMultiLineOptions += "# ADD LINK32 ";
1271 libMultiLineOptions += extraLinkOptions;
1272 libMultiLineOptions += " \n";
1273 libMultiLineOptionsForDebug += "# ADD LINK32 ";
1274 libMultiLineOptionsForDebug += extraLinkOptions;
1275 libMultiLineOptionsForDebug += " \n";
1277 #endif
1279 // are there any custom rules on the target itself
1280 // only if the target is a lib or exe
1281 std::string customRuleCodeRelease
1282 = this->CreateTargetRules(target, "RELEASE", libName);
1283 std::string customRuleCodeDebug
1284 = this->CreateTargetRules(target, "DEBUG", libName);
1285 std::string customRuleCodeMinSizeRel
1286 = this->CreateTargetRules(target, "MINSIZEREL", libName);
1287 std::string customRuleCodeRelWithDebInfo
1288 = this->CreateTargetRules(target, "RELWITHDEBINFO", libName);
1290 std::ifstream fin(this->DSPHeaderTemplate.c_str());
1291 if(!fin)
1293 cmSystemTools::Error("Error Reading ", this->DSPHeaderTemplate.c_str());
1295 std::string staticLibOptions;
1296 if(target.GetType() == cmTarget::STATIC_LIBRARY )
1298 if(const char* libflags = target.GetProperty("STATIC_LIBRARY_FLAGS"))
1300 staticLibOptions = libflags;
1304 // Add the export symbol definition for shared library objects.
1305 std::string exportSymbol;
1306 if(const char* exportMacro = target.GetExportMacro())
1308 exportSymbol = exportMacro;
1311 std::string line;
1312 std::string libnameExports;
1313 if(exportSymbol.size())
1315 libnameExports = "/D \"";
1316 libnameExports += exportSymbol;
1317 libnameExports += "\"";
1319 while(cmSystemTools::GetLineFromStream(fin, line))
1321 const char* mfcFlag = this->Makefile->GetDefinition("CMAKE_MFC_FLAG");
1322 if(!mfcFlag)
1324 mfcFlag = "0";
1326 cmSystemTools::ReplaceString(line, "OUTPUT_LIBNAME_EXPORTS",
1327 libnameExports.c_str());
1328 cmSystemTools::ReplaceString(line, "CMAKE_MFC_FLAG",
1329 mfcFlag);
1330 if(target.GetType() == cmTarget::STATIC_LIBRARY )
1332 cmSystemTools::ReplaceString(line, "CM_STATIC_LIB_ARGS",
1333 staticLibOptions.c_str());
1335 if(this->Makefile->IsOn("CMAKE_VERBOSE_MAKEFILE"))
1337 cmSystemTools::ReplaceString(line, "/nologo", "");
1340 #ifdef CM_USE_OLD_VS6
1341 cmSystemTools::ReplaceString(line, "CM_LIBRARIES",
1342 libOptions.c_str());
1343 cmSystemTools::ReplaceString(line, "CM_DEBUG_LIBRARIES",
1344 libDebugOptions.c_str());
1345 cmSystemTools::ReplaceString(line, "CM_OPTIMIZED_LIBRARIES",
1346 libOptimizedOptions.c_str());
1347 cmSystemTools::ReplaceString(line, "CM_MULTILINE_LIBRARIES_FOR_DEBUG",
1348 libMultiLineOptionsForDebug.c_str());
1349 cmSystemTools::ReplaceString(line, "CM_MULTILINE_LIBRARIES",
1350 libMultiLineOptions.c_str());
1351 cmSystemTools::ReplaceString(line, "CM_MULTILINE_DEBUG_LIBRARIES",
1352 libMultiLineDebugOptions.c_str());
1353 cmSystemTools::ReplaceString(line, "CM_MULTILINE_OPTIMIZED_LIBRARIES",
1354 libMultiLineOptimizedOptions.c_str());
1355 #endif
1357 // Substitute the rules for custom command. When specifying just the
1358 // target name for the command the command can be different for
1359 // different configs
1360 cmSystemTools::ReplaceString(line, "CMAKE_CUSTOM_RULE_CODE_RELEASE",
1361 customRuleCodeRelease.c_str());
1362 cmSystemTools::ReplaceString(line, "CMAKE_CUSTOM_RULE_CODE_DEBUG",
1363 customRuleCodeDebug.c_str());
1364 cmSystemTools::ReplaceString(line, "CMAKE_CUSTOM_RULE_CODE_MINSIZEREL",
1365 customRuleCodeMinSizeRel.c_str());
1366 cmSystemTools::ReplaceString(line, "CMAKE_CUSTOM_RULE_CODE_RELWITHDEBINFO",
1367 customRuleCodeRelWithDebInfo.c_str());
1369 // Substitute the real output name into the template.
1370 cmSystemTools::ReplaceString(line, "OUTPUT_NAME_DEBUG",
1371 outputNameDebug.c_str());
1372 cmSystemTools::ReplaceString(line, "OUTPUT_NAME_RELEASE",
1373 outputNameRelease.c_str());
1374 cmSystemTools::ReplaceString(line, "OUTPUT_NAME_MINSIZEREL",
1375 outputNameMinSizeRel.c_str());
1376 cmSystemTools::ReplaceString(line, "OUTPUT_NAME_RELWITHDEBINFO",
1377 outputNameRelWithDebInfo.c_str());
1378 cmSystemTools::ReplaceString(line, "OUTPUT_NAME", outputName.c_str());
1380 // Substitute the proper link information into the template.
1381 cmSystemTools::ReplaceString(line, "CM_MULTILINE_OPTIONS_DEBUG",
1382 optionsDebug.c_str());
1383 cmSystemTools::ReplaceString(line, "CM_MULTILINE_OPTIONS_RELEASE",
1384 optionsRelease.c_str());
1385 cmSystemTools::ReplaceString(line, "CM_MULTILINE_OPTIONS_MINSIZEREL",
1386 optionsMinSizeRel.c_str());
1387 cmSystemTools::ReplaceString(line, "CM_MULTILINE_OPTIONS_RELWITHDEBINFO",
1388 optionsRelWithDebInfo.c_str());
1390 cmSystemTools::ReplaceString(line, "BUILD_INCLUDES",
1391 this->IncludeOptions.c_str());
1392 cmSystemTools::ReplaceString(line, "TARGET_VERSION_FLAG",
1393 targetVersionFlag.c_str());
1394 cmSystemTools::ReplaceString(line, "TARGET_IMPLIB_FLAG_DEBUG",
1395 targetImplibFlagDebug.c_str());
1396 cmSystemTools::ReplaceString(line, "TARGET_IMPLIB_FLAG_RELEASE",
1397 targetImplibFlagRelease.c_str());
1398 cmSystemTools::ReplaceString(line, "TARGET_IMPLIB_FLAG_MINSIZEREL",
1399 targetImplibFlagMinSizeRel.c_str());
1400 cmSystemTools::ReplaceString(line, "TARGET_IMPLIB_FLAG_RELWITHDEBINFO",
1401 targetImplibFlagRelWithDebInfo.c_str());
1403 std::string vs6name = GetVS6TargetName(libName);
1404 cmSystemTools::ReplaceString(line, "OUTPUT_LIBNAME", vs6name.c_str());
1406 #ifdef CM_USE_OLD_VS6
1407 // because LIBRARY_OUTPUT_PATH and EXECUTABLE_OUTPUT_PATH
1408 // are already quoted in the template file,
1409 // we need to remove the quotes here, we still need
1410 // to convert to output path for unix to win32 conversion
1411 cmSystemTools::ReplaceString
1412 (line, "LIBRARY_OUTPUT_PATH",
1413 removeQuotes(this->ConvertToOptionallyRelativeOutputPath
1414 (libPath.c_str())).c_str());
1415 cmSystemTools::ReplaceString
1416 (line, "EXECUTABLE_OUTPUT_PATH",
1417 removeQuotes(this->ConvertToOptionallyRelativeOutputPath
1418 (exePath.c_str())).c_str());
1419 #endif
1421 if(targetBuilds)
1423 std::string outPath = target.GetDirectory();
1424 cmSystemTools::ReplaceString
1425 (line, "OUTPUT_DIRECTORY",
1426 removeQuotes(this->ConvertToOptionallyRelativeOutputPath
1427 (outPath.c_str())).c_str());
1430 cmSystemTools::ReplaceString(line,
1431 "EXTRA_DEFINES",
1432 this->Makefile->GetDefineFlags());
1433 const char* debugPostfix
1434 = this->Makefile->GetDefinition("CMAKE_DEBUG_POSTFIX");
1435 cmSystemTools::ReplaceString(line, "DEBUG_POSTFIX",
1436 debugPostfix?debugPostfix:"");
1437 // store flags for each configuration
1438 std::string flags = " ";
1439 std::string flagsRelease = " ";
1440 std::string flagsMinSize = " ";
1441 std::string flagsDebug = " ";
1442 std::string flagsDebugRel = " ";
1443 if(target.GetType() >= cmTarget::EXECUTABLE &&
1444 target.GetType() <= cmTarget::MODULE_LIBRARY)
1446 const char* linkLanguage = target.GetLinkerLanguage();
1447 if(!linkLanguage)
1449 cmSystemTools::Error
1450 ("CMake can not determine linker language for target:",
1451 target.GetName());
1452 return;
1454 // if CXX is on and the target contains cxx code then add the cxx flags
1455 std::string baseFlagVar = "CMAKE_";
1456 baseFlagVar += linkLanguage;
1457 baseFlagVar += "_FLAGS";
1458 flags = this->Makefile->GetSafeDefinition(baseFlagVar.c_str());
1460 std::string flagVar = baseFlagVar + "_RELEASE";
1461 flagsRelease = this->Makefile->GetSafeDefinition(flagVar.c_str());
1462 flagsRelease += " -DCMAKE_INTDIR=\\\"Release\\\" ";
1463 if(const char* targetLinkFlags =
1464 target.GetProperty("LINK_FLAGS_RELEASE"))
1466 flagsRelease += targetLinkFlags;
1467 flagsRelease += " ";
1469 flagVar = baseFlagVar + "_MINSIZEREL";
1470 flagsMinSize = this->Makefile->GetSafeDefinition(flagVar.c_str());
1471 flagsMinSize += " -DCMAKE_INTDIR=\\\"MinSizeRel\\\" ";
1472 if(const char* targetLinkFlags =
1473 target.GetProperty("LINK_FLAGS_MINSIZEREL"))
1475 flagsMinSize += targetLinkFlags;
1476 flagsMinSize += " ";
1479 flagVar = baseFlagVar + "_DEBUG";
1480 flagsDebug = this->Makefile->GetSafeDefinition(flagVar.c_str());
1481 flagsDebug += " -DCMAKE_INTDIR=\\\"Debug\\\" ";
1482 if(const char* targetLinkFlags = target.GetProperty("LINK_FLAGS_DEBUG"))
1484 flagsDebug += targetLinkFlags;
1485 flagsDebug += " ";
1488 flagVar = baseFlagVar + "_RELWITHDEBINFO";
1489 flagsDebugRel = this->Makefile->GetSafeDefinition(flagVar.c_str());
1490 flagsDebugRel += " -DCMAKE_INTDIR=\\\"RelWithDebInfo\\\" ";
1491 if(const char* targetLinkFlags =
1492 target.GetProperty("LINK_FLAGS_RELWITHDEBINFO"))
1494 flagsDebugRel += targetLinkFlags;
1495 flagsDebugRel += " ";
1500 // if unicode is not found, then add -D_MBCS
1501 std::string defs = this->Makefile->GetDefineFlags();
1502 if(flags.find("D_UNICODE") == flags.npos &&
1503 defs.find("D_UNICODE") == flags.npos)
1505 flags += " /D \"_MBCS\"";
1508 // Add per-target flags.
1509 if(const char* targetFlags = target.GetProperty("COMPILE_FLAGS"))
1511 flags += " ";
1512 flags += targetFlags;
1515 // Add per-target and per-configuration preprocessor definitions.
1516 std::string defines = " ";
1517 std::string debugDefines = " ";
1518 std::string releaseDefines = " ";
1519 std::string minsizeDefines = " ";
1520 std::string debugrelDefines = " ";
1522 this->AppendDefines(
1523 defines,
1524 this->Makefile->GetProperty("COMPILE_DEFINITIONS"), 0);
1525 this->AppendDefines(
1526 debugDefines,
1527 this->Makefile->GetProperty("COMPILE_DEFINITIONS_DEBUG"),0);
1528 this->AppendDefines(
1529 releaseDefines,
1530 this->Makefile->GetProperty("COMPILE_DEFINITIONS_RELEASE"), 0);
1531 this->AppendDefines(
1532 minsizeDefines,
1533 this->Makefile->GetProperty("COMPILE_DEFINITIONS_MINSIZEREL"), 0);
1534 this->AppendDefines(
1535 debugrelDefines,
1536 this->Makefile->GetProperty("COMPILE_DEFINITIONS_RELWITHDEBINFO"), 0);
1538 this->AppendDefines(
1539 defines,
1540 target.GetProperty("COMPILE_DEFINITIONS"), 0);
1541 this->AppendDefines(
1542 debugDefines,
1543 target.GetProperty("COMPILE_DEFINITIONS_DEBUG"), 0);
1544 this->AppendDefines(
1545 releaseDefines,
1546 target.GetProperty("COMPILE_DEFINITIONS_RELEASE"), 0);
1547 this->AppendDefines(
1548 minsizeDefines,
1549 target.GetProperty("COMPILE_DEFINITIONS_MINSIZEREL"), 0);
1550 this->AppendDefines(
1551 debugrelDefines,
1552 target.GetProperty("COMPILE_DEFINITIONS_RELWITHDEBINFO"), 0);
1553 flags += defines;
1554 flagsDebug += debugDefines;
1555 flagsRelease += releaseDefines;
1556 flagsMinSize += minsizeDefines;
1557 flagsDebugRel += debugrelDefines;
1559 // The template files have CXX FLAGS in them, that need to be replaced.
1560 // There are not separate CXX and C template files, so we use the same
1561 // variable names. The previous code sets up flags* variables to contain
1562 // the correct C or CXX flags
1563 cmSystemTools::ReplaceString(line, "CMAKE_CXX_FLAGS_MINSIZEREL",
1564 flagsMinSize.c_str());
1565 cmSystemTools::ReplaceString(line, "CMAKE_CXX_FLAGS_DEBUG",
1566 flagsDebug.c_str());
1567 cmSystemTools::ReplaceString(line, "CMAKE_CXX_FLAGS_RELWITHDEBINFO",
1568 flagsDebugRel.c_str());
1569 cmSystemTools::ReplaceString(line, "CMAKE_CXX_FLAGS_RELEASE",
1570 flagsRelease.c_str());
1571 cmSystemTools::ReplaceString(line, "CMAKE_CXX_FLAGS", flags.c_str());
1573 cmSystemTools::ReplaceString(line, "COMPILE_DEFINITIONS_MINSIZE",
1574 minsizeDefines.c_str());
1575 cmSystemTools::ReplaceString(line, "COMPILE_DEFINITIONS_DEBUG",
1576 debugDefines.c_str());
1577 cmSystemTools::ReplaceString(line, "COMPILE_DEFINITIONS_RELWITHDEBINFO",
1578 debugrelDefines.c_str());
1579 cmSystemTools::ReplaceString(line, "COMPILE_DEFINITIONS_RELEASE",
1580 releaseDefines.c_str());
1581 cmSystemTools::ReplaceString(line, "COMPILE_DEFINITIONS", defines.c_str());
1583 fout << line.c_str() << std::endl;
1587 void cmLocalVisualStudio6Generator::WriteDSPFooter(std::ostream& fout)
1589 std::ifstream fin(this->DSPFooterTemplate.c_str());
1590 if(!fin)
1592 cmSystemTools::Error("Error Reading ",
1593 this->DSPFooterTemplate.c_str());
1595 std::string line;
1596 while(cmSystemTools::GetLineFromStream(fin, line))
1598 fout << line << std::endl;
1602 //----------------------------------------------------------------------------
1603 void cmLocalVisualStudio6Generator
1604 ::ComputeLinkOptions(cmTarget& target,
1605 const char* configName,
1606 const std::string extraOptions,
1607 std::string& options)
1609 // Compute the link information for this configuration.
1610 cmComputeLinkInformation* pcli = target.GetLinkInformation(configName);
1611 if(!pcli)
1613 return;
1615 cmComputeLinkInformation& cli = *pcli;
1616 typedef cmComputeLinkInformation::ItemVector ItemVector;
1617 ItemVector const& linkLibs = cli.GetItems();
1618 std::vector<std::string> const& linkDirs = cli.GetDirectories();
1620 // Build the link options code.
1621 for(std::vector<std::string>::const_iterator d = linkDirs.begin();
1622 d != linkDirs.end(); ++d)
1624 std::string dir = *d;
1625 if(!dir.empty())
1627 if(dir[dir.size()-1] != '/')
1629 dir += "/";
1631 dir += "$(IntDir)";
1632 options += "# ADD LINK32 /LIBPATH:";
1633 options += this->ConvertToOptionallyRelativeOutputPath(dir.c_str());
1634 options += " /LIBPATH:";
1635 options += this->ConvertToOptionallyRelativeOutputPath(d->c_str());
1636 options += "\n";
1639 for(ItemVector::const_iterator l = linkLibs.begin();
1640 l != linkLibs.end(); ++l)
1642 options += "# ADD LINK32 ";
1643 if(l->IsPath)
1645 options +=
1646 this->ConvertToOptionallyRelativeOutputPath(l->Value.c_str());
1648 else
1650 options += l->Value;
1652 options += "\n";
1655 // Add extra options if any.
1656 if(!extraOptions.empty())
1658 options += "# ADD LINK32 ";
1659 options += extraOptions;
1660 options += "\n";
1664 std::string
1665 cmLocalVisualStudio6Generator
1666 ::GetTargetDirectory(cmTarget const&) const
1668 // No per-target directory for this generator (yet).
1669 return "";
1672 void cmLocalVisualStudio6Generator
1673 ::GetTargetObjectFileDirectories(cmTarget* ,
1674 std::vector<std::string>&
1675 dirs)
1677 std::string dir = this->Makefile->GetCurrentOutputDirectory();
1678 dir += "/";
1679 dir += this->GetGlobalGenerator()->GetCMakeCFGInitDirectory();
1680 dirs.push_back(dir);
1683 std::string
1684 cmLocalVisualStudio6Generator
1685 ::GetConfigName(std::string const& configuration) const
1687 // Strip the subdirectory name out of the configuration name.
1688 std::string config = configuration;
1689 std::string::size_type pos = config.find_last_of(" ");
1690 config = config.substr(pos+1, std::string::npos);
1691 config = config.substr(0, config.size()-1);
1692 return config;
1695 //----------------------------------------------------------------------------
1696 bool
1697 cmLocalVisualStudio6Generator
1698 ::CheckDefinition(std::string const& define) const
1700 // Perform the standard check first.
1701 if(!this->cmLocalGenerator::CheckDefinition(define))
1703 return false;
1706 // Now do the VS6-specific check.
1707 if(define.find_first_of(" ") != define.npos &&
1708 define.find_first_of("\"$;") != define.npos)
1710 cmOStringStream e;
1711 e << "WARNING: The VS6 IDE does not support preprocessor definition "
1712 << "values with spaces and '\"', '$', or ';'.\n"
1713 << "CMake is dropping a preprocessor definition: " << define << "\n"
1714 << "Consider defining the macro in a (configured) header file.\n";
1715 cmSystemTools::Message(e.str().c_str());
1716 return false;
1719 // Assume it is supported.
1720 return true;