The JUCE cross-platform C++ framework, with DISTRHO/KXStudio specific changes
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

1539 lines
66KB

  1. /*
  2. ==============================================================================
  3. This file is part of the JUCE library.
  4. Copyright (c) 2013 - Raw Material Software Ltd.
  5. Permission is granted to use this software under the terms of either:
  6. a) the GPL v2 (or any later version)
  7. b) the Affero GPL v3
  8. Details of these licenses can be found at: www.gnu.org/licenses
  9. JUCE is distributed in the hope that it will be useful, but WITHOUT ANY
  10. WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
  11. A PARTICULAR PURPOSE. See the GNU General Public License for more details.
  12. ------------------------------------------------------------------------------
  13. To release a closed-source product which uses JUCE, commercial licenses are
  14. available: visit www.juce.com for more information.
  15. ==============================================================================
  16. */
  17. class MSVCProjectExporterBase : public ProjectExporter
  18. {
  19. public:
  20. MSVCProjectExporterBase (Project& p, const ValueTree& t, const char* const folderName)
  21. : ProjectExporter (p, t)
  22. {
  23. if (getTargetLocationString().isEmpty())
  24. getTargetLocationValue() = getDefaultBuildsRootFolder() + folderName;
  25. projectGUID = createGUID (project.getProjectUID());
  26. updateOldSettings();
  27. }
  28. //==============================================================================
  29. bool usesMMFiles() const { return false; }
  30. bool isVisualStudio() const { return true; }
  31. bool isWindows() const { return true; }
  32. bool canCopeWithDuplicateFiles() { return false; }
  33. bool launchProject()
  34. {
  35. #if JUCE_WINDOWS
  36. return getSLNFile().startAsProcess();
  37. #else
  38. return false;
  39. #endif
  40. }
  41. void createExporterProperties (PropertyListBuilder&)
  42. {
  43. }
  44. protected:
  45. String projectGUID;
  46. mutable File rcFile, iconFile;
  47. File getProjectFile (const String& extension) const { return getTargetFolder().getChildFile (project.getProjectFilenameRoot()).withFileExtension (extension); }
  48. File getSLNFile() const { return getProjectFile (".sln"); }
  49. bool isLibraryDLL() const { return msvcIsDLL || projectType.isDynamicLibrary(); }
  50. static String prependIfNotAbsolute (const String& file, const char* prefix)
  51. {
  52. if (File::isAbsolutePath (file) || file.startsWithChar ('$'))
  53. prefix = "";
  54. return prefix + FileHelpers::windowsStylePath (file);
  55. }
  56. static String getIntDirFile (const String& file) { return prependIfNotAbsolute (file, "$(IntDir)\\"); }
  57. static String getOutDirFile (const String& file) { return prependIfNotAbsolute (file, "$(OutDir)\\"); }
  58. void updateOldSettings()
  59. {
  60. {
  61. const String oldStylePrebuildCommand (getSettingString (Ids::prebuildCommand));
  62. settings.removeProperty (Ids::prebuildCommand, nullptr);
  63. if (oldStylePrebuildCommand.isNotEmpty())
  64. for (ConfigIterator config (*this); config.next();)
  65. dynamic_cast <MSVCBuildConfiguration&> (*config).getPrebuildCommand() = oldStylePrebuildCommand;
  66. }
  67. {
  68. const String oldStyleLibName (getSettingString ("libraryName_Debug"));
  69. settings.removeProperty ("libraryName_Debug", nullptr);
  70. if (oldStyleLibName.isNotEmpty())
  71. for (ConfigIterator config (*this); config.next();)
  72. if (config->isDebug())
  73. config->getTargetBinaryName() = oldStyleLibName;
  74. }
  75. {
  76. const String oldStyleLibName (getSettingString ("libraryName_Release"));
  77. settings.removeProperty ("libraryName_Release", nullptr);
  78. if (oldStyleLibName.isNotEmpty())
  79. for (ConfigIterator config (*this); config.next();)
  80. if (! config->isDebug())
  81. config->getTargetBinaryName() = oldStyleLibName;
  82. }
  83. }
  84. //==============================================================================
  85. class MSVCBuildConfiguration : public BuildConfiguration
  86. {
  87. public:
  88. MSVCBuildConfiguration (Project& p, const ValueTree& settings)
  89. : BuildConfiguration (p, settings)
  90. {
  91. if (getWarningLevel() == 0)
  92. getWarningLevelValue() = 4;
  93. setValueIfVoid (shouldGenerateManifestValue(), true);
  94. }
  95. Value getWarningLevelValue() { return getValue (Ids::winWarningLevel); }
  96. int getWarningLevel() const { return config [Ids::winWarningLevel]; }
  97. Value getPrebuildCommand() { return getValue (Ids::prebuildCommand); }
  98. String getPrebuildCommandString() const { return config [Ids::prebuildCommand]; }
  99. Value getPostbuildCommand() { return getValue (Ids::postbuildCommand); }
  100. String getPostbuildCommandString() const { return config [Ids::postbuildCommand]; }
  101. Value shouldGenerateDebugSymbolsValue() { return getValue (Ids::alwaysGenerateDebugSymbols); }
  102. bool shouldGenerateDebugSymbols() const { return config [Ids::alwaysGenerateDebugSymbols]; }
  103. Value shouldGenerateManifestValue() { return getValue (Ids::generateManifest); }
  104. bool shouldGenerateManifest() const { return config [Ids::generateManifest]; }
  105. Value getWholeProgramOptValue() { return getValue (Ids::wholeProgramOptimisation); }
  106. bool shouldDisableWholeProgramOpt() const { return static_cast<int> (config [Ids::wholeProgramOptimisation]) > 0; }
  107. Value getUsingRuntimeLibDLL() { return getValue (Ids::useRuntimeLibDLL); }
  108. bool isUsingRuntimeLibDLL() const { return config [Ids::useRuntimeLibDLL]; }
  109. String getIntermediatesPath() const { return config [Ids::intermediatesPath].toString(); }
  110. Value getIntermediatesPathValue() { return getValue (Ids::intermediatesPath); }
  111. String getCharacterSet() const
  112. {
  113. String charSet (config [Ids::characterSet].toString());
  114. if (charSet.isEmpty())
  115. charSet = "MultiByte";
  116. return charSet;
  117. }
  118. Value getCharacterSetValue() { return getValue (Ids::characterSet); }
  119. String getOutputFilename (const String& suffix, bool forceSuffix) const
  120. {
  121. const String target (File::createLegalFileName (getTargetBinaryNameString().trim()));
  122. if (forceSuffix || ! target.containsChar ('.'))
  123. return target.upToLastOccurrenceOf (".", false, false) + suffix;
  124. return target;
  125. }
  126. void createConfigProperties (PropertyListBuilder& props)
  127. {
  128. props.add (new TextPropertyComponent (getIntermediatesPathValue(), "Intermediates path", 2048, false),
  129. "An optional path to a folder to use for the intermediate build files. Note that Visual Studio allows "
  130. "you to use macros in this path, e.g. \"$(TEMP)\\MyAppBuildFiles\\$(Configuration)\", which is a handy way to "
  131. "send them to the user's temp folder.");
  132. const char* const warningLevelNames[] = { "Low", "Medium", "High", nullptr };
  133. const int warningLevels[] = { 2, 3, 4 };
  134. props.add (new ChoicePropertyComponent (getWarningLevelValue(), "Warning Level",
  135. StringArray (warningLevelNames), Array<var> (warningLevels, numElementsInArray (warningLevels))));
  136. {
  137. const char* const runtimeNames[] = { "(Default)", "Use static runtime", "Use DLL runtime", nullptr };
  138. const var runtimeValues[] = { var(), var (false), var (true) };
  139. props.add (new ChoicePropertyComponent (getUsingRuntimeLibDLL(), "Runtime Library",
  140. StringArray (runtimeNames), Array<var> (runtimeValues, numElementsInArray (runtimeValues))));
  141. }
  142. {
  143. const char* const wpoNames[] = { "Enable link-time code generation when possible",
  144. "Always disable link-time code generation", nullptr };
  145. const var wpoValues[] = { var(), var (1) };
  146. props.add (new ChoicePropertyComponent (getWholeProgramOptValue(), "Whole Program Optimisation",
  147. StringArray (wpoNames), Array<var> (wpoValues, numElementsInArray (wpoValues))));
  148. }
  149. if (! isDebug())
  150. props.add (new BooleanPropertyComponent (shouldGenerateDebugSymbolsValue(), "Debug Symbols", "Force generation of debug symbols"));
  151. props.add (new TextPropertyComponent (getPrebuildCommand(), "Pre-build Command", 2048, false));
  152. props.add (new TextPropertyComponent (getPostbuildCommand(), "Post-build Command", 2048, false));
  153. props.add (new BooleanPropertyComponent (shouldGenerateManifestValue(), "Manifest", "Generate Manifest"));
  154. {
  155. const char* const characterSetNames[] = { "Default", "MultiByte", "Unicode", nullptr };
  156. const var charSets[] = { var::null, "MultiByte", "Unicode", };
  157. props.add (new ChoicePropertyComponent (getCharacterSetValue(), "Character Set",
  158. StringArray (characterSetNames), Array<var> (charSets, numElementsInArray (charSets))));
  159. }
  160. }
  161. };
  162. BuildConfiguration::Ptr createBuildConfig (const ValueTree& v) const
  163. {
  164. return new MSVCBuildConfiguration (project, v);
  165. }
  166. static int getWarningLevel (const BuildConfiguration& config)
  167. {
  168. return dynamic_cast <const MSVCBuildConfiguration&> (config).getWarningLevel();
  169. }
  170. //==============================================================================
  171. String getConfigTargetPath (const BuildConfiguration& config) const
  172. {
  173. const String binaryPath (config.getTargetBinaryRelativePathString().trim());
  174. if (binaryPath.isEmpty())
  175. return prependDot (File::createLegalFileName (config.getName().trim()));
  176. RelativePath binaryRelPath (binaryPath, RelativePath::projectFolder);
  177. if (binaryRelPath.isAbsolute())
  178. return binaryRelPath.toWindowsStyle();
  179. return prependDot (binaryRelPath.rebased (projectFolder, getTargetFolder(), RelativePath::buildTargetFolder)
  180. .toWindowsStyle());
  181. }
  182. String getPreprocessorDefs (const BuildConfiguration& config, const String& joinString) const
  183. {
  184. StringPairArray defines (msvcExtraPreprocessorDefs);
  185. defines.set ("WIN32", "");
  186. defines.set ("_WINDOWS", "");
  187. if (config.isDebug())
  188. {
  189. defines.set ("DEBUG", "");
  190. defines.set ("_DEBUG", "");
  191. }
  192. else
  193. {
  194. defines.set ("NDEBUG", "");
  195. }
  196. defines = mergePreprocessorDefs (defines, getAllPreprocessorDefs (config));
  197. StringArray result;
  198. for (int i = 0; i < defines.size(); ++i)
  199. {
  200. String def (defines.getAllKeys()[i]);
  201. const String value (defines.getAllValues()[i]);
  202. if (value.isNotEmpty())
  203. def << "=" << value;
  204. result.add (def);
  205. }
  206. return result.joinIntoString (joinString);
  207. }
  208. StringArray getHeaderSearchPaths (const BuildConfiguration& config) const
  209. {
  210. StringArray searchPaths (extraSearchPaths);
  211. searchPaths.addArray (config.getHeaderSearchPaths());
  212. searchPaths.removeDuplicates (false);
  213. return searchPaths;
  214. }
  215. virtual String createConfigName (const BuildConfiguration& config) const
  216. {
  217. return config.getName() + "|Win32";
  218. }
  219. //==============================================================================
  220. void writeSolutionFile (OutputStream& out, const String& versionString, String commentString, const File& vcProject) const
  221. {
  222. if (commentString.isNotEmpty())
  223. commentString += newLine;
  224. out << "Microsoft Visual Studio Solution File, Format Version " << versionString << newLine
  225. << commentString
  226. << "Project(\"" << createGUID (projectName + "sln_guid") << "\") = \"" << projectName << "\", \""
  227. << vcProject.getFileName() << "\", \"" << projectGUID << '"' << newLine
  228. << "EndProject" << newLine
  229. << "Global" << newLine
  230. << "\tGlobalSection(SolutionConfigurationPlatforms) = preSolution" << newLine;
  231. for (ConstConfigIterator i (*this); i.next();)
  232. {
  233. const String configName (createConfigName (*i));
  234. out << "\t\t" << configName << " = " << configName << newLine;
  235. }
  236. out << "\tEndGlobalSection" << newLine
  237. << "\tGlobalSection(ProjectConfigurationPlatforms) = postSolution" << newLine;
  238. for (ConstConfigIterator i (*this); i.next();)
  239. {
  240. const String configName (createConfigName (*i));
  241. out << "\t\t" << projectGUID << "." << configName << ".ActiveCfg = " << configName << newLine;
  242. out << "\t\t" << projectGUID << "." << configName << ".Build.0 = " << configName << newLine;
  243. }
  244. out << "\tEndGlobalSection" << newLine
  245. << "\tGlobalSection(SolutionProperties) = preSolution" << newLine
  246. << "\t\tHideSolutionNode = FALSE" << newLine
  247. << "\tEndGlobalSection" << newLine
  248. << "EndGlobal" << newLine;
  249. }
  250. //==============================================================================
  251. static void writeBMPImage (const Image& image, const int w, const int h, MemoryOutputStream& out)
  252. {
  253. const int maskStride = (w / 8 + 3) & ~3;
  254. out.writeInt (40); // bitmapinfoheader size
  255. out.writeInt (w);
  256. out.writeInt (h * 2);
  257. out.writeShort (1); // planes
  258. out.writeShort (32); // bits
  259. out.writeInt (0); // compression
  260. out.writeInt ((h * w * 4) + (h * maskStride)); // size image
  261. out.writeInt (0); // x pixels per meter
  262. out.writeInt (0); // y pixels per meter
  263. out.writeInt (0); // clr used
  264. out.writeInt (0); // clr important
  265. const Image::BitmapData bitmap (image, Image::BitmapData::readOnly);
  266. const int alphaThreshold = 5;
  267. int y;
  268. for (y = h; --y >= 0;)
  269. {
  270. for (int x = 0; x < w; ++x)
  271. {
  272. const Colour pixel (bitmap.getPixelColour (x, y));
  273. if (pixel.getAlpha() <= alphaThreshold)
  274. {
  275. out.writeInt (0);
  276. }
  277. else
  278. {
  279. out.writeByte ((char) pixel.getBlue());
  280. out.writeByte ((char) pixel.getGreen());
  281. out.writeByte ((char) pixel.getRed());
  282. out.writeByte ((char) pixel.getAlpha());
  283. }
  284. }
  285. }
  286. for (y = h; --y >= 0;)
  287. {
  288. int mask = 0, count = 0;
  289. for (int x = 0; x < w; ++x)
  290. {
  291. const Colour pixel (bitmap.getPixelColour (x, y));
  292. mask <<= 1;
  293. if (pixel.getAlpha() <= alphaThreshold)
  294. mask |= 1;
  295. if (++count == 8)
  296. {
  297. out.writeByte ((char) mask);
  298. count = 0;
  299. mask = 0;
  300. }
  301. }
  302. if (mask != 0)
  303. out.writeByte ((char) mask);
  304. for (int i = maskStride - w / 8; --i >= 0;)
  305. out.writeByte (0);
  306. }
  307. }
  308. static void writeIconFile (const Array<Image>& images, MemoryOutputStream& out)
  309. {
  310. out.writeShort (0); // reserved
  311. out.writeShort (1); // .ico tag
  312. out.writeShort ((short) images.size());
  313. MemoryOutputStream dataBlock;
  314. const int imageDirEntrySize = 16;
  315. const int dataBlockStart = 6 + images.size() * imageDirEntrySize;
  316. for (int i = 0; i < images.size(); ++i)
  317. {
  318. const size_t oldDataSize = dataBlock.getDataSize();
  319. const Image& image = images.getReference (i);
  320. const int w = image.getWidth();
  321. const int h = image.getHeight();
  322. if (w >= 256 || h >= 256)
  323. {
  324. PNGImageFormat pngFormat;
  325. pngFormat.writeImageToStream (image, dataBlock);
  326. }
  327. else
  328. {
  329. writeBMPImage (image, w, h, dataBlock);
  330. }
  331. out.writeByte ((char) w);
  332. out.writeByte ((char) h);
  333. out.writeByte (0);
  334. out.writeByte (0);
  335. out.writeShort (1); // colour planes
  336. out.writeShort (32); // bits per pixel
  337. out.writeInt ((int) (dataBlock.getDataSize() - oldDataSize));
  338. out.writeInt (dataBlockStart + oldDataSize);
  339. }
  340. jassert (out.getPosition() == dataBlockStart);
  341. out << dataBlock;
  342. }
  343. bool hasResourceFile() const
  344. {
  345. return ! projectType.isStaticLibrary();
  346. }
  347. void createResourcesAndIcon() const
  348. {
  349. if (hasResourceFile())
  350. {
  351. Array<Image> images;
  352. const int sizes[] = { 16, 32, 48, 256 };
  353. for (int i = 0; i < numElementsInArray (sizes); ++i)
  354. {
  355. Image im (getBestIconForSize (sizes[i], true));
  356. if (im.isValid())
  357. images.add (im);
  358. }
  359. if (images.size() > 0)
  360. {
  361. iconFile = getTargetFolder().getChildFile ("icon.ico");
  362. MemoryOutputStream mo;
  363. writeIconFile (images, mo);
  364. overwriteFileIfDifferentOrThrow (iconFile, mo);
  365. }
  366. createRCFile();
  367. }
  368. }
  369. void createRCFile() const
  370. {
  371. rcFile = getTargetFolder().getChildFile ("resources.rc");
  372. const String version (project.getVersionString());
  373. MemoryOutputStream mo;
  374. mo << "#ifdef JUCE_USER_DEFINED_RC_FILE" << newLine
  375. << " #include JUCE_USER_DEFINED_RC_FILE" << newLine
  376. << "#else" << newLine
  377. << newLine
  378. << "#undef WIN32_LEAN_AND_MEAN" << newLine
  379. << "#define WIN32_LEAN_AND_MEAN" << newLine
  380. << "#include <windows.h>" << newLine
  381. << newLine
  382. << "VS_VERSION_INFO VERSIONINFO" << newLine
  383. << "FILEVERSION " << getCommaSeparatedVersionNumber (version) << newLine
  384. << "BEGIN" << newLine
  385. << " BLOCK \"StringFileInfo\"" << newLine
  386. << " BEGIN" << newLine
  387. << " BLOCK \"040904E4\"" << newLine
  388. << " BEGIN" << newLine;
  389. writeRCValue (mo, "CompanyName", project.getCompanyName().toString());
  390. writeRCValue (mo, "FileDescription", project.getTitle());
  391. writeRCValue (mo, "FileVersion", version);
  392. writeRCValue (mo, "ProductName", project.getTitle());
  393. writeRCValue (mo, "ProductVersion", version);
  394. mo << " END" << newLine
  395. << " END" << newLine
  396. << newLine
  397. << " BLOCK \"VarFileInfo\"" << newLine
  398. << " BEGIN" << newLine
  399. << " VALUE \"Translation\", 0x409, 65001" << newLine
  400. << " END" << newLine
  401. << "END" << newLine
  402. << newLine
  403. << "#endif" << newLine;
  404. if (iconFile != File::nonexistent)
  405. mo << newLine
  406. << "IDI_ICON1 ICON DISCARDABLE " << iconFile.getFileName().quoted()
  407. << newLine
  408. << "IDI_ICON2 ICON DISCARDABLE " << iconFile.getFileName().quoted();
  409. overwriteFileIfDifferentOrThrow (rcFile, mo);
  410. }
  411. static void writeRCValue (MemoryOutputStream& mo, const String& name, const String& value)
  412. {
  413. if (value.isNotEmpty())
  414. mo << " VALUE \"" << name << "\", \""
  415. << CodeHelpers::addEscapeChars (value) << "\\0\"" << newLine;
  416. }
  417. static String getCommaSeparatedVersionNumber (const String& version)
  418. {
  419. StringArray versionParts;
  420. versionParts.addTokens (version, ",.", "");
  421. versionParts.trim();
  422. versionParts.removeEmptyStrings();
  423. while (versionParts.size() < 4)
  424. versionParts.add ("0");
  425. return versionParts.joinIntoString (",");
  426. }
  427. static String prependDot (const String& filename)
  428. {
  429. return FileHelpers::isAbsolutePath (filename) ? filename
  430. : (".\\" + filename);
  431. }
  432. JUCE_DECLARE_NON_COPYABLE (MSVCProjectExporterBase)
  433. };
  434. //==============================================================================
  435. class MSVCProjectExporterVC2008 : public MSVCProjectExporterBase
  436. {
  437. public:
  438. //==============================================================================
  439. MSVCProjectExporterVC2008 (Project& project_, const ValueTree& settings_,
  440. const char* folderName = "VisualStudio2008")
  441. : MSVCProjectExporterBase (project_, settings_, folderName)
  442. {
  443. name = getName();
  444. }
  445. static const char* getName() { return "Visual Studio 2008"; }
  446. static const char* getValueTreeTypeName() { return "VS2008"; }
  447. int getVisualStudioVersion() const { return 9; }
  448. static MSVCProjectExporterVC2008* createForSettings (Project& project, const ValueTree& settings)
  449. {
  450. if (settings.hasType (getValueTreeTypeName()))
  451. return new MSVCProjectExporterVC2008 (project, settings);
  452. return nullptr;
  453. }
  454. //==============================================================================
  455. void create (const OwnedArray<LibraryModule>&) const
  456. {
  457. createResourcesAndIcon();
  458. if (hasResourceFile())
  459. {
  460. for (int i = 0; i < getAllGroups().size(); ++i)
  461. {
  462. Project::Item& group = getAllGroups().getReference(i);
  463. if (group.getID() == ProjectSaver::getGeneratedGroupID())
  464. {
  465. if (iconFile != File::nonexistent)
  466. {
  467. group.addFile (iconFile, -1, true);
  468. group.findItemForFile (iconFile).getShouldAddToResourceValue() = false;
  469. }
  470. group.addFile (rcFile, -1, true);
  471. group.findItemForFile (rcFile).getShouldAddToResourceValue() = false;
  472. break;
  473. }
  474. }
  475. }
  476. {
  477. XmlElement projectXml ("VisualStudioProject");
  478. fillInProjectXml (projectXml);
  479. writeXmlOrThrow (projectXml, getVCProjFile(), "UTF-8", 10);
  480. }
  481. {
  482. MemoryOutputStream mo;
  483. writeSolutionFile (mo, getSolutionVersionString(), String::empty, getVCProjFile());
  484. overwriteFileIfDifferentOrThrow (getSLNFile(), mo);
  485. }
  486. }
  487. protected:
  488. virtual String getProjectVersionString() const { return "9.00"; }
  489. virtual String getSolutionVersionString() const { return "10.00" + newLine + "# Visual C++ Express 2008"; }
  490. File getVCProjFile() const { return getProjectFile (".vcproj"); }
  491. //==============================================================================
  492. void fillInProjectXml (XmlElement& projectXml) const
  493. {
  494. projectXml.setAttribute ("ProjectType", "Visual C++");
  495. projectXml.setAttribute ("Version", getProjectVersionString());
  496. projectXml.setAttribute ("Name", projectName);
  497. projectXml.setAttribute ("ProjectGUID", projectGUID);
  498. projectXml.setAttribute ("TargetFrameworkVersion", "131072");
  499. {
  500. XmlElement* platforms = projectXml.createNewChildElement ("Platforms");
  501. XmlElement* platform = platforms->createNewChildElement ("Platform");
  502. platform->setAttribute ("Name", "Win32");
  503. }
  504. projectXml.createNewChildElement ("ToolFiles");
  505. createConfigs (*projectXml.createNewChildElement ("Configurations"));
  506. projectXml.createNewChildElement ("References");
  507. createFiles (*projectXml.createNewChildElement ("Files"));
  508. projectXml.createNewChildElement ("Globals");
  509. }
  510. //==============================================================================
  511. void addFile (const RelativePath& file, XmlElement& parent, const bool excludeFromBuild, const bool useStdcall) const
  512. {
  513. jassert (file.getRoot() == RelativePath::buildTargetFolder);
  514. XmlElement* fileXml = parent.createNewChildElement ("File");
  515. fileXml->setAttribute ("RelativePath", file.toWindowsStyle());
  516. if (excludeFromBuild || useStdcall)
  517. {
  518. for (ConstConfigIterator i (*this); i.next();)
  519. {
  520. XmlElement* fileConfig = fileXml->createNewChildElement ("FileConfiguration");
  521. fileConfig->setAttribute ("Name", createConfigName (*i));
  522. if (excludeFromBuild)
  523. fileConfig->setAttribute ("ExcludedFromBuild", "true");
  524. XmlElement* tool = createToolElement (*fileConfig, "VCCLCompilerTool");
  525. if (useStdcall)
  526. tool->setAttribute ("CallingConvention", "2");
  527. }
  528. }
  529. }
  530. XmlElement* createGroup (const String& groupName, XmlElement& parent) const
  531. {
  532. XmlElement* filter = parent.createNewChildElement ("Filter");
  533. filter->setAttribute ("Name", groupName);
  534. return filter;
  535. }
  536. void addFiles (const Project::Item& projectItem, XmlElement& parent) const
  537. {
  538. if (projectItem.isGroup())
  539. {
  540. XmlElement* filter = createGroup (projectItem.getName(), parent);
  541. for (int i = 0; i < projectItem.getNumChildren(); ++i)
  542. addFiles (projectItem.getChild(i), *filter);
  543. }
  544. else if (projectItem.shouldBeAddedToTargetProject())
  545. {
  546. const RelativePath path (projectItem.getFile(), getTargetFolder(), RelativePath::buildTargetFolder);
  547. addFile (path, parent,
  548. projectItem.shouldBeAddedToBinaryResources()
  549. || (shouldFileBeCompiledByDefault (path) && ! projectItem.shouldBeCompiled()),
  550. shouldFileBeCompiledByDefault (path) && (bool) projectItem.shouldUseStdCall());
  551. }
  552. }
  553. void createFiles (XmlElement& files) const
  554. {
  555. for (int i = 0; i < getAllGroups().size(); ++i)
  556. {
  557. const Project::Item& group = getAllGroups().getReference(i);
  558. if (group.getNumChildren() > 0)
  559. addFiles (group, files);
  560. }
  561. }
  562. //==============================================================================
  563. XmlElement* createToolElement (XmlElement& parent, const String& toolName) const
  564. {
  565. XmlElement* const e = parent.createNewChildElement ("Tool");
  566. e->setAttribute ("Name", toolName);
  567. return e;
  568. }
  569. void createConfig (XmlElement& xml, const MSVCBuildConfiguration& config) const
  570. {
  571. const bool isDebug = config.isDebug();
  572. xml.setAttribute ("Name", createConfigName (config));
  573. xml.setAttribute ("OutputDirectory", FileHelpers::windowsStylePath (getConfigTargetPath (config)));
  574. if (config.getIntermediatesPath().isNotEmpty())
  575. xml.setAttribute ("IntermediateDirectory", FileHelpers::windowsStylePath (config.getIntermediatesPath()));
  576. xml.setAttribute ("ConfigurationType", isLibraryDLL() ? "2" : (projectType.isStaticLibrary() ? "4" : "1"));
  577. xml.setAttribute ("UseOfMFC", "0");
  578. xml.setAttribute ("ATLMinimizesCRunTimeLibraryUsage", "false");
  579. xml.setAttribute ("CharacterSet", "2");
  580. if (! (isDebug || config.shouldDisableWholeProgramOpt()))
  581. xml.setAttribute ("WholeProgramOptimization", "1");
  582. XmlElement* preBuildEvent = createToolElement (xml, "VCPreBuildEventTool");
  583. if (config.getPrebuildCommandString().isNotEmpty())
  584. {
  585. preBuildEvent->setAttribute ("Description", "Pre-build");
  586. preBuildEvent->setAttribute ("CommandLine", config.getPrebuildCommandString());
  587. }
  588. createToolElement (xml, "VCCustomBuildTool");
  589. createToolElement (xml, "VCXMLDataGeneratorTool");
  590. createToolElement (xml, "VCWebServiceProxyGeneratorTool");
  591. if (! projectType.isStaticLibrary())
  592. {
  593. XmlElement* midl = createToolElement (xml, "VCMIDLTool");
  594. midl->setAttribute ("PreprocessorDefinitions", isDebug ? "_DEBUG" : "NDEBUG");
  595. midl->setAttribute ("MkTypLibCompatible", "true");
  596. midl->setAttribute ("SuppressStartupBanner", "true");
  597. midl->setAttribute ("TargetEnvironment", "1");
  598. midl->setAttribute ("TypeLibraryName", getIntDirFile (config.getOutputFilename (".tlb", true)));
  599. midl->setAttribute ("HeaderFileName", "");
  600. }
  601. {
  602. XmlElement* compiler = createToolElement (xml, "VCCLCompilerTool");
  603. compiler->setAttribute ("Optimization", getOptimisationLevelString (config.getOptimisationLevelInt()));
  604. if (isDebug)
  605. {
  606. compiler->setAttribute ("BufferSecurityCheck", "");
  607. compiler->setAttribute ("DebugInformationFormat", projectType.isStaticLibrary() ? "3" : "4");
  608. }
  609. else
  610. {
  611. compiler->setAttribute ("InlineFunctionExpansion", "1");
  612. compiler->setAttribute ("StringPooling", "true");
  613. }
  614. compiler->setAttribute ("AdditionalIncludeDirectories", replacePreprocessorTokens (config, getHeaderSearchPaths (config).joinIntoString (";")));
  615. compiler->setAttribute ("PreprocessorDefinitions", getPreprocessorDefs (config, ";"));
  616. compiler->setAttribute ("RuntimeLibrary", config.isUsingRuntimeLibDLL() ? (isDebug ? 3 : 2) // MT DLL
  617. : (isDebug ? 1 : 0)); // MT static
  618. compiler->setAttribute ("RuntimeTypeInfo", "true");
  619. compiler->setAttribute ("UsePrecompiledHeader", "0");
  620. compiler->setAttribute ("PrecompiledHeaderFile", getIntDirFile (config.getOutputFilename (".pch", true)));
  621. compiler->setAttribute ("AssemblerListingLocation", "$(IntDir)\\");
  622. compiler->setAttribute ("ObjectFile", "$(IntDir)\\");
  623. compiler->setAttribute ("ProgramDataBaseFileName", "$(IntDir)\\");
  624. compiler->setAttribute ("WarningLevel", String (getWarningLevel (config)));
  625. compiler->setAttribute ("SuppressStartupBanner", "true");
  626. const String extraFlags (replacePreprocessorTokens (config, getExtraCompilerFlagsString()).trim());
  627. if (extraFlags.isNotEmpty())
  628. compiler->setAttribute ("AdditionalOptions", extraFlags);
  629. }
  630. createToolElement (xml, "VCManagedResourceCompilerTool");
  631. {
  632. XmlElement* resCompiler = createToolElement (xml, "VCResourceCompilerTool");
  633. resCompiler->setAttribute ("PreprocessorDefinitions", isDebug ? "_DEBUG" : "NDEBUG");
  634. }
  635. createToolElement (xml, "VCPreLinkEventTool");
  636. if (! projectType.isStaticLibrary())
  637. {
  638. XmlElement* linker = createToolElement (xml, "VCLinkerTool");
  639. linker->setAttribute ("OutputFile", getOutDirFile (config.getOutputFilename (msvcTargetSuffix, false)));
  640. linker->setAttribute ("SuppressStartupBanner", "true");
  641. linker->setAttribute ("IgnoreDefaultLibraryNames", isDebug ? "libcmt.lib, msvcrt.lib" : "");
  642. linker->setAttribute ("GenerateDebugInformation", (isDebug || config.shouldGenerateDebugSymbols()) ? "true" : "false");
  643. linker->setAttribute ("ProgramDatabaseFile", getIntDirFile (config.getOutputFilename (".pdb", true)));
  644. linker->setAttribute ("SubSystem", msvcIsWindowsSubsystem ? "2" : "1");
  645. const StringArray librarySearchPaths (config.getLibrarySearchPaths());
  646. if (librarySearchPaths.size() > 0)
  647. linker->setAttribute ("AdditionalLibraryDirectories", librarySearchPaths.joinIntoString (";"));
  648. linker->setAttribute ("GenerateManifest", config.shouldGenerateManifest() ? "true" : "false");
  649. if (! isDebug)
  650. {
  651. linker->setAttribute ("OptimizeReferences", "2");
  652. linker->setAttribute ("EnableCOMDATFolding", "2");
  653. }
  654. linker->setAttribute ("TargetMachine", "1"); // (64-bit build = 5)
  655. if (msvcDelayLoadedDLLs.isNotEmpty())
  656. linker->setAttribute ("DelayLoadDLLs", msvcDelayLoadedDLLs);
  657. if (config.config [Ids::msvcModuleDefinitionFile].toString().isNotEmpty())
  658. linker->setAttribute ("ModuleDefinitionFile", config.config [Ids::msvcModuleDefinitionFile].toString());
  659. String externalLibraries (getExternalLibrariesString());
  660. if (externalLibraries.isNotEmpty())
  661. linker->setAttribute ("AdditionalDependencies", replacePreprocessorTokens (config, externalLibraries).trim());
  662. String extraLinkerOptions (getExtraLinkerFlagsString());
  663. if (extraLinkerOptions.isNotEmpty())
  664. linker->setAttribute ("AdditionalOptions", replacePreprocessorTokens (config, extraLinkerOptions).trim());
  665. }
  666. else
  667. {
  668. if (isLibraryDLL())
  669. {
  670. XmlElement* linker = createToolElement (xml, "VCLinkerTool");
  671. String extraLinkerOptions (getExtraLinkerFlagsString());
  672. extraLinkerOptions << " /IMPLIB:" << getOutDirFile (config.getOutputFilename (".lib", true));
  673. linker->setAttribute ("AdditionalOptions", replacePreprocessorTokens (config, extraLinkerOptions).trim());
  674. String externalLibraries (getExternalLibrariesString());
  675. if (externalLibraries.isNotEmpty())
  676. linker->setAttribute ("AdditionalDependencies", replacePreprocessorTokens (config, externalLibraries).trim());
  677. linker->setAttribute ("OutputFile", getOutDirFile (config.getOutputFilename (msvcTargetSuffix, false)));
  678. linker->setAttribute ("IgnoreDefaultLibraryNames", isDebug ? "libcmt.lib, msvcrt.lib" : "");
  679. }
  680. else
  681. {
  682. XmlElement* librarian = createToolElement (xml, "VCLibrarianTool");
  683. librarian->setAttribute ("OutputFile", getOutDirFile (config.getOutputFilename (msvcTargetSuffix, false)));
  684. librarian->setAttribute ("IgnoreDefaultLibraryNames", isDebug ? "libcmt.lib, msvcrt.lib" : "");
  685. }
  686. }
  687. createToolElement (xml, "VCALinkTool");
  688. createToolElement (xml, "VCManifestTool");
  689. createToolElement (xml, "VCXDCMakeTool");
  690. {
  691. XmlElement* bscMake = createToolElement (xml, "VCBscMakeTool");
  692. bscMake->setAttribute ("SuppressStartupBanner", "true");
  693. bscMake->setAttribute ("OutputFile", getIntDirFile (config.getOutputFilename (".bsc", true)));
  694. }
  695. createToolElement (xml, "VCFxCopTool");
  696. if (! projectType.isStaticLibrary())
  697. createToolElement (xml, "VCAppVerifierTool");
  698. XmlElement* postBuildEvent = createToolElement (xml, "VCPostBuildEventTool");
  699. if (config.getPostbuildCommandString().isNotEmpty())
  700. {
  701. postBuildEvent->setAttribute ("Description", "Post-build");
  702. postBuildEvent->setAttribute ("CommandLine", config.getPostbuildCommandString());
  703. }
  704. }
  705. void createConfigs (XmlElement& xml) const
  706. {
  707. for (ConstConfigIterator config (*this); config.next();)
  708. createConfig (*xml.createNewChildElement ("Configuration"),
  709. dynamic_cast <const MSVCBuildConfiguration&> (*config));
  710. }
  711. static const char* getOptimisationLevelString (int level)
  712. {
  713. switch (level)
  714. {
  715. case optimiseMaxSpeed: return "3";
  716. case optimiseMinSize: return "1";
  717. default: return "0";
  718. }
  719. }
  720. //==============================================================================
  721. JUCE_DECLARE_NON_COPYABLE (MSVCProjectExporterVC2008)
  722. };
  723. //==============================================================================
  724. class MSVCProjectExporterVC2005 : public MSVCProjectExporterVC2008
  725. {
  726. public:
  727. MSVCProjectExporterVC2005 (Project& p, const ValueTree& t)
  728. : MSVCProjectExporterVC2008 (p, t, "VisualStudio2005")
  729. {
  730. name = getName();
  731. }
  732. static const char* getName() { return "Visual Studio 2005"; }
  733. static const char* getValueTreeTypeName() { return "VS2005"; }
  734. int getVisualStudioVersion() const { return 8; }
  735. static MSVCProjectExporterVC2005* createForSettings (Project& project, const ValueTree& settings)
  736. {
  737. if (settings.hasType (getValueTreeTypeName()))
  738. return new MSVCProjectExporterVC2005 (project, settings);
  739. return nullptr;
  740. }
  741. protected:
  742. String getProjectVersionString() const { return "8.00"; }
  743. String getSolutionVersionString() const { return "9.00" + newLine + "# Visual C++ Express 2005"; }
  744. JUCE_DECLARE_NON_COPYABLE (MSVCProjectExporterVC2005)
  745. };
  746. //==============================================================================
  747. class MSVCProjectExporterVC2010 : public MSVCProjectExporterBase
  748. {
  749. public:
  750. MSVCProjectExporterVC2010 (Project& p, const ValueTree& t, const char* folderName = "VisualStudio2010")
  751. : MSVCProjectExporterBase (p, t, folderName)
  752. {
  753. name = getName();
  754. }
  755. static const char* getName() { return "Visual Studio 2010"; }
  756. static const char* getValueTreeTypeName() { return "VS2010"; }
  757. int getVisualStudioVersion() const { return 10; }
  758. virtual String getPlatformToolset() const { return "Windows7.1SDK"; }
  759. virtual String getSolutionComment() const { return "# Visual Studio 2010"; }
  760. static MSVCProjectExporterVC2010* createForSettings (Project& project, const ValueTree& settings)
  761. {
  762. if (settings.hasType (getValueTreeTypeName()))
  763. return new MSVCProjectExporterVC2010 (project, settings);
  764. return nullptr;
  765. }
  766. //==============================================================================
  767. void create (const OwnedArray<LibraryModule>&) const
  768. {
  769. createResourcesAndIcon();
  770. {
  771. XmlElement projectXml ("Project");
  772. fillInProjectXml (projectXml);
  773. addPlatformToolsetToPropertyGroup (projectXml);
  774. writeXmlOrThrow (projectXml, getVCProjFile(), "utf-8", 100);
  775. }
  776. {
  777. XmlElement filtersXml ("Project");
  778. fillInFiltersXml (filtersXml);
  779. writeXmlOrThrow (filtersXml, getVCProjFiltersFile(), "utf-8", 100);
  780. }
  781. {
  782. MemoryOutputStream mo;
  783. writeSolutionFile (mo, "11.00", getSolutionComment(), getVCProjFile());
  784. overwriteFileIfDifferentOrThrow (getSLNFile(), mo);
  785. }
  786. }
  787. protected:
  788. //==============================================================================
  789. class VC2010BuildConfiguration : public MSVCBuildConfiguration
  790. {
  791. public:
  792. VC2010BuildConfiguration (Project& p, const ValueTree& settings)
  793. : MSVCBuildConfiguration (p, settings)
  794. {
  795. if (getArchitectureType().toString().isEmpty())
  796. getArchitectureType() = get32BitArchName();
  797. }
  798. //==============================================================================
  799. static const char* get32BitArchName() { return "32-bit"; }
  800. static const char* get64BitArchName() { return "x64"; }
  801. Value getArchitectureType() { return getValue (Ids::winArchitecture); }
  802. bool is64Bit() const { return config [Ids::winArchitecture].toString() == get64BitArchName(); }
  803. //==============================================================================
  804. void createConfigProperties (PropertyListBuilder& props)
  805. {
  806. MSVCBuildConfiguration::createConfigProperties (props);
  807. const char* const archTypes[] = { get32BitArchName(), get64BitArchName() };
  808. props.add (new ChoicePropertyComponent (getArchitectureType(), "Architecture",
  809. StringArray (archTypes, numElementsInArray (archTypes)),
  810. Array<var> (archTypes, numElementsInArray (archTypes))));
  811. }
  812. };
  813. virtual void addPlatformToolsetToPropertyGroup (XmlElement&) const {}
  814. BuildConfiguration::Ptr createBuildConfig (const ValueTree& v) const
  815. {
  816. return new VC2010BuildConfiguration (project, v);
  817. }
  818. static bool is64Bit (const BuildConfiguration& config)
  819. {
  820. return dynamic_cast <const VC2010BuildConfiguration&> (config).is64Bit();
  821. }
  822. //==============================================================================
  823. File getVCProjFile() const { return getProjectFile (".vcxproj"); }
  824. File getVCProjFiltersFile() const { return getProjectFile (".vcxproj.filters"); }
  825. String createConfigName (const BuildConfiguration& config) const
  826. {
  827. return config.getName() + (is64Bit (config) ? "|x64"
  828. : "|Win32");
  829. }
  830. void setConditionAttribute (XmlElement& xml, const BuildConfiguration& config) const
  831. {
  832. xml.setAttribute ("Condition", "'$(Configuration)|$(Platform)'=='" + createConfigName (config) + "'");
  833. }
  834. //==============================================================================
  835. void fillInProjectXml (XmlElement& projectXml) const
  836. {
  837. projectXml.setAttribute ("DefaultTargets", "Build");
  838. projectXml.setAttribute ("ToolsVersion", "4.0");
  839. projectXml.setAttribute ("xmlns", "http://schemas.microsoft.com/developer/msbuild/2003");
  840. {
  841. XmlElement* configsGroup = projectXml.createNewChildElement ("ItemGroup");
  842. configsGroup->setAttribute ("Label", "ProjectConfigurations");
  843. for (ConstConfigIterator config (*this); config.next();)
  844. {
  845. XmlElement* e = configsGroup->createNewChildElement ("ProjectConfiguration");
  846. e->setAttribute ("Include", createConfigName (*config));
  847. e->createNewChildElement ("Configuration")->addTextElement (config->getName());
  848. e->createNewChildElement ("Platform")->addTextElement (is64Bit (*config) ? "x64" : "Win32");
  849. }
  850. }
  851. {
  852. XmlElement* globals = projectXml.createNewChildElement ("PropertyGroup");
  853. globals->setAttribute ("Label", "Globals");
  854. globals->createNewChildElement ("ProjectGuid")->addTextElement (projectGUID);
  855. }
  856. {
  857. XmlElement* imports = projectXml.createNewChildElement ("Import");
  858. imports->setAttribute ("Project", "$(VCTargetsPath)\\Microsoft.Cpp.Default.props");
  859. }
  860. for (ConstConfigIterator i (*this); i.next();)
  861. {
  862. const MSVCBuildConfiguration& config = dynamic_cast <const MSVCBuildConfiguration&> (*i);
  863. XmlElement* e = projectXml.createNewChildElement ("PropertyGroup");
  864. setConditionAttribute (*e, config);
  865. e->setAttribute ("Label", "Configuration");
  866. e->createNewChildElement ("ConfigurationType")->addTextElement (getProjectType());
  867. e->createNewChildElement ("UseOfMfc")->addTextElement ("false");
  868. e->createNewChildElement ("CharacterSet")->addTextElement (config.getCharacterSet());
  869. if (! (config.isDebug() || config.shouldDisableWholeProgramOpt()))
  870. e->createNewChildElement ("WholeProgramOptimization")->addTextElement ("true");
  871. if (is64Bit (config))
  872. e->createNewChildElement ("PlatformToolset")->addTextElement (getPlatformToolset());
  873. }
  874. {
  875. XmlElement* e = projectXml.createNewChildElement ("Import");
  876. e->setAttribute ("Project", "$(VCTargetsPath)\\Microsoft.Cpp.props");
  877. }
  878. {
  879. XmlElement* e = projectXml.createNewChildElement ("ImportGroup");
  880. e->setAttribute ("Label", "ExtensionSettings");
  881. }
  882. {
  883. XmlElement* e = projectXml.createNewChildElement ("ImportGroup");
  884. e->setAttribute ("Label", "PropertySheets");
  885. XmlElement* p = e->createNewChildElement ("Import");
  886. p->setAttribute ("Project", "$(UserRootDir)\\Microsoft.Cpp.$(Platform).user.props");
  887. p->setAttribute ("Condition", "exists('$(UserRootDir)\\Microsoft.Cpp.$(Platform).user.props')");
  888. p->setAttribute ("Label", "LocalAppDataPlatform");
  889. }
  890. {
  891. XmlElement* e = projectXml.createNewChildElement ("PropertyGroup");
  892. e->setAttribute ("Label", "UserMacros");
  893. }
  894. {
  895. XmlElement* props = projectXml.createNewChildElement ("PropertyGroup");
  896. props->createNewChildElement ("_ProjectFileVersion")->addTextElement ("10.0.30319.1");
  897. for (ConstConfigIterator i (*this); i.next();)
  898. {
  899. const MSVCBuildConfiguration& config = dynamic_cast <const MSVCBuildConfiguration&> (*i);
  900. {
  901. XmlElement* outdir = props->createNewChildElement ("OutDir");
  902. setConditionAttribute (*outdir, config);
  903. outdir->addTextElement (FileHelpers::windowsStylePath (getConfigTargetPath (config)) + "\\");
  904. }
  905. if (config.getIntermediatesPath().isNotEmpty())
  906. {
  907. XmlElement* intdir = props->createNewChildElement ("IntDir");
  908. setConditionAttribute (*intdir, config);
  909. intdir->addTextElement (FileHelpers::windowsStylePath (config.getIntermediatesPath()) + "\\");
  910. }
  911. {
  912. XmlElement* targetName = props->createNewChildElement ("TargetName");
  913. setConditionAttribute (*targetName, config);
  914. targetName->addTextElement (config.getOutputFilename (String::empty, true));
  915. }
  916. {
  917. XmlElement* manifest = props->createNewChildElement ("GenerateManifest");
  918. setConditionAttribute (*manifest, config);
  919. manifest->addTextElement (config.shouldGenerateManifest() ? "true" : "false");
  920. }
  921. const StringArray librarySearchPaths (config.getLibrarySearchPaths());
  922. if (librarySearchPaths.size() > 0)
  923. {
  924. XmlElement* libPath = props->createNewChildElement ("LibraryPath");
  925. setConditionAttribute (*libPath, config);
  926. libPath->addTextElement ("$(LibraryPath);" + librarySearchPaths.joinIntoString (";"));
  927. }
  928. }
  929. }
  930. for (ConstConfigIterator i (*this); i.next();)
  931. {
  932. const MSVCBuildConfiguration& config = dynamic_cast <const MSVCBuildConfiguration&> (*i);
  933. const bool isDebug = config.isDebug();
  934. XmlElement* group = projectXml.createNewChildElement ("ItemDefinitionGroup");
  935. setConditionAttribute (*group, config);
  936. {
  937. XmlElement* midl = group->createNewChildElement ("Midl");
  938. midl->createNewChildElement ("PreprocessorDefinitions")->addTextElement (isDebug ? "_DEBUG;%(PreprocessorDefinitions)"
  939. : "NDEBUG;%(PreprocessorDefinitions)");
  940. midl->createNewChildElement ("MkTypLibCompatible")->addTextElement ("true");
  941. midl->createNewChildElement ("SuppressStartupBanner")->addTextElement ("true");
  942. midl->createNewChildElement ("TargetEnvironment")->addTextElement ("Win32");
  943. midl->createNewChildElement ("HeaderFileName");
  944. }
  945. bool isUsingEditAndContinue = false;
  946. {
  947. XmlElement* cl = group->createNewChildElement ("ClCompile");
  948. cl->createNewChildElement ("Optimization")->addTextElement (getOptimisationLevelString (config.getOptimisationLevelInt()));
  949. if (isDebug && config.getOptimisationLevelInt() <= optimisationOff)
  950. {
  951. isUsingEditAndContinue = ! is64Bit (config);
  952. cl->createNewChildElement ("DebugInformationFormat")
  953. ->addTextElement (isUsingEditAndContinue ? "EditAndContinue"
  954. : "ProgramDatabase");
  955. }
  956. StringArray includePaths (getHeaderSearchPaths (config));
  957. includePaths.add ("%(AdditionalIncludeDirectories)");
  958. cl->createNewChildElement ("AdditionalIncludeDirectories")->addTextElement (includePaths.joinIntoString (";"));
  959. cl->createNewChildElement ("PreprocessorDefinitions")->addTextElement (getPreprocessorDefs (config, ";") + ";%(PreprocessorDefinitions)");
  960. cl->createNewChildElement ("RuntimeLibrary")->addTextElement (config.isUsingRuntimeLibDLL() ? (isDebug ? "MultiThreadedDebugDLL" : "MultiThreadedDLL")
  961. : (isDebug ? "MultiThreadedDebug" : "MultiThreaded"));
  962. cl->createNewChildElement ("RuntimeTypeInfo")->addTextElement ("true");
  963. cl->createNewChildElement ("PrecompiledHeader");
  964. cl->createNewChildElement ("AssemblerListingLocation")->addTextElement ("$(IntDir)\\");
  965. cl->createNewChildElement ("ObjectFileName")->addTextElement ("$(IntDir)\\");
  966. cl->createNewChildElement ("ProgramDataBaseFileName")->addTextElement ("$(IntDir)\\");
  967. cl->createNewChildElement ("WarningLevel")->addTextElement ("Level" + String (getWarningLevel (config)));
  968. cl->createNewChildElement ("SuppressStartupBanner")->addTextElement ("true");
  969. cl->createNewChildElement ("MultiProcessorCompilation")->addTextElement ("true");
  970. const String extraFlags (replacePreprocessorTokens (config, getExtraCompilerFlagsString()).trim());
  971. if (extraFlags.isNotEmpty())
  972. cl->createNewChildElement ("AdditionalOptions")->addTextElement (extraFlags + " %(AdditionalOptions)");
  973. }
  974. {
  975. XmlElement* res = group->createNewChildElement ("ResourceCompile");
  976. res->createNewChildElement ("PreprocessorDefinitions")->addTextElement (isDebug ? "_DEBUG;%(PreprocessorDefinitions)"
  977. : "NDEBUG;%(PreprocessorDefinitions)");
  978. }
  979. {
  980. XmlElement* link = group->createNewChildElement ("Link");
  981. link->createNewChildElement ("OutputFile")->addTextElement (getOutDirFile (config.getOutputFilename (msvcTargetSuffix, false)));
  982. link->createNewChildElement ("SuppressStartupBanner")->addTextElement ("true");
  983. link->createNewChildElement ("IgnoreSpecificDefaultLibraries")->addTextElement (isDebug ? "libcmt.lib; msvcrt.lib;;%(IgnoreSpecificDefaultLibraries)"
  984. : "%(IgnoreSpecificDefaultLibraries)");
  985. link->createNewChildElement ("GenerateDebugInformation")->addTextElement ((isDebug || config.shouldGenerateDebugSymbols()) ? "true" : "false");
  986. link->createNewChildElement ("ProgramDatabaseFile")->addTextElement (getIntDirFile (config.getOutputFilename (".pdb", true)));
  987. link->createNewChildElement ("SubSystem")->addTextElement (msvcIsWindowsSubsystem ? "Windows" : "Console");
  988. if (! is64Bit (config))
  989. link->createNewChildElement ("TargetMachine")->addTextElement ("MachineX86");
  990. if (isUsingEditAndContinue)
  991. link->createNewChildElement ("ImageHasSafeExceptionHandlers")->addTextElement ("false");
  992. if (! isDebug)
  993. {
  994. link->createNewChildElement ("OptimizeReferences")->addTextElement ("true");
  995. link->createNewChildElement ("EnableCOMDATFolding")->addTextElement ("true");
  996. }
  997. const StringArray librarySearchPaths (config.getLibrarySearchPaths());
  998. if (librarySearchPaths.size() > 0)
  999. link->createNewChildElement ("AdditionalLibraryDirectories")->addTextElement (replacePreprocessorTokens (config, librarySearchPaths.joinIntoString (";"))
  1000. + ";%(AdditionalLibraryDirectories)");
  1001. link->createNewChildElement ("LargeAddressAware")->addTextElement ("true");
  1002. String externalLibraries (getExternalLibrariesString());
  1003. if (externalLibraries.isNotEmpty())
  1004. link->createNewChildElement ("AdditionalDependencies")->addTextElement (replacePreprocessorTokens (config, externalLibraries).trim()
  1005. + ";%(AdditionalDependencies)");
  1006. String extraLinkerOptions (getExtraLinkerFlagsString());
  1007. if (extraLinkerOptions.isNotEmpty())
  1008. link->createNewChildElement ("AdditionalOptions")->addTextElement (replacePreprocessorTokens (config, extraLinkerOptions).trim()
  1009. + " %(AdditionalOptions)");
  1010. if (msvcDelayLoadedDLLs.isNotEmpty())
  1011. link->createNewChildElement ("DelayLoadDLLs")->addTextElement (msvcDelayLoadedDLLs);
  1012. if (config.config [Ids::msvcModuleDefinitionFile].toString().isNotEmpty())
  1013. link->createNewChildElement ("ModuleDefinitionFile")
  1014. ->addTextElement (config.config [Ids::msvcModuleDefinitionFile].toString());
  1015. }
  1016. {
  1017. XmlElement* bsc = group->createNewChildElement ("Bscmake");
  1018. bsc->createNewChildElement ("SuppressStartupBanner")->addTextElement ("true");
  1019. bsc->createNewChildElement ("OutputFile")->addTextElement (getIntDirFile (config.getOutputFilename (".bsc", true)));
  1020. }
  1021. if (config.getPrebuildCommandString().isNotEmpty())
  1022. group->createNewChildElement ("PreBuildEvent")
  1023. ->createNewChildElement ("Command")
  1024. ->addTextElement (config.getPrebuildCommandString());
  1025. if (config.getPostbuildCommandString().isNotEmpty())
  1026. group->createNewChildElement ("PostBuildEvent")
  1027. ->createNewChildElement ("Command")
  1028. ->addTextElement (config.getPostbuildCommandString());
  1029. }
  1030. ScopedPointer<XmlElement> otherFilesGroup (new XmlElement ("ItemGroup"));
  1031. {
  1032. XmlElement* cppFiles = projectXml.createNewChildElement ("ItemGroup");
  1033. XmlElement* headerFiles = projectXml.createNewChildElement ("ItemGroup");
  1034. for (int i = 0; i < getAllGroups().size(); ++i)
  1035. {
  1036. const Project::Item& group = getAllGroups().getReference(i);
  1037. if (group.getNumChildren() > 0)
  1038. addFilesToCompile (group, *cppFiles, *headerFiles, *otherFilesGroup);
  1039. }
  1040. }
  1041. if (iconFile != File::nonexistent)
  1042. {
  1043. XmlElement* e = otherFilesGroup->createNewChildElement ("None");
  1044. e->setAttribute ("Include", prependDot (iconFile.getFileName()));
  1045. }
  1046. if (otherFilesGroup->getFirstChildElement() != nullptr)
  1047. projectXml.addChildElement (otherFilesGroup.release());
  1048. if (hasResourceFile())
  1049. {
  1050. XmlElement* rcGroup = projectXml.createNewChildElement ("ItemGroup");
  1051. XmlElement* e = rcGroup->createNewChildElement ("ResourceCompile");
  1052. e->setAttribute ("Include", prependDot (rcFile.getFileName()));
  1053. }
  1054. {
  1055. XmlElement* e = projectXml.createNewChildElement ("Import");
  1056. e->setAttribute ("Project", "$(VCTargetsPath)\\Microsoft.Cpp.targets");
  1057. }
  1058. {
  1059. XmlElement* e = projectXml.createNewChildElement ("ImportGroup");
  1060. e->setAttribute ("Label", "ExtensionTargets");
  1061. }
  1062. }
  1063. String getProjectType() const
  1064. {
  1065. if (projectType.isGUIApplication() || projectType.isCommandLineApp()) return "Application";
  1066. if (isLibraryDLL()) return "DynamicLibrary";
  1067. if (projectType.isStaticLibrary()) return "StaticLibrary";
  1068. jassertfalse;
  1069. return String::empty;
  1070. }
  1071. static const char* getOptimisationLevelString (int level)
  1072. {
  1073. switch (level)
  1074. {
  1075. case optimiseMaxSpeed: return "Full";
  1076. case optimiseMinSize: return "MinSpace";
  1077. default: return "Disabled";
  1078. }
  1079. }
  1080. //==============================================================================
  1081. void addFilesToCompile (const Project::Item& projectItem, XmlElement& cpps, XmlElement& headers, XmlElement& otherFiles) const
  1082. {
  1083. if (projectItem.isGroup())
  1084. {
  1085. for (int i = 0; i < projectItem.getNumChildren(); ++i)
  1086. addFilesToCompile (projectItem.getChild(i), cpps, headers, otherFiles);
  1087. }
  1088. else if (projectItem.shouldBeAddedToTargetProject())
  1089. {
  1090. const RelativePath path (projectItem.getFile(), getTargetFolder(), RelativePath::buildTargetFolder);
  1091. jassert (path.getRoot() == RelativePath::buildTargetFolder);
  1092. if (path.hasFileExtension ("cpp;cc;cxx;c"))
  1093. {
  1094. XmlElement* e = cpps.createNewChildElement ("ClCompile");
  1095. e->setAttribute ("Include", path.toWindowsStyle());
  1096. if (! projectItem.shouldBeCompiled())
  1097. e->createNewChildElement ("ExcludedFromBuild")->addTextElement ("true");
  1098. if (projectItem.shouldUseStdCall())
  1099. e->createNewChildElement ("CallingConvention")->addTextElement ("StdCall");
  1100. }
  1101. else if (path.hasFileExtension (headerFileExtensions))
  1102. {
  1103. headers.createNewChildElement ("ClInclude")->setAttribute ("Include", path.toWindowsStyle());
  1104. }
  1105. else if (! path.hasFileExtension ("mm;m"))
  1106. {
  1107. otherFiles.createNewChildElement ("None")->setAttribute ("Include", path.toWindowsStyle());
  1108. }
  1109. }
  1110. }
  1111. //==============================================================================
  1112. void addFilterGroup (XmlElement& groups, const String& path) const
  1113. {
  1114. XmlElement* e = groups.createNewChildElement ("Filter");
  1115. e->setAttribute ("Include", path);
  1116. e->createNewChildElement ("UniqueIdentifier")->addTextElement (createGUID (path + "_guidpathsaltxhsdf"));
  1117. }
  1118. void addFileToFilter (const RelativePath& file, const String& groupPath,
  1119. XmlElement& cpps, XmlElement& headers, XmlElement& otherFiles) const
  1120. {
  1121. XmlElement* e;
  1122. if (file.hasFileExtension (headerFileExtensions))
  1123. e = headers.createNewChildElement ("ClInclude");
  1124. else if (file.hasFileExtension (sourceFileExtensions))
  1125. e = cpps.createNewChildElement ("ClCompile");
  1126. else
  1127. e = otherFiles.createNewChildElement ("None");
  1128. jassert (file.getRoot() == RelativePath::buildTargetFolder);
  1129. e->setAttribute ("Include", file.toWindowsStyle());
  1130. e->createNewChildElement ("Filter")->addTextElement (groupPath);
  1131. }
  1132. void addFilesToFilter (const Project::Item& projectItem, const String& path,
  1133. XmlElement& cpps, XmlElement& headers, XmlElement& otherFiles, XmlElement& groups) const
  1134. {
  1135. if (projectItem.isGroup())
  1136. {
  1137. addFilterGroup (groups, path);
  1138. for (int i = 0; i < projectItem.getNumChildren(); ++i)
  1139. addFilesToFilter (projectItem.getChild(i),
  1140. (path.isEmpty() ? String::empty : (path + "\\")) + projectItem.getChild(i).getName(),
  1141. cpps, headers, otherFiles, groups);
  1142. }
  1143. else if (projectItem.shouldBeAddedToTargetProject())
  1144. {
  1145. addFileToFilter (RelativePath (projectItem.getFile(), getTargetFolder(), RelativePath::buildTargetFolder),
  1146. path.upToLastOccurrenceOf ("\\", false, false), cpps, headers, otherFiles);
  1147. }
  1148. }
  1149. void addFilesToFilter (const Array<RelativePath>& files, const String& path,
  1150. XmlElement& cpps, XmlElement& headers, XmlElement& otherFiles, XmlElement& groups)
  1151. {
  1152. if (files.size() > 0)
  1153. {
  1154. addFilterGroup (groups, path);
  1155. for (int i = 0; i < files.size(); ++i)
  1156. addFileToFilter (files.getReference(i), path, cpps, headers, otherFiles);
  1157. }
  1158. }
  1159. void fillInFiltersXml (XmlElement& filterXml) const
  1160. {
  1161. filterXml.setAttribute ("ToolsVersion", "4.0");
  1162. filterXml.setAttribute ("xmlns", "http://schemas.microsoft.com/developer/msbuild/2003");
  1163. XmlElement* groupsXml = filterXml.createNewChildElement ("ItemGroup");
  1164. XmlElement* cpps = filterXml.createNewChildElement ("ItemGroup");
  1165. XmlElement* headers = filterXml.createNewChildElement ("ItemGroup");
  1166. ScopedPointer<XmlElement> otherFilesGroup (new XmlElement ("ItemGroup"));
  1167. for (int i = 0; i < getAllGroups().size(); ++i)
  1168. {
  1169. const Project::Item& group = getAllGroups().getReference(i);
  1170. if (group.getNumChildren() > 0)
  1171. addFilesToFilter (group, group.getName(), *cpps, *headers, *otherFilesGroup, *groupsXml);
  1172. }
  1173. if (iconFile.exists())
  1174. {
  1175. XmlElement* e = otherFilesGroup->createNewChildElement ("None");
  1176. e->setAttribute ("Include", prependDot (iconFile.getFileName()));
  1177. e->createNewChildElement ("Filter")->addTextElement (ProjectSaver::getJuceCodeGroupName());
  1178. }
  1179. if (otherFilesGroup->getFirstChildElement() != nullptr)
  1180. filterXml.addChildElement (otherFilesGroup.release());
  1181. if (hasResourceFile())
  1182. {
  1183. XmlElement* rcGroup = filterXml.createNewChildElement ("ItemGroup");
  1184. XmlElement* e = rcGroup->createNewChildElement ("ResourceCompile");
  1185. e->setAttribute ("Include", prependDot (rcFile.getFileName()));
  1186. e->createNewChildElement ("Filter")->addTextElement (ProjectSaver::getJuceCodeGroupName());
  1187. }
  1188. }
  1189. JUCE_DECLARE_NON_COPYABLE (MSVCProjectExporterVC2010)
  1190. };
  1191. //==============================================================================
  1192. class MSVCProjectExporterVC2012 : public MSVCProjectExporterVC2010
  1193. {
  1194. public:
  1195. MSVCProjectExporterVC2012 (Project& p, const ValueTree& t)
  1196. : MSVCProjectExporterVC2010 (p, t, "VisualStudio2012")
  1197. {
  1198. name = getName();
  1199. }
  1200. static const char* getName() { return "Visual Studio 2012"; }
  1201. static const char* getValueTreeTypeName() { return "VS2012"; }
  1202. int getVisualStudioVersion() const { return 11; }
  1203. String getSolutionComment() const { return "# Visual Studio 2012"; }
  1204. String getPlatformToolset() const
  1205. {
  1206. const String s (settings [Ids::toolset].toString());
  1207. return s.isNotEmpty() ? s : "v110";
  1208. }
  1209. Value getPlatformToolsetValue() { return getSetting (Ids::toolset); }
  1210. static MSVCProjectExporterVC2012* createForSettings (Project& project, const ValueTree& settings)
  1211. {
  1212. if (settings.hasType (getValueTreeTypeName()))
  1213. return new MSVCProjectExporterVC2012 (project, settings);
  1214. return nullptr;
  1215. }
  1216. void createExporterProperties (PropertyListBuilder& props)
  1217. {
  1218. MSVCProjectExporterVC2010::createExporterProperties (props);
  1219. const char* const toolsetNames[] = { "(default)", "v110", "v110_xp", "Windows7.1SDK", nullptr };
  1220. const var toolsets[] = { var(), "v110", "v110_xp", "Windows7.1SDK" };
  1221. props.add (new ChoicePropertyComponent (getPlatformToolsetValue(), "Platform Toolset",
  1222. StringArray (toolsetNames),
  1223. Array<var> (toolsets, numElementsInArray (toolsets))));
  1224. }
  1225. private:
  1226. void addPlatformToolsetToPropertyGroup (XmlElement& p) const
  1227. {
  1228. forEachXmlChildElementWithTagName (p, e, "PropertyGroup")
  1229. {
  1230. XmlElement* platformToolset (new XmlElement ("PlatformToolset"));
  1231. platformToolset->addTextElement (getPlatformToolset());
  1232. e->addChildElement (platformToolset);
  1233. }
  1234. }
  1235. JUCE_DECLARE_NON_COPYABLE (MSVCProjectExporterVC2012)
  1236. };