From 2e81e8a0dc8e4c509baa3317ad760153ddb2eeb5 Mon Sep 17 00:00:00 2001 From: ed Date: Wed, 19 Jul 2017 17:23:20 +0100 Subject: [PATCH] Projucer: Made the C++ language standard option a per-project instead of per-build configuration setting. Added an option to enable GNU compiler extensions for supported exporters. Added the option to specify a minimum C++ language standard in module declarations and added a warning to the Projucer when adding a module that has a higher standard than currently set. --- BREAKING-CHANGES.txt | 41 ++++++++---- .../jucer_ProjectExport_Android.h | 24 +++---- .../jucer_ProjectExport_CodeBlocks.h | 13 +++- .../Project Saving/jucer_ProjectExport_MSVC.h | 18 +----- .../Project Saving/jucer_ProjectExport_Make.h | 26 +++----- .../jucer_ProjectExport_XCode.h | 62 +++++++++---------- .../Project Saving/jucer_ProjectExporter.cpp | 4 ++ .../Project Saving/jucer_ProjectExporter.h | 3 + .../Source/Project/jucer_ConfigTree_Modules.h | 35 ++++++++++- .../Projucer/Source/Project/jucer_Module.cpp | 12 ++++ extras/Projucer/Source/Project/jucer_Module.h | 43 +++++++------ .../Projucer/Source/Project/jucer_Project.cpp | 13 ++++ .../Projucer/Source/Project/jucer_Project.h | 6 +- .../Utility/jucer_JucerTreeViewBase.cpp | 8 +-- .../Source/Utility/jucer_JucerTreeViewBase.h | 7 ++- .../Projucer/Source/Utility/jucer_PresetIDs.h | 2 + modules/JUCE Module Format.txt | 60 +++++++++--------- 17 files changed, 221 insertions(+), 156 deletions(-) diff --git a/BREAKING-CHANGES.txt b/BREAKING-CHANGES.txt index f86caaae60..c4bf2f3698 100644 --- a/BREAKING-CHANGES.txt +++ b/BREAKING-CHANGES.txt @@ -6,7 +6,24 @@ Develop Branch Change ------ -PopupMenus now scale according to the AffineTransform and scaling factor of their target components +The option to set the C++ language standard is now located in the project settings instead of the build configuration settings. + +Possible Issues +--------------- +Projects that had a specific verison of the C++ language standard set for exporter build configurations will instead use the default (C++11) when re-saving with the new Projucer. + +Workaround +---------- +Change the "C++ Language Standard" setting in the main project settings to the required version - the Projucer will add this value to the exported project as a compiler flag when saving exporters. + +Rationale +--------- +Having a different C++ language standard option for each build configuration was unnecessary and was not fully implemented for all exporters. Changing it to a per-project settings means that the preference will propagate to all exporters and only needs to be set in one place. + + +Change +------ +PopupMenus now scale according to the AffineTransform and scaling factor of their target components. Possible Issues --------------- @@ -28,24 +45,24 @@ Previously, PopupMenus would not scale if the GUI of the target component (or an Change ------ -Removed the setSecurityFlags() method from the Windows implementation of WebInputStream as it disabled HTTPS security features +Removed the setSecurityFlags() method from the Windows implementation of WebInputStream as it disabled HTTPS security features. Possible Issues --------------- -Any code previously relying on connections to insecure webpages succeeding will no longer work +Any code previously relying on connections to insecure webpages succeeding will no longer work. Workaround ---------- -Check network connectivity on Windows and re-write any code that relied on insecure connections +Check network connectivity on Windows and re-write any code that relied on insecure connections. Rationale --------- -The previous behaviour resulted in network connections on Windows having all the HTTPS security features disabled, exposing users to network attacks. HTTPS connections on Windows are now secure and will fail when connecting to an insecure web address +The previous behaviour resulted in network connections on Windows having all the HTTPS security features disabled, exposing users to network attacks. HTTPS connections on Windows are now secure and will fail when connecting to an insecure web address. Change ------ -Pointer arithmetic on a pointer will have the same result regardless if it is wrapped in JUCE's Atomic class or not +Pointer arithmetic on a pointer will have the same result regardless if it is wrapped in JUCE's Atomic class or not. Possible Issues --------------- @@ -72,11 +89,11 @@ Version 4.3.1 Change ------ -JUCE has changed the way native VST3/AudioUnit parameter ids are calculated +JUCE has changed the way native VST3/AudioUnit parameter ids are calculated. Possible Issues --------------- -DAW projects with automation data written by an AudioUnit or VST3 plug-in built with pre JUCE 4.3.1 versions will load incorrectly when opened by an AudioUnit or VST3 built with JUCE versions 4.3.1 and later. Plug-ins using JUCE_FORCE_USE_LEGACY_IDS are not affected +DAW projects with automation data written by an AudioUnit or VST3 plug-in built with pre JUCE 4.3.1 versions will load incorrectly when opened by an AudioUnit or VST3 built with JUCE versions 4.3.1 and later. Plug-ins using JUCE_FORCE_USE_LEGACY_IDS are not affected. Workaround ---------- @@ -93,7 +110,7 @@ Version 4.3.0 Change ------ -A revised multi-bus API was released which supersedes the previously flawed multi-bus API - JUCE versions 4.0.0 - 4.2.4 (inclusive) +A revised multi-bus API was released which supersedes the previously flawed multi-bus API - JUCE versions 4.0.0 - 4.2.4 (inclusive). Possible Issues --------------- @@ -101,7 +118,7 @@ If you have developed a plug-in with JUCE versions 4.0.0 - 4.2.4 (inclusive), th Woraround --------- -None +None. Rationale -------- @@ -131,7 +148,7 @@ Version 4.2.1 Change ------ -JUCE now uses the paramID property used in AudioProcessorParameterWithID to uniquely identify parameters to the host +JUCE now uses the paramID property used in AudioProcessorParameterWithID to uniquely identify parameters to the host. Possible Issues --------------- @@ -144,4 +161,4 @@ Enable JUCE_FORCE_USE_LEGACY_IDS in the juce_audio_plugin_client module config p Rationale -------- Each parameter of the AudioProcessor has an id associated so that the plug-in’s host can uniquely identify parameters. The id has a different data-type for different plug-in types (for example VST uses integers, AAX uses string identifiers). Before 4.2.1, JUCE generated the parameter id by using the index of the parameter, i.e. the first parameter had id zero, the second parameter had id one, etc. This caused problems for certain plug-in types where JUCE needs to add internal parameters to the plug-in (for example VST3 requires the bypass control to be a parameter - so JUCE automatically creates this parameter for you in the VST3 backend). This causes subtle problems if a parameter is added to an update of an already published plug-in. The new parameter’s id would be identical to the id of the bypass parameter in old versions of your plug-in, causing seemingly random plug-in bypass behaviour when user’s upgrade their plug-in. -Most plug-in backends differentiate between a parameter’s id an index, so this distinction was adopted starting with JUCE 4.2.1 by deriving the parameter’s unique id from the paramID property of AudioProcessorParameterWithID class. \ No newline at end of file +Most plug-in backends differentiate between a parameter’s id an index, so this distinction was adopted starting with JUCE 4.2.1 by deriving the parameter’s unique id from the paramID property of AudioProcessorParameterWithID class. diff --git a/extras/Projucer/Source/Project Saving/jucer_ProjectExport_Android.h b/extras/Projucer/Source/Project Saving/jucer_ProjectExport_Android.h index 0ce8c7efa3..1674de90da 100644 --- a/extras/Projucer/Source/Project Saving/jucer_ProjectExport_Android.h +++ b/extras/Projucer/Source/Project Saving/jucer_ProjectExport_Android.h @@ -850,19 +850,8 @@ private: { props.add (new TextPropertyComponent (androidTheme.getPropertyAsValue(), "Android Theme", 256, false), "E.g. @android:style/Theme.NoTitleBar or leave blank for default"); - - static const char* cppStandardNames[] = { "C++03", "C++11", "C++14", nullptr }; - static const char* cppStandardValues[] = { "-std=c++03", "-std=c++11", "-std=c++14", nullptr }; - - props.add (new ChoicePropertyComponent (getCppStandardValue(), "C++ standard to use", - StringArray (cppStandardNames), Array (cppStandardValues)), - "The C++ standard to specify in the makefile"); } - //============================================================================== - Value getCppStandardValue() { return getSetting (Ids::cppLanguageStandard); } - String getCppStandardString() const { return settings[Ids::cppLanguageStandard]; } - //============================================================================== String createDefaultClassName() const { @@ -1183,13 +1172,16 @@ private: StringArray getAndroidCxxCompilerFlags() const { - StringArray cxxFlags (getAndroidCompilerFlags()); - String cppStandardToUse (getCppStandardString()); + auto cxxFlags = getAndroidCompilerFlags(); + + auto cppStandard = project.getCppStandardValue().toString(); + + if (cppStandard == "latest") + cppStandard = "1z"; - if (cppStandardToUse.isEmpty()) - cppStandardToUse = "-std=c++11"; + cppStandard = "-std=" + String (shouldUseGNUExtensions() ? "gnu++" : "c++") + cppStandard; - cxxFlags.add ("\"" + cppStandardToUse + "\""); + cxxFlags.add (cppStandard.quoted()); return cxxFlags; } diff --git a/extras/Projucer/Source/Project Saving/jucer_ProjectExport_CodeBlocks.h b/extras/Projucer/Source/Project Saving/jucer_ProjectExport_CodeBlocks.h index ce5ec7a791..b219cc7756 100644 --- a/extras/Projucer/Source/Project Saving/jucer_ProjectExport_CodeBlocks.h +++ b/extras/Projucer/Source/Project Saving/jucer_ProjectExport_CodeBlocks.h @@ -343,7 +343,18 @@ private: flags.add (codeBlocksConfig->getArchitectureTypeVar()); flags.add ("-O" + config.getGCCOptimisationFlag()); - flags.add ("-std=c++11"); + + { + auto cppStandard = config.project.getCppStandardValue().toString(); + + if (cppStandard == "latest") + cppStandard = "1z"; + + cppStandard = "-std=" + String (shouldUseGNUExtensions() ? "gnu++" : "c++") + cppStandard; + + flags.add (cppStandard); + } + flags.add ("-mstackrealign"); if (config.isDebug()) diff --git a/extras/Projucer/Source/Project Saving/jucer_ProjectExport_MSVC.h b/extras/Projucer/Source/Project Saving/jucer_ProjectExport_MSVC.h index b0aff9756d..4eb43a5767 100644 --- a/extras/Projucer/Source/Project Saving/jucer_ProjectExport_MSVC.h +++ b/extras/Projucer/Source/Project Saving/jucer_ProjectExport_MSVC.h @@ -63,9 +63,6 @@ public: return (targetPlatform.isNotEmpty() ? targetPlatform : getDefaultWindowsTargetPlatformVersion()); } - Value getCppStandardValue() { return getSetting (Ids::cppLanguageStandard); } - String getCppLanguageStandard() const { return settings [Ids::cppLanguageStandard]; } - //============================================================================== void addToolsetProperty (PropertyListBuilder& props, const char** names, const var* values, int num) { @@ -83,12 +80,6 @@ public: Array (ippValues, numElementsInArray (ippValues)))); } - void addCppStandardProperty (PropertyListBuilder& props, const char** names, const var* values, int num) - { - props.add (new ChoicePropertyComponent (getCppStandardValue(), "C++ standard to use", - StringArray (names, num), Array (values, num))); - } - void addWindowsTargetPlatformProperties (PropertyListBuilder& props) { static const char* targetPlatformNames[] = { "(default)", "8.1", "10.0.10240.0", "10.0.10586.0", "10.0.14393.0", "10.0.15063.0" }; @@ -512,9 +503,8 @@ public: if (config.areWarningsTreatedAsErrors()) cl->createNewChildElement ("TreatWarningAsError")->addTextElement ("true"); - String cppLanguageStandard = getOwner().getCppLanguageStandard(); - if (cppLanguageStandard.isNotEmpty()) - cl->createNewChildElement ("LanguageStandard")->addTextElement (cppLanguageStandard); + auto cppStandard = owner.project.getCppStandardValue().toString(); + cl->createNewChildElement ("LanguageStandard")->addTextElement ("stdcpp" + cppStandard); } { @@ -1859,10 +1849,6 @@ public: addIPPLibraryProperty (props); addWindowsTargetPlatformProperties (props); - - static const char* cppStandardNames[] = { "(default)", "C++14", "Latest C++ Standard"}; - const var standards[] = { var(), "stdcpp14", "stdcpplatest" }; - addCppStandardProperty (props, cppStandardNames, standards, numElementsInArray (standards)); } JUCE_DECLARE_NON_COPYABLE (MSVCProjectExporterVC2017) diff --git a/extras/Projucer/Source/Project Saving/jucer_ProjectExport_Make.h b/extras/Projucer/Source/Project Saving/jucer_ProjectExport_Make.h index a0d1ebd911..67c2d7e35b 100644 --- a/extras/Projucer/Source/Project Saving/jucer_ProjectExport_Make.h +++ b/extras/Projucer/Source/Project Saving/jucer_ProjectExport_Make.h @@ -353,20 +353,8 @@ public: return false; } - Value getCppStandardValue() { return getSetting (Ids::cppLanguageStandard); } - String getCppStandardString() const { return settings[Ids::cppLanguageStandard]; } - void createExporterProperties (PropertyListBuilder& properties) override { - static const char* cppStandardNames[] = { "C++03", "C++11", "C++14", nullptr }; - static const char* cppStandardValues[] = { "-std=c++03", "-std=c++11", "-std=c++14", nullptr }; - - properties.add (new ChoicePropertyComponent (getCppStandardValue(), - "C++ standard to use", - StringArray (cppStandardNames), - Array (cppStandardValues)), - "The C++ standard to specify in the makefile"); - properties.add (new TextPropertyComponent (getExtraPkgConfig(), "pkg-config libraries", 8192, false), "Extra pkg-config libraries for you application. Each package should be space separated."); } @@ -606,13 +594,17 @@ private: << (" " + replacePreprocessorTokens (config, getExtraCompilerFlagsString())).trimEnd() << " $(CFLAGS)" << newLine; - String cppStandardToUse (getCppStandardString()); + { + auto cppStandard = config.project.getCppStandardValue().toString(); + + if (cppStandard == "latest") + cppStandard = "1z"; - if (cppStandardToUse.isEmpty()) - cppStandardToUse = "-std=c++11"; + cppStandard = "-std=" + String (shouldUseGNUExtensions() ? "gnu++" : "c++") + cppStandard; - out << " JUCE_CXXFLAGS += $(CXXFLAGS) $(JUCE_CFLAGS) " - << cppStandardToUse << " $(CXXFLAGS)" << newLine; + out << " JUCE_CXXFLAGS += $(CXXFLAGS) $(JUCE_CFLAGS) " + << cppStandard << " $(CXXFLAGS)" << newLine; + } writeLinkerFlags (out, config); diff --git a/extras/Projucer/Source/Project Saving/jucer_ProjectExport_XCode.h b/extras/Projucer/Source/Project Saving/jucer_ProjectExport_XCode.h index a3b3d55426..215d9c710f 100644 --- a/extras/Projucer/Source/Project Saving/jucer_ProjectExport_XCode.h +++ b/extras/Projucer/Source/Project Saving/jucer_ProjectExport_XCode.h @@ -88,14 +88,14 @@ public: Value getPListPreprocessValue() { return getSetting ("PListPreprocess"); } bool isPListPreprocessEnabled() const { return settings ["PListPreprocess"]; } - Value getExtraFrameworksValue() { return getSetting (Ids::extraFrameworks); } - String getExtraFrameworksString() const { return settings [Ids::extraFrameworks]; } + Value getExtraFrameworksValue() { return getSetting (Ids::extraFrameworks); } + String getExtraFrameworksString() const { return settings [Ids::extraFrameworks]; } - Value getPostBuildScriptValue() { return getSetting (Ids::postbuildCommand); } - String getPostBuildScript() const { return settings [Ids::postbuildCommand]; } + Value getPostBuildScriptValue() { return getSetting (Ids::postbuildCommand); } + String getPostBuildScript() const { return settings [Ids::postbuildCommand]; } - Value getPreBuildScriptValue() { return getSetting (Ids::prebuildCommand); } - String getPreBuildScript() const { return settings [Ids::prebuildCommand]; } + Value getPreBuildScriptValue() { return getSetting (Ids::prebuildCommand); } + String getPreBuildScript() const { return settings [Ids::prebuildCommand]; } Value getDuplicateResourcesFolderForAppExtensionValue() { return getSetting (Ids::iosAppExtensionDuplicateResourcesFolder); } bool shouldDuplicateResourcesFolderForAppExtension() const { return settings [Ids::iosAppExtensionDuplicateResourcesFolder]; } @@ -376,7 +376,6 @@ protected: osxArchitecture (config, Ids::osxArchitecture, nullptr, "default"), customXcodeFlags (config, Ids::customXcodeFlags, nullptr), plistPreprocessorDefinitions (config, Ids::plistPreprocessorDefinitions, nullptr), - cppLanguageStandard (config, Ids::cppLanguageStandard, nullptr), cppStandardLibrary (config, Ids::cppLibType, nullptr), codeSignIdentity (config, Ids::codeSigningIdentity, nullptr, iOS ? "iPhone Developer" : "Mac Developer"), fastMathEnabled (config, Ids::fastMath, nullptr), @@ -394,8 +393,7 @@ protected: bool iOS; CachedValue osxSDKVersion, osxDeploymentTarget, iosDeploymentTarget, osxArchitecture, - customXcodeFlags, plistPreprocessorDefinitions, - cppLanguageStandard, cppStandardLibrary, codeSignIdentity; + customXcodeFlags, plistPreprocessorDefinitions, cppStandardLibrary, codeSignIdentity; CachedValue fastMathEnabled, linkTimeOptimisationEnabled, stripLocalSymbolsEnabled; CachedValue vstBinaryLocation, vst3BinaryLocation, auBinaryLocation, rtasBinaryLocation, aaxBinaryLocation; @@ -455,26 +453,15 @@ protected: props.add (new TextPropertyComponent (plistPreprocessorDefinitions.getPropertyAsValue(), "PList Preprocessor Definitions", 2048, true), "Preprocessor definitions used during PList preprocessing (see PList Preprocess)."); - const char* cppLanguageStandardNames[] = { "Use Default", "C++11", "GNU++11", "C++14", "GNU++14", nullptr }; - Array cppLanguageStandardValues; - cppLanguageStandardValues.add (var()); - cppLanguageStandardValues.add ("c++11"); - cppLanguageStandardValues.add ("gnu++11"); - cppLanguageStandardValues.add ("c++14"); - cppLanguageStandardValues.add ("gnu++14"); - - props.add (new ChoicePropertyComponent (cppLanguageStandard.getPropertyAsValue(), "C++ Language Standard", - StringArray (cppLanguageStandardNames), cppLanguageStandardValues), - "The standard of the C++ language that will be used for compilation."); - - const char* cppLibNames[] = { "Use Default", "LLVM libc++", "GNU libstdc++", nullptr }; - Array cppLibValues; - cppLibValues.add (var()); - cppLibValues.add ("libc++"); - cppLibValues.add ("libstdc++"); + { + static const char* cppLibNames[] = { "Use Default", "LLVM libc++", "GNU libstdc++", nullptr }; + static const var cppLibValues[] = { var(), "libc++", "libstdc++" }; - props.add (new ChoicePropertyComponent (cppStandardLibrary.getPropertyAsValue(), "C++ Library", StringArray (cppLibNames), cppLibValues), - "The type of C++ std lib that will be linked."); + props.add (new ChoicePropertyComponent (cppStandardLibrary.getPropertyAsValue(), "C++ Library", + StringArray (cppLibNames), + Array (cppLibValues, numElementsInArray (cppLibValues))), + "The type of C++ std lib that will be linked."); + } props.add (new TextWithDefaultPropertyComponent (codeSignIdentity, "Code-signing Identity", 1024), "The name of a code-signing identity for Xcode to apply."); @@ -954,7 +941,6 @@ public: } s.add ("GCC_VERSION = " + gccVersion); - s.add ("CLANG_CXX_LANGUAGE_STANDARD = \"c++0x\""); s.add ("CLANG_LINK_OBJC_RUNTIME = NO"); if (! config.codeSignIdentity.isUsingDefault()) @@ -963,8 +949,15 @@ public: if (owner.isPushNotificationsEnabled()) s.add ("CODE_SIGN_ENTITLEMENTS = " + owner.getProject().getTitle() + ".entitlements"); - if (config.cppLanguageStandard.get().isNotEmpty()) - s.add ("CLANG_CXX_LANGUAGE_STANDARD = " + config.cppLanguageStandard.get().quoted()); + { + auto cppStandard = owner.project.getCppStandardValue().toString(); + + if (cppStandard == "latest") + cppStandard = "1z"; + + s.add ("CLANG_CXX_LANGUAGE_STANDARD = " + (String (owner.shouldUseGNUExtensions() ? "gnu++" + : "c++") + cppStandard).quoted()); + } if (config.cppStandardLibrary.get().isNotEmpty()) s.add ("CLANG_CXX_LIBRARY = " + config.cppStandardLibrary.get().quoted()); @@ -1466,13 +1459,14 @@ public: { if (auto xcodeConfig = dynamic_cast (&config)) { - const String& configValue = xcodeConfig->cppStandardLibrary.get(); + const auto& configValue = xcodeConfig->cppStandardLibrary.get(); if (configValue.isNotEmpty()) return (configValue == "libc++"); - const int minorOSXDeploymentTarget - = getOSXDeploymentTarget (*xcodeConfig).fromLastOccurrenceOf (".", false, false).getIntValue(); + auto minorOSXDeploymentTarget = getOSXDeploymentTarget (*xcodeConfig) + .fromLastOccurrenceOf (".", false, false) + .getIntValue(); return (minorOSXDeploymentTarget > 8); } diff --git a/extras/Projucer/Source/Project Saving/jucer_ProjectExporter.cpp b/extras/Projucer/Source/Project Saving/jucer_ProjectExporter.cpp index 5368d68d01..d74df52a12 100644 --- a/extras/Projucer/Source/Project Saving/jucer_ProjectExporter.cpp +++ b/extras/Projucer/Source/Project Saving/jucer_ProjectExporter.cpp @@ -269,6 +269,10 @@ void ProjectExporter::createPropertyEditors (PropertyListBuilder& props) "Additional libraries to link (one per line). You should not add any platform specific decoration to these names. " "This string can contain references to preprocessor definitions in the form ${NAME_OF_VALUE}, which will be replaced with their values."); + if (! isVisualStudio()) + props.add (new BooleanPropertyComponent (getShouldUseGNUExtensionsValue(), "GNU Compiler Extensions", "Enabled"), + "Enabling this will use the GNU C++ language standard variant for compilation."); + createIconProperties (props); createExporterProperties (props); diff --git a/extras/Projucer/Source/Project Saving/jucer_ProjectExporter.h b/extras/Projucer/Source/Project Saving/jucer_ProjectExporter.h index e64d2d53c7..746ce2f079 100644 --- a/extras/Projucer/Source/Project Saving/jucer_ProjectExporter.h +++ b/extras/Projucer/Source/Project Saving/jucer_ProjectExporter.h @@ -154,6 +154,9 @@ public: Value getRTASPathValue() const { return rtasPath; } Value getAAXPathValue() const { return aaxPath; } + Value getShouldUseGNUExtensionsValue() { return getSetting (Ids::enableGNUExtensions); } + bool shouldUseGNUExtensions() const { return (getSettingString (Ids::enableGNUExtensions) == "1");} + // NB: this is the path to the parent "modules" folder that contains the named module, not the // module folder itself. Value getPathForModuleValue (const String& moduleID); diff --git a/extras/Projucer/Source/Project/jucer_ConfigTree_Modules.h b/extras/Projucer/Source/Project/jucer_ConfigTree_Modules.h index 27990dcecc..bd57571de6 100644 --- a/extras/Projucer/Source/Project/jucer_ConfigTree_Modules.h +++ b/extras/Projucer/Source/Project/jucer_ConfigTree_Modules.h @@ -39,6 +39,7 @@ public: String getRenamingName() const override { return getDisplayName(); } void setName (const String&) override {} bool isMissing() const override { return hasMissingDependencies(); } + bool hasWarnings() const override { return hasHigherCppStandardThanProject(); } void showDocument() override { @@ -93,6 +94,11 @@ private: return project.getModules().getExtraDependenciesNeeded (moduleID).size() > 0; } + bool hasHigherCppStandardThanProject() const + { + return project.getModules().doesModuleHaveHigherCppStandardThanProject (moduleID); + } + //============================================================================== class ModuleSettingsPanel : public Component, private Value::Listener @@ -129,6 +135,9 @@ private: if (modules.getExtraDependenciesNeeded (moduleID).size() > 0) props.add (new MissingDependenciesComponent (project, moduleID)); + if (modules.doesModuleHaveHigherCppStandardThanProject (moduleID)) + props.add (new CppStandardWarningComponent()); + modulePathValueSources.clear(); for (Project::ExporterIterator exporter (project); exporter.next();) @@ -329,7 +338,7 @@ private: text << missingDependencies.joinIntoString (", "); g.setColour (Colours::red); - g.drawFittedText (text, getLocalBounds().reduced (4, 16), Justification::topLeft, 3); + g.drawFittedText (text, getLocalBounds().reduced (10), Justification::topLeft, 3); } void buttonClicked (Button*) override @@ -420,6 +429,30 @@ private: JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (MissingDependenciesComponent) }; + + //============================================================================== + struct CppStandardWarningComponent : public PropertyComponent + { + CppStandardWarningComponent() + : PropertyComponent ("CppStandard", 100) + { + } + + void refresh() override {} + + void paint (Graphics& g) override + { + auto text = String ("This module has a higher C++ language standard requirement than your project!\n\n" + "To use this module you need to increase the C++ standard of the project.\n"); + + g.setColour (findColour (defaultHighlightColourId)); + g.drawFittedText (text, getLocalBounds().reduced (10), Justification::topLeft, 3); + } + + StringArray configsToWarnAbout; + + JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (CppStandardWarningComponent) + }; }; JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (ModuleItem) diff --git a/extras/Projucer/Source/Project/jucer_Module.cpp b/extras/Projucer/Source/Project/jucer_Module.cpp index c0d27d084b..2930771777 100644 --- a/extras/Projucer/Source/Project/jucer_Module.cpp +++ b/extras/Projucer/Source/Project/jucer_Module.cpp @@ -824,6 +824,18 @@ StringArray EnabledModuleList::getExtraDependenciesNeeded (const String& moduleI return extraDepsNeeded; } +bool EnabledModuleList::doesModuleHaveHigherCppStandardThanProject (const String& moduleID) +{ + auto projectCppStandard = project.getCppStandardValue().toString(); + + if (projectCppStandard == "latest") + return false; + + auto moduleCppStandard = getModuleInfo (moduleID).getMinimumCppStandard(); + + return (moduleCppStandard.getIntValue() > projectCppStandard.getIntValue()); +} + bool EnabledModuleList::areMostModulesUsingGlobalPath() const { auto numYes = 0, numNo = 0; diff --git a/extras/Projucer/Source/Project/jucer_Module.h b/extras/Projucer/Source/Project/jucer_Module.h index 60b41fe41e..a523d24a87 100644 --- a/extras/Projucer/Source/Project/jucer_Module.h +++ b/extras/Projucer/Source/Project/jucer_Module.h @@ -41,22 +41,23 @@ struct ModuleDescription ModuleDescription (const File& folder); ModuleDescription (const var& info) : moduleInfo (info) {} - bool isValid() const { return getID().isNotEmpty(); } - - String getID() const { return moduleInfo [Ids::ID_uppercase].toString(); } - String getVendor() const { return moduleInfo [Ids::vendor].toString(); } - String getVersion() const { return moduleInfo [Ids::version].toString(); } - String getName() const { return moduleInfo [Ids::name].toString(); } - String getDescription() const { return moduleInfo [Ids::description].toString(); } - String getLicense() const { return moduleInfo [Ids::license].toString(); } - String getPreprocessorDefs() const { return moduleInfo [Ids::defines].toString(); } - String getExtraSearchPaths() const { return moduleInfo [Ids::searchpaths].toString(); } + bool isValid() const { return getID().isNotEmpty(); } + + String getID() const { return moduleInfo [Ids::ID_uppercase].toString(); } + String getVendor() const { return moduleInfo [Ids::vendor].toString(); } + String getVersion() const { return moduleInfo [Ids::version].toString(); } + String getName() const { return moduleInfo [Ids::name].toString(); } + String getDescription() const { return moduleInfo [Ids::description].toString(); } + String getLicense() const { return moduleInfo [Ids::license].toString(); } + String getMinimumCppStandard() const { return moduleInfo [Ids::minimumCppStandard].toString(); } + String getPreprocessorDefs() const { return moduleInfo [Ids::defines].toString(); } + String getExtraSearchPaths() const { return moduleInfo [Ids::searchpaths].toString(); } StringArray getDependencies() const; - File getFolder() const { jassert (moduleFolder != File()); return moduleFolder; } + File getFolder() const { jassert (moduleFolder != File()); return moduleFolder; } File getHeader() const; - bool isPluginClient() const { return getID() == "juce_audio_plugin_client"; } + bool isPluginClient() const { return getID() == "juce_audio_plugin_client"; } File moduleFolder; var moduleInfo; @@ -91,15 +92,16 @@ class LibraryModule public: LibraryModule (const ModuleDescription&); - bool isValid() const { return moduleInfo.isValid(); } - String getID() const { return moduleInfo.getID(); } - String getVendor() const { return moduleInfo.getVendor(); } - String getVersion() const { return moduleInfo.getVersion(); } - String getName() const { return moduleInfo.getName(); } - String getDescription() const { return moduleInfo.getDescription(); } - String getLicense() const { return moduleInfo.getLicense(); } + bool isValid() const { return moduleInfo.isValid(); } + String getID() const { return moduleInfo.getID(); } + String getVendor() const { return moduleInfo.getVendor(); } + String getVersion() const { return moduleInfo.getVersion(); } + String getName() const { return moduleInfo.getName(); } + String getDescription() const { return moduleInfo.getDescription(); } + String getLicense() const { return moduleInfo.getLicense(); } + String getMinimumCppStandard() const { return moduleInfo.getMinimumCppStandard(); } - File getFolder() const { return moduleInfo.getFolder(); } + File getFolder() const { return moduleInfo.getFolder(); } void writeIncludes (ProjectSaver&, OutputStream&); void addSettingsForModuleToExporter (ProjectExporter&, ProjectSaver&) const; @@ -159,6 +161,7 @@ public: StringArray getAllModules() const; StringArray getExtraDependenciesNeeded (const String& moduleID) const; + bool doesModuleHaveHigherCppStandardThanProject (const String& moduleID); void createRequiredModules (OwnedArray& modules); int getNumModules() const { return state.getNumChildren(); } diff --git a/extras/Projucer/Source/Project/jucer_Project.cpp b/extras/Projucer/Source/Project/jucer_Project.cpp index 4c5ebfd3f6..edc6429968 100644 --- a/extras/Projucer/Source/Project/jucer_Project.cpp +++ b/extras/Projucer/Source/Project/jucer_Project.cpp @@ -152,6 +152,9 @@ void Project::setMissingDefaultValues() if (shouldIncludeBinaryInAppConfig() == var()) shouldIncludeBinaryInAppConfig() = true; + if (! projectRoot.hasType (Ids::cppLanguageStandard)) + getCppStandardValue() = "11"; + ProjucerApplication::getApp().updateNewlyOpenedProject (*this); } @@ -687,6 +690,16 @@ void Project::createPropertyEditors (PropertyListBuilder& props) props.add (new TextPropertyComponent (binaryDataNamespace(), "BinaryData Namespace", 256, false), "The namespace containing the binary assests. If left empty this defaults to \"BinaryData\"."); + { + static const char* cppLanguageStandardNames[] = { "C++11", "C++14", "Use Latest", nullptr }; + static const var cppLanguageStandardValues[] = { "11", "14", "latest" }; + + props.add (new ChoicePropertyComponent (getCppStandardValue(), "C++ Language Standard", + StringArray (cppLanguageStandardNames), + Array (cppLanguageStandardValues, numElementsInArray (cppLanguageStandardValues))), + "The standard of the C++ language that will be used for compilation."); + } + props.add (new TextPropertyComponent (getProjectPreprocessorDefs(), "Preprocessor definitions", 32768, true), "Global preprocessor definitions. Use the form \"NAME1=value NAME2=value\", using whitespace, commas, or " "new-lines to separate the items - to include a space or comma in a definition, precede it with a backslash."); diff --git a/extras/Projucer/Source/Project/jucer_Project.h b/extras/Projucer/Source/Project/jucer_Project.h index ed03f4056e..5c53c3d203 100644 --- a/extras/Projucer/Source/Project/jucer_Project.h +++ b/extras/Projucer/Source/Project/jucer_Project.h @@ -100,14 +100,16 @@ public: Value shouldReportAppUsage() { return getProjectValue (Ids::reportAppUsage); } Value splashScreenColour() { return getProjectValue (Ids::splashScreenColour); } + Value getCppStandardValue() { return getProjectValue (Ids::cppLanguageStandard); } + //============================================================================== 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); } + Value getProjectPreprocessorDefs() { return getProjectValue (Ids::defines); } StringPairArray getPreprocessorDefs() const; - Value getProjectUserNotes() { return getProjectValue (Ids::userNotes); } + Value getProjectUserNotes() { return getProjectValue (Ids::userNotes); } //============================================================================== File getGeneratedCodeFolder() const { return getFile().getSiblingFile ("JuceLibraryCode"); } diff --git a/extras/Projucer/Source/Utility/jucer_JucerTreeViewBase.cpp b/extras/Projucer/Source/Utility/jucer_JucerTreeViewBase.cpp index fe100e2007..0163cd5ea1 100644 --- a/extras/Projucer/Source/Utility/jucer_JucerTreeViewBase.cpp +++ b/extras/Projucer/Source/Utility/jucer_JucerTreeViewBase.cpp @@ -112,11 +112,9 @@ void JucerTreeViewBase::paintItem (Graphics& g, int width, int height) Colour JucerTreeViewBase::getContentColour (bool isIcon) const { - if (isMissing()) - return Colours::red; - - if (isSelected()) - return getOwnerView()->findColour (defaultHighlightedTextColourId); + if (isMissing()) return Colours::red; + if (isSelected()) return getOwnerView()->findColour (defaultHighlightedTextColourId); + if (hasWarnings()) return getOwnerView()->findColour (defaultHighlightColourId); return getOwnerView()->findColour (isIcon ? treeIconColourId : defaultTextColourId); } diff --git a/extras/Projucer/Source/Utility/jucer_JucerTreeViewBase.h b/extras/Projucer/Source/Utility/jucer_JucerTreeViewBase.h index 3e1b1329b8..754a23360b 100644 --- a/extras/Projucer/Source/Utility/jucer_JucerTreeViewBase.h +++ b/extras/Projucer/Source/Utility/jucer_JucerTreeViewBase.h @@ -49,20 +49,21 @@ public: void cancelDelayedSelectionTimer(); //============================================================================== - virtual bool isRoot() const { return false; } + virtual bool isRoot() const { return false; } virtual Font getFont() const; virtual String getRenamingName() const = 0; virtual String getDisplayName() const = 0; virtual void setName (const String& newName) = 0; virtual bool isMissing() const = 0; + virtual bool hasWarnings() const { return false; } virtual Icon getIcon() const = 0; virtual bool isIconCrossedOut() const { return false; } virtual void paintIcon (Graphics& g, Rectangle area); virtual void paintContent (Graphics& g, const Rectangle& area); virtual int getRightHandButtonSpace() { return 0; } virtual Colour getContentColour (bool isIcon) const; - virtual int getMillisecsAllowedForDragGesture() { return 120; } - virtual File getDraggableFile() const { return {}; } + virtual int getMillisecsAllowedForDragGesture() { return 120; } + virtual File getDraggableFile() const { return {}; } virtual Component* createItemComponent() override; void refreshSubItems(); diff --git a/extras/Projucer/Source/Utility/jucer_PresetIDs.h b/extras/Projucer/Source/Utility/jucer_PresetIDs.h index 3a8b03a565..ba76993b29 100644 --- a/extras/Projucer/Source/Utility/jucer_PresetIDs.h +++ b/extras/Projucer/Source/Utility/jucer_PresetIDs.h @@ -39,6 +39,7 @@ namespace Ids DECLARE_ID (vendor); DECLARE_ID (version); DECLARE_ID (license); + DECLARE_ID (minimumCppStandard); DECLARE_ID (include); DECLARE_ID (info); DECLARE_ID (description); @@ -95,6 +96,7 @@ namespace Ids DECLARE_ID (customXcodeResourceFolders); DECLARE_ID (plistPreprocessorDefinitions); DECLARE_ID (cppLanguageStandard); + DECLARE_ID (enableGNUExtensions); DECLARE_ID (cppLibType); DECLARE_ID (codeSigningIdentity); DECLARE_ID (fastMath); diff --git a/modules/JUCE Module Format.txt b/modules/JUCE Module Format.txt index 5032dca7e3..571f7b0341 100644 --- a/modules/JUCE Module Format.txt +++ b/modules/JUCE Module Format.txt @@ -149,35 +149,37 @@ The order in which they're declared doesn't matter. Possible values: - ID: (Compulsory) This ID must match the name of the file and folder, e.g. juce_core. - The main reason for also including it here is as a sanity-check - vendor: (Compulsory) A unique ID for the vendor, e.g. "juce". This should be short - and shouldn't contain any spaces - version: (Compulsory) A version number for the module - name: (Compulsory) A short description of the module - description: (Compulsory) A longer description (but still only one line of text, please!) - - dependencies: (Optional) A list (space or comma-separated) of other modules that are required by - this one. The Introjucer can use this to auto-resolve dependencies. - website: (Optional) A URL linking to useful info about the module] - license: (Optional) A description of the type of software license that applies - searchpaths: (Optional) A space-separated list of internal include paths, relative to the module's - parent folder, which need to be added to a project's header search path - OSXFrameworks: (Optional) A list (space or comma-separated) of OSX frameworks that are needed - by this module - iOSFrameworks: (Optional) Like OSXFrameworks, but for iOS targets - linuxPackages: (Optional) A list (space or comma-separated) pkg-config packages that should be used to pass - compiler (CFLAGS) and linker (LDFLAGS) flags - linuxLibs: (Optional) A list (space or comma-separated) of static or dynamic libs that should be linked in a - linux build (these are passed to the linker via the -l flag) - mingwLibs: (Optional) A list (space or comma-separated) of static libs that should be linked in a - win32 mingw build (these are passed to the linker via the -l flag) - OSXLibs: (Optional) A list (space or comma-separated) of static or dynamic libs that should be linked in an - OS X build (these are passed to the linker via the -l flag) - iOSLibs: (Optional) A list (space or comma-separated) of static or dynamic libs that should be linked in an - iOS build (these are passed to the linker via the -l flag) - windowsLibs: (Optional) A list (space or comma-separated) of static or dynamic libs that should be linked in a - Visual Studio build (without the .lib suffixes) + ID: (Compulsory) This ID must match the name of the file and folder, e.g. juce_core. + The main reason for also including it here is as a sanity-check + vendor: (Compulsory) A unique ID for the vendor, e.g. "juce". This should be short + and shouldn't contain any spaces + version: (Compulsory) A version number for the module + name: (Compulsory) A short description of the module + description: (Compulsory) A longer description (but still only one line of text, please!) + + dependencies: (Optional) A list (space or comma-separated) of other modules that are required by + this one. The Introjucer can use this to auto-resolve dependencies. + website: (Optional) A URL linking to useful info about the module] + license: (Optional) A description of the type of software license that applies + minimumCppStandard: (Optional) A number indicating the minimum C++ language standard that is required for this module. + This must be just the standard number with no prefix e.g. 14 for C++14 + searchpaths: (Optional) A space-separated list of internal include paths, relative to the module's + parent folder, which need to be added to a project's header search path + OSXFrameworks: (Optional) A list (space or comma-separated) of OSX frameworks that are needed + by this module + iOSFrameworks: (Optional) Like OSXFrameworks, but for iOS targets + linuxPackages: (Optional) A list (space or comma-separated) pkg-config packages that should be used to pass + compiler (CFLAGS) and linker (LDFLAGS) flags + linuxLibs: (Optional) A list (space or comma-separated) of static or dynamic libs that should be linked in a + linux build (these are passed to the linker via the -l flag) + mingwLibs: (Optional) A list (space or comma-separated) of static libs that should be linked in a + win32 mingw build (these are passed to the linker via the -l flag) + OSXLibs: (Optional) A list (space or comma-separated) of static or dynamic libs that should be linked in an + OS X build (these are passed to the linker via the -l flag) + iOSLibs: (Optional) A list (space or comma-separated) of static or dynamic libs that should be linked in an + iOS build (these are passed to the linker via the -l flag) + windowsLibs: (Optional) A list (space or comma-separated) of static or dynamic libs that should be linked in a + Visual Studio build (without the .lib suffixes) Here's an example block: