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.

1512 lines
65KB

  1. /*
  2. ==============================================================================
  3. This file is part of the JUCE library - "Jules' Utility Class Extensions"
  4. Copyright 2004-11 by Raw Material Software Ltd.
  5. ------------------------------------------------------------------------------
  6. JUCE can be redistributed and/or modified under the terms of the GNU General
  7. Public License (Version 2), as published by the Free Software Foundation.
  8. A copy of the license is included in the JUCE distribution, or can be found
  9. online at www.gnu.org/licenses.
  10. JUCE is distributed in the hope that it will be useful, but WITHOUT ANY
  11. WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
  12. A PARTICULAR PURPOSE. See the GNU General Public License for more details.
  13. ------------------------------------------------------------------------------
  14. To release a closed-source product which uses JUCE, commercial licenses are
  15. available: visit www.rawmaterialsoftware.com/juce for more information.
  16. ==============================================================================
  17. */
  18. #ifndef __JUCER_PROJECTEXPORT_MSVC_JUCEHEADER__
  19. #define __JUCER_PROJECTEXPORT_MSVC_JUCEHEADER__
  20. #include "jucer_ProjectExporter.h"
  21. #include "jucer_ProjectSaver.h"
  22. //==============================================================================
  23. class MSVCProjectExporterBase : public ProjectExporter
  24. {
  25. public:
  26. MSVCProjectExporterBase (Project& p, const ValueTree& t, const char* const folderName)
  27. : ProjectExporter (p, t)
  28. {
  29. if (getTargetLocationString().isEmpty())
  30. getTargetLocationValue() = getDefaultBuildsRootFolder() + folderName;
  31. if ((int) getLibraryType().getValue() <= 0)
  32. getLibraryType() = 1;
  33. projectGUID = createGUID (project.getProjectUID());
  34. updateOldSettings();
  35. }
  36. //==============================================================================
  37. bool usesMMFiles() const { return false; }
  38. bool isVisualStudio() const { return true; }
  39. bool canCopeWithDuplicateFiles() { return false; }
  40. bool launchProject()
  41. {
  42. #if JUCE_WINDOWS
  43. return getSLNFile().startAsProcess();
  44. #else
  45. return false;
  46. #endif
  47. }
  48. void createExporterProperties (PropertyListBuilder& props)
  49. {
  50. if (projectType.isLibrary())
  51. {
  52. const char* const libTypes[] = { "Static Library (.lib)", "Dynamic Library (.dll)", 0 };
  53. const int libTypeValues[] = { 1, 2, 0 };
  54. props.add (new ChoicePropertyComponent (getLibraryType(), "Library Type",
  55. StringArray (libTypes), Array<var> (libTypeValues)));
  56. }
  57. }
  58. protected:
  59. String projectGUID;
  60. mutable File rcFile, iconFile;
  61. File getProjectFile (const String& extension) const { return getTargetFolder().getChildFile (project.getProjectFilenameRoot()).withFileExtension (extension); }
  62. File getSLNFile() const { return getProjectFile (".sln"); }
  63. Value getLibraryType() { return getSetting (Ids::libraryType); }
  64. String getLibraryString() const { return getSettingString (Ids::libraryType); }
  65. bool isLibraryDLL() const { return msvcIsDLL || (projectType.isLibrary() && (int) settings [Ids::libraryType] == 2); }
  66. static String prependIfNotAbsolute (const String& file, const char* prefix)
  67. {
  68. if (File::isAbsolutePath (file) || file.startsWithChar ('$'))
  69. prefix = "";
  70. return prefix + FileHelpers::windowsStylePath (file);
  71. }
  72. static String getIntDirFile (const String& file) { return prependIfNotAbsolute (file, "$(IntDir)\\"); }
  73. static String getOutDirFile (const String& file) { return prependIfNotAbsolute (file, "$(OutDir)\\"); }
  74. void updateOldSettings()
  75. {
  76. {
  77. const String oldStylePrebuildCommand (getSettingString (Ids::prebuildCommand));
  78. settings.removeProperty (Ids::prebuildCommand, nullptr);
  79. if (oldStylePrebuildCommand.isNotEmpty())
  80. for (ConfigIterator config (*this); config.next();)
  81. dynamic_cast <MSVCBuildConfiguration&> (*config).getPrebuildCommand() = oldStylePrebuildCommand;
  82. }
  83. {
  84. const String oldStyleLibName (getSettingString ("libraryName_Debug"));
  85. settings.removeProperty ("libraryName_Debug", nullptr);
  86. if (oldStyleLibName.isNotEmpty())
  87. for (ConfigIterator config (*this); config.next();)
  88. if (config->isDebug())
  89. config->getTargetBinaryName() = oldStyleLibName;
  90. }
  91. {
  92. const String oldStyleLibName (getSettingString ("libraryName_Release"));
  93. settings.removeProperty ("libraryName_Release", nullptr);
  94. if (oldStyleLibName.isNotEmpty())
  95. for (ConfigIterator config (*this); config.next();)
  96. if (! config->isDebug())
  97. config->getTargetBinaryName() = oldStyleLibName;
  98. }
  99. }
  100. //==============================================================================
  101. class MSVCBuildConfiguration : public BuildConfiguration
  102. {
  103. public:
  104. MSVCBuildConfiguration (Project& project, const ValueTree& settings)
  105. : BuildConfiguration (project, settings)
  106. {
  107. if (getWarningLevel() == 0)
  108. getWarningLevelValue() = 4;
  109. setValueIfVoid (shouldGenerateManifestValue(), true);
  110. }
  111. Value getWarningLevelValue() { return getValue (Ids::winWarningLevel); }
  112. int getWarningLevel() const { return config [Ids::winWarningLevel]; }
  113. Value getPrebuildCommand() { return getValue (Ids::prebuildCommand); }
  114. String getPrebuildCommandString() const { return config [Ids::prebuildCommand]; }
  115. Value getPostbuildCommand() { return getValue (Ids::postbuildCommand); }
  116. String getPostbuildCommandString() const { return config [Ids::postbuildCommand]; }
  117. Value shouldGenerateDebugSymbolsValue() { return getValue (Ids::alwaysGenerateDebugSymbols); }
  118. bool shouldGenerateDebugSymbols() const { return config [Ids::alwaysGenerateDebugSymbols]; }
  119. Value shouldGenerateManifestValue() { return getValue (Ids::generateManifest); }
  120. bool shouldGenerateManifest() const { return config [Ids::generateManifest]; }
  121. Value getWholeProgramOptValue() { return getValue (Ids::wholeProgramOptimisation); }
  122. bool shouldDisableWholeProgramOpt() const { return static_cast<int> (config [Ids::wholeProgramOptimisation]) > 0; }
  123. Value getUsingRuntimeLibDLL() { return getValue (Ids::useRuntimeLibDLL); }
  124. bool isUsingRuntimeLibDLL() const { return config [Ids::useRuntimeLibDLL]; }
  125. String getOutputFilename (const String& suffix, bool forceSuffix) const
  126. {
  127. const String target (File::createLegalFileName (getTargetBinaryNameString().trim()));
  128. if (forceSuffix || ! target.containsChar ('.'))
  129. return target.upToLastOccurrenceOf (".", false, false) + suffix;
  130. return target;
  131. }
  132. void createConfigProperties (PropertyListBuilder& props)
  133. {
  134. const char* const warningLevelNames[] = { "Low", "Medium", "High", nullptr };
  135. const int warningLevels[] = { 2, 3, 4, 0 };
  136. props.add (new ChoicePropertyComponent (getWarningLevelValue(), "Warning Level",
  137. StringArray (warningLevelNames), Array<var> (warningLevels)));
  138. {
  139. const char* const runtimeNames[] = { "(Default)", "Use static runtime", "Use DLL runtime", nullptr };
  140. const var runtimeValues[] = { var(), var (false), var (true) };
  141. props.add (new ChoicePropertyComponent (getUsingRuntimeLibDLL(), "Runtime Library",
  142. StringArray (runtimeNames), Array<var> (runtimeValues, numElementsInArray (runtimeValues))));
  143. }
  144. {
  145. const char* const wpoNames[] = { "Enable link-time code generation when possible",
  146. "Always disable link-time code generation", nullptr };
  147. const var wpoValues[] = { var(), var (1) };
  148. props.add (new ChoicePropertyComponent (getWholeProgramOptValue(), "Whole Program Optimisation",
  149. StringArray (wpoNames), Array<var> (wpoValues, numElementsInArray (wpoValues))));
  150. }
  151. if (! isDebug())
  152. props.add (new BooleanPropertyComponent (shouldGenerateDebugSymbolsValue(), "Debug Symbols", "Force generation of debug symbols"));
  153. props.add (new TextPropertyComponent (getPrebuildCommand(), "Pre-build Command", 2048, false));
  154. props.add (new TextPropertyComponent (getPostbuildCommand(), "Post-build Command", 2048, false));
  155. props.add (new BooleanPropertyComponent (shouldGenerateManifestValue(), "Manifest", "Generate Manifest"));
  156. }
  157. };
  158. BuildConfiguration::Ptr createBuildConfig (const ValueTree& settings) const
  159. {
  160. return new MSVCBuildConfiguration (project, settings);
  161. }
  162. static int getWarningLevel (const BuildConfiguration& config)
  163. {
  164. return dynamic_cast <const MSVCBuildConfiguration&> (config).getWarningLevel();
  165. }
  166. //==============================================================================
  167. String getIntermediatesPath (const BuildConfiguration& config) const
  168. {
  169. return prependDot (File::createLegalFileName (config.getName().trim()));
  170. }
  171. String getConfigTargetPath (const BuildConfiguration& config) const
  172. {
  173. const String binaryPath (config.getTargetBinaryRelativePathString().trim());
  174. if (binaryPath.isEmpty())
  175. return getIntermediatesPath (config);
  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.isLibrary();
  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() || (shouldFileBeCompiledByDefault (path) && ! projectItem.shouldBeCompiled()),
  549. shouldFileBeCompiledByDefault (path) && (bool) projectItem.shouldUseStdCall());
  550. }
  551. }
  552. void createFiles (XmlElement& files) const
  553. {
  554. for (int i = 0; i < getAllGroups().size(); ++i)
  555. {
  556. const Project::Item& group = getAllGroups().getReference(i);
  557. if (group.getNumChildren() > 0)
  558. addFiles (group, files);
  559. }
  560. }
  561. //==============================================================================
  562. XmlElement* createToolElement (XmlElement& parent, const String& toolName) const
  563. {
  564. XmlElement* const e = parent.createNewChildElement ("Tool");
  565. e->setAttribute ("Name", toolName);
  566. return e;
  567. }
  568. void createConfig (XmlElement& xml, const MSVCBuildConfiguration& config) const
  569. {
  570. const bool isDebug = config.isDebug();
  571. xml.setAttribute ("Name", createConfigName (config));
  572. xml.setAttribute ("OutputDirectory", FileHelpers::windowsStylePath (getConfigTargetPath (config)));
  573. xml.setAttribute ("IntermediateDirectory", FileHelpers::windowsStylePath (getIntermediatesPath (config)));
  574. xml.setAttribute ("ConfigurationType", isLibraryDLL() ? "2" : (projectType.isLibrary() ? "4" : "1"));
  575. xml.setAttribute ("UseOfMFC", "0");
  576. xml.setAttribute ("ATLMinimizesCRunTimeLibraryUsage", "false");
  577. xml.setAttribute ("CharacterSet", "2");
  578. if (! (isDebug || config.shouldDisableWholeProgramOpt()))
  579. xml.setAttribute ("WholeProgramOptimization", "1");
  580. XmlElement* preBuildEvent = createToolElement (xml, "VCPreBuildEventTool");
  581. if (config.getPrebuildCommandString().isNotEmpty())
  582. {
  583. preBuildEvent->setAttribute ("Description", "Pre-build");
  584. preBuildEvent->setAttribute ("CommandLine", config.getPrebuildCommandString());
  585. }
  586. createToolElement (xml, "VCCustomBuildTool");
  587. createToolElement (xml, "VCXMLDataGeneratorTool");
  588. createToolElement (xml, "VCWebServiceProxyGeneratorTool");
  589. if (! projectType.isLibrary())
  590. {
  591. XmlElement* midl = createToolElement (xml, "VCMIDLTool");
  592. midl->setAttribute ("PreprocessorDefinitions", isDebug ? "_DEBUG" : "NDEBUG");
  593. midl->setAttribute ("MkTypLibCompatible", "true");
  594. midl->setAttribute ("SuppressStartupBanner", "true");
  595. midl->setAttribute ("TargetEnvironment", "1");
  596. midl->setAttribute ("TypeLibraryName", getIntDirFile (config.getOutputFilename (".tlb", true)));
  597. midl->setAttribute ("HeaderFileName", "");
  598. }
  599. {
  600. XmlElement* compiler = createToolElement (xml, "VCCLCompilerTool");
  601. compiler->setAttribute ("Optimization", getOptimisationLevelString (config.getOptimisationLevelInt()));
  602. if (isDebug)
  603. {
  604. compiler->setAttribute ("BufferSecurityCheck", "");
  605. compiler->setAttribute ("DebugInformationFormat", projectType.isLibrary() ? "3" : "4");
  606. }
  607. else
  608. {
  609. compiler->setAttribute ("InlineFunctionExpansion", "1");
  610. compiler->setAttribute ("StringPooling", "true");
  611. }
  612. compiler->setAttribute ("AdditionalIncludeDirectories", replacePreprocessorTokens (config, getHeaderSearchPaths (config).joinIntoString (";")));
  613. compiler->setAttribute ("PreprocessorDefinitions", getPreprocessorDefs (config, ";"));
  614. compiler->setAttribute ("RuntimeLibrary", config.isUsingRuntimeLibDLL() ? (isDebug ? 3 : 2) // MT DLL
  615. : (isDebug ? 1 : 0)); // MT static
  616. compiler->setAttribute ("RuntimeTypeInfo", "true");
  617. compiler->setAttribute ("UsePrecompiledHeader", "0");
  618. compiler->setAttribute ("PrecompiledHeaderFile", getIntDirFile (config.getOutputFilename (".pch", true)));
  619. compiler->setAttribute ("AssemblerListingLocation", "$(IntDir)\\");
  620. compiler->setAttribute ("ObjectFile", "$(IntDir)\\");
  621. compiler->setAttribute ("ProgramDataBaseFileName", "$(IntDir)\\");
  622. compiler->setAttribute ("WarningLevel", String (getWarningLevel (config)));
  623. compiler->setAttribute ("SuppressStartupBanner", "true");
  624. const String extraFlags (replacePreprocessorTokens (config, getExtraCompilerFlagsString()).trim());
  625. if (extraFlags.isNotEmpty())
  626. compiler->setAttribute ("AdditionalOptions", extraFlags);
  627. }
  628. createToolElement (xml, "VCManagedResourceCompilerTool");
  629. {
  630. XmlElement* resCompiler = createToolElement (xml, "VCResourceCompilerTool");
  631. resCompiler->setAttribute ("PreprocessorDefinitions", isDebug ? "_DEBUG" : "NDEBUG");
  632. }
  633. createToolElement (xml, "VCPreLinkEventTool");
  634. if (! projectType.isLibrary())
  635. {
  636. XmlElement* linker = createToolElement (xml, "VCLinkerTool");
  637. linker->setAttribute ("OutputFile", getOutDirFile (config.getOutputFilename (msvcTargetSuffix, false)));
  638. linker->setAttribute ("SuppressStartupBanner", "true");
  639. linker->setAttribute ("IgnoreDefaultLibraryNames", isDebug ? "libcmt.lib, msvcrt.lib" : "");
  640. linker->setAttribute ("GenerateDebugInformation", (isDebug || config.shouldGenerateDebugSymbols()) ? "true" : "false");
  641. linker->setAttribute ("ProgramDatabaseFile", getIntDirFile (config.getOutputFilename (".pdb", true)));
  642. linker->setAttribute ("SubSystem", msvcIsWindowsSubsystem ? "2" : "1");
  643. const StringArray librarySearchPaths (config.getLibrarySearchPaths());
  644. if (librarySearchPaths.size() > 0)
  645. linker->setAttribute ("AdditionalLibraryDirectories", librarySearchPaths.joinIntoString (";"));
  646. linker->setAttribute ("GenerateManifest", config.shouldGenerateManifest() ? "true" : "false");
  647. if (! isDebug)
  648. {
  649. linker->setAttribute ("OptimizeReferences", "2");
  650. linker->setAttribute ("EnableCOMDATFolding", "2");
  651. }
  652. linker->setAttribute ("TargetMachine", "1"); // (64-bit build = 5)
  653. if (msvcDelayLoadedDLLs.isNotEmpty())
  654. linker->setAttribute ("DelayLoadDLLs", msvcDelayLoadedDLLs);
  655. if (config.config [Ids::msvcModuleDefinitionFile].toString().isNotEmpty())
  656. linker->setAttribute ("ModuleDefinitionFile", config.config [Ids::msvcModuleDefinitionFile].toString());
  657. String externalLibraries (getExternalLibrariesString());
  658. if (externalLibraries.isNotEmpty())
  659. linker->setAttribute ("AdditionalDependencies", replacePreprocessorTokens (config, externalLibraries).trim());
  660. String extraLinkerOptions (getExtraLinkerFlagsString());
  661. if (extraLinkerOptions.isNotEmpty())
  662. linker->setAttribute ("AdditionalOptions", replacePreprocessorTokens (config, extraLinkerOptions).trim());
  663. }
  664. else
  665. {
  666. if (isLibraryDLL())
  667. {
  668. XmlElement* linker = createToolElement (xml, "VCLinkerTool");
  669. String extraLinkerOptions (getExtraLinkerFlagsString());
  670. extraLinkerOptions << " /IMPLIB:" << getOutDirFile (config.getOutputFilename (".lib", true));
  671. linker->setAttribute ("AdditionalOptions", replacePreprocessorTokens (config, extraLinkerOptions).trim());
  672. String externalLibraries (getExternalLibrariesString());
  673. if (externalLibraries.isNotEmpty())
  674. linker->setAttribute ("AdditionalDependencies", replacePreprocessorTokens (config, externalLibraries).trim());
  675. linker->setAttribute ("OutputFile", getOutDirFile (config.getOutputFilename (msvcTargetSuffix, false)));
  676. linker->setAttribute ("IgnoreDefaultLibraryNames", isDebug ? "libcmt.lib, msvcrt.lib" : "");
  677. }
  678. else
  679. {
  680. XmlElement* librarian = createToolElement (xml, "VCLibrarianTool");
  681. librarian->setAttribute ("OutputFile", getOutDirFile (config.getOutputFilename (msvcTargetSuffix, false)));
  682. librarian->setAttribute ("IgnoreDefaultLibraryNames", isDebug ? "libcmt.lib, msvcrt.lib" : "");
  683. }
  684. }
  685. createToolElement (xml, "VCALinkTool");
  686. createToolElement (xml, "VCManifestTool");
  687. createToolElement (xml, "VCXDCMakeTool");
  688. {
  689. XmlElement* bscMake = createToolElement (xml, "VCBscMakeTool");
  690. bscMake->setAttribute ("SuppressStartupBanner", "true");
  691. bscMake->setAttribute ("OutputFile", getIntDirFile (config.getOutputFilename (".bsc", true)));
  692. }
  693. createToolElement (xml, "VCFxCopTool");
  694. if (! projectType.isLibrary())
  695. createToolElement (xml, "VCAppVerifierTool");
  696. XmlElement* postBuildEvent = createToolElement (xml, "VCPostBuildEventTool");
  697. if (config.getPostbuildCommandString().isNotEmpty())
  698. {
  699. postBuildEvent->setAttribute ("Description", "Post-build");
  700. postBuildEvent->setAttribute ("CommandLine", config.getPostbuildCommandString());
  701. }
  702. }
  703. void createConfigs (XmlElement& xml) const
  704. {
  705. for (ConstConfigIterator config (*this); config.next();)
  706. createConfig (*xml.createNewChildElement ("Configuration"),
  707. dynamic_cast <const MSVCBuildConfiguration&> (*config));
  708. }
  709. static const char* getOptimisationLevelString (int level)
  710. {
  711. switch (level)
  712. {
  713. case optimiseMaxSpeed: return "3";
  714. case optimiseMinSize: return "1";
  715. default: return "0";
  716. }
  717. }
  718. //==============================================================================
  719. JUCE_DECLARE_NON_COPYABLE (MSVCProjectExporterVC2008)
  720. };
  721. //==============================================================================
  722. class MSVCProjectExporterVC2005 : public MSVCProjectExporterVC2008
  723. {
  724. public:
  725. MSVCProjectExporterVC2005 (Project& p, const ValueTree& t)
  726. : MSVCProjectExporterVC2008 (p, t, "VisualStudio2005")
  727. {
  728. name = getName();
  729. }
  730. static const char* getName() { return "Visual Studio 2005"; }
  731. static const char* getValueTreeTypeName() { return "VS2005"; }
  732. int getVisualStudioVersion() const { return 8; }
  733. static MSVCProjectExporterVC2005* createForSettings (Project& project, const ValueTree& settings)
  734. {
  735. if (settings.hasType (getValueTreeTypeName()))
  736. return new MSVCProjectExporterVC2005 (project, settings);
  737. return nullptr;
  738. }
  739. protected:
  740. String getProjectVersionString() const { return "8.00"; }
  741. String getSolutionVersionString() const { return "9.00" + newLine + "# Visual C++ Express 2005"; }
  742. JUCE_DECLARE_NON_COPYABLE (MSVCProjectExporterVC2005)
  743. };
  744. //==============================================================================
  745. class MSVCProjectExporterVC2010 : public MSVCProjectExporterBase
  746. {
  747. public:
  748. MSVCProjectExporterVC2010 (Project& p, const ValueTree& t, const char* folderName = "VisualStudio2010")
  749. : MSVCProjectExporterBase (p, t, folderName)
  750. {
  751. name = getName();
  752. }
  753. static const char* getName() { return "Visual Studio 2010"; }
  754. static const char* getValueTreeTypeName() { return "VS2010"; }
  755. int getVisualStudioVersion() const { return 10; }
  756. virtual String getPlatformToolset() const { return "Windows7.1SDK"; }
  757. virtual String getSolutionComment() const { return "# Visual Studio 2010"; }
  758. static MSVCProjectExporterVC2010* createForSettings (Project& project, const ValueTree& settings)
  759. {
  760. if (settings.hasType (getValueTreeTypeName()))
  761. return new MSVCProjectExporterVC2010 (project, settings);
  762. return nullptr;
  763. }
  764. //==============================================================================
  765. void create (const OwnedArray<LibraryModule>&) const
  766. {
  767. createResourcesAndIcon();
  768. {
  769. XmlElement projectXml ("Project");
  770. fillInProjectXml (projectXml);
  771. addPlatformToolsetToPropertyGroup (projectXml);
  772. writeXmlOrThrow (projectXml, getVCProjFile(), "utf-8", 100);
  773. }
  774. {
  775. XmlElement filtersXml ("Project");
  776. fillInFiltersXml (filtersXml);
  777. writeXmlOrThrow (filtersXml, getVCProjFiltersFile(), "utf-8", 100);
  778. }
  779. {
  780. MemoryOutputStream mo;
  781. writeSolutionFile (mo, "11.00", getSolutionComment(), getVCProjFile());
  782. overwriteFileIfDifferentOrThrow (getSLNFile(), mo);
  783. }
  784. }
  785. protected:
  786. //==============================================================================
  787. class VC2010BuildConfiguration : public MSVCBuildConfiguration
  788. {
  789. public:
  790. VC2010BuildConfiguration (Project& project, const ValueTree& settings)
  791. : MSVCBuildConfiguration (project, settings)
  792. {
  793. if (getArchitectureType().toString().isEmpty())
  794. getArchitectureType() = get32BitArchName();
  795. }
  796. //==============================================================================
  797. static const char* get32BitArchName() { return "32-bit"; }
  798. static const char* get64BitArchName() { return "x64"; }
  799. Value getArchitectureType() { return getValue (Ids::winArchitecture); }
  800. bool is64Bit() const { return config [Ids::winArchitecture].toString() == get64BitArchName(); }
  801. //==============================================================================
  802. void createConfigProperties (PropertyListBuilder& props)
  803. {
  804. MSVCBuildConfiguration::createConfigProperties (props);
  805. const char* const archTypes[] = { get32BitArchName(), get64BitArchName(), nullptr };
  806. props.add (new ChoicePropertyComponent (getArchitectureType(), "Architecture",
  807. StringArray (archTypes), Array<var> (archTypes)));
  808. }
  809. };
  810. virtual void addPlatformToolsetToPropertyGroup (XmlElement&) const {}
  811. BuildConfiguration::Ptr createBuildConfig (const ValueTree& settings) const
  812. {
  813. return new VC2010BuildConfiguration (project, settings);
  814. }
  815. static bool is64Bit (const BuildConfiguration& config)
  816. {
  817. return dynamic_cast <const VC2010BuildConfiguration&> (config).is64Bit();
  818. }
  819. //==============================================================================
  820. File getVCProjFile() const { return getProjectFile (".vcxproj"); }
  821. File getVCProjFiltersFile() const { return getProjectFile (".vcxproj.filters"); }
  822. String createConfigName (const BuildConfiguration& config) const
  823. {
  824. return config.getName() + (is64Bit (config) ? "|x64"
  825. : "|Win32");
  826. }
  827. void setConditionAttribute (XmlElement& xml, const BuildConfiguration& config) const
  828. {
  829. xml.setAttribute ("Condition", "'$(Configuration)|$(Platform)'=='" + createConfigName (config) + "'");
  830. }
  831. //==============================================================================
  832. void fillInProjectXml (XmlElement& projectXml) const
  833. {
  834. projectXml.setAttribute ("DefaultTargets", "Build");
  835. projectXml.setAttribute ("ToolsVersion", "4.0");
  836. projectXml.setAttribute ("xmlns", "http://schemas.microsoft.com/developer/msbuild/2003");
  837. {
  838. XmlElement* configsGroup = projectXml.createNewChildElement ("ItemGroup");
  839. configsGroup->setAttribute ("Label", "ProjectConfigurations");
  840. for (ConstConfigIterator config (*this); config.next();)
  841. {
  842. XmlElement* e = configsGroup->createNewChildElement ("ProjectConfiguration");
  843. e->setAttribute ("Include", createConfigName (*config));
  844. e->createNewChildElement ("Configuration")->addTextElement (config->getName());
  845. e->createNewChildElement ("Platform")->addTextElement (is64Bit (*config) ? "x64" : "Win32");
  846. }
  847. }
  848. {
  849. XmlElement* globals = projectXml.createNewChildElement ("PropertyGroup");
  850. globals->setAttribute ("Label", "Globals");
  851. globals->createNewChildElement ("ProjectGuid")->addTextElement (projectGUID);
  852. }
  853. {
  854. XmlElement* imports = projectXml.createNewChildElement ("Import");
  855. imports->setAttribute ("Project", "$(VCTargetsPath)\\Microsoft.Cpp.Default.props");
  856. }
  857. for (ConstConfigIterator i (*this); i.next();)
  858. {
  859. const MSVCBuildConfiguration& config = dynamic_cast <const MSVCBuildConfiguration&> (*i);
  860. XmlElement* e = projectXml.createNewChildElement ("PropertyGroup");
  861. setConditionAttribute (*e, config);
  862. e->setAttribute ("Label", "Configuration");
  863. e->createNewChildElement ("ConfigurationType")->addTextElement (getProjectType());
  864. e->createNewChildElement ("UseOfMfc")->addTextElement ("false");
  865. e->createNewChildElement ("CharacterSet")->addTextElement ("MultiByte");
  866. if (! (config.isDebug() || config.shouldDisableWholeProgramOpt()))
  867. e->createNewChildElement ("WholeProgramOptimization")->addTextElement ("true");
  868. if (is64Bit (config))
  869. e->createNewChildElement ("PlatformToolset")->addTextElement (getPlatformToolset());
  870. }
  871. {
  872. XmlElement* e = projectXml.createNewChildElement ("Import");
  873. e->setAttribute ("Project", "$(VCTargetsPath)\\Microsoft.Cpp.props");
  874. }
  875. {
  876. XmlElement* e = projectXml.createNewChildElement ("ImportGroup");
  877. e->setAttribute ("Label", "ExtensionSettings");
  878. }
  879. {
  880. XmlElement* e = projectXml.createNewChildElement ("ImportGroup");
  881. e->setAttribute ("Label", "PropertySheets");
  882. XmlElement* p = e->createNewChildElement ("Import");
  883. p->setAttribute ("Project", "$(UserRootDir)\\Microsoft.Cpp.$(Platform).user.props");
  884. p->setAttribute ("Condition", "exists('$(UserRootDir)\\Microsoft.Cpp.$(Platform).user.props')");
  885. p->setAttribute ("Label", "LocalAppDataPlatform");
  886. }
  887. {
  888. XmlElement* e = projectXml.createNewChildElement ("PropertyGroup");
  889. e->setAttribute ("Label", "UserMacros");
  890. }
  891. {
  892. XmlElement* props = projectXml.createNewChildElement ("PropertyGroup");
  893. props->createNewChildElement ("_ProjectFileVersion")->addTextElement ("10.0.30319.1");
  894. for (ConstConfigIterator i (*this); i.next();)
  895. {
  896. const MSVCBuildConfiguration& config = dynamic_cast <const MSVCBuildConfiguration&> (*i);
  897. {
  898. XmlElement* outdir = props->createNewChildElement ("OutDir");
  899. setConditionAttribute (*outdir, config);
  900. outdir->addTextElement (getConfigTargetPath (config) + "\\");
  901. }
  902. {
  903. XmlElement* intdir = props->createNewChildElement ("IntDir");
  904. setConditionAttribute (*intdir, config);
  905. intdir->addTextElement (getIntermediatesPath (config) + "\\");
  906. }
  907. {
  908. XmlElement* name = props->createNewChildElement ("TargetName");
  909. setConditionAttribute (*name, config);
  910. name->addTextElement (config.getOutputFilename (String::empty, true));
  911. }
  912. {
  913. XmlElement* manifest = props->createNewChildElement ("GenerateManifest");
  914. setConditionAttribute (*manifest, config);
  915. manifest->addTextElement (config.shouldGenerateManifest() ? "true" : "false");
  916. }
  917. const StringArray librarySearchPaths (config.getLibrarySearchPaths());
  918. if (librarySearchPaths.size() > 0)
  919. {
  920. XmlElement* libPath = props->createNewChildElement ("LibraryPath");
  921. setConditionAttribute (*libPath, config);
  922. libPath->addTextElement ("$(LibraryPath);" + librarySearchPaths.joinIntoString (";"));
  923. }
  924. }
  925. }
  926. for (ConstConfigIterator i (*this); i.next();)
  927. {
  928. const MSVCBuildConfiguration& config = dynamic_cast <const MSVCBuildConfiguration&> (*i);
  929. const bool isDebug = config.isDebug();
  930. XmlElement* group = projectXml.createNewChildElement ("ItemDefinitionGroup");
  931. setConditionAttribute (*group, config);
  932. {
  933. XmlElement* midl = group->createNewChildElement ("Midl");
  934. midl->createNewChildElement ("PreprocessorDefinitions")->addTextElement (isDebug ? "_DEBUG;%(PreprocessorDefinitions)"
  935. : "NDEBUG;%(PreprocessorDefinitions)");
  936. midl->createNewChildElement ("MkTypLibCompatible")->addTextElement ("true");
  937. midl->createNewChildElement ("SuppressStartupBanner")->addTextElement ("true");
  938. midl->createNewChildElement ("TargetEnvironment")->addTextElement ("Win32");
  939. midl->createNewChildElement ("HeaderFileName");
  940. }
  941. bool isUsingEditAndContinue = false;
  942. {
  943. XmlElement* cl = group->createNewChildElement ("ClCompile");
  944. cl->createNewChildElement ("Optimization")->addTextElement (getOptimisationLevelString (config.getOptimisationLevelInt()));
  945. if (isDebug && config.getOptimisationLevelInt() <= optimisationOff)
  946. {
  947. isUsingEditAndContinue = ! is64Bit (config);
  948. cl->createNewChildElement ("DebugInformationFormat")
  949. ->addTextElement (isUsingEditAndContinue ? "EditAndContinue"
  950. : "ProgramDatabase");
  951. }
  952. StringArray includePaths (getHeaderSearchPaths (config));
  953. includePaths.add ("%(AdditionalIncludeDirectories)");
  954. cl->createNewChildElement ("AdditionalIncludeDirectories")->addTextElement (includePaths.joinIntoString (";"));
  955. cl->createNewChildElement ("PreprocessorDefinitions")->addTextElement (getPreprocessorDefs (config, ";") + ";%(PreprocessorDefinitions)");
  956. cl->createNewChildElement ("RuntimeLibrary")->addTextElement (config.isUsingRuntimeLibDLL() ? (isDebug ? "MultiThreadedDebugDLL" : "MultiThreadedDLL")
  957. : (isDebug ? "MultiThreadedDebug" : "MultiThreaded"));
  958. cl->createNewChildElement ("RuntimeTypeInfo")->addTextElement ("true");
  959. cl->createNewChildElement ("PrecompiledHeader");
  960. cl->createNewChildElement ("AssemblerListingLocation")->addTextElement ("$(IntDir)\\");
  961. cl->createNewChildElement ("ObjectFileName")->addTextElement ("$(IntDir)\\");
  962. cl->createNewChildElement ("ProgramDataBaseFileName")->addTextElement ("$(IntDir)\\");
  963. cl->createNewChildElement ("WarningLevel")->addTextElement ("Level" + String (getWarningLevel (config)));
  964. cl->createNewChildElement ("SuppressStartupBanner")->addTextElement ("true");
  965. cl->createNewChildElement ("MultiProcessorCompilation")->addTextElement ("true");
  966. const String extraFlags (replacePreprocessorTokens (config, getExtraCompilerFlagsString()).trim());
  967. if (extraFlags.isNotEmpty())
  968. cl->createNewChildElement ("AdditionalOptions")->addTextElement (extraFlags + " %(AdditionalOptions)");
  969. }
  970. {
  971. XmlElement* res = group->createNewChildElement ("ResourceCompile");
  972. res->createNewChildElement ("PreprocessorDefinitions")->addTextElement (isDebug ? "_DEBUG;%(PreprocessorDefinitions)"
  973. : "NDEBUG;%(PreprocessorDefinitions)");
  974. }
  975. {
  976. XmlElement* link = group->createNewChildElement ("Link");
  977. link->createNewChildElement ("OutputFile")->addTextElement (getOutDirFile (config.getOutputFilename (msvcTargetSuffix, false)));
  978. link->createNewChildElement ("SuppressStartupBanner")->addTextElement ("true");
  979. link->createNewChildElement ("IgnoreSpecificDefaultLibraries")->addTextElement (isDebug ? "libcmt.lib; msvcrt.lib;;%(IgnoreSpecificDefaultLibraries)"
  980. : "%(IgnoreSpecificDefaultLibraries)");
  981. link->createNewChildElement ("GenerateDebugInformation")->addTextElement ((isDebug || config.shouldGenerateDebugSymbols()) ? "true" : "false");
  982. link->createNewChildElement ("ProgramDatabaseFile")->addTextElement (getIntDirFile (config.getOutputFilename (".pdb", true)));
  983. link->createNewChildElement ("SubSystem")->addTextElement (msvcIsWindowsSubsystem ? "Windows" : "Console");
  984. if (! is64Bit (config))
  985. link->createNewChildElement ("TargetMachine")->addTextElement ("MachineX86");
  986. if (isUsingEditAndContinue)
  987. link->createNewChildElement ("ImageHasSafeExceptionHandlers")->addTextElement ("false");
  988. if (! isDebug)
  989. {
  990. link->createNewChildElement ("OptimizeReferences")->addTextElement ("true");
  991. link->createNewChildElement ("EnableCOMDATFolding")->addTextElement ("true");
  992. }
  993. const StringArray librarySearchPaths (config.getLibrarySearchPaths());
  994. if (librarySearchPaths.size() > 0)
  995. link->createNewChildElement ("AdditionalLibraryDirectories")->addTextElement (replacePreprocessorTokens (config, librarySearchPaths.joinIntoString (";"))
  996. + ";%(AdditionalLibraryDirectories)");
  997. String externalLibraries (getExternalLibrariesString());
  998. if (externalLibraries.isNotEmpty())
  999. link->createNewChildElement ("AdditionalDependencies")->addTextElement (replacePreprocessorTokens (config, externalLibraries).trim()
  1000. + ";%(AdditionalDependencies)");
  1001. String extraLinkerOptions (getExtraLinkerFlagsString());
  1002. if (extraLinkerOptions.isNotEmpty())
  1003. link->createNewChildElement ("AdditionalOptions")->addTextElement (replacePreprocessorTokens (config, extraLinkerOptions).trim()
  1004. + " %(AdditionalOptions)");
  1005. if (msvcDelayLoadedDLLs.isNotEmpty())
  1006. link->createNewChildElement ("DelayLoadDLLs")->addTextElement (msvcDelayLoadedDLLs);
  1007. if (config.config [Ids::msvcModuleDefinitionFile].toString().isNotEmpty())
  1008. link->createNewChildElement ("ModuleDefinitionFile")
  1009. ->addTextElement (config.config [Ids::msvcModuleDefinitionFile].toString());
  1010. }
  1011. {
  1012. XmlElement* bsc = group->createNewChildElement ("Bscmake");
  1013. bsc->createNewChildElement ("SuppressStartupBanner")->addTextElement ("true");
  1014. bsc->createNewChildElement ("OutputFile")->addTextElement (getIntDirFile (config.getOutputFilename (".bsc", true)));
  1015. }
  1016. if (config.getPrebuildCommandString().isNotEmpty())
  1017. group->createNewChildElement ("PreBuildEvent")
  1018. ->createNewChildElement ("Command")
  1019. ->addTextElement (config.getPrebuildCommandString());
  1020. if (config.getPostbuildCommandString().isNotEmpty())
  1021. group->createNewChildElement ("PostBuildEvent")
  1022. ->createNewChildElement ("Command")
  1023. ->addTextElement (config.getPostbuildCommandString());
  1024. }
  1025. ScopedPointer<XmlElement> otherFilesGroup (new XmlElement ("ItemGroup"));
  1026. {
  1027. XmlElement* cppFiles = projectXml.createNewChildElement ("ItemGroup");
  1028. XmlElement* headerFiles = projectXml.createNewChildElement ("ItemGroup");
  1029. for (int i = 0; i < getAllGroups().size(); ++i)
  1030. {
  1031. const Project::Item& group = getAllGroups().getReference(i);
  1032. if (group.getNumChildren() > 0)
  1033. addFilesToCompile (group, *cppFiles, *headerFiles, *otherFilesGroup);
  1034. }
  1035. }
  1036. if (iconFile != File::nonexistent)
  1037. {
  1038. XmlElement* e = otherFilesGroup->createNewChildElement ("None");
  1039. e->setAttribute ("Include", prependDot (iconFile.getFileName()));
  1040. }
  1041. if (otherFilesGroup->getFirstChildElement() != nullptr)
  1042. projectXml.addChildElement (otherFilesGroup.release());
  1043. if (hasResourceFile())
  1044. {
  1045. XmlElement* rcGroup = projectXml.createNewChildElement ("ItemGroup");
  1046. XmlElement* e = rcGroup->createNewChildElement ("ResourceCompile");
  1047. e->setAttribute ("Include", prependDot (rcFile.getFileName()));
  1048. }
  1049. {
  1050. XmlElement* e = projectXml.createNewChildElement ("Import");
  1051. e->setAttribute ("Project", "$(VCTargetsPath)\\Microsoft.Cpp.targets");
  1052. }
  1053. {
  1054. XmlElement* e = projectXml.createNewChildElement ("ImportGroup");
  1055. e->setAttribute ("Label", "ExtensionTargets");
  1056. }
  1057. }
  1058. String getProjectType() const
  1059. {
  1060. if (projectType.isGUIApplication() || projectType.isCommandLineApp()) return "Application";
  1061. if (isLibraryDLL()) return "DynamicLibrary";
  1062. if (projectType.isLibrary()) return "StaticLibrary";
  1063. jassertfalse;
  1064. return String::empty;
  1065. }
  1066. static const char* getOptimisationLevelString (int level)
  1067. {
  1068. switch (level)
  1069. {
  1070. case optimiseMaxSpeed: return "Full";
  1071. case optimiseMinSize: return "MinSpace";
  1072. default: return "Disabled";
  1073. }
  1074. }
  1075. //==============================================================================
  1076. void addFilesToCompile (const Project::Item& projectItem, XmlElement& cpps, XmlElement& headers, XmlElement& otherFiles) const
  1077. {
  1078. if (projectItem.isGroup())
  1079. {
  1080. for (int i = 0; i < projectItem.getNumChildren(); ++i)
  1081. addFilesToCompile (projectItem.getChild(i), cpps, headers, otherFiles);
  1082. }
  1083. else if (projectItem.shouldBeAddedToTargetProject())
  1084. {
  1085. const RelativePath path (projectItem.getFile(), getTargetFolder(), RelativePath::buildTargetFolder);
  1086. jassert (path.getRoot() == RelativePath::buildTargetFolder);
  1087. if (path.hasFileExtension ("cpp;cc;cxx;c"))
  1088. {
  1089. XmlElement* e = cpps.createNewChildElement ("ClCompile");
  1090. e->setAttribute ("Include", path.toWindowsStyle());
  1091. if (! projectItem.shouldBeCompiled())
  1092. e->createNewChildElement ("ExcludedFromBuild")->addTextElement ("true");
  1093. if (projectItem.shouldUseStdCall())
  1094. e->createNewChildElement ("CallingConvention")->addTextElement ("StdCall");
  1095. }
  1096. else if (path.hasFileExtension (headerFileExtensions))
  1097. {
  1098. headers.createNewChildElement ("ClInclude")->setAttribute ("Include", path.toWindowsStyle());
  1099. }
  1100. else if (! path.hasFileExtension ("mm;m"))
  1101. {
  1102. otherFiles.createNewChildElement ("None")->setAttribute ("Include", path.toWindowsStyle());
  1103. }
  1104. }
  1105. }
  1106. //==============================================================================
  1107. void addFilterGroup (XmlElement& groups, const String& path) const
  1108. {
  1109. XmlElement* e = groups.createNewChildElement ("Filter");
  1110. e->setAttribute ("Include", path);
  1111. e->createNewChildElement ("UniqueIdentifier")->addTextElement (createGUID (path + "_guidpathsaltxhsdf"));
  1112. }
  1113. void addFileToFilter (const RelativePath& file, const String& groupPath,
  1114. XmlElement& cpps, XmlElement& headers, XmlElement& otherFiles) const
  1115. {
  1116. XmlElement* e;
  1117. if (file.hasFileExtension (headerFileExtensions))
  1118. e = headers.createNewChildElement ("ClInclude");
  1119. else if (file.hasFileExtension (sourceFileExtensions))
  1120. e = cpps.createNewChildElement ("ClCompile");
  1121. else
  1122. e = otherFiles.createNewChildElement ("None");
  1123. jassert (file.getRoot() == RelativePath::buildTargetFolder);
  1124. e->setAttribute ("Include", file.toWindowsStyle());
  1125. e->createNewChildElement ("Filter")->addTextElement (groupPath);
  1126. }
  1127. void addFilesToFilter (const Project::Item& projectItem, const String& path,
  1128. XmlElement& cpps, XmlElement& headers, XmlElement& otherFiles, XmlElement& groups) const
  1129. {
  1130. if (projectItem.isGroup())
  1131. {
  1132. addFilterGroup (groups, path);
  1133. for (int i = 0; i < projectItem.getNumChildren(); ++i)
  1134. addFilesToFilter (projectItem.getChild(i),
  1135. (path.isEmpty() ? String::empty : (path + "\\")) + projectItem.getChild(i).getName(),
  1136. cpps, headers, otherFiles, groups);
  1137. }
  1138. else if (projectItem.shouldBeAddedToTargetProject())
  1139. {
  1140. addFileToFilter (RelativePath (projectItem.getFile(), getTargetFolder(), RelativePath::buildTargetFolder),
  1141. path.upToLastOccurrenceOf ("\\", false, false), cpps, headers, otherFiles);
  1142. }
  1143. }
  1144. void addFilesToFilter (const Array<RelativePath>& files, const String& path,
  1145. XmlElement& cpps, XmlElement& headers, XmlElement& otherFiles, XmlElement& groups)
  1146. {
  1147. if (files.size() > 0)
  1148. {
  1149. addFilterGroup (groups, path);
  1150. for (int i = 0; i < files.size(); ++i)
  1151. addFileToFilter (files.getReference(i), path, cpps, headers, otherFiles);
  1152. }
  1153. }
  1154. void fillInFiltersXml (XmlElement& filterXml) const
  1155. {
  1156. filterXml.setAttribute ("ToolsVersion", "4.0");
  1157. filterXml.setAttribute ("xmlns", "http://schemas.microsoft.com/developer/msbuild/2003");
  1158. XmlElement* groupsXml = filterXml.createNewChildElement ("ItemGroup");
  1159. XmlElement* cpps = filterXml.createNewChildElement ("ItemGroup");
  1160. XmlElement* headers = filterXml.createNewChildElement ("ItemGroup");
  1161. ScopedPointer<XmlElement> otherFilesGroup (new XmlElement ("ItemGroup"));
  1162. for (int i = 0; i < getAllGroups().size(); ++i)
  1163. {
  1164. const Project::Item& group = getAllGroups().getReference(i);
  1165. if (group.getNumChildren() > 0)
  1166. addFilesToFilter (group, group.getName(), *cpps, *headers, *otherFilesGroup, *groupsXml);
  1167. }
  1168. if (iconFile.exists())
  1169. {
  1170. XmlElement* e = otherFilesGroup->createNewChildElement ("None");
  1171. e->setAttribute ("Include", prependDot (iconFile.getFileName()));
  1172. e->createNewChildElement ("Filter")->addTextElement (ProjectSaver::getJuceCodeGroupName());
  1173. }
  1174. if (otherFilesGroup->getFirstChildElement() != nullptr)
  1175. filterXml.addChildElement (otherFilesGroup.release());
  1176. if (hasResourceFile())
  1177. {
  1178. XmlElement* rcGroup = filterXml.createNewChildElement ("ItemGroup");
  1179. XmlElement* e = rcGroup->createNewChildElement ("ResourceCompile");
  1180. e->setAttribute ("Include", prependDot (rcFile.getFileName()));
  1181. e->createNewChildElement ("Filter")->addTextElement (ProjectSaver::getJuceCodeGroupName());
  1182. }
  1183. }
  1184. JUCE_DECLARE_NON_COPYABLE (MSVCProjectExporterVC2010)
  1185. };
  1186. //==============================================================================
  1187. class MSVCProjectExporterVC2012 : public MSVCProjectExporterVC2010
  1188. {
  1189. public:
  1190. MSVCProjectExporterVC2012 (Project& p, const ValueTree& t)
  1191. : MSVCProjectExporterVC2010 (p, t, "VisualStudio2012")
  1192. {
  1193. name = getName();
  1194. }
  1195. static const char* getName() { return "Visual Studio 2012"; }
  1196. static const char* getValueTreeTypeName() { return "VS2012"; }
  1197. int getVisualStudioVersion() const { return 11; }
  1198. String getPlatformToolset() const { return "v110_xp"; }
  1199. String getSolutionComment() const { return "# Visual Studio 2012"; }
  1200. static MSVCProjectExporterVC2012* createForSettings (Project& project, const ValueTree& settings)
  1201. {
  1202. if (settings.hasType (getValueTreeTypeName()))
  1203. return new MSVCProjectExporterVC2012 (project, settings);
  1204. return nullptr;
  1205. }
  1206. private:
  1207. void addPlatformToolsetToPropertyGroup (XmlElement& project) const
  1208. {
  1209. forEachXmlChildElementWithTagName (project, e, "PropertyGroup")
  1210. {
  1211. XmlElement* platformToolset (new XmlElement ("PlatformToolset"));
  1212. platformToolset->addTextElement (getPlatformToolset());
  1213. e->addChildElement (platformToolset);
  1214. }
  1215. }
  1216. JUCE_DECLARE_NON_COPYABLE (MSVCProjectExporterVC2012)
  1217. };
  1218. #endif // __JUCER_PROJECTEXPORT_MSVC_JUCEHEADER__