cmVisualStudio10TargetGenerator.cxx 32 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965
  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 "cmVisualStudio10TargetGenerator.h"
  14. #include "cmGlobalVisualStudio7Generator.h"
  15. #include "cmTarget.h"
  16. #include "cmComputeLinkInformation.h"
  17. #include "cmGeneratedFileStream.h"
  18. #include "cmMakefile.h"
  19. #include "cmSourceFile.h"
  20. #include "cmVisualStudioGeneratorOptions.h"
  21. #include "cmLocalVisualStudio7Generator.h"
  22. #include "cmVS10CLFlagTable.h"
  23. #include "cmVS10LinkFlagTable.h"
  24. cmVisualStudio10TargetGenerator::
  25. cmVisualStudio10TargetGenerator(cmTarget* target,
  26. cmGlobalVisualStudio7Generator* gg)
  27. {
  28. this->GlobalGenerator = gg;
  29. this->GlobalGenerator->CreateGUID(target->GetName());
  30. this->GUID = this->GlobalGenerator->GetGUID(target->GetName());
  31. this->Target = target;
  32. this->Makefile = target->GetMakefile();
  33. this->LocalGenerator =
  34. (cmLocalVisualStudio7Generator*)
  35. this->Makefile->GetLocalGenerator();
  36. this->Platform = "|Win32";
  37. }
  38. cmVisualStudio10TargetGenerator::~cmVisualStudio10TargetGenerator()
  39. {
  40. delete this->BuildFileStream;
  41. }
  42. void cmVisualStudio10TargetGenerator::WritePlatformConfigTag(
  43. const char* tag,
  44. const char* config,
  45. int indentLevel,
  46. const char* attribute,
  47. const char* end,
  48. std::ostream* stream)
  49. {
  50. if(!stream)
  51. {
  52. stream = this->BuildFileStream;
  53. }
  54. stream->fill(' ');
  55. stream->width(indentLevel*2 );
  56. (*stream ) << "";
  57. (*stream ) << "<" << tag
  58. << " Condition=\"'$(Configuration)|$(Platform)'=='";
  59. (*stream ) << config << this->Platform << "'\"";
  60. if(attribute)
  61. {
  62. (*stream ) << attribute;
  63. }
  64. // close the tag
  65. (*stream ) << ">";
  66. if(end)
  67. {
  68. (*stream ) << end;
  69. }
  70. }
  71. void cmVisualStudio10TargetGenerator::WriteString(const char* line,
  72. int indentLevel)
  73. {
  74. this->BuildFileStream->fill(' ');
  75. this->BuildFileStream->width(indentLevel*2 );
  76. // write an empty string to get the fill level indent to print
  77. (*this->BuildFileStream ) << "";
  78. (*this->BuildFileStream ) << line;
  79. }
  80. void cmVisualStudio10TargetGenerator::Generate()
  81. {
  82. // Tell the global generator the name of the project file
  83. this->Target->SetProperty("GENERATOR_FILE_NAME",this->Target->GetName());
  84. this->Target->SetProperty("GENERATOR_FILE_NAME_EXT",
  85. ".vcxproj");
  86. cmMakefile* mf = this->Target->GetMakefile();
  87. std::string path = mf->GetStartOutputDirectory();
  88. path += "/";
  89. path += this->Target->GetName();
  90. path += ".vcxproj";
  91. this->BuildFileStream =
  92. new cmGeneratedFileStream(path.c_str());
  93. this->BuildFileStream->SetCopyIfDifferent(true);
  94. // Write the encoding header into the file
  95. char magic[] = {0xEF,0xBB, 0xBF};
  96. this->BuildFileStream->write(magic, 3);
  97. this->WriteString("<Project DefaultTargets=\"Build\" "
  98. "ToolsVersion=\"4.0\" "
  99. "xmlns=\"http://schemas.microsoft.com/"
  100. "developer/msbuild/2003\">\n",
  101. 0);
  102. this->WriteProjectConfigurations();
  103. this->WriteString("<PropertyGroup Label=\"Globals\">\n", 1);
  104. this->WriteString("<ProjectGUID>", 2);
  105. (*this->BuildFileStream) << "{" << this->GUID << "}</ProjectGUID>\n";
  106. this->WriteString("<SccProjectName />\n", 2);
  107. this->WriteString("<SccLocalPath />\n", 2);
  108. this->WriteString("<Keyword>Win32Proj</Keyword>\n", 2);
  109. this->WriteString("</PropertyGroup>\n", 1);
  110. this->WriteString("<Import Project="
  111. "\"$(VCTargetsPath)\\Microsoft.Cpp.Default.props\" />\n",
  112. 1);
  113. this->WriteProjectConfigurationValues();
  114. this->WriteString(
  115. "<Import Project=\"$(VCTargetsPath)\\Microsoft.Cpp.props\" />\n", 1);
  116. this->WriteString("<ImportGroup Label=\"ExtensionSettings\">\n", 1);
  117. this->WriteString("</ImportGroup>\n", 1);
  118. this->WriteString("<ImportGroup Label=\"PropertySheets\">\n", 1);
  119. this->WriteString("<Import Project="
  120. "\"$(LocalAppData)\\Microsoft\\VisualStudio\\10.0\\"
  121. "Microsoft.Cpp.$(Platform).user.props\" "
  122. "Condition=\"exists('$(LocalAppData)\\Microsoft"
  123. "\\VisualStudio\\10.0\\"
  124. "Microsoft.Cpp.$(Platform).user.props')\" />\n", 2);
  125. this->WriteString("</ImportGroup>\n", 1);
  126. this->WriteString("<PropertyGroup Label=\"UserMacros\" />\n", 1);
  127. this->WritePathAndIncrementalLinkOptions();
  128. this->WriteItemDefinitionGroups();
  129. this->WriteCustomCommands();
  130. this->WriteSources();
  131. this->WriteProjectReferences();
  132. this->WriteString(
  133. "<Import Project=\"$(VCTargetsPath)\\Microsoft.Cpp.targets\""
  134. " />\n", 1);
  135. this->WriteString("<ImportGroup Label=\"ExtensionTargets\">\n", 1);
  136. this->WriteString("</ImportGroup>\n", 1);
  137. this->WriteString("</Project>", 0);
  138. // The groups are stored in a separate file for VS 10
  139. this->WriteGroups();
  140. }
  141. // ConfigurationType Application, Utility StaticLibrary DynamicLibrary
  142. void cmVisualStudio10TargetGenerator::WriteProjectConfigurations()
  143. {
  144. this->WriteString("<ItemGroup Label=\"ProjectConfigurations\">\n", 1);
  145. std::vector<std::string> *configs =
  146. static_cast<cmGlobalVisualStudio7Generator *>
  147. (this->GlobalGenerator)->GetConfigurations();
  148. for(std::vector<std::string>::iterator i = configs->begin();
  149. i != configs->end(); ++i)
  150. {
  151. this->WriteString("<ProjectConfiguration Include=\"", 2);
  152. (*this->BuildFileStream ) << *i << this->Platform << "\">\n";
  153. this->WriteString("<Configuration>", 3);
  154. (*this->BuildFileStream ) << *i << "</Configuration>\n";
  155. this->WriteString("<Platform>Win32</Platform>\n", 3);
  156. this->WriteString("</ProjectConfiguration>\n", 2);
  157. }
  158. this->WriteString("</ItemGroup>\n", 1);
  159. }
  160. void cmVisualStudio10TargetGenerator::WriteProjectConfigurationValues()
  161. {
  162. std::vector<std::string> *configs =
  163. static_cast<cmGlobalVisualStudio7Generator *>
  164. (this->GlobalGenerator)->GetConfigurations();
  165. for(std::vector<std::string>::iterator i = configs->begin();
  166. i != configs->end(); ++i)
  167. {
  168. this->WritePlatformConfigTag("PropertyGroup",
  169. i->c_str(),
  170. 1, " Label=\"Configuration\"", "\n");
  171. std::string configType = "<ConfigurationType>";
  172. switch(this->Target->GetType())
  173. {
  174. case cmTarget::SHARED_LIBRARY:
  175. case cmTarget::MODULE_LIBRARY:
  176. configType += "DynamicLibrary";
  177. break;
  178. case cmTarget::STATIC_LIBRARY:
  179. configType += "StaticLibrary";
  180. break;
  181. case cmTarget::EXECUTABLE:
  182. configType += "Application";
  183. break;
  184. case cmTarget::UTILITY:
  185. configType += "Utility";
  186. break;
  187. }
  188. configType += "</ConfigurationType>\n";
  189. this->WriteString(configType.c_str(), 2);
  190. const char* mfcFlag =
  191. this->Target->GetMakefile()->GetDefinition("CMAKE_MFC_FLAG");
  192. if(mfcFlag)
  193. {
  194. this->WriteString("<UseOfMfc>true</UseOfMfc>\n", 2);
  195. }
  196. else
  197. {
  198. this->WriteString("<UseOfMfc>false</UseOfMfc>\n", 2);
  199. }
  200. this->WriteString("<CharacterSet>MultiByte</CharacterSet>\n", 2);
  201. this->WriteString("</PropertyGroup>\n", 1);
  202. }
  203. }
  204. void cmVisualStudio10TargetGenerator::WriteCustomCommands()
  205. {
  206. this->WriteString("<ItemGroup>\n", 1);
  207. std::vector<cmSourceFile*>const & sources = this->Target->GetSourceFiles();
  208. for(std::vector<cmSourceFile*>::const_iterator source = sources.begin();
  209. source != sources.end(); ++source)
  210. {
  211. if(cmCustomCommand const* command = (*source)->GetCustomCommand())
  212. {
  213. this->WriteCustomRule(*source, *command);
  214. }
  215. }
  216. this->WriteString("</ItemGroup>\n", 1);
  217. }
  218. void
  219. cmVisualStudio10TargetGenerator::WriteCustomRule(cmSourceFile* source,
  220. cmCustomCommand const &
  221. command)
  222. {
  223. std::string sourcePath = source->GetFullPath();
  224. // the rule file seems to need to exist for vs10
  225. if (source->GetExtension() == "rule")
  226. {
  227. if(!cmSystemTools::FileExists(sourcePath.c_str()))
  228. {
  229. std::ofstream fout(sourcePath.c_str());
  230. if(fout)
  231. {
  232. fout << "# generated from CMake\n";
  233. fout.flush();
  234. fout.close();
  235. }
  236. }
  237. }
  238. cmLocalVisualStudio7Generator* lg = this->LocalGenerator;
  239. std::string comment = lg->ConstructComment(command);
  240. std::vector<std::string> *configs =
  241. static_cast<cmGlobalVisualStudio7Generator *>
  242. (this->GlobalGenerator)->GetConfigurations();
  243. this->WriteString("<CustomBuild Include=\"", 2);
  244. (*this->BuildFileStream ) <<
  245. cmSystemTools::RelativePath(this->Makefile->GetCurrentOutputDirectory(),
  246. sourcePath.c_str()) << "\">\n";
  247. for(std::vector<std::string>::iterator i = configs->begin();
  248. i != configs->end(); ++i)
  249. {
  250. std::string script = lg->ConstructScript(command.GetCommandLines(),
  251. command.GetWorkingDirectory(),
  252. i->c_str(),
  253. command.GetEscapeOldStyle(),
  254. command.GetEscapeAllowMakeVars());
  255. this->WritePlatformConfigTag("Message",i->c_str(), 3);
  256. (*this->BuildFileStream ) << comment << "</Message>\n";
  257. this->WritePlatformConfigTag("Command", i->c_str(), 3);
  258. (*this->BuildFileStream ) << script << "</Command>\n";
  259. this->WritePlatformConfigTag("AdditionalInputs", i->c_str(), 3);
  260. (*this->BuildFileStream ) << source->GetFullPath();
  261. for(std::vector<std::string>::const_iterator d =
  262. command.GetDepends().begin();
  263. d != command.GetDepends().end();
  264. ++d)
  265. {
  266. std::string dep = this->LocalGenerator->
  267. GetRealDependency(d->c_str(), i->c_str());
  268. this->ConvertToWindowsSlash(dep);
  269. (*this->BuildFileStream ) << ";" << dep;
  270. }
  271. (*this->BuildFileStream ) << ";%(AdditionalInputs)</AdditionalInputs>\n";
  272. this->WritePlatformConfigTag("Outputs", i->c_str(), 3);
  273. const char* sep = "";
  274. for(std::vector<std::string>::const_iterator o =
  275. command.GetOutputs().begin();
  276. o != command.GetOutputs().end();
  277. ++o)
  278. {
  279. std::string out = *o;
  280. this->ConvertToWindowsSlash(out);
  281. (*this->BuildFileStream ) << sep << out;
  282. sep = ";";
  283. }
  284. (*this->BuildFileStream ) << ";%(Outputs)</Outputs>\n";
  285. }
  286. this->WriteString("</CustomBuild>\n", 2);
  287. }
  288. void cmVisualStudio10TargetGenerator::ConvertToWindowsSlash(std::string& s)
  289. {
  290. // first convert all of the slashes
  291. std::string::size_type pos = 0;
  292. while((pos = s.find('/', pos)) != std::string::npos)
  293. {
  294. s[pos] = '\\';
  295. pos++;
  296. }
  297. }
  298. void cmVisualStudio10TargetGenerator::WriteGroups()
  299. {
  300. // This should create a target.vcxproj.filters file
  301. // something like this:
  302. /*
  303. <?xml version="1.0" encoding="utf-8"?>
  304. <Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
  305. <ItemGroup>
  306. <CustomBuild Include="..\CMakeLists.txt" />
  307. </ItemGroup>
  308. <ItemGroup>
  309. <Filter Include="Source Files">
  310. <UniqueIdentifier>{05072589-c7be-439a-8fd7-5db6ee5008a9}</UniqueIdentifier>
  311. </Filter>
  312. </ItemGroup>
  313. <ItemGroup>
  314. <ClCompile Include="..\foo.c">
  315. <Filter>Source Files</Filter>
  316. </ClCompile>
  317. <ClCompile Include="..\testCCompiler.c">
  318. <Filter>Source Files</Filter>
  319. </ClCompile>
  320. </ItemGroup>
  321. </Project>
  322. */
  323. }
  324. void cmVisualStudio10TargetGenerator::WriteSources()
  325. {
  326. this->WriteString("<ItemGroup>\n", 1);
  327. if(this->Target->GetType() > cmTarget::MODULE_LIBRARY)
  328. {
  329. this->WriteString("<None Include=\"", 2);
  330. (*this->BuildFileStream ) << this->Target->GetDirectory()
  331. << "\\" << this->Target->GetName()
  332. << "\" />\n";
  333. }
  334. else
  335. {
  336. std::vector<cmSourceFile*>const & sources = this->Target->GetSourceFiles();
  337. for(std::vector<cmSourceFile*>::const_iterator source = sources.begin();
  338. source != sources.end(); ++source)
  339. {
  340. // if it is not a custom command then add it as a c file,
  341. // TODO: need to check for idl or rc, or exclude from build
  342. if(!(*source)->GetCustomCommand()
  343. && !(*source)->GetPropertyAsBool("HEADER_FILE_ONLY")
  344. && !this->GlobalGenerator->IgnoreFile
  345. ((*source)->GetExtension().c_str()))
  346. {
  347. const char* lang = (*source)->GetLanguage();
  348. if(lang && (strcmp(lang, "C") == 0 || strcmp(lang, "CXX") ==0))
  349. {
  350. std::string sourceFile = (*source)->GetFullPath();
  351. // output the source file
  352. this->WriteString("<ClCompile Include=\"", 2);
  353. (*this->BuildFileStream ) << sourceFile << "\"";
  354. // ouput any flags specific to this source file
  355. if(this->OutputSourceSpecificFlags(*source))
  356. {
  357. // if the source file has specific flags the tag
  358. // is ended on a new line
  359. this->WriteString("</ClCompile>\n", 2);
  360. }
  361. else
  362. {
  363. (*this->BuildFileStream ) << " />\n";
  364. }
  365. }
  366. }
  367. }
  368. }
  369. this->WriteString("</ItemGroup>\n", 1);
  370. }
  371. bool cmVisualStudio10TargetGenerator::OutputSourceSpecificFlags(
  372. cmSourceFile* source)
  373. {
  374. cmSourceFile& sf = *source;
  375. std::string flags;
  376. std::string defines;
  377. if(const char* cflags = sf.GetProperty("COMPILE_FLAGS"))
  378. {
  379. flags += cflags;
  380. }
  381. if(const char* cdefs = sf.GetProperty("COMPILE_DEFINITIONS"))
  382. {
  383. defines += cdefs;
  384. }
  385. const char* lang =
  386. this->GlobalGenerator->GetLanguageFromExtension
  387. (sf.GetExtension().c_str());
  388. const char* sourceLang = this->LocalGenerator->GetSourceFileLanguage(sf);
  389. const char* linkLanguage = this->Target->GetLinkerLanguage
  390. (this->LocalGenerator->GetGlobalGenerator());
  391. bool needForceLang = false;
  392. // source file does not match its extension language
  393. if(lang && sourceLang && strcmp(lang, sourceLang) != 0)
  394. {
  395. needForceLang = true;
  396. lang = sourceLang;
  397. }
  398. // if the source file does not match the linker language
  399. // then force c or c++
  400. if(needForceLang || (linkLanguage && lang
  401. && strcmp(lang, linkLanguage) != 0))
  402. {
  403. if(strcmp(lang, "CXX") == 0)
  404. {
  405. // force a C++ file type
  406. flags += " /TP ";
  407. }
  408. else if(strcmp(lang, "C") == 0)
  409. {
  410. // force to c
  411. flags += " /TC ";
  412. }
  413. }
  414. // for the first time we need a new line if there is something
  415. // produced here.
  416. const char* firstString = ">\n";
  417. std::vector<std::string> *configs =
  418. static_cast<cmGlobalVisualStudio7Generator *>
  419. (this->GlobalGenerator)->GetConfigurations();
  420. bool hasFlags = false;
  421. for( std::vector<std::string>::iterator config = configs->begin();
  422. config != configs->end(); ++config)
  423. {
  424. std::string configUpper = cmSystemTools::UpperCase(*config);
  425. std::string configDefines = defines;
  426. std::string defPropName = "COMPILE_DEFINITIONS_";
  427. defPropName += configUpper;
  428. if(const char* ccdefs = sf.GetProperty(defPropName.c_str()))
  429. {
  430. if(configDefines.size())
  431. {
  432. configDefines += ",";
  433. }
  434. configDefines += ccdefs;
  435. }
  436. // if we have flags or defines for this config then
  437. // use them
  438. if(flags.size() || configDefines.size())
  439. {
  440. (*this->BuildFileStream ) << firstString;
  441. firstString = ""; // only do firstString once
  442. hasFlags = true;
  443. cmVisualStudioGeneratorOptions
  444. clOptions(this->LocalGenerator,
  445. 10, cmVisualStudioGeneratorOptions::Compiler,
  446. cmVS10CLFlagTable, 0, this);
  447. clOptions.Parse(flags.c_str());
  448. clOptions.AddDefines(configDefines.c_str());
  449. clOptions.SetConfiguration((*config).c_str());
  450. clOptions.OutputAdditionalOptions(*this->BuildFileStream, " ", "");
  451. clOptions.OutputFlagMap(*this->BuildFileStream, " ");
  452. clOptions.OutputPreprocessorDefinitions(*this->BuildFileStream, " ",
  453. "\n");
  454. }
  455. }
  456. return hasFlags;
  457. }
  458. void cmVisualStudio10TargetGenerator::WritePathAndIncrementalLinkOptions()
  459. {
  460. this->WriteString("<PropertyGroup>\n", 2);
  461. this->WriteString("<_ProjectFileVersion>10.0.20506.1"
  462. "</_ProjectFileVersion>\n", 3);
  463. std::vector<std::string> *configs =
  464. static_cast<cmGlobalVisualStudio7Generator *>
  465. (this->GlobalGenerator)->GetConfigurations();
  466. for(std::vector<std::string>::iterator config = configs->begin();
  467. config != configs->end(); ++config)
  468. {
  469. std::string targetNameFull =
  470. this->Target->GetFullName(config->c_str());
  471. std::string intermediateDir = this->LocalGenerator->
  472. GetTargetDirectory(*this->Target);
  473. intermediateDir += "/";
  474. intermediateDir += *config;
  475. intermediateDir += "/";
  476. this->ConvertToWindowsSlash(intermediateDir);
  477. std::string outDir = this->Target->GetDirectory(config->c_str());
  478. this->ConvertToWindowsSlash(outDir);
  479. this->WritePlatformConfigTag("OutDir", config->c_str(), 3);
  480. *this->BuildFileStream << outDir
  481. << "\\"
  482. << "</OutDir>\n";
  483. this->WritePlatformConfigTag("IntDir", config->c_str(), 3);
  484. *this->BuildFileStream << intermediateDir
  485. << "</IntDir>\n";
  486. this->WritePlatformConfigTag("TargetName", config->c_str(), 3);
  487. *this->BuildFileStream << cmSystemTools::GetFilenameWithoutExtension(
  488. targetNameFull.c_str())
  489. << "</TargetName>\n";
  490. this->WritePlatformConfigTag("TargetExt", config->c_str(), 3);
  491. *this->BuildFileStream << cmSystemTools::GetFilenameLastExtension(
  492. targetNameFull.c_str())
  493. << "</TargetExt>\n";
  494. this->OutputLinkIncremental(*config);
  495. }
  496. this->WriteString("</PropertyGroup>\n", 2);
  497. }
  498. void
  499. cmVisualStudio10TargetGenerator::
  500. OutputLinkIncremental(std::string const& configName)
  501. {
  502. std::string CONFIG = cmSystemTools::UpperCase(configName);
  503. // static libraries and things greater than modules do not need
  504. // to set this option
  505. if(this->Target->GetType() == cmTarget::STATIC_LIBRARY
  506. || this->Target->GetType() > cmTarget::MODULE_LIBRARY)
  507. {
  508. return;
  509. }
  510. const char* linkType = "SHARED";
  511. if(this->Target->GetType() == cmTarget::EXECUTABLE)
  512. {
  513. linkType = "EXE";
  514. }
  515. // assume incremental linking
  516. const char* incremental = "true";
  517. const char* linkLanguage =
  518. this->Target->GetLinkerLanguage(this->GlobalGenerator);
  519. if(!linkLanguage)
  520. {
  521. cmSystemTools::Error
  522. ("CMake can not determine linker language for target:",
  523. this->Target->GetName());
  524. return;
  525. }
  526. std::string linkFlagVarBase = "CMAKE_";
  527. linkFlagVarBase += linkType;
  528. linkFlagVarBase += "_LINKER_FLAGS";
  529. std::string flags = this->
  530. Target->GetMakefile()->GetRequiredDefinition(linkFlagVarBase.c_str());
  531. std::string linkFlagVar = linkFlagVarBase + "_" + CONFIG;
  532. flags += this->
  533. Target->GetMakefile()->GetRequiredDefinition(linkFlagVar.c_str());
  534. if(strcmp(linkLanguage, "C") == 0 || strcmp(linkLanguage, "CXX") == 0
  535. || strcmp(linkLanguage, "Fortran") == 0)
  536. {
  537. std::string baseFlagVar = "CMAKE_";
  538. baseFlagVar += linkLanguage;
  539. baseFlagVar += "_FLAGS";
  540. flags += this->
  541. Target->GetMakefile()->GetRequiredDefinition(baseFlagVar.c_str());
  542. std::string flagVar = baseFlagVar + std::string("_") + CONFIG;
  543. flags +=
  544. Target->GetMakefile()->GetRequiredDefinition(flagVar.c_str());
  545. }
  546. if(flags.find("INCREMENTAL:NO") != flags.npos)
  547. {
  548. incremental = "false";
  549. }
  550. this->WritePlatformConfigTag("LinkIncremental", configName.c_str(), 3);
  551. *this->BuildFileStream << incremental
  552. << "</LinkIncremental>\n";
  553. }
  554. void
  555. cmVisualStudio10TargetGenerator::
  556. WriteClOptions(std::string const&
  557. configName,
  558. std::vector<std::string> const & includes)
  559. {
  560. // much of this was copied from here:
  561. // copied from cmLocalVisualStudio7Generator.cxx 805
  562. this->WriteString("<ClCompile>\n", 2);
  563. cmVisualStudioGeneratorOptions
  564. clOptions(this->LocalGenerator,
  565. 10, cmVisualStudioGeneratorOptions::Compiler,
  566. cmVS10CLFlagTable);
  567. std::string flags;
  568. // collect up flags for
  569. if(this->Target->GetType() < cmTarget::UTILITY)
  570. {
  571. const char* linkLanguage =
  572. this->Target->GetLinkerLanguage(this->GlobalGenerator);
  573. if(!linkLanguage)
  574. {
  575. cmSystemTools::Error
  576. ("CMake can not determine linker language for target:",
  577. this->Target->GetName());
  578. return;
  579. }
  580. if(strcmp(linkLanguage, "C") == 0 || strcmp(linkLanguage, "CXX") == 0
  581. || strcmp(linkLanguage, "Fortran") == 0)
  582. {
  583. std::string baseFlagVar = "CMAKE_";
  584. baseFlagVar += linkLanguage;
  585. baseFlagVar += "_FLAGS";
  586. flags = this->
  587. Target->GetMakefile()->GetRequiredDefinition(baseFlagVar.c_str());
  588. std::string flagVar = baseFlagVar + std::string("_") +
  589. cmSystemTools::UpperCase(configName);
  590. flags += " ";
  591. flags += this->
  592. Target->GetMakefile()->GetRequiredDefinition(flagVar.c_str());
  593. }
  594. // set the correct language
  595. if(strcmp(linkLanguage, "C") == 0)
  596. {
  597. flags += " /TC ";
  598. }
  599. if(strcmp(linkLanguage, "CXX") == 0)
  600. {
  601. flags += " /TP ";
  602. }
  603. }
  604. std::string configUpper = cmSystemTools::UpperCase(configName);
  605. std::string defPropName = "COMPILE_DEFINITIONS_";
  606. defPropName += configUpper;
  607. // Get preprocessor definitions for this directory.
  608. std::string defineFlags = this->Target->GetMakefile()->GetDefineFlags();
  609. clOptions.FixExceptionHandlingDefault();
  610. clOptions.Parse(flags.c_str());
  611. clOptions.Parse(defineFlags.c_str());
  612. clOptions.AddDefines
  613. (this->Makefile->GetProperty("COMPILE_DEFINITIONS"));
  614. clOptions.AddDefines(this->Target->GetProperty("COMPILE_DEFINITIONS"));
  615. clOptions.AddDefines(this->Makefile->GetProperty(defPropName.c_str()));
  616. clOptions.AddDefines(this->Target->GetProperty(defPropName.c_str()));
  617. clOptions.SetVerboseMakefile(
  618. this->Makefile->IsOn("CMAKE_VERBOSE_MAKEFILE"));
  619. // Add a definition for the configuration name.
  620. std::string configDefine = "CMAKE_INTDIR=\"";
  621. configDefine += configName;
  622. configDefine += "\"";
  623. clOptions.AddDefine(configDefine);
  624. if(const char* exportMacro = this->Target->GetExportMacro())
  625. {
  626. clOptions.AddDefine(exportMacro);
  627. }
  628. clOptions.OutputAdditionalOptions(*this->BuildFileStream, " ", "");
  629. this->OutputIncludes(includes);
  630. clOptions.OutputFlagMap(*this->BuildFileStream, " ");
  631. clOptions.OutputPreprocessorDefinitions(*this->BuildFileStream, " ",
  632. "\n");
  633. this->WriteString("<AssemblerListingLocation>", 3);
  634. *this->BuildFileStream << configName
  635. << "</AssemblerListingLocation>\n";
  636. this->WriteString("<ObjectFileName>$(IntDir)</ObjectFileName>\n", 3);
  637. this->WriteString("<ProgramDataBaseFileName>", 3);
  638. *this->BuildFileStream << this->Target->GetDirectory(configName.c_str())
  639. << "/"
  640. << this->Target->GetPDBName(configName.c_str())
  641. << "</ProgramDataBaseFileName>\n";
  642. this->WriteString("</ClCompile>\n", 2);
  643. }
  644. void cmVisualStudio10TargetGenerator::
  645. OutputIncludes(std::vector<std::string> const & includes)
  646. {
  647. this->WriteString("<AdditionalIncludeDirectories>", 3);
  648. for(std::vector<std::string>::const_iterator i = includes.begin();
  649. i != includes.end(); ++i)
  650. {
  651. *this->BuildFileStream << *i << ";";
  652. }
  653. this->WriteString("%(AdditionalIncludeDirectories)"
  654. "</AdditionalIncludeDirectories>\n", 0);
  655. }
  656. void cmVisualStudio10TargetGenerator::
  657. WriteRCOptions(std::string const& config,
  658. std::vector<std::string> const & includes)
  659. {
  660. this->WriteString("<ResourceCompile>\n", 2);
  661. this->OutputIncludes(includes);
  662. this->WriteString("</ResourceCompile>\n", 2);
  663. }
  664. void cmVisualStudio10TargetGenerator::WriteLinkOptions(std::string const&
  665. config)
  666. {
  667. // static libraries and things greater than modules do not need
  668. // to set this option
  669. if(this->Target->GetType() == cmTarget::STATIC_LIBRARY
  670. || this->Target->GetType() > cmTarget::MODULE_LIBRARY)
  671. {
  672. return;
  673. }
  674. const char* linkLanguage =
  675. this->Target->GetLinkerLanguage(this->GlobalGenerator);
  676. if(!linkLanguage)
  677. {
  678. cmSystemTools::Error
  679. ("CMake can not determine linker language for target:",
  680. this->Target->GetName());
  681. return;
  682. }
  683. this->WriteString("<Link>\n", 2);
  684. std::string CONFIG = cmSystemTools::UpperCase(config);
  685. const char* linkType = "SHARED";
  686. if(this->Target->GetType() == cmTarget::MODULE_LIBRARY)
  687. {
  688. linkType = "MODULE";
  689. }
  690. if(this->Target->GetType() == cmTarget::EXECUTABLE)
  691. {
  692. linkType = "EXE";
  693. }
  694. std::string stackVar = "CMAKE_";
  695. stackVar += linkLanguage;
  696. stackVar += "_STACK_SIZE";
  697. const char* stackVal = this->Makefile->GetDefinition(stackVar.c_str());
  698. std::string flags;
  699. if(stackVal)
  700. {
  701. flags += " ";
  702. flags += stackVal;
  703. }
  704. // assume incremental linking
  705. std::string linkFlagVarBase = "CMAKE_";
  706. linkFlagVarBase += linkType;
  707. linkFlagVarBase += "_LINKER_FLAGS";
  708. flags += " ";
  709. flags += this->
  710. Target->GetMakefile()->GetRequiredDefinition(linkFlagVarBase.c_str());
  711. std::string linkFlagVar = linkFlagVarBase + "_" + CONFIG;
  712. flags += " ";
  713. flags += this->
  714. Target->GetMakefile()->GetRequiredDefinition(linkFlagVar.c_str());
  715. const char* targetLinkFlags = this->Target->GetProperty("LINK_FLAGS");
  716. if(targetLinkFlags)
  717. {
  718. flags += " ";
  719. flags += targetLinkFlags;
  720. }
  721. cmVisualStudioGeneratorOptions
  722. linkOptions(this->LocalGenerator,
  723. 10, cmVisualStudioGeneratorOptions::Compiler,
  724. cmVS10LinkFlagTable);
  725. if ( this->Target->GetPropertyAsBool("WIN32_EXECUTABLE") )
  726. {
  727. flags += " /SUBSYSTEM:WINDOWS";
  728. }
  729. else
  730. {
  731. flags += " /SUBSYSTEM:CONSOLE";
  732. }
  733. cmSystemTools::ReplaceString(flags, "/INCREMENTAL:YES", "");
  734. cmSystemTools::ReplaceString(flags, "/INCREMENTAL:NO", "");
  735. std::string standardLibsVar = "CMAKE_";
  736. standardLibsVar += linkLanguage;
  737. standardLibsVar += "_STANDARD_LIBRARIES";
  738. std::string
  739. libs = this->Makefile->GetSafeDefinition(standardLibsVar.c_str());
  740. // Remove trailing spaces from libs
  741. std::string::size_type pos = libs.size()-1;
  742. if(libs.size() != 0)
  743. {
  744. while(libs[pos] == ' ')
  745. {
  746. pos--;
  747. }
  748. }
  749. if(pos != libs.size()-1)
  750. {
  751. libs = libs.substr(0, pos+1);
  752. }
  753. // Replace spaces in libs with ;
  754. cmSystemTools::ReplaceString(libs, " ", ";");
  755. cmComputeLinkInformation* pcli =
  756. this->Target->GetLinkInformation(config.c_str());
  757. if(!pcli)
  758. {
  759. cmSystemTools::Error
  760. ("CMake can not compute cmComputeLinkInformation for target:",
  761. this->Target->GetName());
  762. return;
  763. }
  764. // add the libraries for the target to libs string
  765. cmComputeLinkInformation& cli = *pcli;
  766. this->AddLibraries(cli, libs);
  767. linkOptions.AddFlag("AdditionalDependencies", libs.c_str());
  768. std::vector<std::string> const& ldirs = cli.GetDirectories();
  769. const char* sep = "";
  770. std::string linkDirs;
  771. for(std::vector<std::string>::const_iterator d = ldirs.begin();
  772. d != ldirs.end(); ++d)
  773. {
  774. linkDirs += sep;
  775. linkDirs += *d;
  776. sep = ";";
  777. }
  778. linkDirs += "%(AdditionalLibraryDirectories)";
  779. linkOptions.AddFlag("AdditionalLibraryDirectories", linkDirs.c_str());
  780. linkOptions.AddFlag("AdditionalDependencies", libs.c_str());
  781. linkOptions.AddFlag("Version", "0.0");
  782. if(linkOptions.IsDebug() || flags.find("/debug") != flags.npos)
  783. {
  784. linkOptions.AddFlag("GenerateDebugInformation", "true");
  785. }
  786. else
  787. {
  788. linkOptions.AddFlag("GenerateDebugInformation", "false");
  789. }
  790. std::string targetName;
  791. std::string targetNameSO;
  792. std::string targetNameFull;
  793. std::string targetNameImport;
  794. std::string targetNamePDB;
  795. if(this->Target->GetType() == cmTarget::EXECUTABLE)
  796. {
  797. this->Target->GetExecutableNames(targetName, targetNameFull,
  798. targetNameImport, targetNamePDB,
  799. config.c_str());
  800. }
  801. else
  802. {
  803. this->Target->GetLibraryNames(targetName, targetNameSO, targetNameFull,
  804. targetNameImport, targetNamePDB,
  805. config.c_str());
  806. }
  807. std::string dir = this->Target->GetDirectory(config.c_str());
  808. dir += "/";
  809. std::string imLib = dir;
  810. imLib += targetNameImport;
  811. std::string pdb = dir;
  812. pdb += targetNamePDB;
  813. linkOptions.AddFlag("ImportLibrary", imLib.c_str());
  814. linkOptions.AddFlag("ProgramDataBaseFileName", pdb.c_str());
  815. linkOptions.Parse(flags.c_str());
  816. linkOptions.OutputAdditionalOptions(*this->BuildFileStream, " ", "");
  817. linkOptions.OutputFlagMap(*this->BuildFileStream, " ");
  818. this->WriteString("</Link>\n", 2);
  819. }
  820. void cmVisualStudio10TargetGenerator::AddLibraries(
  821. cmComputeLinkInformation& cli,
  822. std::string& libstring)
  823. {
  824. typedef cmComputeLinkInformation::ItemVector ItemVector;
  825. ItemVector libs = cli.GetItems();
  826. const char* sep = ";";
  827. for(ItemVector::const_iterator l = libs.begin(); l != libs.end(); ++l)
  828. {
  829. if(l->IsPath)
  830. {
  831. std::string path = this->LocalGenerator->
  832. Convert(l->Value.c_str(),
  833. cmLocalGenerator::START_OUTPUT,
  834. cmLocalGenerator::UNCHANGED);
  835. libstring += sep;
  836. libstring += path;
  837. }
  838. else
  839. {
  840. libstring += sep;
  841. libstring += l->Value;
  842. }
  843. }
  844. }
  845. void cmVisualStudio10TargetGenerator::
  846. WriteMidlOptions(std::string const&
  847. config,
  848. std::vector<std::string> const & includes)
  849. {
  850. this->WriteString("<Midl>\n", 2);
  851. this->OutputIncludes(includes);
  852. // Need this stuff, but there is an midl.xml file...
  853. // should we look for .idl language?, and flags?
  854. /*
  855. <MkTypLibCompatible>false</MkTypLibCompatible>
  856. <TargetEnvironment>Win32</TargetEnvironment>
  857. <GenerateStublessProxies>true</GenerateStublessProxies>
  858. <TypeLibraryName>%(FileName).tlb</TypeLibraryName>
  859. <OutputDirectory>$(IntDir)\</OutputDirectory>
  860. <HeaderFileName>%(FileName).h</HeaderFileName>
  861. <DllDataFileName>
  862. </DllDataFileName>
  863. <InterfaceIdentifierFileName>%(FileName)_i.c</InterfaceIdentifierFileName>
  864. <ProxyFileName>%(FileName)_p.c</ProxyFileName>
  865. */
  866. this->WriteString("</Midl>\n", 2);
  867. }
  868. void cmVisualStudio10TargetGenerator::WriteItemDefinitionGroups()
  869. {
  870. std::vector<std::string> *configs =
  871. static_cast<cmGlobalVisualStudio7Generator *>
  872. (this->GlobalGenerator)->GetConfigurations();
  873. std::vector<std::string> includes;
  874. this->LocalGenerator->GetIncludeDirectories(includes);
  875. for(std::vector<std::string>::iterator i = configs->begin();
  876. i != configs->end(); ++i)
  877. {
  878. this->WritePlatformConfigTag("ItemDefinitionGroup", i->c_str(), 1);
  879. *this->BuildFileStream << "\n";
  880. // output cl compile flags <ClCompile></ClCompile>
  881. if(this->Target->GetType() <= cmTarget::MODULE_LIBRARY)
  882. {
  883. this->WriteClOptions(*i, includes);
  884. // output rc compile flags <ResourceCompile></ResourceCompile>
  885. this->WriteRCOptions(*i, includes);
  886. }
  887. // output midl flags <Midl></Midl>
  888. this->WriteMidlOptions(*i, includes);
  889. // output link flags <Link></Link> or <Lib></Lib>
  890. this->WriteLinkOptions(*i);
  891. // TODO: need a WriteLibOptions for static
  892. this->WriteString("</ItemDefinitionGroup>\n", 1);
  893. }
  894. }
  895. // TODO handle .obj file direct stuff
  896. void cmVisualStudio10TargetGenerator::WriteProjectReferences()
  897. {
  898. // TODO
  899. // This should have dependent targets listed like this:
  900. /*
  901. <ItemGroup>
  902. <ProjectReference Include="ZERO_CHECK.vcxproj">
  903. <Project>{2f1e4f3c-0a51-46c3-aaf9-e486599604f2}</Project>
  904. </ProjectReference>
  905. </ItemGroup>
  906. */
  907. }