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.

1440 lines
63KB

  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_, const char* folderName = "VisualStudio2008")
  440. : MSVCProjectExporterBase (project_, settings_, folderName)
  441. {
  442. name = getName();
  443. }
  444. static const char* getName() { return "Visual Studio 2008"; }
  445. static const char* getValueTreeTypeName() { return "VS2008"; }
  446. int getVisualStudioVersion() const { return 9; }
  447. static MSVCProjectExporterVC2008* createForSettings (Project& project, const ValueTree& settings)
  448. {
  449. if (settings.hasType (getValueTreeTypeName()))
  450. return new MSVCProjectExporterVC2008 (project, settings);
  451. return nullptr;
  452. }
  453. //==============================================================================
  454. void create (const OwnedArray<LibraryModule>&) const
  455. {
  456. createResourcesAndIcon();
  457. if (hasResourceFile())
  458. {
  459. for (int i = 0; i < getAllGroups().size(); ++i)
  460. {
  461. Project::Item& group = getAllGroups().getReference(i);
  462. if (group.getID() == ProjectSaver::getGeneratedGroupID())
  463. {
  464. if (iconFile != File::nonexistent)
  465. {
  466. group.addFile (iconFile, -1, true);
  467. group.findItemForFile (iconFile).getShouldAddToResourceValue() = false;
  468. }
  469. group.addFile (rcFile, -1, true);
  470. group.findItemForFile (rcFile).getShouldAddToResourceValue() = false;
  471. break;
  472. }
  473. }
  474. }
  475. {
  476. XmlElement projectXml ("VisualStudioProject");
  477. fillInProjectXml (projectXml);
  478. writeXmlOrThrow (projectXml, getVCProjFile(), "UTF-8", 10);
  479. }
  480. {
  481. MemoryOutputStream mo;
  482. writeSolutionFile (mo, getSolutionVersionString(), String::empty, getVCProjFile());
  483. overwriteFileIfDifferentOrThrow (getSLNFile(), mo);
  484. }
  485. }
  486. protected:
  487. virtual String getProjectVersionString() const { return "9.00"; }
  488. virtual String getSolutionVersionString() const { return "10.00" + newLine + "# Visual C++ Express 2008"; }
  489. File getVCProjFile() const { return getProjectFile (".vcproj"); }
  490. //==============================================================================
  491. void fillInProjectXml (XmlElement& projectXml) const
  492. {
  493. projectXml.setAttribute ("ProjectType", "Visual C++");
  494. projectXml.setAttribute ("Version", getProjectVersionString());
  495. projectXml.setAttribute ("Name", projectName);
  496. projectXml.setAttribute ("ProjectGUID", projectGUID);
  497. projectXml.setAttribute ("TargetFrameworkVersion", "131072");
  498. {
  499. XmlElement* platforms = projectXml.createNewChildElement ("Platforms");
  500. XmlElement* platform = platforms->createNewChildElement ("Platform");
  501. platform->setAttribute ("Name", "Win32");
  502. }
  503. projectXml.createNewChildElement ("ToolFiles");
  504. createConfigs (*projectXml.createNewChildElement ("Configurations"));
  505. projectXml.createNewChildElement ("References");
  506. createFiles (*projectXml.createNewChildElement ("Files"));
  507. projectXml.createNewChildElement ("Globals");
  508. }
  509. //==============================================================================
  510. void addFile (const RelativePath& file, XmlElement& parent, const bool excludeFromBuild, const bool useStdcall) const
  511. {
  512. jassert (file.getRoot() == RelativePath::buildTargetFolder);
  513. XmlElement* fileXml = parent.createNewChildElement ("File");
  514. fileXml->setAttribute ("RelativePath", file.toWindowsStyle());
  515. if (excludeFromBuild || useStdcall)
  516. {
  517. for (ConstConfigIterator i (*this); i.next();)
  518. {
  519. XmlElement* fileConfig = fileXml->createNewChildElement ("FileConfiguration");
  520. fileConfig->setAttribute ("Name", createConfigName (*i));
  521. if (excludeFromBuild)
  522. fileConfig->setAttribute ("ExcludedFromBuild", "true");
  523. XmlElement* tool = createToolElement (*fileConfig, "VCCLCompilerTool");
  524. if (useStdcall)
  525. tool->setAttribute ("CallingConvention", "2");
  526. }
  527. }
  528. }
  529. XmlElement* createGroup (const String& groupName, XmlElement& parent) const
  530. {
  531. XmlElement* filter = parent.createNewChildElement ("Filter");
  532. filter->setAttribute ("Name", groupName);
  533. return filter;
  534. }
  535. void addFiles (const Project::Item& projectItem, XmlElement& parent) const
  536. {
  537. if (projectItem.isGroup())
  538. {
  539. XmlElement* filter = createGroup (projectItem.getName(), parent);
  540. for (int i = 0; i < projectItem.getNumChildren(); ++i)
  541. addFiles (projectItem.getChild(i), *filter);
  542. }
  543. else if (projectItem.shouldBeAddedToTargetProject())
  544. {
  545. const RelativePath path (projectItem.getFile(), getTargetFolder(), RelativePath::buildTargetFolder);
  546. addFile (path, parent,
  547. projectItem.shouldBeAddedToBinaryResources() || (shouldFileBeCompiledByDefault (path) && ! projectItem.shouldBeCompiled()),
  548. shouldFileBeCompiledByDefault (path) && (bool) projectItem.shouldUseStdCall());
  549. }
  550. }
  551. void createFiles (XmlElement& files) const
  552. {
  553. for (int i = 0; i < getAllGroups().size(); ++i)
  554. {
  555. const Project::Item& group = getAllGroups().getReference(i);
  556. if (group.getNumChildren() > 0)
  557. addFiles (group, files);
  558. }
  559. }
  560. //==============================================================================
  561. XmlElement* createToolElement (XmlElement& parent, const String& toolName) const
  562. {
  563. XmlElement* const e = parent.createNewChildElement ("Tool");
  564. e->setAttribute ("Name", toolName);
  565. return e;
  566. }
  567. void createConfig (XmlElement& xml, const MSVCBuildConfiguration& config) const
  568. {
  569. const bool isDebug = config.isDebug();
  570. xml.setAttribute ("Name", createConfigName (config));
  571. xml.setAttribute ("OutputDirectory", FileHelpers::windowsStylePath (getConfigTargetPath (config)));
  572. xml.setAttribute ("IntermediateDirectory", FileHelpers::windowsStylePath (getIntermediatesPath (config)));
  573. xml.setAttribute ("ConfigurationType", isLibraryDLL() ? "2" : (projectType.isLibrary() ? "4" : "1"));
  574. xml.setAttribute ("UseOfMFC", "0");
  575. xml.setAttribute ("ATLMinimizesCRunTimeLibraryUsage", "false");
  576. xml.setAttribute ("CharacterSet", "2");
  577. if (! (isDebug || config.shouldDisableWholeProgramOpt()))
  578. xml.setAttribute ("WholeProgramOptimization", "1");
  579. XmlElement* preBuildEvent = createToolElement (xml, "VCPreBuildEventTool");
  580. if (config.getPrebuildCommandString().isNotEmpty())
  581. {
  582. preBuildEvent->setAttribute ("Description", "Pre-build");
  583. preBuildEvent->setAttribute ("CommandLine", config.getPrebuildCommandString());
  584. }
  585. createToolElement (xml, "VCCustomBuildTool");
  586. createToolElement (xml, "VCXMLDataGeneratorTool");
  587. createToolElement (xml, "VCWebServiceProxyGeneratorTool");
  588. if (! projectType.isLibrary())
  589. {
  590. XmlElement* midl = createToolElement (xml, "VCMIDLTool");
  591. midl->setAttribute ("PreprocessorDefinitions", isDebug ? "_DEBUG" : "NDEBUG");
  592. midl->setAttribute ("MkTypLibCompatible", "true");
  593. midl->setAttribute ("SuppressStartupBanner", "true");
  594. midl->setAttribute ("TargetEnvironment", "1");
  595. midl->setAttribute ("TypeLibraryName", getIntDirFile (config.getOutputFilename (".tlb", true)));
  596. midl->setAttribute ("HeaderFileName", "");
  597. }
  598. {
  599. XmlElement* compiler = createToolElement (xml, "VCCLCompilerTool");
  600. const int optimiseLevel = config.getOptimisationLevelInt();
  601. compiler->setAttribute ("Optimization", optimiseLevel <= 1 ? "0" : (optimiseLevel == 2 ? "1" : "2"));
  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. //==============================================================================
  710. JUCE_DECLARE_NON_COPYABLE (MSVCProjectExporterVC2008);
  711. };
  712. //==============================================================================
  713. class MSVCProjectExporterVC2005 : public MSVCProjectExporterVC2008
  714. {
  715. public:
  716. MSVCProjectExporterVC2005 (Project& p, const ValueTree& t)
  717. : MSVCProjectExporterVC2008 (p, t, "VisualStudio2005")
  718. {
  719. name = getName();
  720. }
  721. static const char* getName() { return "Visual Studio 2005"; }
  722. static const char* getValueTreeTypeName() { return "VS2005"; }
  723. int getVisualStudioVersion() const { return 8; }
  724. static MSVCProjectExporterVC2005* createForSettings (Project& project, const ValueTree& settings)
  725. {
  726. if (settings.hasType (getValueTreeTypeName()))
  727. return new MSVCProjectExporterVC2005 (project, settings);
  728. return nullptr;
  729. }
  730. protected:
  731. String getProjectVersionString() const { return "8.00"; }
  732. String getSolutionVersionString() const { return "9.00" + newLine + "# Visual C++ Express 2005"; }
  733. JUCE_DECLARE_NON_COPYABLE (MSVCProjectExporterVC2005);
  734. };
  735. //==============================================================================
  736. class MSVCProjectExporterVC2010 : public MSVCProjectExporterBase
  737. {
  738. public:
  739. MSVCProjectExporterVC2010 (Project& p, const ValueTree& t)
  740. : MSVCProjectExporterBase (p, t, "VisualStudio2010")
  741. {
  742. name = getName();
  743. }
  744. static const char* getName() { return "Visual Studio 2010"; }
  745. static const char* getValueTreeTypeName() { return "VS2010"; }
  746. int getVisualStudioVersion() const { return 10; }
  747. static MSVCProjectExporterVC2010* createForSettings (Project& project, const ValueTree& settings)
  748. {
  749. if (settings.hasType (getValueTreeTypeName()))
  750. return new MSVCProjectExporterVC2010 (project, settings);
  751. return nullptr;
  752. }
  753. //==============================================================================
  754. void create (const OwnedArray<LibraryModule>&) const
  755. {
  756. createResourcesAndIcon();
  757. {
  758. XmlElement projectXml ("Project");
  759. fillInProjectXml (projectXml);
  760. writeXmlOrThrow (projectXml, getVCProjFile(), "utf-8", 100);
  761. }
  762. {
  763. XmlElement filtersXml ("Project");
  764. fillInFiltersXml (filtersXml);
  765. writeXmlOrThrow (filtersXml, getVCProjFiltersFile(), "utf-8", 100);
  766. }
  767. {
  768. MemoryOutputStream mo;
  769. writeSolutionFile (mo, "11.00", "# Visual Studio 2010", getVCProjFile());
  770. overwriteFileIfDifferentOrThrow (getSLNFile(), mo);
  771. }
  772. }
  773. protected:
  774. //==============================================================================
  775. class VC2010BuildConfiguration : public MSVCBuildConfiguration
  776. {
  777. public:
  778. VC2010BuildConfiguration (Project& project, const ValueTree& settings)
  779. : MSVCBuildConfiguration (project, settings)
  780. {
  781. if (getArchitectureType().toString().isEmpty())
  782. getArchitectureType() = get32BitArchName();
  783. }
  784. //==============================================================================
  785. static const char* get32BitArchName() { return "32-bit"; }
  786. static const char* get64BitArchName() { return "x64"; }
  787. Value getArchitectureType() { return getValue (Ids::winArchitecture); }
  788. bool is64Bit() const { return config [Ids::winArchitecture].toString() == get64BitArchName(); }
  789. //==============================================================================
  790. void createConfigProperties (PropertyListBuilder& props)
  791. {
  792. MSVCBuildConfiguration::createConfigProperties (props);
  793. const char* const archTypes[] = { get32BitArchName(), get64BitArchName(), nullptr };
  794. props.add (new ChoicePropertyComponent (getArchitectureType(), "Architecture",
  795. StringArray (archTypes), Array<var> (archTypes)));
  796. }
  797. };
  798. BuildConfiguration::Ptr createBuildConfig (const ValueTree& settings) const
  799. {
  800. return new VC2010BuildConfiguration (project, settings);
  801. }
  802. static bool is64Bit (const BuildConfiguration& config)
  803. {
  804. return dynamic_cast <const VC2010BuildConfiguration&> (config).is64Bit();
  805. }
  806. //==============================================================================
  807. File getVCProjFile() const { return getProjectFile (".vcxproj"); }
  808. File getVCProjFiltersFile() const { return getProjectFile (".vcxproj.filters"); }
  809. String createConfigName (const BuildConfiguration& config) const
  810. {
  811. return config.getName() + (is64Bit (config) ? "|x64"
  812. : "|Win32");
  813. }
  814. void setConditionAttribute (XmlElement& xml, const BuildConfiguration& config) const
  815. {
  816. xml.setAttribute ("Condition", "'$(Configuration)|$(Platform)'=='" + createConfigName (config) + "'");
  817. }
  818. //==============================================================================
  819. void fillInProjectXml (XmlElement& projectXml) const
  820. {
  821. projectXml.setAttribute ("DefaultTargets", "Build");
  822. projectXml.setAttribute ("ToolsVersion", "4.0");
  823. projectXml.setAttribute ("xmlns", "http://schemas.microsoft.com/developer/msbuild/2003");
  824. {
  825. XmlElement* configsGroup = projectXml.createNewChildElement ("ItemGroup");
  826. configsGroup->setAttribute ("Label", "ProjectConfigurations");
  827. for (ConstConfigIterator config (*this); config.next();)
  828. {
  829. XmlElement* e = configsGroup->createNewChildElement ("ProjectConfiguration");
  830. e->setAttribute ("Include", createConfigName (*config));
  831. e->createNewChildElement ("Configuration")->addTextElement (config->getName());
  832. e->createNewChildElement ("Platform")->addTextElement (is64Bit (*config) ? "x64" : "Win32");
  833. }
  834. }
  835. {
  836. XmlElement* globals = projectXml.createNewChildElement ("PropertyGroup");
  837. globals->setAttribute ("Label", "Globals");
  838. globals->createNewChildElement ("ProjectGuid")->addTextElement (projectGUID);
  839. }
  840. {
  841. XmlElement* imports = projectXml.createNewChildElement ("Import");
  842. imports->setAttribute ("Project", "$(VCTargetsPath)\\Microsoft.Cpp.Default.props");
  843. }
  844. for (ConstConfigIterator i (*this); i.next();)
  845. {
  846. const MSVCBuildConfiguration& config = dynamic_cast <const MSVCBuildConfiguration&> (*i);
  847. XmlElement* e = projectXml.createNewChildElement ("PropertyGroup");
  848. setConditionAttribute (*e, config);
  849. e->setAttribute ("Label", "Configuration");
  850. e->createNewChildElement ("ConfigurationType")->addTextElement (getProjectType());
  851. e->createNewChildElement ("UseOfMfc")->addTextElement ("false");
  852. e->createNewChildElement ("CharacterSet")->addTextElement ("MultiByte");
  853. if (! (config.isDebug() || config.shouldDisableWholeProgramOpt()))
  854. e->createNewChildElement ("WholeProgramOptimization")->addTextElement ("true");
  855. if (is64Bit (config))
  856. e->createNewChildElement ("PlatformToolset")->addTextElement ("Windows7.1SDK");
  857. }
  858. {
  859. XmlElement* e = projectXml.createNewChildElement ("Import");
  860. e->setAttribute ("Project", "$(VCTargetsPath)\\Microsoft.Cpp.props");
  861. }
  862. {
  863. XmlElement* e = projectXml.createNewChildElement ("ImportGroup");
  864. e->setAttribute ("Label", "ExtensionSettings");
  865. }
  866. {
  867. XmlElement* e = projectXml.createNewChildElement ("ImportGroup");
  868. e->setAttribute ("Label", "PropertySheets");
  869. XmlElement* p = e->createNewChildElement ("Import");
  870. p->setAttribute ("Project", "$(UserRootDir)\\Microsoft.Cpp.$(Platform).user.props");
  871. p->setAttribute ("Condition", "exists('$(UserRootDir)\\Microsoft.Cpp.$(Platform).user.props')");
  872. p->setAttribute ("Label", "LocalAppDataPlatform");
  873. }
  874. {
  875. XmlElement* e = projectXml.createNewChildElement ("PropertyGroup");
  876. e->setAttribute ("Label", "UserMacros");
  877. }
  878. {
  879. XmlElement* props = projectXml.createNewChildElement ("PropertyGroup");
  880. props->createNewChildElement ("_ProjectFileVersion")->addTextElement ("10.0.30319.1");
  881. for (ConstConfigIterator i (*this); i.next();)
  882. {
  883. const MSVCBuildConfiguration& config = dynamic_cast <const MSVCBuildConfiguration&> (*i);
  884. {
  885. XmlElement* outdir = props->createNewChildElement ("OutDir");
  886. setConditionAttribute (*outdir, config);
  887. outdir->addTextElement (getConfigTargetPath (config) + "\\");
  888. }
  889. {
  890. XmlElement* intdir = props->createNewChildElement ("IntDir");
  891. setConditionAttribute (*intdir, config);
  892. intdir->addTextElement (getIntermediatesPath (config) + "\\");
  893. }
  894. {
  895. XmlElement* name = props->createNewChildElement ("TargetName");
  896. setConditionAttribute (*name, config);
  897. name->addTextElement (config.getOutputFilename (String::empty, true));
  898. }
  899. {
  900. XmlElement* manifest = props->createNewChildElement ("GenerateManifest");
  901. setConditionAttribute (*manifest, config);
  902. manifest->addTextElement (config.shouldGenerateManifest() ? "true" : "false");
  903. }
  904. const StringArray librarySearchPaths (config.getLibrarySearchPaths());
  905. if (librarySearchPaths.size() > 0)
  906. {
  907. XmlElement* libPath = props->createNewChildElement ("LibraryPath");
  908. setConditionAttribute (*libPath, config);
  909. libPath->addTextElement ("$(LibraryPath);" + librarySearchPaths.joinIntoString (";"));
  910. }
  911. }
  912. }
  913. for (ConstConfigIterator i (*this); i.next();)
  914. {
  915. const MSVCBuildConfiguration& config = dynamic_cast <const MSVCBuildConfiguration&> (*i);
  916. const bool isDebug = config.isDebug();
  917. XmlElement* group = projectXml.createNewChildElement ("ItemDefinitionGroup");
  918. setConditionAttribute (*group, config);
  919. {
  920. XmlElement* midl = group->createNewChildElement ("Midl");
  921. midl->createNewChildElement ("PreprocessorDefinitions")->addTextElement (isDebug ? "_DEBUG;%(PreprocessorDefinitions)"
  922. : "NDEBUG;%(PreprocessorDefinitions)");
  923. midl->createNewChildElement ("MkTypLibCompatible")->addTextElement ("true");
  924. midl->createNewChildElement ("SuppressStartupBanner")->addTextElement ("true");
  925. midl->createNewChildElement ("TargetEnvironment")->addTextElement ("Win32");
  926. midl->createNewChildElement ("HeaderFileName");
  927. }
  928. {
  929. XmlElement* cl = group->createNewChildElement ("ClCompile");
  930. const int optimiseLevel = config.getOptimisationLevelInt();
  931. cl->createNewChildElement ("Optimization")->addTextElement (optimiseLevel <= 1 ? "Disabled"
  932. : optimiseLevel == 2 ? "MinSpace"
  933. : "MaxSpeed");
  934. if (isDebug && optimiseLevel <= 1)
  935. cl->createNewChildElement ("DebugInformationFormat")->addTextElement (is64Bit (config) ? "ProgramDatabase"
  936. : "EditAndContinue");
  937. StringArray includePaths (getHeaderSearchPaths (config));
  938. includePaths.add ("%(AdditionalIncludeDirectories)");
  939. cl->createNewChildElement ("AdditionalIncludeDirectories")->addTextElement (includePaths.joinIntoString (";"));
  940. cl->createNewChildElement ("PreprocessorDefinitions")->addTextElement (getPreprocessorDefs (config, ";") + ";%(PreprocessorDefinitions)");
  941. cl->createNewChildElement ("RuntimeLibrary")->addTextElement (config.isUsingRuntimeLibDLL() ? (isDebug ? "MultiThreadedDebugDLL" : "MultiThreadedDLL")
  942. : (isDebug ? "MultiThreadedDebug" : "MultiThreaded"));
  943. cl->createNewChildElement ("RuntimeTypeInfo")->addTextElement ("true");
  944. cl->createNewChildElement ("PrecompiledHeader");
  945. cl->createNewChildElement ("AssemblerListingLocation")->addTextElement ("$(IntDir)\\");
  946. cl->createNewChildElement ("ObjectFileName")->addTextElement ("$(IntDir)\\");
  947. cl->createNewChildElement ("ProgramDataBaseFileName")->addTextElement ("$(IntDir)\\");
  948. cl->createNewChildElement ("WarningLevel")->addTextElement ("Level" + String (getWarningLevel (config)));
  949. cl->createNewChildElement ("SuppressStartupBanner")->addTextElement ("true");
  950. cl->createNewChildElement ("MultiProcessorCompilation")->addTextElement ("true");
  951. const String extraFlags (replacePreprocessorTokens (config, getExtraCompilerFlagsString()).trim());
  952. if (extraFlags.isNotEmpty())
  953. cl->createNewChildElement ("AdditionalOptions")->addTextElement (extraFlags + " %(AdditionalOptions)");
  954. }
  955. {
  956. XmlElement* res = group->createNewChildElement ("ResourceCompile");
  957. res->createNewChildElement ("PreprocessorDefinitions")->addTextElement (isDebug ? "_DEBUG;%(PreprocessorDefinitions)"
  958. : "NDEBUG;%(PreprocessorDefinitions)");
  959. }
  960. {
  961. XmlElement* link = group->createNewChildElement ("Link");
  962. link->createNewChildElement ("OutputFile")->addTextElement (getOutDirFile (config.getOutputFilename (msvcTargetSuffix, false)));
  963. link->createNewChildElement ("SuppressStartupBanner")->addTextElement ("true");
  964. link->createNewChildElement ("IgnoreSpecificDefaultLibraries")->addTextElement (isDebug ? "libcmt.lib; msvcrt.lib;;%(IgnoreSpecificDefaultLibraries)"
  965. : "%(IgnoreSpecificDefaultLibraries)");
  966. link->createNewChildElement ("GenerateDebugInformation")->addTextElement ((isDebug || config.shouldGenerateDebugSymbols()) ? "true" : "false");
  967. link->createNewChildElement ("ProgramDatabaseFile")->addTextElement (getIntDirFile (config.getOutputFilename (".pdb", true)));
  968. link->createNewChildElement ("SubSystem")->addTextElement (msvcIsWindowsSubsystem ? "Windows" : "Console");
  969. if (! is64Bit (config))
  970. link->createNewChildElement ("TargetMachine")->addTextElement ("MachineX86");
  971. if (! isDebug)
  972. {
  973. link->createNewChildElement ("OptimizeReferences")->addTextElement ("true");
  974. link->createNewChildElement ("EnableCOMDATFolding")->addTextElement ("true");
  975. }
  976. const StringArray librarySearchPaths (config.getLibrarySearchPaths());
  977. if (librarySearchPaths.size() > 0)
  978. link->createNewChildElement ("AdditionalLibraryDirectories")->addTextElement (replacePreprocessorTokens (config, librarySearchPaths.joinIntoString (";"))
  979. + ";%(AdditionalLibraryDirectories)");
  980. String externalLibraries (getExternalLibrariesString());
  981. if (externalLibraries.isNotEmpty())
  982. link->createNewChildElement ("AdditionalDependencies")->addTextElement (replacePreprocessorTokens (config, externalLibraries).trim()
  983. + ";%(AdditionalDependencies)");
  984. String extraLinkerOptions (getExtraLinkerFlagsString());
  985. if (extraLinkerOptions.isNotEmpty())
  986. link->createNewChildElement ("AdditionalOptions")->addTextElement (replacePreprocessorTokens (config, extraLinkerOptions).trim()
  987. + " %(AdditionalOptions)");
  988. if (msvcDelayLoadedDLLs.isNotEmpty())
  989. link->createNewChildElement ("DelayLoadDLLs")->addTextElement (msvcDelayLoadedDLLs);
  990. if (config.config [Ids::msvcModuleDefinitionFile].toString().isNotEmpty())
  991. link->createNewChildElement ("ModuleDefinitionFile")
  992. ->addTextElement (config.config [Ids::msvcModuleDefinitionFile].toString());
  993. }
  994. {
  995. XmlElement* bsc = group->createNewChildElement ("Bscmake");
  996. bsc->createNewChildElement ("SuppressStartupBanner")->addTextElement ("true");
  997. bsc->createNewChildElement ("OutputFile")->addTextElement (getIntDirFile (config.getOutputFilename (".bsc", true)));
  998. }
  999. if (config.getPrebuildCommandString().isNotEmpty())
  1000. group->createNewChildElement ("PreBuildEvent")
  1001. ->createNewChildElement ("Command")
  1002. ->addTextElement (config.getPrebuildCommandString());
  1003. if (config.getPostbuildCommandString().isNotEmpty())
  1004. group->createNewChildElement ("PostBuildEvent")
  1005. ->createNewChildElement ("Command")
  1006. ->addTextElement (config.getPostbuildCommandString());
  1007. }
  1008. ScopedPointer<XmlElement> otherFilesGroup (new XmlElement ("ItemGroup"));
  1009. {
  1010. XmlElement* cppFiles = projectXml.createNewChildElement ("ItemGroup");
  1011. XmlElement* headerFiles = projectXml.createNewChildElement ("ItemGroup");
  1012. for (int i = 0; i < getAllGroups().size(); ++i)
  1013. {
  1014. const Project::Item& group = getAllGroups().getReference(i);
  1015. if (group.getNumChildren() > 0)
  1016. addFilesToCompile (group, *cppFiles, *headerFiles, *otherFilesGroup);
  1017. }
  1018. }
  1019. if (iconFile != File::nonexistent)
  1020. {
  1021. XmlElement* e = otherFilesGroup->createNewChildElement ("None");
  1022. e->setAttribute ("Include", prependDot (iconFile.getFileName()));
  1023. }
  1024. if (otherFilesGroup->getFirstChildElement() != nullptr)
  1025. projectXml.addChildElement (otherFilesGroup.release());
  1026. if (hasResourceFile())
  1027. {
  1028. XmlElement* rcGroup = projectXml.createNewChildElement ("ItemGroup");
  1029. XmlElement* e = rcGroup->createNewChildElement ("ResourceCompile");
  1030. e->setAttribute ("Include", prependDot (rcFile.getFileName()));
  1031. }
  1032. {
  1033. XmlElement* e = projectXml.createNewChildElement ("Import");
  1034. e->setAttribute ("Project", "$(VCTargetsPath)\\Microsoft.Cpp.targets");
  1035. }
  1036. {
  1037. XmlElement* e = projectXml.createNewChildElement ("ImportGroup");
  1038. e->setAttribute ("Label", "ExtensionTargets");
  1039. }
  1040. }
  1041. String getProjectType() const
  1042. {
  1043. if (projectType.isGUIApplication() || projectType.isCommandLineApp()) return "Application";
  1044. if (isLibraryDLL()) return "DynamicLibrary";
  1045. if (projectType.isLibrary()) return "StaticLibrary";
  1046. jassertfalse;
  1047. return String::empty;
  1048. }
  1049. //==============================================================================
  1050. void addFilesToCompile (const Project::Item& projectItem, XmlElement& cpps, XmlElement& headers, XmlElement& otherFiles) const
  1051. {
  1052. if (projectItem.isGroup())
  1053. {
  1054. for (int i = 0; i < projectItem.getNumChildren(); ++i)
  1055. addFilesToCompile (projectItem.getChild(i), cpps, headers, otherFiles);
  1056. }
  1057. else if (projectItem.shouldBeAddedToTargetProject())
  1058. {
  1059. const RelativePath path (projectItem.getFile(), getTargetFolder(), RelativePath::buildTargetFolder);
  1060. jassert (path.getRoot() == RelativePath::buildTargetFolder);
  1061. if (path.hasFileExtension ("cpp;cc;cxx;c"))
  1062. {
  1063. XmlElement* e = cpps.createNewChildElement ("ClCompile");
  1064. e->setAttribute ("Include", path.toWindowsStyle());
  1065. if (! projectItem.shouldBeCompiled())
  1066. e->createNewChildElement ("ExcludedFromBuild")->addTextElement ("true");
  1067. if (projectItem.shouldUseStdCall())
  1068. e->createNewChildElement ("CallingConvention")->addTextElement ("StdCall");
  1069. }
  1070. else if (path.hasFileExtension (headerFileExtensions))
  1071. {
  1072. headers.createNewChildElement ("ClInclude")->setAttribute ("Include", path.toWindowsStyle());
  1073. }
  1074. else if (! path.hasFileExtension ("mm;m"))
  1075. {
  1076. otherFiles.createNewChildElement ("None")->setAttribute ("Include", path.toWindowsStyle());
  1077. }
  1078. }
  1079. }
  1080. //==============================================================================
  1081. void addFilterGroup (XmlElement& groups, const String& path) const
  1082. {
  1083. XmlElement* e = groups.createNewChildElement ("Filter");
  1084. e->setAttribute ("Include", path);
  1085. e->createNewChildElement ("UniqueIdentifier")->addTextElement (createGUID (path + "_guidpathsaltxhsdf"));
  1086. }
  1087. void addFileToFilter (const RelativePath& file, const String& groupPath,
  1088. XmlElement& cpps, XmlElement& headers, XmlElement& otherFiles) const
  1089. {
  1090. XmlElement* e;
  1091. if (file.hasFileExtension (headerFileExtensions))
  1092. e = headers.createNewChildElement ("ClInclude");
  1093. else if (file.hasFileExtension (sourceFileExtensions))
  1094. e = cpps.createNewChildElement ("ClCompile");
  1095. else
  1096. e = otherFiles.createNewChildElement ("None");
  1097. jassert (file.getRoot() == RelativePath::buildTargetFolder);
  1098. e->setAttribute ("Include", file.toWindowsStyle());
  1099. e->createNewChildElement ("Filter")->addTextElement (groupPath);
  1100. }
  1101. void addFilesToFilter (const Project::Item& projectItem, const String& path,
  1102. XmlElement& cpps, XmlElement& headers, XmlElement& otherFiles, XmlElement& groups) const
  1103. {
  1104. if (projectItem.isGroup())
  1105. {
  1106. addFilterGroup (groups, path);
  1107. for (int i = 0; i < projectItem.getNumChildren(); ++i)
  1108. addFilesToFilter (projectItem.getChild(i),
  1109. (path.isEmpty() ? String::empty : (path + "\\")) + projectItem.getChild(i).getName(),
  1110. cpps, headers, otherFiles, groups);
  1111. }
  1112. else if (projectItem.shouldBeAddedToTargetProject())
  1113. {
  1114. addFileToFilter (RelativePath (projectItem.getFile(), getTargetFolder(), RelativePath::buildTargetFolder),
  1115. path.upToLastOccurrenceOf ("\\", false, false), cpps, headers, otherFiles);
  1116. }
  1117. }
  1118. void addFilesToFilter (const Array<RelativePath>& files, const String& path,
  1119. XmlElement& cpps, XmlElement& headers, XmlElement& otherFiles, XmlElement& groups)
  1120. {
  1121. if (files.size() > 0)
  1122. {
  1123. addFilterGroup (groups, path);
  1124. for (int i = 0; i < files.size(); ++i)
  1125. addFileToFilter (files.getReference(i), path, cpps, headers, otherFiles);
  1126. }
  1127. }
  1128. void fillInFiltersXml (XmlElement& filterXml) const
  1129. {
  1130. filterXml.setAttribute ("ToolsVersion", "4.0");
  1131. filterXml.setAttribute ("xmlns", "http://schemas.microsoft.com/developer/msbuild/2003");
  1132. XmlElement* groupsXml = filterXml.createNewChildElement ("ItemGroup");
  1133. XmlElement* cpps = filterXml.createNewChildElement ("ItemGroup");
  1134. XmlElement* headers = filterXml.createNewChildElement ("ItemGroup");
  1135. ScopedPointer<XmlElement> otherFilesGroup (new XmlElement ("ItemGroup"));
  1136. for (int i = 0; i < getAllGroups().size(); ++i)
  1137. {
  1138. const Project::Item& group = getAllGroups().getReference(i);
  1139. if (group.getNumChildren() > 0)
  1140. addFilesToFilter (group, group.getName(), *cpps, *headers, *otherFilesGroup, *groupsXml);
  1141. }
  1142. if (iconFile.exists())
  1143. {
  1144. XmlElement* e = otherFilesGroup->createNewChildElement ("None");
  1145. e->setAttribute ("Include", prependDot (iconFile.getFileName()));
  1146. e->createNewChildElement ("Filter")->addTextElement (ProjectSaver::getJuceCodeGroupName());
  1147. }
  1148. if (otherFilesGroup->getFirstChildElement() != nullptr)
  1149. filterXml.addChildElement (otherFilesGroup.release());
  1150. if (hasResourceFile())
  1151. {
  1152. XmlElement* rcGroup = filterXml.createNewChildElement ("ItemGroup");
  1153. XmlElement* e = rcGroup->createNewChildElement ("ResourceCompile");
  1154. e->setAttribute ("Include", prependDot (rcFile.getFileName()));
  1155. e->createNewChildElement ("Filter")->addTextElement (ProjectSaver::getJuceCodeGroupName());
  1156. }
  1157. }
  1158. //==============================================================================
  1159. JUCE_DECLARE_NON_COPYABLE (MSVCProjectExporterVC2010);
  1160. };
  1161. #endif // __JUCER_PROJECTEXPORT_MSVC_JUCEHEADER__