cmLocalVisualStudio6Generator.cxx 37 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. if(cmSystemTools::GetFileFormat((*sf)->GetSourceExtension().c_str())
  312. == cmSystemTools::CXX_FILE_FORMAT)
  313. {
  314. // force a C++ file type
  315. compileFlags += " /TP ";
  316. }
  317. // Check for extra object-file dependencies.
  318. const char* dependsValue = (*sf)->GetProperty("OBJECT_DEPENDS");
  319. if(dependsValue)
  320. {
  321. cmSystemTools::ExpandListArgument(dependsValue, depends);
  322. }
  323. if (source != libName || target.GetType() == cmTarget::UTILITY)
  324. {
  325. fout << "# Begin Source File\n\n";
  326. // Tell MS-Dev what the source is. If the compiler knows how to
  327. // build it, then it will.
  328. fout << "SOURCE=" <<
  329. this->ConvertToRelativeOutputPath(source.c_str()) << "\n\n";
  330. if(!depends.empty())
  331. {
  332. // Write out the dependencies for the rule.
  333. fout << "USERDEP__HACK=";
  334. for(std::vector<std::string>::const_iterator d = depends.begin();
  335. d != depends.end(); ++d)
  336. {
  337. fout << "\\\n\t" <<
  338. this->ConvertToRelativeOutputPath(d->c_str());
  339. }
  340. fout << "\n";
  341. }
  342. if (command)
  343. {
  344. std::string totalCommandStr;
  345. totalCommandStr =
  346. this->ConvertToRelativeOutputPath(command->GetCommand().c_str());
  347. totalCommandStr += " ";
  348. totalCommandStr += command->GetArguments();
  349. totalCommandStr += "\n";
  350. const char* comment = command->GetComment().c_str();
  351. const char* flags = compileFlags.size() ? compileFlags.c_str(): 0;
  352. this->WriteCustomRule(fout, source.c_str(), totalCommandStr.c_str(),
  353. (*comment?comment:"Custom Rule"),
  354. command->GetDepends(),
  355. command->GetOutput().c_str(), flags);
  356. }
  357. else if(compileFlags.size())
  358. {
  359. for(std::vector<std::string>::iterator i
  360. = m_Configurations.begin(); i != m_Configurations.end(); ++i)
  361. {
  362. if (i == m_Configurations.begin())
  363. {
  364. fout << "!IF \"$(CFG)\" == " << i->c_str() << std::endl;
  365. }
  366. else
  367. {
  368. fout << "!ELSEIF \"$(CFG)\" == " << i->c_str() << std::endl;
  369. }
  370. fout << "\n# ADD CPP " << compileFlags << "\n\n";
  371. }
  372. fout << "!ENDIF\n\n";
  373. }
  374. fout << "# End Source File\n";
  375. }
  376. }
  377. // If the group has a name, write the footer.
  378. if(name != "")
  379. {
  380. this->WriteDSPEndGroup(fout);
  381. }
  382. }
  383. // Write the DSP file's footer.
  384. this->WriteDSPFooter(fout);
  385. }
  386. void cmLocalVisualStudio6Generator::WriteCustomRule(std::ostream& fout,
  387. const char* source,
  388. const char* command,
  389. const char* comment,
  390. const std::vector<std::string>& depends,
  391. const char *output,
  392. const char* flags
  393. )
  394. {
  395. std::vector<std::string>::iterator i;
  396. for(i = m_Configurations.begin(); i != m_Configurations.end(); ++i)
  397. {
  398. if (i == m_Configurations.begin())
  399. {
  400. fout << "!IF \"$(CFG)\" == " << i->c_str() << std::endl;
  401. }
  402. else
  403. {
  404. fout << "!ELSEIF \"$(CFG)\" == " << i->c_str() << std::endl;
  405. }
  406. if(flags)
  407. {
  408. fout << "\n# ADD CPP " << flags << "\n\n";
  409. }
  410. // Write out the dependencies for the rule.
  411. fout << "USERDEP__HACK=";
  412. for(std::vector<std::string>::const_iterator d = depends.begin();
  413. d != depends.end(); ++d)
  414. {
  415. std::string dep = cmSystemTools::GetFilenameName(*d);
  416. if (cmSystemTools::GetFilenameLastExtension(dep) == ".exe")
  417. {
  418. dep = cmSystemTools::GetFilenameWithoutLastExtension(dep);
  419. }
  420. std::string libPath = dep + "_CMAKE_PATH";
  421. const char* cacheValue = m_Makefile->GetDefinition(libPath.c_str());
  422. if (cacheValue && *cacheValue)
  423. {
  424. std::string exePath = "";
  425. if (m_Makefile->GetDefinition("EXECUTABLE_OUTPUT_PATH"))
  426. {
  427. exePath = m_Makefile->GetDefinition("EXECUTABLE_OUTPUT_PATH");
  428. }
  429. if(exePath.size())
  430. {
  431. libPath = exePath;
  432. }
  433. else
  434. {
  435. libPath = cacheValue;
  436. }
  437. libPath += "/";
  438. libPath += "$(INTDIR)/";
  439. libPath += dep;
  440. libPath += ".exe";
  441. fout << "\\\n\t" <<
  442. this->ConvertToRelativeOutputPath(libPath.c_str());
  443. }
  444. else
  445. {
  446. fout << "\\\n\t" <<
  447. this->ConvertToRelativeOutputPath(d->c_str());
  448. }
  449. }
  450. fout << "\n";
  451. fout << "# PROP Ignore_Default_Tool 1\n";
  452. fout << "# Begin Custom Build - Building " << comment
  453. << " $(InputPath)\n\n";
  454. if(output == 0)
  455. {
  456. fout << source << "_force : \"$(SOURCE)\" \"$(INTDIR)\" \"$(OUTDIR)\"\n\t";
  457. fout << command << "\n\n";
  458. }
  459. // Write a rule for every output generated by this command.
  460. fout << this->ConvertToRelativeOutputPath(output)
  461. << " : \"$(SOURCE)\" \"$(INTDIR)\" \"$(OUTDIR)\"\n\t";
  462. fout << command << "\n\n";
  463. fout << "# End Custom Build\n\n";
  464. }
  465. fout << "!ENDIF\n\n";
  466. }
  467. void cmLocalVisualStudio6Generator::WriteDSPBeginGroup(std::ostream& fout,
  468. const char* group,
  469. const char* filter)
  470. {
  471. fout << "# Begin Group \"" << group << "\"\n"
  472. "# PROP Default_Filter \"" << filter << "\"\n";
  473. }
  474. void cmLocalVisualStudio6Generator::WriteDSPEndGroup(std::ostream& fout)
  475. {
  476. fout << "# End Group\n";
  477. }
  478. void cmLocalVisualStudio6Generator::SetBuildType(BuildType b,
  479. const char* libName,
  480. const cmTarget& target)
  481. {
  482. std::string root= m_Makefile->GetRequiredDefinition("CMAKE_ROOT");
  483. const char *def= m_Makefile->GetDefinition( "MSPROJECT_TEMPLATE_DIRECTORY");
  484. std::string exportSymbol;
  485. if (const char* custom_export_name = target.GetProperty("DEFINE_SYMBOL"))
  486. {
  487. exportSymbol = custom_export_name;
  488. }
  489. else
  490. {
  491. std::string in = libName;
  492. in += "_EXPORTS";
  493. exportSymbol = cmSystemTools::MakeCindentifier(in.c_str());
  494. }
  495. if( def)
  496. {
  497. root = def;
  498. }
  499. else
  500. {
  501. root += "/Templates";
  502. }
  503. switch(b)
  504. {
  505. case STATIC_LIBRARY:
  506. m_DSPHeaderTemplate = root;
  507. m_DSPHeaderTemplate += "/staticLibHeader.dsptemplate";
  508. m_DSPFooterTemplate = root;
  509. m_DSPFooterTemplate += "/staticLibFooter.dsptemplate";
  510. break;
  511. case DLL:
  512. m_DSPHeaderTemplate = root;
  513. m_DSPHeaderTemplate += "/DLLHeader.dsptemplate";
  514. m_DSPFooterTemplate = root;
  515. m_DSPFooterTemplate += "/DLLFooter.dsptemplate";
  516. break;
  517. case EXECUTABLE:
  518. if ( target.GetPropertyAsBool("WIN32_EXECUTABLE") )
  519. {
  520. m_DSPHeaderTemplate = root;
  521. m_DSPHeaderTemplate += "/EXEWinHeader.dsptemplate";
  522. m_DSPFooterTemplate = root;
  523. m_DSPFooterTemplate += "/EXEFooter.dsptemplate";
  524. }
  525. else
  526. {
  527. m_DSPHeaderTemplate = root;
  528. m_DSPHeaderTemplate += "/EXEHeader.dsptemplate";
  529. m_DSPFooterTemplate = root;
  530. m_DSPFooterTemplate += "/EXEFooter.dsptemplate";
  531. }
  532. break;
  533. case UTILITY:
  534. m_DSPHeaderTemplate = root;
  535. m_DSPHeaderTemplate += "/UtilityHeader.dsptemplate";
  536. m_DSPFooterTemplate = root;
  537. m_DSPFooterTemplate += "/UtilityFooter.dsptemplate";
  538. break;
  539. }
  540. // once the build type is set, determine what configurations are
  541. // possible
  542. std::ifstream fin(m_DSPHeaderTemplate.c_str());
  543. cmsys::RegularExpression reg("# Name ");
  544. if(!fin)
  545. {
  546. cmSystemTools::Error("Error Reading ", m_DSPHeaderTemplate.c_str());
  547. }
  548. // reset m_Configurations
  549. m_Configurations.erase(m_Configurations.begin(), m_Configurations.end());
  550. // now add all the configurations possible
  551. std::string line;
  552. while(cmSystemTools::GetLineFromStream(fin, line))
  553. {
  554. cmSystemTools::ReplaceString(line, "OUTPUT_LIBNAME_EXPORTS",
  555. exportSymbol.c_str());
  556. cmSystemTools::ReplaceString(line, "OUTPUT_LIBNAME",libName);
  557. if (reg.find(line))
  558. {
  559. m_Configurations.push_back(line.substr(reg.end()));
  560. }
  561. }
  562. }
  563. // look for custom rules on a target and collect them together
  564. std::string
  565. cmLocalVisualStudio6Generator::CreateTargetRules(const cmTarget &target,
  566. const char * /* libName */)
  567. {
  568. std::string customRuleCode = "";
  569. if (target.GetType() >= cmTarget::UTILITY)
  570. {
  571. return customRuleCode;
  572. }
  573. // are there any rules?
  574. if (target.GetPreBuildCommands().size() +
  575. target.GetPreLinkCommands().size() +
  576. target.GetPostBuildCommands().size() == 0)
  577. {
  578. return customRuleCode;
  579. }
  580. customRuleCode = "# Begin Special Build Tool\n";
  581. // Do the PreBuild and PreLink (VS6 does not support both)
  582. bool init = false;
  583. for (std::vector<cmCustomCommand>::const_iterator cr =
  584. target.GetPreBuildCommands().begin();
  585. cr != target.GetPreBuildCommands().end(); ++cr)
  586. {
  587. cmCustomCommand cc(*cr);
  588. cc.ExpandVariables(*m_Makefile);
  589. if (!init)
  590. {
  591. // header stuff
  592. customRuleCode += "PreLink_Cmds=";
  593. init = true;
  594. }
  595. else
  596. {
  597. customRuleCode += "\\\n\t";
  598. }
  599. customRuleCode += this->ConvertToRelativeOutputPath(cc.GetCommand().c_str()) + " " + cc.GetArguments();
  600. }
  601. for (std::vector<cmCustomCommand>::const_iterator cr =
  602. target.GetPreLinkCommands().begin();
  603. cr != target.GetPreLinkCommands().end(); ++cr)
  604. {
  605. cmCustomCommand cc(*cr);
  606. cc.ExpandVariables(*m_Makefile);
  607. if (!init)
  608. {
  609. // header stuff
  610. customRuleCode += "PreLink_Cmds=";
  611. init = true;
  612. }
  613. else
  614. {
  615. customRuleCode += "\\\n\t";
  616. }
  617. customRuleCode += this->ConvertToRelativeOutputPath(cc.GetCommand().c_str()) + " " + cc.GetArguments();
  618. }
  619. // do the post build rules
  620. init = false;
  621. for (std::vector<cmCustomCommand>::const_iterator cr =
  622. target.GetPostBuildCommands().begin();
  623. cr != target.GetPostBuildCommands().end(); ++cr)
  624. {
  625. cmCustomCommand cc(*cr);
  626. cc.ExpandVariables(*m_Makefile);
  627. if (!init)
  628. {
  629. // header stuff
  630. customRuleCode += "PostBuild_Cmds=";
  631. init = true;
  632. }
  633. else
  634. {
  635. customRuleCode += "\\\n\t";
  636. }
  637. customRuleCode +=
  638. this->ConvertToRelativeOutputPath(cc.GetCommand().c_str()) +
  639. " " + cc.GetArguments();
  640. }
  641. customRuleCode += "\n# End Special Build Tool\n";
  642. return customRuleCode;
  643. }
  644. inline std::string removeQuotes(const std::string& s)
  645. {
  646. if(s[0] == '\"' && s[s.size()-1] == '\"')
  647. {
  648. return s.substr(1, s.size()-2);
  649. }
  650. return s;
  651. }
  652. void cmLocalVisualStudio6Generator::WriteDSPHeader(std::ostream& fout, const char *libName,
  653. const cmTarget &target,
  654. std::vector<cmSourceGroup> &)
  655. {
  656. std::set<std::string> pathEmitted;
  657. // determine the link directories
  658. std::string libOptions;
  659. std::string libDebugOptions;
  660. std::string libOptimizedOptions;
  661. std::string libMultiLineOptions;
  662. std::string libMultiLineOptionsForDebug;
  663. std::string libMultiLineDebugOptions;
  664. std::string libMultiLineOptimizedOptions;
  665. // suppoirt override in output directory
  666. std::string libPath = "";
  667. if (m_Makefile->GetDefinition("LIBRARY_OUTPUT_PATH"))
  668. {
  669. libPath = m_Makefile->GetDefinition("LIBRARY_OUTPUT_PATH");
  670. }
  671. std::string exePath = "";
  672. if (m_Makefile->GetDefinition("EXECUTABLE_OUTPUT_PATH"))
  673. {
  674. exePath = m_Makefile->GetDefinition("EXECUTABLE_OUTPUT_PATH");
  675. }
  676. if(libPath.size())
  677. {
  678. // make sure there is a trailing slash
  679. if(libPath[libPath.size()-1] != '/')
  680. {
  681. libPath += "/";
  682. }
  683. std::string lpath =
  684. this->ConvertToRelativeOutputPath(libPath.c_str());
  685. if(lpath.size() == 0)
  686. {
  687. lpath = ".";
  688. }
  689. std::string lpathIntDir = libPath + "$(INTDIR)";
  690. lpathIntDir = this->ConvertToRelativeOutputPath(lpathIntDir.c_str());
  691. if(pathEmitted.insert(lpath).second)
  692. {
  693. libOptions += " /LIBPATH:";
  694. libOptions += lpathIntDir;
  695. libOptions += " ";
  696. libOptions += " /LIBPATH:";
  697. libOptions += lpath;
  698. libOptions += " ";
  699. libMultiLineOptions += "# ADD LINK32 /LIBPATH:";
  700. libMultiLineOptions += lpathIntDir;
  701. libMultiLineOptions += " ";
  702. libMultiLineOptions += " /LIBPATH:";
  703. libMultiLineOptions += lpath;
  704. libMultiLineOptions += " \n";
  705. libMultiLineOptionsForDebug += "# ADD LINK32 /LIBPATH:";
  706. libMultiLineOptionsForDebug += lpathIntDir;
  707. libMultiLineOptionsForDebug += " ";
  708. libMultiLineOptionsForDebug += " /LIBPATH:";
  709. libMultiLineOptionsForDebug += lpath;
  710. libMultiLineOptionsForDebug += " \n";
  711. }
  712. }
  713. if(exePath.size())
  714. {
  715. // make sure there is a trailing slash
  716. if(exePath[exePath.size()-1] != '/')
  717. {
  718. exePath += "/";
  719. }
  720. std::string lpath =
  721. this->ConvertToRelativeOutputPath(exePath.c_str());
  722. if(lpath.size() == 0)
  723. {
  724. lpath = ".";
  725. }
  726. std::string lpathIntDir = exePath + "$(INTDIR)";
  727. lpathIntDir = this->ConvertToRelativeOutputPath(lpathIntDir.c_str());
  728. if(pathEmitted.insert(lpath).second)
  729. {
  730. libOptions += " /LIBPATH:";
  731. libOptions += lpathIntDir;
  732. libOptions += " ";
  733. libOptions += " /LIBPATH:";
  734. libOptions += lpath;
  735. libOptions += " ";
  736. libMultiLineOptions += "# ADD LINK32 /LIBPATH:";
  737. libMultiLineOptions += lpathIntDir;
  738. libMultiLineOptions += " ";
  739. libMultiLineOptions += " /LIBPATH:";
  740. libMultiLineOptions += lpath;
  741. libMultiLineOptions += " \n";
  742. libMultiLineOptionsForDebug += "# ADD LINK32 /LIBPATH:";
  743. libMultiLineOptionsForDebug += lpathIntDir;
  744. libMultiLineOptionsForDebug += " ";
  745. libMultiLineOptionsForDebug += " /LIBPATH:";
  746. libMultiLineOptionsForDebug += lpath;
  747. libMultiLineOptionsForDebug += " \n";
  748. }
  749. }
  750. std::vector<std::string>::const_iterator i;
  751. const std::vector<std::string>& libdirs = target.GetLinkDirectories();
  752. for(i = libdirs.begin(); i != libdirs.end(); ++i)
  753. {
  754. std::string path = *i;
  755. if(path[path.size()-1] != '/')
  756. {
  757. path += "/";
  758. }
  759. std::string lpath =
  760. this->ConvertToRelativeOutputPath(path.c_str());
  761. if(lpath.size() == 0)
  762. {
  763. lpath = ".";
  764. }
  765. std::string lpathIntDir = path + "$(INTDIR)";
  766. lpathIntDir = this->ConvertToRelativeOutputPath(lpathIntDir.c_str());
  767. if(pathEmitted.insert(lpath).second)
  768. {
  769. libOptions += " /LIBPATH:";
  770. libOptions += lpathIntDir;
  771. libOptions += " ";
  772. libOptions += " /LIBPATH:";
  773. libOptions += lpath;
  774. libOptions += " ";
  775. libMultiLineOptions += "# ADD LINK32 /LIBPATH:";
  776. libMultiLineOptions += lpathIntDir;
  777. libMultiLineOptions += " ";
  778. libMultiLineOptions += " /LIBPATH:";
  779. libMultiLineOptions += lpath;
  780. libMultiLineOptions += " \n";
  781. libMultiLineOptionsForDebug += "# ADD LINK32 /LIBPATH:";
  782. libMultiLineOptionsForDebug += lpathIntDir;
  783. libMultiLineOptionsForDebug += " ";
  784. libMultiLineOptionsForDebug += " /LIBPATH:";
  785. libMultiLineOptionsForDebug += lpath;
  786. libMultiLineOptionsForDebug += " \n";
  787. }
  788. }
  789. // find link libraries
  790. const cmTarget::LinkLibraries& libs = target.GetLinkLibraries();
  791. cmTarget::LinkLibraries::const_iterator j;
  792. for(j = libs.begin(); j != libs.end(); ++j)
  793. {
  794. // add libraries to executables and dlls (but never include
  795. // a library in a library, bad recursion)
  796. if ((target.GetType() != cmTarget::SHARED_LIBRARY
  797. && target.GetType() != cmTarget::STATIC_LIBRARY
  798. && target.GetType() != cmTarget::MODULE_LIBRARY) ||
  799. (target.GetType()==cmTarget::SHARED_LIBRARY && libName != j->first) ||
  800. (target.GetType()==cmTarget::MODULE_LIBRARY && libName != j->first))
  801. {
  802. std::string lib = j->first;
  803. std::string libDebug = j->first;
  804. std::string libPath = j->first + "_CMAKE_PATH";
  805. const char* cacheValue
  806. = m_GlobalGenerator->GetCMakeInstance()->GetCacheDefinition(
  807. libPath.c_str());
  808. if ( cacheValue && *cacheValue && m_Makefile->GetDefinition("CMAKE_DEBUG_POSTFIX") )
  809. {
  810. libDebug += m_Makefile->GetDefinition("CMAKE_DEBUG_POSTFIX");
  811. }
  812. if(j->first.find(".lib") == std::string::npos)
  813. {
  814. lib += ".lib";
  815. libDebug += ".lib";
  816. }
  817. lib = this->ConvertToRelativeOutputPath(lib.c_str());
  818. libDebug = this->ConvertToRelativeOutputPath(libDebug.c_str());
  819. if (j->second == cmTarget::GENERAL)
  820. {
  821. libOptions += " ";
  822. libOptions += lib;
  823. libMultiLineOptions += "# ADD LINK32 ";
  824. libMultiLineOptions += lib;
  825. libMultiLineOptions += "\n";
  826. libMultiLineOptionsForDebug += "# ADD LINK32 ";
  827. libMultiLineOptionsForDebug += libDebug;
  828. libMultiLineOptionsForDebug += "\n";
  829. }
  830. if (j->second == cmTarget::DEBUG)
  831. {
  832. libDebugOptions += " ";
  833. libDebugOptions += lib;
  834. libMultiLineDebugOptions += "# ADD LINK32 ";
  835. libMultiLineDebugOptions += libDebug;
  836. libMultiLineDebugOptions += "\n";
  837. }
  838. if (j->second == cmTarget::OPTIMIZED)
  839. {
  840. libOptimizedOptions += " ";
  841. libOptimizedOptions += lib;
  842. libMultiLineOptimizedOptions += "# ADD LINK32 ";
  843. libMultiLineOptimizedOptions += lib;
  844. libMultiLineOptimizedOptions += "\n";
  845. }
  846. }
  847. }
  848. std::string extraLinkOptions;
  849. if(target.GetType() == cmTarget::EXECUTABLE)
  850. {
  851. extraLinkOptions = m_Makefile->GetRequiredDefinition("CMAKE_EXE_LINKER_FLAGS");
  852. }
  853. if(target.GetType() == cmTarget::SHARED_LIBRARY)
  854. {
  855. extraLinkOptions = m_Makefile->GetRequiredDefinition("CMAKE_SHARED_LINKER_FLAGS");
  856. }
  857. if(target.GetType() == cmTarget::MODULE_LIBRARY)
  858. {
  859. extraLinkOptions = m_Makefile->GetRequiredDefinition("CMAKE_MODULE_LINKER_FLAGS");
  860. }
  861. if(extraLinkOptions.size())
  862. {
  863. libOptions += " ";
  864. libOptions += extraLinkOptions;
  865. libOptions += " ";
  866. libMultiLineOptions += "# ADD LINK32 ";
  867. libMultiLineOptions += extraLinkOptions;
  868. libMultiLineOptions += " \n";
  869. libMultiLineOptionsForDebug += "# ADD LINK32 ";
  870. libMultiLineOptionsForDebug += extraLinkOptions;
  871. libMultiLineOptionsForDebug += " \n";
  872. }
  873. if(const char* stdLibs = m_Makefile->GetDefinition("CMAKE_STANDARD_LIBRARIES"))
  874. {
  875. libOptions += " ";
  876. libOptions += stdLibs;
  877. libOptions += " ";
  878. libMultiLineOptions += "# ADD LINK32 ";
  879. libMultiLineOptions += stdLibs;
  880. libMultiLineOptions += " \n";
  881. libMultiLineOptionsForDebug += "# ADD LINK32 ";
  882. libMultiLineOptionsForDebug += stdLibs;
  883. libMultiLineOptionsForDebug += " \n";
  884. }
  885. if(const char* targetLinkFlags = target.GetProperty("LINK_FLAGS"))
  886. {
  887. libOptions += " ";
  888. libOptions += targetLinkFlags;
  889. libOptions += " ";
  890. libMultiLineOptions += "# ADD LINK32 ";
  891. libMultiLineOptions += targetLinkFlags;
  892. libMultiLineOptions += " \n";
  893. libMultiLineOptionsForDebug += "# ADD LINK32 ";
  894. libMultiLineOptionsForDebug += targetLinkFlags;
  895. libMultiLineOptionsForDebug += " \n";
  896. }
  897. // are there any custom rules on the target itself
  898. // only if the target is a lib or exe
  899. std::string customRuleCode = this->CreateTargetRules(target, libName);
  900. std::ifstream fin(m_DSPHeaderTemplate.c_str());
  901. if(!fin)
  902. {
  903. cmSystemTools::Error("Error Reading ", m_DSPHeaderTemplate.c_str());
  904. }
  905. std::string staticLibOptions;
  906. if(target.GetType() == cmTarget::STATIC_LIBRARY )
  907. {
  908. if(const char* libflags = target.GetProperty("STATIC_LIBRARY_FLAGS"))
  909. {
  910. staticLibOptions = libflags;
  911. }
  912. }
  913. std::string line;
  914. while(cmSystemTools::GetLineFromStream(fin, line))
  915. {
  916. const char* mfcFlag = m_Makefile->GetDefinition("CMAKE_MFC_FLAG");
  917. if(!mfcFlag)
  918. {
  919. mfcFlag = "0";
  920. }
  921. cmSystemTools::ReplaceString(line, "CMAKE_CUSTOM_RULE_CODE",
  922. customRuleCode.c_str());
  923. cmSystemTools::ReplaceString(line, "CMAKE_MFC_FLAG",
  924. mfcFlag);
  925. if(target.GetType() == cmTarget::STATIC_LIBRARY )
  926. {
  927. cmSystemTools::ReplaceString(line, "CM_STATIC_LIB_ARGS",
  928. staticLibOptions.c_str());
  929. }
  930. if(m_Makefile->IsOn("CMAKE_VERBOSE_MAKEFILE"))
  931. {
  932. cmSystemTools::ReplaceString(line, "/nologo", "");
  933. }
  934. cmSystemTools::ReplaceString(line, "CM_LIBRARIES",
  935. libOptions.c_str());
  936. cmSystemTools::ReplaceString(line, "CM_DEBUG_LIBRARIES",
  937. libDebugOptions.c_str());
  938. cmSystemTools::ReplaceString(line, "CM_OPTIMIZED_LIBRARIES",
  939. libOptimizedOptions.c_str());
  940. cmSystemTools::ReplaceString(line, "CM_MULTILINE_LIBRARIES_FOR_DEBUG",
  941. libMultiLineOptionsForDebug.c_str());
  942. cmSystemTools::ReplaceString(line, "CM_MULTILINE_LIBRARIES",
  943. libMultiLineOptions.c_str());
  944. cmSystemTools::ReplaceString(line, "CM_MULTILINE_DEBUG_LIBRARIES",
  945. libMultiLineDebugOptions.c_str());
  946. cmSystemTools::ReplaceString(line, "CM_MULTILINE_OPTIMIZED_LIBRARIES",
  947. libMultiLineOptimizedOptions.c_str());
  948. cmSystemTools::ReplaceString(line, "BUILD_INCLUDES",
  949. m_IncludeOptions.c_str());
  950. cmSystemTools::ReplaceString(line, "OUTPUT_LIBNAME",libName);
  951. // because LIBRARY_OUTPUT_PATH and EXECUTABLE_OUTPUT_PATH
  952. // are already quoted in the template file,
  953. // we need to remove the quotes here, we still need
  954. // to convert to output path for unix to win32 conversion
  955. cmSystemTools::ReplaceString(line, "LIBRARY_OUTPUT_PATH",
  956. removeQuotes(
  957. this->ConvertToRelativeOutputPath(libPath.c_str())).c_str());
  958. cmSystemTools::ReplaceString(line, "EXECUTABLE_OUTPUT_PATH",
  959. removeQuotes(
  960. this->ConvertToRelativeOutputPath(exePath.c_str())).c_str());
  961. cmSystemTools::ReplaceString(line,
  962. "EXTRA_DEFINES",
  963. m_Makefile->GetDefineFlags());
  964. const char* debugPostfix
  965. = m_Makefile->GetDefinition("CMAKE_DEBUG_POSTFIX");
  966. cmSystemTools::ReplaceString(line, "DEBUG_POSTFIX",
  967. debugPostfix?debugPostfix:"");
  968. cmGlobalGenerator* gen = this->GetGlobalGenerator();
  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 CXX is on and the target contains cxx code then add the cxx flags
  976. if ( gen->GetLanguageEnabled("CXX") && target.HasCxx() )
  977. {
  978. flagsRelease = m_Makefile->GetRequiredDefinition("CMAKE_CXX_FLAGS_RELEASE");
  979. flagsRelease += " -DCMAKE_INTDIR=\\\"Release\\\" ";
  980. flagsMinSize = m_Makefile->GetRequiredDefinition("CMAKE_CXX_FLAGS_MINSIZEREL");
  981. flagsMinSize += " -DCMAKE_INTDIR=\\\"MinSizeRel\\\" ";
  982. flagsDebug = m_Makefile->GetRequiredDefinition("CMAKE_CXX_FLAGS_DEBUG");
  983. flagsDebug += " -DCMAKE_INTDIR=\\\"Debug\\\" ";
  984. flagsDebugRel = m_Makefile->GetRequiredDefinition("CMAKE_CXX_FLAGS_RELWITHDEBINFO");
  985. flagsDebugRel += " -DCMAKE_INTDIR=\\\"RelWithDebInfo\\\" ";
  986. flags = " ";
  987. flags = m_Makefile->GetRequiredDefinition("CMAKE_CXX_FLAGS");
  988. }
  989. // if C and the target is not CXX
  990. else if(gen->GetLanguageEnabled("C") && !target.HasCxx())
  991. {
  992. flagsRelease += m_Makefile->GetRequiredDefinition("CMAKE_C_FLAGS_RELEASE");
  993. flagsRelease += " -DCMAKE_INTDIR=\\\"Release\\\"";
  994. flagsMinSize += m_Makefile->GetRequiredDefinition("CMAKE_C_FLAGS_MINSIZEREL");
  995. flagsMinSize += " -DCMAKE_INTDIR=\\\"MinSizeRel\\\"";
  996. flagsDebug += m_Makefile->GetRequiredDefinition("CMAKE_C_FLAGS_DEBUG");
  997. flagsDebug += " -DCMAKE_INTDIR=\\\"Debug\\\"";
  998. flagsDebugRel += m_Makefile->GetRequiredDefinition("CMAKE_C_FLAGS_RELWITHDEBINFO");
  999. flagsDebugRel += " -DCMAKE_INTDIR=\\\"RelWithDebInfo\\\"";
  1000. flags = " ";
  1001. flags = m_Makefile->GetRequiredDefinition("CMAKE_C_FLAGS");
  1002. }
  1003. // if unicode is not found, then add -D_MBCS
  1004. if(flags.find("D_UNICODE") == flags.npos)
  1005. {
  1006. flags += " /D \"_MBCS\"";
  1007. }
  1008. // The template files have CXX FLAGS in them, that need to be replaced.
  1009. // There are not separate CXX and C template files, so we use the same
  1010. // variable names. The previous code sets up flags* variables to contain
  1011. // the correct C or CXX flags
  1012. cmSystemTools::ReplaceString(line, "CMAKE_CXX_FLAGS_RELEASE", flagsRelease.c_str());
  1013. cmSystemTools::ReplaceString(line, "CMAKE_CXX_FLAGS_MINSIZEREL", flagsMinSize.c_str());
  1014. cmSystemTools::ReplaceString(line, "CMAKE_CXX_FLAGS_DEBUG", flagsDebug.c_str());
  1015. cmSystemTools::ReplaceString(line,"CMAKE_CXX_FLAGS_RELWITHDEBINFO", flagsDebugRel.c_str());
  1016. cmSystemTools::ReplaceString(line, "CMAKE_CXX_FLAGS", flags.c_str());
  1017. fout << line.c_str() << std::endl;
  1018. }
  1019. }
  1020. void cmLocalVisualStudio6Generator::WriteDSPFooter(std::ostream& fout)
  1021. {
  1022. std::ifstream fin(m_DSPFooterTemplate.c_str());
  1023. if(!fin)
  1024. {
  1025. cmSystemTools::Error("Error Reading ",
  1026. m_DSPFooterTemplate.c_str());
  1027. }
  1028. std::string line;
  1029. while(cmSystemTools::GetLineFromStream(fin, line))
  1030. {
  1031. fout << line << std::endl;
  1032. }
  1033. }