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.

1691 lines
74KB

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