|
- /*
- ==============================================================================
-
- This file is part of the JUCE 6 technical preview.
- Copyright (c) 2017 - ROLI Ltd.
-
- You may use this code under the terms of the GPL v3
- (see www.gnu.org/licenses).
-
- For this technical preview, this file is not subject to commercial licensing.
-
- JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER
- EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE
- DISCLAIMED.
-
- ==============================================================================
- */
-
- #pragma once
-
- #include "jucer_XcodeProjectParser.h"
-
- //==============================================================================
- namespace
- {
- static const char* const iOSDefaultVersion = "9.3";
- static const StringArray iOSVersions { "7.0", "7.1", "8.0", "8.1", "8.2", "8.3", "8.4",
- "9.0", "9.1", "9.2", "9.3", "10.0", "10.1", "10.2", "10.3",
- "11.0", "12.0", "13.0" };
-
- static const int oldestDeploymentTarget = 7;
- static const int defaultDeploymentTarget = 11;
- static const int oldestSDKVersion = 11;
- static const int currentSDKVersion = 15;
- static const int minimumAUv3SDKVersion = 11;
-
- static String getVersionName (int version) { return "10." + String (version); }
- static String getSDKDisplayName (int version) { return getVersionName (version) + " SDK"; }
- static String getSDKRootName (int version) { return "macosx" + getVersionName (version); }
-
- static String getOSXSDKVersion (const String& sdkVersion)
- {
- for (int v = oldestSDKVersion; v <= currentSDKVersion; ++v)
- if (sdkVersion == getSDKDisplayName (v))
- return getSDKRootName (v);
-
- return "macosx";
- }
-
- template<class ContainerType>
- static ContainerType getSDKChoiceList (int oldestVersion, bool displayName)
- {
- ContainerType container;
-
- for (int v = oldestVersion; v <= currentSDKVersion; ++v)
- container.add (displayName ? getSDKDisplayName (v) : getVersionName (v));
-
- return container;
- }
-
- static const char* const osxArch_Default = "default";
- static const char* const osxArch_Native = "Native";
- static const char* const osxArch_32BitUniversal = "32BitUniversal";
- static const char* const osxArch_64BitUniversal = "64BitUniversal";
- static const char* const osxArch_64Bit = "64BitIntel";
- }
-
- //==============================================================================
- class XcodeProjectExporter : public ProjectExporter
- {
- public:
- //==============================================================================
- static const char* getNameMac() { return "Xcode (MacOSX)"; }
- static const char* getNameiOS() { return "Xcode (iOS)"; }
- static const char* getValueTreeTypeName (bool iOS) { return iOS ? "XCODE_IPHONE" : "XCODE_MAC"; }
-
- //==============================================================================
- XcodeProjectExporter (Project& p, const ValueTree& t, const bool isIOS)
- : ProjectExporter (p, t),
- xcodeCanUseDwarf (true),
- iOS (isIOS),
- customPListValue (settings, Ids::customPList, getUndoManager()),
- pListPrefixHeaderValue (settings, Ids::pListPrefixHeader, getUndoManager()),
- pListPreprocessValue (settings, Ids::pListPreprocess, getUndoManager()),
- subprojectsValue (settings, Ids::xcodeSubprojects, getUndoManager()),
- extraFrameworksValue (settings, Ids::extraFrameworks, getUndoManager()),
- frameworkSearchPathsValue (settings, Ids::frameworkSearchPaths, getUndoManager()),
- extraCustomFrameworksValue (settings, Ids::extraCustomFrameworks, getUndoManager()),
- embeddedFrameworksValue (settings, Ids::embeddedFrameworks, getUndoManager()),
- postbuildCommandValue (settings, Ids::postbuildCommand, getUndoManager()),
- prebuildCommandValue (settings, Ids::prebuildCommand, getUndoManager()),
- duplicateAppExResourcesFolderValue (settings, Ids::duplicateAppExResourcesFolder, getUndoManager(), true),
- iosDeviceFamilyValue (settings, Ids::iosDeviceFamily, getUndoManager(), "1,2"),
- iPhoneScreenOrientationValue (settings, Ids::iPhoneScreenOrientation, getUndoManager(), getDefaultScreenOrientations(), ","),
- iPadScreenOrientationValue (settings, Ids::iPadScreenOrientation, getUndoManager(), getDefaultScreenOrientations(), ","),
- customXcodeResourceFoldersValue (settings, Ids::customXcodeResourceFolders, getUndoManager()),
- customXcassetsFolderValue (settings, Ids::customXcassetsFolder, getUndoManager()),
- appSandboxValue (settings, Ids::appSandbox, getUndoManager()),
- appSandboxInheritanceValue (settings, Ids::appSandboxInheritance, getUndoManager()),
- appSandboxOptionsValue (settings, Ids::appSandboxOptions, getUndoManager(), Array<var>(), ","),
- hardenedRuntimeValue (settings, Ids::hardenedRuntime, getUndoManager()),
- hardenedRuntimeOptionsValue (settings, Ids::hardenedRuntimeOptions, getUndoManager(), Array<var>(), ","),
- microphonePermissionNeededValue (settings, Ids::microphonePermissionNeeded, getUndoManager()),
- microphonePermissionsTextValue (settings, Ids::microphonePermissionsText, getUndoManager(),
- "This app requires audio input. If you do not have an audio interface connected it will use the built-in microphone."),
- cameraPermissionNeededValue (settings, Ids::cameraPermissionNeeded, getUndoManager()),
- cameraPermissionTextValue (settings, Ids::cameraPermissionText, getUndoManager(),
- "This app requires access to the camera to function correctly."),
- iosBluetoothPermissionNeededValue (settings, Ids::iosBluetoothPermissionNeeded, getUndoManager()),
- iosBluetoothPermissionTextValue (settings, Ids::iosBluetoothPermissionText, getUndoManager(),
- "This app requires access to Bluetooth to function correctly."),
- sendAppleEventsPermissionNeededValue (settings, Ids::sendAppleEventsPermissionNeeded, getUndoManager()),
- sendAppleEventsPermissionTextValue (settings, Ids::sendAppleEventsPermissionText, getUndoManager(),
- "This app requires the ability to send Apple events to function correctly."),
- uiFileSharingEnabledValue (settings, Ids::UIFileSharingEnabled, getUndoManager()),
- uiSupportsDocumentBrowserValue (settings, Ids::UISupportsDocumentBrowser, getUndoManager()),
- uiStatusBarHiddenValue (settings, Ids::UIStatusBarHidden, getUndoManager()),
- documentExtensionsValue (settings, Ids::documentExtensions, getUndoManager()),
- iosInAppPurchasesValue (settings, Ids::iosInAppPurchases, getUndoManager()),
- iosContentSharingValue (settings, Ids::iosContentSharing, getUndoManager(), true),
- iosBackgroundAudioValue (settings, Ids::iosBackgroundAudio, getUndoManager()),
- iosBackgroundBleValue (settings, Ids::iosBackgroundBle, getUndoManager()),
- iosPushNotificationsValue (settings, Ids::iosPushNotifications, getUndoManager()),
- iosAppGroupsValue (settings, Ids::iosAppGroups, getUndoManager()),
- iCloudPermissionsValue (settings, Ids::iCloudPermissions, getUndoManager()),
- iosDevelopmentTeamIDValue (settings, Ids::iosDevelopmentTeamID, getUndoManager()),
- iosAppGroupsIDValue (settings, Ids::iosAppGroupsId, getUndoManager()),
- keepCustomXcodeSchemesValue (settings, Ids::keepCustomXcodeSchemes, getUndoManager()),
- useHeaderMapValue (settings, Ids::useHeaderMap, getUndoManager()),
- customLaunchStoryboardValue (settings, Ids::customLaunchStoryboard, getUndoManager()),
- exporterBundleIdentifierValue (settings, Ids::bundleIdentifier, getUndoManager())
- {
- name = iOS ? getNameiOS() : getNameMac();
-
- targetLocationValue.setDefault (getDefaultBuildsRootFolder() + getTargetFolderForExporter (getValueTreeTypeName (isIOS)));
- }
-
- static XcodeProjectExporter* createForSettings (Project& projectToUse, const ValueTree& settingsToUse)
- {
- if (settingsToUse.hasType (getValueTreeTypeName (false))) return new XcodeProjectExporter (projectToUse, settingsToUse, false);
- if (settingsToUse.hasType (getValueTreeTypeName (true))) return new XcodeProjectExporter (projectToUse, settingsToUse, true);
-
- return nullptr;
- }
-
- //==============================================================================
- String getPListToMergeString() const { return customPListValue.get(); }
- String getPListPrefixHeaderString() const { return pListPrefixHeaderValue.get(); }
- bool isPListPreprocessEnabled() const { return pListPreprocessValue.get(); }
-
- String getSubprojectsString() const { return subprojectsValue.get(); }
-
- String getExtraFrameworksString() const { return extraFrameworksValue.get(); }
- String getFrameworkSearchPathsString() const { return frameworkSearchPathsValue.get(); }
- String getExtraCustomFrameworksString() const { return extraCustomFrameworksValue.get(); }
- String getEmbeddedFrameworksString() const { return embeddedFrameworksValue.get(); }
-
- String getPostBuildScript() const { return postbuildCommandValue.get(); }
- String getPreBuildScript() const { return prebuildCommandValue.get(); }
-
- bool shouldDuplicateAppExResourcesFolder() const { return duplicateAppExResourcesFolderValue.get(); }
-
- String getDeviceFamilyString() const { return iosDeviceFamilyValue.get(); }
-
- Array<var> getDefaultScreenOrientations() const { return { "UIInterfaceOrientationPortrait",
- "UIInterfaceOrientationLandscapeLeft",
- "UIInterfaceOrientationLandscapeRight" }; }
-
- Array<var> getiPhoneScreenOrientations() const { return *iPhoneScreenOrientationValue.get().getArray(); }
- Array<var> getiPadScreenOrientations() const { return *iPadScreenOrientationValue.get().getArray(); }
-
- String getCustomResourceFoldersString() const { return customXcodeResourceFoldersValue.get().toString().replaceCharacters ("\r\n", "::"); }
- String getCustomXcassetsFolderString() const { return customXcassetsFolderValue.get(); }
- String getCustomLaunchStoryboardString() const { return customLaunchStoryboardValue.get(); }
- bool shouldAddStoryboardToProject() const { return getCustomLaunchStoryboardString().isNotEmpty() || getCustomXcassetsFolderString().isEmpty(); }
-
- bool isHardenedRuntimeEnabled() const { return hardenedRuntimeValue.get(); }
- Array<var> getHardenedRuntimeOptions() const { return *hardenedRuntimeOptionsValue.get().getArray(); }
-
- bool isAppSandboxEnabled() const { return appSandboxValue.get(); }
- bool isAppSandboxInhertianceEnabled() const { return appSandboxInheritanceValue.get(); }
- Array<var> getAppSandboxOptions() const { return *appSandboxOptionsValue.get().getArray(); }
-
- bool isMicrophonePermissionEnabled() const { return microphonePermissionNeededValue.get(); }
- String getMicrophonePermissionsTextString() const { return microphonePermissionsTextValue.get(); }
-
- bool isCameraPermissionEnabled() const { return cameraPermissionNeededValue.get(); }
- String getCameraPermissionTextString() const { return cameraPermissionTextValue.get(); }
-
- bool isBluetoothPermissionEnabled() const { return iosBluetoothPermissionNeededValue.get(); }
- String getBluetoothPermissionTextString() const { return iosBluetoothPermissionTextValue.get(); }
-
- bool isSendAppleEventsPermissionEnabled() const { return sendAppleEventsPermissionNeededValue.get(); }
- String getSendAppleEventsPermissionTextString() const { return sendAppleEventsPermissionTextValue.get(); }
-
- bool isInAppPurchasesEnabled() const { return iosInAppPurchasesValue.get(); }
- bool isContentSharingEnabled() const { return iosContentSharingValue.get(); }
- bool isBackgroundAudioEnabled() const { return iosBackgroundAudioValue.get(); }
- bool isBackgroundBleEnabled() const { return iosBackgroundBleValue.get(); }
- bool isPushNotificationsEnabled() const { return iosPushNotificationsValue.get(); }
- bool isAppGroupsEnabled() const { return iosAppGroupsValue.get(); }
- bool isiCloudPermissionsEnabled() const { return iCloudPermissionsValue.get(); }
- bool isFileSharingEnabled() const { return uiFileSharingEnabledValue.get(); }
- bool isDocumentBrowserEnabled() const { return uiSupportsDocumentBrowserValue.get(); }
- bool isStatusBarHidden() const { return uiStatusBarHiddenValue.get(); }
-
- String getDocumentExtensionsString() const { return documentExtensionsValue.get(); }
-
- bool shouldKeepCustomXcodeSchemes() const { return keepCustomXcodeSchemesValue.get(); }
-
- String getDevelopmentTeamIDString() const { return iosDevelopmentTeamIDValue.get(); }
- String getAppGroupIdString() const { return iosAppGroupsIDValue.get(); }
-
- String getDefaultLaunchStoryboardName() const { return "LaunchScreen"; }
-
- //==============================================================================
- bool usesMMFiles() const override { return true; }
- bool canCopeWithDuplicateFiles() override { return true; }
- bool supportsUserDefinedConfigurations() const override { return true; }
-
- bool isXcode() const override { return true; }
- bool isVisualStudio() const override { return false; }
- bool isCodeBlocks() const override { return false; }
- bool isMakefile() const override { return false; }
- bool isAndroidStudio() const override { return false; }
- bool isCLion() const override { return false; }
-
- bool isAndroid() const override { return false; }
- bool isWindows() const override { return false; }
- bool isLinux() const override { return false; }
- bool isOSX() const override { return ! iOS; }
- bool isiOS() const override { return iOS; }
-
- bool supportsTargetType (build_tools::ProjectType::Target::Type type) const override
- {
- switch (type)
- {
- case build_tools::ProjectType::Target::AudioUnitv3PlugIn:
- case build_tools::ProjectType::Target::StandalonePlugIn:
- case build_tools::ProjectType::Target::GUIApp:
- case build_tools::ProjectType::Target::StaticLibrary:
- case build_tools::ProjectType::Target::DynamicLibrary:
- case build_tools::ProjectType::Target::SharedCodeTarget:
- case build_tools::ProjectType::Target::AggregateTarget:
- return true;
- case build_tools::ProjectType::Target::ConsoleApp:
- case build_tools::ProjectType::Target::VSTPlugIn:
- case build_tools::ProjectType::Target::VST3PlugIn:
- case build_tools::ProjectType::Target::AAXPlugIn:
- case build_tools::ProjectType::Target::RTASPlugIn:
- case build_tools::ProjectType::Target::AudioUnitPlugIn:
- case build_tools::ProjectType::Target::UnityPlugIn:
- return ! iOS;
- case build_tools::ProjectType::Target::unspecified:
- default:
- break;
- }
-
- return false;
- }
-
- void createExporterProperties (PropertyListBuilder& props) override
- {
- if (iOS)
- {
- props.add (new TextPropertyComponent (customXcassetsFolderValue, "Custom Xcassets Folder", 128, false),
- "If this field is not empty, your Xcode project will use the custom xcassets folder specified here "
- "for the app icons and launchimages, and will ignore the Icon files specified above. This will also prevent "
- "a launch storyboard from being used.");
-
- props.add (new TextPropertyComponent (customLaunchStoryboardValue, "Custom Launch Storyboard", 256, false),
- "If this field is not empty then the specified launch storyboard file will be added to the project as an Xcode "
- "resource and will be used for the app's launch screen, otherwise a default blank launch storyboard will be used. "
- "The file path should be relative to the project folder.");
- }
-
- props.add (new TextPropertyComponent (customXcodeResourceFoldersValue, "Custom Xcode Resource Folders", 8192, true),
- "You can specify a list of custom resource folders here (separated by newlines or whitespace). "
- "References to these folders will then be added to the Xcode resources. "
- "This way you can specify them for OS X and iOS separately, and modify the content of the resource folders "
- "without re-saving the Projucer project.");
-
- if (getProject().isAudioPluginProject())
- props.add (new ChoicePropertyComponent (duplicateAppExResourcesFolderValue, "Add Duplicate Resources Folder to App Extension"),
- "Disable this to prevent the Projucer from creating a duplicate resources folder for AUv3 app extensions.");
-
- if (iOS)
- {
- props.add (new ChoicePropertyComponent (iosDeviceFamilyValue, "Device Family",
- { "iPhone", "iPad", "Universal" },
- { "1", "2", "1,2" }),
- "The device family to target.");
-
- {
- StringArray orientationStrings { "Portrait", "Portrait Upside Down",
- "Landscape Left", "Landsscape Right" };
-
- Array<var> orientationVars { "UIInterfaceOrientationPortrait", "UIInterfaceOrientationPortraitUpsideDown",
- "UIInterfaceOrientationLandscapeLeft", "UIInterfaceOrientationLandscapeRight" };
-
- props.add (new MultiChoicePropertyComponent (iPhoneScreenOrientationValue, "iPhone Screen Orientation", orientationStrings, orientationVars),
- "The screen orientations that this app should support on iPhones.");
-
- props.add (new MultiChoicePropertyComponent (iPadScreenOrientationValue, "iPad Screen Orientation", orientationStrings, orientationVars),
- "The screen orientations that this app should support on iPads.");
- }
-
- props.add (new ChoicePropertyComponent (uiFileSharingEnabledValue, "File Sharing Enabled"),
- "Enable this to expose your app's files to iTunes.");
-
- props.add (new ChoicePropertyComponent (uiSupportsDocumentBrowserValue, "Support Document Browser"),
- "Enable this to allow the user to access your app documents from a native file chooser.");
-
- props.add (new ChoicePropertyComponent (uiStatusBarHiddenValue, "Status Bar Hidden"),
- "Enable this to disable the status bar in your app.");
- }
- else if (projectType.isGUIApplication())
- {
- props.add (new TextPropertyComponent (documentExtensionsValue, "Document File Extensions", 128, false),
- "A comma-separated list of file extensions for documents that your app can open. "
- "Using a leading '.' is optional, and the extensions are not case-sensitive.");
- }
-
- if (isOSX())
- {
- props.add (new ChoicePropertyComponent (appSandboxValue, "Use App Sandbox"),
- "Enable this to use the app sandbox.");
-
- props.add (new ChoicePropertyComponentWithEnablement (appSandboxInheritanceValue, appSandboxValue, "App Sandbox Inheritance"),
- "If app sandbox is enabled, this setting will configure a child process to inherit the sandbox of its parent. "
- "Note that if you enable this and have specified any other app sandbox entitlements below, the child process "
- "will fail to launch.");
-
- std::vector<std::pair<String, String>> sandboxOptions
- {
- { "Network: Incoming Connections (Server)", "network.server" },
- { "Network: Outgoing Connections (Client)", "network.client" },
-
- { "Hardware: Camera", "device.camera" },
- { "Hardware: Microphone", "device.microphone" },
- { "Hardware: USB", "device.usb" },
- { "Hardware: Printing", "print" },
- { "Hardware: Bluetooth", "device.bluetooth" },
-
- { "App Data: Contacts", "personal-information.addressbook" },
- { "App Data: Location", "personal-information.location" },
- { "App Data: Calendar", "personal-information.calendars" },
-
- { "File Access: User Selected File (Read Only)", "files.user-selected.read-only" },
- { "File Access: User Selected File (Read/Write)", "files.user-selected.read-write" },
- { "File Access: Downloads Folder (Read Only)", "files.downloads.read-only" },
- { "File Access: Downloads Folder (Read/Write)", "files.downloads.read-write" },
- { "File Access: Pictures Folder (Read Only)", "files.pictures.read-only" },
- { "File Access: Pictures Folder (Read/Write)", "files.pictures.read-write" },
- { "File Access: Music Folder (Read Only)", "assets.music.read-only" },
- { "File Access: Music Folder (Read/Write)", "assets.music.read-write" },
- { "File Access: Movies Folder (Read Only)", "assets.movies.read-only" },
- { "File Access: Movies Folder (Read/Write)", "assets.movies.read-write" },
-
- { "Temporary Exception: Audio Unit Hosting", "temporary-exception.audio-unit-host" },
- { "Temporary Exception: Global Mach Service", "temporary-exception.mach-lookup.global-name" },
- { "Temporary Exception: Global Mach Service Dynamic Registration", "temporary-exception.mach-register.global-name" },
- { "Temporary Exception: Home Directory File Access (Read Only)", "temporary-exception.files.home-relative-path.read-only" },
- { "Temporary Exception: Home Directory File Access (Read/Write)", "temporary-exception.files.home-relative-path.read-write" },
- { "Temporary Exception: Absolute Path File Access (Read Only)", "temporary-exception.files.absolute-path.read-only" },
- { "Temporary Exception: Absolute Path File Access (Read/Write)", "temporary-exception.files.absolute-path.read-write" },
- { "Temporary Exception: IOKit User Client Class", "temporary-exception.iokit-user-client-class" },
- { "Temporary Exception: Shared Preference Domain (Read Only)", "temporary-exception.shared-preference.read-only" },
- { "Temporary Exception: Shared Preference Domain (Read/Write)", "temporary-exception.shared-preference.read-write" }
- };
-
- StringArray sandboxKeys;
- Array<var> sanboxValues;
-
- for (auto& opt : sandboxOptions)
- {
- sandboxKeys.add (opt.first);
- sanboxValues.add ("com.apple.security." + opt.second);
- }
-
- props.add (new MultiChoicePropertyComponentWithEnablement (appSandboxOptionsValue,
- appSandboxValue,
- "App Sandbox Options",
- sandboxKeys,
- sanboxValues));
-
- props.add (new ChoicePropertyComponent (hardenedRuntimeValue, "Use Hardened Runtime"),
- "Enable this to use the hardened runtime required for app notarization.");
-
- std::vector<std::pair<String, String>> hardeningOptions
- {
- { "Runtime Exceptions: Allow Execution of JIT-compiled Code", "cs.allow-jit" },
- { "Runtime Exceptions: Allow Unsigned Executable Memory", "cs.allow-unsigned-executable-memory" },
- { "Runtime Exceptions: Allow DYLD Environment Variables", "cs.allow-dyld-environment-variables" },
- { "Runtime Exceptions: Disable Library Validation", "cs.disable-library-validation" },
- { "Runtime Exceptions: Disable Executable Memory Protection", "cs.disable-executable-page-protection" },
- { "Runtime Exceptions: Debugging Tool", "cs.debugger" },
-
- { "Resource Access: Audio Input", "device.audio-input" },
- { "Resource Access: Camera", "device.camera" },
- { "Resource Access: Location", "personal-information.location" },
- { "Resource Access: Address Book", "personal-information.addressbook" },
- { "Resource Access: Calendar", "personal-information.calendars" },
- { "Resource Access: Photos Library", "personal-information.photos-library" },
- { "Resource Access: Apple Events", "automation.apple-events" }
- };
-
- StringArray hardeningKeys;
- Array<var> hardeningValues;
-
- for (auto& opt : hardeningOptions)
- {
- hardeningKeys.add (opt.first);
- hardeningValues.add ("com.apple.security." + opt.second);
- }
-
- props.add (new MultiChoicePropertyComponentWithEnablement (hardenedRuntimeOptionsValue,
- hardenedRuntimeValue,
- "Hardened Runtime Options",
- hardeningKeys,
- hardeningValues));
- }
-
- props.add (new ChoicePropertyComponent (microphonePermissionNeededValue, "Microphone Access"),
- "Enable this to allow your app to use the microphone. "
- "The user of your app will be prompted to grant microphone access permissions.");
-
- props.add (new TextPropertyComponentWithEnablement (microphonePermissionsTextValue, microphonePermissionNeededValue,
- "Microphone Access Text", 1024, false),
- "A short description of why your app requires microphone access.");
-
- props.add (new ChoicePropertyComponent (cameraPermissionNeededValue, "Camera Access"),
- "Enable this to allow your app to use the camera. "
- "The user of your app will be prompted to grant camera access permissions.");
-
- props.add (new TextPropertyComponentWithEnablement (cameraPermissionTextValue, cameraPermissionNeededValue,
- "Camera Access Text", 1024, false),
- "A short description of why your app requires camera access.");
-
- if (iOS)
- {
- props.add (new ChoicePropertyComponent (iosBluetoothPermissionNeededValue, "Bluetooth Access"),
- "Enable this to allow your app to use Bluetooth on iOS 13.0 and above. "
- "The user of your app will be prompted to grant Bluetooth access permissions.");
-
- props.add (new TextPropertyComponentWithEnablement (iosBluetoothPermissionTextValue, iosBluetoothPermissionNeededValue,
- "Bluetooth Access Text", 1024, false),
- "A short description of why your app requires Bluetooth access.");
- }
- else
- {
- props.add (new ChoicePropertyComponent (sendAppleEventsPermissionNeededValue, "Send Apple Events"),
- "Enable this to allow your app to send Apple events. "
- "The user of your app will be prompted to grant permissions to control other apps.");
-
- props.add (new TextPropertyComponentWithEnablement (sendAppleEventsPermissionTextValue, sendAppleEventsPermissionNeededValue,
- "Send Apple Events Text", 1024, false),
- "A short description of why your app requires the ability to send Apple events.");
- }
-
- props.add (new ChoicePropertyComponent (iosInAppPurchasesValue, "In-App Purchases Capability"),
- "Enable this to grant your app the capability for in-app purchases. "
- "This option requires that you specify a valid Development Team ID.");
-
- if (iOS)
- {
- props.add (new ChoicePropertyComponent (iosContentSharingValue, "Content Sharing"),
- "Enable this to allow your app to share content with other apps.");
-
- props.add (new ChoicePropertyComponent (iosBackgroundAudioValue, "Audio Background Capability"),
- "Enable this to grant your app the capability to access audio when in background mode. "
- "This permission is required if your app creates a MIDI input or output device.");
-
- props.add (new ChoicePropertyComponent (iosBackgroundBleValue, "Bluetooth MIDI Background Capability"),
- "Enable this to grant your app the capability to connect to Bluetooth LE devices when in background mode.");
-
- props.add (new ChoicePropertyComponent (iosAppGroupsValue, "App Groups Capability"),
- "Enable this to grant your app the capability to share resources between apps using the same app group ID.");
-
- props.add (new ChoicePropertyComponent (iCloudPermissionsValue, "iCloud Permissions"),
- "Enable this to grant your app the capability to use native file load/save browser windows on iOS.");
- }
-
- props.add (new ChoicePropertyComponent (iosPushNotificationsValue, "Push Notifications Capability"),
- "Enable this to grant your app the capability to receive push notifications.");
-
- props.add (new TextPropertyComponent (customPListValue, "Custom PList", 8192, true),
- "You can paste the contents of an XML PList file in here, and the settings that it contains will override any "
- "settings that the Projucer creates. BEWARE! When doing this, be careful to remove from the XML any "
- "values that you DO want the Projucer to change!");
-
- props.add (new ChoicePropertyComponent (pListPreprocessValue, "PList Preprocess"),
- "Enable this to preprocess PList file. This will allow you to set values to preprocessor defines,"
- " for instance if you define: #define MY_FLAG 1 in a prefix header file (see PList prefix header), you can have"
- " a key with MY_FLAG value and it will be replaced with 1.");
-
- props.add (new TextPropertyComponent (pListPrefixHeaderValue, "PList Prefix Header", 512, false),
- "Header file containing definitions used in plist file (see PList Preprocess).");
-
- props.add (new TextPropertyComponent (extraFrameworksValue, "Extra System Frameworks", 2048, false),
- "A comma-separated list of extra system frameworks that should be added to the build. "
- "(Don't include the .framework extension in the name)"
- " The frameworks are expected to be located in /System/Library/Frameworks");
-
- props.add (new TextPropertyComponent (frameworkSearchPathsValue, "Framework Search Paths", 8192, true),
- "A set of paths to search for custom frameworks (one per line).");
-
- props.add (new TextPropertyComponent (extraCustomFrameworksValue, "Extra Custom Frameworks", 8192, true),
- "Paths to custom frameworks that should be added to the build (one per line). "
- "You will probably need to add an entry to the Framework Search Paths for each unique directory.");
-
- props.add (new TextPropertyComponent (embeddedFrameworksValue, "Embedded Frameworks", 8192, true),
- "Paths to frameworks to be embedded with the app (one per line). "
- "If you are adding a framework here then you do not need to specify it in Extra Custom Frameworks too. "
- "You will probably need to add an entry to the Framework Search Paths for each unique directory.");
-
- props.add (new TextPropertyComponent (subprojectsValue, "Xcode Subprojects", 8192, true),
- "Paths to Xcode projects that should be added to the build (one per line). "
- "These can be absolute or relative to the build directory. "
- "The names of the required build products can be specified after a colon, comma separated, "
- "e.g. \"path/to/MySubProject.xcodeproj: MySubProject, OtherTarget\". "
- "If no build products are specified, all build products associated with a subproject will be added.");
-
- props.add (new TextPropertyComponent (prebuildCommandValue, "Pre-Build Shell Script", 32768, true),
- "Some shell-script that will be run before a build starts.");
-
- props.add (new TextPropertyComponent (postbuildCommandValue, "Post-Build Shell Script", 32768, true),
- "Some shell-script that will be run after a build completes.");
-
- props.add (new TextPropertyComponent (exporterBundleIdentifierValue, "Exporter Bundle Identifier", 256, false),
- "Use this to override the project bundle identifier for this exporter. "
- "This is useful if you want to use different bundle identifiers for Mac and iOS exporters in the same project.");
-
- props.add (new TextPropertyComponent (iosDevelopmentTeamIDValue, "Development Team ID", 10, false),
- "The Development Team ID to be used for setting up code-signing your app. This is a ten-character "
- "string (for example, \"S7B6T5XJ2Q\") that describes the distribution certificate Apple issued to you. "
- "You can find this string in the OS X app Keychain Access under \"Certificates\".");
-
- if (iOS)
- props.add (new TextPropertyComponentWithEnablement (iosAppGroupsIDValue, iosAppGroupsValue, "App Group ID", 256, false),
- "The App Group ID to be used for allowing multiple apps to access a shared resource folder. Multiple IDs can be "
- "added separated by a semicolon.");
-
- props.add (new ChoicePropertyComponent (keepCustomXcodeSchemesValue, "Keep Custom Xcode Schemes"),
- "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.");
-
- props.add (new ChoicePropertyComponent (useHeaderMapValue, "USE_HEADERMAP"),
- "Enable this to make Xcode search all the projects folders for include files. This means you can be lazy "
- "and not bother using relative paths to include your headers, but it means your code won't be "
- "compatible with other build systems");
- }
-
- bool launchProject() override
- {
- #if JUCE_MAC
- return getProjectBundle().startAsProcess();
- #else
- return false;
- #endif
- }
-
- bool canLaunchProject() override
- {
- #if JUCE_MAC
- return true;
- #else
- return false;
- #endif
- }
-
- //==============================================================================
- void create (const OwnedArray<LibraryModule>&) const override
- {
- for (auto& target : targets)
- if (target->shouldCreatePList())
- target->infoPlistFile = getTargetFolder().getChildFile (target->getInfoPlistName());
-
- menuNibFile = getTargetFolder().getChildFile ("RecentFilesMenuTemplate.nib");
-
- createIconFile();
-
- auto projectBundle = getProjectBundle();
- createDirectoryOrThrow (projectBundle);
-
- createObjects();
-
- build_tools::writeStreamToFile (projectBundle.getChildFile ("project.pbxproj"),
- [this] (MemoryOutputStream& mo) { writeProjectFile (mo); });
-
- writeInfoPlistFiles();
-
- // This forces the project to use the legacy build system to workaround Xcode 10 issues,
- // hopefully these will be fixed in the future and this can be removed...
- writeWorkspaceSettings();
-
- // Deleting the .rsrc files can be needed to force Xcode to update the version number.
- deleteRsrcFiles (getTargetFolder().getChildFile ("build"));
- }
-
- //==============================================================================
- void addPlatformSpecificSettingsForProjectType (const build_tools::ProjectType&) override
- {
- callForAllSupportedTargets ([this] (build_tools::ProjectType::Target::Type targetType)
- {
- targets.insert (targetType == build_tools::ProjectType::Target::AggregateTarget ? 0 : -1,
- new XcodeTarget (targetType, *this));
- });
-
- // 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 updateDeprecatedSettings() override
- {
- if (iOS)
- updateOldOrientationSettings();
- }
-
- void updateDeprecatedSettingsInteractively() override
- {
- if (hasInvalidPostBuildScript())
- {
- String alertWindowText = iOS ? "Your Xcode (iOS) Exporter settings use an invalid post-build script. Click 'Update' to remove it."
- : "Your Xcode (OSX) Exporter settings use a pre-JUCE 4.2 post-build script to move the plug-in binaries to their plug-in install folders.\n\n"
- "Since JUCE 4.2, this is instead done using \"AU/VST/VST2/AAX/RTAS Binary Location\" in the Xcode (OS X) configuration settings.\n\n"
- "Click 'Update' to remove the script (otherwise your plug-in may not compile correctly).";
-
- if (AlertWindow::showOkCancelBox (AlertWindow::WarningIcon,
- "Project settings: " + project.getDocumentTitle(),
- alertWindowText, "Update", "Cancel", nullptr, nullptr))
- postbuildCommandValue.resetToDefault();
- }
- }
-
- bool hasInvalidPostBuildScript() const
- {
- // check whether the script is identical to the old one that the Introjucer used to auto-generate
- return (MD5 (getPostBuildScript().toUTF8()).toHexString() == "265ac212a7e734c5bbd6150e1eae18a1");
- }
-
- //==============================================================================
- void initialiseDependencyPathValues() override
- {
- vstLegacyPathValueWrapper.init ({ settings, Ids::vstLegacyFolder, nullptr },
- getAppSettings().getStoredPath (Ids::vstLegacyPath, TargetOS::osx), TargetOS::osx);
-
- aaxPathValueWrapper.init ({ settings, Ids::aaxFolder, nullptr },
- getAppSettings().getStoredPath (Ids::aaxPath, TargetOS::osx), TargetOS::osx);
-
- rtasPathValueWrapper.init ({ settings, Ids::rtasFolder, nullptr },
- getAppSettings().getStoredPath (Ids::rtasPath, TargetOS::osx), TargetOS::osx);
- }
-
- protected:
- //==============================================================================
- class XcodeBuildConfiguration : public BuildConfiguration
- {
- public:
- XcodeBuildConfiguration (Project& p, const ValueTree& t, const bool isIOS, const ProjectExporter& e)
- : BuildConfiguration (p, t, e),
- iOS (isIOS),
- osxSDKVersion (config, Ids::osxSDK, getUndoManager()),
- osxDeploymentTarget (config, Ids::osxCompatibility, getUndoManager(), getSDKDisplayName (defaultDeploymentTarget)),
- iosDeploymentTarget (config, Ids::iosCompatibility, getUndoManager(), iOSDefaultVersion),
- osxArchitecture (config, Ids::osxArchitecture, getUndoManager(), osxArch_Default),
- customXcodeFlags (config, Ids::customXcodeFlags, getUndoManager()),
- plistPreprocessorDefinitions (config, Ids::plistPreprocessorDefinitions, getUndoManager()),
- codeSignIdentity (config, Ids::codeSigningIdentity, getUndoManager()),
- fastMathEnabled (config, Ids::fastMath, getUndoManager()),
- stripLocalSymbolsEnabled (config, Ids::stripLocalSymbols, getUndoManager()),
- pluginBinaryCopyStepEnabled (config, Ids::enablePluginBinaryCopyStep, getUndoManager(), true),
- vstBinaryLocation (config, Ids::vstBinaryLocation, getUndoManager(), "$(HOME)/Library/Audio/Plug-Ins/VST/"),
- vst3BinaryLocation (config, Ids::vst3BinaryLocation, getUndoManager(), "$(HOME)/Library/Audio/Plug-Ins/VST3/"),
- auBinaryLocation (config, Ids::auBinaryLocation, getUndoManager(), "$(HOME)/Library/Audio/Plug-Ins/Components/"),
- rtasBinaryLocation (config, Ids::rtasBinaryLocation, getUndoManager(), "/Library/Application Support/Digidesign/Plug-Ins/"),
- aaxBinaryLocation (config, Ids::aaxBinaryLocation, getUndoManager(), "/Library/Application Support/Avid/Audio/Plug-Ins/"),
- unityPluginBinaryLocation (config, Ids::unityPluginBinaryLocation, getUndoManager())
- {
- updateOldPluginBinaryLocations();
- updateOldSDKDefaults();
-
- optimisationLevelValue.setDefault (isDebug() ? gccO0 : gccO3);
- }
-
- //==============================================================================
- void createConfigProperties (PropertyListBuilder& props) override
- {
- if (project.isAudioPluginProject())
- addXcodePluginInstallPathProperties (props);
-
- addRecommendedLLVMCompilerWarningsProperty (props);
- addGCCOptimisationProperty (props);
-
- if (iOS)
- {
- Array<var> iOSVersionVars;
-
- for (auto& s : iOSVersions)
- iOSVersionVars.add (s);
-
- props.add (new ChoicePropertyComponent (iosDeploymentTarget, "iOS Deployment Target", iOSVersions, iOSVersionVars),
- "The minimum version of iOS that the target binary will run on.");
- }
- else
- {
- props.add (new ChoicePropertyComponent (osxSDKVersion, "OSX Base SDK Version", getSDKChoiceList<StringArray> (oldestSDKVersion, true),
- getSDKChoiceList<Array<var>> (oldestSDKVersion, true)),
- "The version of the macOS SDK to link against. If \"Default\" is selected then the Xcode default will be used.");
-
- props.add (new ChoicePropertyComponent (osxDeploymentTarget, "OSX Deployment Target", getSDKChoiceList<StringArray> (oldestDeploymentTarget, false),
- getSDKChoiceList<Array<var>> (oldestDeploymentTarget, true)),
- "The minimum version of OSX that the target binary will be compatible with.");
-
- props.add (new ChoicePropertyComponent (osxArchitecture, "OSX Architecture",
- { "Native architecture of build machine", "Universal Binary (32-bit)", "Universal Binary (32/64-bit)", "64-bit Intel" },
- { osxArch_Native, osxArch_32BitUniversal, osxArch_64BitUniversal, osxArch_64Bit }),
- "The type of OSX binary that will be produced.");
- }
-
- props.add (new TextPropertyComponent (customXcodeFlags, "Custom Xcode Flags", 8192, true),
- "A comma-separated list of custom Xcode setting flags which will be appended to the list of generated flags, "
- "e.g. MACOSX_DEPLOYMENT_TARGET_i386 = 10.5, VALID_ARCHS = \"ppc i386 x86_64\"");
-
- props.add (new TextPropertyComponent (plistPreprocessorDefinitions, "PList Preprocessor Definitions", 2048, true),
- "Preprocessor definitions used during PList preprocessing (see PList Preprocess).");
-
- props.add (new TextPropertyComponent (codeSignIdentity, "Code-Signing Identity", 1024, false),
- "The name of a code-signing identity for Xcode to apply.");
-
- props.add (new ChoicePropertyComponent (fastMathEnabled, "Relax IEEE Compliance"),
- "Enable this to use FAST_MATH non-IEEE mode. (Warning: this can have unexpected results!)");
-
- props.add (new ChoicePropertyComponent (stripLocalSymbolsEnabled, "Strip Local Symbols"),
- "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. "
- "Note that disabling this will not necessarily generate full debug symbols. For release configs, "
- "you will also need to add the following to the \"Custom Xcode Flags\" field: "
- "GCC_GENERATE_DEBUGGING_SYMBOLS = YES, STRIP_INSTALLED_PRODUCT = NO, COPY_PHASE_STRIP = NO");
- }
-
- String getModuleLibraryArchName() const override
- {
- return "${CURRENT_ARCH}";
- }
-
- //==============================================================================
- String getOSXArchitectureString() const { return osxArchitecture.get(); }
- String getPListPreprocessorDefinitionsString() const { return plistPreprocessorDefinitions.get(); }
-
- bool isFastMathEnabled() const { return fastMathEnabled.get(); }
-
- bool isStripLocalSymbolsEnabled() const { return stripLocalSymbolsEnabled.get(); }
-
- String getCustomXcodeFlagsString() const { return customXcodeFlags.get(); }
-
- String getOSXSDKVersionString() const { return osxSDKVersion.get(); }
- String getOSXDeploymentTargetString() const { return osxDeploymentTarget.get(); }
-
- String getCodeSignIdentityString() const { return codeSignIdentity.get(); }
-
- String getiOSDeploymentTargetString() const { return iosDeploymentTarget.get(); }
-
- bool isPluginBinaryCopyStepEnabled() const { return pluginBinaryCopyStepEnabled.get(); }
- String getVSTBinaryLocationString() const { return vstBinaryLocation.get(); }
- String getVST3BinaryLocationString() const { return vst3BinaryLocation.get(); }
- String getAUBinaryLocationString() const { return auBinaryLocation.get(); }
- String getRTASBinaryLocationString() const { return rtasBinaryLocation.get();}
- String getAAXBinaryLocationString() const { return aaxBinaryLocation.get();}
- String getUnityPluginBinaryLocationString() const { return unityPluginBinaryLocation.get(); }
-
- private:
- //==============================================================================
- bool iOS;
-
- ValueWithDefault osxSDKVersion, osxDeploymentTarget, iosDeploymentTarget, osxArchitecture,
- customXcodeFlags, plistPreprocessorDefinitions, codeSignIdentity,
- fastMathEnabled, stripLocalSymbolsEnabled, pluginBinaryCopyStepEnabled,
- vstBinaryLocation, vst3BinaryLocation, auBinaryLocation, rtasBinaryLocation,
- aaxBinaryLocation, unityPluginBinaryLocation;
-
- //==============================================================================
- void addXcodePluginInstallPathProperties (PropertyListBuilder& props)
- {
- auto isBuildingAnyPlugins = (project.shouldBuildVST() || project.shouldBuildVST3() || project.shouldBuildAU()
- || project.shouldBuildRTAS() || project.shouldBuildAAX() || project.shouldBuildUnityPlugin());
-
- if (isBuildingAnyPlugins)
- props.add (new ChoicePropertyComponent (pluginBinaryCopyStepEnabled, "Enable Plugin Copy Step"),
- "Enable this to copy plugin binaries to the specified folder after building.");
-
- if (project.shouldBuildVST3())
- props.add (new TextPropertyComponentWithEnablement (vst3BinaryLocation, pluginBinaryCopyStepEnabled, "VST3 Binary Location",
- 1024, false),
- "The folder in which the compiled VST3 binary should be placed.");
-
- if (project.shouldBuildAU())
- props.add (new TextPropertyComponentWithEnablement (auBinaryLocation, pluginBinaryCopyStepEnabled, "AU Binary Location",
- 1024, false),
- "The folder in which the compiled AU binary should be placed.");
-
- if (project.shouldBuildRTAS())
- props.add (new TextPropertyComponentWithEnablement (rtasBinaryLocation, pluginBinaryCopyStepEnabled, "RTAS Binary Location",
- 1024, false),
- "The folder in which the compiled RTAS binary should be placed.");
-
- if (project.shouldBuildAAX())
- props.add (new TextPropertyComponentWithEnablement (aaxBinaryLocation, pluginBinaryCopyStepEnabled, "AAX Binary Location",
- 1024, false),
- "The folder in which the compiled AAX binary should be placed.");
-
- if (project.shouldBuildUnityPlugin())
- props.add (new TextPropertyComponentWithEnablement (unityPluginBinaryLocation, pluginBinaryCopyStepEnabled, "Unity Binary Location",
- 1024, false),
- "The folder in which the compiled Unity plugin binary and associated C# GUI script should be placed.");
-
- if (project.shouldBuildVST())
- props.add (new TextPropertyComponentWithEnablement (vstBinaryLocation, pluginBinaryCopyStepEnabled, "VST Binary Location",
- 1024, false),
- "The folder in which the compiled legacy VST binary should be placed.");
- }
-
- void updateOldPluginBinaryLocations()
- {
- if (! config ["xcodeVstBinaryLocation"].isVoid()) vstBinaryLocation = config ["xcodeVstBinaryLocation"];
- if (! config ["xcodeVst3BinaryLocation"].isVoid()) vst3BinaryLocation = config ["xcodeVst3BinaryLocation"];
- if (! config ["xcodeAudioUnitBinaryLocation"].isVoid()) auBinaryLocation = config ["xcodeAudioUnitBinaryLocation"];
- if (! config ["xcodeRtasBinaryLocation"].isVoid()) rtasBinaryLocation = config ["xcodeRtasBinaryLocation"];
- if (! config ["xcodeAaxBinaryLocation"].isVoid()) aaxBinaryLocation = config ["xcodeAaxBinaryLocation"];
- }
-
- void updateOldSDKDefaults()
- {
- if (iosDeploymentTarget.get() == "default") iosDeploymentTarget.resetToDefault();
- if (osxArchitecture.get() == "default") osxArchitecture.resetToDefault();
- if (osxSDKVersion.get() == "default") osxSDKVersion.resetToDefault();
- if (osxDeploymentTarget.get() == "default") osxDeploymentTarget.resetToDefault();
- }
- };
-
- BuildConfiguration::Ptr createBuildConfig (const ValueTree& v) const override
- {
- return *new XcodeBuildConfiguration (project, v, iOS, *this);
- }
-
- public:
- //==============================================================================
- /* The numbers for these enum values are defined by Xcode for the different
- possible destinations of a "copy files" post-build step.
- */
- enum XcodeCopyFilesDestinationIDs
- {
- kWrapperFolder = 1,
- kExecutablesFolder = 6,
- kResourcesFolder = 7,
- kFrameworksFolder = 10,
- kSharedFrameworksFolder = 11,
- kSharedSupportFolder = 12,
- kPluginsFolder = 13,
- kJavaResourcesFolder = 15,
- kXPCServicesFolder = 16
- };
-
- //==============================================================================
- struct XcodeTarget : build_tools::ProjectType::Target
- {
- //==============================================================================
- XcodeTarget (build_tools::ProjectType::Target::Type targetType, const XcodeProjectExporter& exporter)
- : Target (targetType),
- owner (exporter)
- {
- switch (type)
- {
- case GUIApp:
- xcodeFileType = "wrapper.application";
- xcodeBundleExtension = ".app";
- xcodeProductType = "com.apple.product-type.application";
- xcodeCopyToProductInstallPathAfterBuild = false;
- break;
-
- case ConsoleApp:
- xcodeFileType = "compiled.mach-o.executable";
- xcodeBundleExtension = String();
- xcodeProductType = "com.apple.product-type.tool";
- xcodeCopyToProductInstallPathAfterBuild = false;
- break;
-
- case StaticLibrary:
- xcodeFileType = "archive.ar";
- xcodeBundleExtension = ".a";
- xcodeProductType = "com.apple.product-type.library.static";
- xcodeCopyToProductInstallPathAfterBuild = false;
- break;
-
- case DynamicLibrary:
- xcodeFileType = "compiled.mach-o.dylib";
- xcodeProductType = "com.apple.product-type.library.dynamic";
- xcodeBundleExtension = ".dylib";
- xcodeCopyToProductInstallPathAfterBuild = false;
- break;
-
- case VSTPlugIn:
- xcodeFileType = "wrapper.cfbundle";
- xcodeBundleExtension = ".vst";
- xcodeProductType = "com.apple.product-type.bundle";
- xcodeCopyToProductInstallPathAfterBuild = true;
- break;
-
- case VST3PlugIn:
- xcodeFileType = "wrapper.cfbundle";
- xcodeBundleExtension = ".vst3";
- xcodeProductType = "com.apple.product-type.bundle";
- xcodeCopyToProductInstallPathAfterBuild = true;
- break;
-
- case AudioUnitPlugIn:
- xcodeFileType = "wrapper.cfbundle";
- xcodeBundleExtension = ".component";
- xcodeProductType = "com.apple.product-type.bundle";
- xcodeCopyToProductInstallPathAfterBuild = true;
-
- addExtraAudioUnitTargetSettings();
- break;
-
- case StandalonePlugIn:
- xcodeFileType = "wrapper.application";
- xcodeBundleExtension = ".app";
- xcodeProductType = "com.apple.product-type.application";
- xcodeCopyToProductInstallPathAfterBuild = false;
- break;
-
- case AudioUnitv3PlugIn:
- xcodeFileType = "wrapper.app-extension";
- xcodeBundleExtension = ".appex";
- xcodeBundleIDSubPath = "AUv3";
- xcodeProductType = "com.apple.product-type.app-extension";
- xcodeCopyToProductInstallPathAfterBuild = false;
-
- addExtraAudioUnitv3PlugInTargetSettings();
- break;
-
- case AAXPlugIn:
- xcodeFileType = "wrapper.cfbundle";
- xcodeBundleExtension = ".aaxplugin";
- xcodeProductType = "com.apple.product-type.bundle";
- xcodeCopyToProductInstallPathAfterBuild = true;
- break;
-
- case RTASPlugIn:
- xcodeFileType = "wrapper.cfbundle";
- xcodeBundleExtension = ".dpm";
- xcodeProductType = "com.apple.product-type.bundle";
- xcodeCopyToProductInstallPathAfterBuild = true;
- break;
-
- case UnityPlugIn:
- xcodeFileType = "wrapper.cfbundle";
- xcodeBundleExtension = ".bundle";
- xcodeProductType = "com.apple.product-type.bundle";
- xcodeCopyToProductInstallPathAfterBuild = true;
- break;
-
- case SharedCodeTarget:
- xcodeFileType = "archive.ar";
- xcodeBundleExtension = ".a";
- xcodeProductType = "com.apple.product-type.library.static";
- xcodeCopyToProductInstallPathAfterBuild = false;
- break;
-
- case AggregateTarget:
- xcodeCopyToProductInstallPathAfterBuild = false;
- break;
-
- case unspecified:
- default:
- // unknown target type!
- jassertfalse;
- break;
- }
- }
-
- String getXcodeSchemeName() const
- {
- return owner.projectName + " - " + getName();
- }
-
- String getID() const
- {
- return owner.createID (String ("__target") + getName());
- }
-
- String getInfoPlistName() const
- {
- return String ("Info-") + String (getName()).replace (" ", "_") + String (".plist");
- }
-
- String getEntitlementsFilename() const
- {
- return String (getName()).replace (" ", "_") + String (".entitlements");
- }
-
- String xcodeBundleExtension;
- String xcodeProductType, xcodeFileType;
- String xcodeOtherRezFlags, xcodeBundleIDSubPath;
- bool xcodeCopyToProductInstallPathAfterBuild;
- StringArray xcodeFrameworks, xcodeLibs;
- Array<XmlElement> xcodeExtraPListEntries;
-
- StringArray frameworkIDs, buildPhaseIDs, configIDs, sourceIDs, rezFileIDs;
- StringArray frameworkNames;
- String dependencyID, mainBuildProductID;
- File infoPlistFile;
-
- struct SourceFileInfo
- {
- build_tools::RelativePath path;
- bool shouldBeCompiled = false;
- };
-
- Array<SourceFileInfo> getSourceFilesInfo (const Project::Item& projectItem) const
- {
- Array<SourceFileInfo> result;
-
- auto targetType = (owner.getProject().isAudioPluginProject() ? type : SharedCodeTarget);
-
- if (projectItem.isGroup())
- {
- for (int i = 0; i < projectItem.getNumChildren(); ++i)
- result.addArray (getSourceFilesInfo (projectItem.getChild (i)));
- }
- else if (projectItem.shouldBeAddedToTargetProject() && projectItem.shouldBeAddedToTargetExporter (owner)
- && owner.getProject().getTargetTypeFromFilePath (projectItem.getFile(), true) == targetType)
- {
- SourceFileInfo info;
-
- info.path = build_tools::RelativePath (projectItem.getFile(),
- owner.getTargetFolder(),
- build_tools::RelativePath::buildTargetFolder);
-
- jassert (info.path.getRoot() == build_tools::RelativePath::buildTargetFolder);
-
- if (targetType == SharedCodeTarget || projectItem.shouldBeCompiled())
- info.shouldBeCompiled = projectItem.shouldBeCompiled();
-
- result.add (info);
- }
-
- return result;
- }
-
- //==============================================================================
- void addMainBuildProduct() const
- {
- jassert (xcodeFileType.isNotEmpty());
- jassert (xcodeBundleExtension.isEmpty() || xcodeBundleExtension.startsWithChar ('.'));
-
- if (ProjectExporter::BuildConfiguration::Ptr config = owner.getConfiguration(0))
- {
- auto productName = owner.replacePreprocessorTokens (*config, config->getTargetBinaryNameString (type == UnityPlugIn));
-
- if (xcodeFileType == "archive.ar")
- productName = getStaticLibbedFilename (productName);
- else
- productName += xcodeBundleExtension;
-
- addBuildProduct (xcodeFileType, productName);
- }
- }
-
- //==============================================================================
- void addBuildProduct (const String& fileType, const String& binaryName) const
- {
- auto* v = new ValueTree (owner.createID (String ("__productFileID") + getName()));
- v->setProperty ("isa", "PBXFileReference", nullptr);
- v->setProperty ("explicitFileType", fileType, nullptr);
- v->setProperty ("includeInIndex", (int) 0, nullptr);
- v->setProperty ("path", sanitisePath (binaryName), nullptr);
- v->setProperty ("sourceTree", "BUILT_PRODUCTS_DIR", nullptr);
- owner.pbxFileReferences.add (v);
- }
-
- //==============================================================================
- void addDependency()
- {
- jassert (dependencyID.isEmpty());
-
- dependencyID = owner.createID (String ("__dependency") + getName());
- auto* v = new ValueTree (dependencyID);
-
- v->setProperty ("isa", "PBXTargetDependency", nullptr);
- v->setProperty ("target", getID(), nullptr);
-
- owner.misc.add (v);
- }
-
- String getDependencyID() const
- {
- jassert (dependencyID.isNotEmpty());
-
- return dependencyID;
- }
-
- //==============================================================================
- void addTargetConfig (const String& configName, const StringArray& buildSettings)
- {
- auto configID = owner.createID (String ("targetconfigid_") + getName() + String ("_") + configName);
-
- auto* v = new ValueTree (configID);
- v->setProperty ("isa", "XCBuildConfiguration", nullptr);
- v->setProperty ("buildSettings", indentBracedList (buildSettings), nullptr);
- v->setProperty (Ids::name, configName, nullptr);
-
- configIDs.add (configID);
- owner.targetConfigs.add (v);
- }
-
- //==============================================================================
- String getTargetAttributes() const
- {
- auto attributes = getID() + " = { ";
-
- auto developmentTeamID = owner.getDevelopmentTeamIDString();
-
- if (developmentTeamID.isNotEmpty())
- {
- attributes << "DevelopmentTeam = " << developmentTeamID << "; ";
- attributes << "ProvisioningStyle = Automatic; ";
- }
-
- auto appGroupsEnabled = (owner.iOS && owner.isAppGroupsEnabled()) ? 1 : 0;
- auto inAppPurchasesEnabled = owner.isInAppPurchasesEnabled() ? 1 : 0;
- auto interAppAudioEnabled = (owner.iOS
- && type == Target::StandalonePlugIn
- && owner.getProject().shouldEnableIAA()) ? 1 : 0;
-
- auto pushNotificationsEnabled = owner.isPushNotificationsEnabled() ? 1 : 0;
- auto sandboxEnabled = ((type == Target::AudioUnitv3PlugIn) || owner.isAppSandboxEnabled()) ? 1 : 0;
- auto hardendedRuntimeEnabled = owner.isHardenedRuntimeEnabled() ? 1 : 0;
-
- attributes << "SystemCapabilities = {";
- attributes << "com.apple.ApplicationGroups.iOS = { enabled = " << appGroupsEnabled << "; }; ";
- attributes << "com.apple.InAppPurchase = { enabled = " << inAppPurchasesEnabled << "; }; ";
- attributes << "com.apple.InterAppAudio = { enabled = " << interAppAudioEnabled << "; }; ";
- attributes << "com.apple.Push = { enabled = " << pushNotificationsEnabled << "; }; ";
- attributes << "com.apple.Sandbox = { enabled = " << sandboxEnabled << "; }; ";
- attributes << "com.apple.HardenedRuntime = { enabled = " << hardendedRuntimeEnabled << "; }; ";
-
- if (owner.iOS && owner.isiCloudPermissionsEnabled())
- attributes << "com.apple.iCloud = { enabled = 1; }; ";
-
- attributes << "}; };";
-
- return attributes;
- }
-
- //==============================================================================
- ValueTree& addBuildPhase (const String& buildPhaseType, const StringArray& fileIds, const StringRef humanReadableName = StringRef())
- {
- auto buildPhaseName = buildPhaseType + "_" + getName() + "_" + (humanReadableName.isNotEmpty() ? String (humanReadableName) : String ("resbuildphase"));
- auto buildPhaseId (owner.createID (buildPhaseName));
-
- int n = 0;
- while (buildPhaseIDs.contains (buildPhaseId))
- buildPhaseId = owner.createID (buildPhaseName + String (++n));
-
- buildPhaseIDs.add (buildPhaseId);
-
- auto* v = new ValueTree (buildPhaseId);
- v->setProperty ("isa", buildPhaseType, nullptr);
- v->setProperty ("buildActionMask", "2147483647", nullptr);
- v->setProperty ("files", indentParenthesisedList (fileIds), nullptr);
- v->setProperty ("runOnlyForDeploymentPostprocessing", (int) 0, nullptr);
-
- if (humanReadableName.isNotEmpty())
- v->setProperty ("name", String (humanReadableName), nullptr);
-
- owner.misc.add (v);
- return *v;
- }
-
- bool shouldCreatePList() const
- {
- auto fileType = getTargetFileType();
- return (fileType == executable && type != ConsoleApp) || fileType == pluginBundle || fileType == macOSAppex;
- }
-
- //==============================================================================
- bool shouldAddEntitlements() const
- {
- if (owner.isPushNotificationsEnabled()
- || owner.isAppGroupsEnabled()
- || owner.isAppSandboxEnabled()
- || owner.isHardenedRuntimeEnabled()
- || (owner.isiOS() && owner.isiCloudPermissionsEnabled()))
- return true;
-
- if (owner.project.isAudioPluginProject()
- && ((owner.isOSX() && type == Target::AudioUnitv3PlugIn)
- || (owner.isiOS() && type == Target::StandalonePlugIn && owner.getProject().shouldEnableIAA())))
- return true;
-
- return false;
- }
-
- String getBundleIdentifier() const
- {
- auto exporterBundleIdentifier = owner.exporterBundleIdentifierValue.get().toString();
- auto bundleIdentifier = exporterBundleIdentifier.isNotEmpty() ? exporterBundleIdentifier
- : owner.project.getBundleIdentifierString();
-
- if (xcodeBundleIDSubPath.isNotEmpty())
- {
- auto bundleIdSegments = StringArray::fromTokens (bundleIdentifier, ".", StringRef());
-
- jassert (bundleIdSegments.size() > 0);
- bundleIdentifier += String (".") + bundleIdSegments[bundleIdSegments.size() - 1] + xcodeBundleIDSubPath;
- }
-
- return bundleIdentifier;
- }
-
- StringPairArray getConfigPreprocessorDefs (const XcodeBuildConfiguration& config) const
- {
- StringPairArray defines;
-
- if (config.isDebug())
- {
- defines.set ("_DEBUG", "1");
- defines.set ("DEBUG", "1");
- }
- else
- {
- defines.set ("_NDEBUG", "1");
- defines.set ("NDEBUG", "1");
- }
-
- if (owner.isInAppPurchasesEnabled())
- defines.set ("JUCE_IN_APP_PURCHASES", "1");
-
- if (owner.iOS && owner.isContentSharingEnabled())
- defines.set ("JUCE_CONTENT_SHARING", "1");
-
- if (owner.isPushNotificationsEnabled())
- defines.set ("JUCE_PUSH_NOTIFICATIONS", "1");
-
- return mergePreprocessorDefs (defines, owner.getAllPreprocessorDefs (config, type));
- }
-
- //==============================================================================
- StringPairArray getTargetSettings (const XcodeBuildConfiguration& config) const
- {
- StringPairArray s;
-
- if (type == AggregateTarget && ! owner.isiOS())
- {
- // the aggregate target needs to have the deployment target set for
- // pre-/post-build scripts
- s.set ("MACOSX_DEPLOYMENT_TARGET", getOSXDeploymentTarget (config.getOSXDeploymentTargetString()));
- s.set ("SDKROOT", getOSXSDKVersion (config.getOSXSDKVersionString()));
-
- return s;
- }
-
- s.set ("PRODUCT_NAME", owner.replacePreprocessorTokens (config, config.getTargetBinaryNameString (type == UnityPlugIn)).quoted());
- s.set ("PRODUCT_BUNDLE_IDENTIFIER", getBundleIdentifier());
-
- auto arch = (! owner.isiOS() && type == Target::AudioUnitv3PlugIn) ? osxArch_64Bit
- : config.getOSXArchitectureString();
-
- if (arch == osxArch_Native) s.set ("ARCHS", "\"$(NATIVE_ARCH_ACTUAL)\"");
- else if (arch == osxArch_32BitUniversal) s.set ("ARCHS", "\"$(ARCHS_STANDARD_32_BIT)\"");
- else if (arch == osxArch_64BitUniversal) s.set ("ARCHS", "\"$(ARCHS_STANDARD_32_64_BIT)\"");
- else if (arch == osxArch_64Bit) s.set ("ARCHS", "\"$(ARCHS_STANDARD_64_BIT)\"");
-
- StringArray headerPaths (getHeaderSearchPaths (config));
- headerPaths.add ("\"$(inherited)\"");
- s.set ("HEADER_SEARCH_PATHS", indentParenthesisedList (headerPaths, 1));
- s.set ("USE_HEADERMAP", String (static_cast<bool> (config.exporter.settings.getProperty ("useHeaderMap")) ? "YES" : "NO"));
-
- auto frameworkSearchPaths = getFrameworkSearchPaths (config);
-
- if (! frameworkSearchPaths.isEmpty())
- s.set ("FRAMEWORK_SEARCH_PATHS", String ("(") + frameworkSearchPaths.joinIntoString (", ") + ", \"$(inherited)\")");
-
- s.set ("GCC_OPTIMIZATION_LEVEL", config.getGCCOptimisationFlag());
-
- if (shouldCreatePList())
- {
- s.set ("INFOPLIST_FILE", infoPlistFile.getFileName());
-
- if (owner.getPListPrefixHeaderString().isNotEmpty())
- s.set ("INFOPLIST_PREFIX_HEADER", owner.getPListPrefixHeaderString());
-
- s.set ("INFOPLIST_PREPROCESS", (owner.isPListPreprocessEnabled() ? String ("YES") : String ("NO")));
-
- auto plistDefs = parsePreprocessorDefs (config.getPListPreprocessorDefinitionsString());
- StringArray defsList;
-
- for (int i = 0; i < plistDefs.size(); ++i)
- {
- auto def = plistDefs.getAllKeys()[i];
- auto value = plistDefs.getAllValues()[i];
-
- if (value.isNotEmpty())
- def << "=" << value.replace ("\"", "\\\\\\\"");
-
- defsList.add ("\"" + def + "\"");
- }
-
- if (defsList.size() > 0)
- s.set ("INFOPLIST_PREPROCESSOR_DEFINITIONS", indentParenthesisedList (defsList, 1));
- }
-
- if (config.isLinkTimeOptimisationEnabled())
- s.set ("LLVM_LTO", "YES");
-
- if (config.isFastMathEnabled())
- s.set ("GCC_FAST_MATH", "YES");
-
-
- auto flags = (config.getRecommendedCompilerWarningFlags().joinIntoString (" ")
- + " " + owner.getExtraCompilerFlagsString()).trim();
- flags = owner.replacePreprocessorTokens (config, flags);
-
- if (flags.isNotEmpty())
- s.set ("OTHER_CPLUSPLUSFLAGS", flags.quoted());
-
- auto installPath = getInstallPathForConfiguration (config);
-
- if (installPath.startsWith ("~"))
- installPath = installPath.replace ("~", "$(HOME)");
-
- if (installPath.isNotEmpty())
- {
- s.set ("INSTALL_PATH", installPath.quoted());
-
- if (type == Target::SharedCodeTarget)
- s.set ("SKIP_INSTALL", "YES");
-
- if (! owner.embeddedFrameworkIDs.isEmpty())
- s.set ("LD_RUNPATH_SEARCH_PATHS", "\"$(inherited) @executable_path/Frameworks @executable_path/../Frameworks\"");
-
- if (xcodeCopyToProductInstallPathAfterBuild)
- {
- s.set ("DEPLOYMENT_LOCATION", "YES");
- s.set ("DSTROOT", "/");
- }
- }
-
- if (getTargetFileType() == pluginBundle)
- {
- s.set ("LIBRARY_STYLE", "Bundle");
- s.set ("WRAPPER_EXTENSION", xcodeBundleExtension.substring (1));
- s.set ("GENERATE_PKGINFO_FILE", "YES");
- }
-
- if (xcodeOtherRezFlags.isNotEmpty())
- s.set ("OTHER_REZFLAGS", "\"" + xcodeOtherRezFlags + "\"");
-
- String configurationBuildDir ("$(PROJECT_DIR)/build/$(CONFIGURATION)");
-
- if (config.getTargetBinaryRelativePathString().isNotEmpty())
- {
- // a target's position can either be defined via installPath + xcodeCopyToProductInstallPathAfterBuild
- // (= for audio plug-ins) or using a custom binary path (for everything else), but not both (= conflict!)
- jassert (! xcodeCopyToProductInstallPathAfterBuild);
-
- build_tools::RelativePath binaryPath (config.getTargetBinaryRelativePathString(),
- build_tools::RelativePath::projectFolder);
- configurationBuildDir = sanitisePath (binaryPath.rebased (owner.projectFolder,
- owner.getTargetFolder(),
- build_tools::RelativePath::buildTargetFolder)
- .toUnixStyle());
- }
-
- s.set ("CONFIGURATION_BUILD_DIR", addQuotesIfRequired (configurationBuildDir));
-
- if (owner.isHardenedRuntimeEnabled())
- s.set ("ENABLE_HARDENED_RUNTIME", "YES");
-
- String gccVersion ("com.apple.compilers.llvm.clang.1_0");
-
- if (owner.iOS)
- {
- s.set ("ASSETCATALOG_COMPILER_APPICON_NAME", "AppIcon");
-
- if (! owner.shouldAddStoryboardToProject())
- s.set ("ASSETCATALOG_COMPILER_LAUNCHIMAGE_NAME", "LaunchImage");
- }
- else
- {
- s.set ("MACOSX_DEPLOYMENT_TARGET", getOSXDeploymentTarget (config.getOSXDeploymentTargetString()));
- }
-
- s.set ("GCC_VERSION", gccVersion);
- s.set ("CLANG_LINK_OBJC_RUNTIME", "NO");
-
- auto codeSigningIdentity = owner.getCodeSigningIdentity (config);
- s.set (owner.iOS ? "\"CODE_SIGN_IDENTITY[sdk=iphoneos*]\"" : "CODE_SIGN_IDENTITY",
- codeSigningIdentity.quoted());
-
- if (codeSigningIdentity.isNotEmpty())
- s.set ("PROVISIONING_PROFILE_SPECIFIER", "\"\"");
-
- if (owner.getDevelopmentTeamIDString().isNotEmpty())
- s.set ("DEVELOPMENT_TEAM", owner.getDevelopmentTeamIDString());
-
- if (shouldAddEntitlements())
- s.set ("CODE_SIGN_ENTITLEMENTS", getEntitlementsFilename().quoted());
-
- {
- auto cppStandard = owner.project.getCppStandardString();
-
- if (cppStandard == "latest")
- cppStandard = "17";
-
- s.set ("CLANG_CXX_LANGUAGE_STANDARD", (String (owner.shouldUseGNUExtensions() ? "gnu++"
- : "c++") + cppStandard).quoted());
- }
-
- s.set ("CLANG_CXX_LIBRARY", "\"libc++\"");
-
- s.set ("COMBINE_HIDPI_IMAGES", "YES");
-
- {
- StringArray linkerFlags, librarySearchPaths;
- getLinkerSettings (config, linkerFlags, librarySearchPaths);
-
- if (linkerFlags.size() > 0)
- s.set ("OTHER_LDFLAGS", linkerFlags.joinIntoString (" ").quoted());
-
- librarySearchPaths.addArray (config.getLibrarySearchPaths());
- librarySearchPaths = getCleanedStringArray (librarySearchPaths);
-
- if (librarySearchPaths.size() > 0)
- {
- StringArray libPaths;
- libPaths.add ("\"$(inherited)\"");
-
- for (auto& p : librarySearchPaths)
- libPaths.add ("\"\\\"" + p + "\\\"\"");
-
- s.set ("LIBRARY_SEARCH_PATHS", indentParenthesisedList (libPaths, 1));
- }
- }
-
- if (config.isDebug())
- {
- s.set ("COPY_PHASE_STRIP", "NO");
- s.set ("GCC_DYNAMIC_NO_PIC", "NO");
- }
- else
- {
- s.set ("GCC_GENERATE_DEBUGGING_SYMBOLS", "NO");
- s.set ("DEAD_CODE_STRIPPING", "YES");
- }
-
- if (type != Target::SharedCodeTarget && type != Target::StaticLibrary && type != Target::DynamicLibrary
- && config.isStripLocalSymbolsEnabled())
- {
- s.set ("STRIPFLAGS", "\"-x\"");
- s.set ("DEPLOYMENT_POSTPROCESSING", "YES");
- s.set ("SEPARATE_STRIP", "YES");
- }
-
- StringArray defsList;
-
- const auto defines = getConfigPreprocessorDefs (config);
-
- for (int i = 0; i < defines.size(); ++i)
- {
- auto def = defines.getAllKeys()[i];
- auto value = defines.getAllValues()[i];
- if (value.isNotEmpty())
- def << "=" << value.replace ("\"", "\\\\\\\"").replace (" ", "\\\\ ");
-
- defsList.add ("\"" + def + "\"");
- }
-
- s.set ("GCC_PREPROCESSOR_DEFINITIONS", indentParenthesisedList (defsList, 1));
-
- StringArray customFlags;
- customFlags.addTokens (config.getCustomXcodeFlagsString(), ",", "\"'");
- customFlags.removeEmptyStrings();
-
- for (auto flag : customFlags)
- {
- s.set (flag.upToFirstOccurrenceOf ("=", false, false).trim(),
- flag.fromFirstOccurrenceOf ("=", false, false).trim().quoted());
- }
-
- return s;
- }
-
- String getInstallPathForConfiguration (const XcodeBuildConfiguration& config) const
- {
- switch (type)
- {
- case GUIApp: return "$(HOME)/Applications";
- case ConsoleApp: return "/usr/bin";
- case VSTPlugIn: return config.isPluginBinaryCopyStepEnabled() ? config.getVSTBinaryLocationString() : String();
- case VST3PlugIn: return config.isPluginBinaryCopyStepEnabled() ? config.getVST3BinaryLocationString() : String();
- case AudioUnitPlugIn: return config.isPluginBinaryCopyStepEnabled() ? config.getAUBinaryLocationString() : String();
- case RTASPlugIn: return config.isPluginBinaryCopyStepEnabled() ? config.getRTASBinaryLocationString() : String();
- case AAXPlugIn: return config.isPluginBinaryCopyStepEnabled() ? config.getAAXBinaryLocationString() : String();
- case UnityPlugIn: return config.isPluginBinaryCopyStepEnabled() ? config.getUnityPluginBinaryLocationString() : String();
- case SharedCodeTarget: return owner.isiOS() ? "@executable_path/Frameworks" : "@executable_path/../Frameworks";
- case StaticLibrary:
- case DynamicLibrary:
- case AudioUnitv3PlugIn:
- case StandalonePlugIn:
- case AggregateTarget:
- case unspecified:
- default: return {};
- }
- }
-
- //==============================================================================
- void getLinkerSettings (const BuildConfiguration& config, StringArray& flags, StringArray& librarySearchPaths) const
- {
- if (getTargetFileType() == pluginBundle)
- flags.add (owner.isiOS() ? "-bitcode_bundle" : "-bundle");
-
- if (type != Target::SharedCodeTarget)
- {
- Array<build_tools::RelativePath> extraLibs;
-
- addExtraLibsForTargetType (config, extraLibs);
-
- for (auto& lib : extraLibs)
- {
- flags.add (getLinkerFlagForLib (lib.getFileNameWithoutExtension()));
- librarySearchPaths.add (owner.getSearchPathForStaticLibrary (lib));
- }
-
- if (owner.project.isAudioPluginProject())
- {
- if (owner.getTargetOfType (Target::SharedCodeTarget) != nullptr)
- {
- auto productName = getStaticLibbedFilename (owner.replacePreprocessorTokens (config, config.getTargetBinaryNameString()));
-
- build_tools::RelativePath sharedCodelib (productName, build_tools::RelativePath::buildTargetFolder);
- flags.add (getLinkerFlagForLib (sharedCodelib.getFileNameWithoutExtension()));
- }
- }
-
- flags.add (owner.getExternalLibraryFlags (config));
-
- auto libs = owner.xcodeLibs;
- libs.addArray (xcodeLibs);
-
- for (auto& l : libs)
- flags.add (getLinkerFlagForLib (l));
- }
-
- flags.add (owner.replacePreprocessorTokens (config, owner.getExtraLinkerFlagsString()));
- flags = getCleanedStringArray (flags);
- }
-
- //==========================================================================
- void writeInfoPlistFile() const
- {
- if (! shouldCreatePList())
- return;
-
- build_tools::PlistOptions options;
-
- options.type = type;
- options.executableName = "${EXECUTABLE_NAME}";
- options.bundleIdentifier = getBundleIdentifier();
- options.plistToMerge = owner.getPListToMergeString();
- options.iOS = owner.iOS;
- options.microphonePermissionEnabled = owner.isMicrophonePermissionEnabled();
- options.microphonePermissionText = owner.getMicrophonePermissionsTextString();
- options.cameraPermissionEnabled = owner.isCameraPermissionEnabled();
- options.cameraPermissionText = owner.getCameraPermissionTextString();
- options.bluetoothPermissionEnabled = owner.isBluetoothPermissionEnabled();
- options.bluetoothPermissionText = owner.getBluetoothPermissionTextString();
- options.sendAppleEventsPermissionEnabled = owner.isSendAppleEventsPermissionEnabled();
- options.sendAppleEventsPermissionText = owner.getSendAppleEventsPermissionTextString();
- options.shouldAddStoryboardToProject = owner.shouldAddStoryboardToProject();
- options.iconFile = owner.iconFile;
- options.projectName = owner.projectName;
- options.version = owner.project.getVersionString();
- options.companyCopyright = owner.project.getCompanyCopyrightString();
- options.allPreprocessorDefs = owner.getAllPreprocessorDefs();
- options.documentExtensions = owner.getDocumentExtensionsString();
- options.fileSharingEnabled = owner.isFileSharingEnabled();
- options.documentBrowserEnabled = owner.isDocumentBrowserEnabled();
- options.statusBarHidden = owner.isStatusBarHidden();
- options.backgroundAudioEnabled = owner.isBackgroundAudioEnabled();
- options.backgroundBleEnabled = owner.isBackgroundBleEnabled();
- options.pushNotificationsEnabled = owner.isPushNotificationsEnabled();
- options.enableIAA = owner.project.shouldEnableIAA();
- options.IAAPluginName = owner.project.getIAAPluginName();
- options.pluginManufacturerCode = owner.project.getPluginManufacturerCodeString();
- options.IAATypeCode = owner.project.getIAATypeCode();
- options.pluginCode = owner.project.getPluginCodeString();
- options.versionAsHex = owner.project.getVersionAsHexInteger();
- options.iPhoneScreenOrientations = owner.getiPhoneScreenOrientations();
- options.iPadScreenOrientations = owner.getiPadScreenOrientations();
-
- options.storyboardName = [&]
- {
- const auto customLaunchStoryboard = owner.getCustomLaunchStoryboardString();
-
- if (customLaunchStoryboard.isEmpty())
- return owner.getDefaultLaunchStoryboardName();
-
- return customLaunchStoryboard.fromLastOccurrenceOf ("/", false, false)
- .upToLastOccurrenceOf (".storyboard", false, false);
- }();
-
- options.pluginName = owner.project.getPluginNameString();
- options.pluginManufacturer = owner.project.getPluginManufacturerString();
- options.pluginDescription = owner.project.getPluginDescriptionString();
- options.pluginAUExportPrefix = owner.project.getPluginAUExportPrefixString();
- options.auMainType = owner.project.getAUMainTypeString();
- options.isAuSandboxSafe = owner.project.isAUSandBoxSafe();
- options.isPluginSynth = owner.project.isPluginSynth();
-
- options.write (infoPlistFile);
- }
-
- //==============================================================================
- void addShellScriptBuildPhase (const String& phaseName, const String& script)
- {
- if (script.trim().isNotEmpty())
- {
- auto& v = addBuildPhase ("PBXShellScriptBuildPhase", {});
- v.setProperty (Ids::name, phaseName, nullptr);
- v.setProperty ("shellPath", "/bin/sh", nullptr);
- v.setProperty ("shellScript", script.replace ("\\", "\\\\")
- .replace ("\"", "\\\"")
- .replace ("\r\n", "\\n")
- .replace ("\n", "\\n"), nullptr);
- }
- }
-
- void addCopyFilesPhase (const String& phaseName, const StringArray& files, XcodeCopyFilesDestinationIDs dst)
- {
- auto& v = addBuildPhase ("PBXCopyFilesBuildPhase", files, phaseName);
- v.setProperty ("dstPath", "", nullptr);
- v.setProperty ("dstSubfolderSpec", (int) dst, nullptr);
- }
-
- //==============================================================================
- void sanitiseAndEscapeSearchPaths (const BuildConfiguration& config, StringArray& paths) const
- {
- paths = getCleanedStringArray (paths);
-
- for (auto& path : paths)
- {
- // Xcode 10 can't deal with search paths starting with "~" so we need to replace them here...
- path = owner.replacePreprocessorTokens (config, sanitisePath (path));
-
- if (path.containsChar (' '))
- path = "\"\\\"" + path + "\\\"\""; // crazy double quotes required when there are spaces..
- else
- path = "\"" + path + "\"";
- }
- }
-
- StringArray getHeaderSearchPaths (const BuildConfiguration& config) const
- {
- StringArray paths (owner.extraSearchPaths);
- paths.addArray (config.getHeaderSearchPaths());
- paths.addArray (getTargetExtraHeaderSearchPaths());
-
- if (owner.project.getEnabledModules().isModuleEnabled ("juce_audio_plugin_client"))
- {
- // Needed to compile .r files
- paths.add (owner.getModuleFolderRelativeToProject ("juce_audio_plugin_client")
- .rebased (owner.projectFolder, owner.getTargetFolder(), build_tools::RelativePath::buildTargetFolder)
- .toUnixStyle());
- }
-
- sanitiseAndEscapeSearchPaths (config, paths);
- return paths;
- }
-
- StringArray getFrameworkSearchPaths (const BuildConfiguration& config) const
- {
- auto paths = getSearchPathsFromString (owner.getFrameworkSearchPathsString());
- sanitiseAndEscapeSearchPaths (config, paths);
- return paths;
- }
-
- private:
- //==============================================================================
- void addExtraAudioUnitTargetSettings()
- {
- xcodeOtherRezFlags = "-d ppc_$ppc -d i386_$i386 -d ppc64_$ppc64 -d x86_64_$x86_64"
- " -I /System/Library/Frameworks/CoreServices.framework/Frameworks/CarbonCore.framework/Versions/A/Headers"
- " -I \\\"$(DEVELOPER_DIR)/Extras/CoreAudio/AudioUnits/AUPublic/AUBase\\\""
- " -I \\\"$(DEVELOPER_DIR)/Platforms/MacOSX.platform/Developer/SDKs/MacOSX.sdk/System/Library/Frameworks/AudioUnit.framework/Headers\\\"";
-
- xcodeFrameworks.addArray ({ "AudioUnit", "CoreAudioKit" });
- }
-
- void addExtraAudioUnitv3PlugInTargetSettings()
- {
- xcodeFrameworks.addArray ({ "AVFoundation", "CoreAudioKit" });
-
- if (owner.isOSX())
- xcodeFrameworks.add ("AudioUnit");
- }
-
- void addExtraLibsForTargetType (const BuildConfiguration& config, Array<build_tools::RelativePath>& extraLibs) const
- {
- if (type == AAXPlugIn)
- {
- auto aaxLibsFolder = build_tools::RelativePath (owner.getAAXPathString(), build_tools::RelativePath::projectFolder).getChildFile ("Libs");
-
- String libraryPath (config.isDebug() ? "Debug" : "Release");
- libraryPath += "/libAAXLibrary_libcpp.a";
-
- extraLibs.add (aaxLibsFolder.getChildFile (libraryPath));
- }
- else if (type == RTASPlugIn)
- {
- build_tools::RelativePath rtasFolder (owner.getRTASPathString(), build_tools::RelativePath::projectFolder);
-
- extraLibs.add (rtasFolder.getChildFile ("MacBag/Libs/Debug/libPluginLibrary.a"));
- extraLibs.add (rtasFolder.getChildFile ("MacBag/Libs/Release/libPluginLibrary.a"));
- }
- }
-
- StringArray getTargetExtraHeaderSearchPaths() const
- {
- StringArray targetExtraSearchPaths;
-
- if (type == RTASPlugIn)
- {
- build_tools::RelativePath rtasFolder (owner.getRTASPathString(), build_tools::RelativePath::projectFolder);
-
- targetExtraSearchPaths.add ("$(DEVELOPER_DIR)/Headers/FlatCarbon");
- targetExtraSearchPaths.add ("$(SDKROOT)/Developer/Headers/FlatCarbon");
-
- static const char* p[] = { "AlturaPorts/TDMPlugIns/PlugInLibrary/Controls",
- "AlturaPorts/TDMPlugIns/PlugInLibrary/CoreClasses",
- "AlturaPorts/TDMPlugIns/PlugInLibrary/DSPClasses",
- "AlturaPorts/TDMPlugIns/PlugInLibrary/EffectClasses",
- "AlturaPorts/TDMPlugIns/PlugInLibrary/MacBuild",
- "AlturaPorts/TDMPlugIns/PlugInLibrary/Meters",
- "AlturaPorts/TDMPlugIns/PlugInLibrary/ProcessClasses",
- "AlturaPorts/TDMPlugIns/PlugInLibrary/ProcessClasses/Interfaces",
- "AlturaPorts/TDMPlugIns/PlugInLibrary/RTASP_Adapt",
- "AlturaPorts/TDMPlugIns/PlugInLibrary/Utilities",
- "AlturaPorts/TDMPlugIns/PlugInLibrary/ViewClasses",
- "AlturaPorts/TDMPlugIns/DSPManager/**",
- "AlturaPorts/TDMPlugIns/SupplementalPlugInLib/Encryption",
- "AlturaPorts/TDMPlugIns/SupplementalPlugInLib/GraphicsExtensions",
- "AlturaPorts/TDMPlugIns/common/**",
- "AlturaPorts/TDMPlugIns/common/PI_LibInterface",
- "AlturaPorts/TDMPlugIns/PACEProtection/**",
- "AlturaPorts/TDMPlugIns/SignalProcessing/**",
- "AlturaPorts/OMS/Headers",
- "AlturaPorts/Fic/Interfaces/**",
- "AlturaPorts/Fic/Source/SignalNets",
- "AlturaPorts/DSIPublicInterface/PublicHeaders",
- "DAEWin/Include",
- "AlturaPorts/DigiPublic/Interfaces",
- "AlturaPorts/DigiPublic",
- "AlturaPorts/NewFileLibs/DOA",
- "AlturaPorts/NewFileLibs/Cmn",
- "xplat/AVX/avx2/avx2sdk/inc",
- "xplat/AVX/avx2/avx2sdk/utils" };
-
- for (auto* path : p)
- owner.addProjectPathToBuildPathList (targetExtraSearchPaths, rtasFolder.getChildFile (path));
- }
-
- return targetExtraSearchPaths;
- }
-
- String getOSXDeploymentTarget (const String& deploymentTarget) const
- {
- auto minVersion = (type == Target::AudioUnitv3PlugIn ? minimumAUv3SDKVersion : oldestDeploymentTarget);
-
- for (int v = minVersion; v <= currentSDKVersion; ++v)
- if (deploymentTarget == getSDKDisplayName (v))
- return getVersionName (v);
-
- return getVersionName (minVersion);
- }
-
- //==============================================================================
- const XcodeProjectExporter& owner;
-
- Target& operator= (const Target&) = delete;
- };
-
- mutable StringArray xcodeFrameworks;
- StringArray xcodeLibs;
-
- private:
- //==============================================================================
- friend class CLionProjectExporter;
-
- bool xcodeCanUseDwarf;
- OwnedArray<XcodeTarget> targets;
-
- mutable OwnedArray<ValueTree> pbxBuildFiles, pbxFileReferences, pbxGroups, misc, projectConfigs, targetConfigs;
- mutable StringArray resourceIDs, sourceIDs, targetIDs;
- mutable StringArray frameworkFileIDs, embeddedFrameworkIDs, rezFileIDs, resourceFileRefs, subprojectFileIDs;
- mutable Array<std::pair<String, String>> subprojectReferences;
- mutable File menuNibFile, iconFile;
- mutable StringArray buildProducts;
-
- const bool iOS;
-
- ValueWithDefault customPListValue, pListPrefixHeaderValue, pListPreprocessValue,
- subprojectsValue,
- extraFrameworksValue, frameworkSearchPathsValue, extraCustomFrameworksValue, embeddedFrameworksValue,
- postbuildCommandValue, prebuildCommandValue,
- duplicateAppExResourcesFolderValue, iosDeviceFamilyValue, iPhoneScreenOrientationValue,
- iPadScreenOrientationValue, customXcodeResourceFoldersValue, customXcassetsFolderValue,
- appSandboxValue, appSandboxInheritanceValue, appSandboxOptionsValue,
- hardenedRuntimeValue, hardenedRuntimeOptionsValue,
- microphonePermissionNeededValue, microphonePermissionsTextValue,
- cameraPermissionNeededValue, cameraPermissionTextValue,
- iosBluetoothPermissionNeededValue, iosBluetoothPermissionTextValue,
- sendAppleEventsPermissionNeededValue, sendAppleEventsPermissionTextValue,
- uiFileSharingEnabledValue, uiSupportsDocumentBrowserValue, uiStatusBarHiddenValue, documentExtensionsValue, iosInAppPurchasesValue,
- iosContentSharingValue, iosBackgroundAudioValue, iosBackgroundBleValue, iosPushNotificationsValue, iosAppGroupsValue, iCloudPermissionsValue,
- iosDevelopmentTeamIDValue, iosAppGroupsIDValue, keepCustomXcodeSchemesValue, useHeaderMapValue, customLaunchStoryboardValue,
- exporterBundleIdentifierValue;
-
- static String sanitisePath (const String& path)
- {
- if (path.startsWithChar ('~'))
- return "$(HOME)" + path.substring (1);
-
- return path;
- }
-
- static String addQuotesIfRequired (const String& s)
- {
- return s.containsAnyOf (" $") ? s.quoted() : s;
- }
-
- File getProjectBundle() const { return getTargetFolder().getChildFile (project.getProjectFilenameRootString()).withFileExtension (".xcodeproj"); }
-
- //==============================================================================
- void createObjects() const
- {
- prepareTargets();
-
- // Must be called before adding embedded frameworks, as we want to
- // embed any frameworks found in subprojects.
- addSubprojects();
-
- addFrameworks();
- addCustomFrameworks();
- addEmbeddedFrameworks();
-
- addCustomResourceFolders();
- addPlistFileReferences();
-
- if (iOS && ! projectType.isStaticLibrary())
- {
- addXcassets();
-
- if (shouldAddStoryboardToProject())
- {
- auto customLaunchStoryboard = getCustomLaunchStoryboardString();
-
- if (customLaunchStoryboard.isEmpty())
- writeDefaultLaunchStoryboardFile();
- else if (getProject().getProjectFolder().getChildFile (customLaunchStoryboard).existsAsFile())
- addLaunchStoryboardFileReference (build_tools::RelativePath (customLaunchStoryboard, build_tools::RelativePath::projectFolder)
- .rebased (getProject().getProjectFolder(), getTargetFolder(), build_tools::RelativePath::buildTargetFolder)
- .toUnixStyle());
- }
- }
- else
- {
- addNibFiles();
- }
-
- addIcons();
- addBuildConfigurations();
-
- addProjectConfigList (projectConfigs, createID ("__projList"));
-
- {
- StringArray topLevelGroupIDs;
-
- addFilesAndGroupsToProject (topLevelGroupIDs);
- addBuildPhases();
- addExtraGroupsToProject (topLevelGroupIDs);
-
- addGroup (createID ("__mainsourcegroup"), "Source", topLevelGroupIDs);
- }
-
- addProjectObject();
- removeMismatchedXcuserdata();
- }
-
- void prepareTargets() const
- {
- for (auto* target : targets)
- {
- if (target->type == XcodeTarget::AggregateTarget)
- continue;
-
- target->addMainBuildProduct();
-
- auto targetName = target->getName();
- auto fileID = createID (targetName + String ("__targetbuildref"));
- auto fileRefID = createID (String ("__productFileID") + targetName);
-
- auto* v = new ValueTree (fileID);
- v->setProperty ("isa", "PBXBuildFile", nullptr);
- v->setProperty ("fileRef", fileRefID, nullptr);
-
- target->mainBuildProductID = fileID;
-
- pbxBuildFiles.add (v);
- target->addDependency();
- }
- }
-
- void addPlistFileReferences() const
- {
- for (auto* target : targets)
- {
- if (target->type == XcodeTarget::AggregateTarget)
- continue;
-
- if (target->shouldCreatePList())
- {
- build_tools::RelativePath plistPath (target->infoPlistFile, getTargetFolder(), build_tools::RelativePath::buildTargetFolder);
- addFileReference (plistPath.toUnixStyle());
- resourceFileRefs.add (createFileRefID (plistPath));
- }
- }
- }
-
- void addNibFiles() const
- {
- build_tools::writeStreamToFile (menuNibFile, [&] (MemoryOutputStream& mo)
- {
- mo.write (BinaryData::RecentFilesMenuTemplate_nib, BinaryData::RecentFilesMenuTemplate_nibSize);
- });
-
- build_tools::RelativePath menuNibPath (menuNibFile, getTargetFolder(), build_tools::RelativePath::buildTargetFolder);
- addFileReference (menuNibPath.toUnixStyle());
- resourceIDs.add (addBuildFile (menuNibPath, false, false));
- resourceFileRefs.add (createFileRefID (menuNibPath));
- }
-
- void addIcons() const
- {
- if (iconFile.exists())
- {
- build_tools::RelativePath iconPath (iconFile, getTargetFolder(), build_tools::RelativePath::buildTargetFolder);
- addFileReference (iconPath.toUnixStyle());
- resourceIDs.add (addBuildFile (iconPath, false, false));
- resourceFileRefs.add (createFileRefID (iconPath));
- }
- }
-
- void addBuildConfigurations() const
- {
- for (ConstConfigIterator config (*this); config.next();)
- {
- auto& xcodeConfig = dynamic_cast<const XcodeBuildConfiguration&> (*config);
- StringArray settingsLines;
- auto configSettings = getProjectSettings (xcodeConfig);
-
- for (auto& key : configSettings.getAllKeys())
- settingsLines.add (key + " = " + configSettings[key]);
-
- addProjectConfig (config->getName(), settingsLines);
- }
- }
-
- void addFilesAndGroupsToProject (StringArray& topLevelGroupIDs) const
- {
- for (auto* target : targets)
- if (target->shouldAddEntitlements())
- addEntitlementsFile (*target);
-
- for (auto& group : getAllGroups())
- {
- if (group.getNumChildren() > 0)
- {
- auto groupID = addProjectItem (group);
-
- if (groupID.isNotEmpty())
- topLevelGroupIDs.add (groupID);
- }
- }
- }
-
- void addExtraGroupsToProject (StringArray& topLevelGroupIDs) const
- {
- {
- auto resourcesGroupID = createID ("__resources");
- addGroup (resourcesGroupID, "Resources", resourceFileRefs);
- topLevelGroupIDs.add (resourcesGroupID);
- }
-
- {
- auto frameworksGroupID = createID ("__frameworks");
- addGroup (frameworksGroupID, "Frameworks", frameworkFileIDs);
- topLevelGroupIDs.add (frameworksGroupID);
- }
-
- {
- auto productsGroupID = createID ("__products");
- addGroup (productsGroupID, "Products", buildProducts);
- topLevelGroupIDs.add (productsGroupID);
- }
-
- if (! subprojectFileIDs.isEmpty())
- {
- auto subprojectLibrariesGroupID = createID ("__subprojects");
- addGroup (subprojectLibrariesGroupID, "Subprojects", subprojectFileIDs);
- topLevelGroupIDs.add (subprojectLibrariesGroupID);
- }
- }
-
- void addBuildPhases() const
- {
- // add build phases
- for (auto* target : targets)
- {
- if (target->type != XcodeTarget::AggregateTarget)
- buildProducts.add (createID (String ("__productFileID") + String (target->getName())));
-
- for (ConstConfigIterator config (*this); config.next();)
- {
- auto& xcodeConfig = dynamic_cast<const XcodeBuildConfiguration&> (*config);
-
- auto configSettings = target->getTargetSettings (xcodeConfig);
- StringArray settingsLines;
-
- for (auto& key : configSettings.getAllKeys())
- settingsLines.add (key + " = " + configSettings.getValue (key, "\"\""));
-
- target->addTargetConfig (config->getName(), settingsLines);
- }
-
- addConfigList (*target, targetConfigs, createID (String ("__configList") + target->getName()));
-
- target->addShellScriptBuildPhase ("Pre-build script", getPreBuildScript());
-
- if (target->type != XcodeTarget::AggregateTarget)
- {
- auto skipAUv3 = (target->type == XcodeTarget::AudioUnitv3PlugIn && ! shouldDuplicateAppExResourcesFolder());
-
- if (! projectType.isStaticLibrary() && target->type != XcodeTarget::SharedCodeTarget && ! skipAUv3)
- target->addBuildPhase ("PBXResourcesBuildPhase", resourceIDs);
-
- auto rezFiles = rezFileIDs;
- rezFiles.addArray (target->rezFileIDs);
-
- if (rezFiles.size() > 0)
- target->addBuildPhase ("PBXRezBuildPhase", rezFiles);
-
- auto sourceFiles = target->sourceIDs;
-
- if (target->type == XcodeTarget::SharedCodeTarget
- || (! project.isAudioPluginProject()))
- sourceFiles.addArray (sourceIDs);
-
- target->addBuildPhase ("PBXSourcesBuildPhase", sourceFiles);
-
- if (! projectType.isStaticLibrary() && target->type != XcodeTarget::SharedCodeTarget)
- target->addBuildPhase ("PBXFrameworksBuildPhase", target->frameworkIDs);
- }
-
- target->addShellScriptBuildPhase ("Post-build script", getPostBuildScript());
-
- if (project.isAudioPluginProject() && project.shouldBuildAUv3()
- && project.shouldBuildStandalonePlugin() && target->type == XcodeTarget::StandalonePlugIn)
- embedAppExtension();
-
- if (project.isAudioPluginProject() && project.shouldBuildUnityPlugin()
- && target->type == XcodeTarget::UnityPlugIn)
- embedUnityScript();
-
- addTargetObject (*target);
- }
- }
-
- void embedAppExtension() const
- {
- if (auto* standaloneTarget = getTargetOfType (XcodeTarget::StandalonePlugIn))
- {
- if (auto* auv3Target = getTargetOfType (XcodeTarget::AudioUnitv3PlugIn))
- {
- StringArray files;
- files.add (auv3Target->mainBuildProductID);
- standaloneTarget->addCopyFilesPhase ("Embed App Extensions", files, kPluginsFolder);
- }
- }
- }
-
- void embedUnityScript() const
- {
- if (auto* unityTarget = getTargetOfType (XcodeTarget::UnityPlugIn))
- {
- build_tools::RelativePath scriptPath (getProject().getGeneratedCodeFolder().getChildFile (getProject().getUnityScriptName()),
- getTargetFolder(),
- build_tools::RelativePath::buildTargetFolder);
-
- auto path = scriptPath.toUnixStyle();
- auto refID = addFileReference (path);
- auto fileID = addBuildFile (path, refID, false, false);
-
- resourceIDs.add (fileID);
- resourceFileRefs.add (refID);
-
- unityTarget->addCopyFilesPhase ("Embed Unity Script", fileID, kResourcesFolder);
- }
- }
-
- //==============================================================================
- XcodeTarget* getTargetOfType (build_tools::ProjectType::Target::Type type) const
- {
- for (auto& target : targets)
- if (target->type == type)
- return target;
-
- return nullptr;
- }
-
- void addTargetObject (XcodeTarget& target) const
- {
- auto targetName = target.getName();
-
- auto targetID = target.getID();
- auto* v = new ValueTree (targetID);
- 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);
- v->setProperty ("buildRules", "( )", nullptr);
-
- v->setProperty ("dependencies", indentParenthesisedList (getTargetDependencies (target)), nullptr);
- v->setProperty (Ids::name, target.getXcodeSchemeName(), nullptr);
-
- v->setProperty ("productName", projectName, nullptr);
-
- if (target.type != XcodeTarget::AggregateTarget)
- {
- v->setProperty ("productReference", createID (String ("__productFileID") + targetName), nullptr);
-
- jassert (target.xcodeProductType.isNotEmpty());
- v->setProperty ("productType", target.xcodeProductType, nullptr);
- }
-
- targetIDs.add (targetID);
- misc.add (v);
- }
-
- StringArray getTargetDependencies (const XcodeTarget& target) const
- {
- StringArray dependencies;
-
- if (project.isAudioPluginProject())
- {
- if (target.type == XcodeTarget::StandalonePlugIn) // depends on AUv3 and shared code
- {
- if (auto* auv3Target = getTargetOfType (XcodeTarget::AudioUnitv3PlugIn))
- dependencies.add (auv3Target->getDependencyID());
-
- if (auto* sharedCodeTarget = getTargetOfType (XcodeTarget::SharedCodeTarget))
- dependencies.add (sharedCodeTarget->getDependencyID());
- }
- 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 != XcodeTarget::SharedCodeTarget) // shared code doesn't depend on anything; all other targets depend only on the shared code
- {
- if (auto* sharedCodeTarget = getTargetOfType (XcodeTarget::SharedCodeTarget))
- dependencies.add (sharedCodeTarget->getDependencyID());
- }
- }
-
- return dependencies;
- }
-
- void createIconFile() const
- {
- const auto icons = getIcons();
-
- if (! build_tools::asArray (icons).isEmpty())
- {
- iconFile = getTargetFolder().getChildFile ("Icon.icns");
- build_tools::writeMacIcon (icons, iconFile);
- }
- }
-
- void writeWorkspaceSettings() const
- {
- const auto settingsFile = getProjectBundle().getChildFile ("project.xcworkspace")
- .getChildFile ("xcshareddata")
- .getChildFile ("WorkspaceSettings.xcsettings");
-
- build_tools::writeStreamToFile (settingsFile, [] (MemoryOutputStream& mo)
- {
- mo.setNewLineString ("\n");
-
- mo << "<?xml version=\"1.0\" encoding=\"UTF-8\"?>" << newLine
- << "<!DOCTYPE plist PUBLIC \"-//Apple//DTD PLIST 1.0//EN\" \"http://www.apple.com/DTDs/PropertyList-1.0.dtd\">" << newLine
- << "<plist version=\"1.0\">" << newLine
- << "<dict>" << newLine
- << "\t" << "<key>BuildSystemType</key>" << newLine
- << "\t" << "<string>Original</string>" << newLine
- << "</dict>" << newLine
- << "</plist>" << newLine;
- });
- }
-
- void writeInfoPlistFiles() const
- {
- for (auto& target : targets)
- target->writeInfoPlistFile();
- }
-
- // Delete .rsrc files in folder but don't follow sym-links
- void deleteRsrcFiles (const File& folder) const
- {
- for (const auto& di : RangedDirectoryIterator (folder, false, "*", File::findFilesAndDirectories))
- {
- const auto& entry = di.getFile();
-
- if (! entry.isSymbolicLink())
- {
- if (entry.existsAsFile() && entry.getFileExtension().toLowerCase() == ".rsrc")
- entry.deleteFile();
- else if (entry.isDirectory())
- deleteRsrcFiles (entry);
- }
- }
- }
-
- static String getLinkerFlagForLib (String library)
- {
- if (library.substring (0, 3) == "lib")
- library = library.substring (3);
-
- return "-l" + library.replace (" ", "\\\\ ").replace ("\"", "\\\\\"").replace ("\'", "\\\\\'").upToLastOccurrenceOf (".", false, false);
- }
-
- String getSearchPathForStaticLibrary (const build_tools::RelativePath& library) const
- {
- auto searchPath = library.toUnixStyle().upToLastOccurrenceOf ("/", false, false);
-
- if (! library.isAbsolute())
- {
- auto srcRoot = rebaseFromProjectFolderToBuildTarget (build_tools::RelativePath (".", build_tools::RelativePath::projectFolder)).toUnixStyle();
-
- if (srcRoot.endsWith ("/.")) srcRoot = srcRoot.dropLastCharacters (2);
- if (! srcRoot.endsWithChar ('/')) srcRoot << '/';
-
- searchPath = srcRoot + searchPath;
- }
-
- return sanitisePath (searchPath);
- }
-
- String getCodeSigningIdentity (const XcodeBuildConfiguration& config) const
- {
- auto identity = config.getCodeSignIdentityString();
-
- if (identity.isEmpty() && getDevelopmentTeamIDString().isNotEmpty())
- return iOS ? "iPhone Developer" : "Mac Developer";
-
- return identity;
- }
-
- StringPairArray getProjectSettings (const XcodeBuildConfiguration& config) const
- {
- StringPairArray s;
-
- s.set ("ALWAYS_SEARCH_USER_PATHS", "NO");
- s.set ("ENABLE_STRICT_OBJC_MSGSEND", "YES");
- s.set ("GCC_C_LANGUAGE_STANDARD", "c11");
- s.set ("GCC_NO_COMMON_BLOCKS", "YES");
- s.set ("GCC_MODEL_TUNING", "G5");
- s.set ("GCC_WARN_ABOUT_RETURN_TYPE", "YES");
- s.set ("GCC_WARN_CHECK_SWITCH_STATEMENTS", "YES");
- s.set ("GCC_WARN_UNUSED_VARIABLE", "YES");
- s.set ("GCC_WARN_MISSING_PARENTHESES", "YES");
- s.set ("GCC_WARN_NON_VIRTUAL_DESTRUCTOR", "YES");
- s.set ("GCC_WARN_TYPECHECK_CALLS_TO_PRINTF", "YES");
- s.set ("GCC_WARN_64_TO_32_BIT_CONVERSION", "YES");
- s.set ("GCC_WARN_UNDECLARED_SELECTOR", "YES");
- s.set ("GCC_WARN_UNINITIALIZED_AUTOS", "YES");
- s.set ("GCC_WARN_UNUSED_FUNCTION", "YES");
- s.set ("CLANG_ENABLE_OBJC_WEAK", "YES");
- s.set ("CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING", "YES");
- s.set ("CLANG_WARN_BOOL_CONVERSION", "YES");
- s.set ("CLANG_WARN_COMMA", "YES");
- s.set ("CLANG_WARN_CONSTANT_CONVERSION", "YES");
- s.set ("CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS", "YES");
- s.set ("CLANG_WARN_EMPTY_BODY", "YES");
- s.set ("CLANG_WARN_ENUM_CONVERSION", "YES");
- s.set ("CLANG_WARN_INFINITE_RECURSION", "YES");
- s.set ("CLANG_WARN_INT_CONVERSION", "YES");
- s.set ("CLANG_WARN_NON_LITERAL_NULL_CONVERSION", "YES");
- s.set ("CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF", "YES");
- s.set ("CLANG_WARN_OBJC_LITERAL_CONVERSION", "YES");
- s.set ("CLANG_WARN_RANGE_LOOP_ANALYSIS", "YES");
- s.set ("CLANG_WARN_STRICT_PROTOTYPES", "YES");
- s.set ("CLANG_WARN_SUSPICIOUS_MOVE", "YES");
- s.set ("CLANG_WARN_UNREACHABLE_CODE", "YES");
- s.set ("CLANG_WARN__DUPLICATE_METHOD_MATCH", "YES");
- s.set ("WARNING_CFLAGS", "\"-Wreorder\"");
- s.set ("GCC_INLINES_ARE_PRIVATE_EXTERN", projectType.isStaticLibrary() ? "NO" : "YES");
-
- // GCC_SYMBOLS_PRIVATE_EXTERN only takes effect if ENABLE_TESTABILITY is off
- s.set ("ENABLE_TESTABILITY", "NO");
- s.set ("GCC_SYMBOLS_PRIVATE_EXTERN", "YES");
-
- if (config.isDebug())
- {
- if (config.getOSXArchitectureString() == osxArch_Default)
- s.set ("ONLY_ACTIVE_ARCH", "YES");
- }
-
- s.set (iOS ? "\"CODE_SIGN_IDENTITY[sdk=iphoneos*]\"" : "CODE_SIGN_IDENTITY",
- getCodeSigningIdentity (config).quoted());
-
- if (iOS)
- {
- s.set ("SDKROOT", "iphoneos");
- s.set ("TARGETED_DEVICE_FAMILY", getDeviceFamilyString().quoted());
- s.set ("IPHONEOS_DEPLOYMENT_TARGET", config.getiOSDeploymentTargetString());
- }
- else
- {
- s.set ("SDKROOT", getOSXSDKVersion (config.getOSXSDKVersionString()));
- }
-
- s.set ("ZERO_LINK", "NO");
-
- if (xcodeCanUseDwarf)
- s.set ("DEBUG_INFORMATION_FORMAT", "dwarf");
-
- s.set ("PRODUCT_NAME", replacePreprocessorTokens (config, config.getTargetBinaryNameString()).quoted());
-
- return s;
- }
-
- void addFrameworks() const
- {
- if (! projectType.isStaticLibrary())
- {
- if (isInAppPurchasesEnabled())
- xcodeFrameworks.addIfNotAlreadyThere ("StoreKit");
-
- if (iOS && isPushNotificationsEnabled())
- xcodeFrameworks.addIfNotAlreadyThere ("UserNotifications");
-
- if (iOS
- && project.getEnabledModules().isModuleEnabled ("juce_video")
- && project.isConfigFlagEnabled ("JUCE_USE_CAMERA", false))
- {
- xcodeFrameworks.addIfNotAlreadyThere ("ImageIO");
- }
-
- xcodeFrameworks.addTokens (getExtraFrameworksString(), ",;", "\"'");
- xcodeFrameworks.trim();
-
- auto s = xcodeFrameworks;
-
- for (auto& target : targets)
- s.addArray (target->xcodeFrameworks);
-
- if (! project.getConfigFlag ("JUCE_QUICKTIME").get())
- s.removeString ("QuickTime");
-
- s.trim();
- s.removeDuplicates (true);
- s.sort (true);
-
- // When building against the 10.15 SDK we need to make sure the
- // AudioUnit framework is linked before the AudioToolbox framework.
- auto audioUnitIndex = s.indexOf ("AudioUnit", false, 1);
-
- if (audioUnitIndex != -1)
- {
- s.remove (audioUnitIndex);
- s.insert (0, "AudioUnit");
- }
-
- for (auto& framework : s)
- {
- auto frameworkID = addFramework (framework);
-
- // find all the targets that are referring to this object
- for (auto& target : targets)
- {
- if (xcodeFrameworks.contains (framework) || target->xcodeFrameworks.contains (framework))
- {
- target->frameworkIDs.add (frameworkID);
- target->frameworkNames.add (framework);
- }
- }
- }
- }
- }
-
- void addCustomFrameworks() const
- {
- StringArray customFrameworks;
- customFrameworks.addTokens (getExtraCustomFrameworksString(), true);
- customFrameworks.trim();
-
- for (auto& framework : customFrameworks)
- {
- auto frameworkID = addCustomFramework (framework);
-
- for (auto& target : targets)
- {
- target->frameworkIDs.add (frameworkID);
- target->frameworkNames.add (framework);
- }
- }
- }
-
- void addEmbeddedFrameworks() const
- {
- StringArray frameworks;
- frameworks.addTokens (getEmbeddedFrameworksString(), true);
- frameworks.trim();
-
- for (auto& framework : frameworks)
- {
- auto frameworkID = addEmbeddedFramework (framework);
- embeddedFrameworkIDs.add (frameworkID);
-
- for (auto& target : targets)
- {
- target->frameworkIDs.add (frameworkID);
- target->frameworkNames.add (framework);
- }
- }
-
- if (! embeddedFrameworkIDs.isEmpty())
- for (auto& target : targets)
- target->addCopyFilesPhase ("Embed Frameworks", embeddedFrameworkIDs, kFrameworksFolder);
- }
-
- void addCustomResourceFolders() const
- {
- StringArray folders;
-
- folders.addTokens (getCustomResourceFoldersString(), ":", "");
- folders.trim();
- folders.removeEmptyStrings();
-
- for (auto& crf : folders)
- addCustomResourceFolder (crf);
- }
-
- void addSubprojects() const
- {
- auto subprojectLines = StringArray::fromLines (getSubprojectsString());
- subprojectLines.removeEmptyStrings (true);
-
- Array<std::pair<String, StringArray>> subprojects;
-
- for (auto& line : subprojectLines)
- {
- String subprojectName (line.upToFirstOccurrenceOf (":", false, false));
- StringArray requestedBuildProducts (StringArray::fromTokens (line.fromFirstOccurrenceOf (":", false, false), ",;|", "\"'"));
- requestedBuildProducts.trim();
- subprojects.add ({ subprojectName, requestedBuildProducts });
- }
-
- for (const auto& subprojectInfo : subprojects)
- {
- String subprojectPath (subprojectInfo.first);
-
- if (! subprojectPath.endsWith (".xcodeproj"))
- subprojectPath += ".xcodeproj";
-
- File subprojectFile = File::isAbsolutePath (subprojectPath) ? subprojectPath
- : getTargetFolder().getChildFile (subprojectPath);
-
- if (! subprojectFile.isDirectory())
- continue;
-
- auto availableBuildProducts = XcodeProjectParser::parseBuildProducts (subprojectFile);
-
- // If no build products have been specified then we'll take everything
- if (! subprojectInfo.second.isEmpty())
- {
- auto newEnd = std::remove_if (availableBuildProducts.begin(), availableBuildProducts.end(),
- [&subprojectInfo](const std::pair<String, String> &item)
- {
- return ! subprojectInfo.second.contains (item.first);
- });
- availableBuildProducts.erase (newEnd, availableBuildProducts.end());
- }
-
- if (availableBuildProducts.empty())
- continue;
-
- auto subprojectFileType = getFileType (build_tools::RelativePath (subprojectFile.getFullPathName(), build_tools::RelativePath::buildTargetFolder));
- auto subprojectFileID = addFileOrFolderReference (subprojectFile.getFullPathName(), "<group>", subprojectFileType);
- subprojectFileIDs.add (subprojectFileID);
-
- StringArray proxyIDs;
-
- for (auto& buildProduct : availableBuildProducts)
- {
- auto buildProductFileType = getFileType (build_tools::RelativePath (buildProduct.second, build_tools::RelativePath::projectFolder));
-
- auto containerID = addContainerItemProxy (subprojectFileID, buildProduct.first);
- auto proxyID = addReferenceProxy (containerID, buildProduct.second, buildProductFileType);
- proxyIDs.add (proxyID);
-
- if (buildProductFileType == "archive.ar" || buildProductFileType == "wrapper.framework")
- {
- auto buildFileID = addBuildFile (buildProduct.second, proxyID, false, true);
-
- for (auto& target : targets)
- target->frameworkIDs.add (buildFileID);
-
- if (buildProductFileType == "wrapper.framework")
- {
- auto fileID = createID (buildProduct.second + "buildref");
-
- auto* v = new ValueTree (fileID);
- v->setProperty ("isa", "PBXBuildFile", nullptr);
- v->setProperty ("fileRef", proxyID, nullptr);
- v->setProperty ("settings", "{ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }", nullptr);
- pbxBuildFiles.add (v);
-
- embeddedFrameworkIDs.add (fileID);
- }
- }
- }
-
- auto productGroupID = createFileRefID (subprojectFile.getFullPathName() + "_products");
- addGroup (productGroupID, "Products", proxyIDs);
-
- subprojectReferences.add ({ productGroupID, subprojectFileID });
- }
- }
-
- void addXcassets() const
- {
- auto customXcassetsPath = getCustomXcassetsFolderString();
-
- if (customXcassetsPath.isEmpty())
- addDefaultXcassetsFolders();
- else
- addCustomResourceFolder (customXcassetsPath, "folder.assetcatalog");
- }
-
- void addCustomResourceFolder (String folderPathRelativeToProjectFolder, const String fileType = "folder") const
- {
- auto folderPath = build_tools::RelativePath (folderPathRelativeToProjectFolder, build_tools::RelativePath::projectFolder)
- .rebased (projectFolder, getTargetFolder(), build_tools::RelativePath::buildTargetFolder)
- .toUnixStyle();
-
- auto fileRefID = createFileRefID (folderPath);
-
- addFileOrFolderReference (folderPath, "<group>", fileType);
-
- resourceIDs.add (addBuildFile (folderPath, fileRefID, false, false));
- resourceFileRefs.add (createFileRefID (folderPath));
- }
-
- //==============================================================================
- void writeProjectFile (OutputStream& output) const
- {
- output << "// !$*UTF8*$!\n{\n"
- "\tarchiveVersion = 1;\n"
- "\tclasses = {\n\t};\n"
- "\tobjectVersion = 46;\n"
- "\tobjects = {\n";
-
- Array<ValueTree*> objects;
- objects.addArray (pbxBuildFiles);
- objects.addArray (pbxFileReferences);
- objects.addArray (pbxGroups);
- objects.addArray (targetConfigs);
- objects.addArray (projectConfigs);
- objects.addArray (misc);
-
- for (auto* o : objects)
- {
- output << "\t\t" << o->getType().toString() << " = {\n";
-
- for (int j = 0; j < o->getNumProperties(); ++j)
- {
- auto propertyName = o->getPropertyName(j);
- auto val = o->getProperty (propertyName).toString();
-
- if (val.isEmpty() || (val.containsAnyOf (" \t;<>()=,&+-_@~\r\n\\#%^`*")
- && ! (val.trimStart().startsWithChar ('(')
- || val.trimStart().startsWithChar ('{'))))
- val = "\"" + val + "\"";
-
- output << "\t\t\t" << propertyName.toString() << " = " << val << ";\n";
- }
-
- output << "\t\t};\n";
- }
-
- output << "\t};\n\trootObject = " << createID ("__root") << ";\n}\n";
- }
-
- String addBuildFile (const String& path, const String& fileRefID, bool addToSourceBuildPhase, bool inhibitWarnings,
- XcodeTarget* xcodeTarget = nullptr, String compilerFlags = {}) const
- {
- auto fileID = createID (path + "buildref");
-
- if (addToSourceBuildPhase)
- {
- if (xcodeTarget != nullptr)
- xcodeTarget->sourceIDs.add (fileID);
- else
- sourceIDs.add (fileID);
- }
-
- auto* v = new ValueTree (fileID);
- v->setProperty ("isa", "PBXBuildFile", nullptr);
- v->setProperty ("fileRef", fileRefID, nullptr);
-
- if (inhibitWarnings)
- compilerFlags += " -w";
-
- if (compilerFlags.isNotEmpty())
- v->setProperty ("settings", "{ COMPILER_FLAGS = \"" + compilerFlags.trim() + "\"; }", nullptr);
-
- pbxBuildFiles.add (v);
- return fileID;
- }
-
- String addBuildFile (const build_tools::RelativePath& path, bool addToSourceBuildPhase, bool inhibitWarnings, XcodeTarget* xcodeTarget = nullptr) const
- {
- return addBuildFile (path.toUnixStyle(), createFileRefID (path), addToSourceBuildPhase, inhibitWarnings, xcodeTarget);
- }
-
- String addFileReference (String pathString) const
- {
- String sourceTree ("SOURCE_ROOT");
- build_tools::RelativePath path (pathString, build_tools::RelativePath::unknown);
-
- if (pathString.startsWith ("${"))
- {
- sourceTree = pathString.substring (2).upToFirstOccurrenceOf ("}", false, false);
- pathString = pathString.fromFirstOccurrenceOf ("}/", false, false);
- }
- else if (path.isAbsolute())
- {
- sourceTree = "<absolute>";
- }
-
- auto fileType = getFileType (path);
-
- return addFileOrFolderReference (pathString, sourceTree, fileType);
- }
-
- void checkAndAddFileReference (std::unique_ptr<ValueTree> v) const
- {
- auto existing = pbxFileReferences.indexOfSorted (*this, v.get());
-
- if (existing >= 0)
- {
- // If this fails, there's either a string hash collision, or the same file is being added twice (incorrectly)
- jassert (pbxFileReferences.getUnchecked (existing)->isEquivalentTo (*v));
- }
- else
- {
- pbxFileReferences.addSorted (*this, v.release());
- }
- }
-
- String addFileOrFolderReference (const String& pathString, String sourceTree, String fileType) const
- {
- auto fileRefID = createFileRefID (pathString);
-
- std::unique_ptr<ValueTree> v (new ValueTree (fileRefID));
- v->setProperty ("isa", "PBXFileReference", nullptr);
- v->setProperty ("lastKnownFileType", fileType, nullptr);
- v->setProperty (Ids::name, pathString.fromLastOccurrenceOf ("/", false, false), nullptr);
- v->setProperty ("path", pathString, nullptr);
- v->setProperty ("sourceTree", sourceTree, nullptr);
-
- checkAndAddFileReference (std::move (v));
-
- return fileRefID;
- }
-
- String addContainerItemProxy (const String& subprojectID, const String& itemName) const
- {
- auto uniqueString = subprojectID + "_" + itemName;
- auto fileRefID = createFileRefID (uniqueString);
-
- std::unique_ptr<ValueTree> v (new ValueTree (fileRefID));
- v->setProperty ("isa", "PBXContainerItemProxy", nullptr);
- v->setProperty ("containerPortal", subprojectID, nullptr);
- v->setProperty ("proxyType", 2, nullptr);
- v->setProperty ("remoteGlobalIDString", createFileRefID (uniqueString + "_global"), nullptr);
- v->setProperty ("remoteInfo", itemName, nullptr);
-
- checkAndAddFileReference (std::move (v));
-
- return fileRefID;
- }
-
- String addReferenceProxy (const String& containerItemID, const String& proxyPath, const String& fileType) const
- {
- auto fileRefID = createFileRefID (containerItemID + "_" + proxyPath);
-
- std::unique_ptr<ValueTree> v (new ValueTree (fileRefID));
- v->setProperty ("isa", "PBXReferenceProxy", nullptr);
- v->setProperty ("fileType", fileType, nullptr);
- v->setProperty ("path", proxyPath, nullptr);
- v->setProperty ("remoteRef", containerItemID, nullptr);
- v->setProperty ("sourceTree", "BUILT_PRODUCTS_DIR", nullptr);
-
- checkAndAddFileReference (std::move (v));
-
- return fileRefID;
- }
-
- public:
- static int compareElements (const ValueTree* first, const ValueTree* second)
- {
- return first->getType().getCharPointer().compare (second->getType().getCharPointer());
- }
-
- private:
- static String getFileType (const build_tools::RelativePath& file)
- {
- if (file.hasFileExtension (cppFileExtensions)) return "sourcecode.cpp.cpp";
- if (file.hasFileExtension (".mm")) return "sourcecode.cpp.objcpp";
- if (file.hasFileExtension (".m")) return "sourcecode.c.objc";
- if (file.hasFileExtension (".c")) return "sourcecode.c.c";
- if (file.hasFileExtension (headerFileExtensions)) return "sourcecode.c.h";
- if (file.hasFileExtension (asmFileExtensions)) return "sourcecode.c.asm";
- if (file.hasFileExtension (".framework")) return "wrapper.framework";
- if (file.hasFileExtension (".jpeg;.jpg")) return "image.jpeg";
- if (file.hasFileExtension ("png;gif")) return "image" + file.getFileExtension();
- if (file.hasFileExtension ("html;htm")) return "text.html";
- if (file.hasFileExtension ("xml;zip;wav")) return "file" + file.getFileExtension();
- if (file.hasFileExtension ("txt;rtf")) return "text" + file.getFileExtension();
- if (file.hasFileExtension ("plist")) return "text.plist.xml";
- if (file.hasFileExtension ("entitlements")) return "text.plist.xml";
- if (file.hasFileExtension ("app")) return "wrapper.application";
- if (file.hasFileExtension ("component;vst;plugin")) return "wrapper.cfbundle";
- if (file.hasFileExtension ("xcodeproj")) return "wrapper.pb-project";
- if (file.hasFileExtension ("a")) return "archive.ar";
- if (file.hasFileExtension ("xcassets")) return "folder.assetcatalog";
-
- return "file" + file.getFileExtension();
- }
-
- String addFile (const build_tools::RelativePath& path, bool shouldBeCompiled, bool shouldBeAddedToBinaryResources,
- bool shouldBeAddedToXcodeResources, bool inhibitWarnings, XcodeTarget* xcodeTarget, const String& compilerFlags) const
- {
- auto pathAsString = path.toUnixStyle();
- auto refID = addFileReference (path.toUnixStyle());
-
- if (shouldBeCompiled)
- {
- addBuildFile (pathAsString, refID, true, inhibitWarnings, xcodeTarget, compilerFlags);
- }
- else if (! shouldBeAddedToBinaryResources || shouldBeAddedToXcodeResources)
- {
- auto fileType = getFileType (path);
-
- if (shouldBeAddedToXcodeResources)
- {
- resourceIDs.add (addBuildFile (pathAsString, refID, false, false));
- resourceFileRefs.add (refID);
- }
- }
-
- return refID;
- }
-
- String addRezFile (const Project::Item& projectItem, const build_tools::RelativePath& path) const
- {
- auto pathAsString = path.toUnixStyle();
- auto refID = addFileReference (path.toUnixStyle());
-
- if (projectItem.isModuleCode())
- {
- if (auto* xcodeTarget = getTargetOfType (getProject().getTargetTypeFromFilePath (projectItem.getFile(), false)))
- {
- auto rezFileID = addBuildFile (pathAsString, refID, false, false, xcodeTarget);
- xcodeTarget->rezFileIDs.add (rezFileID);
-
- return refID;
- }
- }
-
- return {};
- }
-
- void addEntitlementsFile (XcodeTarget& target) const
- {
- build_tools::EntitlementOptions options;
-
- options.type = target.type;
- options.isiOS = isiOS();
- options.isAudioPluginProject = project.isAudioPluginProject();
- options.shouldEnableIAA = project.shouldEnableIAA();
- options.isiCloudPermissionsEnabled = isiCloudPermissionsEnabled();
- options.isPushNotificationsEnabled = isPushNotificationsEnabled();
- options.isAppGroupsEnabled = isAppGroupsEnabled();
- options.isHardenedRuntimeEnabled = isHardenedRuntimeEnabled();
- options.isAppSandboxEnabled = isAppSandboxEnabled();
- options.isAppSandboxInhertianceEnabled = isAppSandboxInhertianceEnabled();
- options.appGroupIdString = getAppGroupIdString();
- options.hardenedRuntimeOptions = getHardenedRuntimeOptions();
- options.appSandboxOptions = getAppSandboxOptions();
-
- const auto entitlementsFile = getTargetFolder().getChildFile (target.getEntitlementsFilename());
- build_tools::overwriteFileIfDifferentOrThrow (entitlementsFile, options.getEntitlementsFileContent());
-
- build_tools::RelativePath entitlementsPath (entitlementsFile, getTargetFolder(), build_tools::RelativePath::buildTargetFolder);
- addFile (entitlementsPath, false, false, false, false, nullptr, {});
- }
-
- String addProjectItem (const Project::Item& projectItem) const
- {
- if (modulesGroup != nullptr && projectItem.getParent() == *modulesGroup)
- return addFileReference (rebaseFromProjectFolderToBuildTarget (getModuleFolderRelativeToProject (projectItem.getName())).toUnixStyle());
-
- if (projectItem.isGroup())
- {
- StringArray childIDs;
- for (int i = 0; i < projectItem.getNumChildren(); ++i)
- {
- auto child = projectItem.getChild (i);
-
- auto childID = addProjectItem (child);
-
- if (childID.isNotEmpty() && ! child.shouldBeAddedToXcodeResources())
- childIDs.add (childID);
- }
-
- if (childIDs.isEmpty())
- return {};
-
- return addGroup (projectItem, childIDs);
- }
-
- if (projectItem.shouldBeAddedToTargetProject() && projectItem.shouldBeAddedToTargetExporter (*this))
- {
- auto itemPath = projectItem.getFilePath();
- build_tools::RelativePath path;
-
- if (itemPath.startsWith ("${"))
- path = build_tools::RelativePath (itemPath, build_tools::RelativePath::unknown);
- else
- path = build_tools::RelativePath (projectItem.getFile(), getTargetFolder(), build_tools::RelativePath::buildTargetFolder);
-
- if (path.hasFileExtension (".r"))
- return addRezFile (projectItem, path);
-
- XcodeTarget* xcodeTarget = nullptr;
- if (projectItem.isModuleCode() && projectItem.shouldBeCompiled())
- xcodeTarget = getTargetOfType (project.getTargetTypeFromFilePath (projectItem.getFile(), false));
-
- return addFile (path, projectItem.shouldBeCompiled(),
- projectItem.shouldBeAddedToBinaryResources(),
- projectItem.shouldBeAddedToXcodeResources(),
- projectItem.shouldInhibitWarnings(),
- xcodeTarget,
- compilerFlagSchemesMap[projectItem.getCompilerFlagSchemeString()].get());
- }
-
- return {};
- }
-
- String addFramework (const String& frameworkName) const
- {
- auto path = frameworkName;
- auto isRelativePath = path.startsWith ("../");
-
- if (! File::isAbsolutePath (path) && ! isRelativePath)
- path = "System/Library/Frameworks/" + path;
-
- if (! path.endsWithIgnoreCase (".framework"))
- path << ".framework";
-
- auto fileRefID = createFileRefID (path);
-
- addFileReference (((File::isAbsolutePath (frameworkName) || isRelativePath) ? "" : "${SDKROOT}/") + path);
- frameworkFileIDs.add (fileRefID);
-
- return addBuildFile (path, fileRefID, false, false);
- }
-
- String addCustomFramework (String frameworkPath) const
- {
- if (! frameworkPath.endsWithIgnoreCase (".framework"))
- frameworkPath << ".framework";
-
- auto fileRefID = createFileRefID (frameworkPath);
-
- auto fileType = getFileType (build_tools::RelativePath (frameworkPath, build_tools::RelativePath::projectFolder));
- addFileOrFolderReference (frameworkPath, "<group>", fileType);
-
- frameworkFileIDs.add (fileRefID);
-
- return addBuildFile (frameworkPath, fileRefID, false, false);
- }
-
- String addEmbeddedFramework (const String& path) const
- {
- auto fileRefID = createFileRefID (path);
-
- auto fileType = getFileType (build_tools::RelativePath (path, build_tools::RelativePath::projectFolder));
- addFileOrFolderReference (path, "<group>", fileType);
-
- auto fileID = createID (path + "buildref");
-
- auto* v = new ValueTree (fileID);
- v->setProperty ("isa", "PBXBuildFile", nullptr);
- v->setProperty ("fileRef", fileRefID, nullptr);
- v->setProperty ("settings", "{ ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }", nullptr);
- pbxBuildFiles.add (v);
-
- frameworkFileIDs.add (fileRefID);
-
- return fileID;
- }
-
- void addGroup (const String& groupID, const String& groupName, const StringArray& childIDs) const
- {
- auto* v = new ValueTree (groupID);
- v->setProperty ("isa", "PBXGroup", nullptr);
- v->setProperty ("children", indentParenthesisedList (childIDs), nullptr);
- v->setProperty (Ids::name, groupName, nullptr);
- v->setProperty ("sourceTree", "<group>", nullptr);
- pbxGroups.add (v);
- }
-
- String addGroup (const Project::Item& item, StringArray& childIDs) const
- {
- auto groupName = item.getName();
- auto groupID = getIDForGroup (item);
- addGroup (groupID, groupName, childIDs);
- return groupID;
- }
-
- void addProjectConfig (const String& configName, const StringArray& buildSettings) const
- {
- auto* v = new ValueTree (createID ("projectconfigid_" + configName));
- v->setProperty ("isa", "XCBuildConfiguration", nullptr);
- v->setProperty ("buildSettings", indentBracedList (buildSettings), nullptr);
- v->setProperty (Ids::name, configName, nullptr);
- projectConfigs.add (v);
- }
-
- void addConfigList (XcodeTarget& target, const OwnedArray <ValueTree>& configsToUse, const String& listID) const
- {
- auto* v = new ValueTree (listID);
- v->setProperty ("isa", "XCConfigurationList", nullptr);
- v->setProperty ("buildConfigurations", indentParenthesisedList (target.configIDs), nullptr);
- v->setProperty ("defaultConfigurationIsVisible", (int) 0, nullptr);
-
- if (auto* first = configsToUse.getFirst())
- v->setProperty ("defaultConfigurationName", first->getProperty (Ids::name), nullptr);
-
- misc.add (v);
- }
-
- void addProjectConfigList (const OwnedArray <ValueTree>& configsToUse, const String& listID) const
- {
- StringArray configIDs;
-
- for (auto* c : configsToUse)
- configIDs.add (c->getType().toString());
-
- auto* v = new ValueTree (listID);
- v->setProperty ("isa", "XCConfigurationList", nullptr);
- v->setProperty ("buildConfigurations", indentParenthesisedList (configIDs), nullptr);
- v->setProperty ("defaultConfigurationIsVisible", (int) 0, nullptr);
-
- if (auto* first = configsToUse.getFirst())
- v->setProperty ("defaultConfigurationName", first->getProperty (Ids::name), nullptr);
-
- misc.add (v);
- }
-
- void addProjectObject() const
- {
- auto* v = new ValueTree (createID ("__root"));
- v->setProperty ("isa", "PBXProject", nullptr);
- v->setProperty ("buildConfigurationList", createID ("__projList"), nullptr);
- v->setProperty ("attributes", getProjectObjectAttributes(), nullptr);
- v->setProperty ("compatibilityVersion", "Xcode 3.2", nullptr);
- v->setProperty ("hasScannedForEncodings", (int) 0, nullptr);
- v->setProperty ("mainGroup", createID ("__mainsourcegroup"), nullptr);
- v->setProperty ("projectDirPath", "\"\"", nullptr);
-
- if (! subprojectReferences.isEmpty())
- {
- StringArray projectReferences;
-
- for (auto& reference : subprojectReferences)
- projectReferences.add (indentBracedList ({ "ProductGroup = " + reference.first, "ProjectRef = " + reference.second }, 1));
-
- v->setProperty ("projectReferences", indentParenthesisedList (projectReferences), nullptr);
- }
-
- v->setProperty ("projectRoot", "\"\"", nullptr);
-
- auto targetString = "(" + targetIDs.joinIntoString (", ") + ")";
- v->setProperty ("targets", targetString, nullptr);
-
- v->setProperty ("knownRegions", "(en, Base)", nullptr);
-
- misc.add (v);
- }
-
- //==============================================================================
- void removeMismatchedXcuserdata() const
- {
- if (shouldKeepCustomXcodeSchemes())
- return;
-
- auto xcuserdata = getProjectBundle().getChildFile ("xcuserdata");
-
- if (! xcuserdata.exists())
- return;
-
- if (! xcuserdataMatchesTargets (xcuserdata))
- {
- xcuserdata.deleteRecursively();
- getProjectBundle().getChildFile ("xcshareddata").getChildFile ("xcschemes").deleteRecursively();
- getProjectBundle().getChildFile ("project.xcworkspace").deleteRecursively();
- }
- }
-
- bool xcuserdataMatchesTargets (const File& xcuserdata) const
- {
- for (auto& plist : xcuserdata.findChildFiles (File::findFiles, true, "xcschememanagement.plist"))
- if (! xcschemeManagementPlistMatchesTargets (plist))
- return false;
-
- return true;
- }
-
- static StringArray parseNamesOfTargetsFromPlist (const XmlElement& dictXML)
- {
- forEachXmlChildElementWithTagName (dictXML, schemesKey, "key")
- {
- if (schemesKey->getAllSubText().trim().equalsIgnoreCase ("SchemeUserState"))
- {
- if (auto* dict = schemesKey->getNextElement())
- {
- if (dict->hasTagName ("dict"))
- {
- StringArray names;
-
- forEachXmlChildElementWithTagName (*dict, key, "key")
- names.add (key->getAllSubText().upToLastOccurrenceOf (".xcscheme", false, false).trim());
-
- names.sort (false);
- return names;
- }
- }
- }
- }
-
- return {};
- }
-
- StringArray getNamesOfTargets() const
- {
- StringArray names;
-
- for (auto& target : targets)
- names.add (target->getXcodeSchemeName());
-
- names.sort (false);
- return names;
- }
-
- bool xcschemeManagementPlistMatchesTargets (const File& plist) const
- {
- if (auto xml = parseXML (plist))
- if (auto* dict = xml->getChildByName ("dict"))
- return parseNamesOfTargetsFromPlist (*dict) == getNamesOfTargets();
-
- return false;
- }
-
- String getProjectObjectAttributes() const
- {
- String attributes;
-
- attributes << "{ LastUpgradeCheck = 1100; "
- << "ORGANIZATIONNAME = " << getProject().getCompanyNameString().quoted()
- <<"; ";
-
- if (projectType.isGUIApplication() || projectType.isAudioPlugin())
- {
- attributes << "TargetAttributes = { ";
-
- for (auto& target : targets)
- attributes << target->getTargetAttributes();
-
- attributes << " }; ";
- }
-
- attributes << "}";
-
- return attributes;
- }
-
- //==============================================================================
- void writeDefaultLaunchStoryboardFile() const
- {
- const auto storyboardFile = getTargetFolder().getChildFile (getDefaultLaunchStoryboardName() + ".storyboard");
-
- build_tools::writeStreamToFile (storyboardFile, [&] (MemoryOutputStream& mo)
- {
- mo << String (BinaryData::LaunchScreen_storyboard);
- });
-
- addLaunchStoryboardFileReference (build_tools::RelativePath (storyboardFile,
- getTargetFolder(),
- build_tools::RelativePath::buildTargetFolder).toUnixStyle());
- }
-
- void addLaunchStoryboardFileReference (const String& relativePath) const
- {
- auto refID = addFileReference (relativePath);
- auto fileID = addBuildFile (relativePath, refID, false, false);
-
- resourceIDs.add (fileID);
- resourceFileRefs.add (refID);
- }
-
- void addDefaultXcassetsFolders() const
- {
- const auto assetsPath = build_tools::createXcassetsFolderFromIcons (getIcons(),
- getTargetFolder(),
- project.getProjectFilenameRootString());
- addFileReference (assetsPath.toUnixStyle());
- resourceIDs.add (addBuildFile (assetsPath, false, false));
- resourceFileRefs.add (createFileRefID (assetsPath));
- }
-
- //==============================================================================
- static String indentBracedList (const StringArray& list, int depth = 0) { return indentList (list, '{', '}', ";", depth, true); }
- static String indentParenthesisedList (const StringArray& list, int depth = 0) { return indentList (list, '(', ')', ",", depth, false); }
-
- static String indentList (StringArray list, char openBracket, char closeBracket, const String& separator, int extraTabs, bool shouldSort)
- {
- if (list.size() == 0)
- return openBracket + String (" ") + closeBracket;
-
- auto tabs = "\n" + String::repeatedString ("\t", extraTabs + 4);
-
- if (shouldSort)
- list.sort (true);
-
- return openBracket + tabs + list.joinIntoString (separator + tabs) + separator
- + "\n" + String::repeatedString ("\t", extraTabs + 3) + closeBracket;
- }
-
- String createID (String rootString) const
- {
- if (rootString.startsWith ("${"))
- rootString = rootString.fromFirstOccurrenceOf ("}/", false, false);
-
- rootString += project.getProjectUIDString();
-
- return MD5 (rootString.toUTF8()).toHexString().substring (0, 24).toUpperCase();
- }
-
- String createFileRefID (const build_tools::RelativePath& path) const { return createFileRefID (path.toUnixStyle()); }
- String createFileRefID (const String& path) const { return createID ("__fileref_" + path); }
- String getIDForGroup (const Project::Item& item) const { return createID (item.getID()); }
-
- bool shouldFileBeCompiledByDefault (const File& file) const override
- {
- return file.hasFileExtension (sourceFileExtensions);
- }
-
- //==============================================================================
- void updateOldOrientationSettings()
- {
- jassert (iOS);
-
- StringArray orientationSettingStrings { getSetting (Ids::iPhoneScreenOrientation).getValue().toString(),
- getSetting (Ids::iPadScreenOrientation).getValue().toString() };
-
- for (int i = 0; i < 2; ++i)
- {
- auto& settingsString = orientationSettingStrings[i];
-
- if (settingsString.isNotEmpty())
- {
- Array<var> orientations;
-
- if (settingsString.contains ("portrait")) orientations.add ("UIInterfaceOrientationPortrait");
- if (settingsString.contains ("landscape")) orientations.addArray ({ "UIInterfaceOrientationLandscapeLeft",
- "UIInterfaceOrientationLandscapeRight" });
- if (i == 0)
- iPhoneScreenOrientationValue = orientations;
- else
- iPadScreenOrientationValue = orientations;
- }
- }
- }
-
- JUCE_DECLARE_NON_COPYABLE (XcodeProjectExporter)
- };
|