diff --git a/extras/Projucer/Source/Project Saving/jucer_ProjectExport_AndroidAnt.h b/extras/Projucer/Source/Project Saving/jucer_ProjectExport_AndroidAnt.h index e3b3907e70..5fa6efc61a 100644 --- a/extras/Projucer/Source/Project Saving/jucer_ProjectExport_AndroidAnt.h +++ b/extras/Projucer/Source/Project Saving/jucer_ProjectExport_AndroidAnt.h @@ -36,11 +36,19 @@ public: bool isAndroidStudio() const override { return false; } bool isAndroidAnt() const override { return true; } - bool supportsVST() const override { return false; } - bool supportsVST3() const override { return false; } - bool supportsAAX() const override { return false; } - bool supportsRTAS() const override { return false; } - bool supportsStandalone() const override { return false; } + bool supportsTargetType (ProjectType::Target::Type type) const override + { + switch (type) + { + case ProjectType::Target::GUIApp: + case ProjectType::Target::StaticLibrary: + return true; + default: + break; + } + + return false; + } //============================================================================== static const char* getName() { return "Android Ant Project"; } @@ -340,7 +348,7 @@ private: flags << " -std=gnu++11"; - defines = mergePreprocessorDefs (defines, getAllPreprocessorDefs (config)); + defines = mergePreprocessorDefs (defines, getAllPreprocessorDefs ()); return flags + createGCCPreprocessorFlags (defines); } diff --git a/extras/Projucer/Source/Project Saving/jucer_ProjectExport_AndroidBase.h b/extras/Projucer/Source/Project Saving/jucer_ProjectExport_AndroidBase.h index aad706fb84..2ca853d335 100644 --- a/extras/Projucer/Source/Project Saving/jucer_ProjectExport_AndroidBase.h +++ b/extras/Projucer/Source/Project Saving/jucer_ProjectExport_AndroidBase.h @@ -58,13 +58,19 @@ public: bool isOSX() const override { return false; } bool isiOS() const override { return false; } - bool supportsVST() const override { return false; } - bool supportsVST3() const override { return false; } - bool supportsAAX() const override { return false; } - bool supportsRTAS() const override { return false; } - bool supportsAU() const override { return false; } - bool supportsAUv3() const override { return false; } - bool supportsStandalone() const override { return false; } + bool supportsTargetType (ProjectType::Target::Type type) const override + { + switch (type) + { + case ProjectType::Target::GUIApp: + case ProjectType::Target::StaticLibrary: + return true; + default: + break; + } + + return false; + } //============================================================================== void create (const OwnedArray& modules) const override diff --git a/extras/Projucer/Source/Project Saving/jucer_ProjectExport_AndroidStudio.h b/extras/Projucer/Source/Project Saving/jucer_ProjectExport_AndroidStudio.h index 587d622769..1081ae6959 100644 --- a/extras/Projucer/Source/Project Saving/jucer_ProjectExport_AndroidStudio.h +++ b/extras/Projucer/Source/Project Saving/jucer_ProjectExport_AndroidStudio.h @@ -51,7 +51,7 @@ public: AndroidStudioProjectExporter (Project& p, const ValueTree& t) : AndroidProjectExporterBase (p, t), gradleVersion (settings, Ids::gradleVersion, nullptr, "2.14.1"), - gradleWrapperVersion (settings, Ids::gradleWrapperVersion, nullptr, "0.8.1"), + gradleWrapperVersion (settings, Ids::androidPluginVersion, nullptr, "0.8.1"), gradleToolchain (settings, Ids::gradleToolchain, nullptr, "clang"), buildToolsVersion (settings, Ids::buildToolsVersion, nullptr, "23.0.2"), androidStudioExecutable (findAndroidStudioExecutable()) diff --git a/extras/Projucer/Source/Project Saving/jucer_ProjectExport_CodeBlocks.h b/extras/Projucer/Source/Project Saving/jucer_ProjectExport_CodeBlocks.h index 5e2df15728..f125e6d04a 100644 --- a/extras/Projucer/Source/Project Saving/jucer_ProjectExport_CodeBlocks.h +++ b/extras/Projucer/Source/Project Saving/jucer_ProjectExport_CodeBlocks.h @@ -113,13 +113,25 @@ public: bool isOSX() const override { return false; } bool isiOS() const override { return false; } - bool supportsVST() const override { return false; } - bool supportsVST3() const override { return false; } - bool supportsAAX() const override { return false; } - bool supportsRTAS() const override { return false; } - bool supportsAU() const override { return false; } - bool supportsAUv3() const override { return false; } - bool supportsStandalone() const override { return false; } + bool supportsTargetType (ProjectType::Target::Type type) const override + { + switch (type) + { + case ProjectType::Target::StandalonePlugIn: + case ProjectType::Target::GUIApp: + case ProjectType::Target::ConsoleApp: + case ProjectType::Target::StaticLibrary: + case ProjectType::Target::SharedCodeTarget: + case ProjectType::Target::AggregateTarget: + case ProjectType::Target::VSTPlugIn: + case ProjectType::Target::DynamicLibrary: + return true; + default: + break; + } + + return false; + } void createExporterProperties (PropertyListBuilder&) override { @@ -138,9 +150,30 @@ public: } //============================================================================== - void addPlatformSpecificSettingsForProjectType (const ProjectType& type) override + void addPlatformSpecificSettingsForProjectType (const ProjectType&) override { - createDynamicLibrary = type.isAudioPlugin() || type.isDynamicLibrary(); + // add shared code target first as order matters for Codeblocks + if (shouldBuildTargetType (ProjectType::Target::SharedCodeTarget)) + targets.add (new CodeBlocksTarget (*this, ProjectType::Target::SharedCodeTarget)); + + //ProjectType::Target::SharedCodeTarget + callForAllSupportedTargets ([this] (ProjectType::Target::Type targetType) + { + if (targetType == ProjectType::Target::SharedCodeTarget) + return; + + if (auto* target = new CodeBlocksTarget (*this, targetType)) + { + if (targetType == ProjectType::Target::AggregateTarget) + targets.insert (0, target); + else + targets.add (target); + } + }); + + // If you hit this assert, you tried to generate a project for an exporter + // that does not support any of your targets! + jassert (targets.size() > 0); } private: @@ -151,14 +184,52 @@ private: CodeBlocksBuildConfiguration (Project& p, const ValueTree& settings, const ProjectExporter& e) : BuildConfiguration (p, settings, e) { + if (getArchitectureType().toString().isEmpty()) + getArchitectureType() = static_cast ("-m64"); + } + + Value getArchitectureType() + { + const auto archID = exporter.isWindows() ? Ids::windowsCodeBlocksArchitecture + : Ids::linuxCodeBlocksArchitecture; + return getValue (archID); + } + var getArchitectureTypeVar() const + { + const auto archID = exporter.isWindows() ? Ids::windowsCodeBlocksArchitecture + : Ids::linuxCodeBlocksArchitecture; + return config [archID]; } + var getDefaultOptimisationLevel() const override { return var ((int) (isDebug() ? gccO0 : gccO3)); } + void createConfigProperties (PropertyListBuilder& props) override { addGCCOptimisationProperty (props); + + static const char* const archNames[] = { "32-bit (-m32)", "64-bit (-m64)", "ARM v6", "ARM v7" }; + const var archFlags[] = { "-m32", "-m64", "-march=armv6", "-march=armv7" }; + + props.add (new ChoicePropertyComponent (getArchitectureType(), "Architecture", + StringArray (archNames, numElementsInArray (archNames)), + Array (archFlags, numElementsInArray (archFlags)))); } - var getDefaultOptimisationLevel() const override { return var ((int) (isDebug() ? gccO0 : gccO3)); } + String getLibrarySubdirPath () const override + { + const String archFlag = getArchitectureTypeVar(); + + const auto prefix = String ("-march="); + if (archFlag.startsWith (prefix)) + return String ("/") + archFlag.substring (prefix.length()); + else if (archFlag == "-m64") + return "/x86_64"; + else if (archFlag == "-m32") + return "/i386"; + + jassertfalse; + return String(); + } }; BuildConfiguration::Ptr createBuildConfig (const ValueTree& tree) const override @@ -166,6 +237,59 @@ private: return new CodeBlocksBuildConfiguration (project, tree, *this); } + //============================================================================== + class CodeBlocksTarget : public ProjectType::Target + { + public: + CodeBlocksTarget (CodeBlocksProjectExporter&, ProjectType::Target::Type typeToUse) + : ProjectType::Target (typeToUse) + {} + + String getTargetNameForConfiguration (const BuildConfiguration& config) const + { + if (type == ProjectType::Target::AggregateTarget) + return config.getName(); + + return getName() + String (" | ") + config.getName(); + } + + String getTargetSuffix() const + { + const ProjectType::Target::TargetFileType fileType = getTargetFileType(); + + switch (fileType) + { + case executable: + return ""; + case staticLibrary: + return ".a"; + case sharedLibraryOrDLL: + return ".so"; + case pluginBundle: + switch (type) + { + case VST3PlugIn: + return ".vst3"; + case VSTPlugIn: + return ".so"; + default: + break; + } + + return ".so"; + default: + break; + } + + return String(); + } + + bool isDynamicLibrary() const + { + return (type == DynamicLibrary || type == VST3PlugIn || type == VSTPlugIn || type == AAXPlugIn); + } + }; + //============================================================================== void addVersion (XmlElement& xml) const { @@ -181,7 +305,7 @@ private: xml.createNewChildElement ("Option")->setAttribute ("compiler", "gcc"); } - StringArray getDefines (const BuildConfiguration& config) const + StringArray getDefines (const BuildConfiguration& config, CodeBlocksTarget& target) const { StringPairArray defines; @@ -205,7 +329,7 @@ private: defines.set ("NDEBUG", "1"); } - defines = mergePreprocessorDefs (defines, getAllPreprocessorDefs (config)); + defines = mergePreprocessorDefs (defines, getAllPreprocessorDefs (config, target.type)); StringArray defs; for (int i = 0; i < defines.size(); ++i) @@ -214,9 +338,12 @@ private: return getCleanedStringArray (defs); } - StringArray getCompilerFlags (const BuildConfiguration& config) const + StringArray getCompilerFlags (const BuildConfiguration& config, CodeBlocksTarget& target) const { StringArray flags; + if (const auto codeBlocksConfig = dynamic_cast (&config)) + flags.add (codeBlocksConfig->getArchitectureTypeVar()); + flags.add ("-O" + config.getGCCOptimisationFlag()); flags.add ("-std=c++11"); flags.add ("-mstackrealign"); @@ -228,7 +355,7 @@ private: " \n", "\"'"); { - const StringArray defines (getDefines (config)); + const StringArray defines (getDefines (config, target)); for (int i = 0; i < defines.size(); ++i) { @@ -243,7 +370,7 @@ private: if (config.exporter.isLinux()) { - if (createDynamicLibrary) + if (target.isDynamicLibrary() || getProject().getProjectType().isAudioPlugin()) flags.add ("-fPIC"); if (linuxPackages.size() > 0) @@ -263,19 +390,25 @@ private: return getCleanedStringArray (flags); } - StringArray getLinkerFlags (const BuildConfiguration& config) const + StringArray getLinkerFlags (const BuildConfiguration& config, CodeBlocksTarget& target) const { StringArray flags (makefileExtraLinkerFlags); + if (const auto codeBlocksConfig = dynamic_cast (&config)) + flags.add (codeBlocksConfig->getArchitectureTypeVar()); + if (! config.isDebug()) flags.add ("-s"); flags.addTokens (replacePreprocessorTokens (config, getExtraLinkerFlagsString()).trim(), " \n", "\"'"); + if (getProject().getProjectType().isAudioPlugin() && target.type != ProjectType::Target::SharedCodeTarget) + flags.add ("-l" + config.getTargetBinaryNameString()); + if (config.exporter.isLinux() && linuxPackages.size() > 0) { - if (createDynamicLibrary) + if (target.isDynamicLibrary()) flags.add ("-shared"); auto pkgconfigLibs = String ("`pkg-config --libs"); @@ -303,80 +436,119 @@ private: return getCleanedStringArray (paths); } - static int getTypeIndex (const ProjectType& type) + static int getTypeIndex (const ProjectType::Target::Type& type) { - if (type.isGUIApplication()) return 0; - if (type.isCommandLineApp()) return 1; - if (type.isStaticLibrary()) return 2; - if (type.isDynamicLibrary()) return 3; - if (type.isAudioPlugin()) return 3; + switch (type) + { + case ProjectType::Target::GUIApp: + case ProjectType::Target::StandalonePlugIn: + return 0; + case ProjectType::Target::ConsoleApp: + return 1; + case ProjectType::Target::StaticLibrary: + case ProjectType::Target::SharedCodeTarget: + return 2; + case ProjectType::Target::DynamicLibrary: + case ProjectType::Target::VSTPlugIn: + case ProjectType::Target::VST3PlugIn: + return 3; + default: + break; + } + return 0; } - void createBuildTarget (XmlElement& xml, const BuildConfiguration& config) const + String getOutputPathForTarget (CodeBlocksTarget& target, const BuildConfiguration& config) const + { + String outputPath; + if (config.getTargetBinaryRelativePathString().isNotEmpty()) + { + RelativePath binaryPath (config.getTargetBinaryRelativePathString(), RelativePath::projectFolder); + binaryPath = binaryPath.rebased (projectFolder, getTargetFolder(), RelativePath::buildTargetFolder); + outputPath = config.getTargetBinaryRelativePathString(); + } + else + { + outputPath ="bin/" + File::createLegalFileName (config.getName().trim()); + } + + return outputPath + "/" + replacePreprocessorTokens (config, config.getTargetBinaryNameString() + target.getTargetSuffix()); + } + + String getSharedCodePath (const BuildConfiguration& config) const + { + const String outputPath = getOutputPathForTarget (getTargetWithType (ProjectType::Target::SharedCodeTarget), config); + RelativePath path (outputPath, RelativePath::buildTargetFolder); + + const String autoPrefixedFilename = "lib" + path.getFileName(); + return path.getParentDirectory().getChildFile (autoPrefixedFilename).toUnixStyle(); + } + + void createBuildTarget (XmlElement& xml, CodeBlocksTarget& target, const BuildConfiguration& config) const { - xml.setAttribute ("title", config.getName()); + xml.setAttribute ("title", target.getTargetNameForConfiguration (config)); { XmlElement* output = xml.createNewChildElement ("Option"); - String outputPath; - if (config.getTargetBinaryRelativePathString().isNotEmpty()) - { - RelativePath binaryPath (config.getTargetBinaryRelativePathString(), RelativePath::projectFolder); - binaryPath = binaryPath.rebased (projectFolder, getTargetFolder(), RelativePath::buildTargetFolder); - outputPath = config.getTargetBinaryRelativePathString(); - } - else - { - outputPath ="bin/" + File::createLegalFileName (config.getName().trim()); - } + output->setAttribute ("output", getOutputPathForTarget (target, config)); - output->setAttribute ("output", outputPath + "/" + replacePreprocessorTokens (config, config.getTargetBinaryNameString())); + const bool keepPrefix = (target.type == ProjectType::Target::VSTPlugIn || target.type == ProjectType::Target::VST3PlugIn + || target.type == ProjectType::Target::AAXPlugIn || target.type == ProjectType::Target::RTASPlugIn); - output->setAttribute ("prefix_auto", 1); - output->setAttribute ("extension_auto", 1); + output->setAttribute ("prefix_auto", keepPrefix ? 0 : 1); + output->setAttribute ("extension_auto", 0); } xml.createNewChildElement ("Option") ->setAttribute ("object_output", "obj/" + File::createLegalFileName (config.getName().trim())); - xml.createNewChildElement ("Option")->setAttribute ("type", getTypeIndex (project.getProjectType())); + xml.createNewChildElement ("Option")->setAttribute ("type", getTypeIndex (target.type)); xml.createNewChildElement ("Option")->setAttribute ("compiler", "gcc"); + if (getProject().getProjectType().isAudioPlugin() && target.type != ProjectType::Target::SharedCodeTarget) + xml.createNewChildElement ("Option")->setAttribute ("external_deps", getSharedCodePath (config)); + { XmlElement* const compiler = xml.createNewChildElement ("Compiler"); { - const StringArray compilerFlags (getCompilerFlags (config)); + const StringArray compilerFlags (getCompilerFlags (config, target)); - for (int i = 0; i < compilerFlags.size(); ++i) - setAddOption (*compiler, "option", compilerFlags[i]); + for (auto flag : compilerFlags) + setAddOption (*compiler, "option", flag); } { const StringArray includePaths (getIncludePaths (config)); - for (int i = 0; i < includePaths.size(); ++i) - setAddOption (*compiler, "directory", includePaths[i]); + for (auto path : includePaths) + setAddOption (*compiler, "directory", path); } } { XmlElement* const linker = xml.createNewChildElement ("Linker"); - const StringArray linkerFlags (getLinkerFlags (config)); - for (int i = 0; i < linkerFlags.size(); ++i) - setAddOption (*linker, "option", linkerFlags[i]); + const StringArray linkerFlags (getLinkerFlags (config, target)); + for (auto flag : linkerFlags) + setAddOption (*linker, "option", flag); const StringArray& libs = isWindows() ? mingwLibs : linuxLibs; - for (int i = 0; i < libs.size(); ++i) - setAddOption (*linker, "library", libs[i]); + for (auto lib : libs) + setAddOption (*linker, "library", lib); - const StringArray librarySearchPaths (config.getLibrarySearchPaths()); - for (int i = 0; i < librarySearchPaths.size(); ++i) - setAddOption (*linker, "directory", replacePreprocessorDefs (getAllPreprocessorDefs(), librarySearchPaths[i])); + StringArray librarySearchPaths (config.getLibrarySearchPaths()); + + if (getProject().getProjectType().isAudioPlugin() && target.type != ProjectType::Target::SharedCodeTarget) + librarySearchPaths.add (RelativePath (getSharedCodePath (config), RelativePath::buildTargetFolder).getParentDirectory().toUnixStyle()); + + for (auto path : librarySearchPaths) + { + setAddOption (*linker, "directory", replacePreprocessorDefs (getAllPreprocessorDefs(), path)); + } } } @@ -385,7 +557,36 @@ private: XmlElement* const build = xml.createNewChildElement ("Build"); for (ConstConfigIterator config (*this); config.next();) - createBuildTarget (*build->createNewChildElement ("Target"), *config); + { + for (auto target : targets) + if (target->type != ProjectType::Target::AggregateTarget) + createBuildTarget (*build->createNewChildElement ("Target"), *target, *config); + } + } + + void addVirtualTargets (XmlElement& xml) const + { + XmlElement* const virtualTargets = xml.createNewChildElement ("VirtualTargets"); + + for (ConstConfigIterator config (*this); config.next();) + { + StringArray allTargets; + + for (auto target : targets) + if (target->type != ProjectType::Target::AggregateTarget) + allTargets.add (target->getTargetNameForConfiguration (*config)); + + for (auto target : targets) + { + if (target->type == ProjectType::Target::AggregateTarget) + { + auto* configTarget = virtualTargets->createNewChildElement ("Add"); + + configTarget->setAttribute ("alias", config->getName()); + configTarget->setAttribute ("targets", allTargets.joinIntoString (";")); + } + } + } } void addProjectCompilerOptions (XmlElement& xml) const @@ -416,6 +617,54 @@ private: setAddOption (*linker, "library", replacePreprocessorDefs (getAllPreprocessorDefs(), libs[i])); } + CodeBlocksTarget& getTargetWithType (ProjectType::Target::Type type) const + { + CodeBlocksTarget* nonAggregrateTarget = nullptr; + + for (auto* target : targets) + { + if (target->type == type) + return *target; + + if (target->type != ProjectType::Target::AggregateTarget) + nonAggregrateTarget = target; + } + + // this project has no valid targets + jassert (nonAggregrateTarget != nullptr); + + return *nonAggregrateTarget; + } + + // Returns SharedCode target for multi-target projects, otherwise it returns + // the single target + CodeBlocksTarget& getMainTarget() const + { + if (getProject().getProjectType().isAudioPlugin()) + return getTargetWithType (ProjectType::Target::SharedCodeTarget); + + for (auto* target : targets) + if (target->type != ProjectType::Target::AggregateTarget) + return *target; + + jassertfalse; + + return *targets[0]; + } + + CodeBlocksTarget& getTargetForProjectItem (const Project::Item& projectItem) const + { + if (getProject().getProjectType().isAudioPlugin()) + { + if (! projectItem.shouldBeCompiled()) + return getTargetWithType (ProjectType::Target::SharedCodeTarget); + + return getTargetWithType (getProject().getTargetTypeFromFilePath (projectItem.getFile(), true)); + } + + return getMainTarget(); + } + void addCompileUnits (const Project::Item& projectItem, XmlElement& xml) const { if (projectItem.isGroup()) @@ -430,10 +679,16 @@ private: XmlElement* unit = xml.createNewChildElement ("Unit"); unit->setAttribute ("filename", file.toUnixStyle()); + for (ConstConfigIterator config (*this); config.next();) + { + const String& targetName = getTargetForProjectItem (projectItem).getTargetNameForConfiguration (*config); + unit->createNewChildElement ("Option")->setAttribute ("target", targetName); + } + if (! projectItem.shouldBeCompiled()) { - unit->createNewChildElement("Option")->setAttribute ("compile", 0); - unit->createNewChildElement("Option")->setAttribute ("link", 0); + unit->createNewChildElement ("Option")->setAttribute ("compile", 0); + unit->createNewChildElement ("Option")->setAttribute ("link", 0); } } } @@ -448,6 +703,7 @@ private: { addOptions (xml); addBuild (xml); + addVirtualTargets (xml); addProjectCompilerOptions (xml); addProjectLinkerOptions (xml); addCompileUnits (xml); @@ -473,7 +729,8 @@ private: } CodeBlocksOS os; - bool createDynamicLibrary = false; + + OwnedArray targets; JUCE_DECLARE_NON_COPYABLE (CodeBlocksProjectExporter) }; diff --git a/extras/Projucer/Source/Project Saving/jucer_ProjectExport_MSVC.h b/extras/Projucer/Source/Project Saving/jucer_ProjectExport_MSVC.h index 54a90d33ef..76e12497ca 100644 --- a/extras/Projucer/Source/Project Saving/jucer_ProjectExport_MSVC.h +++ b/extras/Projucer/Source/Project Saving/jucer_ProjectExport_MSVC.h @@ -1,23 +1,23 @@ /* ============================================================================== - This file is part of the JUCE library. - Copyright (c) 2015 - ROLI Ltd. + This file is part of the JUCE library. + Copyright (c) 2015 - ROLI Ltd. - Permission is granted to use this software under the terms of either: - a) the GPL v2 (or any later version) - b) the Affero GPL v3 + Permission is granted to use this software under the terms of either: + a) the GPL v2 (or any later version) + b) the Affero GPL v3 - Details of these licenses can be found at: www.gnu.org/licenses + Details of these licenses can be found at: www.gnu.org/licenses - JUCE is distributed in the hope that it will be useful, but WITHOUT ANY - WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR - A PARTICULAR PURPOSE. See the GNU General Public License for more details. + JUCE is distributed in the hope that it will be useful, but WITHOUT ANY + WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR + A PARTICULAR PURPOSE. See the GNU General Public License for more details. - ------------------------------------------------------------------------------ + ------------------------------------------------------------------------------ - To release a closed-source product which uses JUCE, commercial licenses are - available: visit www.juce.com for more information. + To release a closed-source product which uses JUCE, commercial licenses are + available: visit www.juce.com for more information. ============================================================================== */ @@ -31,338 +31,11 @@ public: if (getTargetLocationString().isEmpty()) getTargetLocationValue() = getDefaultBuildsRootFolder() + folderName; - projectGUID = createGUID (project.getProjectUID()); updateOldSettings(); initialiseDependencyPathValues(); } - //============================================================================== - bool usesMMFiles() const override { return false; } - bool canCopeWithDuplicateFiles() override { return false; } - bool supportsUserDefinedConfigurations() const override { return true; } - - bool isXcode() const override { return false; } - bool isVisualStudio() const override { return true; } - bool isCodeBlocks() const override { return false; } - bool isMakefile() const override { return false; } - bool isAndroidStudio() const override { return false; } - bool isAndroidAnt() const override { return false; } - - bool isAndroid() const override { return false; } - bool isWindows() const override { return true; } - bool isLinux() const override { return false; } - bool isOSX() const override { return false; } - bool isiOS() const override { return false; } - - bool supportsVST() const override { return true; } - bool supportsVST3() const override { return true; } - bool supportsAAX() const override { return true; } - bool supportsRTAS() const override { return true; } - bool supportsAU() const override { return false; } - bool supportsAUv3() const override { return false; } - bool supportsStandalone() const override { return false; } - - //============================================================================== - virtual int getVisualStudioVersion() const = 0; - - bool launchProject() override - { - #if JUCE_WINDOWS - return getSLNFile().startAsProcess(); - #else - return false; - #endif - } - - bool canLaunchProject() override - { - #if JUCE_WINDOWS - return true; - #else - return false; - #endif - } - - void createExporterProperties (PropertyListBuilder&) override - { - } - - enum OptimisationLevel - { - optimisationOff = 1, - optimiseMinSize = 2, - optimiseMaxSpeed = 3 - }; - - //============================================================================== - void addPlatformSpecificSettingsForProjectType (const ProjectType& type) override - { - msvcExtraPreprocessorDefs.set ("_CRT_SECURE_NO_WARNINGS", ""); - - if (type.isGUIApplication()) - { - msvcIsWindowsSubsystem = true; - msvcTargetSuffix = ".exe"; - } - else if (type.isCommandLineApp()) - { - msvcIsWindowsSubsystem = false; - msvcTargetSuffix = ".exe"; - msvcExtraPreprocessorDefs.set ("_CONSOLE", ""); - } - else if (type.isStaticLibrary()) - { - msvcTargetSuffix = ".lib"; - msvcExtraPreprocessorDefs.set ("_LIB", ""); - } - else if (type.isDynamicLibrary()) - { - msvcTargetSuffix = ".dll"; - msvcExtraPreprocessorDefs.set ("_LIB", ""); - msvcIsDLL = true; - } - else if (type.isAudioPlugin()) - { - msvcTargetSuffix = ".dll"; - msvcIsDLL = true; - - if (project.shouldBuildVST().getValue()) - addVSTPluginSettings (false); - - if (project.shouldBuildVST3().getValue()) - addVSTPluginSettings (true); - - if (project.shouldBuildAAX().getValue()) - addAAXPluginSettings(); - - if (project.shouldBuildRTAS().getValue()) - addRTASPluginSettings(); - } - } - -private: - //============================================================================== - String createRebasedPath (const RelativePath& path) - { - String rebasedPath = rebaseFromProjectFolderToBuildTarget (path).toWindowsStyle(); - - return getVisualStudioVersion() < 10 // (VS10 automatically adds escape characters to the quotes for this definition) - ? CppTokeniserFunctions::addEscapeChars (rebasedPath.quoted()) - : CppTokeniserFunctions::addEscapeChars (rebasedPath).quoted(); - } - - void addVSTPluginSettings (bool isVST3) - { - RelativePath modulePath (rebaseFromProjectFolderToBuildTarget (RelativePath (getPathForModuleString ("juce_audio_plugin_client"), - RelativePath::projectFolder) - .getChildFile ("juce_audio_plugin_client") - .getChildFile ("VST3"))); - - for (ProjectExporter::ConfigIterator config (*this); config.next();) - { - if (config->getValue (Ids::useRuntimeLibDLL).getValue().isVoid()) - config->getValue (Ids::useRuntimeLibDLL) = true; - - if (isVST3) - { - if (config->getValue (Ids::postbuildCommand).toString().isEmpty()) - { - const String previousBuildCommands = config->getValue (Ids::internalPostBuildComamnd).toString(); - - String script; - if (previousBuildCommands.isNotEmpty()) - script += "\r\n"; - - script += "copy /Y \"$(OutDir)$(TargetFileName)\" \"$(OutDir)$(TargetName).vst3\""; - - config->getValue (Ids::internalPostBuildComamnd) = previousBuildCommands + script; - } - } - } - } - - void addAAXPluginSettings() - { - const RelativePath aaxSDKFolder = RelativePath (getAAXPathValue().toString(), - RelativePath::projectFolder); - msvcExtraPreprocessorDefs.set ("JucePlugin_AAXLibs_path", - createRebasedPath (aaxSDKFolder.getChildFile ("Libs"))); - const RelativePath aaxSDKUtilitiesFolder = aaxSDKFolder.getChildFile ("Utilities"); - - for (ProjectExporter::ConfigIterator config (*this); config.next();) - { - if (config->getValue (Ids::useRuntimeLibDLL).getValue().isVoid()) - config->getValue (Ids::useRuntimeLibDLL) = true; - - if (config->getValue(Ids::postbuildCommand).toString().isEmpty()) - { - const String previousBuildCommands = config->getValue (Ids::internalPostBuildComamnd).toString(); - - const bool is64Bit = (config->getValue (Ids::winArchitecture) == "x64"); - const String bundleDir = "$(OutDir)$(TargetName).aaxplugin"; - const String bundleContents = bundleDir + "\\Contents"; - const String macOSDir = bundleContents + String ("\\") + (is64Bit ? "x64" : "Win32"); - const String executable = macOSDir + String ("\\$(TargetName).aaxplugin"); - const String bundleScript = createRebasedPath (aaxSDKUtilitiesFolder.getChildFile ("CreatePackage.bat")); - - String iconFilePath = getTargetFolder().getChildFile ("icon.ico").getFullPathName(); - if (! File (iconFilePath).existsAsFile()) - iconFilePath = createRebasedPath (aaxSDKUtilitiesFolder.getChildFile ("PlugIn.ico")); - - String script; - - if (previousBuildCommands.isNotEmpty()) - script += "\r\n"; - - StringArray folders; - folders.add (bundleDir); - folders.add (bundleContents); - folders.add (macOSDir); - - for (int i = 0; i < folders.size(); ++i) - script += String ("if not exist \"") + folders[i] + String ("\" mkdir \"") + folders[i] + String ("\"\r\n"); - - script += String ("copy /Y \"$(OutDir)$(TargetFileName)\" \"") + executable + String ("\"\r\n"); - script += String ("\"") + bundleScript + String ("\" \"") + macOSDir + String ("\" \"") + iconFilePath + String ("\""); - - config->getValue (Ids::internalPostBuildComamnd) = previousBuildCommands + script; - } - } - } - - void addRTASPluginSettings() - { - RelativePath rtasFolder (getRTASPathValue().toString(), RelativePath::projectFolder); - - msvcTargetSuffix = ".dpm"; - - msvcExtraPreprocessorDefs.set ("JucePlugin_WinBag_path", - createRebasedPath (rtasFolder.getChildFile ("WinBag"))); - - msvcDelayLoadedDLLs = "DAE.dll; DigiExt.dll; DSI.dll; PluginLib.dll; " - "DSPManager.dll; DSPManager.dll; DSPManagerClientLib.dll; RTASClientLib.dll"; - - if (! getExtraLinkerFlagsString().contains ("/FORCE:multiple")) - getExtraLinkerFlags() = getExtraLinkerFlags().toString() + " /FORCE:multiple"; - - RelativePath modulePath (rebaseFromProjectFolderToBuildTarget (RelativePath (getPathForModuleString ("juce_audio_plugin_client"), - RelativePath::projectFolder) - .getChildFile ("juce_audio_plugin_client") - .getChildFile ("RTAS"))); - - for (ProjectExporter::ConfigIterator config (*this); config.next();) - { - config->getValue (Ids::msvcModuleDefinitionFile) = modulePath.getChildFile ("juce_RTAS_WinExports.def").toWindowsStyle(); - - if (config->getValue (Ids::useRuntimeLibDLL).getValue().isVoid()) - config->getValue (Ids::useRuntimeLibDLL) = true; - - if (config->getValue (Ids::postbuildCommand).toString().isEmpty()) - { - const String previousBuildCommands = config->getValue (Ids::internalPostBuildComamnd).toString(); - - String script; - if (previousBuildCommands.isNotEmpty()) - script += "\r\n"; - - script += "copy /Y " - + modulePath.getChildFile("juce_RTAS_WinResources.rsr").toWindowsStyle().quoted() - + " \"$(TargetPath)\".rsr"; - - config->getValue (Ids::internalPostBuildComamnd) = previousBuildCommands + script; - } - } - - RelativePath juceWrapperFolder (project.getGeneratedCodeFolder(), - getTargetFolder(), RelativePath::buildTargetFolder); - - extraSearchPaths.add (juceWrapperFolder.toWindowsStyle()); - - static const char* p[] = { "AlturaPorts/TDMPlugins/PluginLibrary/EffectClasses", - "AlturaPorts/TDMPlugins/PluginLibrary/ProcessClasses", - "AlturaPorts/TDMPlugins/PluginLibrary/ProcessClasses/Interfaces", - "AlturaPorts/TDMPlugins/PluginLibrary/Utilities", - "AlturaPorts/TDMPlugins/PluginLibrary/RTASP_Adapt", - "AlturaPorts/TDMPlugins/PluginLibrary/CoreClasses", - "AlturaPorts/TDMPlugins/PluginLibrary/Controls", - "AlturaPorts/TDMPlugins/PluginLibrary/Meters", - "AlturaPorts/TDMPlugins/PluginLibrary/ViewClasses", - "AlturaPorts/TDMPlugins/PluginLibrary/DSPClasses", - "AlturaPorts/TDMPlugins/PluginLibrary/Interfaces", - "AlturaPorts/TDMPlugins/common", - "AlturaPorts/TDMPlugins/common/Platform", - "AlturaPorts/TDMPlugins/common/Macros", - "AlturaPorts/TDMPlugins/SignalProcessing/Public", - "AlturaPorts/TDMPlugIns/DSPManager/Interfaces", - "AlturaPorts/SADriver/Interfaces", - "AlturaPorts/DigiPublic/Interfaces", - "AlturaPorts/DigiPublic", - "AlturaPorts/Fic/Interfaces/DAEClient", - "AlturaPorts/NewFileLibs/Cmn", - "AlturaPorts/NewFileLibs/DOA", - "AlturaPorts/AlturaSource/PPC_H", - "AlturaPorts/AlturaSource/AppSupport", - "AvidCode/AVX2sdk/AVX/avx2/avx2sdk/inc", - "xplat/AVX/avx2/avx2sdk/inc" }; - - for (int i = 0; i < numElementsInArray (p); ++i) - addToExtraSearchPaths (rtasFolder.getChildFile (p[i])); - } - -protected: - //============================================================================== - String projectGUID; - mutable File rcFile, iconFile; - - File getProjectFile (const String& extension) const { return getTargetFolder().getChildFile (project.getProjectFilenameRoot()).withFileExtension (extension); } - File getSLNFile() const { return getProjectFile (".sln"); } - - bool isLibraryDLL() const { return msvcIsDLL || projectType.isDynamicLibrary(); } - - static String prependIfNotAbsolute (const String& file, const char* prefix) - { - if (File::isAbsolutePath (file) || file.startsWithChar ('$')) - prefix = ""; - - return prefix + FileHelpers::windowsStylePath (file); - } - - String getIntDirFile (const BuildConfiguration& config, const String& file) const { return prependIfNotAbsolute (replacePreprocessorTokens (config, file), "$(IntDir)\\"); } - String getOutDirFile (const BuildConfiguration& config, const String& file) const { return prependIfNotAbsolute (replacePreprocessorTokens (config, file), "$(OutDir)\\"); } - - void updateOldSettings() - { - { - const String oldStylePrebuildCommand (getSettingString (Ids::prebuildCommand)); - settings.removeProperty (Ids::prebuildCommand, nullptr); - - if (oldStylePrebuildCommand.isNotEmpty()) - for (ConfigIterator config (*this); config.next();) - dynamic_cast (*config).getPrebuildCommand() = oldStylePrebuildCommand; - } - - { - const String oldStyleLibName (getSettingString ("libraryName_Debug")); - settings.removeProperty ("libraryName_Debug", nullptr); - - if (oldStyleLibName.isNotEmpty()) - for (ConfigIterator config (*this); config.next();) - if (config->isDebug()) - config->getTargetBinaryName() = oldStyleLibName; - } - - { - const String oldStyleLibName (getSettingString ("libraryName_Release")); - settings.removeProperty ("libraryName_Release", nullptr); - - if (oldStyleLibName.isNotEmpty()) - for (ConfigIterator config (*this); config.next();) - if (! config->isDebug()) - config->getTargetBinaryName() = oldStyleLibName; - } - } - //============================================================================== class MSVCBuildConfiguration : public BuildConfiguration { @@ -387,8 +60,6 @@ protected: Value getPostbuildCommand() { return getValue (Ids::postbuildCommand); } String getPostbuildCommandString() const { return config [Ids::postbuildCommand]; } - Value getInternalPostbuildCommands() { return getValue (Ids::internalPostBuildComamnd); } - Value shouldGenerateDebugSymbolsValue() { return getValue (Ids::alwaysGenerateDebugSymbols); } bool shouldGenerateDebugSymbols() const { return config [Ids::alwaysGenerateDebugSymbols]; } @@ -410,6 +81,11 @@ protected: String getCharacterSet() const { return config [Ids::characterSet].toString(); } Value getCharacterSetValue() { return getValue (Ids::characterSet); } + String createMSVCConfigName() const + { + return getName() + "|" + (config [Ids::winArchitecture] == "x64" ? "x64" : "Win32"); + } + String getOutputFilename (const String& suffix, bool forceSuffix) const { const String target (File::createLegalFileName (getTargetBinaryNameString().trim())); @@ -483,110 +159,645 @@ protected: StringArray (characterSetNames), Array (charSets, numElementsInArray (charSets)))); } } - }; - BuildConfiguration::Ptr createBuildConfig (const ValueTree& v) const override - { - return new MSVCBuildConfiguration (project, v, *this); - } + String getLibrarySubdirPath () const override + { + auto result = String ("$(Platform)\\"); + result += isUsingRuntimeLibDLL() ? "MD" : "MT"; + if (isDebug()) + result += "d"; + + return result; + } + }; //============================================================================== - String getConfigTargetPath (const BuildConfiguration& config) const + class MSVCTargetBase : public ProjectType::Target { - const String binaryPath (config.getTargetBinaryRelativePathString().trim()); - if (binaryPath.isEmpty()) - return binaryPath; + public: + MSVCTargetBase (ProjectType::Target::Type targetType, const MSVCProjectExporterBase& exporter) + : ProjectType::Target (targetType), owner (exporter) + { + projectGuid = createGUID (owner.getProject().getProjectUID() + getName()); + } - RelativePath binaryRelPath (binaryPath, RelativePath::projectFolder); + virtual ~MSVCTargetBase() {} - if (binaryRelPath.isAbsolute()) - return binaryRelPath.toWindowsStyle(); + const MSVCProjectExporterBase& getOwner() const { return owner; } + virtual String getTopLevelXmlEntity() const = 0; + const String& getProjectGuid() const { return projectGuid; } - return prependDot (binaryRelPath.rebased (projectFolder, getTargetFolder(), RelativePath::buildTargetFolder) - .toWindowsStyle()); - } + //============================================================================== + void writeProjectFile() + { + XmlElement projectXml (getTopLevelXmlEntity()); + fillInProjectXml (projectXml); + writeXmlOrThrow (projectXml, getVCProjFile(), "UTF-8", 10); + } - String getPreprocessorDefs (const BuildConfiguration& config, const String& joinString) const - { - StringPairArray defines (msvcExtraPreprocessorDefs); - defines.set ("WIN32", ""); - defines.set ("_WINDOWS", ""); + virtual void fillInProjectXml (XmlElement& projectXml) const = 0; - if (config.isDebug()) + String getSolutionTargetPath (const BuildConfiguration& config) const { - defines.set ("DEBUG", ""); - defines.set ("_DEBUG", ""); + const String binaryPath (config.getTargetBinaryRelativePathString().trim()); + if (binaryPath.isEmpty()) + return "$(SolutionDir)$(Configuration)"; + + RelativePath binaryRelPath (binaryPath, RelativePath::projectFolder); + + if (binaryRelPath.isAbsolute()) + return binaryRelPath.toWindowsStyle(); + + return prependDot (binaryRelPath.rebased (getOwner().projectFolder, getOwner().getTargetFolder(), RelativePath::buildTargetFolder) + .toWindowsStyle()); } - else + + String getConfigTargetPath (const BuildConfiguration& config) const { - defines.set ("NDEBUG", ""); + String solutionTargetFolder (getSolutionTargetPath (config)); + return solutionTargetFolder + String ("\\") + getName(); } - defines = mergePreprocessorDefs (defines, getAllPreprocessorDefs (config)); - - StringArray result; - - for (int i = 0; i < defines.size(); ++i) + String getIntermediatesPath (const MSVCBuildConfiguration& config) const { - String def (defines.getAllKeys()[i]); - const String value (defines.getAllValues()[i]); - if (value.isNotEmpty()) - def << "=" << value; + String intDir = (config.getIntermediatesPath().isNotEmpty() ? config.getIntermediatesPath() : "$(Configuration)"); + if (! intDir.endsWithChar (L'\\')) + intDir += L'\\'; - result.add (def); + return intDir + getName(); } - return result.joinIntoString (joinString); - } - - StringArray getHeaderSearchPaths (const BuildConfiguration& config) const - { - StringArray searchPaths (extraSearchPaths); - searchPaths.addArray (config.getHeaderSearchPaths()); - return getCleanedStringArray (searchPaths); - } + static const char* getOptimisationLevelString (int level) + { + switch (level) + { + case optimiseMaxSpeed: return "Full"; + case optimiseMinSize: return "MinSpace"; + default: return "Disabled"; + } + } - virtual String createConfigName (const BuildConfiguration& config) const - { - return config.getName() + "|Win32"; - } + String getTargetSuffix() const + { + const ProjectType::Target::TargetFileType fileType = getTargetFileType(); - //============================================================================== - void writeSolutionFile (OutputStream& out, const String& versionString, String commentString, const File& vcProject) const - { - if (commentString.isNotEmpty()) - commentString += newLine; + switch (fileType) + { + case executable: + return ".exe"; + case staticLibrary: + return ".lib"; + case sharedLibraryOrDLL: + return ".dll"; + case pluginBundle: + switch (type) + { + case VST3PlugIn: + return ".vst3"; + case AAXPlugIn: + return ".aaxdll"; + case RTASPlugIn: + return ".dpm"; + default: + break; + } - out << "Microsoft Visual Studio Solution File, Format Version " << versionString << newLine - << commentString - << "Project(\"" << createGUID (projectName + "sln_guid") << "\") = \"" << projectName << "\", \"" - << vcProject.getFileName() << "\", \"" << projectGUID << '"' << newLine - << "EndProject" << newLine - << "Global" << newLine - << "\tGlobalSection(SolutionConfigurationPlatforms) = preSolution" << newLine; + return ".dll"; + default: + break; + } - for (ConstConfigIterator i (*this); i.next();) - { - const String configName (createConfigName (*i)); - out << "\t\t" << configName << " = " << configName << newLine; + return String(); } - out << "\tEndGlobalSection" << newLine - << "\tGlobalSection(ProjectConfigurationPlatforms) = postSolution" << newLine; - - for (ConstConfigIterator i (*this); i.next();) + XmlElement* createToolElement (XmlElement& parent, const String& toolName) const { - const String configName (createConfigName (*i)); - out << "\t\t" << projectGUID << "." << configName << ".ActiveCfg = " << configName << newLine; - out << "\t\t" << projectGUID << "." << configName << ".Build.0 = " << configName << newLine; + XmlElement* const e = parent.createNewChildElement ("Tool"); + e->setAttribute ("Name", toolName); + return e; } - out << "\tEndGlobalSection" << newLine - << "\tGlobalSection(SolutionProperties) = preSolution" << newLine - << "\t\tHideSolutionNode = FALSE" << newLine - << "\tEndGlobalSection" << newLine - << "EndGlobal" << newLine; - } + String getPreprocessorDefs (const BuildConfiguration& config, const String& joinString) const + { + StringPairArray defines (getOwner().msvcExtraPreprocessorDefs); + defines.set ("WIN32", ""); + defines.set ("_WINDOWS", ""); + + if (config.isDebug()) + { + defines.set ("DEBUG", ""); + defines.set ("_DEBUG", ""); + } + else + { + defines.set ("NDEBUG", ""); + } + + defines = mergePreprocessorDefs (defines, getOwner().getAllPreprocessorDefs (config, type)); + addExtraPreprocessorDefines (defines); + + if (getTargetFileType() == staticLibrary || getTargetFileType() == sharedLibraryOrDLL) + defines.set("_LIB", ""); + + StringArray result; + + for (int i = 0; i < defines.size(); ++i) + { + String def (defines.getAllKeys()[i]); + const String value (defines.getAllValues()[i]); + if (value.isNotEmpty()) + def << "=" << value; + + result.add (def); + } + + return result.joinIntoString (joinString); + } + + //============================================================================== + RelativePath getAAXIconFile() const + { + const RelativePath aaxSDK (getOwner().getAAXPathValue().toString(), RelativePath::projectFolder); + const RelativePath projectIcon ("icon.ico", RelativePath::buildTargetFolder); + + if (getOwner().getTargetFolder().getChildFile ("icon.ico").existsAsFile()) + return projectIcon.rebased (getOwner().getTargetFolder(), + getOwner().getProject().getProjectFolder(), + RelativePath::projectFolder); + else + return aaxSDK.getChildFile ("Utilities").getChildFile ("PlugIn.ico"); + } + + String getExtraPostBuildSteps (const MSVCBuildConfiguration& config) const + { + if (type == AAXPlugIn) + { + const RelativePath aaxSDK (getOwner().getAAXPathValue().toString(), RelativePath::projectFolder); + const RelativePath aaxLibsFolder = aaxSDK.getChildFile ("Libs"); + const RelativePath bundleScript = aaxSDK.getChildFile ("Utilities").getChildFile ("CreatePackage.bat"); + const RelativePath iconFilePath = getAAXIconFile(); + + const bool is64Bit = (config.config [Ids::winArchitecture] == "x64"); + const String bundleDir = getOwner().getOutDirFile (config, config.getOutputFilename (".aaxplugin", true)); + const String bundleContents = bundleDir + "\\Contents"; + const String macOSDir = bundleContents + String ("\\") + (is64Bit ? "x64" : "Win32"); + const String executable = macOSDir + String ("\\") + config.getOutputFilename (".aaxplugin", true); + + return String ("copy /Y \"") + getOutputFilePath (config) + String ("\" \"") + executable + String ("\"\r\n") + + createRebasedPath (bundleScript) + String (" \"") + macOSDir + String ("\" ") + createRebasedPath (iconFilePath); + } + + return String(); + } + + String getExtraPreBuildSteps (const MSVCBuildConfiguration& config) const + { + if (type == AAXPlugIn) + { + String script; + + const bool is64Bit = (config.config [Ids::winArchitecture] == "x64"); + const String bundleDir = getOwner().getOutDirFile (config, config.getOutputFilename (".aaxplugin", false)); + + const String bundleContents = bundleDir + "\\Contents"; + const String macOSDir = bundleContents + String ("\\") + (is64Bit ? "x64" : "Win32"); + + StringArray folders = {bundleDir.toRawUTF8(), bundleContents.toRawUTF8(), macOSDir.toRawUTF8()}; + for (int i = 0; i < folders.size(); ++i) + script += String ("if not exist \"") + folders[i] + String ("\" mkdir \"") + folders[i] + String ("\"\r\n"); + + return script; + } + + return String(); + } + + String getPostBuildSteps (const MSVCBuildConfiguration& config) const + { + String postBuild = config.getPostbuildCommandString(); + const String extraPostBuild = getExtraPostBuildSteps (config); + + postBuild += String (postBuild.isNotEmpty() && extraPostBuild.isNotEmpty() ? "\r\n" : "") + extraPostBuild; + + return postBuild; + } + + String getPreBuildSteps (const MSVCBuildConfiguration& config) const + { + String preBuild = config.getPrebuildCommandString(); + const String extraPreBuild = getExtraPreBuildSteps (config); + + preBuild += String (preBuild.isNotEmpty() && extraPreBuild.isNotEmpty() ? "\r\n" : "") + extraPreBuild; + + return preBuild; + } + + void addExtraPreprocessorDefines (StringPairArray& defines) const + { + switch (type) + { + case AAXPlugIn: + { + const RelativePath aaxLibsFolder = RelativePath (getOwner().getAAXPathValue().toString(), RelativePath::projectFolder).getChildFile ("Libs"); + defines.set ("JucePlugin_AAXLibs_path", createRebasedPath (aaxLibsFolder)); + } + break; + case RTASPlugIn: + { + const RelativePath rtasFolder (getOwner().getRTASPathValue().toString(), RelativePath::projectFolder); + defines.set ("JucePlugin_WinBag_path", createRebasedPath (rtasFolder.getChildFile ("WinBag"))); + } + break; + default: + break; + } + } + + String getExtraLinkerFlags() const + { + if (type == RTASPlugIn) return "/FORCE:multiple"; + + return String(); + } + + void addExtraSearchPaths (Array& searchPaths) const + { + if (type == RTASPlugIn) + { + const RelativePath rtasFolder (getOwner().getRTASPathValue().toString(), RelativePath::projectFolder); + static const char* p[] = { "AlturaPorts/TDMPlugins/PluginLibrary/EffectClasses", + "AlturaPorts/TDMPlugins/PluginLibrary/ProcessClasses", + "AlturaPorts/TDMPlugins/PluginLibrary/ProcessClasses/Interfaces", + "AlturaPorts/TDMPlugins/PluginLibrary/Utilities", + "AlturaPorts/TDMPlugins/PluginLibrary/RTASP_Adapt", + "AlturaPorts/TDMPlugins/PluginLibrary/CoreClasses", + "AlturaPorts/TDMPlugins/PluginLibrary/Controls", + "AlturaPorts/TDMPlugins/PluginLibrary/Meters", + "AlturaPorts/TDMPlugins/PluginLibrary/ViewClasses", + "AlturaPorts/TDMPlugins/PluginLibrary/DSPClasses", + "AlturaPorts/TDMPlugins/PluginLibrary/Interfaces", + "AlturaPorts/TDMPlugins/common", + "AlturaPorts/TDMPlugins/common/Platform", + "AlturaPorts/TDMPlugins/common/Macros", + "AlturaPorts/TDMPlugins/SignalProcessing/Public", + "AlturaPorts/TDMPlugIns/DSPManager/Interfaces", + "AlturaPorts/SADriver/Interfaces", + "AlturaPorts/DigiPublic/Interfaces", + "AlturaPorts/DigiPublic", + "AlturaPorts/Fic/Interfaces/DAEClient", + "AlturaPorts/NewFileLibs/Cmn", + "AlturaPorts/NewFileLibs/DOA", + "AlturaPorts/AlturaSource/PPC_H", + "AlturaPorts/AlturaSource/AppSupport", + "AvidCode/AVX2sdk/AVX/avx2/avx2sdk/inc", + "xplat/AVX/avx2/avx2sdk/inc" }; + + for (int i = 0; i < numElementsInArray (p); ++i) + searchPaths.add (rtasFolder.getChildFile (p[i])); + } + } + + String getBinaryNameWithSuffix (const MSVCBuildConfiguration& config) const + { + return config.getOutputFilename (getTargetSuffix(), true); + } + + String getOutputFilePath (const MSVCBuildConfiguration& config) const + { + return getOwner().getOutDirFile (config, getBinaryNameWithSuffix (config)); + } + + StringArray getLibrarySearchPaths (const BuildConfiguration& config) const + { + StringArray librarySearchPaths (config.getLibrarySearchPaths()); + + if (type != SharedCodeTarget) + if (const MSVCTargetBase* shared = getOwner().getSharedCodeTarget()) + librarySearchPaths.add (shared->getConfigTargetPath (config)); + + return librarySearchPaths; + } + + String getExternalLibraries (const MSVCBuildConfiguration& config, const String& otherLibs) const + { + StringArray libraries; + + if (otherLibs.isNotEmpty()) + libraries.add (otherLibs); + + StringArray moduleLibs = getOwner().getModuleLibs(); + if (! moduleLibs.isEmpty()) + libraries.addArray (moduleLibs); + + if (type != SharedCodeTarget) + if (const MSVCTargetBase* shared = getOwner().getSharedCodeTarget()) + libraries.add (shared->getBinaryNameWithSuffix (config)); + + return libraries.joinIntoString (";"); + } + + String getDelayLoadedDLLs() const + { + String delayLoadedDLLs = getOwner().msvcDelayLoadedDLLs; + + if (type == RTASPlugIn) + delayLoadedDLLs += "DAE.dll; DigiExt.dll; DSI.dll; PluginLib.dll; " + "DSPManager.dll; DSPManager.dll; DSPManagerClientLib.dll; RTASClientLib.dll"; + + return delayLoadedDLLs; + } + + bool shouldUseRuntimeDLL (const MSVCBuildConfiguration& config) const + { + return (config.config [Ids::useRuntimeLibDLL].isVoid() ? (getOwner().hasTarget (AAXPlugIn) || getOwner().hasTarget (RTASPlugIn)) + : config.isUsingRuntimeLibDLL()); + } + + virtual String getProjectFileSuffix() const = 0; + + File getVCProjFile() const { return getOwner().getProjectFile (getProjectFileSuffix(), getName()); } + + String createRebasedPath (const RelativePath& path) const { return getOwner().createRebasedPath (path); } + + //============================================================================== + virtual String getProjectVersionString() const = 0; + protected: + const MSVCProjectExporterBase& owner; + String projectGuid; + }; + + //============================================================================== + bool usesMMFiles() const override { return false; } + bool canCopeWithDuplicateFiles() override { return false; } + bool supportsUserDefinedConfigurations() const override { return true; } + + bool isXcode() const override { return false; } + bool isVisualStudio() const override { return true; } + bool isCodeBlocks() const override { return false; } + bool isMakefile() const override { return false; } + bool isAndroidStudio() const override { return false; } + bool isAndroidAnt() const override { return false; } + + bool isAndroid() const override { return false; } + bool isWindows() const override { return true; } + bool isLinux() const override { return false; } + bool isOSX() const override { return false; } + bool isiOS() const override { return false; } + + bool supportsTargetType (ProjectType::Target::Type type) const override + { + switch (type) + { + case ProjectType::Target::StandalonePlugIn: + case ProjectType::Target::GUIApp: + case ProjectType::Target::ConsoleApp: + case ProjectType::Target::StaticLibrary: + case ProjectType::Target::SharedCodeTarget: + case ProjectType::Target::AggregateTarget: + case ProjectType::Target::VSTPlugIn: + case ProjectType::Target::VST3PlugIn: + case ProjectType::Target::AAXPlugIn: + case ProjectType::Target::RTASPlugIn: + case ProjectType::Target::DynamicLibrary: + return true; + default: + break; + } + + return false; + } + + //============================================================================== + const String& getProjectName() const { return projectName; } + + virtual int getVisualStudioVersion() const = 0; + + bool launchProject() override + { + #if JUCE_WINDOWS + return getSLNFile().startAsProcess(); + #else + return false; + #endif + } + + bool canLaunchProject() override + { + #if JUCE_WINDOWS + return true; + #else + return false; + #endif + } + + void createExporterProperties (PropertyListBuilder&) override + { + } + + enum OptimisationLevel + { + optimisationOff = 1, + optimiseMinSize = 2, + optimiseMaxSpeed = 3 + }; + + //============================================================================== + void addPlatformSpecificSettingsForProjectType (const ProjectType& type) override + { + msvcExtraPreprocessorDefs.set ("_CRT_SECURE_NO_WARNINGS", ""); + + if (type.isCommandLineApp()) + msvcExtraPreprocessorDefs.set("_CONSOLE", ""); + } + + const MSVCTargetBase* getSharedCodeTarget() const + { + for (auto target : targets) + if (target->type == ProjectType::Target::SharedCodeTarget) + return target; + + return nullptr; + } + + bool hasTarget (ProjectType::Target::Type type) const + { + for (auto target : targets) + if (target->type == type) + return true; + + return false; + } + +private: + //============================================================================== + String createRebasedPath (const RelativePath& path) const + { + String rebasedPath = rebaseFromProjectFolderToBuildTarget (path).toWindowsStyle(); + + return getVisualStudioVersion() < 10 // (VS10 automatically adds escape characters to the quotes for this definition) + ? CppTokeniserFunctions::addEscapeChars (rebasedPath.quoted()) + : CppTokeniserFunctions::addEscapeChars (rebasedPath).quoted(); + } + +protected: + //============================================================================== + mutable File rcFile, iconFile; + OwnedArray targets; + + File getProjectFile (const String& extension, const String& target) const + { + String filename = project.getProjectFilenameRoot(); + + if (target.isNotEmpty()) + filename += String (" (") + target + String (")"); + + return getTargetFolder().getChildFile (filename).withFileExtension (extension); + } + + File getSLNFile() const { return getProjectFile (".sln", String()); } + + static String prependIfNotAbsolute (const String& file, const char* prefix) + { + if (File::isAbsolutePath (file) || file.startsWithChar ('$')) + prefix = ""; + + return prefix + FileHelpers::windowsStylePath (file); + } + + String getIntDirFile (const BuildConfiguration& config, const String& file) const { return prependIfNotAbsolute (replacePreprocessorTokens (config, file), "$(IntDir)\\"); } + String getOutDirFile (const BuildConfiguration& config, const String& file) const { return prependIfNotAbsolute (replacePreprocessorTokens (config, file), "$(OutDir)\\"); } + + void updateOldSettings() + { + { + const String oldStylePrebuildCommand (getSettingString (Ids::prebuildCommand)); + settings.removeProperty (Ids::prebuildCommand, nullptr); + + if (oldStylePrebuildCommand.isNotEmpty()) + for (ConfigIterator config (*this); config.next();) + dynamic_cast (*config).getPrebuildCommand() = oldStylePrebuildCommand; + } + + { + const String oldStyleLibName (getSettingString ("libraryName_Debug")); + settings.removeProperty ("libraryName_Debug", nullptr); + + if (oldStyleLibName.isNotEmpty()) + for (ConfigIterator config (*this); config.next();) + if (config->isDebug()) + config->getTargetBinaryName() = oldStyleLibName; + } + + { + const String oldStyleLibName (getSettingString ("libraryName_Release")); + settings.removeProperty ("libraryName_Release", nullptr); + + if (oldStyleLibName.isNotEmpty()) + for (ConfigIterator config (*this); config.next();) + if (! config->isDebug()) + config->getTargetBinaryName() = oldStyleLibName; + } + } + + BuildConfiguration::Ptr createBuildConfig (const ValueTree& v) const override + { + return new MSVCBuildConfiguration (project, v, *this); + } + + StringArray getHeaderSearchPaths (const BuildConfiguration& config) const + { + StringArray searchPaths (extraSearchPaths); + searchPaths.addArray (config.getHeaderSearchPaths()); + return getCleanedStringArray (searchPaths); + } + + String getSharedCodeGuid() const + { + String sharedCodeGuid; + + for (int i = 0; i < targets.size(); ++i) + if (MSVCTargetBase* target = targets[i]) + if (target->type == ProjectType::Target::SharedCodeTarget) + return target->getProjectGuid(); + + return String(); + } + + //============================================================================== + virtual void addSolutionFiles (OutputStream&, StringArray&) const + { + // older VS targets do not support solution files, so do nothing! + } + + void writeProjectDependencies (OutputStream& out) const + { + const String sharedCodeGuid = getSharedCodeGuid(); + for (int i = 0; i < targets.size(); ++i) + { + if (MSVCTargetBase* target = targets[i]) + { + out << "Project(\"{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}\") = \"" << projectName << " (" + << target->getName() << ")\", \"" + << target->getVCProjFile().getFileName() << "\", \"" << target->getProjectGuid() << '"' << newLine; + + if (sharedCodeGuid.isNotEmpty() && target->type != ProjectType::Target::SharedCodeTarget) + out << "\tProjectSection(ProjectDependencies) = postProject" << newLine + << "\t\t" << sharedCodeGuid << " = " << sharedCodeGuid << newLine + << "\tEndProjectSection" << newLine; + + out << "EndProject" << newLine; + } + } + } + + void writeSolutionFile (OutputStream& out, const String& versionString, String commentString) const + { + StringArray nestedProjects; + + if (commentString.isNotEmpty()) + commentString += newLine; + + out << "Microsoft Visual Studio Solution File, Format Version " << versionString << newLine + << commentString << newLine; + + writeProjectDependencies (out); + addSolutionFiles (out, nestedProjects); + + out << "Global" << newLine + << "\tGlobalSection(SolutionConfigurationPlatforms) = preSolution" << newLine; + + for (ConstConfigIterator i (*this); i.next();) + { + const MSVCBuildConfiguration& config = dynamic_cast (*i); + const String configName = config.createMSVCConfigName(); + out << "\t\t" << configName << " = " << configName << newLine; + } + + out << "\tEndGlobalSection" << newLine + << "\tGlobalSection(ProjectConfigurationPlatforms) = postSolution" << newLine; + + for (auto& target : targets) + for (ConstConfigIterator i (*this); i.next();) + { + const MSVCBuildConfiguration& config = dynamic_cast (*i); + const String configName = config.createMSVCConfigName(); + out << "\t\t" << target->getProjectGuid() << "." << configName << ".Build.0 = " << configName << newLine; + } + + out << "\tEndGlobalSection" << newLine + << "\tGlobalSection(SolutionProperties) = preSolution" << newLine + << "\t\tHideSolutionNode = FALSE" << newLine + << "\tEndGlobalSection" << newLine; + + if (nestedProjects.size() > 0) + { + out << "\tGlobalSection(NestedProjects) = preSolution" << newLine << "\t\t"; + out << nestedProjects.joinIntoString ("\n\t\t") << newLine; + out << "\tEndGlobalSection" << newLine; + } + + out << "EndGlobal" << newLine; + } //============================================================================== static void writeBMPImage (const Image& image, const int w, const int h, MemoryOutputStream& out) @@ -774,10 +985,10 @@ protected: << "#endif" << newLine; if (iconFile != File()) - mo << newLine - << "IDI_ICON1 ICON DISCARDABLE " << iconFile.getFileName().quoted() - << newLine - << "IDI_ICON2 ICON DISCARDABLE " << iconFile.getFileName().quoted(); + mo << newLine + << "IDI_ICON1 ICON DISCARDABLE " << iconFile.getFileName().quoted() + << newLine + << "IDI_ICON2 ICON DISCARDABLE " << iconFile.getFileName().quoted(); overwriteFileIfDifferentOrThrow (rcFile, mo); } @@ -827,6 +1038,15 @@ protected: return path.getFileNameWithoutExtension().startsWithIgnoreCase ("juce_audio_plugin_client_RTAS_"); } + StringArray getModuleLibs () const + { + StringArray result; + for (auto& lib : windowsLibs) + result.add (lib + ".lib"); + + return result; + } + JUCE_DECLARE_NON_COPYABLE (MSVCProjectExporterBase) }; @@ -856,339 +1076,347 @@ public: } //============================================================================== - void create (const OwnedArray&) const override + class MSVC2008Target : public MSVCTargetBase { - createResourcesAndIcon(); + public: + MSVC2008Target (ProjectType::Target::Type targetType, const MSVCProjectExporterVC2008& exporter) + : MSVCTargetBase (targetType, exporter) + {} - if (hasResourceFile()) + const MSVCProjectExporterVC2008& getOwner() const { return dynamic_cast (owner); } + String getProjectVersionString() const override { return "9.00"; } + String getProjectFileSuffix() const override { return ".vcproj"; } + String getTopLevelXmlEntity() const override { return "VisualStudioProject"; } + + //============================================================================== + void fillInProjectXml (XmlElement& projectXml) const override { - for (int i = 0; i < getAllGroups().size(); ++i) - { - Project::Item& group = getAllGroups().getReference(i); + projectXml.setAttribute("ProjectType", "Visual C++"); + projectXml.setAttribute("Version", getProjectVersionString()); - if (group.getID() == ProjectSaver::getGeneratedGroupID()) - { - if (iconFile != File()) - { - group.addFileAtIndex (iconFile, -1, true); - group.findItemForFile (iconFile).getShouldAddToBinaryResourcesValue() = false; - } + String fullTargetName = (getOwner().getProjectName() + String (" (") + getName() + String (")")); - group.addFileAtIndex (rcFile, -1, true); - group.findItemForFile (rcFile).getShouldAddToBinaryResourcesValue() = false; + projectXml.setAttribute("Name", fullTargetName); + projectXml.setAttribute("ProjectGUID", getProjectGuid()); + projectXml.setAttribute("TargetFrameworkVersion", "131072"); - break; - } + { + XmlElement* platforms = projectXml.createNewChildElement("Platforms"); + XmlElement* platform = platforms->createNewChildElement("Platform"); + platform->setAttribute("Name", "Win32"); } - } - { - XmlElement projectXml ("VisualStudioProject"); - fillInProjectXml (projectXml); - writeXmlOrThrow (projectXml, getVCProjFile(), "UTF-8", 10); + projectXml.createNewChildElement("ToolFiles"); + createConfigs (*projectXml.createNewChildElement("Configurations")); + projectXml.createNewChildElement("References"); + createFiles (*projectXml.createNewChildElement("Files")); + projectXml.createNewChildElement("Globals"); } + void createConfig (XmlElement& xml, const MSVCBuildConfiguration& config) const { - MemoryOutputStream mo; - writeSolutionFile (mo, getSolutionVersionString(), String(), getVCProjFile()); + const bool isDebug = config.isDebug(); - overwriteFileIfDifferentOrThrow (getSLNFile(), mo); - } - } + xml.setAttribute ("Name", config.createMSVCConfigName()); -protected: - virtual String getProjectVersionString() const { return "9.00"; } - virtual String getSolutionVersionString() const { return String ("10.00") + newLine + "# Visual C++ Express 2008"; } + if (getConfigTargetPath (config).isNotEmpty()) + xml.setAttribute ("OutputDirectory", FileHelpers::windowsStylePath (getConfigTargetPath (config))); - File getVCProjFile() const { return getProjectFile (".vcproj"); } + xml.setAttribute ("IntermediateDirectory", FileHelpers::windowsStylePath (getIntermediatesPath (config))); - //============================================================================== - void fillInProjectXml (XmlElement& projectXml) const - { - projectXml.setAttribute ("ProjectType", "Visual C++"); - projectXml.setAttribute ("Version", getProjectVersionString()); - projectXml.setAttribute ("Name", projectName); - projectXml.setAttribute ("ProjectGUID", projectGUID); - projectXml.setAttribute ("TargetFrameworkVersion", "131072"); + const ProjectType::Target::TargetFileType fileType = getTargetFileType(); - { - XmlElement* platforms = projectXml.createNewChildElement ("Platforms"); - XmlElement* platform = platforms->createNewChildElement ("Platform"); - platform->setAttribute ("Name", "Win32"); - } + xml.setAttribute ("ConfigurationType", (fileType == sharedLibraryOrDLL || fileType == pluginBundle) ? "2" + : ((fileType == staticLibrary) ? "4" : "1")); + xml.setAttribute ("UseOfMFC", "0"); + xml.setAttribute ("ATLMinimizesCRunTimeLibraryUsage", "false"); + xml.setAttribute ("CharacterSet", "2"); + + if (! (isDebug || config.shouldDisableWholeProgramOpt())) + xml.setAttribute ("WholeProgramOptimization", "1"); + + XmlElement* preBuildEvent = createToolElement (xml, "VCPreBuildEventTool"); + const String preBuildCommand = getPreBuildSteps (config); + if (preBuildCommand.isNotEmpty()) + { + preBuildEvent->setAttribute ("Description", "Pre-build"); + preBuildEvent->setAttribute ("CommandLine", preBuildCommand); + } + + createToolElement (xml, "VCCustomBuildTool"); + createToolElement (xml, "VCXMLDataGeneratorTool"); + createToolElement (xml, "VCWebServiceProxyGeneratorTool"); + + if (fileType != staticLibrary) + { + XmlElement* midl = createToolElement (xml, "VCMIDLTool"); + midl->setAttribute ("PreprocessorDefinitions", isDebug ? "_DEBUG" : "NDEBUG"); + midl->setAttribute ("MkTypLibCompatible", "true"); + midl->setAttribute ("SuppressStartupBanner", "true"); + midl->setAttribute ("TargetEnvironment", "1"); + midl->setAttribute ("TypeLibraryName", getOwner().getIntDirFile (config, config.getOutputFilename (".tlb", true))); + midl->setAttribute ("HeaderFileName", ""); + } + + { + XmlElement* compiler = createToolElement (xml, "VCCLCompilerTool"); - projectXml.createNewChildElement ("ToolFiles"); - createConfigs (*projectXml.createNewChildElement ("Configurations")); - projectXml.createNewChildElement ("References"); - createFiles (*projectXml.createNewChildElement ("Files")); - projectXml.createNewChildElement ("Globals"); - } + compiler->setAttribute ("Optimization", getOptimisationLevelString (config.getOptimisationLevelInt())); - //============================================================================== - void addFile (const RelativePath& file, XmlElement& parent, const bool excludeFromBuild, const bool useStdcall) const - { - jassert (file.getRoot() == RelativePath::buildTargetFolder); + if (isDebug) + { + compiler->setAttribute ("BufferSecurityCheck", ""); + compiler->setAttribute ("DebugInformationFormat", (fileType == staticLibrary) ? "3" : "4"); + } + else + { + compiler->setAttribute ("InlineFunctionExpansion", "1"); + compiler->setAttribute ("StringPooling", "true"); + } - XmlElement* fileXml = parent.createNewChildElement ("File"); - fileXml->setAttribute ("RelativePath", file.toWindowsStyle()); + compiler->setAttribute ("AdditionalIncludeDirectories", getOwner().replacePreprocessorTokens (config, getOwner().getHeaderSearchPaths (config).joinIntoString (";"))); + compiler->setAttribute ("PreprocessorDefinitions", getPreprocessorDefs (config, ";")); + + const bool runtimeDLL = shouldUseRuntimeDLL (config); + compiler->setAttribute ("RuntimeLibrary", runtimeDLL ? (isDebug ? 3 : 2) // MT DLL + : (isDebug ? 1 : 0)); // MT static + compiler->setAttribute ("RuntimeTypeInfo", "true"); + compiler->setAttribute ("UsePrecompiledHeader", "0"); + compiler->setAttribute ("PrecompiledHeaderFile", getOwner().getIntDirFile (config, config.getOutputFilename (".pch", true))); + compiler->setAttribute ("AssemblerListingLocation", "$(IntDir)\\"); + compiler->setAttribute ("ObjectFile", "$(IntDir)\\"); + compiler->setAttribute ("ProgramDataBaseFileName", "$(IntDir)\\"); + compiler->setAttribute ("WarningLevel", String (config.getWarningLevel())); + compiler->setAttribute ("SuppressStartupBanner", "true"); + + const String extraFlags (getOwner().replacePreprocessorTokens (config, getOwner().getExtraCompilerFlagsString()).trim()); + if (extraFlags.isNotEmpty()) + compiler->setAttribute ("AdditionalOptions", extraFlags); + } + + createToolElement (xml, "VCManagedResourceCompilerTool"); - if (excludeFromBuild || useStdcall) - { - for (ConstConfigIterator i (*this); i.next();) { - XmlElement* fileConfig = fileXml->createNewChildElement ("FileConfiguration"); - fileConfig->setAttribute ("Name", createConfigName (*i)); + XmlElement* resCompiler = createToolElement (xml, "VCResourceCompilerTool"); + resCompiler->setAttribute ("PreprocessorDefinitions", isDebug ? "_DEBUG" : "NDEBUG"); + } - if (excludeFromBuild) - fileConfig->setAttribute ("ExcludedFromBuild", "true"); + createToolElement (xml, "VCPreLinkEventTool"); - XmlElement* tool = createToolElement (*fileConfig, "VCCLCompilerTool"); + if (fileType != staticLibrary) + { + XmlElement* linker = createToolElement (xml, "VCLinkerTool"); - if (useStdcall) - tool->setAttribute ("CallingConvention", "2"); - } - } - } + linker->setAttribute ("OutputFile", getOutputFilePath (config)); + linker->setAttribute ("SuppressStartupBanner", "true"); - XmlElement* createGroup (const String& groupName, XmlElement& parent) const - { - XmlElement* filter = parent.createNewChildElement ("Filter"); - filter->setAttribute ("Name", groupName); - return filter; - } + linker->setAttribute ("IgnoreDefaultLibraryNames", isDebug ? "libcmt.lib, msvcrt.lib" : ""); + linker->setAttribute ("GenerateDebugInformation", (isDebug || config.shouldGenerateDebugSymbols()) ? "true" : "false"); + linker->setAttribute ("LinkIncremental", config.shouldLinkIncremental() ? "2" : "1"); + linker->setAttribute ("ProgramDatabaseFile", getOwner().getIntDirFile (config, config.getOutputFilename (".pdb", true))); + linker->setAttribute ("SubSystem", (type != ConsoleApp ? "2" : "1")); - void addFiles (const Project::Item& projectItem, XmlElement& parent) const - { - if (projectItem.isGroup()) - { - XmlElement* filter = createGroup (projectItem.getName(), parent); + const StringArray librarySearchPaths (getLibrarySearchPaths (config)); + if (librarySearchPaths.size() > 0) + linker->setAttribute ("AdditionalLibraryDirectories", librarySearchPaths.joinIntoString (";")); - for (int i = 0; i < projectItem.getNumChildren(); ++i) - addFiles (projectItem.getChild(i), *filter); - } - else if (projectItem.shouldBeAddedToTargetProject()) - { - const RelativePath path (projectItem.getFile(), getTargetFolder(), RelativePath::buildTargetFolder); + linker->setAttribute ("GenerateManifest", config.shouldGenerateManifest() ? "true" : "false"); - addFile (path, parent, - projectItem.shouldBeAddedToBinaryResources() - || (shouldFileBeCompiledByDefault (path) && ! projectItem.shouldBeCompiled()), - shouldFileBeCompiledByDefault (path) && shouldUseStdCall (path)); - } - } + if (! isDebug) + { + linker->setAttribute ("OptimizeReferences", "2"); + linker->setAttribute ("EnableCOMDATFolding", "2"); + } - void createFiles (XmlElement& files) const - { - for (int i = 0; i < getAllGroups().size(); ++i) - { - const Project::Item& group = getAllGroups().getReference(i); + linker->setAttribute ("TargetMachine", "1"); // (64-bit build = 5) - if (group.getNumChildren() > 0) - addFiles (group, files); - } - } + const String delayLoadedDLLs (getDelayLoadedDLLs()); + if (delayLoadedDLLs.isNotEmpty()) + linker->setAttribute ("DelayLoadDLLs", delayLoadedDLLs); - //============================================================================== - XmlElement* createToolElement (XmlElement& parent, const String& toolName) const - { - XmlElement* const e = parent.createNewChildElement ("Tool"); - e->setAttribute ("Name", toolName); - return e; - } + if (config.config [Ids::msvcModuleDefinitionFile].toString().isNotEmpty()) + linker->setAttribute ("ModuleDefinitionFile", config.config [Ids::msvcModuleDefinitionFile].toString()); - void createConfig (XmlElement& xml, const MSVCBuildConfiguration& config) const - { - const bool isDebug = config.isDebug(); + const String externalLibraries (getExternalLibraries (config, getOwner().getExternalLibrariesString())); + if (externalLibraries.isNotEmpty()) + linker->setAttribute ("AdditionalDependencies", getOwner().replacePreprocessorTokens (config, externalLibraries).trim()); + + String extraLinkerOptions (getOwner().getExtraLinkerFlagsString()); + if (extraLinkerOptions.isNotEmpty()) + linker->setAttribute ("AdditionalOptions", getOwner().replacePreprocessorTokens (config, extraLinkerOptions).trim()); + } + else + { + XmlElement* librarian = createToolElement (xml, "VCLibrarianTool"); - xml.setAttribute ("Name", createConfigName (config)); + librarian->setAttribute ("OutputFile", getOutputFilePath (config)); + librarian->setAttribute ("IgnoreDefaultLibraryNames", isDebug ? "libcmt.lib, msvcrt.lib" : ""); + } - if (getConfigTargetPath (config).isNotEmpty()) - xml.setAttribute ("OutputDirectory", FileHelpers::windowsStylePath (getConfigTargetPath (config))); + createToolElement (xml, "VCALinkTool"); + createToolElement (xml, "VCManifestTool"); + createToolElement (xml, "VCXDCMakeTool"); - if (config.getIntermediatesPath().isNotEmpty()) - xml.setAttribute ("IntermediateDirectory", FileHelpers::windowsStylePath (config.getIntermediatesPath())); + { + XmlElement* bscMake = createToolElement (xml, "VCBscMakeTool"); + bscMake->setAttribute ("SuppressStartupBanner", "true"); + bscMake->setAttribute ("OutputFile", getOwner().getIntDirFile (config, config.getOutputFilename (".bsc", true))); + } - xml.setAttribute ("ConfigurationType", isLibraryDLL() ? "2" : (projectType.isStaticLibrary() ? "4" : "1")); - xml.setAttribute ("UseOfMFC", "0"); - xml.setAttribute ("ATLMinimizesCRunTimeLibraryUsage", "false"); - xml.setAttribute ("CharacterSet", "2"); + createToolElement (xml, "VCFxCopTool"); - if (! (isDebug || config.shouldDisableWholeProgramOpt())) - xml.setAttribute ("WholeProgramOptimization", "1"); + if (fileType != staticLibrary) + createToolElement (xml, "VCAppVerifierTool"); - XmlElement* preBuildEvent = createToolElement (xml, "VCPreBuildEventTool"); + XmlElement* postBuildEvent = createToolElement (xml, "VCPostBuildEventTool"); + const String postBuild = getPostBuildSteps (config); - if (config.getPrebuildCommandString().isNotEmpty()) - { - preBuildEvent->setAttribute ("Description", "Pre-build"); - preBuildEvent->setAttribute ("CommandLine", config.getPrebuildCommandString()); + if (postBuild.isNotEmpty()) + { + postBuildEvent->setAttribute ("Description", "Post-build"); + postBuildEvent->setAttribute ("CommandLine", postBuild); + } } - createToolElement (xml, "VCCustomBuildTool"); - createToolElement (xml, "VCXMLDataGeneratorTool"); - createToolElement (xml, "VCWebServiceProxyGeneratorTool"); - - if (! projectType.isStaticLibrary()) + void createConfigs (XmlElement& xml) const { - XmlElement* midl = createToolElement (xml, "VCMIDLTool"); - midl->setAttribute ("PreprocessorDefinitions", isDebug ? "_DEBUG" : "NDEBUG"); - midl->setAttribute ("MkTypLibCompatible", "true"); - midl->setAttribute ("SuppressStartupBanner", "true"); - midl->setAttribute ("TargetEnvironment", "1"); - midl->setAttribute ("TypeLibraryName", getIntDirFile (config, config.getOutputFilename (".tlb", true))); - midl->setAttribute ("HeaderFileName", ""); + for (ConstConfigIterator config (getOwner()); config.next();) + createConfig (*xml.createNewChildElement ("Configuration"), + dynamic_cast (*config)); } + //============================================================================== + void addFile (const RelativePath& file, XmlElement& parent, const bool useStdcall) const { - XmlElement* compiler = createToolElement (xml, "VCCLCompilerTool"); + jassert (file.getRoot() == RelativePath::buildTargetFolder); - compiler->setAttribute ("Optimization", getOptimisationLevelString (config.getOptimisationLevelInt())); + XmlElement* fileXml = parent.createNewChildElement ("File"); + fileXml->setAttribute ("RelativePath", file.toWindowsStyle()); - if (isDebug) - { - compiler->setAttribute ("BufferSecurityCheck", ""); - compiler->setAttribute ("DebugInformationFormat", projectType.isStaticLibrary() ? "3" : "4"); - } - else + if (useStdcall) { - compiler->setAttribute ("InlineFunctionExpansion", "1"); - compiler->setAttribute ("StringPooling", "true"); - } + for (ConstConfigIterator i (getOwner()); i.next();) + { + const MSVCBuildConfiguration& config = dynamic_cast (*i); + XmlElement* fileConfig = fileXml->createNewChildElement ("FileConfiguration"); + fileConfig->setAttribute ("Name", config.createMSVCConfigName()); - compiler->setAttribute ("AdditionalIncludeDirectories", replacePreprocessorTokens (config, getHeaderSearchPaths (config).joinIntoString (";"))); - compiler->setAttribute ("PreprocessorDefinitions", getPreprocessorDefs (config, ";")); - compiler->setAttribute ("RuntimeLibrary", config.isUsingRuntimeLibDLL() ? (isDebug ? 3 : 2) // MT DLL - : (isDebug ? 1 : 0)); // MT static - compiler->setAttribute ("RuntimeTypeInfo", "true"); - compiler->setAttribute ("UsePrecompiledHeader", "0"); - compiler->setAttribute ("PrecompiledHeaderFile", getIntDirFile (config, config.getOutputFilename (".pch", true))); - compiler->setAttribute ("AssemblerListingLocation", "$(IntDir)\\"); - compiler->setAttribute ("ObjectFile", "$(IntDir)\\"); - compiler->setAttribute ("ProgramDataBaseFileName", "$(IntDir)\\"); - compiler->setAttribute ("WarningLevel", String (config.getWarningLevel())); - compiler->setAttribute ("SuppressStartupBanner", "true"); - - const String extraFlags (replacePreprocessorTokens (config, getExtraCompilerFlagsString()).trim()); - if (extraFlags.isNotEmpty()) - compiler->setAttribute ("AdditionalOptions", extraFlags); - } + XmlElement* tool = createToolElement (*fileConfig, "VCCLCompilerTool"); - createToolElement (xml, "VCManagedResourceCompilerTool"); + if (useStdcall) + tool->setAttribute ("CallingConvention", "2"); + } + } + } + XmlElement* createGroup (const String& groupName, XmlElement& parent) const { - XmlElement* resCompiler = createToolElement (xml, "VCResourceCompilerTool"); - resCompiler->setAttribute ("PreprocessorDefinitions", isDebug ? "_DEBUG" : "NDEBUG"); + XmlElement* filter = parent.createNewChildElement ("Filter"); + filter->setAttribute ("Name", groupName); + return filter; } - createToolElement (xml, "VCPreLinkEventTool"); - - if (! projectType.isStaticLibrary()) + void addFiles (const Project::Item& projectItem, XmlElement& parent) const { - XmlElement* linker = createToolElement (xml, "VCLinkerTool"); - - linker->setAttribute ("OutputFile", getOutDirFile (config, config.getOutputFilename (msvcTargetSuffix, false))); - linker->setAttribute ("SuppressStartupBanner", "true"); + const Type targetType = (getOwner().getProject().getProjectType().isAudioPlugin() ? type : SharedCodeTarget); - linker->setAttribute ("IgnoreDefaultLibraryNames", isDebug ? "libcmt.lib, msvcrt.lib" : ""); - linker->setAttribute ("GenerateDebugInformation", (isDebug || config.shouldGenerateDebugSymbols()) ? "true" : "false"); - linker->setAttribute ("LinkIncremental", config.shouldLinkIncremental() ? "2" : "1"); - linker->setAttribute ("ProgramDatabaseFile", getIntDirFile (config, config.getOutputFilename (".pdb", true))); - linker->setAttribute ("SubSystem", msvcIsWindowsSubsystem ? "2" : "1"); + if (projectItem.isGroup()) + { + XmlElement* filter = createGroup (projectItem.getName(), parent); - const StringArray librarySearchPaths (config.getLibrarySearchPaths()); - if (librarySearchPaths.size() > 0) - linker->setAttribute ("AdditionalLibraryDirectories", librarySearchPaths.joinIntoString (";")); + for (int i = 0; i < projectItem.getNumChildren(); ++i) + addFiles (projectItem.getChild (i), *filter); + } + else if (projectItem.shouldBeCompiled() + && getOwner().getProject().getTargetTypeFromFilePath (projectItem.getFile(), true) == targetType) + { + const RelativePath path (projectItem.getFile(), getOwner().getTargetFolder(), RelativePath::buildTargetFolder); - linker->setAttribute ("GenerateManifest", config.shouldGenerateManifest() ? "true" : "false"); + if (getOwner().shouldFileBeCompiledByDefault (path)) + addFile (path, parent, getOwner().shouldFileBeCompiledByDefault (path) && shouldUseStdCall (path)); + } + } - if (! isDebug) + void createFiles (XmlElement& files) const + { + for (int i = 0; i < getOwner().getAllGroups().size(); ++i) { - linker->setAttribute ("OptimizeReferences", "2"); - linker->setAttribute ("EnableCOMDATFolding", "2"); + const Project::Item& group = getOwner().getAllGroups().getReference (i); + + if (group.getNumChildren() > 0) + addFiles (group, files); } + } + }; - linker->setAttribute ("TargetMachine", "1"); // (64-bit build = 5) + //============================================================================== + void addPlatformSpecificSettingsForProjectType (const ProjectType& type) override + { + MSVCProjectExporterBase::addPlatformSpecificSettingsForProjectType (type); - if (msvcDelayLoadedDLLs.isNotEmpty()) - linker->setAttribute ("DelayLoadDLLs", msvcDelayLoadedDLLs); + callForAllSupportedTargets ([this] (ProjectType::Target::Type targetType) + { + if (MSVCTargetBase* target = new MSVC2008Target (targetType, *this)) + { + if (targetType != ProjectType::Target::AggregateTarget) + targets.add (target); + } + }); - if (config.config [Ids::msvcModuleDefinitionFile].toString().isNotEmpty()) - linker->setAttribute ("ModuleDefinitionFile", config.config [Ids::msvcModuleDefinitionFile].toString()); + // If you hit this assert, you tried to generate a project for an exporter + // that does not support any of your targets! + jassert (targets.size() > 0); + } - String externalLibraries (getExternalLibrariesString()); - if (externalLibraries.isNotEmpty()) - linker->setAttribute ("AdditionalDependencies", replacePreprocessorTokens (config, externalLibraries).trim()); + void create (const OwnedArray&) const override + { + createResourcesAndIcon(); - String extraLinkerOptions (getExtraLinkerFlagsString()); - if (extraLinkerOptions.isNotEmpty()) - linker->setAttribute ("AdditionalOptions", replacePreprocessorTokens (config, extraLinkerOptions).trim()); - } - else + if (hasResourceFile()) { - if (isLibraryDLL()) + for (int i = 0; i < getAllGroups().size(); ++i) { - XmlElement* linker = createToolElement (xml, "VCLinkerTool"); - - String extraLinkerOptions (getExtraLinkerFlagsString()); - extraLinkerOptions << " /IMPLIB:" << getOutDirFile (config, config.getOutputFilename (".lib", true)); - linker->setAttribute ("AdditionalOptions", replacePreprocessorTokens (config, extraLinkerOptions).trim()); + Project::Item& group = getAllGroups().getReference (i); - String externalLibraries (getExternalLibrariesString()); - if (externalLibraries.isNotEmpty()) - linker->setAttribute ("AdditionalDependencies", replacePreprocessorTokens (config, externalLibraries).trim()); - - linker->setAttribute ("OutputFile", getOutDirFile (config, config.getOutputFilename (msvcTargetSuffix, false))); - linker->setAttribute ("IgnoreDefaultLibraryNames", isDebug ? "libcmt.lib, msvcrt.lib" : ""); + if (group.getID() == ProjectSaver::getGeneratedGroupID()) + { + if (iconFile != File()) + { + group.addFileAtIndex (iconFile, -1, true); + group.findItemForFile (iconFile).getShouldAddToBinaryResourcesValue() = false; + } - linker->setAttribute ("LinkIncremental", config.shouldLinkIncremental() ? "2" : "1"); - } - else - { - XmlElement* librarian = createToolElement (xml, "VCLibrarianTool"); + group.addFileAtIndex (rcFile, -1, true); + group.findItemForFile (rcFile).getShouldAddToBinaryResourcesValue() = false; - librarian->setAttribute ("OutputFile", getOutDirFile (config, config.getOutputFilename (msvcTargetSuffix, false))); - librarian->setAttribute ("IgnoreDefaultLibraryNames", isDebug ? "libcmt.lib, msvcrt.lib" : ""); + break; + } } } - createToolElement (xml, "VCALinkTool"); - createToolElement (xml, "VCManifestTool"); - createToolElement (xml, "VCXDCMakeTool"); + for (int i = 0; i < targets.size(); ++i) + if (MSVCTargetBase* target = targets[i]) + target->writeProjectFile(); { - XmlElement* bscMake = createToolElement (xml, "VCBscMakeTool"); - bscMake->setAttribute ("SuppressStartupBanner", "true"); - bscMake->setAttribute ("OutputFile", getIntDirFile (config, config.getOutputFilename (".bsc", true))); - } - - createToolElement (xml, "VCFxCopTool"); - - if (! projectType.isStaticLibrary()) - createToolElement (xml, "VCAppVerifierTool"); - - XmlElement* postBuildEvent = createToolElement (xml, "VCPostBuildEventTool"); + MemoryOutputStream mo; + writeSolutionFile (mo, getSolutionVersionString(), String()); - if (config.getPostbuildCommandString().isNotEmpty()) - { - postBuildEvent->setAttribute ("Description", "Post-build"); - postBuildEvent->setAttribute ("CommandLine", config.getPostbuildCommandString()); + overwriteFileIfDifferentOrThrow (getSLNFile(), mo); } } - void createConfigs (XmlElement& xml) const - { - for (ConstConfigIterator config (*this); config.next();) - createConfig (*xml.createNewChildElement ("Configuration"), - dynamic_cast (*config)); - } +protected: + virtual String getSolutionVersionString() const { return String ("10.00") + newLine + "# Visual C++ Express 2008"; } + //============================================================================== static const char* getOptimisationLevelString (int level) { switch (level) { - case optimiseMaxSpeed: return "3"; - case optimiseMinSize: return "1"; - default: return "0"; + case optimiseMaxSpeed: return "3"; + case optimiseMinSize: return "1"; + default: return "0"; } } @@ -1207,6 +1435,17 @@ public: name = getName(); } + class MSVC2005Target : public MSVC2008Target + { + public: + MSVC2005Target (ProjectType::Target::Type targetType, const MSVCProjectExporterVC2005& exporter) + : MSVC2008Target (targetType, exporter) + {} + + const MSVCProjectExporterVC2005& getOwner() const { return dynamic_cast (owner); } + String getProjectVersionString() const override { return "8.00"; } + }; + static const char* getName() { return "Visual Studio 2005"; } static const char* getValueTreeTypeName() { return "VS2005"; } int getVisualStudioVersion() const override { return 8; } @@ -1220,7 +1459,6 @@ public: } protected: - String getProjectVersionString() const override { return "8.00"; } String getSolutionVersionString() const override { return String ("9.00") + newLine + "# Visual C++ Express 2005"; } JUCE_DECLARE_NON_COPYABLE (MSVCProjectExporterVC2005) @@ -1236,618 +1474,602 @@ public: name = getName(); } - static const char* getName() { return "Visual Studio 2010"; } - static const char* getValueTreeTypeName() { return "VS2010"; } - int getVisualStudioVersion() const override { return 10; } - virtual String getSolutionComment() const { return "# Visual Studio 2010"; } - virtual String getToolsVersion() const { return "4.0"; } - virtual String getDefaultToolset() const { return "Windows7.1SDK"; } - Value getPlatformToolsetValue() { return getSetting (Ids::toolset); } - Value getIPPLibraryValue() { return getSetting (Ids::IPPLibrary); } - String getIPPLibrary() const { return settings [Ids::IPPLibrary]; } - - String getPlatformToolset() const - { - const String s (settings [Ids::toolset].toString()); - return s.isNotEmpty() ? s : getDefaultToolset(); - } - - static MSVCProjectExporterVC2010* createForSettings (Project& project, const ValueTree& settings) - { - if (settings.hasType (getValueTreeTypeName())) - return new MSVCProjectExporterVC2010 (project, settings); - - return nullptr; - } - - void addToolsetProperty (PropertyListBuilder& props, const char** names, const var* values, int num) - { - props.add (new ChoicePropertyComponent (getPlatformToolsetValue(), "Platform Toolset", - StringArray (names, num), Array (values, num))); - } - - void addIPPLibraryProperty (PropertyListBuilder& props) - { - static const char* ippOptions[] = { "No", "Yes (Default Mode)", "Multi-Threaded Static Library", "Single-Threaded Static Library", "Multi-Threaded DLL", "Single-Threaded DLL" }; - static const var ippValues[] = { var(), "true", "Parallel_Static", "Sequential", "Parallel_Dynamic", "Sequential_Dynamic" }; - - props.add (new ChoicePropertyComponent (getIPPLibraryValue(), "Use IPP Library", - StringArray (ippOptions, numElementsInArray (ippValues)), - Array (ippValues, numElementsInArray (ippValues)))); - } - - void createExporterProperties (PropertyListBuilder& props) override - { - MSVCProjectExporterBase::createExporterProperties (props); - - static const char* toolsetNames[] = { "(default)", "v100", "v100_xp", "Windows7.1SDK", "CTP_Nov2013" }; - const var toolsets[] = { var(), "v100", "v100_xp", "Windows7.1SDK", "CTP_Nov2013" }; - - addToolsetProperty (props, toolsetNames, toolsets, numElementsInArray (toolsets)); - addIPPLibraryProperty (props); - } - - //============================================================================== - void create (const OwnedArray&) const override - { - createResourcesAndIcon(); - - { - XmlElement projectXml ("Project"); - fillInProjectXml (projectXml); - addPlatformToolsetToPropertyGroup (projectXml); - addIPPSettingToPropertyGroup (projectXml); - - writeXmlOrThrow (projectXml, getVCProjFile(), "utf-8", 100); - } - - { - XmlElement filtersXml ("Project"); - fillInFiltersXml (filtersXml); - writeXmlOrThrow (filtersXml, getVCProjFiltersFile(), "utf-8", 100); - } - - { - MemoryOutputStream mo; - writeSolutionFile (mo, "11.00", getSolutionComment(), getVCProjFile()); - - overwriteFileIfDifferentOrThrow (getSLNFile(), mo); - } - } - -protected: //============================================================================== - class VC2010BuildConfiguration : public MSVCBuildConfiguration + class MSVC2010Target : public MSVCTargetBase { public: - VC2010BuildConfiguration (Project& p, const ValueTree& settings, const ProjectExporter& e) - : MSVCBuildConfiguration (p, settings, e) - { - if (getArchitectureType().toString().isEmpty()) - getArchitectureType() = get32BitArchName(); - } + MSVC2010Target (ProjectType::Target::Type targetType, const MSVCProjectExporterVC2010& exporter) + : MSVCTargetBase (targetType, exporter) + {} - //============================================================================== - static const char* get32BitArchName() { return "32-bit"; } - static const char* get64BitArchName() { return "x64"; } - - Value getArchitectureType() { return getValue (Ids::winArchitecture); } - bool is64Bit() const { return config [Ids::winArchitecture].toString() == get64BitArchName(); } - - Value getFastMathValue() { return getValue (Ids::fastMath); } - bool isFastMathEnabled() const { return config [Ids::fastMath]; } + const MSVCProjectExporterVC2010& getOwner() const { return dynamic_cast (owner); } + String getProjectVersionString() const override { return "10.00"; } + String getProjectFileSuffix() const override { return ".vcxproj"; } + String getTopLevelXmlEntity() const override { return "Project"; } //============================================================================== - void createConfigProperties (PropertyListBuilder& props) override + void fillInProjectXml (XmlElement& projectXml) const override { - MSVCBuildConfiguration::createConfigProperties (props); - - const char* const archTypes[] = { get32BitArchName(), get64BitArchName() }; - - props.add (new ChoicePropertyComponent (getArchitectureType(), "Architecture", - StringArray (archTypes, numElementsInArray (archTypes)), - Array (archTypes, numElementsInArray (archTypes)))); + projectXml.setAttribute ("DefaultTargets", "Build"); + projectXml.setAttribute ("ToolsVersion", getOwner().getToolsVersion()); + projectXml.setAttribute ("xmlns", "http://schemas.microsoft.com/developer/msbuild/2003"); - props.add (new BooleanPropertyComponent (getFastMathValue(), "Relax IEEE compliance", "Enabled"), - "Enable this to use FAST_MATH non-IEEE mode. (Warning: this can have unexpected results!)"); - } - }; + { + XmlElement* configsGroup = projectXml.createNewChildElement ("ItemGroup"); + configsGroup->setAttribute ("Label", "ProjectConfigurations"); - virtual void addPlatformToolsetToPropertyGroup (XmlElement&) const {} + for (ConstConfigIterator i (owner); i.next();) + { + const MSVCBuildConfiguration& config = dynamic_cast (*i); + XmlElement* e = configsGroup->createNewChildElement ("ProjectConfiguration"); + e->setAttribute ("Include", config.createMSVCConfigName()); + e->createNewChildElement ("Configuration")->addTextElement (config.getName()); + e->createNewChildElement ("Platform")->addTextElement (is64Bit (config) ? "x64" : "Win32"); + } + } - void addIPPSettingToPropertyGroup (XmlElement& p) const - { - String ippLibrary = getIPPLibrary(); + { + XmlElement* globals = projectXml.createNewChildElement ("PropertyGroup"); + globals->setAttribute ("Label", "Globals"); + globals->createNewChildElement ("ProjectGuid")->addTextElement (getProjectGuid()); + } - if (ippLibrary.isNotEmpty()) - forEachXmlChildElementWithTagName (p, e, "PropertyGroup") - e->createNewChildElement ("UseIntelIPP")->addTextElement (ippLibrary); - } + { + XmlElement* imports = projectXml.createNewChildElement ("Import"); + imports->setAttribute ("Project", "$(VCTargetsPath)\\Microsoft.Cpp.Default.props"); + } - BuildConfiguration::Ptr createBuildConfig (const ValueTree& v) const override - { - return new VC2010BuildConfiguration (project, v, *this); - } + for (ConstConfigIterator i (owner); i.next();) + { + const VC2010BuildConfiguration& config = dynamic_cast (*i); - static bool is64Bit (const BuildConfiguration& config) - { - return dynamic_cast (config).is64Bit(); - } + XmlElement* e = projectXml.createNewChildElement ("PropertyGroup"); + setConditionAttribute (*e, config); + e->setAttribute ("Label", "Configuration"); + e->createNewChildElement ("ConfigurationType")->addTextElement (getProjectType()); + e->createNewChildElement ("UseOfMfc")->addTextElement ("false"); - //============================================================================== - File getVCProjFile() const { return getProjectFile (".vcxproj"); } - File getVCProjFiltersFile() const { return getProjectFile (".vcxproj.filters"); } + const String charSet (config.getCharacterSet()); - String createConfigName (const BuildConfiguration& config) const override - { - return config.getName() + (is64Bit (config) ? "|x64" - : "|Win32"); - } + if (charSet.isNotEmpty()) + e->createNewChildElement ("CharacterSet")->addTextElement (charSet); - void setConditionAttribute (XmlElement& xml, const BuildConfiguration& config) const - { - xml.setAttribute ("Condition", "'$(Configuration)|$(Platform)'=='" + createConfigName (config) + "'"); - } + if (! (config.isDebug() || config.shouldDisableWholeProgramOpt())) + e->createNewChildElement ("WholeProgramOptimization")->addTextElement ("true"); - //============================================================================== - void fillInProjectXml (XmlElement& projectXml) const - { - projectXml.setAttribute ("DefaultTargets", "Build"); - projectXml.setAttribute ("ToolsVersion", getToolsVersion()); - projectXml.setAttribute ("xmlns", "http://schemas.microsoft.com/developer/msbuild/2003"); + if (config.shouldLinkIncremental()) + e->createNewChildElement ("LinkIncremental")->addTextElement ("true"); - { - XmlElement* configsGroup = projectXml.createNewChildElement ("ItemGroup"); - configsGroup->setAttribute ("Label", "ProjectConfigurations"); + if (config.is64Bit()) + e->createNewChildElement ("PlatformToolset")->addTextElement (getOwner().getPlatformToolset()); + } - for (ConstConfigIterator config (*this); config.next();) { - XmlElement* e = configsGroup->createNewChildElement ("ProjectConfiguration"); - e->setAttribute ("Include", createConfigName (*config)); - e->createNewChildElement ("Configuration")->addTextElement (config->getName()); - e->createNewChildElement ("Platform")->addTextElement (is64Bit (*config) ? "x64" : "Win32"); + XmlElement* e = projectXml.createNewChildElement ("Import"); + e->setAttribute ("Project", "$(VCTargetsPath)\\Microsoft.Cpp.props"); } - } - - { - XmlElement* globals = projectXml.createNewChildElement ("PropertyGroup"); - globals->setAttribute ("Label", "Globals"); - globals->createNewChildElement ("ProjectGuid")->addTextElement (projectGUID); - } - { - XmlElement* imports = projectXml.createNewChildElement ("Import"); - imports->setAttribute ("Project", "$(VCTargetsPath)\\Microsoft.Cpp.Default.props"); - } + { + XmlElement* e = projectXml.createNewChildElement ("ImportGroup"); + e->setAttribute ("Label", "ExtensionSettings"); + } - for (ConstConfigIterator i (*this); i.next();) - { - const VC2010BuildConfiguration& config = dynamic_cast (*i); + { + XmlElement* e = projectXml.createNewChildElement ("ImportGroup"); + e->setAttribute ("Label", "PropertySheets"); + XmlElement* p = e->createNewChildElement ("Import"); + p->setAttribute ("Project", "$(UserRootDir)\\Microsoft.Cpp.$(Platform).user.props"); + p->setAttribute ("Condition", "exists('$(UserRootDir)\\Microsoft.Cpp.$(Platform).user.props')"); + p->setAttribute ("Label", "LocalAppDataPlatform"); + } - XmlElement* e = projectXml.createNewChildElement ("PropertyGroup"); - setConditionAttribute (*e, config); - e->setAttribute ("Label", "Configuration"); - e->createNewChildElement ("ConfigurationType")->addTextElement (getProjectType()); - e->createNewChildElement ("UseOfMfc")->addTextElement ("false"); + { + XmlElement* e = projectXml.createNewChildElement ("PropertyGroup"); + e->setAttribute ("Label", "UserMacros"); + } - const String charSet (config.getCharacterSet()); + { + XmlElement* props = projectXml.createNewChildElement ("PropertyGroup"); + props->createNewChildElement ("_ProjectFileVersion")->addTextElement ("10.0.30319.1"); + props->createNewChildElement ("TargetExt")->addTextElement (getTargetSuffix()); - if (charSet.isNotEmpty()) - e->createNewChildElement ("CharacterSet")->addTextElement (charSet); + for (ConstConfigIterator i (owner); i.next();) + { + const VC2010BuildConfiguration& config = dynamic_cast (*i); - if (! (config.isDebug() || config.shouldDisableWholeProgramOpt())) - e->createNewChildElement ("WholeProgramOptimization")->addTextElement ("true"); + if (getConfigTargetPath (config).isNotEmpty()) + { + XmlElement* outdir = props->createNewChildElement ("OutDir"); + setConditionAttribute (*outdir, config); + outdir->addTextElement (FileHelpers::windowsStylePath (getConfigTargetPath (config)) + "\\"); + } - if (config.shouldLinkIncremental()) - e->createNewChildElement ("LinkIncremental")->addTextElement ("true"); + { + XmlElement* intdir = props->createNewChildElement("IntDir"); + setConditionAttribute(*intdir, config); - if (config.is64Bit()) - e->createNewChildElement ("PlatformToolset")->addTextElement (getPlatformToolset()); - } + String intermediatesPath = getIntermediatesPath (config); + if (!intermediatesPath.endsWith("\\")) + intermediatesPath << "\\"; - { - XmlElement* e = projectXml.createNewChildElement ("Import"); - e->setAttribute ("Project", "$(VCTargetsPath)\\Microsoft.Cpp.props"); - } + intdir->addTextElement (FileHelpers::windowsStylePath (intermediatesPath)); + } - { - XmlElement* e = projectXml.createNewChildElement ("ImportGroup"); - e->setAttribute ("Label", "ExtensionSettings"); - } - { - XmlElement* e = projectXml.createNewChildElement ("ImportGroup"); - e->setAttribute ("Label", "PropertySheets"); - XmlElement* p = e->createNewChildElement ("Import"); - p->setAttribute ("Project", "$(UserRootDir)\\Microsoft.Cpp.$(Platform).user.props"); - p->setAttribute ("Condition", "exists('$(UserRootDir)\\Microsoft.Cpp.$(Platform).user.props')"); - p->setAttribute ("Label", "LocalAppDataPlatform"); - } + { + XmlElement* targetName = props->createNewChildElement ("TargetName"); + setConditionAttribute (*targetName, config); + targetName->addTextElement (config.getOutputFilename ("", false)); + } - { - XmlElement* e = projectXml.createNewChildElement ("PropertyGroup"); - e->setAttribute ("Label", "UserMacros"); - } + { + XmlElement* manifest = props->createNewChildElement ("GenerateManifest"); + setConditionAttribute (*manifest, config); + manifest->addTextElement (config.shouldGenerateManifest() ? "true" : "false"); + } - { - XmlElement* props = projectXml.createNewChildElement ("PropertyGroup"); - props->createNewChildElement ("_ProjectFileVersion")->addTextElement ("10.0.30319.1"); + const StringArray librarySearchPaths (getLibrarySearchPaths (config)); + if (librarySearchPaths.size() > 0) + { + XmlElement* libPath = props->createNewChildElement ("LibraryPath"); + setConditionAttribute (*libPath, config); + libPath->addTextElement ("$(LibraryPath);" + librarySearchPaths.joinIntoString (";")); + } + } + } - for (ConstConfigIterator i (*this); i.next();) + for (ConstConfigIterator i (owner); i.next();) { const VC2010BuildConfiguration& config = dynamic_cast (*i); - if (getConfigTargetPath (config).isNotEmpty()) + const bool isDebug = config.isDebug(); + + XmlElement* group = projectXml.createNewChildElement ("ItemDefinitionGroup"); + setConditionAttribute (*group, config); + { - XmlElement* outdir = props->createNewChildElement ("OutDir"); - setConditionAttribute (*outdir, config); - outdir->addTextElement (FileHelpers::windowsStylePath (getConfigTargetPath (config)) + "\\"); + XmlElement* midl = group->createNewChildElement ("Midl"); + midl->createNewChildElement ("PreprocessorDefinitions")->addTextElement (isDebug ? "_DEBUG;%(PreprocessorDefinitions)" + : "NDEBUG;%(PreprocessorDefinitions)"); + midl->createNewChildElement ("MkTypLibCompatible")->addTextElement ("true"); + midl->createNewChildElement ("SuppressStartupBanner")->addTextElement ("true"); + midl->createNewChildElement ("TargetEnvironment")->addTextElement ("Win32"); + midl->createNewChildElement ("HeaderFileName"); } - if (config.getIntermediatesPath().isNotEmpty()) + bool isUsingEditAndContinue = false; + { - XmlElement* intdir = props->createNewChildElement ("IntDir"); - setConditionAttribute (*intdir, config); + XmlElement* cl = group->createNewChildElement ("ClCompile"); - String intermediatesPath = config.getIntermediatesPath(); - if (! intermediatesPath.endsWith ("\\")) - intermediatesPath << "\\"; + cl->createNewChildElement ("Optimization")->addTextElement (getOptimisationLevelString (config.getOptimisationLevelInt())); - intdir->addTextElement (FileHelpers::windowsStylePath (intermediatesPath)); - } + if (isDebug && config.getOptimisationLevelInt() <= optimisationOff) + { + isUsingEditAndContinue = ! config.is64Bit(); - { - XmlElement* targetName = props->createNewChildElement ("TargetName"); - setConditionAttribute (*targetName, config); - targetName->addTextElement (config.getOutputFilename (String(), true)); - } + cl->createNewChildElement ("DebugInformationFormat") + ->addTextElement (isUsingEditAndContinue ? "EditAndContinue" + : "ProgramDatabase"); + } - { - XmlElement* targetExt = props->createNewChildElement ("TargetExt"); - setConditionAttribute (*targetExt, config); - targetExt->addTextElement (msvcTargetSuffix); + StringArray includePaths (getOwner().getHeaderSearchPaths (config)); + includePaths.add ("%(AdditionalIncludeDirectories)"); + cl->createNewChildElement ("AdditionalIncludeDirectories")->addTextElement (includePaths.joinIntoString (";")); + cl->createNewChildElement ("PreprocessorDefinitions")->addTextElement (getPreprocessorDefs (config, ";") + ";%(PreprocessorDefinitions)"); + + const bool runtimeDLL = shouldUseRuntimeDLL (config); + cl->createNewChildElement ("RuntimeLibrary")->addTextElement (runtimeDLL ? (isDebug ? "MultiThreadedDebugDLL" : "MultiThreadedDLL") + : (isDebug ? "MultiThreadedDebug" : "MultiThreaded")); + cl->createNewChildElement ("RuntimeTypeInfo")->addTextElement ("true"); + cl->createNewChildElement ("PrecompiledHeader"); + cl->createNewChildElement ("AssemblerListingLocation")->addTextElement ("$(IntDir)\\"); + cl->createNewChildElement ("ObjectFileName")->addTextElement ("$(IntDir)\\"); + cl->createNewChildElement ("ProgramDataBaseFileName")->addTextElement ("$(IntDir)\\"); + cl->createNewChildElement ("WarningLevel")->addTextElement ("Level" + String (config.getWarningLevel())); + cl->createNewChildElement ("SuppressStartupBanner")->addTextElement ("true"); + cl->createNewChildElement ("MultiProcessorCompilation")->addTextElement ("true"); + + if (config.isFastMathEnabled()) + cl->createNewChildElement ("FloatingPointModel")->addTextElement ("Fast"); + + const String extraFlags (getOwner().replacePreprocessorTokens (config, getOwner().getExtraCompilerFlagsString()).trim()); + if (extraFlags.isNotEmpty()) + cl->createNewChildElement ("AdditionalOptions")->addTextElement (extraFlags + " %(AdditionalOptions)"); + + if (config.areWarningsTreatedAsErrors()) + cl->createNewChildElement ("TreatWarningAsError")->addTextElement ("true"); } { - XmlElement* manifest = props->createNewChildElement ("GenerateManifest"); - setConditionAttribute (*manifest, config); - manifest->addTextElement (config.shouldGenerateManifest() ? "true" : "false"); + XmlElement* res = group->createNewChildElement ("ResourceCompile"); + res->createNewChildElement ("PreprocessorDefinitions")->addTextElement (isDebug ? "_DEBUG;%(PreprocessorDefinitions)" + : "NDEBUG;%(PreprocessorDefinitions)"); } - const StringArray librarySearchPaths (config.getLibrarySearchPaths()); - - if (librarySearchPaths.size() > 0) { - XmlElement* libPath = props->createNewChildElement ("LibraryPath"); - setConditionAttribute (*libPath, config); - libPath->addTextElement ("$(LibraryPath);" + librarySearchPaths.joinIntoString (";")); - } - } - } - - for (ConstConfigIterator i (*this); i.next();) - { - const VC2010BuildConfiguration& config = dynamic_cast (*i); + XmlElement* link = group->createNewChildElement ("Link"); + link->createNewChildElement ("OutputFile")->addTextElement (getOutputFilePath (config)); + link->createNewChildElement ("SuppressStartupBanner")->addTextElement ("true"); + link->createNewChildElement ("IgnoreSpecificDefaultLibraries")->addTextElement (isDebug ? "libcmt.lib; msvcrt.lib;;%(IgnoreSpecificDefaultLibraries)" + : "%(IgnoreSpecificDefaultLibraries)"); + link->createNewChildElement ("GenerateDebugInformation")->addTextElement ((isDebug || config.shouldGenerateDebugSymbols()) ? "true" : "false"); + link->createNewChildElement ("ProgramDatabaseFile")->addTextElement (getOwner().getIntDirFile (config, config.getOutputFilename (".pdb", true))); + link->createNewChildElement ("SubSystem")->addTextElement (type == ConsoleApp ? "Console" : "Windows"); + + if (! config.is64Bit()) + link->createNewChildElement ("TargetMachine")->addTextElement ("MachineX86"); + + if (isUsingEditAndContinue) + link->createNewChildElement ("ImageHasSafeExceptionHandlers")->addTextElement ("false"); + + if (! isDebug) + { + link->createNewChildElement ("OptimizeReferences")->addTextElement ("true"); + link->createNewChildElement ("EnableCOMDATFolding")->addTextElement ("true"); + } - const bool isDebug = config.isDebug(); + const StringArray librarySearchPaths (config.getLibrarySearchPaths()); + if (librarySearchPaths.size() > 0) + link->createNewChildElement ("AdditionalLibraryDirectories")->addTextElement (getOwner().replacePreprocessorTokens (config, librarySearchPaths.joinIntoString (";")) + + ";%(AdditionalLibraryDirectories)"); - XmlElement* group = projectXml.createNewChildElement ("ItemDefinitionGroup"); - setConditionAttribute (*group, config); + link->createNewChildElement ("LargeAddressAware")->addTextElement ("true"); - { - XmlElement* midl = group->createNewChildElement ("Midl"); - midl->createNewChildElement ("PreprocessorDefinitions")->addTextElement (isDebug ? "_DEBUG;%(PreprocessorDefinitions)" - : "NDEBUG;%(PreprocessorDefinitions)"); - midl->createNewChildElement ("MkTypLibCompatible")->addTextElement ("true"); - midl->createNewChildElement ("SuppressStartupBanner")->addTextElement ("true"); - midl->createNewChildElement ("TargetEnvironment")->addTextElement ("Win32"); - midl->createNewChildElement ("HeaderFileName"); - } + const String externalLibraries (getExternalLibraries (config, getOwner().getExternalLibrariesString())); + if (externalLibraries.isNotEmpty()) + link->createNewChildElement ("AdditionalDependencies")->addTextElement (getOwner().replacePreprocessorTokens (config, externalLibraries).trim() + + ";%(AdditionalDependencies)"); - bool isUsingEditAndContinue = false; + String extraLinkerOptions (getOwner().getExtraLinkerFlagsString()); + if (extraLinkerOptions.isNotEmpty()) + link->createNewChildElement ("AdditionalOptions")->addTextElement (getOwner().replacePreprocessorTokens (config, extraLinkerOptions).trim() + + " %(AdditionalOptions)"); - { - XmlElement* cl = group->createNewChildElement ("ClCompile"); + const String delayLoadedDLLs (getDelayLoadedDLLs()); + if (delayLoadedDLLs.isNotEmpty()) + link->createNewChildElement ("DelayLoadDLLs")->addTextElement (delayLoadedDLLs); - cl->createNewChildElement ("Optimization")->addTextElement (getOptimisationLevelString (config.getOptimisationLevelInt())); + if (config.config [Ids::msvcModuleDefinitionFile].toString().isNotEmpty()) + link->createNewChildElement ("ModuleDefinitionFile") + ->addTextElement (config.config [Ids::msvcModuleDefinitionFile].toString()); + } - if (isDebug && config.getOptimisationLevelInt() <= optimisationOff) { - isUsingEditAndContinue = ! config.is64Bit(); - - cl->createNewChildElement ("DebugInformationFormat") - ->addTextElement (isUsingEditAndContinue ? "EditAndContinue" - : "ProgramDatabase"); + XmlElement* bsc = group->createNewChildElement ("Bscmake"); + bsc->createNewChildElement ("SuppressStartupBanner")->addTextElement ("true"); + bsc->createNewChildElement ("OutputFile")->addTextElement (getOwner().getIntDirFile (config, config.getOutputFilename (".bsc", true))); } - StringArray includePaths (getHeaderSearchPaths (config)); - includePaths.add ("%(AdditionalIncludeDirectories)"); - cl->createNewChildElement ("AdditionalIncludeDirectories")->addTextElement (includePaths.joinIntoString (";")); - cl->createNewChildElement ("PreprocessorDefinitions")->addTextElement (getPreprocessorDefs (config, ";") + ";%(PreprocessorDefinitions)"); - cl->createNewChildElement ("RuntimeLibrary")->addTextElement (config.isUsingRuntimeLibDLL() ? (isDebug ? "MultiThreadedDebugDLL" : "MultiThreadedDLL") - : (isDebug ? "MultiThreadedDebug" : "MultiThreaded")); - cl->createNewChildElement ("RuntimeTypeInfo")->addTextElement ("true"); - cl->createNewChildElement ("PrecompiledHeader"); - cl->createNewChildElement ("AssemblerListingLocation")->addTextElement ("$(IntDir)\\"); - cl->createNewChildElement ("ObjectFileName")->addTextElement ("$(IntDir)\\"); - cl->createNewChildElement ("ProgramDataBaseFileName")->addTextElement ("$(IntDir)\\"); - cl->createNewChildElement ("WarningLevel")->addTextElement ("Level" + String (config.getWarningLevel())); - cl->createNewChildElement ("SuppressStartupBanner")->addTextElement ("true"); - cl->createNewChildElement ("MultiProcessorCompilation")->addTextElement ("true"); - - if (config.isFastMathEnabled()) - cl->createNewChildElement ("FloatingPointModel")->addTextElement ("Fast"); - - const String extraFlags (replacePreprocessorTokens (config, getExtraCompilerFlagsString()).trim()); - if (extraFlags.isNotEmpty()) - cl->createNewChildElement ("AdditionalOptions")->addTextElement (extraFlags + " %(AdditionalOptions)"); + if (getTargetFileType() == staticLibrary && ! config.is64Bit()) + { + XmlElement* lib = group->createNewChildElement ("Lib"); + lib->createNewChildElement ("TargetMachine")->addTextElement ("MachineX86"); + } - if (config.areWarningsTreatedAsErrors()) - cl->createNewChildElement ("TreatWarningAsError")->addTextElement ("true"); + const String preBuild = getPreBuildSteps (config); + if (preBuild.isNotEmpty()) + group->createNewChildElement ("PreBuildEvent") + ->createNewChildElement ("Command") + ->addTextElement (preBuild); + + const String postBuild = getPostBuildSteps (config); + if (postBuild.isNotEmpty()) + group->createNewChildElement ("PostBuildEvent") + ->createNewChildElement ("Command") + ->addTextElement (postBuild); } - { - XmlElement* res = group->createNewChildElement ("ResourceCompile"); - res->createNewChildElement ("PreprocessorDefinitions")->addTextElement (isDebug ? "_DEBUG;%(PreprocessorDefinitions)" - : "NDEBUG;%(PreprocessorDefinitions)"); - } + ScopedPointer otherFilesGroup (new XmlElement ("ItemGroup")); { - XmlElement* link = group->createNewChildElement ("Link"); - link->createNewChildElement ("OutputFile")->addTextElement (getOutDirFile (config, config.getOutputFilename (msvcTargetSuffix, false))); - link->createNewChildElement ("SuppressStartupBanner")->addTextElement ("true"); - link->createNewChildElement ("IgnoreSpecificDefaultLibraries")->addTextElement (isDebug ? "libcmt.lib; msvcrt.lib;;%(IgnoreSpecificDefaultLibraries)" - : "%(IgnoreSpecificDefaultLibraries)"); - link->createNewChildElement ("GenerateDebugInformation")->addTextElement ((isDebug || config.shouldGenerateDebugSymbols()) ? "true" : "false"); - link->createNewChildElement ("ProgramDatabaseFile")->addTextElement (getIntDirFile (config, config.getOutputFilename (".pdb", true))); - link->createNewChildElement ("SubSystem")->addTextElement (msvcIsWindowsSubsystem ? "Windows" : "Console"); - - if (! config.is64Bit()) - link->createNewChildElement ("TargetMachine")->addTextElement ("MachineX86"); + XmlElement* cppFiles = projectXml.createNewChildElement ("ItemGroup"); + XmlElement* headerFiles = projectXml.createNewChildElement ("ItemGroup"); - if (isUsingEditAndContinue) - link->createNewChildElement ("ImageHasSafeExceptionHandlers")->addTextElement ("false"); - - if (! isDebug) + for (int i = 0; i < getOwner().getAllGroups().size(); ++i) { - link->createNewChildElement ("OptimizeReferences")->addTextElement ("true"); - link->createNewChildElement ("EnableCOMDATFolding")->addTextElement ("true"); - } - - const StringArray librarySearchPaths (config.getLibrarySearchPaths()); - if (librarySearchPaths.size() > 0) - link->createNewChildElement ("AdditionalLibraryDirectories")->addTextElement (replacePreprocessorTokens (config, librarySearchPaths.joinIntoString (";")) - + ";%(AdditionalLibraryDirectories)"); - - link->createNewChildElement ("LargeAddressAware")->addTextElement ("true"); + const Project::Item& group = getOwner().getAllGroups().getReference (i); - String externalLibraries (getExternalLibrariesString()); - if (externalLibraries.isNotEmpty()) - link->createNewChildElement ("AdditionalDependencies")->addTextElement (replacePreprocessorTokens (config, externalLibraries).trim() - + ";%(AdditionalDependencies)"); + if (group.getNumChildren() > 0) + addFilesToCompile (group, *cppFiles, *headerFiles, *otherFilesGroup); + } + } - String extraLinkerOptions (getExtraLinkerFlagsString()); - if (extraLinkerOptions.isNotEmpty()) - link->createNewChildElement ("AdditionalOptions")->addTextElement (replacePreprocessorTokens (config, extraLinkerOptions).trim() - + " %(AdditionalOptions)"); + if (getOwner().iconFile != File()) + { + XmlElement* e = otherFilesGroup->createNewChildElement ("None"); + e->setAttribute ("Include", prependDot (getOwner().iconFile.getFileName())); + } - if (msvcDelayLoadedDLLs.isNotEmpty()) - link->createNewChildElement ("DelayLoadDLLs")->addTextElement (msvcDelayLoadedDLLs); + if (otherFilesGroup->getFirstChildElement() != nullptr) + projectXml.addChildElement (otherFilesGroup.release()); - if (config.config [Ids::msvcModuleDefinitionFile].toString().isNotEmpty()) - link->createNewChildElement ("ModuleDefinitionFile") - ->addTextElement (config.config [Ids::msvcModuleDefinitionFile].toString()); + if (getOwner().hasResourceFile()) + { + XmlElement* rcGroup = projectXml.createNewChildElement ("ItemGroup"); + XmlElement* e = rcGroup->createNewChildElement ("ResourceCompile"); + e->setAttribute ("Include", prependDot (getOwner().rcFile.getFileName())); } { - XmlElement* bsc = group->createNewChildElement ("Bscmake"); - bsc->createNewChildElement ("SuppressStartupBanner")->addTextElement ("true"); - bsc->createNewChildElement ("OutputFile")->addTextElement (getIntDirFile (config, config.getOutputFilename (".bsc", true))); + XmlElement* e = projectXml.createNewChildElement ("Import"); + e->setAttribute ("Project", "$(VCTargetsPath)\\Microsoft.Cpp.targets"); } - if (config.getPrebuildCommandString().isNotEmpty()) - group->createNewChildElement ("PreBuildEvent") - ->createNewChildElement ("Command") - ->addTextElement (config.getPrebuildCommandString()); + { + XmlElement* e = projectXml.createNewChildElement ("ImportGroup"); + e->setAttribute ("Label", "ExtensionTargets"); + } - const String internalPostBuildScripts = config.config[Ids::internalPostBuildComamnd].toString(); - if (config.getPostbuildCommandString().isNotEmpty() || internalPostBuildScripts.isNotEmpty()) - group->createNewChildElement ("PostBuildEvent") - ->createNewChildElement ("Command") - ->addTextElement (config.getPostbuildCommandString() + internalPostBuildScripts); + getOwner().addPlatformToolsetToPropertyGroup (projectXml); + getOwner().addIPPSettingToPropertyGroup (projectXml); } - ScopedPointer otherFilesGroup (new XmlElement ("ItemGroup")); - + String getProjectType() const { - XmlElement* cppFiles = projectXml.createNewChildElement ("ItemGroup"); - XmlElement* headerFiles = projectXml.createNewChildElement ("ItemGroup"); - - for (int i = 0; i < getAllGroups().size(); ++i) + switch (getTargetFileType()) { - const Project::Item& group = getAllGroups().getReference(i); - - if (group.getNumChildren() > 0) - addFilesToCompile (group, *cppFiles, *headerFiles, *otherFilesGroup); + case executable: + return "Application"; + case staticLibrary: + return "StaticLibrary"; + default: + break; } + + return "DynamicLibrary"; } - if (iconFile != File()) + //============================================================================== + void addFilesToCompile (const Project::Item& projectItem, XmlElement& cpps, XmlElement& headers, XmlElement& otherFiles) const { - XmlElement* e = otherFilesGroup->createNewChildElement ("None"); - e->setAttribute ("Include", prependDot (iconFile.getFileName())); - } + const Type targetType = (getOwner().getProject().getProjectType().isAudioPlugin() ? type : SharedCodeTarget); - if (otherFilesGroup->getFirstChildElement() != nullptr) - projectXml.addChildElement (otherFilesGroup.release()); + if (projectItem.isGroup()) + { + for (int i = 0; i < projectItem.getNumChildren(); ++i) + addFilesToCompile (projectItem.getChild (i), cpps, headers, otherFiles); + } + else if (projectItem.shouldBeAddedToTargetProject()) + { + const RelativePath path (projectItem.getFile(), getOwner().getTargetFolder(), RelativePath::buildTargetFolder); - if (hasResourceFile()) - { - XmlElement* rcGroup = projectXml.createNewChildElement ("ItemGroup"); - XmlElement* e = rcGroup->createNewChildElement ("ResourceCompile"); - e->setAttribute ("Include", prependDot (rcFile.getFileName())); - } + jassert (path.getRoot() == RelativePath::buildTargetFolder); - { - XmlElement* e = projectXml.createNewChildElement ("Import"); - e->setAttribute ("Project", "$(VCTargetsPath)\\Microsoft.Cpp.targets"); + if (projectItem.shouldBeCompiled() && (path.hasFileExtension (cOrCppFileExtensions) || path.hasFileExtension (asmFileExtensions)) + && getOwner().getProject().getTargetTypeFromFilePath (projectItem.getFile(), true) == targetType) + { + XmlElement* e = cpps.createNewChildElement ("ClCompile"); + e->setAttribute ("Include", path.toWindowsStyle()); + + if (shouldUseStdCall (path)) + e->createNewChildElement ("CallingConvention")->addTextElement ("StdCall"); + } + } } + void setConditionAttribute (XmlElement& xml, const BuildConfiguration& config) const { - XmlElement* e = projectXml.createNewChildElement ("ImportGroup"); - e->setAttribute ("Label", "ExtensionTargets"); + const MSVCBuildConfiguration& msvcConfig = dynamic_cast (config); + xml.setAttribute ("Condition", "'$(Configuration)|$(Platform)'=='" + msvcConfig.createMSVCConfigName() + "'"); } + + }; + + static const char* getName() { return "Visual Studio 2010"; } + static const char* getValueTreeTypeName() { return "VS2010"; } + int getVisualStudioVersion() const override { return 10; } + virtual String getSolutionComment() const { return "# Visual Studio 2010"; } + virtual String getToolsVersion() const { return "4.0"; } + virtual String getDefaultToolset() const { return "Windows7.1SDK"; } + Value getPlatformToolsetValue() { return getSetting (Ids::toolset); } + Value getIPPLibraryValue() { return getSetting (Ids::IPPLibrary); } + String getIPPLibrary() const { return settings [Ids::IPPLibrary]; } + + String getPlatformToolset() const + { + const String s (settings [Ids::toolset].toString()); + return s.isNotEmpty() ? s : getDefaultToolset(); } - String getProjectType() const + static MSVCProjectExporterVC2010* createForSettings (Project& project, const ValueTree& settings) { - if (projectType.isGUIApplication() || projectType.isCommandLineApp()) return "Application"; - if (isLibraryDLL()) return "DynamicLibrary"; - if (projectType.isStaticLibrary()) return "StaticLibrary"; + if (settings.hasType (getValueTreeTypeName())) + return new MSVCProjectExporterVC2010 (project, settings); - jassertfalse; - return String(); + return nullptr; } - static const char* getOptimisationLevelString (int level) + void addToolsetProperty (PropertyListBuilder& props, const char** names, const var* values, int num) { - switch (level) - { - case optimiseMaxSpeed: return "Full"; - case optimiseMinSize: return "MinSpace"; - default: return "Disabled"; - } + props.add (new ChoicePropertyComponent (getPlatformToolsetValue(), "Platform Toolset", + StringArray (names, num), Array (values, num))); } - //============================================================================== - void addFilesToCompile (const Project::Item& projectItem, XmlElement& cpps, XmlElement& headers, XmlElement& otherFiles) const + void addIPPLibraryProperty (PropertyListBuilder& props) { - if (projectItem.isGroup()) - { - for (int i = 0; i < projectItem.getNumChildren(); ++i) - addFilesToCompile (projectItem.getChild(i), cpps, headers, otherFiles); - } - else if (projectItem.shouldBeAddedToTargetProject()) - { - const RelativePath path (projectItem.getFile(), getTargetFolder(), RelativePath::buildTargetFolder); + static const char* ippOptions[] = { "No", "Yes (Default Mode)", "Multi-Threaded Static Library", "Single-Threaded Static Library", "Multi-Threaded DLL", "Single-Threaded DLL" }; + static const var ippValues[] = { var(), "true", "Parallel_Static", "Sequential", "Parallel_Dynamic", "Sequential_Dynamic" }; - jassert (path.getRoot() == RelativePath::buildTargetFolder); + props.add (new ChoicePropertyComponent (getIPPLibraryValue(), "Use IPP Library", + StringArray (ippOptions, numElementsInArray (ippValues)), + Array (ippValues, numElementsInArray (ippValues)))); + } - if (path.hasFileExtension (cOrCppFileExtensions) || path.hasFileExtension (asmFileExtensions)) - { - XmlElement* e = cpps.createNewChildElement ("ClCompile"); - e->setAttribute ("Include", path.toWindowsStyle()); + void createExporterProperties (PropertyListBuilder& props) override + { + MSVCProjectExporterBase::createExporterProperties (props); - if (! projectItem.shouldBeCompiled()) - e->createNewChildElement ("ExcludedFromBuild")->addTextElement ("true"); + static const char* toolsetNames[] = { "(default)", "v100", "v100_xp", "Windows7.1SDK", "CTP_Nov2013" }; + const var toolsets[] = { var(), "v100", "v100_xp", "Windows7.1SDK", "CTP_Nov2013" }; - if (shouldUseStdCall (path)) - e->createNewChildElement ("CallingConvention")->addTextElement ("StdCall"); - } - else if (path.hasFileExtension (headerFileExtensions)) - { - headers.createNewChildElement ("ClInclude")->setAttribute ("Include", path.toWindowsStyle()); - } - else if (! path.hasFileExtension (objCFileExtensions)) - { - otherFiles.createNewChildElement ("None")->setAttribute ("Include", path.toWindowsStyle()); - } - } + addToolsetProperty (props, toolsetNames, toolsets, numElementsInArray (toolsets)); + addIPPLibraryProperty (props); } //============================================================================== - void addFilterGroup (XmlElement& groups, const String& path) const + void addSolutionFiles (OutputStream& out, StringArray& nestedProjects) const override { - XmlElement* e = groups.createNewChildElement ("Filter"); - e->setAttribute ("Include", path); - e->createNewChildElement ("UniqueIdentifier")->addTextElement (createGUID (path + "_guidpathsaltxhsdf")); + const bool ignoreRootGroup = (getAllGroups().size() == 1); + const int numberOfGroups = (ignoreRootGroup ? getAllGroups().getReference (0).getNumChildren() + : getAllGroups().size()); + for (int i = 0; i < numberOfGroups; ++i) + { + const Project::Item& group = (ignoreRootGroup ? getAllGroups().getReference (0).getChild (i) + : getAllGroups().getReference (i)); + + if (group.getNumChildren() > 0) + addSolutionFiles (out, group, nestedProjects, String()); + } } - void addFileToFilter (const RelativePath& file, const String& groupPath, - XmlElement& cpps, XmlElement& headers, XmlElement& otherFiles) const + void addSolutionFiles (OutputStream& out, const Project::Item& item, StringArray& nestedProjectList, const String& parentGuid) const { - XmlElement* e; + jassert (item.isGroup()); - if (file.hasFileExtension (headerFileExtensions)) - e = headers.createNewChildElement ("ClInclude"); - else if (file.hasFileExtension (sourceFileExtensions)) - e = cpps.createNewChildElement ("ClCompile"); - else - e = otherFiles.createNewChildElement ("None"); + const String groupGuid = createGUID (item.getID()); - jassert (file.getRoot() == RelativePath::buildTargetFolder); - e->setAttribute ("Include", file.toWindowsStyle()); - e->createNewChildElement ("Filter")->addTextElement (groupPath); - } + out << "Project(\"{2150E333-8FDC-42A3-9474-1A3956D46DE8}\") = \"" << item.getName() << "\"" + << ", \"" << item.getName() << "\", \"" << groupGuid << "\"" << newLine; - void addFilesToFilter (const Project::Item& projectItem, const String& path, - XmlElement& cpps, XmlElement& headers, XmlElement& otherFiles, XmlElement& groups) const - { - if (projectItem.isGroup()) + bool hasSubFiles = false; + const int n = item.getNumChildren(); + + for (int i = 0; i < n; ++i) { - addFilterGroup (groups, path); + const Project::Item& child = item.getChild (i); + + if (child.isFile()) + { + if (! hasSubFiles) + { + out << "\tProjectSection(SolutionItems) = preProject" << newLine; + hasSubFiles = true; + } - for (int i = 0; i < projectItem.getNumChildren(); ++i) - addFilesToFilter (projectItem.getChild(i), - (path.isEmpty() ? String() : (path + "\\")) + projectItem.getChild(i).getName(), - cpps, headers, otherFiles, groups); + const RelativePath path = RelativePath (child.getFilePath(), RelativePath::projectFolder) + .rebased (getProject().getProjectFolder(), getSLNFile().getParentDirectory(), + RelativePath::buildTargetFolder); + + out << "\t\t" << path.toWindowsStyle() << " = " << path.toWindowsStyle() << newLine; + } } - else if (projectItem.shouldBeAddedToTargetProject()) + + if (hasSubFiles) + out << "\tEndProjectSection" << newLine; + + out << "EndProject" << newLine; + + for (int i = 0; i < n; ++i) { - addFileToFilter (RelativePath (projectItem.getFile(), getTargetFolder(), RelativePath::buildTargetFolder), - path.upToLastOccurrenceOf ("\\", false, false), cpps, headers, otherFiles); + const Project::Item& child = item.getChild (i); + + if (child.isGroup()) + addSolutionFiles (out, child, nestedProjectList, groupGuid); } + + if (parentGuid.isNotEmpty()) + nestedProjectList.add (groupGuid + String (" = ") + parentGuid); } - void addFilesToFilter (const Array& files, const String& path, - XmlElement& cpps, XmlElement& headers, XmlElement& otherFiles, XmlElement& groups) + //============================================================================== + void addPlatformSpecificSettingsForProjectType (const ProjectType& type) override { - if (files.size() > 0) - { - addFilterGroup (groups, path); + MSVCProjectExporterBase::addPlatformSpecificSettingsForProjectType (type); - for (int i = 0; i < files.size(); ++i) - addFileToFilter (files.getReference(i), path, cpps, headers, otherFiles); - } + callForAllSupportedTargets ([this] (ProjectType::Target::Type targetType) + { + if (MSVCTargetBase* target = new MSVC2010Target (targetType, *this)) + { + if (targetType != ProjectType::Target::AggregateTarget) + targets.add (target); + } + }); + + // If you hit this assert, you tried to generate a project for an exporter + // that does not support any of your targets! + jassert (targets.size() > 0); } - void fillInFiltersXml (XmlElement& filterXml) const + void create (const OwnedArray&) const override { - filterXml.setAttribute ("ToolsVersion", getToolsVersion()); - filterXml.setAttribute ("xmlns", "http://schemas.microsoft.com/developer/msbuild/2003"); + createResourcesAndIcon(); - XmlElement* groupsXml = filterXml.createNewChildElement ("ItemGroup"); - XmlElement* cpps = filterXml.createNewChildElement ("ItemGroup"); - XmlElement* headers = filterXml.createNewChildElement ("ItemGroup"); - ScopedPointer otherFilesGroup (new XmlElement ("ItemGroup")); + for (int i = 0; i < targets.size(); ++i) + if (MSVCTargetBase* target = targets[i]) + target->writeProjectFile(); - for (int i = 0; i < getAllGroups().size(); ++i) { - const Project::Item& group = getAllGroups().getReference(i); + MemoryOutputStream mo; + writeSolutionFile (mo, "11.00", getSolutionComment()); - if (group.getNumChildren() > 0) - addFilesToFilter (group, group.getName(), *cpps, *headers, *otherFilesGroup, *groupsXml); + overwriteFileIfDifferentOrThrow (getSLNFile(), mo); } + } - if (iconFile.exists()) +protected: + //============================================================================== + class VC2010BuildConfiguration : public MSVCBuildConfiguration + { + public: + VC2010BuildConfiguration (Project& p, const ValueTree& settings, const ProjectExporter& e) + : MSVCBuildConfiguration (p, settings, e) { - XmlElement* e = otherFilesGroup->createNewChildElement ("None"); - e->setAttribute ("Include", prependDot (iconFile.getFileName())); - e->createNewChildElement ("Filter")->addTextElement (ProjectSaver::getJuceCodeGroupName()); + if (getArchitectureType().toString().isEmpty()) + getArchitectureType() = get32BitArchName(); } - if (otherFilesGroup->getFirstChildElement() != nullptr) - filterXml.addChildElement (otherFilesGroup.release()); + //============================================================================== + static const char* get32BitArchName() { return "32-bit"; } + static const char* get64BitArchName() { return "x64"; } - if (hasResourceFile()) + Value getArchitectureType() { return getValue (Ids::winArchitecture); } + bool is64Bit() const { return config [Ids::winArchitecture].toString() == get64BitArchName(); } + + Value getFastMathValue() { return getValue (Ids::fastMath); } + bool isFastMathEnabled() const { return config [Ids::fastMath]; } + + //============================================================================== + void createConfigProperties (PropertyListBuilder& props) override { - XmlElement* rcGroup = filterXml.createNewChildElement ("ItemGroup"); - XmlElement* e = rcGroup->createNewChildElement ("ResourceCompile"); - e->setAttribute ("Include", prependDot (rcFile.getFileName())); - e->createNewChildElement ("Filter")->addTextElement (ProjectSaver::getJuceCodeGroupName()); + MSVCBuildConfiguration::createConfigProperties (props); + + const char* const archTypes[] = { get32BitArchName(), get64BitArchName() }; + + props.add (new ChoicePropertyComponent (getArchitectureType(), "Architecture", + StringArray (archTypes, numElementsInArray (archTypes)), + Array (archTypes, numElementsInArray (archTypes)))); + + props.add (new BooleanPropertyComponent (getFastMathValue(), "Relax IEEE compliance", "Enabled"), + "Enable this to use FAST_MATH non-IEEE mode. (Warning: this can have unexpected results!)"); } + }; + + virtual void addPlatformToolsetToPropertyGroup (XmlElement&) const {} + + void addIPPSettingToPropertyGroup (XmlElement& p) const + { + String ippLibrary = getIPPLibrary(); + + if (ippLibrary.isNotEmpty()) + forEachXmlChildElementWithTagName (p, e, "PropertyGroup") + e->createNewChildElement ("UseIntelIPP")->addTextElement (ippLibrary); + } + + BuildConfiguration::Ptr createBuildConfig (const ValueTree& v) const override + { + return new VC2010BuildConfiguration (project, v, *this); + } + + static bool is64Bit (const BuildConfiguration& config) + { + return dynamic_cast (config).is64Bit(); } + //============================================================================== + File getVCProjFile() const { return getProjectFile (".vcxproj", "App"); } + File getVCProjFiltersFile() const { return getProjectFile (".vcxproj.filters", String()); } + JUCE_DECLARE_NON_COPYABLE (MSVCProjectExporterVC2010) }; diff --git a/extras/Projucer/Source/Project Saving/jucer_ProjectExport_Make.h b/extras/Projucer/Source/Project Saving/jucer_ProjectExport_Make.h index fdcc401975..502b171d22 100644 --- a/extras/Projucer/Source/Project Saving/jucer_ProjectExport_Make.h +++ b/extras/Projucer/Source/Project Saving/jucer_ProjectExport_Make.h @@ -24,7 +24,243 @@ class MakefileProjectExporter : public ProjectExporter { +protected: + //============================================================================== + class MakeBuildConfiguration : public BuildConfiguration + { + public: + MakeBuildConfiguration (Project& p, const ValueTree& settings, const ProjectExporter& e) + : BuildConfiguration (p, settings, e) + { + } + + Value getArchitectureType() { return getValue (Ids::linuxArchitecture); } + var getArchitectureTypeVar() const { return config [Ids::linuxArchitecture]; } + + var getDefaultOptimisationLevel() const override { return var ((int) (isDebug() ? gccO0 : gccO3)); } + + void createConfigProperties (PropertyListBuilder& props) override + { + addGCCOptimisationProperty (props); + + static const char* const archNames[] = { "(Default)", "", "32-bit (-m32)", "64-bit (-m64)", "ARM v6", "ARM v7" }; + const var archFlags[] = { var(), var (String()), "-m32", "-m64", "-march=armv6", "-march=armv7" }; + + props.add (new ChoicePropertyComponent (getArchitectureType(), "Architecture", + StringArray (archNames, numElementsInArray (archNames)), + Array (archFlags, numElementsInArray (archFlags)))); + } + + String getLibrarySubdirPath () const override + { + const String archFlag = getArchitectureTypeVar(); + + const auto prefix = String ("-march="); + if (archFlag.startsWith (prefix)) + return archFlag.substring (prefix.length()); + else if (archFlag == "-m64") + return "x86_64"; + else if (archFlag == "-m32") + return "i386"; + else + return "$(shell uname -m)"; + } + }; + + BuildConfiguration::Ptr createBuildConfig (const ValueTree& tree) const override + { + return new MakeBuildConfiguration (project, tree, *this); + } + public: + //============================================================================== + class MakefileTarget : public ProjectType::Target + { + public: + MakefileTarget (ProjectType::Target::Type targetType, const MakefileProjectExporter& exporter) + : ProjectType::Target (targetType), owner (exporter) + {} + + StringArray getTargetSettings (const BuildConfiguration& config) const + { + if (type == AggregateTarget) + // the aggregate target should not specify any settings at all! + // it just defines dependencies on the other targets. + return StringArray(); + + StringPairArray commonOptions = owner.getAllPreprocessorDefs (config, ProjectType::Target::unspecified); + StringPairArray targetSpecific = owner.getAllPreprocessorDefs (config, type); + + StringArray defs; + + // remove any defines that have already been added by the configuration + const int n = targetSpecific.size(); + for (int i = 0 ; i < n; ++i) + { + const String& key = targetSpecific.getAllKeys()[i]; + + if (! commonOptions.getAllKeys().contains (key)) + defs.add (String ("-D") + key + String ("=") + targetSpecific.getAllValues()[i]); + } + + StringArray s; + + const String cppflagsVarName = String ("JUCE_CPPFLAGS_") + getTargetVarName(); + + s.add (cppflagsVarName + String (" := ") + defs.joinIntoString (" ")); + + if (getTargetFileType() == sharedLibraryOrDLL || getTargetFileType() == pluginBundle) + { + s.add (String ("JUCE_CFLAGS_") + getTargetVarName() + String (" := -fPIC")); + + const String ldflagsVarName = String ("JUCE_LDFLAGS_") + getTargetVarName(); + String targetLinkOptions = ldflagsVarName + String (" := -shared"); + + if (getTargetFileType() == pluginBundle) + targetLinkOptions += " -Wl,--no-undefined"; + + s.add (targetLinkOptions); + } + + String targetName (owner.replacePreprocessorTokens (config, config.getTargetBinaryNameString())); + + if (owner.projectType.isStaticLibrary() || owner.projectType.isDynamicLibrary()) + targetName = getLibbedFilename (targetName); + else + targetName = targetName.upToLastOccurrenceOf (".", false, false) + getTargetFileSuffix(); + + s.add (String ("JUCE_TARGET_") + getTargetVarName() + String (" := ") + escapeSpaces (targetName)); + + return s; + } + + String getTargetFileSuffix() const + { + switch (type) + { + case VSTPlugIn: + return ".so"; + case VST3PlugIn: + return ".vst3"; + case SharedCodeTarget: + return ".a"; + default: + break; + } + + return String(); + } + + String getTargetVarName() const + { + return String (getName()).toUpperCase().replaceCharacter (L' ', L'_'); + } + + void writeObjects (OutputStream& out) const + { + Array targetFiles; + for (int i = 0; i < owner.getAllGroups().size(); ++i) + findAllFilesToCompile (owner.getAllGroups().getReference(i), targetFiles); + + out << "OBJECTS_" + getTargetVarName() + String (" := \\") << newLine; + + for (int i = 0; i < targetFiles.size(); ++i) + out << " $(JUCE_OBJDIR)/" << escapeSpaces (owner.getObjectFileFor (targetFiles.getReference(i))) << " \\" << newLine; + + out << newLine; + } + + void findAllFilesToCompile (const Project::Item& projectItem, Array& results) const + { + if (projectItem.isGroup()) + { + for (int i = 0; i < projectItem.getNumChildren(); ++i) + findAllFilesToCompile (projectItem.getChild(i), results); + } + else + { + if (projectItem.shouldBeCompiled()) + { + const Type targetType = (owner.getProject().getProjectType().isAudioPlugin() ? type : SharedCodeTarget); + const File f = projectItem.getFile(); + RelativePath relativePath (f, owner.getTargetFolder(), RelativePath::buildTargetFolder); + + if (owner.shouldFileBeCompiledByDefault (relativePath) + && owner.getProject().getTargetTypeFromFilePath (f, true) == targetType) + results.add (relativePath); + } + } + } + + void addFiles (OutputStream& out) + { + Array targetFiles; + for (int i = 0; i < owner.getAllGroups().size(); ++i) + findAllFilesToCompile (owner.getAllGroups().getReference(i), targetFiles); + + const String cppflagsVarName = String ("JUCE_CPPFLAGS_") + getTargetVarName(); + const String cflagsVarName = String ("JUCE_CFLAGS_") + getTargetVarName(); + + for (int i = 0; i < targetFiles.size(); ++i) + { + jassert (targetFiles.getReference(i).getRoot() == RelativePath::buildTargetFolder); + + out << "$(JUCE_OBJDIR)/" << escapeSpaces (owner.getObjectFileFor (targetFiles.getReference(i))) + << ": " << escapeSpaces (targetFiles.getReference(i).toUnixStyle()) << newLine + << "\t-$(V_AT)mkdir -p $(JUCE_OBJDIR)" << newLine + << "\t@echo \"Compiling " << targetFiles.getReference(i).getFileName() << "\"" << newLine + << (targetFiles.getReference(i).hasFileExtension ("c;s;S") ? "\t$(V_AT)$(CC) $(JUCE_CFLAGS)" : "\t$(V_AT)$(CXX) $(JUCE_CXXFLAGS) ") + << "$(" << cppflagsVarName << ") $(" << cflagsVarName << ") -o \"$@\" -c \"$<\"" + << newLine << newLine; + } + } + + String getBuildProduct() const + { + return String ("$(JUCE_OUTDIR)/$(JUCE_TARGET_") + getTargetVarName() + String (")"); + } + + void writeTargetLine (OutputStream& out, const bool useLinuxPackages) + { + jassert (type != AggregateTarget); + + out << getBuildProduct() << " : " + << ((useLinuxPackages) ? "check-pkg-config " : "") + << "$(OBJECTS_" << getTargetVarName() << ") $(RESOURCES)"; + + if (type != SharedCodeTarget && owner.shouldBuildTargetType (SharedCodeTarget)) + out << " $(JUCE_OUTDIR)/$(JUCE_TARGET_SHARED_CODE)"; + + out << newLine << "\t@echo Linking \"" << owner.projectName << " (" << getName() << ")\"" << newLine + << "\t-$(V_AT)mkdir -p $(JUCE_BINDIR)" << newLine + << "\t-$(V_AT)mkdir -p $(JUCE_LIBDIR)" << newLine + << "\t-$(V_AT)mkdir -p $(JUCE_OUTDIR)" << newLine; + + if (owner.projectType.isStaticLibrary() || type == SharedCodeTarget) + out << "\t$(V_AT)$(AR) -rcs " << getBuildProduct() + << " $(OBJECTS_" << getTargetVarName() << ")" << newLine; + else + { + out << "\t$(V_AT)$(CXX) -o " << getBuildProduct() + << " $(OBJECTS_" << getTargetVarName() << ") "; + + if (owner.shouldBuildTargetType (SharedCodeTarget)) + out << "$(JUCE_OUTDIR)/$(JUCE_TARGET_SHARED_CODE) "; + + out << "$(JUCE_LDFLAGS) "; + + if (getTargetFileType() == sharedLibraryOrDLL || getTargetFileType() == pluginBundle) + out << "$(JUCE_LDFLAGS_" << getTargetVarName() << ") "; + + out << "$(RESOURCES) $(TARGET_ARCH)" << newLine; + } + + out << newLine; + } + + const MakefileProjectExporter& owner; + }; + //============================================================================== static const char* getNameLinux() { return "Linux Makefile"; } static const char* getValueTreeTypeName() { return "LINUX_MAKE"; } @@ -72,13 +308,25 @@ public: bool isOSX() const override { return false; } bool isiOS() const override { return false; } - bool supportsVST() const override { return true; } - bool supportsVST3() const override { return false; } - bool supportsAAX() const override { return false; } - bool supportsRTAS() const override { return false; } - bool supportsAU() const override { return false; } - bool supportsAUv3() const override { return false; } - bool supportsStandalone() const override { return false; } + bool supportsTargetType (ProjectType::Target::Type type) const override + { + switch (type) + { + case ProjectType::Target::GUIApp: + case ProjectType::Target::ConsoleApp: + case ProjectType::Target::StaticLibrary: + case ProjectType::Target::SharedCodeTarget: + case ProjectType::Target::AggregateTarget: + case ProjectType::Target::VSTPlugIn: + case ProjectType::Target::StandalonePlugIn: + case ProjectType::Target::DynamicLibrary: + return true; + default: + break; + } + + return false; + } Value getCppStandardValue() { return getSetting (Ids::cppLanguageStandard); } String getCppStandardString() const { return settings[Ids::cppLanguageStandard]; } @@ -99,81 +347,49 @@ public: } //============================================================================== - void create (const OwnedArray&) const override + bool anyTargetIsSharedLibrary() const { - Array files; - for (int i = 0; i < getAllGroups().size(); ++i) - findAllFilesToCompile (getAllGroups().getReference(i), files); - - MemoryOutputStream mo; - writeMakefile (mo, files); + const int n = targets.size(); + for (int i = 0; i < n; ++i) + { + const ProjectType::Target::TargetFileType fileType = targets.getUnchecked (i)->getTargetFileType(); + if (fileType == ProjectType::Target::sharedLibraryOrDLL || fileType == ProjectType::Target::pluginBundle) + return true; + } - overwriteFileIfDifferentOrThrow (getTargetFolder().getChildFile ("Makefile"), mo); + return false; } //============================================================================== - void addPlatformSpecificSettingsForProjectType (const ProjectType& type) override + void create (const OwnedArray&) const override { - if (type.isStaticLibrary()) - makefileTargetSuffix = ".a"; + MemoryOutputStream mo; + writeMakefile (mo); - else if (type.isAudioPlugin() || type.isDynamicLibrary()) - { - makefileIsDLL = true; - if (type.isDynamicLibrary()) - makefileTargetSuffix = ".so"; - } + overwriteFileIfDifferentOrThrow (getTargetFolder().getChildFile ("Makefile"), mo); } -protected: //============================================================================== - class MakeBuildConfiguration : public BuildConfiguration + void addPlatformSpecificSettingsForProjectType (const ProjectType&) override { - public: - MakeBuildConfiguration (Project& p, const ValueTree& settings, const ProjectExporter& e) - : BuildConfiguration (p, settings, e) - { - } - - Value getArchitectureType() { return getValue (Ids::linuxArchitecture); } - var getArchitectureTypeVar() const { return config [Ids::linuxArchitecture]; } - - var getDefaultOptimisationLevel() const override { return var ((int) (isDebug() ? gccO0 : gccO3)); } - - void createConfigProperties (PropertyListBuilder& props) override - { - addGCCOptimisationProperty (props); - - static const char* const archNames[] = { "(Default)", "", "32-bit (-m32)", "64-bit (-m64)", "ARM v6", "ARM v7" }; - const var archFlags[] = { var(), var (String()), "-m32", "-m64", "-march=armv6", "-march=armv7" }; - - props.add (new ChoicePropertyComponent (getArchitectureType(), "Architecture", - StringArray (archNames, numElementsInArray (archNames)), - Array (archFlags, numElementsInArray (archFlags)))); - } - }; - - BuildConfiguration::Ptr createBuildConfig (const ValueTree& tree) const override - { - return new MakeBuildConfiguration (project, tree, *this); + callForAllSupportedTargets ([this] (ProjectType::Target::Type targetType) + { + if (MakefileTarget* target = new MakefileTarget (targetType, *this)) + { + if (targetType == ProjectType::Target::AggregateTarget) + targets.insert (0, target); + else + targets.add (target); + } + }); + + // If you hit this assert, you tried to generate a project for an exporter + // that does not support any of your targets! + jassert (targets.size() > 0); } private: //============================================================================== - void findAllFilesToCompile (const Project::Item& projectItem, Array& results) const - { - if (projectItem.isGroup()) - { - for (int i = 0; i < projectItem.getNumChildren(); ++i) - findAllFilesToCompile (projectItem.getChild(i), results); - } - else - { - if (projectItem.shouldBeCompiled()) - results.add (RelativePath (projectItem.getFile(), getTargetFolder(), RelativePath::buildTargetFolder)); - } - } - void writeDefineFlags (OutputStream& out, const BuildConfiguration& config) const { StringPairArray defines; @@ -189,7 +405,7 @@ private: defines.set ("NDEBUG", "1"); } - out << createGCCPreprocessorFlags (mergePreprocessorDefs (defines, getAllPreprocessorDefs (config))); + out << createGCCPreprocessorFlags (mergePreprocessorDefs (defines, getAllPreprocessorDefs (config, ProjectType::Target::unspecified))); } void writeHeaderPathFlags (OutputStream& out, const BuildConfiguration& config) const @@ -239,9 +455,6 @@ private: { StringArray flags (makefileExtraLinkerFlags); - if (makefileIsDLL) - flags.add ("-shared"); - if (! config.isDebug()) flags.add ("-fvisibility=hidden"); @@ -282,6 +495,36 @@ private: << " $(LDFLAGS)" << newLine; } + void writeTargetLines (OutputStream& out, const bool useLinuxPackages) const + { + const int n = targets.size(); + + for (int i = 0; i < n; ++i) + { + if (MakefileTarget* target = targets.getUnchecked (i)) + { + if (target->type == ProjectType::Target::AggregateTarget) + { + StringArray dependencies; + for (int j = 0; j < n; ++j) + { + if (i == j) continue; + + if (MakefileTarget* dependency = targets.getUnchecked (j)) + { + if (dependency->type != ProjectType::Target::SharedCodeTarget) + dependencies.add (dependency->getBuildProduct()); + } + } + + out << "all : " << dependencies.joinIntoString (" ") << newLine << newLine; + } + else + target->writeTargetLine (out, useLinuxPackages); + } + } + } + void writeConfig (OutputStream& out, const BuildConfiguration& config) const { const String buildDirName ("build"); @@ -307,14 +550,24 @@ private: writeCppFlags (out, config); + for (auto target : targets) + { + StringArray lines = target->getTargetSettings (config); + + if (lines.size() > 0) + out << " " << lines.joinIntoString ("\n ") << newLine; + + out << newLine; + } + out << " JUCE_CFLAGS += $(JUCE_CPPFLAGS) $(TARGET_ARCH)"; + if (anyTargetIsSharedLibrary()) + out << " -fPIC"; + if (config.isDebug()) out << " -g -ggdb"; - if (makefileIsDLL) - out << " -fPIC"; - out << " -O" << config.getGCCOptimisationFlag() << (" " + replacePreprocessorTokens (config, getExtraCompilerFlagsString())).trimEnd() << " $(CFLAGS)" << newLine; @@ -324,44 +577,19 @@ private: if (cppStandardToUse.isEmpty()) cppStandardToUse = "-std=c++11"; - out << " JUCE_CXXFLAGS += $(JUCE_CFLAGS) " + out << " JUCE_CXXFLAGS += $(CXXFLAGS) $(JUCE_CFLAGS) " << cppStandardToUse << " $(CXXFLAGS)" << newLine; writeLinkerFlags (out, config); out << newLine; - String targetName (replacePreprocessorTokens (config, config.getTargetBinaryNameString())); - - if (projectType.isStaticLibrary() || projectType.isDynamicLibrary()) - targetName = getLibbedFilename (targetName); - else - targetName = targetName.upToLastOccurrenceOf (".", false, false) + makefileTargetSuffix; - - out << " TARGET := " << escapeSpaces (targetName) << newLine; - - if (projectType.isStaticLibrary()) - out << " BLDCMD = $(AR) -rcs $(JUCE_OUTDIR)/$(TARGET) $(OBJECTS)" << newLine; - else - out << " BLDCMD = $(CXX) -o $(JUCE_OUTDIR)/$(TARGET) $(OBJECTS) $(JUCE_LDFLAGS) $(RESOURCES) $(TARGET_ARCH)" << newLine; - out << " CLEANCMD = rm -rf $(JUCE_OUTDIR)/$(TARGET) $(JUCE_OBJDIR)" << newLine << "endif" << newLine << newLine; } - void writeObjects (OutputStream& out, const Array& files) const - { - out << "OBJECTS := \\" << newLine; - - for (int i = 0; i < files.size(); ++i) - if (shouldFileBeCompiledByDefault (files.getReference(i))) - out << " $(JUCE_OBJDIR)/" << escapeSpaces (getObjectFileFor (files.getReference(i))) << " \\" << newLine; - - out << newLine; - } - - void writeMakefile (OutputStream& out, const Array& files) const + void writeMakefile (OutputStream& out) const { out << "# Automatically generated makefile, created by the Projucer" << newLine << "# Don't edit this file! Your changes will be overwritten when you re-save the Projucer project!" << newLine @@ -397,26 +625,22 @@ private: for (ConstConfigIterator config (*this); config.next();) writeConfig (out, *config); - writeObjects (out, files); + for (auto target : targets) + target->writeObjects (out); - out << ".PHONY: clean" << newLine + out << ".PHONY: clean all" << newLine << newLine; StringArray packages; packages.addTokens (getExtraPkgConfigString(), " ", "\"'"); packages.removeEmptyStrings(); - bool useLinuxPackages = (linuxPackages.size() > 0 || packages.size() > 0); + const bool useLinuxPackages = (linuxPackages.size() > 0 || packages.size() > 0); - out << "$(JUCE_OUTDIR)/$(TARGET): " - << ((useLinuxPackages) ? "check-pkg-config " : "") - << "$(OBJECTS) $(RESOURCES)" << newLine - << "\t@echo Linking " << projectName << newLine - << "\t-@mkdir -p $(JUCE_BINDIR)" << newLine - << "\t-@mkdir -p $(JUCE_LIBDIR)" << newLine - << "\t-@mkdir -p $(JUCE_OUTDIR)" << newLine - << "\t$(V_AT)$(BLDCMD)" << newLine - << newLine; + writeTargetLines (out, useLinuxPackages); + + for (auto target : targets) + target->addFiles (out); if (useLinuxPackages) { @@ -442,25 +666,9 @@ private: out << "strip:" << newLine << "\t@echo Stripping " << projectName << newLine - << "\t-@$(STRIP) --strip-unneeded $(JUCE_OUTDIR)/$(TARGET)" << newLine + << "\t-$(V_AT)$(STRIP) --strip-unneeded $(JUCE_OUTDIR)/$(TARGET)" << newLine << newLine; - for (int i = 0; i < files.size(); ++i) - { - if (shouldFileBeCompiledByDefault (files.getReference(i))) - { - jassert (files.getReference(i).getRoot() == RelativePath::buildTargetFolder); - - out << "$(JUCE_OBJDIR)/" << escapeSpaces (getObjectFileFor (files.getReference(i))) - << ": " << escapeSpaces (files.getReference(i).toUnixStyle()) << newLine - << "\t-@mkdir -p $(JUCE_OBJDIR)" << newLine - << "\t@echo \"Compiling " << files.getReference(i).getFileName() << "\"" << newLine - << (files.getReference(i).hasFileExtension ("c;s;S") ? "\t$(V_AT)$(CC) $(JUCE_CFLAGS) -o \"$@\" -c \"$<\"" - : "\t$(V_AT)$(CXX) $(JUCE_CXXFLAGS) -o \"$@\" -c \"$<\"") - << newLine << newLine; - } - } - out << "-include $(OBJECTS:%.o=%.d)" << newLine; } @@ -486,5 +694,7 @@ private: TargetOS::linux))); } + OwnedArray targets; + JUCE_DECLARE_NON_COPYABLE (MakefileProjectExporter) }; diff --git a/extras/Projucer/Source/Project Saving/jucer_ProjectExport_XCode.h b/extras/Projucer/Source/Project Saving/jucer_ProjectExport_XCode.h index b7399d8f80..0ea3822cc9 100644 --- a/extras/Projucer/Source/Project Saving/jucer_ProjectExport_XCode.h +++ b/extras/Projucer/Source/Project Saving/jucer_ProjectExport_XCode.h @@ -127,13 +127,31 @@ public: bool isOSX() const override { return ! iOS; } bool isiOS() const override { return iOS; } - bool supportsVST() const override { return ! iOS; } - bool supportsVST3() const override { return ! iOS; } - bool supportsAAX() const override { return ! iOS; } - bool supportsRTAS() const override { return ! iOS; } - bool supportsAU() const override { return ! iOS; } - bool supportsAUv3() const override { return true; } - bool supportsStandalone() const override { return true; } + bool supportsTargetType (ProjectType::Target::Type type) const override + { + switch (type) + { + case ProjectType::Target::AudioUnitv3PlugIn: + case ProjectType::Target::StandalonePlugIn: + case ProjectType::Target::GUIApp: + case ProjectType::Target::StaticLibrary: + case ProjectType::Target::SharedCodeTarget: + case ProjectType::Target::AggregateTarget: + return true; + case ProjectType::Target::ConsoleApp: + case ProjectType::Target::VSTPlugIn: + case ProjectType::Target::VST3PlugIn: + case ProjectType::Target::AAXPlugIn: + case ProjectType::Target::RTASPlugIn: + case ProjectType::Target::AudioUnitPlugIn: + case ProjectType::Target::DynamicLibrary: + return ! iOS; + default: + break; + } + + return false; + } void createExporterProperties (PropertyListBuilder& props) override { @@ -206,7 +224,8 @@ public: "You can find this string in the OS X app Keychain Access under \"Certificates\"."); props.add (new BooleanPropertyComponent (getSetting ("keepCustomXcodeSchemes"), "Keep custom Xcode schemes", "Enabled"), - "Enable this to keep any Xcode schemes you have created for debugging or running, e.g. to launch a plug-in in various hosts. If disabled, all schemes are replaced by a default set."); + "Enable this to keep any Xcode schemes you have created for debugging or running, e.g. to launch a plug-in in" + "various hosts. If disabled, all schemes are replaced by a default set."); } bool launchProject() override @@ -231,7 +250,7 @@ public: void create (const OwnedArray&) const override { for (auto& target : targets) - if (target->xcodeCreatePList) + if (target->shouldCreatePList()) target->infoPlistFile = getTargetFolder().getChildFile (target->getInfoPlistName()); menuNibFile = getTargetFolder().getChildFile ("RecentFilesMenuTemplate.nib"); @@ -265,52 +284,18 @@ public: } //============================================================================== - void addPlatformSpecificSettingsForProjectType (const ProjectType& type) override - { - if (type.isGUIApplication()) - targets.add (new Target (Target::GUIApp, *this)); - - else if (type.isCommandLineApp()) - targets.add (new Target (Target::ConsoleApp, *this)); - - else if (type.isStaticLibrary()) - targets.add (new Target (Target::StaticLibrary, *this)); - - else if (type.isDynamicLibrary()) - targets.add (new Target (Target::DynamicLibrary, *this)); - - else if (type.isAudioPlugin()) - { - if (project.shouldBuildVST().getValue() && supportsVST()) - targets.add (new Target (Target::VSTPlugIn, *this)); - - if (project.shouldBuildVST3().getValue() && supportsVST3()) - targets.add (new Target (Target::VST3PlugIn, *this)); - - if (project.shouldBuildAU().getValue() && supportsAU()) - targets.add (new Target (Target::AudioUnitPlugIn, *this)); - - if (project.shouldBuildAUv3().getValue()) - targets.add (new Target (Target::AudioUnitv3PlugIn, *this)); - - if (project.shouldBuildAAX().getValue() && supportsAAX()) - targets.add (new Target (Target::AAXPlugIn, *this)); - - if (project.shouldBuildStandalone().getValue()) - targets.add (new Target (Target::StandalonePlugIn, *this)); - - if (project.shouldBuildRTAS().getValue() && supportsRTAS()) - { - targets.add (new Target (Target::RTASPlugIn, *this)); - addRTASPluginSettings(); - } - - if (targets.size() > 0) - targets.add (new Target (Target::SharedCodeTarget, *this)); - } - - if (targets.size() > 1) - targets.insert (0, new Target (Target::AggregateTarget, *this)); + void addPlatformSpecificSettingsForProjectType (const ProjectType&) override + { + callForAllSupportedTargets ([this] (ProjectType::Target::Type targetType) + { + if (XCodeTarget* target = new XCodeTarget (targetType, *this)) + { + if (targetType == ProjectType::Target::AggregateTarget) + targets.insert (0, target); + else + targets.add (target); + } + }); // If you hit this assert, you tried to generate a project for an exporter // that does not support any of your targets! @@ -400,7 +385,9 @@ protected: osxVersionNames.add ("Use Default"); versionValues.add (osxVersionDefault); - for (int ver = oldestSDKVersion; ver <= currentSDKVersion; ++ver) + int oldestAllowedSDKVersion = project.shouldBuildAUv3() ? minimumAUv3SDKVersion : oldestSDKVersion; + + for (int ver = oldestAllowedSDKVersion; ver <= currentSDKVersion; ++ver) { sdkVersionNames.add (getSDKName (ver)); osxVersionNames.add (getOSXVersionName (ver)); @@ -463,27 +450,32 @@ protected: "Enable this to strip any locally defined symbols resulting in a smaller binary size. Enabling this will also remove any function names from crash logs. Must be disabled for static library projects."); } + String getLibrarySubdirPath () const override + { + return "${CURRENT_ARCH}"; + } + private: //========================================================================== void addXcodePluginInstallPathProperties (PropertyListBuilder& props) { - if (project.shouldBuildVST().getValue()) + if (project.shouldBuildVST()) props.add (new TextWithDefaultPropertyComponent (vstBinaryLocation, "VST Binary location", 1024), "The folder in which the compiled VST binary should be placed."); - if (project.shouldBuildVST3().getValue()) + if (project.shouldBuildVST3()) props.add (new TextWithDefaultPropertyComponent (vst3BinaryLocation, "VST3 Binary location", 1024), "The folder in which the compiled VST3 binary should be placed."); - if (project.shouldBuildAU().getValue()) + if (project.shouldBuildAU()) props.add (new TextWithDefaultPropertyComponent (auBinaryLocation, "AU Binary location", 1024), "The folder in which the compiled AU binary should be placed."); - if (project.shouldBuildRTAS().getValue()) + if (project.shouldBuildRTAS()) props.add (new TextWithDefaultPropertyComponent (rtasBinaryLocation, "RTAS Binary location", 1024), "The folder in which the compiled RTAS binary should be placed."); - if (project.shouldBuildAAX().getValue()) + if (project.shouldBuildAAX()) props.add (new TextWithDefaultPropertyComponent (aaxBinaryLocation, "AAX Binary location", 1024), "The folder in which the compiled AAX binary should be placed."); } @@ -513,40 +505,16 @@ public: }; //============================================================================== - struct Target + struct XCodeTarget : ProjectType::Target { - enum Type - { - GUIApp = 0, - ConsoleApp = 1, - StaticLibrary = 2, - DynamicLibrary = 3, - - VSTPlugIn = 10, - VST3PlugIn = 11, - AAXPlugIn = 12, - RTASPlugIn = 13, - AudioUnitPlugIn = 14, - AudioUnitv3PlugIn = 15, - StandalonePlugIn = 16, - - SharedCodeTarget = 20, // internal - AggregateTarget = 21, - - unspecified = 30 - }; - //============================================================================== - Target (Type targetType, const XCodeProjectExporter& exporter) - : type (targetType), + XCodeTarget (ProjectType::Target::Type targetType, const XCodeProjectExporter& exporter) + : ProjectType::Target (targetType), owner (exporter) { switch (type) { case GUIApp: - xcodeIsBundle = false; - xcodeIsExecutable = true; - xcodeCreatePList = true; xcodePackageType = "APPL"; xcodeBundleSignature = "????"; xcodeFileType = "wrapper.application"; @@ -556,9 +524,6 @@ public: break; case ConsoleApp: - xcodeIsBundle = false; - xcodeIsExecutable = true; - xcodeCreatePList = false; xcodeFileType = "compiled.mach-o.executable"; xcodeBundleExtension = String(); xcodeProductType = "com.apple.product-type.tool"; @@ -566,55 +531,37 @@ public: break; case StaticLibrary: - xcodeIsBundle = false; - xcodeIsExecutable = false; - xcodeCreatePList = false; xcodeFileType = "archive.ar"; xcodeProductType = "com.apple.product-type.library.static"; xcodeCopyToProductInstallPathAfterBuild = false; break; case DynamicLibrary: - xcodeIsBundle = false; - xcodeIsExecutable = false; - xcodeCreatePList = false; xcodeFileType = "compiled.mach-o.dylib"; xcodeProductType = "com.apple.product-type.library.dynamic"; xcodeBundleExtension = ".dylib"; xcodeCopyToProductInstallPathAfterBuild = false; - break; case VSTPlugIn: - xcodeIsBundle = true; - xcodeIsExecutable = false; - xcodeCreatePList = true; xcodePackageType = "BNDL"; xcodeBundleSignature = "????"; xcodeFileType = "wrapper.cfbundle"; xcodeBundleExtension = ".vst"; xcodeProductType = "com.apple.product-type.bundle"; xcodeCopyToProductInstallPathAfterBuild = true; - break; case VST3PlugIn: - xcodeIsBundle = true; - xcodeIsExecutable = false; - xcodeCreatePList = true; xcodePackageType = "BNDL"; xcodeBundleSignature = "????"; xcodeFileType = "wrapper.cfbundle"; xcodeBundleExtension = ".vst3"; xcodeProductType = "com.apple.product-type.bundle"; xcodeCopyToProductInstallPathAfterBuild = true; - break; case AudioUnitPlugIn: - xcodeIsBundle = true; - xcodeIsExecutable = false; - xcodeCreatePList = true; xcodePackageType = "BNDL"; xcodeBundleSignature = "????"; xcodeFileType = "wrapper.cfbundle"; @@ -626,12 +573,8 @@ public: break; case StandalonePlugIn: - xcodeIsBundle = false; - xcodeIsExecutable = true; - xcodeCreatePList = true; xcodePackageType = "APPL"; xcodeBundleSignature = "????"; - xcodeCreatePList = true; xcodeFileType = "wrapper.application"; xcodeBundleExtension = ".app"; xcodeProductType = "com.apple.product-type.application"; @@ -639,9 +582,6 @@ public: break; case AudioUnitv3PlugIn: - xcodeIsBundle = false; - xcodeIsExecutable = false; - xcodeCreatePList = true; xcodePackageType = "XPC!"; xcodeBundleSignature = "????"; xcodeFileType = "wrapper.app-extension"; @@ -654,9 +594,6 @@ public: break; case AAXPlugIn: - xcodeIsBundle = true; - xcodeIsExecutable = false; - xcodeCreatePList = true; xcodePackageType = "TDMw"; xcodeBundleSignature = "PTul"; xcodeFileType = "wrapper.cfbundle"; @@ -668,9 +605,6 @@ public: break; case RTASPlugIn: - xcodeIsBundle = true; - xcodeIsExecutable = false; - xcodeCreatePList = true; xcodePackageType = "TDMw"; xcodeBundleSignature = "PTul"; xcodeFileType = "wrapper.cfbundle"; @@ -682,18 +616,12 @@ public: break; case SharedCodeTarget: - xcodeIsBundle = false; - xcodeIsExecutable = false; - xcodeCreatePList = false; xcodeFileType = "archive.ar"; xcodeProductType = "com.apple.product-type.library.static"; xcodeCopyToProductInstallPathAfterBuild = false; break; case AggregateTarget: - xcodeIsBundle = false; - xcodeIsExecutable = false; - xcodeCreatePList = false; xcodeCopyToProductInstallPathAfterBuild = false; break; @@ -704,40 +632,11 @@ public: } } - const char* getName() const noexcept - { - switch (type) - { - case GUIApp: return "App"; - case ConsoleApp: return "ConsoleApp"; - case StaticLibrary: return "Static Library"; - case DynamicLibrary: return "Dynamic Library"; - case VSTPlugIn: return "VST"; - case VST3PlugIn: return "VST3"; - case AudioUnitPlugIn: return "AU"; - case StandalonePlugIn: return "AUv3 Standalone"; - case AudioUnitv3PlugIn: return "AUv3 AppExtension"; - case AAXPlugIn: return "AAX"; - case RTASPlugIn: return "RTAS"; - case SharedCodeTarget: return "Shared Code"; - case AggregateTarget: return "All"; - default: return "undefined"; - } - } - String getXCodeSchemeName() const { return owner.projectName + " (" + getName() + ")"; } - bool shouldBuildVST() const { return owner.supportsVST() && owner.project.shouldBuildVST().getValue() && (type == SharedCodeTarget || type == VSTPlugIn); } - bool shouldBuildVST3() const { return owner.supportsVST3() && owner.project.shouldBuildVST3().getValue() && (type == SharedCodeTarget || type == VST3PlugIn); } - bool shouldBuildAAX() const { return owner.supportsAAX() && owner.project.shouldBuildAAX().getValue() && (type == SharedCodeTarget || type == AAXPlugIn); } - bool shouldBuildRTAS() const { return owner.supportsRTAS() && owner.project.shouldBuildRTAS().getValue() && (type == SharedCodeTarget || type == RTASPlugIn); } - bool shouldBuildAU() const { return owner.supportsAU() && owner.project.shouldBuildAU().getValue() && (type == SharedCodeTarget || type == AudioUnitPlugIn); } - bool shouldBuildAUv3() const { return owner.supportsAUv3() && owner.project.shouldBuildAUv3().getValue() && (type == SharedCodeTarget || type == AudioUnitv3PlugIn); } - bool shouldBuildStandalone() const { return owner.project.shouldBuildStandalone().getValue() && (type == SharedCodeTarget || type == StandalonePlugIn); } - String getID() const { return owner.createID (String ("__target") + getName()); @@ -751,9 +650,8 @@ public: String xcodePackageType, xcodeBundleSignature, xcodeBundleExtension; String xcodeProductType, xcodeFileType; String xcodeOtherRezFlags, xcodeExcludedFiles64Bit, xcodeBundleIDSubPath; - bool xcodeIsBundle, xcodeCreatePList, xcodeIsExecutable, xcodeCopyToProductInstallPathAfterBuild; + bool xcodeCopyToProductInstallPathAfterBuild; StringArray xcodeFrameworks, xcodeLibs; - Type type; Array xcodeExtraPListEntries; Array xcodeExtraLibrariesDebug, xcodeExtraLibrariesRelease; @@ -874,6 +772,12 @@ public: return *v; } + bool shouldCreatePList() const + { + const ProjectType::Target::TargetFileType fileType = getTargetFileType(); + return (fileType == executable && type != ConsoleApp) || fileType == pluginBundle || fileType == macOSAppex; + } + //============================================================================== StringArray getTargetSettings (const XcodeBuildConfiguration& config) const { @@ -904,7 +808,7 @@ public: s.add ("HEADER_SEARCH_PATHS = " + owner.getHeaderSearchPaths (config)); s.add ("GCC_OPTIMIZATION_LEVEL = " + config.getGCCOptimisationFlag()); - if (xcodeCreatePList) + if (shouldCreatePList()) s.add ("INFOPLIST_FILE = " + infoPlistFile.getFileName()); if (config.linkTimeOptimisationEnabled.get()) @@ -930,7 +834,7 @@ public: } } - if (xcodeIsBundle) + if (getTargetFileType() == pluginBundle) { s.add ("LIBRARY_STYLE = Bundle"); s.add ("WRAPPER_EXTENSION = " + xcodeBundleExtension.substring (1)); @@ -970,9 +874,7 @@ public: // if the user doesn't set it, then use the last known version that works well with JUCE String deploymentTarget = "10.11"; - int oldestAllowedSDKVersion = (type == AudioUnitv3PlugIn || type == StandalonePlugIn) ? minimumAUv3SDKVersion : oldestSDKVersion; - - for (int ver = oldestAllowedSDKVersion; ver <= currentSDKVersion; ++ver) + for (int ver = oldestSDKVersion; ver <= currentSDKVersion; ++ver) { if (sdk == getSDKName (ver)) s.add ("SDKROOT = macosx10." + String (ver)); if (sdkCompat == getSDKName (ver)) deploymentTarget = "10." + String (ver); @@ -1052,24 +954,10 @@ public: s.add ("SEPARATE_STRIP = YES"); } - if (type == Target::SharedCodeTarget) - defines.set ("JUCE_SHARED_CODE", "1"); - if (owner.project.getProjectType().isAudioPlugin() && type == Target::AudioUnitv3PlugIn && owner.isOSX()) s.add (String ("CODE_SIGN_ENTITLEMENTS = \"") + owner.getEntitlementsFileName() + String ("\"")); - if (owner.project.getProjectType().isAudioPlugin()) - { - defines.set ("JucePlugin_Build_VST", (shouldBuildVST() ? "1" : "0")); - defines.set ("JucePlugin_Build_VST3", (shouldBuildVST3() ? "1" : "0")); - defines.set ("JucePlugin_Build_AU", (shouldBuildAU() ? "1" : "0")); - defines.set ("JucePlugin_Build_AUv3", (shouldBuildAUv3() ? "1" : "0")); - defines.set ("JucePlugin_Build_RTAS", (shouldBuildRTAS() ? "1" : "0")); - defines.set ("JucePlugin_Build_AAX", (shouldBuildAAX() ? "1" : "0")); - defines.set ("JucePlugin_Build_Standalone", (shouldBuildStandalone() ? "1" : "0")); - } - - defines = mergePreprocessorDefs (defines, owner.getAllPreprocessorDefs (config)); + defines = mergePreprocessorDefs (defines, owner.getAllPreprocessorDefs (config, type)); StringArray defsList; @@ -1109,7 +997,7 @@ public: //============================================================================== void getLinkerSettings (const BuildConfiguration& config, StringArray& flags, StringArray& librarySearchPaths) const { - if (xcodeIsBundle) + if (getTargetFileType() == pluginBundle) flags.add (owner.isiOS() ? "-bitcode_bundle" : "-bundle"); const Array& extraLibs = config.isDebug() ? xcodeExtraLibrariesDebug @@ -1147,7 +1035,7 @@ public: //========================================================================== c void writeInfoPlistFile() const { - if (! xcodeCreatePList) + if (! shouldCreatePList()) return; ScopedPointer plist (XmlDocument::parse (owner.getPListToMergeString())); @@ -1409,7 +1297,7 @@ public: private: //============================================================================== bool xcodeCanUseDwarf; - OwnedArray targets; + OwnedArray targets; mutable OwnedArray pbxBuildFiles, pbxFileReferences, pbxGroups, misc, projectConfigs, targetConfigs; mutable StringArray resourceIDs, sourceIDs, targetIDs; @@ -1471,7 +1359,7 @@ private: { for (auto* target : targets) { - if (target->type == Target::AggregateTarget) + if (target->type == XCodeTarget::AggregateTarget) continue; target->addMainBuildProduct(); @@ -1495,10 +1383,10 @@ private: { for (auto* target : targets) { - if (target->type == Target::AggregateTarget) + if (target->type == XCodeTarget::AggregateTarget) continue; - if (target->xcodeCreatePList) + if (target->shouldCreatePList()) { RelativePath plistPath (target->infoPlistFile, getTargetFolder(), RelativePath::buildTargetFolder); addFileReference (plistPath.toUnixStyle()); @@ -1576,7 +1464,7 @@ private: // add build phases for (auto* target : targets) { - if (target->type != Target::AggregateTarget) + if (target->type != XCodeTarget::AggregateTarget) buildProducts.add (createID (String ("__productFileID") + String (target->getName()))); for (ConstConfigIterator config (*this); config.next();) @@ -1589,11 +1477,11 @@ private: target->addShellScriptBuildPhase ("Pre-build script", getPreBuildScript()); - if (target->type != Target::AggregateTarget) + if (target->type != XCodeTarget::AggregateTarget) { // TODO: ideally resources wouldn't be copied into the AUv3 bundle as well. // However, fixing this requires supporting App groups -> TODO: add app groups - if (! projectType.isStaticLibrary() && target->type != Target::SharedCodeTarget) + if (! projectType.isStaticLibrary() && target->type != XCodeTarget::SharedCodeTarget) target->addBuildPhase ("PBXResourcesBuildPhase", resourceIDs); StringArray rezFiles (rezFileIDs); @@ -1604,20 +1492,20 @@ private: StringArray sourceFiles (target->sourceIDs); - if (target->type == Target::SharedCodeTarget + if (target->type == XCodeTarget::SharedCodeTarget || (! project.getProjectType().isAudioPlugin())) sourceFiles.addArray (sourceIDs); target->addBuildPhase ("PBXSourcesBuildPhase", sourceFiles); - if (! projectType.isStaticLibrary() && target->type != Target::SharedCodeTarget) + if (! projectType.isStaticLibrary() && target->type != XCodeTarget::SharedCodeTarget) target->addBuildPhase ("PBXFrameworksBuildPhase", target->frameworkIDs); } target->addShellScriptBuildPhase ("Post-build script", getPostBuildScript()); - if (project.getProjectType().isAudioPlugin() && project.shouldBuildAUv3().getValue() - && project.shouldBuildStandalone().getValue() && target->type == Target::StandalonePlugIn) + if (project.getProjectType().isAudioPlugin() && project.shouldBuildAUv3() + && project.shouldBuildStandalonePlugin() && target->type == XCodeTarget::StandalonePlugIn) embedAppExtension(); addTargetObject (*target); @@ -1626,9 +1514,9 @@ private: void embedAppExtension() const { - if (auto* standaloneTarget = getTargetOfType (Target::StandalonePlugIn)) + if (auto* standaloneTarget = getTargetOfType (XCodeTarget::StandalonePlugIn)) { - if (auto* auv3Target = getTargetOfType (Target::AudioUnitv3PlugIn)) + if (auto* auv3Target = getTargetOfType (XCodeTarget::AudioUnitv3PlugIn)) { StringArray files; files.add (auv3Target->mainBuildProductID); @@ -1662,7 +1550,7 @@ private: } //============================================================================== - Target* getTargetOfType (Target::Type type) const + XCodeTarget* getTargetOfType (ProjectType::Target::Type type) const { for (auto& target : targets) if (target->type == type) @@ -1671,13 +1559,13 @@ private: return nullptr; } - void addTargetObject (Target& target) const + void addTargetObject (XCodeTarget& target) const { String targetName = target.getName(); String targetID = target.getID(); ValueTree* const v = new ValueTree (targetID); - v->setProperty ("isa", target.type == Target::AggregateTarget ? "PBXAggregateTarget" : "PBXNativeTarget", nullptr); + v->setProperty ("isa", target.type == XCodeTarget::AggregateTarget ? "PBXAggregateTarget" : "PBXNativeTarget", nullptr); v->setProperty ("buildConfigurationList", createID (String ("__configList") + targetName), nullptr); v->setProperty ("buildPhases", indentParenthesisedList (target.buildPhaseIDs), nullptr); @@ -1687,7 +1575,7 @@ private: v->setProperty (Ids::name, target.getXCodeSchemeName(), nullptr); v->setProperty ("productName", projectName, nullptr); - if (target.type != Target::AggregateTarget) + if (target.type != XCodeTarget::AggregateTarget) { v->setProperty ("productReference", createID (String ("__productFileID") + targetName), nullptr); @@ -1699,28 +1587,28 @@ private: misc.add (v); } - StringArray getTargetDependencies (const Target& target) const + StringArray getTargetDependencies (const XCodeTarget& target) const { StringArray dependencies; if (project.getProjectType().isAudioPlugin()) { - if (target.type == Target::StandalonePlugIn) // depends on AUv3 and shared code + if (target.type == XCodeTarget::StandalonePlugIn) // depends on AUv3 and shared code { - if (Target* auv3Target = getTargetOfType (Target::AudioUnitv3PlugIn)) + if (XCodeTarget* auv3Target = getTargetOfType (XCodeTarget::AudioUnitv3PlugIn)) dependencies.add (auv3Target->getDependencyID()); - if (Target* sharedCodeTarget = getTargetOfType (Target::SharedCodeTarget)) + if (XCodeTarget* sharedCodeTarget = getTargetOfType (XCodeTarget::SharedCodeTarget)) dependencies.add (sharedCodeTarget->getDependencyID()); } - else if (target.type == Target::AggregateTarget) // depends on all other targets + else if (target.type == XCodeTarget::AggregateTarget) // depends on all other targets { for (int i = 1; i < targets.size(); ++i) dependencies.add (targets[i]->getDependencyID()); } - else if (target.type != Target::SharedCodeTarget) // shared code doesn't depend on anything; all other targets depend only on the shared code + else if (target.type != XCodeTarget::SharedCodeTarget) // shared code doesn't depend on anything; all other targets depend only on the shared code { - if (Target* sharedCodeTarget = getTargetOfType (Target::SharedCodeTarget)) + if (XCodeTarget* sharedCodeTarget = getTargetOfType (XCodeTarget::SharedCodeTarget)) dependencies.add (sharedCodeTarget->getDependencyID()); } } @@ -2099,7 +1987,7 @@ private: output << "\t};\n\trootObject = " << createID ("__root") << ";\n}\n"; } - String addBuildFile (const String& path, const String& fileRefID, bool addToSourceBuildPhase, bool inhibitWarnings, Target* xcodeTarget = nullptr) const + String addBuildFile (const String& path, const String& fileRefID, bool addToSourceBuildPhase, bool inhibitWarnings, XCodeTarget* xcodeTarget = nullptr) const { String fileID (createID (path + "buildref")); @@ -2120,7 +2008,7 @@ private: return fileID; } - String addBuildFile (const RelativePath& path, bool addToSourceBuildPhase, bool inhibitWarnings, Target* xcodeTarget = nullptr) const + String addBuildFile (const RelativePath& path, bool addToSourceBuildPhase, bool inhibitWarnings, XCodeTarget* xcodeTarget = nullptr) const { return addBuildFile (path.toUnixStyle(), createFileRefID (path), addToSourceBuildPhase, inhibitWarnings, xcodeTarget); } @@ -2204,7 +2092,7 @@ private: } String addFile (const RelativePath& path, bool shouldBeCompiled, bool shouldBeAddedToBinaryResources, - bool shouldBeAddedToXcodeResources, bool inhibitWarnings, Target* xcodeTarget) const + bool shouldBeAddedToXcodeResources, bool inhibitWarnings, XCodeTarget* xcodeTarget) const { const String pathAsString (path.toUnixStyle()); const String refID (addFileReference (path.toUnixStyle())); @@ -2234,7 +2122,7 @@ private: if (projectItem.isModuleCode()) { - if (Target* xcodeTarget = getTargetOfType (getTargetTypeFromFilePath (projectItem.getFile(), false))) + if (XCodeTarget* xcodeTarget = getTargetOfType (getProject().getTargetTypeFromFilePath (projectItem.getFile(), false))) { String rezFileID = addBuildFile (pathAsString, refID, false, false, xcodeTarget); xcodeTarget->rezFileIDs.add (rezFileID); @@ -2299,9 +2187,9 @@ private: if (path.hasFileExtension (".r")) return addRezFile (projectItem, path); - Target* xcodeTarget = nullptr; + XCodeTarget* xcodeTarget = nullptr; if (projectItem.isModuleCode() && projectItem.shouldBeCompiled()) - xcodeTarget = getTargetOfType (getTargetTypeFromFilePath (projectItem.getFile(), false)); + xcodeTarget = getTargetOfType (project.getTargetTypeFromFilePath (projectItem.getFile(), false)); return addFile (path, projectItem.shouldBeCompiled(), projectItem.shouldBeAddedToBinaryResources(), @@ -2357,7 +2245,7 @@ private: projectConfigs.add (v); } - void addConfigList (Target& target, const OwnedArray& configsToUse, const String& listID) const + void addConfigList (XCodeTarget& target, const OwnedArray & configsToUse, const String& listID) const { ValueTree* v = new ValueTree (listID); v->setProperty ("isa", "XCConfigurationList", nullptr); @@ -2370,7 +2258,7 @@ private: misc.add (v); } - void addProjectConfigList (const OwnedArray& configsToUse, const String& listID) const + void addProjectConfigList (const OwnedArray & configsToUse, const String& listID) const { StringArray configIDs; @@ -2405,19 +2293,6 @@ private: misc.add (v); } - static Target::Type getTargetTypeFromFilePath (const File& file, bool returnSharedTargetIfNoValidSuffic) - { - if (LibraryModule::CompileUnit::hasSuffix (file, "_AU")) return Target::AudioUnitPlugIn; - else if (LibraryModule::CompileUnit::hasSuffix (file, "_AUv3")) return Target::AudioUnitv3PlugIn; - else if (LibraryModule::CompileUnit::hasSuffix (file, "_AAX")) return Target::AAXPlugIn; - else if (LibraryModule::CompileUnit::hasSuffix (file, "_RTAS")) return Target::RTASPlugIn; - else if (LibraryModule::CompileUnit::hasSuffix (file, "_VST2")) return Target::VSTPlugIn; - else if (LibraryModule::CompileUnit::hasSuffix (file, "_VST3")) return Target::VST3PlugIn; - else if (LibraryModule::CompileUnit::hasSuffix (file, "_Standalone")) return Target::StandalonePlugIn; - - return (returnSharedTargetIfNoValidSuffic ? Target::SharedCodeTarget : Target::unspecified); - } - //============================================================================== void removeMismatchedXcuserdata() const { diff --git a/extras/Projucer/Source/Project Saving/jucer_ProjectExporter.cpp b/extras/Projucer/Source/Project Saving/jucer_ProjectExporter.cpp index f0382e847d..7acac0d3bc 100644 --- a/extras/Projucer/Source/Project Saving/jucer_ProjectExporter.cpp +++ b/extras/Projucer/Source/Project Saving/jucer_ProjectExporter.cpp @@ -173,15 +173,11 @@ bool ProjectExporter::canProjectBeLaunched (Project* project) //============================================================================== ProjectExporter::ProjectExporter (Project& p, const ValueTree& state) - : makefileIsDLL (false), - msvcIsDLL (false), - msvcIsWindowsSubsystem (true), - settings (state), + : settings (state), project (p), projectType (p.getProjectType()), projectName (p.getTitle()), - projectFolder (p.getProjectFolder()), - modulesGroup (nullptr) + projectFolder (p.getProjectFolder()) { } @@ -242,19 +238,19 @@ void ProjectExporter::createPropertyEditors (PropertyListBuilder& props) void ProjectExporter::createDependencyPathProperties (PropertyListBuilder& props) { - if (supportsVST3() && (project.shouldBuildVST3().getValue() || project.isVST3PluginHost())) + if (shouldBuildTargetType (ProjectType::Target::VST3PlugIn) || project.isVST3PluginHost()) { props.add (new DependencyPathPropertyComponent (project.getFile().getParentDirectory(), getVST3PathValue(), "VST3 SDK Folder"), "If you're building a VST3 plugin or host, this must be the folder containing the VST3 SDK. This can be an absolute path, or a path relative to the Projucer project file."); } - if (supportsAAX() && project.shouldBuildAAX().getValue()) + if (shouldBuildTargetType (ProjectType::Target::AAXPlugIn) && project.shouldBuildAAX()) { props.add (new DependencyPathPropertyComponent (project.getFile().getParentDirectory(), getAAXPathValue(), "AAX SDK Folder"), "If you're building an AAX plugin, this must be the folder containing the AAX SDK. This can be an absolute path, or a path relative to the Projucer project file."); } - if (supportsRTAS() && project.shouldBuildRTAS().getValue()) + if (shouldBuildTargetType (ProjectType::Target::RTASPlugIn) && project.shouldBuildRTAS()) { props.add (new DependencyPathPropertyComponent (project.getFile().getParentDirectory(), getRTASPathValue(), "RTAS SDK Folder"), "If you're building an RTAS, this must be the folder containing the RTAS SDK. This can be an absolute path, or a path relative to the Projucer project file."); @@ -300,25 +296,17 @@ void ProjectExporter::addSettingsForProjectType (const ProjectType& type) void ProjectExporter::addVSTPathsIfPluginOrHost() { - if (supportsVST() && project.shouldBuildVST().getValue()) - makefileTargetSuffix = ".so"; - - if (supportsVST3()) - { - if (project.shouldBuildVST3().getValue()) - makefileTargetSuffix = ".so"; - - if (project.shouldBuildVST3().getValue() || project.isVST3PluginHost()) - addVST3FolderToPath(); - } + if (shouldBuildTargetType (ProjectType::Target::VST3PlugIn) || project.isVST3PluginHost()) + addVST3FolderToPath(); } void ProjectExporter::addCommonAudioPluginSettings() { - if (isLinux() && (getProject().shouldBuildVST().getValue() || getProject().shouldBuildVST3().getValue())) + if (isLinux() + && (shouldBuildTargetType (ProjectType::Target::VSTPlugIn) || shouldBuildTargetType (ProjectType::Target::VST3PlugIn))) makefileExtraLinkerFlags.add ("-Wl,--no-undefined"); - if (supportsAAX() && getProject().shouldBuildAAX().getValue()) + if (shouldBuildTargetType (ProjectType::Target::AAXPlugIn)) addAAXFoldersToPath(); // Note: RTAS paths are platform-dependent, impl -> addPlatformSpecificSettingsForProjectType @@ -347,11 +335,13 @@ void ProjectExporter::addAAXFoldersToPath() } //============================================================================== -StringPairArray ProjectExporter::getAllPreprocessorDefs (const ProjectExporter::BuildConfiguration& config) const +StringPairArray ProjectExporter::getAllPreprocessorDefs (const BuildConfiguration& config, const ProjectType::Target::Type targetType) const { StringPairArray defs (mergePreprocessorDefs (config.getAllPreprocessorDefs(), parsePreprocessorDefs (getExporterPreprocessorDefsString()))); addDefaultPreprocessorDefs (defs); + addTargetSpecificPreprocessorDefs (defs, targetType); + return defs; } @@ -363,6 +353,31 @@ StringPairArray ProjectExporter::getAllPreprocessorDefs() const return defs; } +void ProjectExporter::addTargetSpecificPreprocessorDefs (StringPairArray& defs, const ProjectType::Target::Type targetType) const +{ + if (targetType == ProjectType::Target::SharedCodeTarget) + { + defs.set ("JucePlugin_Build_VST", (shouldBuildTargetType (ProjectType::Target::VSTPlugIn) ? "1" : "0")); + defs.set ("JucePlugin_Build_VST3", (shouldBuildTargetType (ProjectType::Target::VST3PlugIn) ? "1" : "0")); + defs.set ("JucePlugin_Build_AU", (shouldBuildTargetType (ProjectType::Target::AudioUnitPlugIn) ? "1" : "0")); + defs.set ("JucePlugin_Build_AUv3", (shouldBuildTargetType (ProjectType::Target::AudioUnitv3PlugIn) ? "1" : "0")); + defs.set ("JucePlugin_Build_RTAS", (shouldBuildTargetType (ProjectType::Target::RTASPlugIn) ? "1" : "0")); + defs.set ("JucePlugin_Build_AAX", (shouldBuildTargetType (ProjectType::Target::AAXPlugIn) ? "1" : "0")); + defs.set ("JucePlugin_Build_Standalone", (shouldBuildTargetType (ProjectType::Target::StandalonePlugIn) ? "1" : "0")); + defs.set ("JUCE_SHARED_CODE", "1"); + } + else if (targetType != ProjectType::Target::unspecified) + { + defs.set ("JucePlugin_Build_VST", (targetType == ProjectType::Target::VSTPlugIn ? "1" : "0")); + defs.set ("JucePlugin_Build_VST3", (targetType == ProjectType::Target::VST3PlugIn ? "1" : "0")); + defs.set ("JucePlugin_Build_AU", (targetType == ProjectType::Target::AudioUnitPlugIn ? "1" : "0")); + defs.set ("JucePlugin_Build_AUv3", (targetType == ProjectType::Target::AudioUnitv3PlugIn ? "1" : "0")); + defs.set ("JucePlugin_Build_RTAS", (targetType == ProjectType::Target::RTASPlugIn ? "1" : "0")); + defs.set ("JucePlugin_Build_AAX", (targetType == ProjectType::Target::AAXPlugIn ? "1" : "0")); + defs.set ("JucePlugin_Build_Standalone", (targetType == ProjectType::Target::StandalonePlugIn ? "1" : "0")); + } +} + void ProjectExporter::addDefaultPreprocessorDefs (StringPairArray& defs) const { defs.set (getExporterIdentifierMacro(), "1"); @@ -370,9 +385,10 @@ void ProjectExporter::addDefaultPreprocessorDefs (StringPairArray& defs) const defs.set ("JUCE_APP_VERSION_HEX", project.getVersionAsHex()); } -String ProjectExporter::replacePreprocessorTokens (const ProjectExporter::BuildConfiguration& config, const String& sourceString) const +String ProjectExporter::replacePreprocessorTokens (const ProjectExporter::BuildConfiguration& config, + const String& sourceString) const { - return replacePreprocessorDefs (getAllPreprocessorDefs (config), sourceString); + return replacePreprocessorDefs (getAllPreprocessorDefs (config, ProjectType::Target::unspecified), sourceString); } void ProjectExporter::copyMainGroupFromProject() @@ -393,14 +409,24 @@ Project::Item& ProjectExporter::getModulesGroup() return *modulesGroup; } -void ProjectExporter::addToExtraSearchPaths (const RelativePath& pathFromProjectFolder, int index) +void ProjectExporter::addProjectPathToBuildPathList (StringArray& pathList, const RelativePath& pathFromProjectFolder, int index) { - RelativePath localPath (rebaseFromProjectFolderToBuildTarget (pathFromProjectFolder)); + const auto localPath = RelativePath (rebaseFromProjectFolderToBuildTarget (pathFromProjectFolder)); + + const auto path = isVisualStudio() ? localPath.toWindowsStyle() : localPath.toUnixStyle(); - const String path (isVisualStudio() ? localPath.toWindowsStyle() : localPath.toUnixStyle()); + if (! pathList.contains (path)) + pathList.insert (index, path); +} - if (! extraSearchPaths.contains (path)) - extraSearchPaths.insert (index, path); +void ProjectExporter::addToModuleLibPaths (const RelativePath& pathFromProjectFolder) +{ + addProjectPathToBuildPathList (moduleLibSearchPaths, pathFromProjectFolder); +} + +void ProjectExporter::addToExtraSearchPaths (const RelativePath& pathFromProjectFolder, int index) +{ + addProjectPathToBuildPathList (extraSearchPaths, pathFromProjectFolder, index); } Value ProjectExporter::getPathForModuleValue (const String& moduleID) @@ -810,16 +836,24 @@ StringArray ProjectExporter::BuildConfiguration::getHeaderSearchPaths() const StringArray ProjectExporter::BuildConfiguration::getLibrarySearchPaths() const { - return getSearchPathsFromString (getLibrarySearchPathString()); + auto separator = exporter.isVisualStudio() ? "\\" : "/"; + auto s = getSearchPathsFromString (getLibrarySearchPathString()); + for (auto path : exporter.moduleLibSearchPaths) + s.add (path + separator + getLibrarySubdirPath()); + + return s; } String ProjectExporter::BuildConfiguration::getGCCLibraryPathFlags() const { String s; - const StringArray libraryPaths (getLibrarySearchPaths()); + const auto libraryPaths = getSearchPathsFromString (getLibrarySearchPathString()); + + for (auto path : libraryPaths) + s << " -L" << escapeSpaces (path).replace ("~", "$(HOME)"); - for (int i = 0; i < libraryPaths.size(); ++i) - s << " -L" << escapeSpaces (libraryPaths[i]).replace ("~", "$(HOME)"); + for (auto path : exporter.moduleLibSearchPaths) + s << " -L" << escapeSpaces (path).replace ("~", "$(HOME)") << "/" << getLibrarySubdirPath(); return s; } diff --git a/extras/Projucer/Source/Project Saving/jucer_ProjectExporter.h b/extras/Projucer/Source/Project Saving/jucer_ProjectExporter.h index cb7ea20bc8..34eb31f4ee 100644 --- a/extras/Projucer/Source/Project Saving/jucer_ProjectExporter.h +++ b/extras/Projucer/Source/Project Saving/jucer_ProjectExporter.h @@ -84,14 +84,21 @@ public: virtual bool isOSX() const = 0; virtual bool isiOS() const = 0; + //============================================================================== // cross-platform audio plug-ins supported by exporter - virtual bool supportsVST() const = 0; - virtual bool supportsVST3() const = 0; - virtual bool supportsAAX() const = 0; - virtual bool supportsRTAS() const = 0; - virtual bool supportsAU() const = 0; - virtual bool supportsAUv3() const = 0; - virtual bool supportsStandalone() const = 0; // as in Standalong plug-in type, not GUIApp or ConsoleApp + virtual bool supportsTargetType (ProjectType::Target::Type type) const = 0; + + inline bool shouldBuildTargetType (ProjectType::Target::Type type) const + { + return project.shouldBuildTargetType (type) && supportsTargetType (type); + } + + inline void callForAllSupportedTargets (std::function callback) + { + for (int i = 0; i < ProjectType::Target::unspecified; ++i) + if (shouldBuildTargetType (static_cast (i))) + callback (static_cast (i)); + } //============================================================================== bool mayCompileOnCurrentOS() const @@ -150,6 +157,7 @@ public: RelativePath rebaseFromProjectFolderToBuildTarget (const RelativePath& path) const; void addToExtraSearchPaths (const RelativePath& pathFromProjectFolder, int index = -1); + void addToModuleLibPaths (const RelativePath& pathFromProjectFolder); Value getBigIconImageItemID() { return getSetting (Ids::bigIcon); } Value getSmallIconImageItemID() { return getSetting (Ids::smallIcon); } @@ -187,19 +195,16 @@ public: Project::Item& getModulesGroup(); //============================================================================== - String makefileTargetSuffix; - bool makefileIsDLL; StringArray linuxLibs, linuxPackages, makefileExtraLinkerFlags; //============================================================================== - String msvcTargetSuffix; StringPairArray msvcExtraPreprocessorDefs; - bool msvcIsDLL, msvcIsWindowsSubsystem; String msvcDelayLoadedDLLs; - StringArray mingwLibs; + StringArray mingwLibs, windowsLibs; //============================================================================== StringArray extraSearchPaths; + StringArray moduleLibSearchPaths; //============================================================================== class BuildConfiguration : public ReferenceCountedObject @@ -213,6 +218,8 @@ public: //============================================================================== virtual void createConfigProperties (PropertyListBuilder&) = 0; virtual var getDefaultOptimisationLevel() const = 0; + virtual String getLibrarySubdirPath() const { return String(); } + //============================================================================== Value getNameValue() { return getValue (Ids::name); } @@ -316,10 +323,12 @@ public: String getExporterPreprocessorDefsString() const { return getSettingString (Ids::extraDefs); } // includes exporter, project + config defs - StringPairArray getAllPreprocessorDefs (const BuildConfiguration& config) const; + StringPairArray getAllPreprocessorDefs (const BuildConfiguration& config, const ProjectType::Target::Type targetType) const; // includes exporter + project defs.. StringPairArray getAllPreprocessorDefs() const; + void addTargetSpecificPreprocessorDefs (StringPairArray& defs, const ProjectType::Target::Type targetType) const; + String replacePreprocessorTokens (const BuildConfiguration&, const String& sourceString) const; ValueTree settings; @@ -345,7 +354,7 @@ protected: mutable Array itemGroups; void initItemGroups() const; - Project::Item* modulesGroup; + Project::Item* modulesGroup = nullptr; virtual BuildConfiguration::Ptr createBuildConfig (const ValueTree&) const = 0; @@ -408,6 +417,7 @@ private: void addCommonAudioPluginSettings(); void addVST3FolderToPath(); void addAAXFoldersToPath(); + void addProjectPathToBuildPathList (StringArray&, const RelativePath&, int index = -1); JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (ProjectExporter) }; diff --git a/extras/Projucer/Source/Project Saving/jucer_ProjectSaver.cpp b/extras/Projucer/Source/Project Saving/jucer_ProjectSaver.cpp index 31ab009504..2ca0f9f4a7 100644 --- a/extras/Projucer/Source/Project Saving/jucer_ProjectSaver.cpp +++ b/extras/Projucer/Source/Project Saving/jucer_ProjectSaver.cpp @@ -73,13 +73,13 @@ namespace void ProjectSaver::writePluginCharacteristicsFile() { StringPairArray flags; - flags.set ("JucePlugin_Build_VST", valueToBool (project.shouldBuildVST())); - flags.set ("JucePlugin_Build_VST3", valueToBool (project.shouldBuildVST3())); - flags.set ("JucePlugin_Build_AU", valueToBool (project.shouldBuildAU())); - flags.set ("JucePlugin_Build_AUv3", valueToBool (project.shouldBuildAUv3())); - flags.set ("JucePlugin_Build_RTAS", valueToBool (project.shouldBuildRTAS())); - flags.set ("JucePlugin_Build_AAX", valueToBool (project.shouldBuildAAX())); - flags.set ("JucePlugin_Build_STANDALONE", valueToBool (project.shouldBuildStandalone())); + flags.set ("JucePlugin_Build_VST", valueToBool (project.getShouldBuildVSTAsValue())); + flags.set ("JucePlugin_Build_VST3", valueToBool (project.getShouldBuildVST3AsValue())); + flags.set ("JucePlugin_Build_AU", valueToBool (project.getShouldBuildAUAsValue())); + flags.set ("JucePlugin_Build_AUv3", valueToBool (project.getShouldBuildAUv3AsValue())); + flags.set ("JucePlugin_Build_RTAS", valueToBool (project.getShouldBuildRTASAsValue())); + flags.set ("JucePlugin_Build_AAX", valueToBool (project.getShouldBuildAAXAsValue())); + flags.set ("JucePlugin_Build_STANDALONE", valueToBool (project.getShouldBuildStandalonePluginAsValue())); flags.set ("JucePlugin_Name", valueToStringLiteral (project.getPluginName())); flags.set ("JucePlugin_Desc", valueToStringLiteral (project.getPluginDesc())); flags.set ("JucePlugin_Manufacturer", valueToStringLiteral (project.getPluginManufacturer())); diff --git a/extras/Projucer/Source/Project/jucer_Module.cpp b/extras/Projucer/Source/Project/jucer_Module.cpp index 307e458aa9..d681e2d71d 100644 --- a/extras/Projucer/Source/Project/jucer_Module.cpp +++ b/extras/Projucer/Source/Project/jucer_Module.cpp @@ -303,21 +303,34 @@ static void parseAndAddLibs (StringArray& libList, const String& libs) void LibraryModule::addSettingsForModuleToExporter (ProjectExporter& exporter, ProjectSaver& projectSaver) const { - Project& project = exporter.getProject(); + auto& project = exporter.getProject(); - RelativePath modulePath = exporter.getModuleFolderRelativeToProject (getID()); + const auto moduleRelativePath = exporter.getModuleFolderRelativeToProject (getID()); - exporter.addToExtraSearchPaths (modulePath.getParentDirectory()); + exporter.addToExtraSearchPaths (moduleRelativePath.getParentDirectory()); - const String extraInternalSearchPaths (moduleInfo.getExtraSearchPaths().trim()); + String libDirPlatform; + if (exporter.isLinux()) + libDirPlatform = "Linux"; + else if (exporter.isCodeBlocks() && exporter.isWindows()) + libDirPlatform = "MinGW"; + else + libDirPlatform = exporter.getTargetFolder().getFileName(); + + const auto libSubdirPath = String (moduleRelativePath.toUnixStyle() + "/libs/") + libDirPlatform; + const auto moduleLibDir = File (project.getProjectFolder().getFullPathName() + "/" + libSubdirPath); + if (moduleLibDir.exists()) + exporter.addToModuleLibPaths (RelativePath (libSubdirPath, moduleRelativePath.getRoot())); + + const auto extraInternalSearchPaths = moduleInfo.getExtraSearchPaths().trim(); if (extraInternalSearchPaths.isNotEmpty()) { StringArray paths; paths.addTokens (extraInternalSearchPaths, true); for (int i = 0; i < paths.size(); ++i) - exporter.addToExtraSearchPaths (modulePath.getChildFile (paths.getReference(i))); + exporter.addToExtraSearchPaths (moduleRelativePath.getChildFile (paths.getReference(i))); } { @@ -357,9 +370,12 @@ void LibraryModule::addSettingsForModuleToExporter (ProjectExporter& exporter, P parseAndAddLibs (exporter.linuxLibs, moduleInfo.moduleInfo ["linuxLibs"].toString()); parseAndAddLibs (exporter.linuxPackages, moduleInfo.moduleInfo ["linuxPackages"].toString()); } - else if (exporter.isCodeBlocks() && exporter.isWindows()) + else if (exporter.isWindows()) { - parseAndAddLibs (exporter.mingwLibs, moduleInfo.moduleInfo ["mingwLibs"].toString()); + if (exporter.isCodeBlocks()) + parseAndAddLibs (exporter.mingwLibs, moduleInfo.moduleInfo ["mingwLibs"].toString()); + else + parseAndAddLibs (exporter.windowsLibs, moduleInfo.moduleInfo ["windowsLibs"].toString()); } } @@ -424,20 +440,15 @@ void LibraryModule::CompileUnit::writeInclude (MemoryOutputStream&) const bool LibraryModule::CompileUnit::isNeededForExporter (ProjectExporter& exporter) const { - Project& project = exporter.getProject(); - if ((hasSuffix (file, "_OSX") && ! exporter.isOSX()) || (hasSuffix (file, "_iOS") && ! exporter.isiOS()) || (hasSuffix (file, "_Windows") && ! exporter.isWindows()) || (hasSuffix (file, "_Linux") && ! exporter.isLinux()) - || (hasSuffix (file, "_Android") && ! exporter.isAndroid()) - || (hasSuffix (file, "_AU") && ! (project.shouldBuildAU() .getValue() && exporter.supportsAU())) - || (hasSuffix (file, "_AUv3") && ! (project.shouldBuildAUv3().getValue() && exporter.supportsAUv3())) - || (hasSuffix (file, "_AAX") && ! (project.shouldBuildAAX() .getValue() && exporter.supportsAAX())) - || (hasSuffix (file, "_RTAS") && ! (project.shouldBuildRTAS().getValue() && exporter.supportsRTAS())) - || (hasSuffix (file, "_VST2") && ! (project.shouldBuildVST() .getValue() && exporter.supportsVST())) - || (hasSuffix (file, "_VST3") && ! (project.shouldBuildVST3().getValue() && exporter.supportsVST3())) - || (hasSuffix (file, "_Standalone") && ! (project.shouldBuildStandalone().getValue() && exporter.supportsStandalone()))) + || (hasSuffix (file, "_Android") && ! exporter.isAndroid())) + return false; + + const ProjectType::Target::Type targetType = Project::getTargetTypeFromFilePath (file, false); + if (targetType != ProjectType::Target::unspecified && ! exporter.shouldBuildTargetType (targetType)) return false; return exporter.usesMMFiles() ? isCompiledForObjC diff --git a/extras/Projucer/Source/Project/jucer_Project.cpp b/extras/Projucer/Source/Project/jucer_Project.cpp index b3b09ba4a3..1d30292872 100644 --- a/extras/Projucer/Source/Project/jucer_Project.cpp +++ b/extras/Projucer/Source/Project/jucer_Project.cpp @@ -24,7 +24,6 @@ #include "../jucer_Headers.h" #include "jucer_Project.h" -#include "jucer_ProjectType.h" #include "../Project Saving/jucer_ProjectExporter.h" #include "../Project Saving/jucer_ProjectSaver.h" #include "../Application/jucer_OpenDocumentManager.h" @@ -147,13 +146,13 @@ void Project::setMissingAudioPluginDefaultValues() { const String sanitisedProjectName (CodeHelpers::makeValidIdentifier (getTitle(), false, true, false)); - setValueIfVoid (shouldBuildVST(), true); - setValueIfVoid (shouldBuildVST3(), false); - setValueIfVoid (shouldBuildAU(), true); - setValueIfVoid (shouldBuildAUv3(), false); - setValueIfVoid (shouldBuildRTAS(), false); - setValueIfVoid (shouldBuildAAX(), false); - setValueIfVoid (shouldBuildStandalone(), false); + setValueIfVoid (getShouldBuildVSTAsValue(), true); + setValueIfVoid (getShouldBuildVST3AsValue(), false); + setValueIfVoid (getShouldBuildAUAsValue(), true); + setValueIfVoid (getShouldBuildAUv3AsValue(), false); + setValueIfVoid (getShouldBuildRTASAsValue(), false); + setValueIfVoid (getShouldBuildAAXAsValue(), false); + setValueIfVoid (getShouldBuildStandalonePluginAsValue(), false); setValueIfVoid (getPluginName(), getTitle()); setValueIfVoid (getPluginDesc(), getTitle()); @@ -222,10 +221,19 @@ void Project::removeDefunctExporters() for (;;) { - ValueTree oldVC6Exporter (exporters.getChildWithName ("MSVC6")); + ValueTree oldVC6Exporter (exporters.getChildWithName ("MSVC6")); + ValueTree oldAndroidAntExporter (exporters.getChildWithName ("ANDROID")); - if (oldVC6Exporter.isValid()) + if (oldVC6Exporter.isValid()) exporters.removeChild (oldVC6Exporter, nullptr); + else if (oldAndroidAntExporter.isValid()) + { + AlertWindow::showMessageBox (AlertWindow::WarningIcon, + TRANS("Android Ant Exporter"), + TRANS("The Android Ant Exporter is deprecated. The exporter will be removed from this project.")); + + exporters.removeChild (oldAndroidAntExporter, nullptr); + } else break; } @@ -436,6 +444,98 @@ const ProjectType& Project::getProjectType() const return *guiType; } +bool Project::shouldBuildTargetType (ProjectType::Target::Type targetType) const noexcept +{ + const ProjectType& projectType = getProjectType(); + + if (! projectType.supportsTargetType (targetType)) + return false; + + switch (targetType) + { + case ProjectType::Target::VSTPlugIn: + return shouldBuildVST(); + case ProjectType::Target::VST3PlugIn: + return shouldBuildVST3(); + case ProjectType::Target::AAXPlugIn: + return shouldBuildAAX(); + case ProjectType::Target::RTASPlugIn: + return shouldBuildRTAS(); + case ProjectType::Target::AudioUnitPlugIn: + return shouldBuildAU(); + case ProjectType::Target::AudioUnitv3PlugIn: + return shouldBuildAUv3(); + case ProjectType::Target::StandalonePlugIn: + return shouldBuildStandalonePlugin(); + case ProjectType::Target::AggregateTarget: + case ProjectType::Target::SharedCodeTarget: + return projectType.isAudioPlugin(); + case ProjectType::Target::unspecified: + return false; + default: + break; + } + + return true; +} + +ProjectType::Target::Type Project::getTargetTypeFromFilePath (const File& file, bool returnSharedTargetIfNoValidSuffix) +{ + if (LibraryModule::CompileUnit::hasSuffix (file, "_AU")) return ProjectType::Target::AudioUnitPlugIn; + else if (LibraryModule::CompileUnit::hasSuffix (file, "_AUv3")) return ProjectType::Target::AudioUnitv3PlugIn; + else if (LibraryModule::CompileUnit::hasSuffix (file, "_AAX")) return ProjectType::Target::AAXPlugIn; + else if (LibraryModule::CompileUnit::hasSuffix (file, "_RTAS")) return ProjectType::Target::RTASPlugIn; + else if (LibraryModule::CompileUnit::hasSuffix (file, "_VST2")) return ProjectType::Target::VSTPlugIn; + else if (LibraryModule::CompileUnit::hasSuffix (file, "_VST3")) return ProjectType::Target::VST3PlugIn; + else if (LibraryModule::CompileUnit::hasSuffix (file, "_Standalone")) return ProjectType::Target::StandalonePlugIn; + + return (returnSharedTargetIfNoValidSuffix ? ProjectType::Target::SharedCodeTarget : ProjectType::Target::unspecified); +} + +const char* ProjectType::Target::getName() const noexcept +{ + switch (type) + { + case GUIApp: return "App"; + case ConsoleApp: return "ConsoleApp"; + case StaticLibrary: return "Static Library"; + case DynamicLibrary: return "Dynamic Library"; + case VSTPlugIn: return "VST"; + case VST3PlugIn: return "VST3"; + case AudioUnitPlugIn: return "AU"; + case StandalonePlugIn: return "Standalone Plugin"; + case AudioUnitv3PlugIn: return "AUv3 AppExtension"; + case AAXPlugIn: return "AAX"; + case RTASPlugIn: return "RTAS"; + case SharedCodeTarget: return "Shared Code"; + case AggregateTarget: return "All"; + default: return "undefined"; + } +} + +ProjectType::Target::TargetFileType ProjectType::Target::getTargetFileType() const noexcept +{ + switch (type) + { + case GUIApp: return executable; + case ConsoleApp: return executable; + case StaticLibrary: return staticLibrary; + case DynamicLibrary: return sharedLibraryOrDLL; + case VSTPlugIn: return pluginBundle; + case VST3PlugIn: return pluginBundle; + case AudioUnitPlugIn: return pluginBundle; + case StandalonePlugIn: return executable; + case AudioUnitv3PlugIn: return macOSAppex; + case AAXPlugIn: return pluginBundle; + case RTASPlugIn: return pluginBundle; + case SharedCodeTarget: return staticLibrary; + default: + break; + } + + return unknown; +} + //============================================================================== void Project::createPropertyEditors (PropertyListBuilder& props) { @@ -515,25 +615,20 @@ void Project::createPropertyEditors (PropertyListBuilder& props) void Project::createAudioPluginPropertyEditors (PropertyListBuilder& props) { - props.add (new BooleanPropertyComponent (shouldBuildVST(), "Build VST", "Enabled"), + props.add (new BooleanPropertyComponent (getShouldBuildVSTAsValue(), "Build VST", "Enabled"), "Whether the project should produce a VST plugin."); - props.add (new BooleanPropertyComponent (shouldBuildVST3(), "Build VST3", "Enabled"), + props.add (new BooleanPropertyComponent (getShouldBuildVST3AsValue(), "Build VST3", "Enabled"), "Whether the project should produce a VST3 plugin."); - props.add (new BooleanPropertyComponent (shouldBuildAU(), "Build AudioUnit", "Enabled"), + props.add (new BooleanPropertyComponent (getShouldBuildAUAsValue(), "Build AudioUnit", "Enabled"), "Whether the project should produce an AudioUnit plugin."); - props.add (new BooleanPropertyComponent (shouldBuildAUv3(), "Build AudioUnit v3", "Enabled"), + props.add (new BooleanPropertyComponent (getShouldBuildAUv3AsValue(), "Build AudioUnit v3", "Enabled"), "Whether the project should produce an AudioUnit version 3 plugin."); - props.add (new BooleanPropertyComponent (shouldBuildRTAS(), "Build RTAS", "Enabled"), + props.add (new BooleanPropertyComponent (getShouldBuildRTASAsValue(), "Build RTAS", "Enabled"), "Whether the project should produce an RTAS plugin."); - props.add (new BooleanPropertyComponent (shouldBuildAAX(), "Build AAX", "Enabled"), + props.add (new BooleanPropertyComponent (getShouldBuildAAXAsValue(), "Build AAX", "Enabled"), "Whether the project should produce an AAX plugin."); - - /* TODO: this property editor is temporarily disabled because right now we build standalone if and only if - we also build AUv3. However as soon as targets are supported on non-Xcode exporters as well, we should - re-enable this option and allow to build the standalone plug-in independently from AUv3. - */ - // props.add (new BooleanPropertyComponent (shouldBuildStandalone(), "Build Standalone", "Enabled"), - // "Whether the project should produce a standalone version of the plugin. Required for AUv3."); + props.add (new BooleanPropertyComponent (getShouldBuildStandalonePluginAsValue(), "Build Standalone Plug-In", "Enabled"), + "Whether the project should produce a standalone version of your plugin."); props.add (new TextPropertyComponent (getPluginName(), "Plugin Name", 128, false), "The name of your plugin (keep it short!)"); diff --git a/extras/Projucer/Source/Project/jucer_Project.h b/extras/Projucer/Source/Project/jucer_Project.h index f78b008aca..ca5c4f5797 100644 --- a/extras/Projucer/Source/Project/jucer_Project.h +++ b/extras/Projucer/Source/Project/jucer_Project.h @@ -25,8 +25,9 @@ #ifndef JUCER_PROJECT_H_INCLUDED #define JUCER_PROJECT_H_INCLUDED +#include "jucer_ProjectType.h" + class ProjectExporter; -class ProjectType; class LibraryModule; class EnabledModuleList; @@ -95,7 +96,8 @@ public: Value getCompanyEmail() { return getProjectValue (Ids::companyEmail); } //============================================================================== - Value getProjectValue (const Identifier& name) { return projectRoot.getPropertyAsValue (name, getUndoManagerFor (projectRoot)); } + Value getProjectValue (const Identifier& name) { return projectRoot.getPropertyAsValue (name, getUndoManagerFor (projectRoot)); } + var getProjectVar (const Identifier& name) const { return projectRoot.getProperty (name); } Value getProjectPreprocessorDefs() { return getProjectValue (Ids::defines); } StringPairArray getPreprocessorDefs() const; @@ -122,13 +124,23 @@ public: //============================================================================== // Some helper methods for audio plugin/host projects. - Value shouldBuildVST() { return getProjectValue ("buildVST"); } - Value shouldBuildVST3() { return getProjectValue ("buildVST3"); } - Value shouldBuildAU() { return getProjectValue ("buildAU"); } - Value shouldBuildAUv3() { return getProjectValue ("buildAUv3"); } - Value shouldBuildRTAS() { return getProjectValue ("buildRTAS"); } - Value shouldBuildAAX() { return getProjectValue ("buildAAX"); } - Value shouldBuildStandalone() { return shouldBuildAUv3(); /* TODO: enable this when standalone becomes independent from AUv3: getProjectValue ("buildStandalone"); */} + Value getShouldBuildVSTAsValue() { return getProjectValue ("buildVST"); } + Value getShouldBuildVST3AsValue() { return getProjectValue ("buildVST3"); } + Value getShouldBuildAUAsValue() { return getProjectValue ("buildAU"); } + Value getShouldBuildAUv3AsValue() { return getProjectValue ("buildAUv3"); } + Value getShouldBuildRTASAsValue() { return getProjectValue ("buildRTAS"); } + Value getShouldBuildAAXAsValue() { return getProjectValue ("buildAAX"); } + Value getShouldBuildStandalonePluginAsValue() { return getProjectValue ("buildStandalone");} + + bool shouldBuildVST() const { return getProjectVar ("buildVST"); } + bool shouldBuildVST3() const { return getProjectVar ("buildVST3"); } + bool shouldBuildAU() const { return getProjectVar ("buildAU"); } + bool shouldBuildAUv3() const { return getProjectVar ("buildAUv3"); } + bool shouldBuildRTAS() const { return getProjectVar ("buildRTAS"); } + bool shouldBuildAAX() const { return getProjectVar ("buildAAX"); } + bool shouldBuildStandalonePlugin() const { return getProjectVar ("buildStandalone"); } + + //============================================================================== Value getPluginName() { return getProjectValue ("pluginName"); } Value getPluginDesc() { return getProjectValue ("pluginDesc"); } Value getPluginManufacturer() { return getProjectValue ("pluginManufacturer"); } @@ -158,6 +170,10 @@ public: bool isVSTPluginHost(); bool isVST3PluginHost(); + bool shouldBuildTargetType (ProjectType::Target::Type targetType) const noexcept; + static ProjectType::Target::Type getTargetTypeFromFilePath (const File& file, bool returnSharedTargetIfNoValidSuffix); + + //============================================================================== void updateDeprecatedProjectSettingsInteractively(); //============================================================================== diff --git a/extras/Projucer/Source/Project/jucer_ProjectType.h b/extras/Projucer/Source/Project/jucer_ProjectType.h index ac620879e1..090eb1b8fa 100644 --- a/extras/Projucer/Source/Project/jucer_ProjectType.h +++ b/extras/Projucer/Source/Project/jucer_ProjectType.h @@ -49,6 +49,55 @@ public: virtual bool isCommandLineApp() const { return false; } virtual bool isAudioPlugin() const { return false; } + //============================================================================== + struct Target + { + enum Type + { + GUIApp = 0, + ConsoleApp = 1, + StaticLibrary = 2, + DynamicLibrary = 3, + + VSTPlugIn = 10, + VST3PlugIn = 11, + AAXPlugIn = 12, + RTASPlugIn = 13, + AudioUnitPlugIn = 14, + AudioUnitv3PlugIn = 15, + StandalonePlugIn = 16, + + SharedCodeTarget = 20, // internal + AggregateTarget = 21, + + unspecified = 30 + }; + + enum TargetFileType + { + executable = 0, + staticLibrary = 1, + sharedLibraryOrDLL = 2, + pluginBundle = 3, + macOSAppex = 4, + unknown = 5 + }; + + //============================================================================== + Target (Type targetType) : type (targetType) {} + + const char* getName() const noexcept; + TargetFileType getTargetFileType() const noexcept; + + const Type type; + + private: + //============================================================================== + Target& operator= (const Target&) JUCE_DELETED_FUNCTION; + }; + + virtual bool supportsTargetType (Target::Type /*targetType*/) const { return false; } + protected: ProjectType (const String& type, const String& desc); @@ -86,32 +135,36 @@ struct ProjectType_GUIApp : public ProjectType { ProjectType_GUIApp() : ProjectType (getTypeName(), "GUI Application") {} - static const char* getTypeName() noexcept { return "guiapp"; } - bool isGUIApplication() const override { return true; } + static const char* getTypeName() noexcept { return "guiapp"; } + bool isGUIApplication() const override { return true; } + bool supportsTargetType (Target::Type targetType) const override { return (targetType == Target::GUIApp); } }; struct ProjectType_ConsoleApp : public ProjectType { ProjectType_ConsoleApp() : ProjectType (getTypeName(), "Console Application") {} - static const char* getTypeName() noexcept { return "consoleapp"; } - bool isCommandLineApp() const override { return true; } + static const char* getTypeName() noexcept { return "consoleapp"; } + bool isCommandLineApp() const override { return true; } + bool supportsTargetType (Target::Type targetType) const override { return (targetType == Target::ConsoleApp); } }; struct ProjectType_StaticLibrary : public ProjectType { ProjectType_StaticLibrary() : ProjectType (getTypeName(), "Static Library") {} - static const char* getTypeName() noexcept { return "library"; } - bool isStaticLibrary() const override { return true; } + static const char* getTypeName() noexcept { return "library"; } + bool isStaticLibrary() const override { return true; } + bool supportsTargetType (Target::Type targetType) const override { return (targetType == Target::StaticLibrary); } }; struct ProjectType_DLL : public ProjectType { ProjectType_DLL() : ProjectType (getTypeName(), "Dynamic Library") {} - static const char* getTypeName() noexcept { return "dll"; } - bool isDynamicLibrary() const override { return true; } + static const char* getTypeName() noexcept { return "dll"; } + bool isDynamicLibrary() const override { return true; } + bool supportsTargetType (Target::Type targetType) const override { return (targetType == Target::DynamicLibrary); } }; struct ProjectType_AudioPlugin : public ProjectType @@ -120,6 +173,27 @@ struct ProjectType_AudioPlugin : public ProjectType static const char* getTypeName() noexcept { return "audioplug"; } bool isAudioPlugin() const override { return true; } + + bool supportsTargetType (Target::Type targetType) const override + { + switch (targetType) + { + case Target::VSTPlugIn: + case Target::VST3PlugIn: + case Target::AAXPlugIn: + case Target::RTASPlugIn: + case Target::AudioUnitPlugIn: + case Target::AudioUnitv3PlugIn: + case Target::StandalonePlugIn: + case Target::SharedCodeTarget: + case Target::AggregateTarget: + return true; + default: + break; + } + + return false; + } }; //============================================================================== diff --git a/extras/Projucer/Source/Utility/jucer_PresetIDs.h b/extras/Projucer/Source/Utility/jucer_PresetIDs.h index e2885c2103..31ef98eb45 100644 --- a/extras/Projucer/Source/Utility/jucer_PresetIDs.h +++ b/extras/Projucer/Source/Utility/jucer_PresetIDs.h @@ -104,6 +104,8 @@ namespace Ids DECLARE_ID (winWarningLevel); DECLARE_ID (warningsAreErrors); DECLARE_ID (linuxArchitecture); + DECLARE_ID (linuxCodeBlocksArchitecture); + DECLARE_ID (windowsCodeBlocksArchitecture); DECLARE_ID (toolset); DECLARE_ID (IPPLibrary); DECLARE_ID (msvcModuleDefinitionFile); @@ -112,7 +114,6 @@ namespace Ids DECLARE_ID (jucerVersion); DECLARE_ID (prebuildCommand); DECLARE_ID (postbuildCommand); - DECLARE_ID (internalPostBuildComamnd); DECLARE_ID (generateManifest); DECLARE_ID (useRuntimeLibDLL); DECLARE_ID (wholeProgramOptimisation); @@ -173,7 +174,7 @@ namespace Ids DECLARE_ID (iosDevelopmentTeamID); DECLARE_ID (buildToolsVersion); DECLARE_ID (gradleVersion); - DECLARE_ID (gradleWrapperVersion); + const Identifier androidPluginVersion ("gradleWrapperVersion"); // old name is very confusing, but we need to remain backward compatible DECLARE_ID (gradleToolchain); DECLARE_ID (gradleToolchainVersion); DECLARE_ID (linuxExtraPkgConfig);