cmLocalVisualStudio6Generator.cxx 36 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120
  1. /*=========================================================================
  2. Program: CMake - Cross-Platform Makefile Generator
  3. Module: $RCSfile$
  4. Language: C++
  5. Date: $Date$
  6. Version: $Revision$
  7. Copyright (c) 2002 Kitware, Inc., Insight Consortium. All rights reserved.
  8. See Copyright.txt or http://www.cmake.org/HTML/Copyright.html for details.
  9. This software is distributed WITHOUT ANY WARRANTY; without even
  10. the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
  11. PURPOSE. See the above copyright notices for more information.
  12. =========================================================================*/
  13. #include "cmGlobalGenerator.h"
  14. #include "cmLocalVisualStudio6Generator.h"
  15. #include "cmMakefile.h"
  16. #include "cmSystemTools.h"
  17. #include "cmSourceFile.h"
  18. #include "cmCacheManager.h"
  19. #include "cmake.h"
  20. #include <cmsys/RegularExpression.hxx>
  21. cmLocalVisualStudio6Generator::cmLocalVisualStudio6Generator()
  22. {
  23. }
  24. cmLocalVisualStudio6Generator::~cmLocalVisualStudio6Generator()
  25. {
  26. }
  27. void cmLocalVisualStudio6Generator::Generate(bool /* fromTheTop */)
  28. {
  29. this->OutputDSPFile();
  30. }
  31. void cmLocalVisualStudio6Generator::OutputDSPFile()
  32. {
  33. // If not an in source build, then create the output directory
  34. if(strcmp(m_Makefile->GetStartOutputDirectory(),
  35. m_Makefile->GetHomeDirectory()) != 0)
  36. {
  37. if(!cmSystemTools::MakeDirectory(m_Makefile->GetStartOutputDirectory()))
  38. {
  39. cmSystemTools::Error("Error creating directory ",
  40. m_Makefile->GetStartOutputDirectory());
  41. }
  42. }
  43. // Setup /I and /LIBPATH options for the resulting DSP file
  44. std::vector<std::string>& includes = m_Makefile->GetIncludeDirectories();
  45. std::vector<std::string>::iterator i;
  46. for(i = includes.begin(); i != includes.end(); ++i)
  47. {
  48. m_IncludeOptions += " /I ";
  49. std::string tmp = this->ConvertToRelativeOutputPath(i->c_str());
  50. // quote if not already quoted
  51. if (tmp[0] != '"')
  52. {
  53. m_IncludeOptions += "\"";
  54. m_IncludeOptions += tmp;
  55. m_IncludeOptions += "\"";
  56. }
  57. else
  58. {
  59. m_IncludeOptions += tmp;
  60. }
  61. }
  62. // Create the DSP or set of DSP's for libraries and executables
  63. // clear project names
  64. m_CreatedProjectNames.clear();
  65. // expand vars for custom commands
  66. m_Makefile->ExpandVariablesInCustomCommands();
  67. // build any targets
  68. cmTargets &tgts = m_Makefile->GetTargets();
  69. for(cmTargets::iterator l = tgts.begin();
  70. l != tgts.end(); l++)
  71. {
  72. switch(l->second.GetType())
  73. {
  74. case cmTarget::STATIC_LIBRARY:
  75. this->SetBuildType(STATIC_LIBRARY, l->first.c_str(), l->second);
  76. break;
  77. case cmTarget::SHARED_LIBRARY:
  78. case cmTarget::MODULE_LIBRARY:
  79. this->SetBuildType(DLL, l->first.c_str(), l->second);
  80. break;
  81. case cmTarget::EXECUTABLE:
  82. this->SetBuildType(EXECUTABLE,l->first.c_str(), l->second);
  83. break;
  84. case cmTarget::UTILITY:
  85. this->SetBuildType(UTILITY, l->first.c_str(), l->second);
  86. break;
  87. case cmTarget::INSTALL_FILES:
  88. break;
  89. case cmTarget::INSTALL_PROGRAMS:
  90. break;
  91. default:
  92. cmSystemTools::Error("Bad target type", l->first.c_str());
  93. break;
  94. }
  95. // INCLUDE_EXTERNAL_MSPROJECT command only affects the workspace
  96. // so don't build a projectfile for it
  97. if ((l->second.GetType() != cmTarget::INSTALL_FILES)
  98. && (l->second.GetType() != cmTarget::INSTALL_PROGRAMS)
  99. && (strncmp(l->first.c_str(), "INCLUDE_EXTERNAL_MSPROJECT", 26) != 0))
  100. {
  101. // check to see if the dsp is going into a sub-directory
  102. std::string::size_type pos = l->first.rfind('/');
  103. if(pos != std::string::npos)
  104. {
  105. std::string dir = m_Makefile->GetStartOutputDirectory();
  106. dir += "/";
  107. dir += l->first.substr(0, pos);
  108. if(!cmSystemTools::MakeDirectory(dir.c_str()))
  109. {
  110. cmSystemTools::Error("Error creating directory ", dir.c_str());
  111. }
  112. }
  113. this->CreateSingleDSP(l->first.c_str(),l->second);
  114. }
  115. }
  116. }
  117. void cmLocalVisualStudio6Generator::CreateSingleDSP(const char *lname, cmTarget &target)
  118. {
  119. // add to the list of projects
  120. std::string pname = lname;
  121. m_CreatedProjectNames.push_back(pname);
  122. // create the dsp.cmake file
  123. std::string fname;
  124. fname = m_Makefile->GetStartOutputDirectory();
  125. fname += "/";
  126. fname += lname;
  127. fname += ".dsp";
  128. // save the name of the real dsp file
  129. std::string realDSP = fname;
  130. fname += ".cmake";
  131. std::ofstream fout(fname.c_str());
  132. if(!fout)
  133. {
  134. cmSystemTools::Error("Error Writing ", fname.c_str());
  135. cmSystemTools::ReportLastSystemError("");
  136. }
  137. this->WriteDSPFile(fout,lname,target);
  138. fout.close();
  139. // if the dsp file has changed, then write it.
  140. cmSystemTools::CopyFileIfDifferent(fname.c_str(), realDSP.c_str());
  141. }
  142. void cmLocalVisualStudio6Generator::AddDSPBuildRule()
  143. {
  144. std::string dspname = *(m_CreatedProjectNames.end()-1);
  145. dspname += ".dsp.cmake";
  146. std::string makefileIn = m_Makefile->GetStartDirectory();
  147. makefileIn += "/";
  148. makefileIn += "CMakeLists.txt";
  149. makefileIn = this->ConvertToRelativeOutputPath(makefileIn.c_str());
  150. std::string dsprule = "${CMAKE_COMMAND}";
  151. m_Makefile->ExpandVariablesInString(dsprule);
  152. dsprule = this->ConvertToRelativeOutputPath(dsprule.c_str());
  153. std::vector<std::string> argv;
  154. argv.push_back(makefileIn);
  155. makefileIn = m_Makefile->GetStartDirectory();
  156. makefileIn += "/";
  157. makefileIn += "CMakeLists.txt";
  158. std::string args;
  159. args = "-H";
  160. args +=
  161. this->ConvertToRelativeOutputPath(m_Makefile->GetHomeDirectory());
  162. argv.push_back(args);
  163. args = "-B";
  164. args +=
  165. this->ConvertToRelativeOutputPath(m_Makefile->GetHomeOutputDirectory());
  166. argv.push_back(args);
  167. std::string configFile =
  168. m_Makefile->GetRequiredDefinition("CMAKE_ROOT");
  169. configFile += "/Templates/CMakeWindowsSystemConfig.cmake";
  170. std::vector<std::string> listFiles = m_Makefile->GetListFiles();
  171. bool found = false;
  172. for(std::vector<std::string>::iterator i = listFiles.begin();
  173. i != listFiles.end(); ++i)
  174. {
  175. if(*i == configFile)
  176. {
  177. found = true;
  178. }
  179. }
  180. if(!found)
  181. {
  182. listFiles.push_back(configFile);
  183. }
  184. m_Makefile->AddCustomCommandToOutput(dspname.c_str(), dsprule.c_str(),
  185. argv, makefileIn.c_str(), listFiles,
  186. NULL, true);
  187. }
  188. void cmLocalVisualStudio6Generator::WriteDSPFile(std::ostream& fout,
  189. const char *libName,
  190. cmTarget &target)
  191. {
  192. // if we should add regen rule then...
  193. const char *suppRegenRule =
  194. m_Makefile->GetDefinition("CMAKE_SUPPRESS_REGENERATION");
  195. if (!cmSystemTools::IsOn(suppRegenRule))
  196. {
  197. this->AddDSPBuildRule();
  198. }
  199. // for utility targets need custom command since post build doesn't
  200. // do anything (Visual Studio 7 seems to do this correctly without
  201. // the hack)
  202. if (target.GetType() == cmTarget::UTILITY &&
  203. target.GetPostBuildCommands().size())
  204. {
  205. int count = 1;
  206. for (std::vector<cmCustomCommand>::const_iterator cr =
  207. target.GetPostBuildCommands().begin();
  208. cr != target.GetPostBuildCommands().end(); ++cr)
  209. {
  210. cmCustomCommand cc(*cr);
  211. cc.ExpandVariables(*m_Makefile);
  212. char *output = new char [
  213. strlen(m_Makefile->GetStartOutputDirectory()) +
  214. strlen(libName) + 30];
  215. sprintf(output,"%s/%s_force_%i",
  216. m_Makefile->GetStartOutputDirectory(),
  217. libName, count);
  218. std::vector<std::string> args;
  219. // This is a hack to fix a problem with cmCustomCommand
  220. // The cmCustomCommand should store the arguments as a vector
  221. // and not a string, and the cmAddCustomTargetCommand should
  222. // not EscapeSpaces.
  223. args.push_back("This is really a single argument do not escape spaces");
  224. args.push_back(cc.GetArguments());
  225. m_Makefile->AddCustomCommandToOutput(output,
  226. cc.GetCommand().c_str(),
  227. args,
  228. 0,
  229. cc.GetDepends());
  230. cmSourceFile* outsf =
  231. m_Makefile->GetSourceFileWithOutput(output);
  232. target.GetSourceFiles().push_back(outsf);
  233. count++;
  234. delete [] output;
  235. }
  236. }
  237. // trace the visual studio dependencies
  238. std::string name = libName;
  239. name += ".dsp.cmake";
  240. target.TraceVSDependencies(name, m_Makefile);
  241. // We may be modifying the source groups temporarily, so make a copy.
  242. std::vector<cmSourceGroup> sourceGroups = m_Makefile->GetSourceGroups();
  243. // get the classes from the source lists then add them to the groups
  244. std::vector<cmSourceFile*> & classes = target.GetSourceFiles();
  245. // now all of the source files have been properly assigned to the target
  246. // now stick them into source groups using the reg expressions
  247. for(std::vector<cmSourceFile*>::iterator i = classes.begin();
  248. i != classes.end(); i++)
  249. {
  250. // Add the file to the list of sources.
  251. std::string source = (*i)->GetFullPath();
  252. cmSourceGroup& sourceGroup = m_Makefile->FindSourceGroup(source.c_str(),
  253. sourceGroups);
  254. sourceGroup.AssignSource(*i);
  255. // while we are at it, if it is a .rule file then for visual studio 6 we
  256. // must generate it
  257. if ((*i)->GetSourceExtension() == "rule")
  258. {
  259. if(!cmSystemTools::FileExists(source.c_str()))
  260. {
  261. cmSystemTools::ReplaceString(source, "$(IntDir)/", "");
  262. #if defined(_WIN32) || defined(__CYGWIN__)
  263. std::ofstream fout(source.c_str(),
  264. std::ios::binary | std::ios::out | std::ios::trunc);
  265. #else
  266. std::ofstream fout(source.c_str(),
  267. std::ios::out | std::ios::trunc);
  268. #endif
  269. if(fout)
  270. {
  271. fout.write("# generated from CMake",22);
  272. fout.flush();
  273. fout.close();
  274. }
  275. }
  276. }
  277. }
  278. // Write the DSP file's header.
  279. this->WriteDSPHeader(fout, libName, target, sourceGroups);
  280. // Loop through every source group.
  281. for(std::vector<cmSourceGroup>::const_iterator sg = sourceGroups.begin();
  282. sg != sourceGroups.end(); ++sg)
  283. {
  284. const std::vector<const cmSourceFile *> &sourceFiles =
  285. sg->GetSourceFiles();
  286. // If the group is empty, don't write it at all.
  287. if(sourceFiles.empty())
  288. {
  289. continue;
  290. }
  291. // If the group has a name, write the header.
  292. std::string name = sg->GetName();
  293. if(name != "")
  294. {
  295. this->WriteDSPBeginGroup(fout, name.c_str(), "");
  296. }
  297. // Loop through each source in the source group.
  298. for(std::vector<const cmSourceFile *>::const_iterator sf =
  299. sourceFiles.begin(); sf != sourceFiles.end(); ++sf)
  300. {
  301. std::string source = (*sf)->GetFullPath();
  302. const cmCustomCommand *command =
  303. (*sf)->GetCustomCommand();
  304. std::string compileFlags;
  305. std::vector<std::string> depends;
  306. const char* cflags = (*sf)->GetProperty("COMPILE_FLAGS");
  307. if(cflags)
  308. {
  309. compileFlags = cflags;
  310. }
  311. const char* lang =
  312. m_GlobalGenerator->GetLanguageFromExtension((*sf)->GetSourceExtension().c_str());
  313. if(lang && strcmp(lang, "CXX") == 0)
  314. {
  315. // force a C++ file type
  316. compileFlags += " /TP ";
  317. }
  318. // Check for extra object-file dependencies.
  319. const char* dependsValue = (*sf)->GetProperty("OBJECT_DEPENDS");
  320. if(dependsValue)
  321. {
  322. cmSystemTools::ExpandListArgument(dependsValue, depends);
  323. }
  324. if (source != libName || target.GetType() == cmTarget::UTILITY)
  325. {
  326. fout << "# Begin Source File\n\n";
  327. // Tell MS-Dev what the source is. If the compiler knows how to
  328. // build it, then it will.
  329. fout << "SOURCE=" <<
  330. this->ConvertToRelativeOutputPath(source.c_str()) << "\n\n";
  331. if(!depends.empty())
  332. {
  333. // Write out the dependencies for the rule.
  334. fout << "USERDEP__HACK=";
  335. for(std::vector<std::string>::const_iterator d = depends.begin();
  336. d != depends.end(); ++d)
  337. {
  338. fout << "\\\n\t" <<
  339. this->ConvertToRelativeOutputPath(d->c_str());
  340. }
  341. fout << "\n";
  342. }
  343. if (command)
  344. {
  345. std::string totalCommandStr;
  346. totalCommandStr =
  347. this->ConvertToRelativeOutputPath(command->GetCommand().c_str());
  348. totalCommandStr += " ";
  349. totalCommandStr += command->GetArguments();
  350. totalCommandStr += "\n";
  351. const char* comment = command->GetComment().c_str();
  352. const char* flags = compileFlags.size() ? compileFlags.c_str(): 0;
  353. this->WriteCustomRule(fout, source.c_str(), totalCommandStr.c_str(),
  354. (*comment?comment:"Custom Rule"),
  355. command->GetDepends(),
  356. command->GetOutput().c_str(), flags);
  357. }
  358. else if(compileFlags.size())
  359. {
  360. for(std::vector<std::string>::iterator i
  361. = m_Configurations.begin(); i != m_Configurations.end(); ++i)
  362. {
  363. if (i == m_Configurations.begin())
  364. {
  365. fout << "!IF \"$(CFG)\" == " << i->c_str() << std::endl;
  366. }
  367. else
  368. {
  369. fout << "!ELSEIF \"$(CFG)\" == " << i->c_str() << std::endl;
  370. }
  371. fout << "\n# ADD CPP " << compileFlags << "\n\n";
  372. }
  373. fout << "!ENDIF\n\n";
  374. }
  375. fout << "# End Source File\n";
  376. }
  377. }
  378. // If the group has a name, write the footer.
  379. if(name != "")
  380. {
  381. this->WriteDSPEndGroup(fout);
  382. }
  383. }
  384. // Write the DSP file's footer.
  385. this->WriteDSPFooter(fout);
  386. }
  387. void cmLocalVisualStudio6Generator::WriteCustomRule(std::ostream& fout,
  388. const char* source,
  389. const char* command,
  390. const char* comment,
  391. const std::vector<std::string>& depends,
  392. const char *output,
  393. const char* flags
  394. )
  395. {
  396. std::vector<std::string>::iterator i;
  397. for(i = m_Configurations.begin(); i != m_Configurations.end(); ++i)
  398. {
  399. if (i == m_Configurations.begin())
  400. {
  401. fout << "!IF \"$(CFG)\" == " << i->c_str() << std::endl;
  402. }
  403. else
  404. {
  405. fout << "!ELSEIF \"$(CFG)\" == " << i->c_str() << std::endl;
  406. }
  407. if(flags)
  408. {
  409. fout << "\n# ADD CPP " << flags << "\n\n";
  410. }
  411. // Write out the dependencies for the rule.
  412. fout << "USERDEP__HACK=";
  413. for(std::vector<std::string>::const_iterator d = depends.begin();
  414. d != depends.end(); ++d)
  415. {
  416. std::string dep = cmSystemTools::GetFilenameName(*d);
  417. if (cmSystemTools::GetFilenameLastExtension(dep) == ".exe")
  418. {
  419. dep = cmSystemTools::GetFilenameWithoutLastExtension(dep);
  420. }
  421. std::string libPath = dep + "_CMAKE_PATH";
  422. const char* cacheValue = m_Makefile->GetDefinition(libPath.c_str());
  423. if (cacheValue && *cacheValue)
  424. {
  425. std::string exePath = "";
  426. if (m_Makefile->GetDefinition("EXECUTABLE_OUTPUT_PATH"))
  427. {
  428. exePath = m_Makefile->GetDefinition("EXECUTABLE_OUTPUT_PATH");
  429. }
  430. if(exePath.size())
  431. {
  432. libPath = exePath;
  433. }
  434. else
  435. {
  436. libPath = cacheValue;
  437. }
  438. libPath += "/";
  439. libPath += "$(INTDIR)/";
  440. libPath += dep;
  441. libPath += ".exe";
  442. fout << "\\\n\t" <<
  443. this->ConvertToRelativeOutputPath(libPath.c_str());
  444. }
  445. else
  446. {
  447. fout << "\\\n\t" <<
  448. this->ConvertToRelativeOutputPath(d->c_str());
  449. }
  450. }
  451. fout << "\n";
  452. fout << "# PROP Ignore_Default_Tool 1\n";
  453. fout << "# Begin Custom Build - Building " << comment
  454. << " $(InputPath)\n\n";
  455. if(output == 0)
  456. {
  457. fout << source << "_force : \"$(SOURCE)\" \"$(INTDIR)\" \"$(OUTDIR)\"\n\t";
  458. fout << command << "\n\n";
  459. }
  460. // Write a rule for every output generated by this command.
  461. fout << this->ConvertToRelativeOutputPath(output)
  462. << " : \"$(SOURCE)\" \"$(INTDIR)\" \"$(OUTDIR)\"\n\t";
  463. fout << command << "\n\n";
  464. fout << "# End Custom Build\n\n";
  465. }
  466. fout << "!ENDIF\n\n";
  467. }
  468. void cmLocalVisualStudio6Generator::WriteDSPBeginGroup(std::ostream& fout,
  469. const char* group,
  470. const char* filter)
  471. {
  472. fout << "# Begin Group \"" << group << "\"\n"
  473. "# PROP Default_Filter \"" << filter << "\"\n";
  474. }
  475. void cmLocalVisualStudio6Generator::WriteDSPEndGroup(std::ostream& fout)
  476. {
  477. fout << "# End Group\n";
  478. }
  479. void cmLocalVisualStudio6Generator::SetBuildType(BuildType b,
  480. const char* libName,
  481. const cmTarget& target)
  482. {
  483. std::string root= m_Makefile->GetRequiredDefinition("CMAKE_ROOT");
  484. const char *def= m_Makefile->GetDefinition( "MSPROJECT_TEMPLATE_DIRECTORY");
  485. std::string exportSymbol;
  486. if (const char* custom_export_name = target.GetProperty("DEFINE_SYMBOL"))
  487. {
  488. exportSymbol = custom_export_name;
  489. }
  490. else
  491. {
  492. std::string in = libName;
  493. in += "_EXPORTS";
  494. exportSymbol = cmSystemTools::MakeCindentifier(in.c_str());
  495. }
  496. if( def)
  497. {
  498. root = def;
  499. }
  500. else
  501. {
  502. root += "/Templates";
  503. }
  504. switch(b)
  505. {
  506. case STATIC_LIBRARY:
  507. m_DSPHeaderTemplate = root;
  508. m_DSPHeaderTemplate += "/staticLibHeader.dsptemplate";
  509. m_DSPFooterTemplate = root;
  510. m_DSPFooterTemplate += "/staticLibFooter.dsptemplate";
  511. break;
  512. case DLL:
  513. m_DSPHeaderTemplate = root;
  514. m_DSPHeaderTemplate += "/DLLHeader.dsptemplate";
  515. m_DSPFooterTemplate = root;
  516. m_DSPFooterTemplate += "/DLLFooter.dsptemplate";
  517. break;
  518. case EXECUTABLE:
  519. if ( target.GetPropertyAsBool("WIN32_EXECUTABLE") )
  520. {
  521. m_DSPHeaderTemplate = root;
  522. m_DSPHeaderTemplate += "/EXEWinHeader.dsptemplate";
  523. m_DSPFooterTemplate = root;
  524. m_DSPFooterTemplate += "/EXEFooter.dsptemplate";
  525. }
  526. else
  527. {
  528. m_DSPHeaderTemplate = root;
  529. m_DSPHeaderTemplate += "/EXEHeader.dsptemplate";
  530. m_DSPFooterTemplate = root;
  531. m_DSPFooterTemplate += "/EXEFooter.dsptemplate";
  532. }
  533. break;
  534. case UTILITY:
  535. m_DSPHeaderTemplate = root;
  536. m_DSPHeaderTemplate += "/UtilityHeader.dsptemplate";
  537. m_DSPFooterTemplate = root;
  538. m_DSPFooterTemplate += "/UtilityFooter.dsptemplate";
  539. break;
  540. }
  541. // once the build type is set, determine what configurations are
  542. // possible
  543. std::ifstream fin(m_DSPHeaderTemplate.c_str());
  544. cmsys::RegularExpression reg("# Name ");
  545. if(!fin)
  546. {
  547. cmSystemTools::Error("Error Reading ", m_DSPHeaderTemplate.c_str());
  548. }
  549. // reset m_Configurations
  550. m_Configurations.erase(m_Configurations.begin(), m_Configurations.end());
  551. // now add all the configurations possible
  552. std::string line;
  553. while(cmSystemTools::GetLineFromStream(fin, line))
  554. {
  555. cmSystemTools::ReplaceString(line, "OUTPUT_LIBNAME_EXPORTS",
  556. exportSymbol.c_str());
  557. cmSystemTools::ReplaceString(line, "OUTPUT_LIBNAME",libName);
  558. if (reg.find(line))
  559. {
  560. m_Configurations.push_back(line.substr(reg.end()));
  561. }
  562. }
  563. }
  564. // look for custom rules on a target and collect them together
  565. std::string
  566. cmLocalVisualStudio6Generator::CreateTargetRules(const cmTarget &target,
  567. const char * /* libName */)
  568. {
  569. std::string customRuleCode = "";
  570. if (target.GetType() >= cmTarget::UTILITY)
  571. {
  572. return customRuleCode;
  573. }
  574. // are there any rules?
  575. if (target.GetPreBuildCommands().size() +
  576. target.GetPreLinkCommands().size() +
  577. target.GetPostBuildCommands().size() == 0)
  578. {
  579. return customRuleCode;
  580. }
  581. customRuleCode = "# Begin Special Build Tool\n";
  582. // Do the PreBuild and PreLink (VS6 does not support both)
  583. bool init = false;
  584. for (std::vector<cmCustomCommand>::const_iterator cr =
  585. target.GetPreBuildCommands().begin();
  586. cr != target.GetPreBuildCommands().end(); ++cr)
  587. {
  588. cmCustomCommand cc(*cr);
  589. cc.ExpandVariables(*m_Makefile);
  590. if (!init)
  591. {
  592. // header stuff
  593. customRuleCode += "PreLink_Cmds=";
  594. init = true;
  595. }
  596. else
  597. {
  598. customRuleCode += "\\\n\t";
  599. }
  600. customRuleCode += this->ConvertToRelativeOutputPath(cc.GetCommand().c_str()) + " " + cc.GetArguments();
  601. }
  602. for (std::vector<cmCustomCommand>::const_iterator cr =
  603. target.GetPreLinkCommands().begin();
  604. cr != target.GetPreLinkCommands().end(); ++cr)
  605. {
  606. cmCustomCommand cc(*cr);
  607. cc.ExpandVariables(*m_Makefile);
  608. if (!init)
  609. {
  610. // header stuff
  611. customRuleCode += "PreLink_Cmds=";
  612. init = true;
  613. }
  614. else
  615. {
  616. customRuleCode += "\\\n\t";
  617. }
  618. customRuleCode += this->ConvertToRelativeOutputPath(cc.GetCommand().c_str()) + " " + cc.GetArguments();
  619. }
  620. // do the post build rules
  621. init = false;
  622. for (std::vector<cmCustomCommand>::const_iterator cr =
  623. target.GetPostBuildCommands().begin();
  624. cr != target.GetPostBuildCommands().end(); ++cr)
  625. {
  626. cmCustomCommand cc(*cr);
  627. cc.ExpandVariables(*m_Makefile);
  628. if (!init)
  629. {
  630. // header stuff
  631. customRuleCode += "PostBuild_Cmds=";
  632. init = true;
  633. }
  634. else
  635. {
  636. customRuleCode += "\\\n\t";
  637. }
  638. customRuleCode +=
  639. this->ConvertToRelativeOutputPath(cc.GetCommand().c_str()) +
  640. " " + cc.GetArguments();
  641. }
  642. customRuleCode += "\n# End Special Build Tool\n";
  643. return customRuleCode;
  644. }
  645. inline std::string removeQuotes(const std::string& s)
  646. {
  647. if(s[0] == '\"' && s[s.size()-1] == '\"')
  648. {
  649. return s.substr(1, s.size()-2);
  650. }
  651. return s;
  652. }
  653. void cmLocalVisualStudio6Generator::WriteDSPHeader(std::ostream& fout, const char *libName,
  654. const cmTarget &target,
  655. std::vector<cmSourceGroup> &)
  656. {
  657. std::set<std::string> pathEmitted;
  658. // determine the link directories
  659. std::string libOptions;
  660. std::string libDebugOptions;
  661. std::string libOptimizedOptions;
  662. std::string libMultiLineOptions;
  663. std::string libMultiLineOptionsForDebug;
  664. std::string libMultiLineDebugOptions;
  665. std::string libMultiLineOptimizedOptions;
  666. // suppoirt override in output directory
  667. std::string libPath = "";
  668. if (m_Makefile->GetDefinition("LIBRARY_OUTPUT_PATH"))
  669. {
  670. libPath = m_Makefile->GetDefinition("LIBRARY_OUTPUT_PATH");
  671. }
  672. std::string exePath = "";
  673. if (m_Makefile->GetDefinition("EXECUTABLE_OUTPUT_PATH"))
  674. {
  675. exePath = m_Makefile->GetDefinition("EXECUTABLE_OUTPUT_PATH");
  676. }
  677. if(libPath.size())
  678. {
  679. // make sure there is a trailing slash
  680. if(libPath[libPath.size()-1] != '/')
  681. {
  682. libPath += "/";
  683. }
  684. std::string lpath =
  685. this->ConvertToRelativeOutputPath(libPath.c_str());
  686. if(lpath.size() == 0)
  687. {
  688. lpath = ".";
  689. }
  690. std::string lpathIntDir = libPath + "$(INTDIR)";
  691. lpathIntDir = this->ConvertToRelativeOutputPath(lpathIntDir.c_str());
  692. if(pathEmitted.insert(lpath).second)
  693. {
  694. libOptions += " /LIBPATH:";
  695. libOptions += lpathIntDir;
  696. libOptions += " ";
  697. libOptions += " /LIBPATH:";
  698. libOptions += lpath;
  699. libOptions += " ";
  700. libMultiLineOptions += "# ADD LINK32 /LIBPATH:";
  701. libMultiLineOptions += lpathIntDir;
  702. libMultiLineOptions += " ";
  703. libMultiLineOptions += " /LIBPATH:";
  704. libMultiLineOptions += lpath;
  705. libMultiLineOptions += " \n";
  706. libMultiLineOptionsForDebug += "# ADD LINK32 /LIBPATH:";
  707. libMultiLineOptionsForDebug += lpathIntDir;
  708. libMultiLineOptionsForDebug += " ";
  709. libMultiLineOptionsForDebug += " /LIBPATH:";
  710. libMultiLineOptionsForDebug += lpath;
  711. libMultiLineOptionsForDebug += " \n";
  712. }
  713. }
  714. if(exePath.size())
  715. {
  716. // make sure there is a trailing slash
  717. if(exePath[exePath.size()-1] != '/')
  718. {
  719. exePath += "/";
  720. }
  721. std::string lpath =
  722. this->ConvertToRelativeOutputPath(exePath.c_str());
  723. if(lpath.size() == 0)
  724. {
  725. lpath = ".";
  726. }
  727. std::string lpathIntDir = exePath + "$(INTDIR)";
  728. lpathIntDir = this->ConvertToRelativeOutputPath(lpathIntDir.c_str());
  729. if(pathEmitted.insert(lpath).second)
  730. {
  731. libOptions += " /LIBPATH:";
  732. libOptions += lpathIntDir;
  733. libOptions += " ";
  734. libOptions += " /LIBPATH:";
  735. libOptions += lpath;
  736. libOptions += " ";
  737. libMultiLineOptions += "# ADD LINK32 /LIBPATH:";
  738. libMultiLineOptions += lpathIntDir;
  739. libMultiLineOptions += " ";
  740. libMultiLineOptions += " /LIBPATH:";
  741. libMultiLineOptions += lpath;
  742. libMultiLineOptions += " \n";
  743. libMultiLineOptionsForDebug += "# ADD LINK32 /LIBPATH:";
  744. libMultiLineOptionsForDebug += lpathIntDir;
  745. libMultiLineOptionsForDebug += " ";
  746. libMultiLineOptionsForDebug += " /LIBPATH:";
  747. libMultiLineOptionsForDebug += lpath;
  748. libMultiLineOptionsForDebug += " \n";
  749. }
  750. }
  751. std::vector<std::string>::const_iterator i;
  752. const std::vector<std::string>& libdirs = target.GetLinkDirectories();
  753. for(i = libdirs.begin(); i != libdirs.end(); ++i)
  754. {
  755. std::string path = *i;
  756. if(path[path.size()-1] != '/')
  757. {
  758. path += "/";
  759. }
  760. std::string lpath =
  761. this->ConvertToRelativeOutputPath(path.c_str());
  762. if(lpath.size() == 0)
  763. {
  764. lpath = ".";
  765. }
  766. std::string lpathIntDir = path + "$(INTDIR)";
  767. lpathIntDir = this->ConvertToRelativeOutputPath(lpathIntDir.c_str());
  768. if(pathEmitted.insert(lpath).second)
  769. {
  770. libOptions += " /LIBPATH:";
  771. libOptions += lpathIntDir;
  772. libOptions += " ";
  773. libOptions += " /LIBPATH:";
  774. libOptions += lpath;
  775. libOptions += " ";
  776. libMultiLineOptions += "# ADD LINK32 /LIBPATH:";
  777. libMultiLineOptions += lpathIntDir;
  778. libMultiLineOptions += " ";
  779. libMultiLineOptions += " /LIBPATH:";
  780. libMultiLineOptions += lpath;
  781. libMultiLineOptions += " \n";
  782. libMultiLineOptionsForDebug += "# ADD LINK32 /LIBPATH:";
  783. libMultiLineOptionsForDebug += lpathIntDir;
  784. libMultiLineOptionsForDebug += " ";
  785. libMultiLineOptionsForDebug += " /LIBPATH:";
  786. libMultiLineOptionsForDebug += lpath;
  787. libMultiLineOptionsForDebug += " \n";
  788. }
  789. }
  790. // find link libraries
  791. const cmTarget::LinkLibraries& libs = target.GetLinkLibraries();
  792. cmTarget::LinkLibraries::const_iterator j;
  793. for(j = libs.begin(); j != libs.end(); ++j)
  794. {
  795. // add libraries to executables and dlls (but never include
  796. // a library in a library, bad recursion)
  797. if ((target.GetType() != cmTarget::SHARED_LIBRARY
  798. && target.GetType() != cmTarget::STATIC_LIBRARY
  799. && target.GetType() != cmTarget::MODULE_LIBRARY) ||
  800. (target.GetType()==cmTarget::SHARED_LIBRARY && libName != j->first) ||
  801. (target.GetType()==cmTarget::MODULE_LIBRARY && libName != j->first))
  802. {
  803. std::string lib = j->first;
  804. std::string libDebug = j->first;
  805. std::string libPath = j->first + "_CMAKE_PATH";
  806. const char* cacheValue
  807. = m_GlobalGenerator->GetCMakeInstance()->GetCacheDefinition(
  808. libPath.c_str());
  809. if ( cacheValue && *cacheValue && m_Makefile->GetDefinition("CMAKE_DEBUG_POSTFIX") )
  810. {
  811. libDebug += m_Makefile->GetDefinition("CMAKE_DEBUG_POSTFIX");
  812. }
  813. if(j->first.find(".lib") == std::string::npos)
  814. {
  815. lib += ".lib";
  816. libDebug += ".lib";
  817. }
  818. lib = this->ConvertToRelativeOutputPath(lib.c_str());
  819. libDebug = this->ConvertToRelativeOutputPath(libDebug.c_str());
  820. if (j->second == cmTarget::GENERAL)
  821. {
  822. libOptions += " ";
  823. libOptions += lib;
  824. libMultiLineOptions += "# ADD LINK32 ";
  825. libMultiLineOptions += lib;
  826. libMultiLineOptions += "\n";
  827. libMultiLineOptionsForDebug += "# ADD LINK32 ";
  828. libMultiLineOptionsForDebug += libDebug;
  829. libMultiLineOptionsForDebug += "\n";
  830. }
  831. if (j->second == cmTarget::DEBUG)
  832. {
  833. libDebugOptions += " ";
  834. libDebugOptions += lib;
  835. libMultiLineDebugOptions += "# ADD LINK32 ";
  836. libMultiLineDebugOptions += libDebug;
  837. libMultiLineDebugOptions += "\n";
  838. }
  839. if (j->second == cmTarget::OPTIMIZED)
  840. {
  841. libOptimizedOptions += " ";
  842. libOptimizedOptions += lib;
  843. libMultiLineOptimizedOptions += "# ADD LINK32 ";
  844. libMultiLineOptimizedOptions += lib;
  845. libMultiLineOptimizedOptions += "\n";
  846. }
  847. }
  848. }
  849. std::string extraLinkOptions;
  850. if(target.GetType() == cmTarget::EXECUTABLE)
  851. {
  852. extraLinkOptions = m_Makefile->GetRequiredDefinition("CMAKE_EXE_LINKER_FLAGS");
  853. }
  854. if(target.GetType() == cmTarget::SHARED_LIBRARY)
  855. {
  856. extraLinkOptions = m_Makefile->GetRequiredDefinition("CMAKE_SHARED_LINKER_FLAGS");
  857. }
  858. if(target.GetType() == cmTarget::MODULE_LIBRARY)
  859. {
  860. extraLinkOptions = m_Makefile->GetRequiredDefinition("CMAKE_MODULE_LINKER_FLAGS");
  861. }
  862. if(extraLinkOptions.size())
  863. {
  864. libOptions += " ";
  865. libOptions += extraLinkOptions;
  866. libOptions += " ";
  867. libMultiLineOptions += "# ADD LINK32 ";
  868. libMultiLineOptions += extraLinkOptions;
  869. libMultiLineOptions += " \n";
  870. libMultiLineOptionsForDebug += "# ADD LINK32 ";
  871. libMultiLineOptionsForDebug += extraLinkOptions;
  872. libMultiLineOptionsForDebug += " \n";
  873. }
  874. if(const char* stdLibs = m_Makefile->GetDefinition("CMAKE_STANDARD_LIBRARIES"))
  875. {
  876. libOptions += " ";
  877. libOptions += stdLibs;
  878. libOptions += " ";
  879. libMultiLineOptions += "# ADD LINK32 ";
  880. libMultiLineOptions += stdLibs;
  881. libMultiLineOptions += " \n";
  882. libMultiLineOptionsForDebug += "# ADD LINK32 ";
  883. libMultiLineOptionsForDebug += stdLibs;
  884. libMultiLineOptionsForDebug += " \n";
  885. }
  886. if(const char* targetLinkFlags = target.GetProperty("LINK_FLAGS"))
  887. {
  888. libOptions += " ";
  889. libOptions += targetLinkFlags;
  890. libOptions += " ";
  891. libMultiLineOptions += "# ADD LINK32 ";
  892. libMultiLineOptions += targetLinkFlags;
  893. libMultiLineOptions += " \n";
  894. libMultiLineOptionsForDebug += "# ADD LINK32 ";
  895. libMultiLineOptionsForDebug += targetLinkFlags;
  896. libMultiLineOptionsForDebug += " \n";
  897. }
  898. // are there any custom rules on the target itself
  899. // only if the target is a lib or exe
  900. std::string customRuleCode = this->CreateTargetRules(target, libName);
  901. std::ifstream fin(m_DSPHeaderTemplate.c_str());
  902. if(!fin)
  903. {
  904. cmSystemTools::Error("Error Reading ", m_DSPHeaderTemplate.c_str());
  905. }
  906. std::string staticLibOptions;
  907. if(target.GetType() == cmTarget::STATIC_LIBRARY )
  908. {
  909. if(const char* libflags = target.GetProperty("STATIC_LIBRARY_FLAGS"))
  910. {
  911. staticLibOptions = libflags;
  912. }
  913. }
  914. std::string line;
  915. while(cmSystemTools::GetLineFromStream(fin, line))
  916. {
  917. const char* mfcFlag = m_Makefile->GetDefinition("CMAKE_MFC_FLAG");
  918. if(!mfcFlag)
  919. {
  920. mfcFlag = "0";
  921. }
  922. cmSystemTools::ReplaceString(line, "CMAKE_CUSTOM_RULE_CODE",
  923. customRuleCode.c_str());
  924. cmSystemTools::ReplaceString(line, "CMAKE_MFC_FLAG",
  925. mfcFlag);
  926. if(target.GetType() == cmTarget::STATIC_LIBRARY )
  927. {
  928. cmSystemTools::ReplaceString(line, "CM_STATIC_LIB_ARGS",
  929. staticLibOptions.c_str());
  930. }
  931. if(m_Makefile->IsOn("CMAKE_VERBOSE_MAKEFILE"))
  932. {
  933. cmSystemTools::ReplaceString(line, "/nologo", "");
  934. }
  935. cmSystemTools::ReplaceString(line, "CM_LIBRARIES",
  936. libOptions.c_str());
  937. cmSystemTools::ReplaceString(line, "CM_DEBUG_LIBRARIES",
  938. libDebugOptions.c_str());
  939. cmSystemTools::ReplaceString(line, "CM_OPTIMIZED_LIBRARIES",
  940. libOptimizedOptions.c_str());
  941. cmSystemTools::ReplaceString(line, "CM_MULTILINE_LIBRARIES_FOR_DEBUG",
  942. libMultiLineOptionsForDebug.c_str());
  943. cmSystemTools::ReplaceString(line, "CM_MULTILINE_LIBRARIES",
  944. libMultiLineOptions.c_str());
  945. cmSystemTools::ReplaceString(line, "CM_MULTILINE_DEBUG_LIBRARIES",
  946. libMultiLineDebugOptions.c_str());
  947. cmSystemTools::ReplaceString(line, "CM_MULTILINE_OPTIMIZED_LIBRARIES",
  948. libMultiLineOptimizedOptions.c_str());
  949. cmSystemTools::ReplaceString(line, "BUILD_INCLUDES",
  950. m_IncludeOptions.c_str());
  951. cmSystemTools::ReplaceString(line, "OUTPUT_LIBNAME",libName);
  952. // because LIBRARY_OUTPUT_PATH and EXECUTABLE_OUTPUT_PATH
  953. // are already quoted in the template file,
  954. // we need to remove the quotes here, we still need
  955. // to convert to output path for unix to win32 conversion
  956. cmSystemTools::ReplaceString(line, "LIBRARY_OUTPUT_PATH",
  957. removeQuotes(
  958. this->ConvertToRelativeOutputPath(libPath.c_str())).c_str());
  959. cmSystemTools::ReplaceString(line, "EXECUTABLE_OUTPUT_PATH",
  960. removeQuotes(
  961. this->ConvertToRelativeOutputPath(exePath.c_str())).c_str());
  962. cmSystemTools::ReplaceString(line,
  963. "EXTRA_DEFINES",
  964. m_Makefile->GetDefineFlags());
  965. const char* debugPostfix
  966. = m_Makefile->GetDefinition("CMAKE_DEBUG_POSTFIX");
  967. cmSystemTools::ReplaceString(line, "DEBUG_POSTFIX",
  968. debugPostfix?debugPostfix:"");
  969. // store flags for each configuration
  970. std::string flags = " ";
  971. std::string flagsRelease = " ";
  972. std::string flagsMinSize = " ";
  973. std::string flagsDebug = " ";
  974. std::string flagsDebugRel = " ";
  975. if(target.GetType() >= cmTarget::EXECUTABLE &&
  976. target.GetType() <= cmTarget::MODULE_LIBRARY)
  977. {
  978. const char* linkLanguage = target.GetLinkerLanguage(this->GetGlobalGenerator());
  979. // if CXX is on and the target contains cxx code then add the cxx flags
  980. std::string baseFlagVar = "CMAKE_";
  981. baseFlagVar += linkLanguage;
  982. baseFlagVar += "_FLAGS";
  983. flags = m_Makefile->GetRequiredDefinition(baseFlagVar.c_str());
  984. std::string flagVar = baseFlagVar + "_RELEASE";
  985. flagsRelease = m_Makefile->GetRequiredDefinition(flagVar.c_str());
  986. flagsRelease += " -DCMAKE_INTDIR=\\\"Release\\\" ";
  987. flagVar = baseFlagVar + "_MINSIZEREL";
  988. flagsMinSize = m_Makefile->GetRequiredDefinition(flagVar.c_str());
  989. flagsMinSize += " -DCMAKE_INTDIR=\\\"MinSizeRel\\\" ";
  990. flagVar = baseFlagVar + "_DEBUG";
  991. flagsDebug = m_Makefile->GetRequiredDefinition(flagVar.c_str());
  992. flagsDebug += " -DCMAKE_INTDIR=\\\"Debug\\\" ";
  993. flagVar = baseFlagVar + "_RELWITHDEBINFO";
  994. flagsDebugRel = m_Makefile->GetRequiredDefinition(flagVar.c_str());
  995. flagsDebugRel += " -DCMAKE_INTDIR=\\\"RelWithDebInfo\\\" ";
  996. }
  997. // if unicode is not found, then add -D_MBCS
  998. std::string defs = m_Makefile->GetDefineFlags();
  999. if(flags.find("D_UNICODE") == flags.npos &&
  1000. defs.find("D_UNICODE") == flags.npos)
  1001. {
  1002. flags += " /D \"_MBCS\"";
  1003. }
  1004. // The template files have CXX FLAGS in them, that need to be replaced.
  1005. // There are not separate CXX and C template files, so we use the same
  1006. // variable names. The previous code sets up flags* variables to contain
  1007. // the correct C or CXX flags
  1008. cmSystemTools::ReplaceString(line, "CMAKE_CXX_FLAGS_MINSIZEREL", flagsMinSize.c_str());
  1009. cmSystemTools::ReplaceString(line, "CMAKE_CXX_FLAGS_DEBUG", flagsDebug.c_str());
  1010. cmSystemTools::ReplaceString(line,"CMAKE_CXX_FLAGS_RELWITHDEBINFO", flagsDebugRel.c_str());
  1011. cmSystemTools::ReplaceString(line, "CMAKE_CXX_FLAGS", flags.c_str());
  1012. fout << line.c_str() << std::endl;
  1013. }
  1014. }
  1015. void cmLocalVisualStudio6Generator::WriteDSPFooter(std::ostream& fout)
  1016. {
  1017. std::ifstream fin(m_DSPFooterTemplate.c_str());
  1018. if(!fin)
  1019. {
  1020. cmSystemTools::Error("Error Reading ",
  1021. m_DSPFooterTemplate.c_str());
  1022. }
  1023. std::string line;
  1024. while(cmSystemTools::GetLineFromStream(fin, line))
  1025. {
  1026. fout << line << std::endl;
  1027. }
  1028. }