From 4dd07111f91c00a448e622ff9fcf5b7f5057900c Mon Sep 17 00:00:00 2001 From: AMZN-Phil Date: Fri, 19 Nov 2021 08:31:32 -0800 Subject: [PATCH 01/23] Make version string settable from Jenkins Signed-off-by: AMZN-Phil --- scripts/build/Platform/Windows/build_config.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/build/Platform/Windows/build_config.json b/scripts/build/Platform/Windows/build_config.json index de83294639..9eb9957729 100644 --- a/scripts/build/Platform/Windows/build_config.json +++ b/scripts/build/Platform/Windows/build_config.json @@ -363,7 +363,7 @@ "PARAMETERS": { "CONFIGURATION": "profile", "OUTPUT_DIRECTORY": "build\\windows_vs2019", - "CMAKE_OPTIONS": "-G \"Visual Studio 16 2019\" -DCMAKE_SYSTEM_VERSION=10.0 -DLY_UNITY_BUILD=TRUE -DLY_DISABLE_TEST_MODULES=TRUE -DLY_VERSION_ENGINE_NAME=o3de-sdk -DLY_INSTALLER_WIX_ROOT=\"!WIX! \"", + "CMAKE_OPTIONS": "-G \"Visual Studio 16 2019\" -DCMAKE_SYSTEM_VERSION=10.0 -DLY_UNITY_BUILD=TRUE -DLY_DISABLE_TEST_MODULES=TRUE -DLY_VERSION_ENGINE_NAME=o3de-sdk -DLY_VERSION_STRING=!O3DE_VERSION! -DLY_INSTALLER_WIX_ROOT=\"!WIX! \"", "EXTRA_CMAKE_OPTIONS": "-DLY_INSTALLER_AUTO_GEN_TAG=ON -DLY_INSTALLER_DOWNLOAD_URL=!INSTALLER_DOWNLOAD_URL! -DLY_INSTALLER_LICENSE_URL=!INSTALLER_DOWNLOAD_URL!/license", "CPACK_BUCKET": "!INSTALLER_BUCKET!", "CMAKE_LY_PROJECTS": "", From 4ad35f424e01356a4745e5f50631dc050b328c98 Mon Sep 17 00:00:00 2001 From: John Jones-Steele <82226755+jjjoness@users.noreply.github.com> Date: Fri, 19 Nov 2021 17:57:38 +0000 Subject: [PATCH 02/23] Adds check to make sure that there are not too many samples created. (#5789) * Adds check to make sure that there are not too many samples created. Signed-off-by: John Jones-Steele <82226755+jjjoness@users.noreply.github.com> * Changes made from PR Signed-off-by: John Jones-Steele <82226755+jjjoness@users.noreply.github.com> * Changes made from PR 2 Signed-off-by: John Jones-Steele <82226755+jjjoness@users.noreply.github.com> --- .../UI/PropertyEditor/PropertyVectorCtrl.hxx | 5 +-- .../Components/TerrainWorldComponent.cpp | 44 ++++++++++++++++++- .../Source/Components/TerrainWorldComponent.h | 8 ++++ 3 files changed, 51 insertions(+), 6 deletions(-) diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/UI/PropertyEditor/PropertyVectorCtrl.hxx b/Code/Framework/AzToolsFramework/AzToolsFramework/UI/PropertyEditor/PropertyVectorCtrl.hxx index e5a6b5803c..cc61593154 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/UI/PropertyEditor/PropertyVectorCtrl.hxx +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/UI/PropertyEditor/PropertyVectorCtrl.hxx @@ -150,10 +150,7 @@ namespace AzToolsFramework TypeBeingHandled actualValue = instance; for (int idx = 0; idx < m_common.GetElementCount(); ++idx) { - if (elements[idx]->wasValueEditedByUser()) - { - actualValue.SetElement(idx, static_cast(elements[idx]->getValue())); - } + actualValue.SetElement(idx, static_cast(elements[idx]->getValue())); } instance = actualValue; } diff --git a/Gems/Terrain/Code/Source/Components/TerrainWorldComponent.cpp b/Gems/Terrain/Code/Source/Components/TerrainWorldComponent.cpp index bd65cf6abc..8d6bf8e4b0 100644 --- a/Gems/Terrain/Code/Source/Components/TerrainWorldComponent.cpp +++ b/Gems/Terrain/Code/Source/Components/TerrainWorldComponent.cpp @@ -40,15 +40,17 @@ namespace Terrain ->DataElement(AZ::Edit::UIHandlers::Default, &TerrainWorldConfig::m_worldMin, "World Bounds (Min)", "") // Temporary constraint until the rest of the Terrain system is updated to support larger worlds. + ->Attribute(AZ::Edit::Attributes::ChangeValidate, &TerrainWorldConfig::ValidateWorldMin) ->Attribute(AZ::Edit::Attributes::Min, -2048.0f) ->Attribute(AZ::Edit::Attributes::Max, 2048.0f) ->DataElement(AZ::Edit::UIHandlers::Default, &TerrainWorldConfig::m_worldMax, "World Bounds (Max)", "") // Temporary constraint until the rest of the Terrain system is updated to support larger worlds. + ->Attribute(AZ::Edit::Attributes::ChangeValidate, &TerrainWorldConfig::ValidateWorldMax) ->Attribute(AZ::Edit::Attributes::Min, -2048.0f) ->Attribute(AZ::Edit::Attributes::Max, 2048.0f) ->DataElement( AZ::Edit::UIHandlers::Default, &TerrainWorldConfig::m_heightQueryResolution, "Height Query Resolution (m)", "") - ; + ->Attribute(AZ::Edit::Attributes::ChangeValidate, &TerrainWorldConfig::ValidateWorldHeight); } } } @@ -128,4 +130,42 @@ namespace Terrain } return false; } -} + + float TerrainWorldConfig::NumberOfSamples(AZ::Vector3* min, AZ::Vector3* max, AZ::Vector2* heightQuery) + { + float numberOfSamples = ((max->GetX() - min->GetX()) / heightQuery->GetX()) * ((max->GetY() - min->GetY()) / heightQuery->GetY()); + return numberOfSamples; + } + + AZ::Outcome TerrainWorldConfig::DetermineMessage(float numSamples) + { + const float maximumSamplesAllowed = 8.0f * 1024.0f * 1024.0f; + if (numSamples < maximumSamplesAllowed) + { + return AZ::Success(); + } + return AZ::Failure(AZStd::string("The number of samples exceeds the maximum allowed.")); + } + + AZ::Outcome TerrainWorldConfig::ValidateWorldMin(void* newValue, [[maybe_unused]]const AZ::Uuid& valueType) + { + AZ::Vector3 minValue = *static_cast(newValue); + + return DetermineMessage(NumberOfSamples(&minValue, &m_worldMax, &m_heightQueryResolution)); + } + + AZ::Outcome TerrainWorldConfig::ValidateWorldMax(void* newValue, [[maybe_unused]] const AZ::Uuid& valueType) + { + AZ::Vector3 maxValue = *static_cast(newValue); + + return DetermineMessage(NumberOfSamples(&m_worldMin, &maxValue, &m_heightQueryResolution)); + } + + AZ::Outcome TerrainWorldConfig::ValidateWorldHeight(void* newValue, [[maybe_unused]] const AZ::Uuid& valueType) + { + AZ::Vector2 heightValue = *static_cast(newValue); + + return DetermineMessage(NumberOfSamples(&m_worldMin, &m_worldMax, &heightValue)); + } + +} // namespace Terrain diff --git a/Gems/Terrain/Code/Source/Components/TerrainWorldComponent.h b/Gems/Terrain/Code/Source/Components/TerrainWorldComponent.h index 2dfe1135c8..a396bcefc8 100644 --- a/Gems/Terrain/Code/Source/Components/TerrainWorldComponent.h +++ b/Gems/Terrain/Code/Source/Components/TerrainWorldComponent.h @@ -32,6 +32,14 @@ namespace Terrain AZ::Vector3 m_worldMin{ 0.0f, 0.0f, 0.0f }; AZ::Vector3 m_worldMax{ 1024.0f, 1024.0f, 1024.0f }; AZ::Vector2 m_heightQueryResolution{ 1.0f, 1.0f }; + + private: + AZ::Outcome ValidateWorldMin(void* newValue, const AZ::Uuid& valueType); + AZ::Outcome ValidateWorldMax(void* newValue, const AZ::Uuid& valueType); + AZ::Outcome ValidateWorldHeight(void* newValue, const AZ::Uuid& valueType); + float NumberOfSamples(AZ::Vector3* min, AZ::Vector3* max, AZ::Vector2* heightQuery); + AZ::Outcome DetermineMessage(float numSamples); + }; From 4ee2f341dc0dc709aedb446b57d5cca61b86160d Mon Sep 17 00:00:00 2001 From: Nicholas Van Sickle Date: Fri, 19 Nov 2021 10:05:19 -0800 Subject: [PATCH 03/23] Fix several Prefab outliner ordering issues (#5747) * Fix several Prefab outliner ordering issues This change does a few things to address instability in entity order when prefabs are enabled: - Changes ordering behavior on entity add to always be "insert after the last selected sibling of the new entity, or at the end if there is no selected sibling" - Adds some logic to ensure selection stays frozen during prefab propagation to allow this behavior to be used - Alters delta generation in `PrefabPublicHandler::CreateEntity` to use the template instead of reserializing the DOM - this avoids a whole bunch of patching issues caused by EditorEntitySortComponent doing post-hoc order fix-up and should generally be safer/faster as we're producing patches for the actual target for those patches - Because the duplicate action is DOM-driven, and there's some thorniness around making changes that will affect the template during propagation, this adds `PrefabPublicHandler::AddNewEntityToSortOrder` to directly patch the DOM for the duplicate case Two bits of this come from patches from the incredibly helpful @AMZN-daimini - Alters `PrefabPublicHandler::GenerateUndoNodesForEntityChangeAndUpdateCache` behavior for determining what's an override: we now check to see if we're part of the current focused instance but *not* owned by the focus instance directly. This lets entity order for nested prefabs get saved to the owning prefab instead of as an override. I'm putting this up for discussion without a feature flag gating it, but we may wish to make this a toggle or disable it outright for stabilization (in which case entity order won't be saved to the owning prefab) - Adds a custom serializer for EditorEntitySortComponent. This isn't strictly necessary now, but it was very useful for debugging and ended up receiving much more manual testing its migration path and save/load path more than I've tested without using the serializer. Signed-off-by: Nicholas Van Sickle * Add missing serializers Signed-off-by: Nicholas Van Sickle * Address some review feedback Signed-off-by: Nicholas Van Sickle * Generate patch in `PrefabPublicHandler::CreateEntity` using the instance's fully evaluated template in-memory Signed-off-by: Nicholas Van Sickle * Fix up comment Signed-off-by: Nicholas Van Sickle * Fix Linux build Signed-off-by: Nicholas Van Sickle * Try to make test less timing dependent (haven't been able to repro failure locally) Signed-off-by: Nicholas Van Sickle * Fix another build issue Signed-off-by: Nicholas Van Sickle * Fix unit test failures Signed-off-by: Nicholas Van Sickle * Fix a duplicate issue with sanitization that was causing sporadic test failure (thanks, test!) Signed-off-by: Nicholas Van Sickle * One more Linux fix... Signed-off-by: Nicholas Van Sickle --- .../EntityOutliner_EntityOrdering.py | 21 +- .../Application/ToolsApplication.cpp | 39 +++ .../Application/ToolsApplication.h | 11 + .../Entity/EditorEntityModel.cpp | 25 +- .../Entity/EditorEntitySortComponent.cpp | 110 ++++++-- .../Entity/EditorEntitySortComponent.h | 5 + .../EditorEntitySortComponentSerializer.cpp | 137 ++++++++++ .../EditorEntitySortComponentSerializer.h | 31 +++ .../Instance/InstanceUpdateExecutor.cpp | 5 +- .../AzToolsFramework/Prefab/PrefabDomUtils.h | 3 + .../Prefab/PrefabPublicHandler.cpp | 247 +++++++++++++++++- .../Prefab/PrefabPublicHandler.h | 2 + .../PropertyEditor/EntityPropertyEditor.cpp | 1 - .../aztoolsframework_files.cmake | 2 + 14 files changed, 598 insertions(+), 41 deletions(-) create mode 100644 Code/Framework/AzToolsFramework/AzToolsFramework/Entity/EditorEntitySortComponentSerializer.cpp create mode 100644 Code/Framework/AzToolsFramework/AzToolsFramework/Entity/EditorEntitySortComponentSerializer.h diff --git a/AutomatedTesting/Gem/PythonTests/editor/EditorScripts/EntityOutliner_EntityOrdering.py b/AutomatedTesting/Gem/PythonTests/editor/EditorScripts/EntityOutliner_EntityOrdering.py index e4575d4d17..5fa8130302 100644 --- a/AutomatedTesting/Gem/PythonTests/editor/EditorScripts/EntityOutliner_EntityOrdering.py +++ b/AutomatedTesting/Gem/PythonTests/editor/EditorScripts/EntityOutliner_EntityOrdering.py @@ -95,7 +95,8 @@ def EntityOutliner_EntityOrdering(): entity_outliner_model.dropMimeData( mime_data, QtCore.Qt.MoveAction, target_row, 0, target_index.parent() ) - QtWidgets.QApplication.processEvents() + # Wait after move to let events (i.e. prefab propagation) process + general.idle_wait(1.0) # Move an entity before another entity in the order by dragging the source above the target move_entity_before = lambda source_name, target_name: _move_entity( @@ -119,24 +120,24 @@ def EntityOutliner_EntityOrdering(): # Our new entity should be given a name with a number automatically new_entity = f"Entity{i+1}" - # The new entity should be added to the top of its parent entity - expected_order = [new_entity] + expected_order + # The new entity should be added to the bottom of its parent entity + expected_order = expected_order + [new_entity] verify_entities_sorted(expected_order) - # 3) Move "Entity1" to the top of the order - move_entity_before("Entity1", "Entity5") - expected_order = ["Entity1", "Entity5", "Entity4", "Entity3", "Entity2"] + # 3) Move "Entity5" to the top of the order + move_entity_before("Entity5", "Entity1") + expected_order = ["Entity5", "Entity1", "Entity2", "Entity3", "Entity4"] verify_entities_sorted(expected_order) - # 4) Move "Entity4" to the bottom of the order - move_entity_after("Entity4", "Entity2") - expected_order = ["Entity1", "Entity5", "Entity3", "Entity2", "Entity4"] + # 4) Move "Entity2" to the bottom of the order + move_entity_after("Entity2", "Entity4") + expected_order = ["Entity5", "Entity1", "Entity3", "Entity4", "Entity2"] verify_entities_sorted(expected_order) # 5) Add another new entity, ensure the rest of the order is unchanged create_entity() - expected_order = ["Entity6", "Entity1", "Entity5", "Entity3", "Entity2", "Entity4"] + expected_order = ["Entity5", "Entity1", "Entity3", "Entity4", "Entity2", "Entity6"] verify_entities_sorted(expected_order) diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/Application/ToolsApplication.cpp b/Code/Framework/AzToolsFramework/AzToolsFramework/Application/ToolsApplication.cpp index d3b3b09583..0412e454a6 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/Application/ToolsApplication.cpp +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/Application/ToolsApplication.cpp @@ -238,12 +238,14 @@ namespace AzToolsFramework , m_isInIsolationMode(false) { ToolsApplicationRequests::Bus::Handler::BusConnect(); + AzToolsFramework::Prefab::PrefabPublicNotificationBus::Handler::BusConnect(); m_undoCache.RegisterToUndoCacheInterface(); } ToolsApplication::~ToolsApplication() { + AzToolsFramework::Prefab::PrefabPublicNotificationBus::Handler::BusDisconnect(); ToolsApplicationRequests::Bus::Handler::BusDisconnect(); Stop(); } @@ -564,6 +566,12 @@ namespace AzToolsFramework void ToolsApplication::MarkEntitySelected(AZ::EntityId entityId) { AZ_PROFILE_FUNCTION(AzToolsFramework); + + if (m_freezeSelectionUpdates) + { + return; + } + AZ_Assert(entityId.IsValid(), "Invalid entity Id being marked as selected."); EntityIdList::iterator foundIter = AZStd::find(m_selectedEntities.begin(), m_selectedEntities.end(), entityId); @@ -583,6 +591,11 @@ namespace AzToolsFramework { AZ_PROFILE_FUNCTION(AzToolsFramework); + if (m_freezeSelectionUpdates) + { + return; + } + EntityIdList entitiesSelected; entitiesSelected.reserve(entitiesToSelect.size()); @@ -606,6 +619,12 @@ namespace AzToolsFramework void ToolsApplication::MarkEntityDeselected(AZ::EntityId entityId) { AZ_PROFILE_FUNCTION(AzToolsFramework); + + if (m_freezeSelectionUpdates) + { + return; + } + auto foundIter = AZStd::find(m_selectedEntities.begin(), m_selectedEntities.end(), entityId); if (foundIter != m_selectedEntities.end()) { @@ -623,6 +642,11 @@ namespace AzToolsFramework { AZ_PROFILE_FUNCTION(AzToolsFramework); + if (m_freezeSelectionUpdates) + { + return; + } + ToolsApplicationEvents::Bus::Broadcast(&ToolsApplicationEvents::BeforeEntitySelectionChanged); EntityIdSet entitySetToDeselect(entitiesToDeselect.begin(), entitiesToDeselect.end()); @@ -677,6 +701,11 @@ namespace AzToolsFramework { AZ_PROFILE_FUNCTION(AzToolsFramework); + if (m_freezeSelectionUpdates) + { + return; + } + // We're setting the selection set as a batch from an external caller. // * Filter out any unselectable entities // * Calculate selection/deselection delta so we can notify specific entities only on change. @@ -1567,6 +1596,16 @@ namespace AzToolsFramework } } + void ToolsApplication::OnPrefabInstancePropagationBegin() + { + m_freezeSelectionUpdates = true; + } + + void ToolsApplication::OnPrefabInstancePropagationEnd() + { + m_freezeSelectionUpdates = false; + } + void ToolsApplication::CreateUndosForDirtyEntities() { AZ_PROFILE_FUNCTION(AzToolsFramework); diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/Application/ToolsApplication.h b/Code/Framework/AzToolsFramework/AzToolsFramework/Application/ToolsApplication.h index 5e9208b475..3dcb43f17d 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/Application/ToolsApplication.h +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/Application/ToolsApplication.h @@ -16,6 +16,7 @@ #include #include #include +#include #pragma once @@ -29,6 +30,7 @@ namespace AzToolsFramework class ToolsApplication : public AzFramework::Application , public ToolsApplicationRequests::Bus::Handler + , public AzToolsFramework::Prefab::PrefabPublicNotificationBus::Handler { public: AZ_RTTI(ToolsApplication, "{2895561E-BE90-4CC3-8370-DD46FCF74C01}", AzFramework::Application); @@ -169,6 +171,14 @@ namespace AzToolsFramework }; ////////////////////////////////////////////////////////////////////////// + ////////////////////////////////////////////////////////////////////////// + // PrefabPublicNotificationBus::Handler + + void OnPrefabInstancePropagationBegin() override; + void OnPrefabInstancePropagationEnd() override; + + ////////////////////////////////////////////////////////////////////////// + void CreateUndosForDirtyEntities(); void ConsistencyCheckUndoCache(); AZ::Aabb m_selectionBounds; @@ -181,6 +191,7 @@ namespace AzToolsFramework bool m_isDuringUndoRedo; bool m_isInIsolationMode; EntityIdSet m_isolatedEntityIdSet; + bool m_freezeSelectionUpdates = false; EditorEntityAPI* m_editorEntityAPI = nullptr; diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/Entity/EditorEntityModel.cpp b/Code/Framework/AzToolsFramework/AzToolsFramework/Entity/EditorEntityModel.cpp index eaff64ba2e..e4d4f40bce 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/Entity/EditorEntityModel.cpp +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/Entity/EditorEntityModel.cpp @@ -449,16 +449,23 @@ namespace AzToolsFramework AZStd::unordered_map>::const_iterator orderItr = m_savedOrderInfo.find(childId); if (orderItr != m_savedOrderInfo.end() && orderItr->second.first == parentId) { - bool sortOrderUpdated = AzToolsFramework::RecoverEntitySortInfo(parentId, childId, orderItr->second.second); - m_savedOrderInfo.erase(childId); - - // force notify the child sort order changed on the parent entity info, but only if the restore didn't actually modify - // the order internally (and sent ChildEntityOrderArrayUpdated). that may seem heavy handed, and it is, but necessary - // to combat scenarios when the initial override detection returns a false positive (see comment about IDH comparisons - // in OnChildSortOrderChanged) and the slice instance source-to-live mapping hasn't been fully reconstructed yet. - if (!sortOrderUpdated) + bool isPrefabEnabled = false; + AzFramework::ApplicationRequests::Bus::BroadcastResult( + isPrefabEnabled, &AzFramework::ApplicationRequests::IsPrefabSystemEnabled); + // If prefabs are enabled, rely on the component to do a sanity check instead of restoring the order from the model + if (!isPrefabEnabled) { - parentInfo.OnChildSortOrderChanged(); + bool sortOrderUpdated = AzToolsFramework::RecoverEntitySortInfo(parentId, childId, orderItr->second.second); + m_savedOrderInfo.erase(childId); + + // force notify the child sort order changed on the parent entity info, but only if the restore didn't actually modify + // the order internally (and sent ChildEntityOrderArrayUpdated). that may seem heavy handed, and it is, but necessary + // to combat scenarios when the initial override detection returns a false positive (see comment about IDH comparisons + // in OnChildSortOrderChanged) and the slice instance source-to-live mapping hasn't been fully reconstructed yet. + if (!sortOrderUpdated) + { + parentInfo.OnChildSortOrderChanged(); + } } } else diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/Entity/EditorEntitySortComponent.cpp b/Code/Framework/AzToolsFramework/AzToolsFramework/Entity/EditorEntitySortComponent.cpp index 6936397187..8ade8c470f 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/Entity/EditorEntitySortComponent.cpp +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/Entity/EditorEntitySortComponent.cpp @@ -8,11 +8,17 @@ #include "EditorEntitySortComponent.h" #include "EditorEntityInfoBus.h" #include "EditorEntityHelpers.h" +#include #include #include +#include #include #include #include +#include +#include +#include +#include static_assert(sizeof(AZ::u64) == sizeof(AZ::EntityId), "We use AZ::EntityId for Persistent ID, which is a u64 under the hood. These must be the same size otherwise the persistent id will have to be rewritten"); @@ -51,6 +57,12 @@ namespace AzToolsFramework ; } } + + AZ::JsonRegistrationContext* jsonRegistration = azrtti_cast(context); + if (jsonRegistration) + { + jsonRegistration->Serializer()->HandlesType(); + } } void EditorEntitySortComponent::GetProvidedServices(AZ::ComponentDescriptor::DependencyArrayType& services) @@ -167,9 +179,6 @@ namespace AzToolsFramework } MarkDirtyAndSendChangedEvent(); - - // Use the ToolsApplication to mark the entity dirty, this will only do something if we already have an undo batch - ToolsApplicationRequestBus::Broadcast(&ToolsApplicationRequestBus::Events::AddDirtyEntity, GetEntityId()); return true; } @@ -187,6 +196,10 @@ namespace AzToolsFramework else { EntityOrderArray::iterator insertPosition = GetFirstSelectedEntityPosition(); + if (insertPosition != m_childEntityOrderArray.end()) + { + ++insertPosition; + } retval = AddChildEntityInternal(entityId, false, insertPosition); } @@ -220,9 +233,6 @@ namespace AzToolsFramework MarkDirtyAndSendChangedEvent(); - // Use the ToolsApplication to mark the entity dirty, this will only do something if we already have an undo batch - ToolsApplicationRequestBus::Broadcast(&ToolsApplicationRequestBus::Events::AddDirtyEntity, GetEntityId()); - return true; } return false; @@ -272,6 +282,12 @@ namespace AzToolsFramework void EditorEntitySortComponent::OnPrefabInstancePropagationEnd() { m_ignoreIncomingOrderChanges = false; + + if (m_shouldSanityCheckStateAfterPropagation) + { + SanitizeOrderEntryArray(); + m_shouldSanityCheckStateAfterPropagation = false; + } } void EditorEntitySortComponent::MarkDirtyAndSendChangedEvent() @@ -280,14 +296,8 @@ namespace AzToolsFramework // one of the event listeners needs to build the InstanceDataHierarchy m_entityOrderIsDirty = true; - // Force an immediate update for prefabs, which won't receive PrepareSave - bool isPrefabEnabled = false; - AzFramework::ApplicationRequests::Bus::BroadcastResult( - isPrefabEnabled, &AzFramework::ApplicationRequests::IsPrefabSystemEnabled); - if (isPrefabEnabled) - { - PrepareSave(); - } + // Use the ToolsApplication to mark the entity dirty, this will only do something if we already have an undo batch + ToolsApplicationRequestBus::Broadcast(&ToolsApplicationRequestBus::Events::AddDirtyEntity, GetEntityId()); EditorEntitySortNotificationBus::Event(GetEntityId(), &EditorEntitySortNotificationBus::Events::ChildEntityOrderArrayUpdated); } @@ -308,9 +318,8 @@ namespace AzToolsFramework isPrefabEnabled, &AzFramework::ApplicationRequests::IsPrefabSystemEnabled); if (isPrefabEnabled) { - PostLoad(); + m_shouldSanityCheckStateAfterPropagation = true; } - // Send out that the order for our entity is now updated EditorEntitySortNotificationBus::Event(GetEntityId(), &EditorEntitySortNotificationBus::Events::ChildEntityOrderArrayUpdated); } @@ -336,6 +345,73 @@ namespace AzToolsFramework m_entityOrderIsDirty = false; } + void EditorEntitySortComponent::SanitizeOrderEntryArray() + { + bool shouldEmitDirtyState = false; + + // Remove invalid and duplicate entries that point at non-existent entities + AZStd::unordered_set duplicateIds; + for (auto it = m_childEntityOrderArray.begin(); it != m_childEntityOrderArray.end();) + { + if (!it->IsValid() || GetEntityById(*it) == nullptr || duplicateIds.contains(*it)) + { + it = m_childEntityOrderArray.erase(it); + shouldEmitDirtyState = true; + } + else + { + duplicateIds.insert(*it); + ++it; + } + } + + // Append any missing children + EntityIdList children; + AZ::TransformBus::EventResult(children, GetEntityId(), &AZ::TransformBus::Events::GetChildren); + for (auto it = m_childEntityOrderArray.begin(); it != m_childEntityOrderArray.end(); ++it) + { + if (auto removedChildrenIt = AZStd::remove(children.begin(), children.end(), *it); removedChildrenIt != children.end()) + { + children.erase(removedChildrenIt); + } + } + + AZStd::sort(children.begin(), children.end(), [](AZ::EntityId lhs, AZ::EntityId rhs) + { + return GetEntityById(lhs)->GetName() < GetEntityById(rhs)->GetName(); + }); + + if (!children.empty()) + { + shouldEmitDirtyState = true; + EntityOrderArray::iterator insertPosition = GetFirstSelectedEntityPosition(); + if (insertPosition != m_childEntityOrderArray.end()) + { + ++insertPosition; + } + m_childEntityOrderArray.insert(insertPosition, children.begin(), children.end()); + } + + // Clear out the vector to be rebuilt from persistent id + m_childEntityOrderEntryArray.resize(m_childEntityOrderArray.size()); + for (size_t i = 0; i < m_childEntityOrderArray.size(); ++i) + { + m_childEntityOrderEntryArray[i] = { + m_childEntityOrderArray[i], + static_cast(i) + }; + } + + RebuildEntityOrderCache(); + + if (shouldEmitDirtyState) + { + ToolsApplicationRequests::Bus::Broadcast(&ToolsApplicationRequests::Bus::Events::AddDirtyEntity, GetEntityId()); + } + + m_entityOrderIsDirty = false; + } + void EditorEntitySortComponent::PostLoad() { // Clear out the vector to be rebuilt from persistent id @@ -383,7 +459,7 @@ namespace AzToolsFramework firstSelectedEntityPos = selectedEntityPos < firstSelectedEntityPos ? selectedEntityPos : firstSelectedEntityPos; } - return firstSelectedEntityPos == m_childEntityOrderArray.end() ? m_childEntityOrderArray.begin() : firstSelectedEntityPos; + return firstSelectedEntityPos; } } } // namespace AzToolsFramework diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/Entity/EditorEntitySortComponent.h b/Code/Framework/AzToolsFramework/AzToolsFramework/Entity/EditorEntitySortComponent.h index 806e903c96..a4715fb041 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/Entity/EditorEntitySortComponent.h +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/Entity/EditorEntitySortComponent.h @@ -23,6 +23,8 @@ namespace AzToolsFramework , public EditorEntityContextNotificationBus::Handler , public AzToolsFramework::Prefab::PrefabPublicNotificationBus::Handler { + friend class JsonEditorEntitySortComponentSerializer; + public: AZ_COMPONENT(EditorEntitySortComponent, "{6EA1E03D-68B2-466D-97F7-83998C8C27F0}", EditorComponentBase); @@ -64,6 +66,8 @@ namespace AzToolsFramework void PrepareSave(); void PostLoad(); + void SanitizeOrderEntryArray(); + class EntitySortSerializationEvents : public AZ::SerializeContext::IEventHandler { @@ -112,6 +116,7 @@ namespace AzToolsFramework bool m_entityOrderIsDirty = true; ///< This flag indicates our stored serialization order data is out of date and must be rebuilt before serialization occurs bool m_ignoreIncomingOrderChanges = false; ///< This is set when prefab propagation occurs so that non-authored order changes can be ignored + bool m_shouldSanityCheckStateAfterPropagation = false; //< This is set after activation, to queue a cleanup of any invalid state after the next prefab propagation. }; } } // namespace AzToolsFramework diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/Entity/EditorEntitySortComponentSerializer.cpp b/Code/Framework/AzToolsFramework/AzToolsFramework/Entity/EditorEntitySortComponentSerializer.cpp new file mode 100644 index 0000000000..0ec13cedda --- /dev/null +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/Entity/EditorEntitySortComponentSerializer.cpp @@ -0,0 +1,137 @@ +/* + * Copyright (c) Contributors to the Open 3D Engine Project. + * For complete copyright and license terms please see the LICENSE at the root of this distribution. + * + * SPDX-License-Identifier: Apache-2.0 OR MIT + * + */ + +#include +#include +#include +#include + +namespace AzToolsFramework::Components +{ + AZ_CLASS_ALLOCATOR_IMPL(JsonEditorEntitySortComponentSerializer, AZ::SystemAllocator, 0); + + AZ::JsonSerializationResult::Result JsonEditorEntitySortComponentSerializer::Load( + void* outputValue, + [[maybe_unused]] const AZ::Uuid& outputValueTypeId, + const rapidjson::Value& inputValue, + AZ::JsonDeserializerContext& context) + { + namespace JSR = AZ::JsonSerializationResult; + + AZ_Assert( + azrtti_typeid() == outputValueTypeId, + "Unable to deserialize EditorEntitySortComponent from json because the provided type is %s.", + outputValueTypeId.ToString().c_str()); + + EditorEntitySortComponent* sortComponentInstance = reinterpret_cast(outputValue); + AZ_Assert(sortComponentInstance, "Output value for JsonEditorEntitySortComponentSerializer can't be null."); + + JSR::ResultCode result(JSR::Tasks::ReadField); + { + JSR::ResultCode componentIdLoadResult = ContinueLoadingFromJsonObjectField( + &sortComponentInstance->m_id, azrtti_typeidm_id)>(), inputValue, + "Id", context); + + result.Combine(componentIdLoadResult); + } + + { + sortComponentInstance->m_childEntityOrderArray.clear(); + JSR::ResultCode enryLoadResult = ContinueLoadingFromJsonObjectField( + &sortComponentInstance->m_childEntityOrderArray, + azrtti_typeidm_childEntityOrderArray)>(), inputValue, "Child Entity Order", + context); + + // Migrate ChildEntityOrderEntryArray -> ChildEntityOrderArray + if (sortComponentInstance->m_childEntityOrderArray.empty()) + { + enryLoadResult = ContinueLoadingFromJsonObjectField( + &sortComponentInstance->m_childEntityOrderEntryArray, + azrtti_typeidm_childEntityOrderEntryArray)>(), inputValue, + "ChildEntityOrderEntryArray", context); + + AZStd::sort( + sortComponentInstance->m_childEntityOrderEntryArray.begin(), + sortComponentInstance->m_childEntityOrderEntryArray.end(), + [](const EditorEntitySortComponent::EntityOrderEntry& lhs, + const EditorEntitySortComponent::EntityOrderEntry& rhs) -> bool + { + return lhs.m_sortIndex < rhs.m_sortIndex; + }); + + // Sort by index and copy to the order array, any duplicates or invalid entries will be cleaned up by the sanitization pass + sortComponentInstance->m_childEntityOrderArray.resize(sortComponentInstance->m_childEntityOrderEntryArray.size()); + for (size_t i = 0; i < sortComponentInstance->m_childEntityOrderEntryArray.size(); ++i) + { + sortComponentInstance->m_childEntityOrderArray[i] = sortComponentInstance->m_childEntityOrderEntryArray[i].m_entityId; + } + } + + sortComponentInstance->RebuildEntityOrderCache(); + + result.Combine(enryLoadResult); + } + + return context.Report( + result, + result.GetProcessing() != JSR::Processing::Halted ? "Successfully loaded EditorEntitySortComponent information." + : "Failed to load EditorEntitySortComponent information."); + } + + AZ::JsonSerializationResult::Result JsonEditorEntitySortComponentSerializer::Store( + rapidjson::Value& outputValue, + const void* inputValue, + const void* defaultValue, + [[maybe_unused]] const AZ::Uuid& valueTypeId, + AZ::JsonSerializerContext& context) + { + namespace JSR = AZ::JsonSerializationResult; + + AZ_Assert( + azrtti_typeid() == valueTypeId, + "Unable to Serialize EditorEntitySortComponent because the provided type is %s.", + valueTypeId.ToString().c_str()); + + const EditorEntitySortComponent* sortComponentInstance = reinterpret_cast(inputValue); + AZ_Assert(sortComponentInstance, "Input value for JsonEditorEntitySortComponentSerializer can't be null."); + const EditorEntitySortComponent* defaultsortComponentInstance = + reinterpret_cast(defaultValue); + + JSR::ResultCode result(JSR::Tasks::WriteValue); + { + AZ::ScopedContextPath subPathName(context, "m_id"); + const AZ::ComponentId* componentId = &sortComponentInstance->m_id; + const AZ::ComponentId* defaultComponentId = + defaultsortComponentInstance ? &defaultsortComponentInstance->m_id : nullptr; + + JSR::ResultCode resultComponentId = ContinueStoringToJsonObjectField( + outputValue, "Id", componentId, defaultComponentId, azrtti_typeidm_id)>(), + context); + + result.Combine(resultComponentId); + } + + { + AZ::ScopedContextPath subPathName(context, "m_childEntityOrderArray"); + const EntityOrderArray* childEntityOrderArray = &sortComponentInstance->m_childEntityOrderArray; + const EntityOrderArray* defaultChildEntityOrderArray = + defaultsortComponentInstance ? &defaultsortComponentInstance->m_childEntityOrderArray : nullptr; + + JSR::ResultCode resultParentEntityId = ContinueStoringToJsonObjectField( + outputValue, "Child Entity Order", childEntityOrderArray, defaultChildEntityOrderArray, + azrtti_typeidm_childEntityOrderArray)>(), context); + + result.Combine(resultParentEntityId); + } + + return context.Report( + result, + result.GetProcessing() != JSR::Processing::Halted ? "Successfully stored EditorEntitySortComponent information." + : "Failed to store EditorEntitySortComponent information."); + } +} // namespace AzToolsFramework::Components diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/Entity/EditorEntitySortComponentSerializer.h b/Code/Framework/AzToolsFramework/AzToolsFramework/Entity/EditorEntitySortComponentSerializer.h new file mode 100644 index 0000000000..29d1f9c14a --- /dev/null +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/Entity/EditorEntitySortComponentSerializer.h @@ -0,0 +1,31 @@ +/* + * Copyright (c) Contributors to the Open 3D Engine Project. + * For complete copyright and license terms please see the LICENSE at the root of this distribution. + * + * SPDX-License-Identifier: Apache-2.0 OR MIT + * + */ + +#pragma once + +#include +#include + +namespace AzToolsFramework::Components +{ + class JsonEditorEntitySortComponentSerializer + : public AZ::BaseJsonSerializer + { + public: + AZ_RTTI(JsonEditorEntitySortComponentSerializer, "{5104782E-B34F-4D87-B1DF-BDFB1AF20D58}", BaseJsonSerializer); + AZ_CLASS_ALLOCATOR_DECL; + + AZ::JsonSerializationResult::Result Load( + void* outputValue, const AZ::Uuid& outputValueTypeId, const rapidjson::Value& inputValue, + AZ::JsonDeserializerContext& context) override; + + AZ::JsonSerializationResult::Result Store( + rapidjson::Value& outputValue, const void* inputValue, const void* defaultValue, const AZ::Uuid& valueTypeId, + AZ::JsonSerializerContext& context) override; + }; +} // namespace AzToolsFramework::Components diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/Instance/InstanceUpdateExecutor.cpp b/Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/Instance/InstanceUpdateExecutor.cpp index 9ef74167a6..6fe3e9e92b 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/Instance/InstanceUpdateExecutor.cpp +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/Instance/InstanceUpdateExecutor.cpp @@ -20,6 +20,7 @@ #include #include #include +#include namespace AzToolsFramework { @@ -244,10 +245,10 @@ namespace AzToolsFramework selectedEntityIds.erase(entityIdIterator--); } } - ToolsApplicationRequestBus::Broadcast(&ToolsApplicationRequests::SetSelectedEntities, selectedEntityIds); - // Notify Propagation has ended + // Notify Propagation has ended, then update selection (which is frozen during propagation, so this order matters) PrefabPublicNotificationBus::Broadcast(&PrefabPublicNotifications::OnPrefabInstancePropagationEnd); + ToolsApplicationRequestBus::Broadcast(&ToolsApplicationRequests::SetSelectedEntities, selectedEntityIds); } m_updatingTemplateInstancesInQueue = false; diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/PrefabDomUtils.h b/Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/PrefabDomUtils.h index 7cab24ad9f..89d1a046e5 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/PrefabDomUtils.h +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/PrefabDomUtils.h @@ -28,6 +28,9 @@ namespace AzToolsFramework inline static const char* EntityIdName = "Id"; inline static const char* EntitiesName = "Entities"; inline static const char* ContainerEntityName = "ContainerEntity"; + inline static const char* ComponentsName = "Components"; + inline static const char* EntityOrderName = "Child Entity Order"; + inline static const char* TypeName = "$type"; /** * Find Prefab value from given parent value and target value's name. diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/PrefabPublicHandler.cpp b/Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/PrefabPublicHandler.cpp index 32600853fd..26cc16f34b 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/PrefabPublicHandler.cpp +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/PrefabPublicHandler.cpp @@ -9,6 +9,7 @@ #include #include #include +#include #include #include @@ -29,6 +30,7 @@ #include #include #include +#include #include @@ -595,8 +597,41 @@ namespace AzToolsFramework Instance& entityOwningInstance = owningInstanceOfParentEntity->get(); + // Get the template for our owning instance from the root prefab DOM and use that to generate our patch + AZStd::vector pathOfInstances; + + InstanceOptionalReference rootInstance = owningInstanceOfParentEntity; + while (rootInstance->get().GetParentInstance() != AZStd::nullopt) + { + pathOfInstances.emplace_back(rootInstance); + rootInstance = rootInstance->get().GetParentInstance(); + } + + AZStd::string aliasPathResult = ""; + for (auto instanceIter = pathOfInstances.rbegin(); instanceIter != pathOfInstances.rend(); ++instanceIter) + { + aliasPathResult.append("/Instances/"); + aliasPathResult.append((*instanceIter)->get().GetInstanceAlias()); + } + + PrefabDomPath rootPrefabDomPath(aliasPathResult.c_str()); + + PrefabDom& rootPrefabTemplateDom = m_prefabSystemComponentInterface->FindTemplateDom(rootInstance->get().GetTemplateId()); + + auto instanceDomFromRootValue = rootPrefabDomPath.Get(rootPrefabTemplateDom); + if (!instanceDomFromRootValue) + { + return AZ::Failure("Could not load Instance DOM from the top level ancestor's DOM."); + } + + PrefabDomValueReference instanceDomFromRoot = *instanceDomFromRootValue; + if (!instanceDomFromRoot.has_value()) + { + return AZ::Failure("Could not load Instance DOM from the top level ancestor's DOM."); + } + PrefabDom instanceDomBeforeUpdate; - m_instanceToTemplateInterface->GenerateDomForInstance(instanceDomBeforeUpdate, entityOwningInstance); + instanceDomBeforeUpdate.CopyFrom(instanceDomFromRoot.value().get(), instanceDomBeforeUpdate.GetAllocator()); ScopedUndoBatch undoBatch("Add Entity"); @@ -674,6 +709,9 @@ namespace AzToolsFramework bool isInstanceContainerEntity = IsInstanceContainerEntity(entityId) && !IsLevelInstanceContainerEntity(entityId); bool isNewParentOwnedByDifferentInstance = false; + bool isInFocusTree = m_prefabFocusPublicInterface->IsOwningPrefabInFocusHierarchy(entityId); + bool isOwnedByFocusedPrefabInstance = m_prefabFocusPublicInterface->IsOwningPrefabBeingFocused(entityId); + if (beforeParentId != afterParentId) { // If the entity parent changed, verify if the owning instance changed too @@ -727,7 +765,7 @@ namespace AzToolsFramework } } - if (isInstanceContainerEntity) + if (isInFocusTree && !isOwnedByFocusedPrefabInstance) { if (isNewParentOwnedByDifferentInstance) { @@ -1653,6 +1691,144 @@ namespace AzToolsFramework return true; } + void PrefabPublicHandler::AddNewEntityToSortOrder( + Instance& owningInstance, + PrefabDom& domToAddEntityUnder, + const EntityAlias& parentEntityAlias, + const EntityAlias& entityToAddAlias) + { + // Find the parent entity to get its sort order component + auto findParentEntity = [&]() -> rapidjson::Value* + { + if (auto containerEntityIter = domToAddEntityUnder.FindMember(PrefabDomUtils::ContainerEntityName); + containerEntityIter != domToAddEntityUnder.MemberEnd()) + { + if (parentEntityAlias == containerEntityIter->value[PrefabDomUtils::EntityIdName].GetString()) + { + return &containerEntityIter->value; + } + } + + if (auto entitiesIter = domToAddEntityUnder.FindMember(PrefabDomUtils::EntitiesName); + entitiesIter != domToAddEntityUnder.MemberEnd()) + { + for (auto entityIter = entitiesIter->value.MemberBegin(); entityIter != entitiesIter->value.MemberEnd(); ++entityIter) + { + if (parentEntityAlias == entityIter->value[PrefabDomUtils::EntityIdName].GetString()) + { + return &entityIter->value; + } + } + } + + return nullptr; + }; + + rapidjson::Value* parentEntityValue = findParentEntity(); + if (parentEntityValue == nullptr) + { + return; + } + + // Get the list of selected entities, we'll insert our duplicated entities after the last selected + // sibling in their parent's list, e.g. for: + // - Entity1 + // - Entity2 (selected) + // - Entity3 + // - Entity4 (selected) + // - Entity5 + // Our duplicate selection command would create duplicate Entity2 and Entity4 and insert them after Entity4: + // - Entity1 + // - Entity2 + // - Entity3 + // - Entity4 + // - Entity2 (new, selected after duplicate) + // - Entity4 (new, selected after duplicate) + // - Entity5 + AzToolsFramework::EntityIdList selectedEntities; + AzToolsFramework::ToolsApplicationRequestBus::BroadcastResult( + selectedEntities, &AzToolsFramework::ToolsApplicationRequests::GetSelectedEntities); + + // Find the EditorEntitySortComponent DOM + auto componentsIter = parentEntityValue->FindMember(PrefabDomUtils::ComponentsName); + if (componentsIter == parentEntityValue->MemberEnd()) + { + return; + } + + for (auto componentIter = componentsIter->value.MemberBegin(); componentIter != componentIter->value.MemberEnd(); + ++componentIter) + { + // Check the component type + auto typeFieldIter = componentIter->value.FindMember(PrefabDomUtils::TypeName); + if (typeFieldIter == componentIter->value.MemberEnd()) + { + continue; + } + + AZ::JsonDeserializerSettings jsonDeserializerSettings; + AZ::Uuid typeId = AZ::Uuid::CreateNull(); + AZ::JsonSerialization::LoadTypeId(typeId, typeFieldIter->value); + + if (typeId != azrtti_typeid()) + { + continue; + } + + // Check for the entity order field + auto orderMembersIter = componentIter->value.FindMember(PrefabDomUtils::EntityOrderName); + if (orderMembersIter == componentIter->value.MemberEnd() || !orderMembersIter->value.IsArray()) + { + continue; + } + + // Scan for the last selected entity in the list (if any) to determine where to add our entries + rapidjson::Value newOrder(rapidjson::kArrayType); + auto insertValuesAfter = orderMembersIter->value.End(); + for (auto orderMemberIter = orderMembersIter->value.Begin(); orderMemberIter != orderMembersIter->value.End(); + ++orderMemberIter) + { + if (!orderMemberIter->IsString()) + { + continue; + } + const char* value = orderMemberIter->GetString(); + for (AZ::EntityId selectedEntity : selectedEntities) + { + auto alias = owningInstance.GetEntityAlias(selectedEntity); + if (alias.has_value() && alias.value().get() == value) + { + insertValuesAfter = orderMemberIter; + break; + } + } + } + + // Construct our new array with the new order - insertion may happen at end, so check for that in the loop itself + for (auto orderMemberIter = orderMembersIter->value.Begin();; ++orderMemberIter) + { + if (orderMemberIter != orderMembersIter->value.End()) + { + newOrder.PushBack(orderMemberIter->Move(), domToAddEntityUnder.GetAllocator()); + } + if (orderMemberIter == insertValuesAfter) + { + newOrder.PushBack( + rapidjson::Value(entityToAddAlias.c_str(), domToAddEntityUnder.GetAllocator()), + domToAddEntityUnder.GetAllocator()); + } + if (orderMemberIter == orderMembersIter->value.End()) + { + break; + } + } + + // Replace the order with our newly constructed one + orderMembersIter->value.Swap(newOrder); + break; + } + } + void PrefabPublicHandler::DuplicateNestedEntitiesInInstance(Instance& commonOwningInstance, const AZStd::vector& entities, PrefabDom& domToAddDuplicatedEntitiesUnder, EntityIdList& duplicatedEntityIds, AZStd::unordered_map& oldAliasToNewAliasMap) @@ -1710,6 +1886,73 @@ namespace AzToolsFramework PrefabDom entityDomAfter(&domToAddDuplicatedEntitiesUnder.GetAllocator()); entityDomAfter.Parse(newEntityDomString.toUtf8().constData()); + EntityAlias parentEntityAlias; + if (auto componentsIter = entityDomAfter.FindMember(PrefabDomUtils::ComponentsName); + componentsIter != entityDomAfter.MemberEnd()) + { + auto checkComponent = [&](const rapidjson::Value& value) -> bool + { + if (!value.IsObject()) + { + return false; + } + + // Check the component type + auto typeFieldIter = value.FindMember(PrefabDomUtils::TypeName); + if (typeFieldIter == value.MemberEnd()) + { + return false; + } + + AZ::JsonDeserializerSettings jsonDeserializerSettings; + AZ::Uuid typeId = AZ::Uuid::CreateNull(); + AZ::JsonSerialization::LoadTypeId(typeId, typeFieldIter->value); + + // Prefabs get serialized with the Editor transform component type, check for that + if (typeId != azrtti_typeid()) + { + return false; + } + + if (auto parentEntityIter = value.FindMember("Parent Entity"); + parentEntityIter != value.MemberEnd()) + { + parentEntityAlias = parentEntityIter->value.GetString(); + return true; + } + return false; + }; + + if (componentsIter->value.IsObject()) + { + for (auto componentIter = componentsIter->value.MemberBegin(); componentIter != componentsIter->value.MemberEnd(); + ++componentIter) + { + if (checkComponent(componentIter->value)) + { + break; + } + } + } + else if (componentsIter->value.IsArray()) + { + for (auto componentIter = componentsIter->value.Begin(); componentIter != componentsIter->value.End(); + ++componentIter) + { + if (checkComponent(*componentIter)) + { + break; + } + } + } + } + + // Insert our entity into its parent's sort order + if (!parentEntityAlias.empty()) + { + AddNewEntityToSortOrder(commonOwningInstance, domToAddDuplicatedEntitiesUnder, parentEntityAlias, newEntityAlias); + } + // Add the new Entity DOM to the Entities member of the instance rapidjson::Value aliasName(newEntityAlias.c_str(), static_cast(newEntityAlias.length()), domToAddDuplicatedEntitiesUnder.GetAllocator()); entitiesIter->value.AddMember(AZStd::move(aliasName), entityDomAfter, domToAddDuplicatedEntitiesUnder.GetAllocator()); diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/PrefabPublicHandler.h b/Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/PrefabPublicHandler.h index 4961be9d77..dd071ac09f 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/PrefabPublicHandler.h +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/PrefabPublicHandler.h @@ -78,6 +78,8 @@ namespace AzToolsFramework InstanceOptionalReference GetOwnerInstanceByEntityId(AZ::EntityId entityId) const; bool EntitiesBelongToSameInstance(const EntityIdList& entityIds) const; + void AddNewEntityToSortOrder(Instance& owningInstance, PrefabDom& domToAddEntityUnder, + const EntityAlias& parentEntityAlias, const EntityAlias& entityToAddAlias); /** * Duplicate a list of entities owned by a common owning instance by directly diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/UI/PropertyEditor/EntityPropertyEditor.cpp b/Code/Framework/AzToolsFramework/AzToolsFramework/UI/PropertyEditor/EntityPropertyEditor.cpp index 9ecbdf5ffc..fa419d5f14 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/UI/PropertyEditor/EntityPropertyEditor.cpp +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/UI/PropertyEditor/EntityPropertyEditor.cpp @@ -1599,7 +1599,6 @@ namespace AzToolsFramework for (size_t entityIndex = 1; entityIndex < m_selectedEntityIds.size(); ++entityIndex) { entity = GetSelectedEntityById(m_selectedEntityIds[entityIndex]); - AZ_Assert(entity, "Entity id selected for display but no such entity exists"); if (!entity) { continue; diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/aztoolsframework_files.cmake b/Code/Framework/AzToolsFramework/AzToolsFramework/aztoolsframework_files.cmake index d61d6486a9..9a891498de 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/aztoolsframework_files.cmake +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/aztoolsframework_files.cmake @@ -148,6 +148,8 @@ set(FILES Entity/EditorEntitySortBus.h Entity/EditorEntitySortComponent.cpp Entity/EditorEntitySortComponent.h + Entity/EditorEntitySortComponentSerializer.cpp + Entity/EditorEntitySortComponentSerializer.h Entity/EditorEntityTransformBus.h Entity/PrefabEditorEntityOwnershipInterface.h Entity/PrefabEditorEntityOwnershipService.h From 4be1e68bad1b627668a4517b00526bba6cc7acea Mon Sep 17 00:00:00 2001 From: Danilo Aimini <82231674+AMZN-daimini@users.noreply.github.com> Date: Fri, 19 Nov 2021 10:45:06 -0800 Subject: [PATCH 04/23] Fix oversight from recent change to PrefabFocusHandler internals. (#5794) * Fix oversight from recent change to PrefabFocusHandler internals. Signed-off-by: Danilo Aimini <82231674+AMZN-daimini@users.noreply.github.com> * Introduce check for null instance in case this is called before the Prefab Focus Handler is initialized. Signed-off-by: Danilo Aimini <82231674+AMZN-daimini@users.noreply.github.com> --- .../AzToolsFramework/Prefab/PrefabFocusHandler.cpp | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/PrefabFocusHandler.cpp b/Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/PrefabFocusHandler.cpp index 744c53ef5a..3d764554ef 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/PrefabFocusHandler.cpp +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/PrefabFocusHandler.cpp @@ -212,7 +212,17 @@ namespace AzToolsFramework::Prefab AZ::EntityId PrefabFocusHandler::GetFocusedPrefabContainerEntityId([[maybe_unused]] AzFramework::EntityContextId entityContextId) const { - return m_focusedInstanceContainerEntityId; + if (m_focusedInstanceContainerEntityId.IsValid()) + { + return m_focusedInstanceContainerEntityId; + } + + if (auto instance = GetReferenceFromContainerEntityId(m_focusedInstanceContainerEntityId); instance.has_value()) + { + return instance->get().GetContainerEntityId(); + } + + return AZ::EntityId(); } bool PrefabFocusHandler::IsOwningPrefabBeingFocused(AZ::EntityId entityId) const From 95da7fcb645224d4dcd50ede2fe282407927e31b Mon Sep 17 00:00:00 2001 From: Allen Jackson <23512001+jackalbe@users.noreply.github.com> Date: Fri, 19 Nov 2021 13:17:21 -0600 Subject: [PATCH 05/23] {lyn7060} adding 'Save as Prefab' for ProcPrefab (#5678) This adds the context menu to the Asset Browser to "Save as Prefab.." so that a Procedural Prefab asset template can be saved in the source assets folder Signed-off-by: Allen Jackson <23512001+jackalbe@users.noreply.github.com> --- .../PrefabGroup/ProceduralAssetHandler.cpp | 93 ++++++++++++++++++- 1 file changed, 91 insertions(+), 2 deletions(-) diff --git a/Gems/Prefab/PrefabBuilder/PrefabGroup/ProceduralAssetHandler.cpp b/Gems/Prefab/PrefabBuilder/PrefabGroup/ProceduralAssetHandler.cpp index 17ed4d9c0c..bcfedad8a8 100644 --- a/Gems/Prefab/PrefabBuilder/PrefabGroup/ProceduralAssetHandler.cpp +++ b/Gems/Prefab/PrefabBuilder/PrefabGroup/ProceduralAssetHandler.cpp @@ -8,12 +8,16 @@ #include #include +#include #include #include -#include +#include +#include +#include #include +#include #include -#include +#include namespace AZ::Prefab { @@ -21,6 +25,7 @@ namespace AZ::Prefab class PrefabGroupAssetHandler::AssetTypeInfoHandler final : public AZ::AssetTypeInfoBus::Handler + , protected AzToolsFramework::AssetBrowser::AssetBrowserInteractionNotificationBus::Handler { public: AZ_CLASS_ALLOCATOR(AssetTypeInfoHandler, AZ::SystemAllocator, 0); @@ -31,15 +36,21 @@ namespace AZ::Prefab const char* GetGroup() const override; const char* GetBrowserIcon() const override; void GetAssetTypeExtensions(AZStd::vector& extensions) override; + + // AzToolsFramework::AssetBrowser::AssetBrowserInteractionNotificationBus::Handler + void AddContextMenuActions(QWidget* caller, QMenu* menu, const AZStd::vector& entries) override; + bool SaveAsAuthoredPrefab(const AZ::Data::AssetId& assetId, const char* destinationFilename); }; PrefabGroupAssetHandler::AssetTypeInfoHandler::AssetTypeInfoHandler() { AZ::AssetTypeInfoBus::Handler::BusConnect(azrtti_typeid()); + AzToolsFramework::AssetBrowser::AssetBrowserInteractionNotificationBus::Handler::BusConnect(); } PrefabGroupAssetHandler::AssetTypeInfoHandler::~AssetTypeInfoHandler() { + AzToolsFramework::AssetBrowser::AssetBrowserInteractionNotificationBus::Handler::BusDisconnect(); AZ::AssetTypeInfoBus::Handler::BusDisconnect(azrtti_typeid()); } @@ -68,6 +79,84 @@ namespace AZ::Prefab extensions.push_back(PrefabGroupAssetHandler::s_Extension); } + void PrefabGroupAssetHandler::AssetTypeInfoHandler::AddContextMenuActions( + [[maybe_unused]] QWidget* caller, + QMenu* menu, + const AZStd::vector& entries) + { + using namespace AzToolsFramework::AssetBrowser; + auto entryIt = AZStd::find_if + ( + entries.begin(), + entries.end(), + [](const AssetBrowserEntry* entry) -> bool + { + return entry->GetEntryType() == AssetBrowserEntry::AssetEntryType::Product; + } + ); + + if (entryIt == entries.end()) + { + return; + } + else if ((*entryIt)->GetEntryType() == AssetBrowserEntry::AssetEntryType::Product) + { + ProductAssetBrowserEntry* product = azrtti_cast(*entryIt); + if (product->GetAssetType() == azrtti_typeid()) + { + AZ::Data::AssetId assetId = product->GetAssetId(); + menu->addAction("Save as Prefab...", [assetId, this]() + { + QString filePath = AzQtComponents::FileDialog::GetSaveFileName(nullptr, QString("Save to file"), "", QString("Prefab file (*.prefab)")); + if (filePath.isEmpty()) + { + return; + } + if (SaveAsAuthoredPrefab(assetId, filePath.toUtf8().data())) + { + AZ_Printf("Prefab", "Prefab was saved to a .prefab file %s", filePath.toUtf8().data()); + } + }); + } + } + } + + bool PrefabGroupAssetHandler::AssetTypeInfoHandler::SaveAsAuthoredPrefab(const AZ::Data::AssetId& assetId, const char* destinationFilename) + { + using namespace AzToolsFramework::Prefab; + using namespace AZ::Data; + + auto procPrefabAsset = AssetManager::Instance().GetAsset(assetId, AssetLoadBehavior::Default); + const auto status = AssetManager::Instance().BlockUntilLoadComplete(procPrefabAsset); + if (status != AssetData::AssetStatus::Ready) + { + return false; + } + + auto* prefabLoaderInterface = AZ::Interface::Get(); + if (!prefabLoaderInterface) + { + return false; + } + + const auto templateId = procPrefabAsset.GetAs()->GetTemplateId(); + AZStd::string outputJson; + if (prefabLoaderInterface->SaveTemplateToString(templateId, outputJson) == false) + { + return false; + } + + const auto fileMode = AZ::IO::OpenMode::ModeWrite | AZ::IO::OpenMode::ModeCreatePath | AZ::IO::OpenMode::ModeText; + AZ::IO::FileIOStream outputFileStream; + if (outputFileStream.Open(destinationFilename, fileMode) == false) + { + return false; + } + + outputFileStream.Write(outputJson.size(), outputJson.data()); + return true; + } + // PrefabGroupAssetHandler AZStd::string_view PrefabGroupAssetHandler::s_Extension{ "procprefab" }; From af85060856faef554308dadc8251349147680ecc Mon Sep 17 00:00:00 2001 From: amzn-mike <80125227+amzn-mike@users.noreply.github.com> Date: Fri, 19 Nov 2021 13:22:43 -0600 Subject: [PATCH 06/23] [SPEC-7644] Cherry Pick - ParallelDeepAssetReferences is failing intermittently (#5797) * [SPEC-7644] ParallelDeepAssetReferences is failing intermittently (#5721) * Fixed race condition caused by trying to handle asset ready event before asset container has finished filling out all the data structures. Added check to only handle asset ready once init is complete Added unit test to verify fix Signed-off-by: amzn-mike <80125227+amzn-mike@users.noreply.github.com> * Re-enable test Signed-off-by: amzn-mike <80125227+amzn-mike@users.noreply.github.com> * Add missing space to error message Signed-off-by: amzn-mike <80125227+amzn-mike@users.noreply.github.com> * Add comment on sleep Signed-off-by: amzn-mike <80125227+amzn-mike@users.noreply.github.com> * Collapse nested namespace Signed-off-by: amzn-mike <80125227+amzn-mike@users.noreply.github.com> * Collapse nested namespace Signed-off-by: amzn-mike <80125227+amzn-mike@users.noreply.github.com> (cherry picked from commit 56900484fcecab198920d32d8b2c6fd89e30d50b) # Conflicts: # Code/Framework/AzCore/AzCore/Asset/AssetContainer.cpp * Fix indentation Signed-off-by: amzn-mike <80125227+amzn-mike@users.noreply.github.com> --- .../AzCore/AzCore/Asset/AssetContainer.cpp | 83 +++++++++++-------- .../AzCore/AzCore/Asset/AssetContainer.h | 16 ++-- .../AzCore/AzCore/Asset/AssetManager.h | 20 ++--- .../Tests/Asset/AssetManagerLoadingTests.cpp | 49 +++++++++-- 4 files changed, 114 insertions(+), 54 deletions(-) diff --git a/Code/Framework/AzCore/AzCore/Asset/AssetContainer.cpp b/Code/Framework/AzCore/AzCore/Asset/AssetContainer.cpp index ce15c7bc4e..eb75852508 100644 --- a/Code/Framework/AzCore/AzCore/Asset/AssetContainer.cpp +++ b/Code/Framework/AzCore/AzCore/Asset/AssetContainer.cpp @@ -37,6 +37,43 @@ namespace AZ AssetLoadBus::MultiHandler::BusDisconnect(); } + AZStd::vector>> AssetContainer::CreateAndQueueDependentAssets( + const AZStd::vector& dependencyInfoList, const AssetLoadParameters& loadParamsCopyWithNoLoadingFilter) + { + AZStd::vector>> dependencyAssets; + + for (auto& thisInfo : dependencyInfoList) + { + auto dependentAsset = AssetManager::Instance().FindOrCreateAsset( + thisInfo.m_assetId, thisInfo.m_assetType, AZ::Data::AssetLoadBehavior::Default); + + if (!dependentAsset || !dependentAsset.GetId().IsValid()) + { + AZ_Warning("AssetContainer", false, "Dependency Asset %s (%s) was not found\n", + thisInfo.m_assetId.ToString().c_str(), thisInfo.m_relativePath.c_str()); + RemoveWaitingAsset(thisInfo.m_assetId); + continue; + } + dependencyAssets.emplace_back(thisInfo, AZStd::move(dependentAsset)); + } + + // Queue the loading of all of the dependent assets before loading the root asset. + for (auto& [dependentAssetInfo, dependentAsset] : dependencyAssets) + { + // Queue each asset to load. + auto queuedDependentAsset = AssetManager::Instance().GetAssetInternal( + dependentAsset.GetId(), dependentAsset.GetType(), + AZ::Data::AssetLoadBehavior::Default, loadParamsCopyWithNoLoadingFilter, + dependentAssetInfo, HasPreloads(dependentAsset.GetId())); + + // Verify that the returned asset reference matches the one that we found or created and queued to load. + AZ_Assert(dependentAsset == queuedDependentAsset, "GetAssetInternal returned an unexpected asset reference for Asset %s", + dependentAsset.GetId().ToString().c_str()); + } + + return dependencyAssets; + } + void AssetContainer::AddDependentAssets(Asset rootAsset, const AssetLoadParameters& loadParams) { AssetId rootAssetId = rootAsset.GetId(); @@ -183,34 +220,7 @@ namespace AZ // Since we've set the load filter to not load dependencies, we need to ensure all the assets are created beforehand // so the dependencies can be hooked up as soon as each asset gets serialized in, even if they start getting serialized // while we're still in the middle of triggering all of the asset loads below. - for (auto& thisInfo : dependencyInfoList) - { - auto dependentAsset = AssetManager::Instance().FindOrCreateAsset( - thisInfo.m_assetId, thisInfo.m_assetType, AZ::Data::AssetLoadBehavior::Default); - - if (!dependentAsset || !dependentAsset.GetId().IsValid()) - { - AZ_Warning("AssetContainer", false, "Dependency Asset %s (%s) was not found\n", - thisInfo.m_assetId.ToString().c_str(), thisInfo.m_relativePath.c_str()); - RemoveWaitingAsset(thisInfo.m_assetId); - continue; - } - dependencyAssets.emplace_back(thisInfo, AZStd::move(dependentAsset)); - } - - // Queue the loading of all of the dependent assets before loading the root asset. - for (auto& [dependentAssetInfo, dependentAsset] : dependencyAssets) - { - // Queue each asset to load. - auto queuedDependentAsset = AssetManager::Instance().GetAssetInternal( - dependentAsset.GetId(), dependentAsset.GetType(), - AZ::Data::AssetLoadBehavior::Default, loadParamsCopyWithNoLoadingFilter, - dependentAssetInfo, HasPreloads(dependentAsset.GetId())); - - // Verify that the returned asset reference matches the one that we found or created and queued to load. - AZ_Assert(dependentAsset == queuedDependentAsset, "GetAssetInternal returned an unexpected asset reference for Asset %s", - dependentAsset.GetId().ToString().c_str()); - } + dependencyAssets = CreateAndQueueDependentAssets(dependencyInfoList, loadParamsCopyWithNoLoadingFilter); // Add all of the queued dependent assets as dependencies { @@ -349,8 +359,15 @@ namespace AZ void AssetContainer::HandleReadyAsset(Asset asset) { - RemoveFromAllWaitingPreloads(asset->GetId()); - RemoveWaitingAsset(asset->GetId()); + // Wait until we've finished initialization before allowing this + // If a ready event happens before we've gotten all the maps/structures set up, there may be some missing data + // which can lead to a crash + // We'll go through and check the ready status of every dependency immediately after finishing initialization anyway + if (m_initComplete) + { + RemoveFromAllWaitingPreloads(asset->GetId()); + RemoveWaitingAsset(asset->GetId()); + } } void AssetContainer::OnAssetDataLoaded(Asset asset) @@ -389,7 +406,7 @@ namespace AZ AssetManager::Instance().ValidateAndPostLoad(thisAsset, true, false, nullptr); } - void AssetContainer::RemoveFromAllWaitingPreloads(const AssetId& thisId) + void AssetContainer::RemoveFromAllWaitingPreloads(const AssetId& thisId) { AZStd::unordered_set checkList; { @@ -547,7 +564,7 @@ namespace AZ if (!preloadList.empty()) { // This method can be entered as additional NoLoad dependency groups are loaded - the container could - // be in the middle of loading so we need to grab both mutexes. + // be in the middle of loading so we need to grab both mutexes. AZStd::scoped_lock lock(m_readyMutex, m_preloadMutex); for (auto thisListPair = preloadList.begin(); thisListPair != preloadList.end();) @@ -568,7 +585,7 @@ namespace AZ // will load the assets but won't/can't create a circular preload dependency chain if (*thisAsset == rootAssetId) { - AZ_Error("AssetContainer", false, "Circular preload dependency found - %s has a preload" + AZ_Error("AssetContainer", false, "Circular preload dependency found - %s has a preload" "dependency back to root %s\n", thisListPair->first.ToString().c_str(), rootAssetId.ToString().c_str()); diff --git a/Code/Framework/AzCore/AzCore/Asset/AssetContainer.h b/Code/Framework/AzCore/AzCore/Asset/AssetContainer.h index e0091d678f..a05343ed0b 100644 --- a/Code/Framework/AzCore/AzCore/Asset/AssetContainer.h +++ b/Code/Framework/AzCore/AzCore/Asset/AssetContainer.h @@ -24,8 +24,8 @@ namespace AZ // AssetContainer loads an asset and all of its dependencies as a collection which is parallellized as much as possible. // With the container, the data will all load in parallel. Dependent asset loads will still obey the expected rules - // where PreLoad assets will emit OnAssetReady before the parent does, and QueueLoad assets will emit OnAssetReady in - // no guaranteed order. However, the OnAssetContainerReady signals will not emit until all PreLoad and QueueLoad assets + // where PreLoad assets will emit OnAssetReady before the parent does, and QueueLoad assets will emit OnAssetReady in + // no guaranteed order. However, the OnAssetContainerReady signals will not emit until all PreLoad and QueueLoad assets // are ready. NoLoad dependencies are not loaded by default but can be loaded along with their dependencies using the // same rules as above by using the LoadAll dependency rule. class AssetContainer : @@ -36,7 +36,7 @@ namespace AZ AZ_CLASS_ALLOCATOR(AssetContainer, SystemAllocator, 0); AssetContainer() = default; - + AssetContainer(Asset asset, const AssetLoadParameters& loadParams); ~AssetContainer(); @@ -81,6 +81,10 @@ namespace AZ // AssetLoadBus void OnAssetDataLoaded(AZ::Data::Asset asset) override; protected: + + virtual AZStd::vector>> CreateAndQueueDependentAssets( + const AZStd::vector& dependencyInfoList, const AssetLoadParameters& loadParamsCopyWithNoLoadingFilter); + // Waiting assets are those which have not yet signalled ready. In the case of PreLoad dependencies the data may have completed the load cycle but // the Assets aren't considered "Ready" yet if there are PreLoad dependencies still loading and will still be in the list until the point that asset and // All of its preload dependencies have been loaded, when it signals OnAssetReady @@ -97,7 +101,7 @@ namespace AZ void AddDependency(Asset&& addDependency); // Add a "graph section" to our list of dependencies. This checks the catalog for all Pre and Queue load assets which are dependents of the requested asset and kicks off loads - // NoLoads which are encounted are placed in another list and can be loaded on demand with the LoadDependency call. + // NoLoads which are encounted are placed in another list and can be loaded on demand with the LoadDependency call. void AddDependentAssets(Asset rootAsset, const AssetLoadParameters& loadParams); // If "PreLoad" assets are found in the graph these are cached and tracked with both OnAssetReady and OnAssetDataLoaded messages. @@ -117,7 +121,7 @@ namespace AZ // duringInit if we're coming from the checkReady method - containers that start ready don't need to signal void HandleReadyAsset(AZ::Data::Asset asset); - // Optimization to save the lookup in the dependencies map + // Optimization to save the lookup in the dependencies map AssetInternal::WeakAsset m_rootAsset; // The root asset id is stored here semi-redundantly on initialization so that we can still refer to it even if the @@ -136,7 +140,7 @@ namespace AZ AZStd::atomic_bool m_finalNotificationSent{false}; mutable AZStd::recursive_mutex m_preloadMutex; - // AssetId -> List of assets it is still waiting on + // AssetId -> List of assets it is still waiting on PreloadAssetListType m_preloadList; // AssetId -> List of assets waiting on it diff --git a/Code/Framework/AzCore/AzCore/Asset/AssetManager.h b/Code/Framework/AzCore/AzCore/Asset/AssetManager.h index f109bb278c..9666d434c1 100644 --- a/Code/Framework/AzCore/AzCore/Asset/AssetManager.h +++ b/Code/Framework/AzCore/AzCore/Asset/AssetManager.h @@ -169,14 +169,14 @@ namespace AZ /// Register handler with the system for a particular asset type. /// A handler should be registered for each asset type it handles. /// Please note that all the handlers are registered just once during app startup from the main thread - /// and therefore this is not a thread safe method and should not be invoked from different threads. + /// and therefore this is not a thread safe method and should not be invoked from different threads. void RegisterHandler(AssetHandler* handler, const AssetType& assetType); /// Unregister handler from the asset system. /// Please note that all the handlers are unregistered just once during app shutdown from the main thread /// and therefore this is not a thread safe method and should not be invoked from different threads. void UnregisterHandler(AssetHandler* handler); // @} - + // @{ Asset catalog management /// Register a catalog with the system for a particular asset type. /// A catalog should be registered for each asset type it is responsible for. @@ -295,7 +295,7 @@ namespace AZ /** * Old 'legacy' assetIds and asset hints can be automatically replaced with new ones during deserialize / assignment. * This operation can be somewhat costly, and its only useful if the program subsequently re-saves the files its loading so that - * the asset hints and assetIds actually persist. Thus, it can be disabled in situations where you know you are not going to be + * the asset hints and assetIds actually persist. Thus, it can be disabled in situations where you know you are not going to be * saving over or creating new source files (for example builders/background apps) * By default, it is enabled. */ @@ -316,7 +316,7 @@ namespace AZ * This method must be invoked before you start unregistering handlers manually and shutting down the asset manager. * This method ensures that all jobs in flight are either canceled or completed. * This method is automatically called in the destructor but if you are unregistering handlers manually, - * you must invoke it yourself. + * you must invoke it yourself. */ void PrepareShutDown(); @@ -366,7 +366,7 @@ namespace AZ /** * Creates a new shared AssetContainer with an optional loadFilter * **/ - AZStd::shared_ptr CreateAssetContainer(Asset asset, const AssetLoadParameters& loadParams = AssetLoadParameters{}) const; + virtual AZStd::shared_ptr CreateAssetContainer(Asset asset, const AssetLoadParameters& loadParams = AssetLoadParameters{}) const; /** @@ -452,7 +452,7 @@ namespace AZ // Variant of RegisterAssetLoading used for jobs which have been queued and need to verify the status of the asset - // before loading in order to prevent cases where a load is queued, then a blocking load goes through, then the queued + // before loading in order to prevent cases where a load is queued, then a blocking load goes through, then the queued // load is processed. This validation step leaves the loaded (And potentially modified) data as is in that case. bool ValidateAndRegisterAssetLoading(const Asset& asset); @@ -482,7 +482,7 @@ namespace AZ * the blocking. That will result in a single thread deadlock. * * If you need to queue work, the logic needs to be similar to this: - * + * AssetHandler::LoadResult MyAssetHandler::LoadAssetData(const Asset& asset, AZStd::shared_ptr stream, const AZ::Data::AssetFilterCB& assetLoadFilterCB) { @@ -496,13 +496,13 @@ namespace AZ } else { - // queue job to load asset in thread identified by m_loadingThreadId + // queue job to load asset in thread identified by m_loadingThreadId auto* queuedJob = QueueLoadingOnOtherThread(...); // block waiting for queued job to complete queuedJob->BlockUntilComplete(); } - + . . . @@ -525,7 +525,7 @@ namespace AZ //! Result from LoadAssetData - it either finished loading, didn't finish and is waiting for more data, or had an error. enum class LoadResult : u8 { - + Error, // The provided data failed to load correctly MoreDataRequired, // The provided data loaded correctly, but more data is required to finish the asset load LoadComplete // The provided data loaded correctly, and the asset has been created diff --git a/Code/Framework/AzCore/Tests/Asset/AssetManagerLoadingTests.cpp b/Code/Framework/AzCore/Tests/Asset/AssetManagerLoadingTests.cpp index 3f2d9491a7..fdacd80542 100644 --- a/Code/Framework/AzCore/Tests/Asset/AssetManagerLoadingTests.cpp +++ b/Code/Framework/AzCore/Tests/Asset/AssetManagerLoadingTests.cpp @@ -2297,6 +2297,45 @@ namespace UnitTest AssetManager::Destroy(); } + struct MockAssetContainer : AssetContainer + { + MockAssetContainer(Asset assetData, const AssetLoadParameters& loadParams) + { + // Copying the code in the original constructor, we can't call that constructor because it will not invoke our virtual method + m_rootAsset = AssetInternal::WeakAsset(assetData); + m_containerAssetId = m_rootAsset.GetId(); + + AddDependentAssets(assetData, loadParams); + } + + protected: + AZStd::vector>> CreateAndQueueDependentAssets( + const AZStd::vector& dependencyInfoList, const AssetLoadParameters& loadParamsCopyWithNoLoadingFilter) override + { + auto result = AssetContainer::CreateAndQueueDependentAssets(dependencyInfoList, loadParamsCopyWithNoLoadingFilter); + + // Sleep for a long enough time to allow asset loads to complete and start triggering AssetReady events + // This forces the race condition to occur + AZStd::this_thread::sleep_for(AZStd::chrono::milliseconds(500)); + + return result; + } + }; + + struct MockAssetManager : AssetManager + { + explicit MockAssetManager(const Descriptor& desc) + : AssetManager(desc) + { + } + + protected: + AZStd::shared_ptr CreateAssetContainer(Asset asset, const AssetLoadParameters& loadParams) const override + { + return AZStd::shared_ptr(aznew MockAssetContainer(asset, loadParams)); + } + }; + void ParallelDeepAssetReferences() { SerializeContext context; @@ -2304,7 +2343,7 @@ namespace UnitTest AssetWithAssetReference::Reflect(context); AssetManager::Descriptor desc; - AssetManager::Create(desc); + AssetManager::SetInstance(aznew MockAssetManager(desc)); auto& db = AssetManager::Instance(); @@ -2327,17 +2366,17 @@ namespace UnitTest // AssetC is MYASSETC AssetWithAssetReference c; - c.m_asset = AssetManager::Instance().CreateAsset(AssetId(MyAssetDId)); // point at D + c.m_asset = db.CreateAsset(AssetId(MyAssetDId)); // point at D EXPECT_TRUE(AZ::Utils::SaveObjectToFile(GetTestFolderPath() + "TestAsset3.txt", AZ::DataStream::ST_XML, &c, &context)); // AssetB is MYASSETB AssetWithAssetReference b; - b.m_asset = AssetManager::Instance().CreateAsset(AssetId(MyAssetCId)); // point at C + b.m_asset = db.CreateAsset(AssetId(MyAssetCId)); // point at C EXPECT_TRUE(AZ::Utils::SaveObjectToFile(GetTestFolderPath() + "TestAsset2.txt", AZ::DataStream::ST_XML, &b, &context)); // AssetA will be written to disk as MYASSETA AssetWithAssetReference a; - a.m_asset = AssetManager::Instance().CreateAsset(AssetId(MyAssetBId)); // point at B + a.m_asset = db.CreateAsset(AssetId(MyAssetBId)); // point at B EXPECT_TRUE(AZ::Utils::SaveObjectToFile(GetTestFolderPath() + "TestAsset1.txt", AZ::DataStream::ST_XML, &a, &context)); } @@ -2546,7 +2585,7 @@ namespace UnitTest TEST_F(AssetJobsMultithreadedTest, DISABLED_ParallelDeepAssetReferences) #else // temporarily disabled until sporadic failures can be root caused - TEST_F(AssetJobsMultithreadedTest, DISABLED_ParallelDeepAssetReferences) + TEST_F(AssetJobsMultithreadedTest, ParallelDeepAssetReferences) #endif // AZ_TRAIT_DISABLE_FAILED_ASSET_MANAGER_TESTS { ParallelDeepAssetReferences(); From 3cf3e45b38d66269862c47d482e2f794a7f6418f Mon Sep 17 00:00:00 2001 From: Steve Pham <82231385+spham-amzn@users.noreply.github.com> Date: Fri, 19 Nov 2021 12:09:00 -0800 Subject: [PATCH 07/23] Enable Resource Mapping Tool on Linux (#5779) * Enable and fix AWS Resource Mapping Tool on Linux - Enable the trait AWSCORE_EDITOR_RESOURCE_MAPPING_TOOL_ENABLED for Linux - Add additional traits to handle launching o3de local python on Linux - Update the resource_mapping_tool.py to support preloading the shared libraries for Pyside (like the QtForPython gem) in order to resolve the local pyside2 libraries Signed-off-by: Steve Pham <82231385+spham-amzn@users.noreply.github.com> * Update pyside2 to a RUNTIME dependency Signed-off-by: Steve Pham <82231385+spham-amzn@users.noreply.github.com> * Update special linux preloading comments for clarity Signed-off-by: Steve Pham <82231385+spham-amzn@users.noreply.github.com> * Add CR at the end of traits files Signed-off-by: Steve Pham <82231385+spham-amzn@users.noreply.github.com> * - Remove unnecessary extra argument '--executable-path' and use '--binaries-path' instead - Add linux only loading of pyside modules to 'setup_qt_environment' instead - Update README.md Signed-off-by: Steve Pham <82231385+spham-amzn@users.noreply.github.com> * Updated unit tests for test_environment_utils.py Signed-off-by: Steve Pham <82231385+spham-amzn@users.noreply.github.com> * Fix indentation for Linux specific logic in environment_utils.py Signed-off-by: Steve Pham <82231385+spham-amzn@users.noreply.github.com> * Fix (more) indentation for Linux specific logic in environment_utils.py Signed-off-by: Steve Pham <82231385+spham-amzn@users.noreply.github.com> * Replace exit with return in setup_qt_environment Signed-off-by: Steve Pham <82231385+spham-amzn@users.noreply.github.com> --- Gems/AWSCore/Code/CMakeLists.txt | 3 +++ .../Editor/UI/AWSCoreResourceMappingToolAction.h | 4 +++- .../Platform/Linux/AWSCoreEditor_Traits_Linux.h | 4 +++- .../Code/Platform/Mac/AWSCoreEditor_Traits_Mac.h | 2 ++ .../Windows/AWSCoreEditor_Traits_Windows.h | 2 ++ .../UI/AWSCoreResourceMappingToolAction.cpp | 2 +- .../Code/Tools/ResourceMappingTool/README.md | 10 ++++++++++ .../ResourceMappingTool/resource_mapping_tool.py | 1 + .../tests/unit/utils/test_environment_utils.py | 15 +++++++++++++-- .../utils/environment_utils.py | 15 +++++++++++++++ 10 files changed, 53 insertions(+), 5 deletions(-) diff --git a/Gems/AWSCore/Code/CMakeLists.txt b/Gems/AWSCore/Code/CMakeLists.txt index 7559f4720b..d84f7814c3 100644 --- a/Gems/AWSCore/Code/CMakeLists.txt +++ b/Gems/AWSCore/Code/CMakeLists.txt @@ -111,6 +111,9 @@ if (PAL_TRAIT_BUILD_HOST_TOOLS) BUILD_DEPENDENCIES PRIVATE Gem::AWSCore.Editor.Static + RUNTIME_DEPENDENCIES + 3rdParty::pyside2 + ) ly_add_dependencies(AWSCore.Editor AWSCore.ResourceMappingTool) diff --git a/Gems/AWSCore/Code/Include/Private/Editor/UI/AWSCoreResourceMappingToolAction.h b/Gems/AWSCore/Code/Include/Private/Editor/UI/AWSCoreResourceMappingToolAction.h index 1a4c428e68..a065773743 100644 --- a/Gems/AWSCore/Code/Include/Private/Editor/UI/AWSCoreResourceMappingToolAction.h +++ b/Gems/AWSCore/Code/Include/Private/Editor/UI/AWSCoreResourceMappingToolAction.h @@ -13,6 +13,8 @@ #include #include +#include "AWSCoreEditor_Traits_Platform.h" + namespace AWSCore { class AWSCoreResourceMappingToolAction @@ -22,7 +24,7 @@ namespace AWSCore static constexpr const char AWSCoreResourceMappingToolActionName[] = "AWSCoreResourceMappingToolAction"; static constexpr const char ResourceMappingToolDirectoryPath[] = "Gems/AWSCore/Code/Tools/ResourceMappingTool"; static constexpr const char ResourceMappingToolLogDirectoryPath[] = "user/log/"; - static constexpr const char EngineWindowsPythonEntryScriptPath[] = "python/python.cmd"; + static constexpr const char EngineWindowsPythonEntryScriptPath[] = AWSCORE_EDITOR_PYTHON_COMMAND; AWSCoreResourceMappingToolAction(const QString& text, QObject* parent = nullptr); diff --git a/Gems/AWSCore/Code/Platform/Linux/AWSCoreEditor_Traits_Linux.h b/Gems/AWSCore/Code/Platform/Linux/AWSCoreEditor_Traits_Linux.h index fb82911dd4..726d4cc86f 100644 --- a/Gems/AWSCore/Code/Platform/Linux/AWSCoreEditor_Traits_Linux.h +++ b/Gems/AWSCore/Code/Platform/Linux/AWSCoreEditor_Traits_Linux.h @@ -7,4 +7,6 @@ */ #pragma once -#define AWSCORE_EDITOR_RESOURCE_MAPPING_TOOL_ENABLED 0 +#define AWSCORE_EDITOR_RESOURCE_MAPPING_TOOL_ENABLED 1 +#define AWSCORE_EDITOR_PYTHON_DEBUG_ARGUMENT "" +#define AWSCORE_EDITOR_PYTHON_COMMAND "python/python.sh" diff --git a/Gems/AWSCore/Code/Platform/Mac/AWSCoreEditor_Traits_Mac.h b/Gems/AWSCore/Code/Platform/Mac/AWSCoreEditor_Traits_Mac.h index fb82911dd4..d815c8273e 100644 --- a/Gems/AWSCore/Code/Platform/Mac/AWSCoreEditor_Traits_Mac.h +++ b/Gems/AWSCore/Code/Platform/Mac/AWSCoreEditor_Traits_Mac.h @@ -8,3 +8,5 @@ #pragma once #define AWSCORE_EDITOR_RESOURCE_MAPPING_TOOL_ENABLED 0 +#define AWSCORE_EDITOR_PYTHON_DEBUG_ARGUMENT "" +#define AWSCORE_EDITOR_PYTHON_COMMAND "python/python.sh" diff --git a/Gems/AWSCore/Code/Platform/Windows/AWSCoreEditor_Traits_Windows.h b/Gems/AWSCore/Code/Platform/Windows/AWSCoreEditor_Traits_Windows.h index e1522db32c..6eca30a8ac 100644 --- a/Gems/AWSCore/Code/Platform/Windows/AWSCoreEditor_Traits_Windows.h +++ b/Gems/AWSCore/Code/Platform/Windows/AWSCoreEditor_Traits_Windows.h @@ -8,3 +8,5 @@ #pragma once #define AWSCORE_EDITOR_RESOURCE_MAPPING_TOOL_ENABLED 1 +#define AWSCORE_EDITOR_PYTHON_DEBUG_ARGUMENT "debug " +#define AWSCORE_EDITOR_PYTHON_COMMAND "python/python.cmd" diff --git a/Gems/AWSCore/Code/Source/Editor/UI/AWSCoreResourceMappingToolAction.cpp b/Gems/AWSCore/Code/Source/Editor/UI/AWSCoreResourceMappingToolAction.cpp index 858d30fa40..49f800dbea 100644 --- a/Gems/AWSCore/Code/Source/Editor/UI/AWSCoreResourceMappingToolAction.cpp +++ b/Gems/AWSCore/Code/Source/Editor/UI/AWSCoreResourceMappingToolAction.cpp @@ -58,7 +58,7 @@ namespace AWSCore if (m_isDebug) { return AZStd::string::format( - "\"%s\" debug -B \"%s\" --binaries-path \"%s\" --debug --profile \"%s\" --config-path \"%s\" --log-path \"%s\"", + "\"%s\" " AWSCORE_EDITOR_PYTHON_DEBUG_ARGUMENT "-B \"%s\" --binaries-path \"%s\" --debug --profile \"%s\" --config-path \"%s\" --log-path \"%s\"", m_enginePythonEntryPath.c_str(), m_toolScriptPath.c_str(), m_toolQtBinDirectoryPath.c_str(), profileName.c_str(), m_toolConfigDirectoryPath.c_str(), m_toolLogDirectoryPath.c_str()); } diff --git a/Gems/AWSCore/Code/Tools/ResourceMappingTool/README.md b/Gems/AWSCore/Code/Tools/ResourceMappingTool/README.md index e09ecc281f..29479fa3e1 100644 --- a/Gems/AWSCore/Code/Tools/ResourceMappingTool/README.md +++ b/Gems/AWSCore/Code/Tools/ResourceMappingTool/README.md @@ -39,6 +39,16 @@ Follow cmake instructions to configure your project, for example: ``` $ python\python.cmd debug Gems\AWSCore\Code\Tools\ResourceMappingTool\resource_mapping_tool.py --binaries_path \bin\debug\AWSCoreEditorQtBin ``` + * Linux + * release mode + ``` + $ python/python.sh Gems/AWSCore/Code/Tools/ResourceMappingTool/resource_mapping_tool.py --binaries_path /bin/profile/AWSCoreEditorQtBin + ``` + * debug mode + ``` + $ python/python.sh Gems/AWSCore/Code/Tools/ResourceMappingTool/resource_mapping_tool.py --binaries_path /bin/debug/AWSCoreEditorQtBin + ``` + * Note - Editor is integrated with the same engine python environment to launch Resource Mapping Tool. If it is failed to launch the tool in Editor, please follow above steps to make sure expected scripts/binaries are present. diff --git a/Gems/AWSCore/Code/Tools/ResourceMappingTool/resource_mapping_tool.py b/Gems/AWSCore/Code/Tools/ResourceMappingTool/resource_mapping_tool.py index 2351fd001b..b254960f77 100755 --- a/Gems/AWSCore/Code/Tools/ResourceMappingTool/resource_mapping_tool.py +++ b/Gems/AWSCore/Code/Tools/ResourceMappingTool/resource_mapping_tool.py @@ -20,6 +20,7 @@ argument_parser.add_argument('--debug', action='store_true', help='Execute on de argument_parser.add_argument('--log-path', help='Path to resource mapping tool logging directory ' '(if not provided, logging file will be located at tool directory)') argument_parser.add_argument('--profile', default='default', help='Named AWS profile to use for querying AWS resources') + arguments: Namespace = argument_parser.parse_args() # logging setup diff --git a/Gems/AWSCore/Code/Tools/ResourceMappingTool/tests/unit/utils/test_environment_utils.py b/Gems/AWSCore/Code/Tools/ResourceMappingTool/tests/unit/utils/test_environment_utils.py index 756d6fdb10..3d36a56468 100644 --- a/Gems/AWSCore/Code/Tools/ResourceMappingTool/tests/unit/utils/test_environment_utils.py +++ b/Gems/AWSCore/Code/Tools/ResourceMappingTool/tests/unit/utils/test_environment_utils.py @@ -5,6 +5,7 @@ For complete copyright and license terms please see the LICENSE at the root of t SPDX-License-Identifier: Apache-2.0 OR MIT """ +import platform from typing import List from unittest import TestCase from unittest.mock import (ANY, call, MagicMock, patch) @@ -27,14 +28,24 @@ class TestEnvironmentUtils(TestCase): self.addCleanup(os_pathsep_patcher.stop) self._mock_os_pathsep: MagicMock = os_pathsep_patcher.start() - def test_setup_qt_environment_global_flag_is_set(self) -> None: + @patch('os.path.exists') + @patch('ctypes.CDLL') + def test_setup_qt_environment_global_flag_is_set(self, mock_os_path_exists, mock_ctype_cdll) -> None: + mock_os_path_exists.return_value = True environment_utils.setup_qt_environment("dummy") self._mock_os_environ.copy.assert_called_once() self._mock_os_pathsep.join.assert_called_once() assert environment_utils.is_qt_linked() is True + if platform.system() == 'Linux': + mock_os_path_exists.assert_called() - def test_cleanup_qt_environment_global_flag_is_set(self) -> None: + @patch('os.path.exists') + @patch('ctypes.CDLL') + def test_cleanup_qt_environment_global_flag_is_set(self, mock_os_path_exists, mock_ctype_cdll) -> None: + mock_os_path_exists.return_value = True environment_utils.setup_qt_environment("dummy") assert environment_utils.is_qt_linked() is True environment_utils.cleanup_qt_environment() assert environment_utils.is_qt_linked() is False + if platform.system() == 'Linux': + mock_os_path_exists.assert_called() diff --git a/Gems/AWSCore/Code/Tools/ResourceMappingTool/utils/environment_utils.py b/Gems/AWSCore/Code/Tools/ResourceMappingTool/utils/environment_utils.py index 8600fe31b5..b67f64e715 100644 --- a/Gems/AWSCore/Code/Tools/ResourceMappingTool/utils/environment_utils.py +++ b/Gems/AWSCore/Code/Tools/ResourceMappingTool/utils/environment_utils.py @@ -7,6 +7,7 @@ SPDX-License-Identifier: Apache-2.0 OR MIT import logging import os +import platform from typing import Dict from utils import file_utils @@ -38,6 +39,20 @@ def setup_qt_environment(bin_path: str) -> None: new_path = os.pathsep.join([binaries_path, path]) os.environ['PATH'] = new_path + # On Linux, we need to load pyside2 and related modules as well + if platform.system() == 'Linux': + import ctypes + + preload_shared_libs = [f'{bin_path}/libpyside2.abi3.so.5.14', + f'{bin_path}/libQt5Widgets.so.5'] + + for preload_shared_lib in preload_shared_libs: + if not os.path.exists(preload_shared_lib): + logger.error(f"Cannot find required shared library at {preload_shared_lib}") + return + else: + ctypes.CDLL(preload_shared_lib) + global qt_binaries_linked qt_binaries_linked = True From dbc5d7a8bc5404b80fbc38b6b004aaa1f9e06df9 Mon Sep 17 00:00:00 2001 From: Esteban Papp <81431996+amznestebanpapp@users.noreply.github.com> Date: Fri, 19 Nov 2021 14:07:25 -0800 Subject: [PATCH 08/23] Cherry-pick of Linux deb package to stabilization (#5778) * Cherry-pick 49e8f358581dad7ca0e8127905a9d5e864c41cee Signed-off-by: Esteban Papp <81431996+amznestebanpapp@users.noreply.github.com> * Merging differences from development of other changes that need to be there for deb packaging Signed-off-by: Esteban Papp <81431996+amznestebanpapp@users.noreply.github.com> * Picks a needed change for the installer Signed-off-by: Esteban Papp <81431996+amznestebanpapp@users.noreply.github.com> * Fixes warning in mac Signed-off-by: Esteban Papp <81431996+amznestebanpapp@users.noreply.github.com> * Takes version from environment if defined Signed-off-by: Esteban Papp <81431996+amznestebanpapp@users.noreply.github.com> * Do not pick up version if it is empty string since that will also break version comparison Signed-off-by: Esteban Papp <81431996+amznestebanpapp@users.noreply.github.com> * creating temp directories if they dont exist Signed-off-by: Esteban Papp <81431996+amznestebanpapp@users.noreply.github.com> * removing a dependency to itself (Multiplayer.Builders is an alias of Multiplayer.Editor) Signed-off-by: Esteban Papp <81431996+amznestebanpapp@users.noreply.github.com> * Filters which runtime dependencies are passed from private build dependencies to only those that are actual targets. This avoids something like a "d3d12" private build dependency from being passed to the runtime dependencies Signed-off-by: Esteban Papp <81431996+amznestebanpapp@users.noreply.github.com> --- AutomatedTesting/CMakeLists.txt | 3 +- AutomatedTesting/cmake/CompilerSettings.cmake | 13 + .../{ => cmake}/EngineFinder.cmake | 42 ++- .../Linux/CompilerSettings_linux.cmake | 0 .../AzCore/Serialization/AZStdContainers.inl | 2 +- .../AzToolsFramework/API/PythonLoader.h | 2 +- .../Prefab/PrefabFocusHandler.cpp | 6 +- Gems/Multiplayer/Code/CMakeLists.txt | 1 - Registry/CMakeLists.txt | 11 +- .../Template/cmake/CompilerSettings.cmake | 2 +- .../Linux/CompilerSettings_linux.cmake} | 0 Templates/DefaultProject/template.json | 4 +- .../Template/cmake/CompilerSettings.cmake | 2 +- .../Linux/CompilerSettings_linux.cmake | 0 Templates/MinimalProject/template.json | 4 +- cmake/3rdPartyPackages.cmake | 11 +- cmake/CompilerSettings.cmake | 2 +- cmake/Install.cmake | 54 +++- cmake/LYWrappers.cmake | 4 +- cmake/Packaging.cmake | 252 +++++++----------- cmake/Packaging/CMakeDownload.cmake.in | 54 ++++ cmake/Platform/Common/Install_common.cmake | 202 +++++++++----- .../Common/PackagingPostBuild_common.cmake | 114 ++++++++ .../Common/PackagingPreBuild_common.cmake | 5 + .../Common/RuntimeDependencies_common.cmake | 2 +- .../runtime_dependencies_common.cmake.in | 18 +- .../Linux/CompilerSettings_linux.cmake | 34 +++ cmake/Platform/Linux/Install_linux.cmake | 42 ++- cmake/Platform/Linux/PAL_linux.cmake | 2 +- cmake/Platform/Linux/Packaging/postinst.in | 21 ++ cmake/Platform/Linux/Packaging/postrm.in | 15 ++ cmake/Platform/Linux/Packaging/prerm.in | 23 ++ .../Linux/PackagingPostBuild_linux.cmake | 62 +++++ .../Linux/PackagingPreBuild_linux.cmake | 16 ++ cmake/Platform/Linux/Packaging_linux.cmake | 56 ++++ .../Platform/Linux/platform_linux_files.cmake | 8 + .../Linux/runtime_dependencies_linux.cmake.in | 26 +- cmake/Platform/Mac/InstallUtils_mac.cmake.in | 37 ++- cmake/Platform/Mac/Install_mac.cmake | 61 +++-- .../Platform/Mac/PackagingPostBuild_mac.cmake | 10 + .../Platform/Mac/PackagingPreBuild_mac.cmake | 10 + .../Mac/runtime_dependencies_mac.cmake.in | 35 ++- .../Platform/Windows/PackagingPostBuild.cmake | 237 ---------------- .../Windows/PackagingPostBuild_windows.cmake | 166 ++++++++++++ .../Platform/Windows/PackagingPreBuild.cmake | 37 --- .../Windows/PackagingPreBuild_windows.cmake | 60 +++++ .../Platform/Windows/Packaging_windows.cmake | 68 ++--- .../Windows/platform_windows_files.cmake | 5 +- cmake/Version.cmake | 5 + .../install/ConfigurationType_config.cmake.in | 2 +- .../build/Platform/Android/build_config.json | 10 +- .../build/Platform/Linux/build_config.json | 82 +++++- .../Platform/Linux/build_installer_linux.sh | 15 ++ scripts/build/Platform/Linux/build_linux.sh | 13 +- scripts/build/Platform/Linux/env_linux.sh | 5 + .../build/Platform/Linux/installer_linux.sh | 30 +++ scripts/build/Platform/Mac/build_config.json | 59 +++- scripts/build/Platform/Mac/build_mac.sh | 5 +- scripts/build/Platform/Mac/env_mac.sh | 5 + .../build/Platform/Windows/build_config.json | 72 +++-- .../build/Platform/Windows/build_windows.cmd | 12 +- .../build/Platform/Windows/env_windows.cmd | 23 ++ .../Platform/Windows/installer_windows.cmd | 14 +- .../Windows/package_build_config.json | 2 +- scripts/build/Platform/iOS/build_config.json | 10 +- .../Linux/package-list.ubuntu-bionic.txt | 9 +- .../Linux/package-list.ubuntu-focal.txt | 4 +- 67 files changed, 1475 insertions(+), 743 deletions(-) create mode 100644 AutomatedTesting/cmake/CompilerSettings.cmake rename AutomatedTesting/{ => cmake}/EngineFinder.cmake (63%) rename Templates/DefaultProject/Template/cmake/Platform/Linux/CompilerSettings.cmake => AutomatedTesting/cmake/Platform/Linux/CompilerSettings_linux.cmake (100%) rename Templates/{MinimalProject/Template/cmake/Platform/Linux/CompilerSettings.cmake => DefaultProject/Template/cmake/Platform/Linux/CompilerSettings_linux.cmake} (100%) rename cmake/Platform/Linux/CompilerSettings.cmake => Templates/MinimalProject/Template/cmake/Platform/Linux/CompilerSettings_linux.cmake (100%) create mode 100644 cmake/Packaging/CMakeDownload.cmake.in create mode 100644 cmake/Platform/Common/PackagingPostBuild_common.cmake create mode 100644 cmake/Platform/Common/PackagingPreBuild_common.cmake create mode 100644 cmake/Platform/Linux/CompilerSettings_linux.cmake create mode 100644 cmake/Platform/Linux/Packaging/postinst.in create mode 100644 cmake/Platform/Linux/Packaging/postrm.in create mode 100644 cmake/Platform/Linux/Packaging/prerm.in create mode 100644 cmake/Platform/Linux/PackagingPostBuild_linux.cmake create mode 100644 cmake/Platform/Linux/PackagingPreBuild_linux.cmake create mode 100644 cmake/Platform/Linux/Packaging_linux.cmake create mode 100644 cmake/Platform/Mac/PackagingPostBuild_mac.cmake create mode 100644 cmake/Platform/Mac/PackagingPreBuild_mac.cmake delete mode 100644 cmake/Platform/Windows/PackagingPostBuild.cmake create mode 100644 cmake/Platform/Windows/PackagingPostBuild_windows.cmake delete mode 100644 cmake/Platform/Windows/PackagingPreBuild.cmake create mode 100644 cmake/Platform/Windows/PackagingPreBuild_windows.cmake create mode 100755 scripts/build/Platform/Linux/build_installer_linux.sh create mode 100755 scripts/build/Platform/Linux/installer_linux.sh diff --git a/AutomatedTesting/CMakeLists.txt b/AutomatedTesting/CMakeLists.txt index dee9d73aea..1c5382ba4b 100644 --- a/AutomatedTesting/CMakeLists.txt +++ b/AutomatedTesting/CMakeLists.txt @@ -8,11 +8,12 @@ if(NOT PROJECT_NAME) cmake_minimum_required(VERSION 3.20) + include(cmake/CompilerSettings.cmake) project(AutomatedTesting LANGUAGES C CXX VERSION 1.0.0.0 ) - include(EngineFinder.cmake OPTIONAL) + include(cmake/EngineFinder.cmake OPTIONAL) find_package(o3de REQUIRED) o3de_initialize() else() diff --git a/AutomatedTesting/cmake/CompilerSettings.cmake b/AutomatedTesting/cmake/CompilerSettings.cmake new file mode 100644 index 0000000000..60bda1d45b --- /dev/null +++ b/AutomatedTesting/cmake/CompilerSettings.cmake @@ -0,0 +1,13 @@ +# +# Copyright (c) Contributors to the Open 3D Engine Project. +# For complete copyright and license terms please see the LICENSE at the root of this distribution. +# +# SPDX-License-Identifier: Apache-2.0 OR MIT +# +# + +# File to tweak compiler settings before compiler detection happens (before project() is called) +# We dont have PAL enabled at this point, so we can only use pure-CMake variables +if("${CMAKE_HOST_SYSTEM_NAME}" STREQUAL "Linux") + include(cmake/Platform/Linux/CompilerSettings_linux.cmake) +endif() diff --git a/AutomatedTesting/EngineFinder.cmake b/AutomatedTesting/cmake/EngineFinder.cmake similarity index 63% rename from AutomatedTesting/EngineFinder.cmake rename to AutomatedTesting/cmake/EngineFinder.cmake index 0a34a43b77..15b96eb8a9 100644 --- a/AutomatedTesting/EngineFinder.cmake +++ b/AutomatedTesting/cmake/EngineFinder.cmake @@ -1,3 +1,4 @@ +# {BEGIN_LICENSE} # # Copyright (c) Contributors to the Open 3D Engine Project. # For complete copyright and license terms please see the LICENSE at the root of this distribution. @@ -5,18 +6,34 @@ # SPDX-License-Identifier: Apache-2.0 OR MIT # # +# {END_LICENSE} # This file is copied during engine registration. Edits to this file will be lost next # time a registration happens. include_guard() # Read the engine name from the project_json file -file(READ ${CMAKE_CURRENT_LIST_DIR}/project.json project_json) -set_property(DIRECTORY APPEND PROPERTY CMAKE_CONFIGURE_DEPENDS ${CMAKE_CURRENT_LIST_DIR}/project.json) +file(READ ${CMAKE_CURRENT_SOURCE_DIR}/project.json project_json) +set_property(DIRECTORY APPEND PROPERTY CMAKE_CONFIGURE_DEPENDS ${CMAKE_CURRENT_SOURCE_DIR}/project.json) string(JSON LY_ENGINE_NAME_TO_USE ERROR_VARIABLE json_error GET ${project_json} engine) if(json_error) - message(FATAL_ERROR "Unable to read key 'engine' from 'project.json', error: ${json_error}") + message(FATAL_ERROR "Unable to read key 'engine' from 'project.json'\nError: ${json_error}") +endif() + +if(CMAKE_MODULE_PATH) + foreach(module_path ${CMAKE_MODULE_PATH}) + if(EXISTS ${module_path}/Findo3de.cmake) + file(READ ${module_path}/../engine.json engine_json) + string(JSON engine_name ERROR_VARIABLE json_error GET ${engine_json} engine_name) + if(json_error) + message(FATAL_ERROR "Unable to read key 'engine_name' from 'engine.json'\nError: ${json_error}") + endif() + if(LY_ENGINE_NAME_TO_USE STREQUAL engine_name) + return() # Engine being forced through CMAKE_MODULE_PATH + endif() + endif() + endforeach() endif() if(DEFINED ENV{USERPROFILE} AND EXISTS $ENV{USERPROFILE}) @@ -25,6 +42,11 @@ else() set(manifest_path $ENV{HOME}/.o3de/o3de_manifest.json) # Unix endif() +set(registration_error [=[ +Engine registration is required before configuring a project. +Run 'scripts/o3de register --this-engine' from the engine root. +]=]) + # Read the ~/.o3de/o3de_manifest.json file and look through the 'engines_path' object. # Find a key that matches LY_ENGINE_NAME_TO_USE and use that as the engine path. if(EXISTS ${manifest_path}) @@ -33,36 +55,38 @@ if(EXISTS ${manifest_path}) string(JSON engines_path_count ERROR_VARIABLE json_error LENGTH ${manifest_json} engines_path) if(json_error) - message(FATAL_ERROR "Unable to read key 'engines_path' from '${manifest_path}', error: ${json_error}") + message(FATAL_ERROR "Unable to read key 'engines_path' from '${manifest_path}'\nError: ${json_error}\n${registration_error}") endif() string(JSON engines_path_type ERROR_VARIABLE json_error TYPE ${manifest_json} engines_path) if(json_error OR NOT ${engines_path_type} STREQUAL "OBJECT") - message(FATAL_ERROR "Type of 'engines_path' in '${manifest_path}' is not a JSON Object, error: ${json_error}") + message(FATAL_ERROR "Type of 'engines_path' in '${manifest_path}' is not a JSON Object\nError: ${json_error}") endif() math(EXPR engines_path_count "${engines_path_count}-1") foreach(engine_path_index RANGE ${engines_path_count}) string(JSON engine_name ERROR_VARIABLE json_error MEMBER ${manifest_json} engines_path ${engine_path_index}) if(json_error) - message(FATAL_ERROR "Unable to read 'engines_path/${engine_path_index}' from '${manifest_path}', error: ${json_error}") + message(FATAL_ERROR "Unable to read 'engines_path/${engine_path_index}' from '${manifest_path}'\nError: ${json_error}") endif() if(LY_ENGINE_NAME_TO_USE STREQUAL engine_name) string(JSON engine_path ERROR_VARIABLE json_error GET ${manifest_json} engines_path ${engine_name}) if(json_error) - message(FATAL_ERROR "Unable to read value from 'engines_path/${engine_name}', error: ${json_error}") + message(FATAL_ERROR "Unable to read value from 'engines_path/${engine_name}'\nError: ${json_error}") endif() if(engine_path) list(APPEND CMAKE_MODULE_PATH "${engine_path}/cmake") - break() + return() endif() endif() endforeach() + + message(FATAL_ERROR "The project.json uses engine name '${LY_ENGINE_NAME_TO_USE}' but no engine with that name has been registered.\n${registration_error}") else() # If the user is passing CMAKE_MODULE_PATH we assume thats where we will find the engine if(NOT CMAKE_MODULE_PATH) - message(FATAL_ERROR "Engine registration is required before configuring a project. Please register an engine by running 'scripts/o3de register --this-engine'") + message(FATAL_ERROR "O3DE Manifest file not found.\n${registration_error}") endif() endif() diff --git a/Templates/DefaultProject/Template/cmake/Platform/Linux/CompilerSettings.cmake b/AutomatedTesting/cmake/Platform/Linux/CompilerSettings_linux.cmake similarity index 100% rename from Templates/DefaultProject/Template/cmake/Platform/Linux/CompilerSettings.cmake rename to AutomatedTesting/cmake/Platform/Linux/CompilerSettings_linux.cmake diff --git a/Code/Framework/AzCore/AzCore/Serialization/AZStdContainers.inl b/Code/Framework/AzCore/AzCore/Serialization/AZStdContainers.inl index bae79a6fe7..2a00652488 100644 --- a/Code/Framework/AzCore/AzCore/Serialization/AZStdContainers.inl +++ b/Code/Framework/AzCore/AzCore/Serialization/AZStdContainers.inl @@ -94,7 +94,7 @@ namespace AZ template AZStd::enable_if_t::value> InitializeDefaultIfPodType(T& t) { - t = {}; + t = T{}; } template diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/API/PythonLoader.h b/Code/Framework/AzToolsFramework/AzToolsFramework/API/PythonLoader.h index 29125667d6..6acc160ddc 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/API/PythonLoader.h +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/API/PythonLoader.h @@ -19,7 +19,7 @@ namespace AzToolsFramework::EmbeddedPython ~PythonLoader(); private: - void* m_embeddedLibPythonHandle{ nullptr }; + [[maybe_unused]] void* m_embeddedLibPythonHandle{ nullptr }; }; } // namespace AzToolsFramework::EmbeddedPython diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/PrefabFocusHandler.cpp b/Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/PrefabFocusHandler.cpp index 3d764554ef..f20c11a1d8 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/PrefabFocusHandler.cpp +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/PrefabFocusHandler.cpp @@ -376,7 +376,7 @@ namespace AzToolsFramework::Prefab size_t index = 0; size_t maxIndex = m_instanceFocusHierarchy.size() - 1; - for (const AZ::EntityId containerEntityId : m_instanceFocusHierarchy) + for (const AZ::EntityId& containerEntityId : m_instanceFocusHierarchy) { InstanceOptionalReference instance = GetReferenceFromContainerEntityId(containerEntityId); if (instance.has_value()) @@ -414,7 +414,7 @@ namespace AzToolsFramework::Prefab return; } - for (const AZ::EntityId containerEntityId : instances) + for (const AZ::EntityId& containerEntityId : instances) { InstanceOptionalReference instance = GetReferenceFromContainerEntityId(containerEntityId); @@ -433,7 +433,7 @@ namespace AzToolsFramework::Prefab return; } - for (const AZ::EntityId containerEntityId : instances) + for (const AZ::EntityId& containerEntityId : instances) { InstanceOptionalReference instance = GetReferenceFromContainerEntityId(containerEntityId); diff --git a/Gems/Multiplayer/Code/CMakeLists.txt b/Gems/Multiplayer/Code/CMakeLists.txt index dee68fa969..cc9988fe57 100644 --- a/Gems/Multiplayer/Code/CMakeLists.txt +++ b/Gems/Multiplayer/Code/CMakeLists.txt @@ -131,7 +131,6 @@ if (PAL_TRAIT_BUILD_HOST_TOOLS) AZ::AzToolsFramework Gem::Multiplayer.Static Gem::Multiplayer.Tools.Static - Gem::Multiplayer.Builders ) ly_create_alias(NAME Multiplayer.Builders NAMESPACE Gem TARGETS Gem::Multiplayer.Editor) diff --git a/Registry/CMakeLists.txt b/Registry/CMakeLists.txt index 773adac07f..df309ba657 100644 --- a/Registry/CMakeLists.txt +++ b/Registry/CMakeLists.txt @@ -12,6 +12,11 @@ endif() ly_install_directory(DIRECTORIES .) -ly_install_directory(DIRECTORIES ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/$/Registry - DESTINATION ${runtime_output_directory} -) +foreach(conf IN LISTS CMAKE_CONFIGURATION_TYPES) + string(TOUPPER ${conf} UCONF) + string(REPLACE "$" "${conf}" output ${runtime_output_directory}) + ly_install_directory(DIRECTORIES ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/${conf}/Registry + DESTINATION ${output} + COMPONENT ${LY_INSTALL_PERMUTATION_COMPONENT}_${UCONF} + ) +endforeach() diff --git a/Templates/DefaultProject/Template/cmake/CompilerSettings.cmake b/Templates/DefaultProject/Template/cmake/CompilerSettings.cmake index cf6614e4a5..60bda1d45b 100644 --- a/Templates/DefaultProject/Template/cmake/CompilerSettings.cmake +++ b/Templates/DefaultProject/Template/cmake/CompilerSettings.cmake @@ -9,5 +9,5 @@ # File to tweak compiler settings before compiler detection happens (before project() is called) # We dont have PAL enabled at this point, so we can only use pure-CMake variables if("${CMAKE_HOST_SYSTEM_NAME}" STREQUAL "Linux") - include(cmake/Platform/${CMAKE_HOST_SYSTEM_NAME}/CompilerSettings.cmake) + include(cmake/Platform/Linux/CompilerSettings_linux.cmake) endif() diff --git a/Templates/MinimalProject/Template/cmake/Platform/Linux/CompilerSettings.cmake b/Templates/DefaultProject/Template/cmake/Platform/Linux/CompilerSettings_linux.cmake similarity index 100% rename from Templates/MinimalProject/Template/cmake/Platform/Linux/CompilerSettings.cmake rename to Templates/DefaultProject/Template/cmake/Platform/Linux/CompilerSettings_linux.cmake diff --git a/Templates/DefaultProject/template.json b/Templates/DefaultProject/template.json index a36926f632..fcffafcb34 100644 --- a/Templates/DefaultProject/template.json +++ b/Templates/DefaultProject/template.json @@ -193,8 +193,8 @@ "isOptional": false }, { - "file": "cmake/Platform/Linux/CompilerSettings.cmake", - "origin": "cmake/Platform/Linux/CompilerSettings.cmake", + "file": "cmake/Platform/Linux/CompilerSettings_linux.cmake", + "origin": "cmake/Platform/Linux/CompilerSettings_linux.cmake", "isTemplated": false, "isOptional": false }, diff --git a/Templates/MinimalProject/Template/cmake/CompilerSettings.cmake b/Templates/MinimalProject/Template/cmake/CompilerSettings.cmake index cf6614e4a5..60bda1d45b 100644 --- a/Templates/MinimalProject/Template/cmake/CompilerSettings.cmake +++ b/Templates/MinimalProject/Template/cmake/CompilerSettings.cmake @@ -9,5 +9,5 @@ # File to tweak compiler settings before compiler detection happens (before project() is called) # We dont have PAL enabled at this point, so we can only use pure-CMake variables if("${CMAKE_HOST_SYSTEM_NAME}" STREQUAL "Linux") - include(cmake/Platform/${CMAKE_HOST_SYSTEM_NAME}/CompilerSettings.cmake) + include(cmake/Platform/Linux/CompilerSettings_linux.cmake) endif() diff --git a/cmake/Platform/Linux/CompilerSettings.cmake b/Templates/MinimalProject/Template/cmake/Platform/Linux/CompilerSettings_linux.cmake similarity index 100% rename from cmake/Platform/Linux/CompilerSettings.cmake rename to Templates/MinimalProject/Template/cmake/Platform/Linux/CompilerSettings_linux.cmake diff --git a/Templates/MinimalProject/template.json b/Templates/MinimalProject/template.json index 4260e71527..7d6a4f9b94 100644 --- a/Templates/MinimalProject/template.json +++ b/Templates/MinimalProject/template.json @@ -185,8 +185,8 @@ "isOptional": false }, { - "file": "cmake/Platform/Linux/CompilerSettings.cmake", - "origin": "cmake/Platform/Linux/CompilerSettings.cmake", + "file": "cmake/Platform/Linux/CompilerSettings_linux.cmake", + "origin": "cmake/Platform/Linux/CompilerSettings_linux.cmake", "isTemplated": false, "isOptional": false }, diff --git a/cmake/3rdPartyPackages.cmake b/cmake/3rdPartyPackages.cmake index efe67b4d24..a3f15bdb22 100644 --- a/cmake/3rdPartyPackages.cmake +++ b/cmake/3rdPartyPackages.cmake @@ -7,7 +7,7 @@ include_guard() -include(cmake/LySet.cmake) +include(${LY_ROOT_FOLDER}/cmake/LySet.cmake) # OVERVIEW: # this is the Open 3D Engine Package system. @@ -80,10 +80,7 @@ macro(ly_package_message) endif() endmacro() -file(MAKE_DIRECTORY ${CMAKE_BINARY_DIR}/packages) - -include(cmake/LYPackage_S3Downloader.cmake) - +include(${LY_ROOT_FOLDER}/cmake/LYPackage_S3Downloader.cmake) # Attempts one time to download a file. # sets should_retry to true if the caller should retry due to an intermittent problem @@ -711,11 +708,11 @@ if (NOT CMAKE_SCRIPT_MODE_FILE) # include the built in 3rd party packages that are for every platform. # you can put your package associations anywhere, but this provides # a good starting point. - include(cmake/3rdParty/BuiltInPackages.cmake) + include(${LY_ROOT_FOLDER}/cmake/3rdParty/BuiltInPackages.cmake) endif() if(PAL_TRAIT_BUILD_HOST_TOOLS) - include(cmake/LYWrappers.cmake) + include(${LY_ROOT_FOLDER}/cmake/LYWrappers.cmake) # Importing this globally to handle AUTOMOC, AUTOUIC, AUTORCC ly_parse_third_party_dependencies(3rdParty::Qt) endif() diff --git a/cmake/CompilerSettings.cmake b/cmake/CompilerSettings.cmake index cf6614e4a5..60bda1d45b 100644 --- a/cmake/CompilerSettings.cmake +++ b/cmake/CompilerSettings.cmake @@ -9,5 +9,5 @@ # File to tweak compiler settings before compiler detection happens (before project() is called) # We dont have PAL enabled at this point, so we can only use pure-CMake variables if("${CMAKE_HOST_SYSTEM_NAME}" STREQUAL "Linux") - include(cmake/Platform/${CMAKE_HOST_SYSTEM_NAME}/CompilerSettings.cmake) + include(cmake/Platform/Linux/CompilerSettings_linux.cmake) endif() diff --git a/cmake/Install.cmake b/cmake/Install.cmake index 3b74e6c654..b558590b9e 100644 --- a/cmake/Install.cmake +++ b/cmake/Install.cmake @@ -8,16 +8,38 @@ set(LY_INSTALL_ENABLED TRUE CACHE BOOL "Indicates if the install process is enabled") -if(LY_INSTALL_ENABLED) - ly_get_absolute_pal_filename(pal_dir ${CMAKE_CURRENT_SOURCE_DIR}/cmake/Platform/${PAL_PLATFORM_NAME}) - include(${pal_dir}/Install_${PAL_PLATFORM_NAME_LOWERCASE}.cmake) -endif() +#! ly_install: wrapper to install that handles common functionality +# +# \notes: +# - this wrapper handles the case where common installs are called multiple times from different +# build folders (when using LY_INSTALL_EXTERNAL_BUILD_DIRS) to generate install layouts that +# have multiple build permutations +# +function(ly_install) + + if(NOT LY_INSTALL_ENABLED) + return() + endif() + + cmake_parse_arguments(ly_install "" "COMPONENT" "" ${ARGN}) + if (NOT ly_install_COMPONENT OR "${ly_install_COMPONENT}" STREQUAL "${CMAKE_INSTALL_DEFAULT_COMPONENT_NAME}") + # if it is installing under the default component, we need to de-duplicate since we can have + # cases coming from different build directories (when using LY_INSTALL_EXTERNAL_BUILD_DIRS) + install(CODE "if(NOT LY_CORE_COMPONENT_ALREADY_INCLUDED)" ALL_COMPONENTS) + install(${ARGN}) + install(CODE "endif()\n" ALL_COMPONENTS) + else() + install(${ARGN}) + endif() + +endfunction() #! ly_install_directory: specifies a directory to be copied to the install layout at install time # # \arg:DIRECTORIES directories to install # \arg:DESTINATION (optional) destination to install the directory to (relative to CMAKE_PREFIX_PATH) # \arg:EXCLUDE_PATTERNS (optional) patterns to exclude +# \arg:COMPONENT (optional) component to use (defaults to CMAKE_INSTALL_DEFAULT_COMPONENT_NAME) # \arg:VERBATIM (optional) copies the directories as they are, this excludes the default exclude patterns # # \notes: @@ -34,7 +56,7 @@ function(ly_install_directory) endif() set(options VERBATIM) - set(oneValueArgs DESTINATION) + set(oneValueArgs DESTINATION COMPONENT) set(multiValueArgs DIRECTORIES EXCLUDE_PATTERNS) cmake_parse_arguments(ly_install_directory "${options}" "${oneValueArgs}" "${multiValueArgs}" ${ARGN}) @@ -42,6 +64,10 @@ function(ly_install_directory) if(NOT ly_install_directory_DIRECTORIES) message(FATAL_ERROR "You must provide at least a directory to install") endif() + + if(NOT ly_install_directory_COMPONENT) + set(ly_install_directory_COMPONENT ${CMAKE_INSTALL_DEFAULT_COMPONENT_NAME}) + endif() foreach(directory ${ly_install_directory_DIRECTORIES}) @@ -77,11 +103,12 @@ function(ly_install_directory) list(APPEND exclude_patterns PATTERN *.egg-info EXCLUDE) endif() - install(DIRECTORY ${directory} + ly_install(DIRECTORY ${directory} DESTINATION ${ly_install_directory_DESTINATION} - COMPONENT ${CMAKE_INSTALL_DEFAULT_COMPONENT_NAME} # use the deafult for the time being + COMPONENT ${ly_install_directory_COMPONENT} ${exclude_patterns} ) + endforeach() endfunction() @@ -126,7 +153,7 @@ function(ly_install_files) set(install_type FILES) endif() - install(${install_type} ${files} + ly_install(${install_type} ${files} DESTINATION ${ly_install_files_DESTINATION} COMPONENT ${CMAKE_INSTALL_DEFAULT_COMPONENT_NAME} # use the default for the time being ) @@ -144,7 +171,7 @@ function(ly_install_run_code CODE) return() endif() - install(CODE ${CODE} + ly_install(CODE ${CODE} COMPONENT ${CMAKE_INSTALL_DEFAULT_COMPONENT_NAME} # use the default for the time being ) @@ -161,8 +188,13 @@ function(ly_install_run_script SCRIPT) return() endif() - install(SCRIPT ${SCRIPT} + ly_install(SCRIPT ${SCRIPT} COMPONENT ${CMAKE_INSTALL_DEFAULT_COMPONENT_NAME} # use the default for the time being ) -endfunction() \ No newline at end of file +endfunction() + +if(LY_INSTALL_ENABLED) + ly_get_absolute_pal_filename(pal_dir ${CMAKE_CURRENT_SOURCE_DIR}/cmake/Platform/${PAL_PLATFORM_NAME}) + include(${pal_dir}/Install_${PAL_PLATFORM_NAME_LOWERCASE}.cmake) +endif() diff --git a/cmake/LYWrappers.cmake b/cmake/LYWrappers.cmake index 0416d41ece..ae097c9bb7 100644 --- a/cmake/LYWrappers.cmake +++ b/cmake/LYWrappers.cmake @@ -354,7 +354,7 @@ function(ly_add_target) # of running the copy of runtime dependencies, the stamp file is touched so the timestamp is updated. # Adding a config as part of the name since the stamp file is added to the VS project. # Note the STAMP_OUTPUT_FILE need to match with the one used in runtime dependencies (e.g. RuntimeDependencies_common.cmake) - set(STAMP_OUTPUT_FILE ${CMAKE_BINARY_DIR}/runtime_dependencies/$/${ly_add_target_NAME}_$.stamp) + set(STAMP_OUTPUT_FILE ${CMAKE_BINARY_DIR}/runtime_dependencies/$/${ly_add_target_NAME}.stamp) add_custom_command( OUTPUT ${STAMP_OUTPUT_FILE} DEPENDS "$>" @@ -367,7 +367,7 @@ function(ly_add_target) # stamp file on each configuration so it gets properly excluded by the generator unset(stamp_files_per_config) foreach(conf IN LISTS CMAKE_CONFIGURATION_TYPES) - set(stamp_file_conf ${CMAKE_BINARY_DIR}/runtime_dependencies/${conf}/${ly_add_target_NAME}_${conf}.stamp) + set(stamp_file_conf ${CMAKE_BINARY_DIR}/runtime_dependencies/${conf}/${ly_add_target_NAME}.stamp) set_source_files_properties(${stamp_file_conf} PROPERTIES GENERATED TRUE SKIP_AUTOGEN TRUE) list(APPEND stamp_files_per_config $<$:${stamp_file_conf}>) endforeach() diff --git a/cmake/Packaging.cmake b/cmake/Packaging.cmake index 006689549b..d716efb225 100644 --- a/cmake/Packaging.cmake +++ b/cmake/Packaging.cmake @@ -24,18 +24,23 @@ number will automatically appended as '/'. If LY_INSTALLER_AUTO_ full URL format will be: //" ) -set(LY_INSTALLER_UPLOAD_URL "" CACHE STRING -"Base URL used to upload the installer artifacts after generation, the host target and version number \ -will automatically appended as '/'. If LY_INSTALLER_AUTO_GEN_TAG is set, the full URL \ -format will be: //. Can also be set via LY_INSTALLER_UPLOAD_URL environment \ -variable. Currently only accepts S3 URLs e.g. s3:///" +set(CPACK_UPLOAD_URL "" CACHE STRING +"URL used to upload the installer artifacts after generation, the host target and version number \ +will automatically appended as '/'. If LY_INSTALLER_AUTO_GEN_TAG is set, the full URL \ +format will be: //. Currently only accepts S3 URLs e.g. s3:///" ) -set(LY_INSTALLER_AWS_PROFILE "" CACHE STRING -"AWS CLI profile for uploading artifacts. Can also be set via LY_INSTALLER_AWS_PROFILE environment variable." +set(CPACK_AWS_PROFILE "" CACHE STRING +"AWS CLI profile for uploading artifacts." ) +set(CPACK_THREADS 0) set(CPACK_DESIRED_CMAKE_VERSION 3.20.2) +if(${CPACK_DESIRED_CMAKE_VERSION} VERSION_LESS ${CMAKE_MINIMUM_REQUIRED_VERSION}) + message(FATAL_ERROR + "The desired version of CMake to be included in the package is " + "below the minimum required version of CMake to run") +endif() # set all common cpack variable overrides first so they can be accessible via configure_file # when the platform specific settings are applied below. additionally, any variable with @@ -44,15 +49,16 @@ set(CPACK_DESIRED_CMAKE_VERSION 3.20.2) set(CPACK_PACKAGE_NAME "${PROJECT_NAME}") set(CPACK_PACKAGE_FULL_NAME "Open3D Engine") set(CPACK_PACKAGE_VENDOR "O3DE Binary Project a Series of LF Projects, LLC") +set(CPACK_PACKAGE_CONTACT "info@o3debinaries.org") set(CPACK_PACKAGE_VERSION "${LY_VERSION_STRING}") set(CPACK_PACKAGE_DESCRIPTION_SUMMARY "Installation Tool") string(TOLOWER "${CPACK_PACKAGE_NAME}_${CPACK_PACKAGE_VERSION}" CPACK_PACKAGE_FILE_NAME) set(DEFAULT_LICENSE_NAME "Apache-2.0") -set(DEFAULT_LICENSE_FILE "${CMAKE_CURRENT_SOURCE_DIR}/LICENSE.txt") -set(CPACK_RESOURCE_FILE_LICENSE ${DEFAULT_LICENSE_FILE}) +set(CPACK_RESOURCE_FILE_LICENSE "${CMAKE_CURRENT_SOURCE_DIR}/LICENSE.txt") +set(CPACK_RESOURCE_FILE_README "${CMAKE_CURRENT_SOURCE_DIR}/README.md") set(CPACK_LICENSE_URL ${LY_INSTALLER_LICENSE_URL}) set(CPACK_PACKAGE_INSTALL_DIRECTORY "${CPACK_PACKAGE_NAME}/${CPACK_PACKAGE_VERSION}") @@ -60,6 +66,7 @@ set(CPACK_PACKAGE_INSTALL_DIRECTORY "${CPACK_PACKAGE_NAME}/${CPACK_PACKAGE_VERSI # neither of the SOURCE_DIR variables equate to anything during execution of pre/post build scripts set(CPACK_SOURCE_DIR ${CMAKE_CURRENT_SOURCE_DIR}/cmake) set(CPACK_BINARY_DIR ${CMAKE_BINARY_DIR}/_CPack) # to match other CPack out dirs +set(CPACK_OUTPUT_FILE_PREFIX CPackUploads) # this config file allows the dynamic setting of cpack variables at cpack-time instead of cmake configure set(CPACK_PROJECT_CONFIG_FILE ${CPACK_SOURCE_DIR}/PackagingConfig.cmake) @@ -74,97 +81,104 @@ if(NOT CPACK_GENERATOR) return() endif() -if(${CPACK_DESIRED_CMAKE_VERSION} VERSION_LESS ${CMAKE_MINIMUM_REQUIRED_VERSION}) - message(FATAL_ERROR - "The desired version of CMake to be included in the package is " - "below the minimum required version of CMake to run") -endif() - -# pull down the desired copy of CMake so it can be included in the package +# We will download the desired copy of CMake so it can be included in the package, we defer the downloading +# to the install process, to do so we generate a script that will perform the download and execute such script +# during the install process (before packaging) if(NOT (CPACK_CMAKE_PACKAGE_FILE AND CPACK_CMAKE_PACKAGE_HASH)) message(FATAL_ERROR "Packaging is missing one or more following properties required to include CMake: " " CPACK_CMAKE_PACKAGE_FILE, CPACK_CMAKE_PACKAGE_HASH") endif() -set(_cmake_package_dest ${CPACK_BINARY_DIR}/${CPACK_CMAKE_PACKAGE_FILE}) +# We download it to a different location because CPACK_PACKAGING_INSTALL_PREFIX will be removed during +# cpack generation. CPACK_BINARY_DIR persists across cpack invocations +set(LY_CMAKE_PACKAGE_DOWNLOAD_PATH ${CPACK_BINARY_DIR}/${CPACK_CMAKE_PACKAGE_FILE}) -if(EXISTS ${_cmake_package_dest}) - file(SHA256 ${_cmake_package_dest} hash_of_downloaded_file) - if (NOT "${hash_of_downloaded_file}" STREQUAL "${CPACK_CMAKE_PACKAGE_HASH}") - message(STATUS "CMake ${CPACK_DESIRED_CMAKE_VERSION} found at ${_cmake_package_dest} but expected hash missmatches, re-downloading...") - file(REMOVE ${_cmake_package_dest}) - else() - message(STATUS "CMake ${CPACK_DESIRED_CMAKE_VERSION} found") - endif() -endif() -if(NOT EXISTS ${_cmake_package_dest}) - # download it - string(REPLACE "." ";" _version_componets "${CPACK_DESIRED_CMAKE_VERSION}") - list(GET _version_componets 0 _major_version) - list(GET _version_componets 1 _minor_version) - - set(_url_version_tag "v${_major_version}.${_minor_version}") - set(_package_url "https://cmake.org/files/${_url_version_tag}/${CPACK_CMAKE_PACKAGE_FILE}") - - message(STATUS "Downloading CMake ${CPACK_DESIRED_CMAKE_VERSION} for packaging...") - download_file( - URL ${_package_url} - TARGET_FILE ${_cmake_package_dest} - EXPECTED_HASH ${CPACK_CMAKE_PACKAGE_HASH} - RESULTS _results - ) - list(GET _results 0 _status_code) - - if (${_status_code} EQUAL 0 AND EXISTS ${_cmake_package_dest}) - message(STATUS "CMake ${CPACK_DESIRED_CMAKE_VERSION} found") - else() - file(REMOVE ${_cmake_package_dest}) - list(REMOVE_AT _results 0) - - set(_error_message "An error occurred, code ${_status_code}. URL ${_package_url} - ${_results}") - - if(${_status_code} EQUAL 1) - string(APPEND _error_message - " Please double check the CPACK_CMAKE_PACKAGE_FILE and " - "CPACK_CMAKE_PACKAGE_HASH properties before trying again.") - endif() - - message(FATAL_ERROR ${_error_message}) - endif() -endif() - -install(FILES ${_cmake_package_dest} - DESTINATION ./Tools/Redistributables/CMake +configure_file(${LY_ROOT_FOLDER}/cmake/Packaging/CMakeDownload.cmake.in + ${CPACK_BINARY_DIR}/CMakeDownload.cmake + @ONLY +) +ly_install(SCRIPT ${CPACK_BINARY_DIR}/CMakeDownload.cmake + COMPONENT ${CMAKE_INSTALL_DEFAULT_COMPONENT_NAME} +) +ly_install(FILES ${LY_CMAKE_PACKAGE_DOWNLOAD_PATH} + DESTINATION Tools/Redistributables/CMake + COMPONENT ${CMAKE_INSTALL_DEFAULT_COMPONENT_NAME} ) -# the version string and git tags are intended to be synchronized so it should be safe to use that instead -# of directly calling into git which could get messy in certain scenarios -if(${CPACK_PACKAGE_VERSION} VERSION_GREATER "0.0.0.0") - set(_3rd_party_license_filename NOTICES.txt) +# Set common CPACK variables to all platforms/generators +set(CPACK_STRIP_FILES TRUE) # always strip symbols on packaging +set(CPACK_PACKAGE_CHECKSUM SHA256) # Generate checksum file +set(CPACK_PRE_BUILD_SCRIPTS ${pal_dir}/PackagingPreBuild_${PAL_HOST_PLATFORM_NAME_LOWERCASE}.cmake) +set(CPACK_POST_BUILD_SCRIPTS ${pal_dir}/PackagingPostBuild_${PAL_HOST_PLATFORM_NAME_LOWERCASE}.cmake) +set(CPACK_LY_PYTHON_CMD ${LY_PYTHON_CMD}) - set(_3rd_party_license_url "https://raw.githubusercontent.com/o3de/3p-package-source/${CPACK_PACKAGE_VERSION}/${_3rd_party_license_filename}") - set(_3rd_party_license_dest ${CPACK_BINARY_DIR}/${_3rd_party_license_filename}) +# IMPORTANT: required to be included AFTER setting all property overrides +include(CPack REQUIRED) - # use the plain file downloader as we don't have the file hash available and using a dummy will - # delete the file once it fails hash verification - file(DOWNLOAD - ${_3rd_party_license_url} - ${_3rd_party_license_dest} - STATUS _status - TLS_VERIFY ON - ) - list(POP_FRONT _status _status_code) +# configure ALL components here +file(APPEND "${CPACK_OUTPUT_CONFIG_FILE}" " +set(CPACK_COMPONENTS_ALL ${CMAKE_INSTALL_DEFAULT_COMPONENT_NAME}) +set(CPACK_COMPONENT_${CMAKE_INSTALL_DEFAULT_COMPONENT_NAME}_DISPLAY_NAME \"Common files\") +set(CPACK_COMPONENT_${CMAKE_INSTALL_DEFAULT_COMPONENT_NAME}_DESCRIPTION \"${PROJECT_NAME} Headers, scripts and common files\") +set(CPACK_COMPONENT_${CMAKE_INSTALL_DEFAULT_COMPONENT_NAME}_REQUIRED TRUE) +set(CPACK_COMPONENT_${CMAKE_INSTALL_DEFAULT_COMPONENT_NAME}_DISABLED FALSE) - if (${_status_code} EQUAL 0 AND EXISTS ${_3rd_party_license_dest}) - install(FILES ${_3rd_party_license_dest} - DESTINATION . - ) - else() - file(REMOVE ${_3rd_party_license_dest}) - message(FATAL_ERROR "Failed to acquire the 3rd Party license manifest file at ${_3rd_party_license_url}. Error: ${_status}") - endif() +include(CPackComponents.cmake) +") + +# Generate a file (CPackComponents.config) that we will include that defines the components +# for this build permutation. This way we can get components for other permutations being passed +# through LY_INSTALL_EXTERNAL_BUILD_DIRS +unset(cpack_components_contents) + +set(required "FALSE") +set(disabled "FALSE") +if(${LY_INSTALL_PERMUTATION_COMPONENT} STREQUAL DEFAULT) + set(required "TRUE") +else() + set(disabled "TRUE") endif() +string(APPEND cpack_components_contents " +list(APPEND CPACK_COMPONENTS_ALL ${LY_INSTALL_PERMUTATION_COMPONENT}) +set(CPACK_COMPONENT_${LY_INSTALL_PERMUTATION_COMPONENT}_DISPLAY_NAME \"${LY_BUILD_PERMUTATION} common files\") +set(CPACK_COMPONENT_${LY_INSTALL_PERMUTATION_COMPONENT}_DESCRIPTION \"${PROJECT_NAME} scripts and common files for ${LY_BUILD_PERMUTATION}\") +set(CPACK_COMPONENT_${LY_INSTALL_PERMUTATION_COMPONENT}_DEPENDS ${CMAKE_INSTALL_DEFAULT_COMPONENT_NAME}) +set(CPACK_COMPONENT_${LY_INSTALL_PERMUTATION_COMPONENT}_REQUIRED ${required}) +set(CPACK_COMPONENT_${LY_INSTALL_PERMUTATION_COMPONENT}_DISABLED ${disabled}) +") + +foreach(conf IN LISTS CMAKE_CONFIGURATION_TYPES) + string(TOUPPER ${conf} UCONF) + set(required "FALSE") + set(disabled "FALSE") + if(${conf} STREQUAL profile AND ${LY_INSTALL_PERMUTATION_COMPONENT} STREQUAL DEFAULT) + set(required "TRUE") + else() + set(disabled "TRUE") + endif() + + # Inject a check to not declare components that have not been built. We are using AzCore since that is a + # common target that will always be build, in every permutation and configuration + string(APPEND cpack_components_contents " +if(EXISTS \"${CMAKE_ARCHIVE_OUTPUT_DIRECTORY}/${conf}/${CMAKE_STATIC_LIBRARY_PREFIX}AzCore${CMAKE_STATIC_LIBRARY_SUFFIX}\") + list(APPEND CPACK_COMPONENTS_ALL ${LY_INSTALL_PERMUTATION_COMPONENT}_${UCONF}) + set(CPACK_COMPONENT_${LY_INSTALL_PERMUTATION_COMPONENT}_${UCONF}_DISPLAY_NAME \"Binaries for ${LY_BUILD_PERMUTATION} ${conf}\") + set(CPACK_COMPONENT_${LY_INSTALL_PERMUTATION_COMPONENT}_${UCONF}_DESCRIPTION \"${PROJECT_NAME} libraries and applications for ${LY_BUILD_PERMUTATION} ${conf}\") + set(CPACK_COMPONENT_${LY_INSTALL_PERMUTATION_COMPONENT}_${UCONF}_DEPENDS ${LY_INSTALL_PERMUTATION_COMPONENT}) + set(CPACK_COMPONENT_${LY_INSTALL_PERMUTATION_COMPONENT}_${UCONF}_REQUIRED ${required}) + set(CPACK_COMPONENT_${LY_INSTALL_PERMUTATION_COMPONENT}_${UCONF}_DISABLED ${disabled}) +endif() +") +endforeach() +file(WRITE "${CMAKE_BINARY_DIR}/CPackComponents.cmake" ${cpack_components_contents}) + +# Inject other build directories +foreach(external_dir ${LY_INSTALL_EXTERNAL_BUILD_DIRS}) + file(APPEND "${CPACK_OUTPUT_CONFIG_FILE}" + "include(${external_dir}/CPackComponents.cmake)\n" + ) +endforeach() # checks for and removes trailing slash function(strip_trailing_slash in_url out_url) @@ -179,75 +193,13 @@ function(strip_trailing_slash in_url out_url) endif() endfunction() -if(NOT LY_INSTALLER_UPLOAD_URL AND DEFINED ENV{LY_INSTALLER_UPLOAD_URL}) - set(LY_INSTALLER_UPLOAD_URL $ENV{LY_INSTALLER_UPLOAD_URL}) -endif() - -if(LY_INSTALLER_UPLOAD_URL) - ly_is_s3_url(${LY_INSTALLER_UPLOAD_URL} _is_s3_bucket) - if(NOT _is_s3_bucket) - message(FATAL_ERROR "Only S3 installer uploading is supported at this time") - endif() - - if (LY_INSTALLER_AWS_PROFILE) - set(CPACK_AWS_PROFILE ${LY_INSTALLER_AWS_PROFILE}) - elseif (DEFINED ENV{LY_INSTALLER_AWS_PROFILE}) - set(CPACK_AWS_PROFILE $ENV{LY_INSTALLER_AWS_PROFILE}) - endif() - - strip_trailing_slash(${LY_INSTALLER_UPLOAD_URL} LY_INSTALLER_UPLOAD_URL) - set(CPACK_UPLOAD_URL ${LY_INSTALLER_UPLOAD_URL}) -endif() - -# IMPORTANT: required to be included AFTER setting all property overrides -include(CPack REQUIRED) - -function(ly_configure_cpack_component ly_configure_cpack_component_NAME) - - set(options REQUIRED) - set(oneValueArgs DISPLAY_NAME DESCRIPTION LICENSE_NAME LICENSE_FILE) - set(multiValueArgs) - - cmake_parse_arguments(ly_configure_cpack_component "${options}" "${oneValueArgs}" "${multiValueArgs}" ${ARGN}) - - # default to optional - set(component_type DISABLED) - - if(ly_configure_cpack_component_REQUIRED) - set(component_type REQUIRED) - endif() - - set(license_name ${DEFAULT_LICENSE_NAME}) - set(license_file ${DEFAULT_LICENSE_FILE}) - - if(ly_configure_cpack_component_LICENSE_NAME AND ly_configure_cpack_component_LICENSE_FILE) - set(license_name ${ly_configure_cpack_component_LICENSE_NAME}) - set(license_file ${ly_configure_cpack_component_LICENSE_FILE}) - elseif(ly_configure_cpack_component_LICENSE_NAME OR ly_configure_cpack_component_LICENSE_FILE) - message(FATAL_ERROR "Invalid argument configuration. Both LICENSE_NAME and LICENSE_FILE must be set for ly_configure_cpack_component") - endif() - - cpack_add_component( - ${ly_configure_cpack_component_NAME} ${component_type} - DISPLAY_NAME ${ly_configure_cpack_component_DISPLAY_NAME} - DESCRIPTION ${ly_configure_cpack_component_DESCRIPTION} - ) -endfunction() - -# configure ALL components here -ly_configure_cpack_component( - ${CMAKE_INSTALL_DEFAULT_COMPONENT_NAME} REQUIRED - DISPLAY_NAME "${PROJECT_NAME} Core" - DESCRIPTION "${PROJECT_NAME} Headers, Libraries and Tools" -) - if(LY_INSTALLER_DOWNLOAD_URL) strip_trailing_slash(${LY_INSTALLER_DOWNLOAD_URL} LY_INSTALLER_DOWNLOAD_URL) # this will set the following variables: CPACK_DOWNLOAD_SITE, CPACK_DOWNLOAD_ALL, and CPACK_UPLOAD_DIRECTORY (local) cpack_configure_downloads( ${LY_INSTALLER_DOWNLOAD_URL} - UPLOAD_DIRECTORY ${CMAKE_BINARY_DIR}/_CPack_Uploads # to match the _CPack_Packages directory + UPLOAD_DIRECTORY ${CMAKE_BINARY_DIR}/CPackUploads # to match the _CPack_Packages directory ALL ) endif() diff --git a/cmake/Packaging/CMakeDownload.cmake.in b/cmake/Packaging/CMakeDownload.cmake.in new file mode 100644 index 0000000000..e84611b354 --- /dev/null +++ b/cmake/Packaging/CMakeDownload.cmake.in @@ -0,0 +1,54 @@ +# +# Copyright (c) Contributors to the Open 3D Engine Project. +# For complete copyright and license terms please see the LICENSE at the root of this distribution. +# +# SPDX-License-Identifier: Apache-2.0 OR MIT +# +# + +set(LY_ROOT_FOLDER "@LY_ROOT_FOLDER@") +set(CMAKE_SCRIPT_MODE_FILE TRUE) +include(@LY_ROOT_FOLDER@/cmake/3rdPartyPackages.cmake) + +if(EXISTS "@LY_CMAKE_PACKAGE_DOWNLOAD_PATH@") + file(SHA256 "@LY_CMAKE_PACKAGE_DOWNLOAD_PATH@" hash_of_downloaded_file) + if (NOT "${hash_of_downloaded_file}" STREQUAL "@CPACK_CMAKE_PACKAGE_HASH@") + message(STATUS "CMake @CPACK_DESIRED_CMAKE_VERSION@ found at @LY_CMAKE_PACKAGE_DOWNLOAD_PATH@ but expected hash missmatches, re-downloading...") + file(REMOVE "@LY_CMAKE_PACKAGE_DOWNLOAD_PATH@") + else() + message(STATUS "CMake @CPACK_DESIRED_CMAKE_VERSION@ found") + endif() +endif() +if(NOT EXISTS "@LY_CMAKE_PACKAGE_DOWNLOAD_PATH@") + # download it + string(REPLACE "." ";" _version_components "@CPACK_DESIRED_CMAKE_VERSION@") + list(GET _version_components 0 _major_version) + list(GET _version_components 1 _minor_version) + + set(_url_version_tag "v${_major_version}.${_minor_version}") + set(_package_url "https://cmake.org/files/${_url_version_tag}/@CPACK_CMAKE_PACKAGE_FILE@") + + message(STATUS "Downloading CMake @CPACK_DESIRED_CMAKE_VERSION@ for packaging...") + download_file( + URL ${_package_url} + TARGET_FILE @LY_CMAKE_PACKAGE_DOWNLOAD_PATH@ + EXPECTED_HASH @CPACK_CMAKE_PACKAGE_HASH@ + RESULTS _results + ) + list(GET _results 0 _status_code) + + if (${_status_code} EQUAL 0 AND EXISTS "@LY_CMAKE_PACKAGE_DOWNLOAD_PATH@") + message(STATUS "CMake @CPACK_DESIRED_CMAKE_VERSION@ found") + else() + file(REMOVE "@LY_CMAKE_PACKAGE_DOWNLOAD_PATH@") + list(REMOVE_AT _results 0) + + set(_error_message "An error occurred, code ${_status_code}. URL ${_package_url} - ${_results}") + if(${_status_code} EQUAL 1) + string(APPEND _error_message + " Please double check the CPACK_CMAKE_PACKAGE_FILE and " + "CPACK_CMAKE_PACKAGE_HASH properties before trying again.") + endif() + message(FATAL_ERROR ${_error_message}) + endif() +endif() diff --git a/cmake/Platform/Common/Install_common.cmake b/cmake/Platform/Common/Install_common.cmake index f844b1bec9..46130f1345 100644 --- a/cmake/Platform/Common/Install_common.cmake +++ b/cmake/Platform/Common/Install_common.cmake @@ -8,6 +8,14 @@ include(cmake/FileUtil.cmake) +set(LY_INSTALL_EXTERNAL_BUILD_DIRS "" CACHE PATH "External build directories to be included in the install process. This allows to package non-monolithic and monolithic.") +unset(normalized_external_build_dirs) +foreach(external_dir ${LY_INSTALL_EXTERNAL_BUILD_DIRS}) + cmake_path(ABSOLUTE_PATH external_dir BASE_DIRECTORY ${LY_ROOT_FOLDER} NORMALIZE) + list(APPEND normalized_external_build_dirs ${external_dir}) +endforeach() +set(LY_INSTALL_EXTERNAL_BUILD_DIRS ${normalized_external_build_dirs}) + set(CMAKE_INSTALL_MESSAGE NEVER) # Simplify messages to reduce output noise define_property(TARGET PROPERTY LY_INSTALL_GENERATE_RUN_TARGET @@ -19,13 +27,25 @@ define_property(TARGET PROPERTY LY_INSTALL_GENERATE_RUN_TARGET ]] ) -ly_set(CMAKE_INSTALL_DEFAULT_COMPONENT_NAME Core) +# We can have elements being installed under the following components: +# - Core (required for all) (default) +# - Default +# - Default_$ +# - Monolithic +# - Monolithic_$ +# Debug/Monolithic are build permutations, so for a CMake run, it can only generate +# one of the permutations. Each build permutation can generate only one cmake_install.cmake. +# Each build permutation will generate the same elements in Core. +# CPack is able to put the two together by taking Core from one permutation and then taking +# each permutation. +ly_set(CMAKE_INSTALL_DEFAULT_COMPONENT_NAME CORE) if(LY_MONOLITHIC_GAME) set(LY_BUILD_PERMUTATION Monolithic) else() set(LY_BUILD_PERMUTATION Default) endif() +string(TOUPPER ${LY_BUILD_PERMUTATION} LY_INSTALL_PERMUTATION_COMPONENT) cmake_path(RELATIVE_PATH CMAKE_RUNTIME_OUTPUT_DIRECTORY BASE_DIRECTORY ${CMAKE_BINARY_DIR} OUTPUT_VARIABLE runtime_output_directory) cmake_path(RELATIVE_PATH CMAKE_LIBRARY_OUTPUT_DIRECTORY BASE_DIRECTORY ${CMAKE_BINARY_DIR} OUTPUT_VARIABLE library_output_directory) @@ -65,14 +85,24 @@ function(ly_setup_target OUTPUT_CONFIGURED_TARGET ALIAS_TARGET_NAME absolute_tar continue() endif() + # For some cases (e.g. codegen) we generate headers that end up in the BUILD_DIR. Since the BUILD_DIR + # is per-permutation, we need to install such headers per permutation. For the other cases, we can install + # under the default component since they are shared across permutations/configs. + cmake_path(IS_PREFIX CMAKE_BINARY_DIR ${include_directory} NORMALIZE include_directory_child_of_build) + if(NOT include_directory_child_of_build) + set(include_directory_component ${CMAKE_INSTALL_DEFAULT_COMPONENT_NAME}) + else() + set(include_directory_component ${LY_INSTALL_PERMUTATION_COMPONENT}) + endif() + unset(rel_include_dir) cmake_path(RELATIVE_PATH include_directory BASE_DIRECTORY ${LY_ROOT_FOLDER} OUTPUT_VARIABLE rel_include_dir) cmake_path(APPEND rel_include_dir "..") cmake_path(NORMAL_PATH rel_include_dir OUTPUT_VARIABLE destination_dir) - - install(DIRECTORY ${include_directory} + + ly_install(DIRECTORY ${include_directory} DESTINATION ${destination_dir} - COMPONENT ${CMAKE_INSTALL_DEFAULT_COMPONENT_NAME} + COMPONENT ${include_directory_component} FILES_MATCHING PATTERN *.h PATTERN *.hpp @@ -94,9 +124,9 @@ function(ly_setup_target OUTPUT_CONFIGURED_TARGET ALIAS_TARGET_NAME absolute_tar cmake_path(RELATIVE_PATH target_library_output_directory BASE_DIRECTORY ${CMAKE_LIBRARY_OUTPUT_DIRECTORY} OUTPUT_VARIABLE target_library_output_subdirectory) endif() - if(COMMAND ly_install_target_override) + if(COMMAND ly_setup_target_install_targets_override) # Mac needs special handling because of a cmake issue - ly_install_target_override(TARGET ${TARGET_NAME} + ly_setup_target_install_targets_override(TARGET ${TARGET_NAME} ARCHIVE_DIR ${archive_output_directory} LIBRARY_DIR ${library_output_directory} RUNTIME_DIR ${runtime_output_directory} @@ -104,18 +134,23 @@ function(ly_setup_target OUTPUT_CONFIGURED_TARGET ALIAS_TARGET_NAME absolute_tar RUNTIME_SUBDIR ${target_runtime_output_subdirectory} ) else() - install( - TARGETS ${TARGET_NAME} - ARCHIVE - DESTINATION ${archive_output_directory} - COMPONENT ${CMAKE_INSTALL_DEFAULT_COMPONENT_NAME} - LIBRARY - DESTINATION ${library_output_directory}/${target_library_output_subdirectory} - COMPONENT ${CMAKE_INSTALL_DEFAULT_COMPONENT_NAME} - RUNTIME - DESTINATION ${runtime_output_directory}/${target_runtime_output_subdirectory} - COMPONENT ${CMAKE_INSTALL_DEFAULT_COMPONENT_NAME} - ) + foreach(conf IN LISTS CMAKE_CONFIGURATION_TYPES) + string(TOUPPER ${conf} UCONF) + ly_install(TARGETS ${TARGET_NAME} + ARCHIVE + DESTINATION ${archive_output_directory} + COMPONENT ${LY_INSTALL_PERMUTATION_COMPONENT}_${UCONF} + CONFIGURATIONS ${conf} + LIBRARY + DESTINATION ${library_output_directory}/${target_library_output_subdirectory} + COMPONENT ${LY_INSTALL_PERMUTATION_COMPONENT}_${UCONF} + CONFIGURATIONS ${conf} + RUNTIME + DESTINATION ${runtime_output_directory}/${target_runtime_output_subdirectory} + COMPONENT ${LY_INSTALL_PERMUTATION_COMPONENT}_${UCONF} + CONFIGURATIONS ${conf} + ) + endforeach() endif() # CMakeLists.txt related files @@ -189,8 +224,14 @@ function(ly_setup_target OUTPUT_CONFIGURED_TARGET ALIAS_TARGET_NAME absolute_tar if("${target_type}" STREQUAL "STATIC_LIBRARY") set(build_deps_target "${build_deps_target};${build_deps_PRIVATE}") endif() - # But we will also pass the private dependencies as runtime dependencies (note the comment above) - set(RUNTIME_DEPENDENCIES_PLACEHOLDER ${build_deps_PRIVATE}) + + # But we will also pass the private dependencies as runtime dependencies (as long as they are targets, note the comment above) + foreach(build_dep_private IN LISTS build_deps_PRIVATE) + if(TARGET ${build_dep_private}) + list(APPEND RUNTIME_DEPENDENCIES_PLACEHOLDER "${build_dep_private}") + endif() + endforeach() + foreach(build_dependency IN LISTS build_deps_target) # Skip wrapping produced when targets are not created in the same directory if(build_dependency) @@ -280,10 +321,15 @@ set_property(TARGET ${NAME_PLACEHOLDER} set(target_install_source_dir ${CMAKE_CURRENT_BINARY_DIR}/install/${relative_target_source_dir}) file(GENERATE OUTPUT "${target_install_source_dir}/Platform/${PAL_PLATFORM_NAME}/${LY_BUILD_PERMUTATION}/${NAME_PLACEHOLDER}_$.cmake" CONTENT "${target_file_contents}") - install(FILES "${target_install_source_dir}/Platform/${PAL_PLATFORM_NAME}/${LY_BUILD_PERMUTATION}/${NAME_PLACEHOLDER}_$.cmake" - DESTINATION ${relative_target_source_dir}/Platform/${PAL_PLATFORM_NAME}/${LY_BUILD_PERMUTATION} - COMPONENT ${CMAKE_INSTALL_DEFAULT_COMPONENT_NAME} - ) + + foreach(conf IN LISTS CMAKE_CONFIGURATION_TYPES) + string(TOUPPER ${conf} UCONF) + ly_install(FILES "${target_install_source_dir}/Platform/${PAL_PLATFORM_NAME}/${LY_BUILD_PERMUTATION}/${NAME_PLACEHOLDER}_${conf}.cmake" + DESTINATION ${relative_target_source_dir}/Platform/${PAL_PLATFORM_NAME}/${LY_BUILD_PERMUTATION} + COMPONENT ${LY_INSTALL_PERMUTATION_COMPONENT}_${UCONF} + CONFIGURATIONS ${conf} + ) + endforeach() # Since a CMakeLists.txt could contain multiple targets, we generate it in a folder per target ly_file_read(${LY_ROOT_FOLDER}/cmake/install/InstalledTarget.in target_cmakelists_template) @@ -323,7 +369,8 @@ function(ly_setup_subdirectory absolute_target_source_dir) @cmake_copyright_comment@ include(Platform/${PAL_PLATFORM_NAME}/platform_${PAL_PLATFORM_NAME_LOWERCASE}.cmake) ]] @ONLY) - install(FILES "${target_install_source_dir}/CMakeLists.txt" + + ly_install(FILES "${target_install_source_dir}/CMakeLists.txt" DESTINATION ${relative_target_source_dir} COMPONENT ${CMAKE_INSTALL_DEFAULT_COMPONENT_NAME} ) @@ -338,7 +385,7 @@ else() include(Platform/${PAL_PLATFORM_NAME}/Default/permutation.cmake) endif() ]]) - install(FILES "${target_install_source_dir}/Platform/${PAL_PLATFORM_NAME}/platform_${PAL_PLATFORM_NAME_LOWERCASE}.cmake" + ly_install(FILES "${target_install_source_dir}/Platform/${PAL_PLATFORM_NAME}/platform_${PAL_PLATFORM_NAME_LOWERCASE}.cmake" DESTINATION ${relative_target_source_dir}/Platform/${PAL_PLATFORM_NAME} COMPONENT ${CMAKE_INSTALL_DEFAULT_COMPONENT_NAME} ) @@ -358,9 +405,10 @@ endif() "${GEM_VARIANT_TO_LOAD_PLACEHOLDER}" "${ENABLE_GEMS_PLACEHOLDER}" ) - install(FILES "${target_install_source_dir}/Platform/${PAL_PLATFORM_NAME}/${LY_BUILD_PERMUTATION}/permutation.cmake" - DESTINATION ${relative_target_source_dir}//Platform/${PAL_PLATFORM_NAME}/${LY_BUILD_PERMUTATION} - COMPONENT ${CMAKE_INSTALL_DEFAULT_COMPONENT_NAME} + + ly_install(FILES "${target_install_source_dir}/Platform/${PAL_PLATFORM_NAME}/${LY_BUILD_PERMUTATION}/permutation.cmake" + DESTINATION ${relative_target_source_dir}/Platform/${PAL_PLATFORM_NAME}/${LY_BUILD_PERMUTATION} + COMPONENT ${LY_INSTALL_PERMUTATION_COMPONENT} ) endfunction() @@ -368,7 +416,7 @@ endfunction() #! ly_setup_cmake_install: install the "cmake" folder function(ly_setup_cmake_install) - install(DIRECTORY "${LY_ROOT_FOLDER}/cmake" + ly_install(DIRECTORY "${LY_ROOT_FOLDER}/cmake" DESTINATION . COMPONENT ${CMAKE_INSTALL_DEFAULT_COMPONENT_NAME} PATTERN "__pycache__" EXCLUDE @@ -378,22 +426,24 @@ function(ly_setup_cmake_install) ) # Connect configuration types - install(FILES "${LY_ROOT_FOLDER}/cmake/install/ConfigurationTypes.cmake" + ly_install(FILES "${LY_ROOT_FOLDER}/cmake/install/ConfigurationTypes.cmake" DESTINATION cmake COMPONENT ${CMAKE_INSTALL_DEFAULT_COMPONENT_NAME} ) - # Inject code that will generate each ConfigurationType_.cmake file - set(install_configuration_type_template [=[ - configure_file(@LY_ROOT_FOLDER@/cmake/install/ConfigurationType_config.cmake.in - ${CMAKE_INSTALL_PREFIX}/cmake/Platform/@PAL_PLATFORM_NAME@/@LY_BUILD_PERMUTATION@/ConfigurationTypes_${CMAKE_INSTALL_CONFIG_NAME}.cmake + + # generate each ConfigurationType_.cmake file and install it under that configuration + foreach(conf IN LISTS CMAKE_CONFIGURATION_TYPES) + string(TOUPPER ${conf} UCONF) + configure_file("${LY_ROOT_FOLDER}/cmake/install/ConfigurationType_config.cmake.in" + "${CMAKE_BINARY_DIR}/cmake/Platform/${PAL_PLATFORM_NAME}/${LY_BUILD_PERMUTATION}/ConfigurationTypes_${conf}.cmake" @ONLY ) - message(STATUS "Generated ${CMAKE_INSTALL_PREFIX}/cmake/Platform/@PAL_PLATFORM_NAME@/@LY_BUILD_PERMUTATION@/ConfigurationTypes_${CMAKE_INSTALL_CONFIG_NAME}.cmake") - ]=]) - string(CONFIGURE "${install_configuration_type_template}" install_configuration_type @ONLY) - install(CODE "${install_configuration_type}" - COMPONENT ${CMAKE_INSTALL_DEFAULT_COMPONENT_NAME} - ) + ly_install(FILES "${CMAKE_BINARY_DIR}/cmake/Platform/${PAL_PLATFORM_NAME}/${LY_BUILD_PERMUTATION}/ConfigurationTypes_${conf}.cmake" + DESTINATION cmake/Platform/${PAL_PLATFORM_NAME}/${LY_BUILD_PERMUTATION} + COMPONENT ${LY_INSTALL_PERMUTATION_COMPONENT}_${UCONF} + CONFIGURATIONS ${conf} + ) + endforeach() # Transform the LY_EXTERNAL_SUBDIRS list into a json array set(indent " ") @@ -412,8 +462,7 @@ function(ly_setup_cmake_install) configure_file(${LY_ROOT_FOLDER}/cmake/install/engine.json.in ${CMAKE_CURRENT_BINARY_DIR}/cmake/engine.json @ONLY) - install( - FILES + ly_install(FILES "${LY_ROOT_FOLDER}/CMakeLists.txt" "${CMAKE_CURRENT_BINARY_DIR}/cmake/engine.json" DESTINATION . @@ -437,18 +486,18 @@ function(ly_setup_cmake_install) endforeach() endforeach() - install(FILES ${additional_find_files} + ly_install(FILES ${additional_find_files} DESTINATION cmake/3rdParty COMPONENT ${CMAKE_INSTALL_DEFAULT_COMPONENT_NAME} ) - install(FILES ${additional_platform_files} + ly_install(FILES ${additional_platform_files} DESTINATION cmake/3rdParty/Platform/${PAL_PLATFORM_NAME} COMPONENT ${CMAKE_INSTALL_DEFAULT_COMPONENT_NAME} ) # Findo3de.cmake file: we generate a different Findo3de.cmake file than the one we have in the source dir. configure_file(${LY_ROOT_FOLDER}/cmake/install/Findo3de.cmake.in ${CMAKE_CURRENT_BINARY_DIR}/cmake/Findo3de.cmake @ONLY) - install(FILES "${CMAKE_CURRENT_BINARY_DIR}/cmake/Findo3de.cmake" + ly_install(FILES "${CMAKE_CURRENT_BINARY_DIR}/cmake/Findo3de.cmake" DESTINATION cmake COMPONENT ${CMAKE_INSTALL_DEFAULT_COMPONENT_NAME} ) @@ -467,9 +516,9 @@ function(ly_setup_cmake_install) ${find_subdirectories} " ) - install(FILES "${permutation_find_subdirectories}" + ly_install(FILES "${permutation_find_subdirectories}" DESTINATION cmake/Platform/${PAL_PLATFORM_NAME}/${LY_BUILD_PERMUTATION} - COMPONENT ${CMAKE_INSTALL_DEFAULT_COMPONENT_NAME} + COMPONENT ${LY_INSTALL_PERMUTATION_COMPONENT} ) set(pal_builtin_file ${CMAKE_CURRENT_BINARY_DIR}/cmake/3rdParty/Platform/${PAL_PLATFORM_NAME}/BuiltInPackages_${PAL_PLATFORM_NAME_LOWERCASE}.cmake) @@ -483,7 +532,7 @@ else() endif() " ) - install(FILES "${pal_builtin_file}" + ly_install(FILES "${pal_builtin_file}" DESTINATION cmake/3rdParty/Platform/${PAL_PLATFORM_NAME} COMPONENT ${CMAKE_INSTALL_DEFAULT_COMPONENT_NAME} ) @@ -506,9 +555,9 @@ endif() file(GENERATE OUTPUT ${permutation_builtin_file} CONTENT ${builtinpackages} ) - install(FILES "${permutation_builtin_file}" + ly_install(FILES "${permutation_builtin_file}" DESTINATION cmake/3rdParty/Platform/${PAL_PLATFORM_NAME}/${LY_BUILD_PERMUTATION} - COMPONENT ${CMAKE_INSTALL_DEFAULT_COMPONENT_NAME} + COMPONENT ${LY_INSTALL_PERMUTATION_COMPONENT} ) endfunction() @@ -517,15 +566,27 @@ endfunction() function(ly_setup_runtime_dependencies) # Common functions used by the bellow code - if(COMMAND ly_install_code_function_override) - ly_install_code_function_override() + if(COMMAND ly_setup_runtime_dependencies_copy_function_override) + ly_setup_runtime_dependencies_copy_function_override() else() - install(CODE + # despite this copy function being the same, we need to install it per component that uses it + # (which is per-configuration per-permutation component) + foreach(conf IN LISTS CMAKE_CONFIGURATION_TYPES) + string(TOUPPER ${conf} UCONF) + ly_install(CODE "function(ly_copy source_file target_directory) - file(COPY \"\${source_file}\" DESTINATION \"\${target_directory}\" FILE_PERMISSIONS ${LY_COPY_PERMISSIONS}) + cmake_path(GET source_file FILENAME target_filename) + cmake_path(APPEND full_target_directory \"\$ENV{DESTDIR}\${CMAKE_INSTALL_PREFIX}\" \"\${target_directory}\") + cmake_path(APPEND target_file \"\${full_target_directory}\" \"\${target_filename}\") + if(\"\${source_file}\" IS_NEWER_THAN \"\${target_file}\") + message(STATUS \"Copying \${source_file} to \${full_target_directory}...\") + file(COPY \"\${source_file}\" DESTINATION \"\${full_target_directory}\" FILE_PERMISSIONS ${LY_COPY_PERMISSIONS} FOLLOW_SYMLINK_CHAIN) + file(TOUCH_NOCREATE \"${target_file}\") + endif() endfunction()" - COMPONENT ${CMAKE_INSTALL_DEFAULT_COMPONENT_NAME} - ) + COMPONENT ${LY_INSTALL_PERMUTATION_COMPONENT}_${UCONF} + ) + endforeach() endif() unset(runtime_commands) @@ -545,12 +606,7 @@ endfunction()" endif() # runtime dependencies that need to be copied to the output - # Anywhere CMAKE_INSTALL_PREFIX is used, it has to be escaped so it is baked into the cmake_install.cmake script instead - # of baking the path. This is needed so `cmake --install --prefix ` works regardless of the CMAKE_INSTALL_PREFIX - # used to generate the solution. - # CMAKE_INSTALL_PREFIX is still used when building the INSTALL target - set(install_output_folder "\${CMAKE_INSTALL_PREFIX}/${runtime_output_directory}") - set(target_file_dir "${install_output_folder}/${target_runtime_output_subdirectory}") + set(target_file_dir "${runtime_output_directory}/${target_runtime_output_subdirectory}") ly_get_runtime_dependencies(runtime_dependencies ${target}) foreach(runtime_dependency ${runtime_dependencies}) unset(runtime_command) @@ -564,9 +620,12 @@ endfunction()" list(REMOVE_DUPLICATES runtime_commands) list(JOIN runtime_commands " " runtime_commands_str) # the spaces are just to see the right identation in the cmake_install.cmake file - install(CODE "${runtime_commands_str}" - COMPONENT ${CMAKE_INSTALL_DEFAULT_COMPONENT_NAME} - ) + foreach(conf IN LISTS CMAKE_CONFIGURATION_TYPES) + string(TOUPPER ${conf} UCONF) + ly_install(CODE "${runtime_commands_str}" + COMPONENT ${LY_INSTALL_PERMUTATION_COMPONENT}_${UCONF} + ) + endforeach() endfunction() @@ -653,16 +712,17 @@ function(ly_setup_assets) endif() if(IS_DIRECTORY ${gem_absolute_path}) - install(DIRECTORY "${gem_absolute_path}" + ly_install(DIRECTORY "${gem_absolute_path}" DESTINATION ${gem_install_dest_dir} COMPONENT ${CMAKE_INSTALL_DEFAULT_COMPONENT_NAME} ) elseif (EXISTS ${gem_absolute_path}) - install(FILES ${gem_absolute_path} + ly_install(FILES ${gem_absolute_path} DESTINATION ${gem_install_dest_dir} COMPONENT ${CMAKE_INSTALL_DEFAULT_COMPONENT_NAME} ) endif() + endforeach() endforeach() @@ -733,7 +793,7 @@ function(ly_setup_o3de_install) ly_setup_assets() # Misc - install(FILES + ly_install(FILES ${LY_ROOT_FOLDER}/pytest.ini ${LY_ROOT_FOLDER}/LICENSE.txt ${LY_ROOT_FOLDER}/README.md @@ -743,7 +803,7 @@ function(ly_setup_o3de_install) # Inject other build directories foreach(external_dir ${LY_INSTALL_EXTERNAL_BUILD_DIRS}) - install(CODE + ly_install(CODE "set(LY_CORE_COMPONENT_ALREADY_INCLUDED TRUE) include(${external_dir}/cmake_install.cmake) set(LY_CORE_COMPONENT_ALREADY_INCLUDED FALSE)" @@ -755,4 +815,4 @@ set(LY_CORE_COMPONENT_ALREADY_INCLUDED FALSE)" ly_post_install_steps() endif() -endfunction() \ No newline at end of file +endfunction() diff --git a/cmake/Platform/Common/PackagingPostBuild_common.cmake b/cmake/Platform/Common/PackagingPostBuild_common.cmake new file mode 100644 index 0000000000..6e3c7ddf0b --- /dev/null +++ b/cmake/Platform/Common/PackagingPostBuild_common.cmake @@ -0,0 +1,114 @@ +# +# Copyright (c) Contributors to the Open 3D Engine Project. +# For complete copyright and license terms please see the LICENSE at the root of this distribution. +# +# SPDX-License-Identifier: Apache-2.0 OR MIT +# +# + +message(STATUS "Executing packaging postbuild...") + +# ly_is_s3_url +# if the given URL is a s3 url of thr form "s3://(stuff)" then sets +# the output_variable_name to TRUE otherwise unsets it. +function (ly_is_s3_url download_url output_variable_name) + if ("${download_url}" MATCHES "s3://.*") + set(${output_variable_name} TRUE PARENT_SCOPE) + else() + unset(${output_variable_name} PARENT_SCOPE) + endif() +endfunction() + +function(ly_upload_to_url in_url in_local_path in_file_regex) + + message(STATUS "Uploading ${in_local_path}/${in_file_regex} artifacts to ${CPACK_UPLOAD_URL}") + ly_is_s3_url(${in_url} _is_s3_bucket) + if(NOT _is_s3_bucket) + message(FATAL_ERROR "Only S3 installer uploading is supported at this time") + endif() + + # strip the scheme and extract the bucket/key prefix from the URL + string(REPLACE "s3://" "" _stripped_url ${in_url}) + string(REPLACE "/" ";" _tokens ${_stripped_url}) + + list(POP_FRONT _tokens _bucket) + string(JOIN "/" _prefix ${_tokens}) + + set(_extra_args [[{"ACL":"bucket-owner-full-control"}]]) + + file(TO_NATIVE_PATH "${LY_ROOT_FOLDER}/scripts/build/tools/upload_to_s3.py" _upload_script) + + set(_upload_command + ${CPACK_LY_PYTHON_CMD} -s + -u ${_upload_script} + --base_dir ${in_local_path} + --file_regex="${in_file_regex}" + --bucket ${_bucket} + --key_prefix ${_prefix} + --extra_args ${_extra_args} + ) + + if(CPACK_AWS_PROFILE) + list(APPEND _upload_command --profile ${CPACK_AWS_PROFILE}) + endif() + + execute_process( + COMMAND ${_upload_command} + RESULT_VARIABLE _upload_result + OUTPUT_VARIABLE _upload_output + ERROR_VARIABLE _upload_error + OUTPUT_STRIP_TRAILING_WHITESPACE + ) + + if (${_upload_result} EQUAL 0) + message(STATUS "Artifact uploading complete!") + else() + message(FATAL_ERROR "An error occurred uploading to s3.\n Output: ${_upload_output}\n\ Error: ${_upload_error}") + endif() +endfunction() + +function(ly_upload_to_latest in_url in_path) + + message(STATUS "Updating latest tagged build") + + # make sure we can extra the commit info from the URL first + string(REGEX MATCH "([0-9][0-9][0-9][0-9]-[0-9][0-9]-[0-9][0-9]-[0-9a-zA-Z]+)" + commit_info ${in_url} + ) + if(NOT commit_info) + message(FATAL_ERROR "Failed to extract the build tag") + endif() + + # Create a temp directory where we are going to rename the file to take out the version + # and then upload it + set(temp_dir ${CPACK_BINARY_DIR}/temp) + if(NOT EXISTS ${temp_dir}) + file(MAKE_DIRECTORY ${temp_dir}) + endif() + file(COPY ${in_path} DESTINATION ${temp_dir}) + + cmake_path(GET in_path FILENAME in_path_filename) + string(REPLACE "_${CPACK_PACKAGE_VERSION}" "" non_versioned_in_path_filename ${in_path_filename}) + file(RENAME "${temp_dir}/${in_path_filename}" "${temp_dir}/${non_versioned_in_path_filename}") + + # include the commit info in a text file that will live next to the exe + set(_temp_info_file ${temp_dir}/build_tag.txt) + file(WRITE ${_temp_info_file} ${commit_info}) + + # update the URL and upload + string(REPLACE + ${commit_info} "Latest" + latest_upload_url ${in_url} + ) + + ly_upload_to_url( + ${latest_upload_url} + ${temp_dir} + ".*(${non_versioned_in_path_filename}|build_tag.txt)$" + ) + + # cleanup the temp files + file(REMOVE_RECURSE ${temp_dir}) + message(STATUS "Latest build update complete!") + +endfunction() \ No newline at end of file diff --git a/cmake/Platform/Common/PackagingPreBuild_common.cmake b/cmake/Platform/Common/PackagingPreBuild_common.cmake new file mode 100644 index 0000000000..e6b8a7796e --- /dev/null +++ b/cmake/Platform/Common/PackagingPreBuild_common.cmake @@ -0,0 +1,5 @@ +# For complete copyright and license terms please see the LICENSE at the root of this distribution. +# +# SPDX-License-Identifier: Apache-2.0 OR MIT +# +# diff --git a/cmake/Platform/Common/RuntimeDependencies_common.cmake b/cmake/Platform/Common/RuntimeDependencies_common.cmake index 60e55453f8..a03f7f667b 100644 --- a/cmake/Platform/Common/RuntimeDependencies_common.cmake +++ b/cmake/Platform/Common/RuntimeDependencies_common.cmake @@ -272,7 +272,7 @@ function(ly_delayed_generate_runtime_dependencies) endforeach() # Generate the output file, note the STAMP_OUTPUT_FILE need to match with the one defined in LYWrappers.cmake - set(STAMP_OUTPUT_FILE ${CMAKE_BINARY_DIR}/runtime_dependencies/$/${target}_$.stamp) + set(STAMP_OUTPUT_FILE ${CMAKE_BINARY_DIR}/runtime_dependencies/$/${target}.stamp) set(target_file_dir "$") set(target_file "$") ly_file_read(${LY_RUNTIME_DEPENDENCIES_TEMPLATE} template_file) diff --git a/cmake/Platform/Common/runtime_dependencies_common.cmake.in b/cmake/Platform/Common/runtime_dependencies_common.cmake.in index 6e41dbaad1..8717710a3b 100644 --- a/cmake/Platform/Common/runtime_dependencies_common.cmake.in +++ b/cmake/Platform/Common/runtime_dependencies_common.cmake.in @@ -9,14 +9,22 @@ cmake_policy(SET CMP0012 NEW) # new policy for the if that evaluates a boolean out of "if(NOT ${same_location})" function(ly_copy source_file target_directory) - get_filename_component(target_filename "${source_file}" NAME) - cmake_path(COMPARE "${source_file}" EQUAL "${target_directory}/${target_filename}" same_location) + cmake_path(GET source_file FILENAME target_filename) + cmake_path(APPEND target_file "${target_directory}" "${target_filename}") + cmake_path(COMPARE "${source_file}" EQUAL "${target_file}" same_location) if(NOT ${same_location}) - file(LOCK ${target_directory}/${target_filename}.lock GUARD FUNCTION TIMEOUT 300) - if("${source_file}" IS_NEWER_THAN "${target_directory}/${target_filename}") + file(LOCK ${target_file}.lock GUARD FUNCTION TIMEOUT 300) + file(SIZE "${source_file}" source_file_size) + if(EXISTS "${target_file}") + file(SIZE "${target_file}" target_file_size) + else() + set(target_file_size 0) + endif() + if((NOT source_file_size EQUAL target_file_size) OR "${source_file}" IS_NEWER_THAN "${target_file}") message(STATUS "Copying \"${source_file}\" to \"${target_directory}\"...") + file(MAKE_DIRECTORY "${full_target_directory}") file(COPY "${source_file}" DESTINATION "${target_directory}" FILE_PERMISSIONS @LY_COPY_PERMISSIONS@ FOLLOW_SYMLINK_CHAIN) - file(TOUCH_NOCREATE ${target_directory}/${target_filename}) + file(TOUCH_NOCREATE ${target_file}) endif() endif() endfunction() diff --git a/cmake/Platform/Linux/CompilerSettings_linux.cmake b/cmake/Platform/Linux/CompilerSettings_linux.cmake new file mode 100644 index 0000000000..9bb629c53b --- /dev/null +++ b/cmake/Platform/Linux/CompilerSettings_linux.cmake @@ -0,0 +1,34 @@ +# +# Copyright (c) Contributors to the Open 3D Engine Project. +# For complete copyright and license terms please see the LICENSE at the root of this distribution. +# +# SPDX-License-Identifier: Apache-2.0 OR MIT +# +# + +if(NOT CMAKE_C_COMPILER AND NOT CMAKE_CXX_COMPILER AND NOT "$ENV{CC}" AND NOT "$ENV{CXX}") + set(path_search + /bin + /usr/bin + /usr/local/bin + /sbin + /usr/sbin + /usr/local/sbin + ) + list(TRANSFORM path_search APPEND "/clang-[0-9]*") + file(GLOB clang_versions ${path_search}) + if(clang_versions) + # Find and pick the highest installed version + list(SORT clang_versions COMPARE NATURAL) + list(GET clang_versions 0 clang_higher_version_path) + string(REGEX MATCH "clang-([0-9.]*)" clang_higher_version ${clang_higher_version_path}) + if(CMAKE_MATCH_1) + set(CMAKE_C_COMPILER clang-${CMAKE_MATCH_1}) + set(CMAKE_CXX_COMPILER clang++-${CMAKE_MATCH_1}) + else() + message(FATAL_ERROR "Clang not found, please install clang") + endif() + else() + message(FATAL_ERROR "Clang not found, please install clang") + endif() +endif() diff --git a/cmake/Platform/Linux/Install_linux.cmake b/cmake/Platform/Linux/Install_linux.cmake index dea26e5872..0f5494131a 100644 --- a/cmake/Platform/Linux/Install_linux.cmake +++ b/cmake/Platform/Linux/Install_linux.cmake @@ -6,25 +6,41 @@ # # -#! ly_install_code_function_override: Linux-specific copy function to handle RPATH fixes +#! ly_setup_runtime_dependencies_copy_function_override: Linux-specific copy function to handle RPATH fixes set(ly_copy_template [[ function(ly_copy source_file target_directory) - file(COPY "${source_file}" DESTINATION "${target_directory}" FILE_PERMISSIONS @LY_COPY_PERMISSIONS@ FOLLOW_SYMLINK_CHAIN) - get_filename_component(target_filename_ext "${source_file}" LAST_EXT) - if("${source_file}" MATCHES "qt/plugins" AND "${target_filename_ext}" STREQUAL ".so") - get_filename_component(target_filename "${source_file}" NAME) - file(RPATH_CHANGE FILE "${target_directory}/${target_filename}" OLD_RPATH "\$ORIGIN/../../lib" NEW_RPATH "\$ORIGIN/..") - elseif("${source_file}" MATCHES "lrelease") - get_filename_component(target_filename "${source_file}" NAME) - file(RPATH_CHANGE FILE "${target_directory}/${target_filename}" OLD_RPATH "\$ORIGIN/../lib" NEW_RPATH "\$ORIGIN") + cmake_path(GET source_file FILENAME target_filename) + cmake_path(APPEND full_target_directory "$ENV{DESTDIR}${CMAKE_INSTALL_PREFIX}" "${target_directory}") + cmake_path(APPEND target_file "${full_target_directory}" "${target_filename}") + if("${source_file}" IS_NEWER_THAN "${target_file}") + message(STATUS "Copying ${source_file} to ${full_target_directory}...") + file(MAKE_DIRECTORY "${full_target_directory}") + file(COPY "${source_file}" DESTINATION "${full_target_directory}" FILE_PERMISSIONS @LY_COPY_PERMISSIONS@ FOLLOW_SYMLINK_CHAIN) + file(TOUCH_NOCREATE "${target_file}") + + # Special case for install + cmake_PATH(GET source_file EXTENSION target_filename_ext) + if("${target_filename_ext}" STREQUAL ".so") + if("${source_file}" MATCHES "qt/plugins") + file(RPATH_CHANGE FILE "${target_file}" OLD_RPATH "\$ORIGIN/../../lib" NEW_RPATH "\$ORIGIN/..") + endif() + if(CMAKE_INSTALL_DO_STRIP) + execute_process(COMMAND @CMAKE_STRIP@ "${target_file}") + endif() + elseif("${source_file}" MATCHES "lrelease") + file(RPATH_CHANGE FILE "${target_file}" OLD_RPATH "\$ORIGIN/../lib" NEW_RPATH "\$ORIGIN") + endif() endif() endfunction()]]) -function(ly_install_code_function_override) +function(ly_setup_runtime_dependencies_copy_function_override) string(CONFIGURE "${ly_copy_template}" ly_copy_function_linux @ONLY) - install(CODE "${ly_copy_function_linux}" - COMPONENT ${CMAKE_INSTALL_DEFAULT_COMPONENT_NAME} - ) + foreach(conf IN LISTS CMAKE_CONFIGURATION_TYPES) + string(TOUPPER ${conf} UCONF) + ly_install(CODE "${ly_copy_function_linux}" + COMPONENT ${LY_INSTALL_PERMUTATION_COMPONENT}_${UCONF} + ) + endforeach() endfunction() include(cmake/Platform/Common/Install_common.cmake) diff --git a/cmake/Platform/Linux/PAL_linux.cmake b/cmake/Platform/Linux/PAL_linux.cmake index e74adb287e..9383b8fcf6 100644 --- a/cmake/Platform/Linux/PAL_linux.cmake +++ b/cmake/Platform/Linux/PAL_linux.cmake @@ -16,7 +16,7 @@ ly_set(PAL_TRAIT_BUILD_TESTS_SUPPORTED TRUE) ly_set(PAL_TRAIT_BUILD_UNITY_SUPPORTED TRUE) ly_set(PAL_TRAIT_BUILD_UNITY_EXCLUDE_EXTENSIONS) ly_set(PAL_TRAIT_BUILD_EXCLUDE_ALL_TEST_RUNS_FROM_IDE FALSE) -ly_set(PAL_TRAIT_BUILD_CPACK_SUPPORTED FALSE) +ly_set(PAL_TRAIT_BUILD_CPACK_SUPPORTED TRUE) ly_set(PAL_TRAIT_PROF_PIX_SUPPORTED FALSE) diff --git a/cmake/Platform/Linux/Packaging/postinst.in b/cmake/Platform/Linux/Packaging/postinst.in new file mode 100644 index 0000000000..c6c0ba228d --- /dev/null +++ b/cmake/Platform/Linux/Packaging/postinst.in @@ -0,0 +1,21 @@ +#!/usr/bin/env bash +# +# Copyright (c) Contributors to the Open 3D Engine Project. +# For complete copyright and license terms please see the LICENSE at the root of this distribution. +# +# SPDX-License-Identifier: Apache-2.0 OR MIT +# +# + +set -o errexit # exit on the first failure encountered + +{ + if [[ ! -f "/usr/lib/x86_64-linux-gnu/libffi.so.6" ]]; then + sudo ln -s /usr/lib/x86_64-linux-gnu/libffi.so.7 /usr/lib/x86_64-linux-gnu/libffi.so.6 + fi + + pushd @CPACK_PACKAGING_INSTALL_PREFIX@ + python/get_python.sh + chown -R $SUDO_USER . + popd +} &> /dev/null # hide output diff --git a/cmake/Platform/Linux/Packaging/postrm.in b/cmake/Platform/Linux/Packaging/postrm.in new file mode 100644 index 0000000000..acda38bf1e --- /dev/null +++ b/cmake/Platform/Linux/Packaging/postrm.in @@ -0,0 +1,15 @@ +#!/usr/bin/env bash +# +# Copyright (c) Contributors to the Open 3D Engine Project. +# For complete copyright and license terms please see the LICENSE at the root of this distribution. +# +# SPDX-License-Identifier: Apache-2.0 OR MIT +# +# + +set -o errexit # exit on the first failure encountered + +{ + pushd @CPACK_PACKAGING_INSTALL_PREFIX@ + popd +} &> /dev/null # hide output diff --git a/cmake/Platform/Linux/Packaging/prerm.in b/cmake/Platform/Linux/Packaging/prerm.in new file mode 100644 index 0000000000..5595d7010f --- /dev/null +++ b/cmake/Platform/Linux/Packaging/prerm.in @@ -0,0 +1,23 @@ +#!/usr/bin/env bash +# +# Copyright (c) Contributors to the Open 3D Engine Project. +# For complete copyright and license terms please see the LICENSE at the root of this distribution. +# +# SPDX-License-Identifier: Apache-2.0 OR MIT +# +# + +set -o errexit # exit on the first failure encountered + +{ + # We dont remove this symlink that we potentially created because the user could have + # installed themselves. + #if [[ -L "/usr/lib/x86_64-linux-gnu/libffi.so.6" ]]; then + # sudo rm /usr/lib/x86_64-linux-gnu/libffi.so.6 + #fi + + pushd @CPACK_PACKAGING_INSTALL_PREFIX@ + # delete python downloads + rm -rf python/downloaded_packages python/runtime + popd +} &> /dev/null # hide output diff --git a/cmake/Platform/Linux/PackagingPostBuild_linux.cmake b/cmake/Platform/Linux/PackagingPostBuild_linux.cmake new file mode 100644 index 0000000000..d92ee908fd --- /dev/null +++ b/cmake/Platform/Linux/PackagingPostBuild_linux.cmake @@ -0,0 +1,62 @@ +# +# Copyright (c) Contributors to the Open 3D Engine Project. +# For complete copyright and license terms please see the LICENSE at the root of this distribution. +# +# SPDX-License-Identifier: Apache-2.0 OR MIT +# +# + +file(REAL_PATH "${CPACK_SOURCE_DIR}/.." LY_ROOT_FOLDER) +include(${LY_ROOT_FOLDER}/cmake/Platform/Common/PackagingPostBuild_common.cmake) + +file(${CPACK_PACKAGE_CHECKSUM} ${CPACK_TOPLEVEL_DIRECTORY}/${CPACK_PACKAGE_FILE_NAME}.deb file_checksum) +file(WRITE ${CPACK_TOPLEVEL_DIRECTORY}/${CPACK_PACKAGE_FILE_NAME}.deb.sha256 "${file_checksum} ${CPACK_PACKAGE_FILE_NAME}.deb") + +if(CPACK_UPLOAD_URL) + + # use the internal default path if somehow not specified from cpack_configure_downloads + if(NOT CPACK_UPLOAD_DIRECTORY) + set(CPACK_UPLOAD_DIRECTORY ${CPACK_PACKAGE_DIRECTORY}/CPackUploads) + endif() + + # Copy the artifacts intended to be uploaded to a remote server into the folder specified + # through CPACK_UPLOAD_DIRECTORY. This mimics the same process cpack does natively for + # some other frameworks that have built-in online installer support. + message(STATUS "Copying packaging artifacts to upload directory...") + file(REMOVE_RECURSE ${CPACK_UPLOAD_DIRECTORY}) + file(GLOB _artifacts + "${CPACK_TOPLEVEL_DIRECTORY}/*.deb" + "${CPACK_TOPLEVEL_DIRECTORY}/*.sha256" + ) + file(COPY ${_artifacts} + DESTINATION ${CPACK_UPLOAD_DIRECTORY} + ) + message(STATUS "Artifacts copied to ${CPACK_UPLOAD_DIRECTORY}") + + # TODO: copy gpg file to CPACK_UPLOAD_DIRECTORY + + ly_upload_to_url( + ${CPACK_UPLOAD_URL} + ${CPACK_UPLOAD_DIRECTORY} + ".*(.deb|.gpg|.sha256)$" + ) + + # for auto tagged builds, we will also upload a second copy of just the boostrapper + # to a special "Latest" folder under the branch in place of the commit date/hash + if(CPACK_AUTO_GEN_TAG) + + set(latest_deb_package "${CPACK_UPLOAD_DIRECTORY}/${CPACK_PACKAGE_NAME}_latest.deb") + file(COPY_FILE + ${CPACK_UPLOAD_DIRECTORY}/${CPACK_PACKAGE_FILE_NAME}.deb + ${latest_deb_package} + ) + ly_upload_to_latest(${CPACK_UPLOAD_URL} ${latest_deb_package}) + + # TODO: upload gpg file to latest + + # Generate a checksum file for latest and upload it + set(latest_hash_file "${CPACK_UPLOAD_DIRECTORY}/${CPACK_PACKAGE_NAME}_latest.deb.sha256") + file(WRITE "${latest_hash_file}" "${file_checksum} ${CPACK_PACKAGE_NAME}_latest.deb") + ly_upload_to_latest(${CPACK_UPLOAD_URL} "${latest_hash_file}") + endif() +endif() diff --git a/cmake/Platform/Linux/PackagingPreBuild_linux.cmake b/cmake/Platform/Linux/PackagingPreBuild_linux.cmake new file mode 100644 index 0000000000..31dc393307 --- /dev/null +++ b/cmake/Platform/Linux/PackagingPreBuild_linux.cmake @@ -0,0 +1,16 @@ +# +# Copyright (c) Contributors to the Open 3D Engine Project. +# For complete copyright and license terms please see the LICENSE at the root of this distribution. +# +# SPDX-License-Identifier: Apache-2.0 OR MIT +# +# + +file(REAL_PATH "${CPACK_SOURCE_DIR}/.." LY_ROOT_FOLDER) +include(${LY_ROOT_FOLDER}/cmake/Platform/Common/PackagingPreBuild_common.cmake) + +if(NOT CPACK_UPLOAD_URL) # Skip signing if we are not uploading the package + return() +endif() + +# TODO: do signing diff --git a/cmake/Platform/Linux/Packaging_linux.cmake b/cmake/Platform/Linux/Packaging_linux.cmake new file mode 100644 index 0000000000..2e178429c3 --- /dev/null +++ b/cmake/Platform/Linux/Packaging_linux.cmake @@ -0,0 +1,56 @@ +# +# Copyright (c) Contributors to the Open 3D Engine Project. +# For complete copyright and license terms please see the LICENSE at the root of this distribution. +# +# SPDX-License-Identifier: Apache-2.0 OR MIT +# +# + +set(CPACK_GENERATOR DEB) + +set(CPACK_PACKAGING_INSTALL_PREFIX "/opt/${CPACK_PACKAGE_NAME}/${LY_VERSION_STRING}") + +set(_cmake_package_name "cmake-${CPACK_DESIRED_CMAKE_VERSION}-linux-x86_64") +set(CPACK_CMAKE_PACKAGE_FILE "${_cmake_package_name}.tar.gz") +set(CPACK_CMAKE_PACKAGE_HASH "3f827544f9c82e74ddf5016461fdfcfea4ede58a26f82612f473bf6bfad8bfc2") + +# get all the package dependencies, extracted from scripts\build\build_node\Platform\Linux\package-list.ubuntu-focal.txt +set(package_dependencies + libffi7 + clang-12 + ninja-build + # Build Libraries + libglu1-mesa-dev # For Qt (GL dependency) + libxcb-xinerama0 # For Qt plugins at runtime + libxcb-xinput0 # For Qt plugins at runtime + libfontconfig1-dev # For Qt plugins at runtime + libcurl4-openssl-dev # For HttpRequestor + # libsdl2-dev # for WWise/Audio + libxcb-xkb-dev # For xcb keyboard input + libxkbcommon-x11-dev # For xcb keyboard input + libxkbcommon-dev # For xcb keyboard input + libxcb-xfixes0-dev # For mouse input + libxcb-xinput-dev # For mouse input + zlib1g-dev + mesa-common-dev +) +list(JOIN package_dependencies "," CPACK_DEBIAN_PACKAGE_DEPENDS) + +# Post-installation and pre/post removal scripts +configure_file("${LY_ROOT_FOLDER}/cmake/Platform/${PAL_PLATFORM_NAME}/Packaging/postinst.in" + "${CMAKE_BINARY_DIR}/cmake/Platform/${PAL_PLATFORM_NAME}/Packaging/postinst" + @ONLY +) +configure_file("${LY_ROOT_FOLDER}/cmake/Platform/${PAL_PLATFORM_NAME}/Packaging/prerm.in" + "${CMAKE_BINARY_DIR}/cmake/Platform/${PAL_PLATFORM_NAME}/Packaging/prerm" + @ONLY +) +configure_file("${LY_ROOT_FOLDER}/cmake/Platform/${PAL_PLATFORM_NAME}/Packaging/postrm.in" + "${CMAKE_BINARY_DIR}/cmake/Platform/${PAL_PLATFORM_NAME}/Packaging/postrm" + @ONLY +) +set(CPACK_DEBIAN_PACKAGE_CONTROL_EXTRA + ${CMAKE_BINARY_DIR}/cmake/Platform/Linux/Packaging/postinst + ${CMAKE_BINARY_DIR}/cmake/Platform/Linux/Packaging/prerm + ${CMAKE_BINARY_DIR}/cmake/Platform/Linux/Packaging/postrm +) diff --git a/cmake/Platform/Linux/platform_linux_files.cmake b/cmake/Platform/Linux/platform_linux_files.cmake index fa5545cd26..d30959b8d2 100644 --- a/cmake/Platform/Linux/platform_linux_files.cmake +++ b/cmake/Platform/Linux/platform_linux_files.cmake @@ -10,11 +10,19 @@ set(FILES ../Common/Configurations_common.cmake ../Common/Clang/Configurations_clang.cmake ../Common/Install_common.cmake + ../Common/PackagingPostBuild_common.cmake + ../Common/PackagingPreBuild_common.cmake + CompilerSettings_linux.cmake Configurations_linux.cmake Install_linux.cmake LYTestWrappers_linux.cmake LYWrappers_linux.cmake + Packaging_linux.cmake + PackagingPostBuild_linux.cmake + PackagingPreBuild_linux.cmake PAL_linux.cmake PALDetection_linux.cmake RPathChange.cmake + runtime_dependencies_linux.cmake.in + RuntimeDependencies_linux.cmake ) diff --git a/cmake/Platform/Linux/runtime_dependencies_linux.cmake.in b/cmake/Platform/Linux/runtime_dependencies_linux.cmake.in index 394252e284..4ccf123e27 100644 --- a/cmake/Platform/Linux/runtime_dependencies_linux.cmake.in +++ b/cmake/Platform/Linux/runtime_dependencies_linux.cmake.in @@ -9,23 +9,33 @@ cmake_policy(SET CMP0012 NEW) # new policy for the if that evaluates a boolean out of "if(NOT ${same_location})" function(ly_copy source_file target_directory) - get_filename_component(target_filename "${source_file}" NAME) - get_filename_component(target_filename_ext "${source_file}" LAST_EXT) - cmake_path(COMPARE "${source_file}" EQUAL "${target_directory}/${target_filename}" same_location) + cmake_path(GET source_file FILENAME target_filename) + cmake_path(APPEND target_file "${target_directory}" "${target_filename}") + cmake_path(COMPARE "${source_file}" EQUAL "${target_file}" same_location) if(NOT ${same_location}) - file(LOCK ${target_directory}/${target_filename}.lock GUARD FUNCTION TIMEOUT 300) - if("${source_file}" IS_NEWER_THAN "${target_directory}/${target_filename}") + file(LOCK ${target_file}.lock GUARD FUNCTION TIMEOUT 300) + file(SIZE "${source_file}" source_file_size) + if(EXISTS "${target_file}") + file(SIZE "${target_file}" target_file_size) + else() + set(target_file_size 0) + endif() + if((NOT source_file_size EQUAL target_file_size) OR "${source_file}" IS_NEWER_THAN "${target_file}") + message(STATUS "Copying \"${source_file}\" to \"${target_directory}\"...") + file(MAKE_DIRECTORY "${full_target_directory}") file(COPY "${source_file}" DESTINATION "${target_directory}" FILE_PERMISSIONS @LY_COPY_PERMISSIONS@ FOLLOW_SYMLINK_CHAIN) - + file(TOUCH_NOCREATE "${target_file}") + # Special case, shared libraries that are copied from qt/plugins have their RPATH set to \$ORIGIN/../../lib # which is the correct relative path based on the source location. But when we copy it to their subfolder, # the rpath needs to be adjusted to the parent ($ORIGIN/..) if("${source_file}" MATCHES "qt/plugins" AND "${target_filename_ext}" STREQUAL ".so") - file(RPATH_CHANGE FILE "${target_directory}/${target_filename}" OLD_RPATH "\$ORIGIN/../../lib" NEW_RPATH "\$ORIGIN/..") + file(RPATH_CHANGE FILE "${target_file}" OLD_RPATH "\$ORIGIN/../../lib" NEW_RPATH "\$ORIGIN/..") endif() - endif() endif() endfunction() @LY_COPY_COMMANDS@ + +file(TOUCH @STAMP_OUTPUT_FILE@) diff --git a/cmake/Platform/Mac/InstallUtils_mac.cmake.in b/cmake/Platform/Mac/InstallUtils_mac.cmake.in index d73c4db459..89ce4a59f2 100644 --- a/cmake/Platform/Mac/InstallUtils_mac.cmake.in +++ b/cmake/Platform/Mac/InstallUtils_mac.cmake.in @@ -130,27 +130,36 @@ endfunction() function(ly_copy source_file target_directory) - if("${source_file}" MATCHES "\\.[Ff]ramework[^\\.]") + if("${source_file}" MATCHES "\\.[Ff]ramework") # fixup origin to copy the whole Framework folder string(REGEX REPLACE "(.*\\.[Ff]ramework).*" "\\1" source_file "${source_file}") endif() - get_filename_component(target_filename "${source_file}" NAME) - file(COPY "${source_file}" DESTINATION "${target_directory}" FILE_PERMISSIONS @LY_COPY_PERMISSIONS@ FOLLOW_SYMLINK_CHAIN) - # Our Qt and Python frameworks aren't in the correct bundle format to be codesigned. - if("${target_filename}" MATCHES "(Qt[^.]+)\\.[Ff]ramework") - fixup_qt_framework(${CMAKE_MATCH_1} "${target_directory}/${target_filename}") - # For some Qt frameworks(QtCore), signing the bundle doesn't work because of bundle - # format issues(despite the fixes above). But once we've patched the framework above, there's - # only one executable that we need to sign so we can do it directly. - set(target_filename "${target_filename}/Versions/5/${CMAKE_MATCH_1}") - elseif("${target_filename}" MATCHES "Python.framework") - fixup_python_framework("${target_directory}/${target_filename}") - codesign_python_framework_binaries("${target_directory}/${target_filename}") + cmake_path(GET source_file FILENAME target_filename) + cmake_path(APPEND full_target_directory "$ENV{DESTDIR}${CMAKE_INSTALL_PREFIX}" "${target_directory}") + cmake_path(APPEND target_file "${full_target_directory}" "${target_filename}") + + if("${source_file}" IS_NEWER_THAN "${target_file}") + message(STATUS "Copying ${source_file} to ${full_target_directory}...") + file(MAKE_DIRECTORY "${full_target_directory}") + file(COPY "${source_file}" DESTINATION "${full_target_directory}" FILE_PERMISSIONS @LY_COPY_PERMISSIONS@ FOLLOW_SYMLINK_CHAIN) + file(TOUCH_NOCREATE "${target_file}") + + # Our Qt and Python frameworks aren't in the correct bundle format to be codesigned. + if("${target_filename}" MATCHES "(Qt[^.]+)\\.[Ff]ramework") + fixup_qt_framework(${CMAKE_MATCH_1} "${target_file}") + # For some Qt frameworks(QtCore), signing the bundle doesn't work because of bundle + # format issues(despite the fixes above). But once we've patched the framework above, there's + # only one executable that we need to sign so we can do it directly. + set(target_filename "${target_filename}/Versions/5/${CMAKE_MATCH_1}") + elseif("${target_filename}" MATCHES "Python.framework") + fixup_python_framework("${target_file}") + codesign_python_framework_binaries("${target_file}") + endif() + codesign_file("${target_file}" "none") endif() - codesign_file("${target_directory}/${target_filename}" "none") endfunction() diff --git a/cmake/Platform/Mac/Install_mac.cmake b/cmake/Platform/Mac/Install_mac.cmake index bdc2300131..d5ab5d0fed 100644 --- a/cmake/Platform/Mac/Install_mac.cmake +++ b/cmake/Platform/Mac/Install_mac.cmake @@ -39,10 +39,10 @@ file(GENERATE # This needs to be done here because it needs to update the install prefix # before cmake does anything else in the install process. configure_file(${LY_ROOT_FOLDER}/cmake/Platform/Mac/PreInstallSteps_mac.cmake.in ${CMAKE_BINARY_DIR}/runtime_install/PreInstallSteps_mac.cmake @ONLY) -install(SCRIPT ${CMAKE_BINARY_DIR}/runtime_install/PreInstallSteps_mac.cmake COMPONENT ${CMAKE_INSTALL_DEFAULT_COMPONENT_NAME}) +ly_install(SCRIPT ${CMAKE_BINARY_DIR}/runtime_install/PreInstallSteps_mac.cmake COMPONENT ${CMAKE_INSTALL_DEFAULT_COMPONENT_NAME}) -#! ly_install_target_override: Mac specific target installation -function(ly_install_target_override) +#! ly_setup_target_install_targets_override: Mac specific target installation +function(ly_setup_target_install_targets_override) set(options) set(oneValueArgs TARGET ARCHIVE_DIR LIBRARY_DIR RUNTIME_DIR LIBRARY_SUBDIR RUNTIME_SUBDIR) @@ -58,24 +58,31 @@ function(ly_install_target_override) set_property(TARGET ${ly_platform_install_target_TARGET} PROPERTY RESOURCE "") endif() - install( - TARGETS ${ly_platform_install_target_TARGET} - ARCHIVE - DESTINATION ${ly_platform_install_target_ARCHIVE_DIR} - COMPONENT ${CMAKE_INSTALL_DEFAULT_COMPONENT_NAME} - LIBRARY - DESTINATION ${ly_platform_install_target_LIBRARY_DIR}/${ly_platform_install_target_LIBRARY_SUBDIR} - COMPONENT ${CMAKE_INSTALL_DEFAULT_COMPONENT_NAME} - RUNTIME - DESTINATION ${ly_platform_install_target_RUNTIME_DIR}/${ly_platform_install_target_RUNTIME_SUBDIR} - COMPONENT ${CMAKE_INSTALL_DEFAULT_COMPONENT_NAME} - BUNDLE - DESTINATION ${ly_platform_install_target_RUNTIME_DIR}/${ly_platform_install_target_RUNTIME_SUBDIR} - COMPONENT ${CMAKE_INSTALL_DEFAULT_COMPONENT_NAME} - RESOURCE - DESTINATION ${ly_platform_install_target_RUNTIME_DIR}/${ly_platform_install_target_RUNTIME_SUBDIR} - COMPONENT ${CMAKE_INSTALL_DEFAULT_COMPONENT_NAME} - ) + foreach(conf IN LISTS CMAKE_CONFIGURATION_TYPES) + string(TOUPPER ${conf} UCONF) + ly_install(TARGETS ${TARGET_NAME} + ARCHIVE + DESTINATION ${ly_platform_install_target_ARCHIVE_DIR} + COMPONENT ${LY_INSTALL_PERMUTATION_COMPONENT}_${UCONF} + CONFIGURATIONS ${conf} + LIBRARY + DESTINATION ${ly_platform_install_target_LIBRARY_DIR}/${ly_platform_install_target_LIBRARY_SUBDIR} + COMPONENT ${LY_INSTALL_PERMUTATION_COMPONENT}_${UCONF} + CONFIGURATIONS ${conf} + RUNTIME + DESTINATION ${ly_platform_install_target_RUNTIME_DIR}/${ly_platform_install_target_RUNTIME_SUBDIR} + COMPONENT ${LY_INSTALL_PERMUTATION_COMPONENT}_${UCONF} + CONFIGURATIONS ${conf} + BUNDLE + DESTINATION ${ly_platform_install_target_RUNTIME_DIR}/${ly_platform_install_target_RUNTIME_SUBDIR} + COMPONENT ${LY_INSTALL_PERMUTATION_COMPONENT}_${UCONF} + CONFIGURATIONS ${conf} + RESOURCE + DESTINATION ${ly_platform_install_target_RUNTIME_DIR}/${ly_platform_install_target_RUNTIME_SUBDIR} + COMPONENT ${LY_INSTALL_PERMUTATION_COMPONENT}_${UCONF} + CONFIGURATIONS ${conf} + ) + endforeach() set(install_relative_binaries_path "${ly_platform_install_target_RUNTIME_DIR}/${ly_platform_install_target_RUNTIME_SUBDIR}") @@ -102,11 +109,16 @@ function(ly_install_target_override) endif() endfunction() -#! ly_install_code_function_override: Mac specific copy function to handle frameworks -function(ly_install_code_function_override) +#! ly_setup_runtime_dependencies_copy_function_override: Mac specific copy function to handle frameworks +function(ly_setup_runtime_dependencies_copy_function_override) configure_file(${LY_ROOT_FOLDER}/cmake/Platform/Mac/InstallUtils_mac.cmake.in ${CMAKE_BINARY_DIR}/runtime_install/InstallUtils_mac.cmake @ONLY) - ly_install_run_script(${CMAKE_BINARY_DIR}/runtime_install/InstallUtils_mac.cmake) + foreach(conf IN LISTS CMAKE_CONFIGURATION_TYPES) + string(TOUPPER ${conf} UCONF) + ly_install(SCRIPT "${CMAKE_BINARY_DIR}/runtime_install/InstallUtils_mac.cmake" + COMPONENT ${LY_INSTALL_PERMUTATION_COMPONENT}_${UCONF} + ) + endforeach() endfunction() @@ -135,4 +147,3 @@ function(ly_post_install_steps) ") endfunction() - diff --git a/cmake/Platform/Mac/PackagingPostBuild_mac.cmake b/cmake/Platform/Mac/PackagingPostBuild_mac.cmake new file mode 100644 index 0000000000..5fa3787c21 --- /dev/null +++ b/cmake/Platform/Mac/PackagingPostBuild_mac.cmake @@ -0,0 +1,10 @@ +# +# Copyright (c) Contributors to the Open 3D Engine Project. +# For complete copyright and license terms please see the LICENSE at the root of this distribution. +# +# SPDX-License-Identifier: Apache-2.0 OR MIT +# +# + +file(REAL_PATH "${CPACK_SOURCE_DIR}/.." LY_ROOT_FOLDER) +include(${LY_ROOT_FOLDER}/cmake/Platform/Common/PackagingPostBuild_common.cmake) diff --git a/cmake/Platform/Mac/PackagingPreBuild_mac.cmake b/cmake/Platform/Mac/PackagingPreBuild_mac.cmake new file mode 100644 index 0000000000..1d30e21767 --- /dev/null +++ b/cmake/Platform/Mac/PackagingPreBuild_mac.cmake @@ -0,0 +1,10 @@ +# +# Copyright (c) Contributors to the Open 3D Engine Project. +# For complete copyright and license terms please see the LICENSE at the root of this distribution. +# +# SPDX-License-Identifier: Apache-2.0 OR MIT +# +# + +file(REAL_PATH "${CPACK_SOURCE_DIR}/.." LY_ROOT_FOLDER) +include(${LY_ROOT_FOLDER}/cmake/Platform/Common/PackagingPreBuild_common.cmake) diff --git a/cmake/Platform/Mac/runtime_dependencies_mac.cmake.in b/cmake/Platform/Mac/runtime_dependencies_mac.cmake.in index 11551f608f..892a90640f 100644 --- a/cmake/Platform/Mac/runtime_dependencies_mac.cmake.in +++ b/cmake/Platform/Mac/runtime_dependencies_mac.cmake.in @@ -34,7 +34,7 @@ endif() function(ly_copy source_file target_directory) - get_filename_component(target_filename "${source_file}" NAME) + cmake_path(GET source_file FILENAME target_filename) # If target_directory is a bundle if("${target_directory}" MATCHES "\\.app/Contents/MacOS") @@ -113,20 +113,37 @@ function(ly_copy source_file target_directory) endif() - cmake_path(COMPARE "${source_file}" EQUAL "${target_directory}/${target_filename}" same_location) + cmake_path(APPEND target_file "${target_directory}" "${target_filename}") + cmake_path(COMPARE "${source_file}" EQUAL "${target_file}" same_location) if(NOT ${same_location}) if(NOT EXISTS "${target_directory}") file(MAKE_DIRECTORY "${target_directory}") endif() - if(NOT EXISTS "${target_directory}/${target_filename}" OR "${source_file}" IS_NEWER_THAN "${target_directory}/${target_filename}") - message(STATUS "Copying \"${source_file}\" to \"${target_directory}\"...") - if(NOT target_is_bundle) - # if it is a bundle, there is no contention about the files in the destination, each bundle target will copy everything - # we dont want these files to invalidate the bundle and cause a new signature - file(LOCK ${target_directory}/${target_filename}.lock GUARD FUNCTION TIMEOUT 300) + + set(is_framework FALSE) + if("${source_file}" MATCHES "\\.[Ff]ramework") + set(is_framework TRUE) + endif() + if(NOT is_framework) + # if it is a bundle, there is no contention about the files in the destination, each bundle target will copy everything + # we dont want these files to invalidate the bundle and cause a new signature + file(LOCK ${target_file}.lock GUARD FUNCTION TIMEOUT 300) + file(SIZE "${source_file}" source_file_size) + if(EXISTS "${target_file}") + file(SIZE "${target_file}" target_file_size) + else() + set(target_file_size 0) endif() + else() + set(source_file_size 0) + set(target_file_size 0) + endif() + + if((NOT source_file_size EQUAL target_file_size) OR "${source_file}" IS_NEWER_THAN "${target_file}") + message(STATUS "Copying \"${source_file}\" to \"${target_directory}\"...") + file(MAKE_DIRECTORY "${target_directory}") file(COPY "${source_file}" DESTINATION "${target_directory}" FILE_PERMISSIONS @LY_COPY_PERMISSIONS@ FOLLOW_SYMLINK_CHAIN) - file(TOUCH_NOCREATE ${target_directory}/${target_filename}) + file(TOUCH_NOCREATE "${target_file}") set(anything_new TRUE PARENT_SCOPE) endif() endif() diff --git a/cmake/Platform/Windows/PackagingPostBuild.cmake b/cmake/Platform/Windows/PackagingPostBuild.cmake deleted file mode 100644 index 377a9fb221..0000000000 --- a/cmake/Platform/Windows/PackagingPostBuild.cmake +++ /dev/null @@ -1,237 +0,0 @@ -# -# Copyright (c) Contributors to the Open 3D Engine Project. -# For complete copyright and license terms please see the LICENSE at the root of this distribution. -# -# SPDX-License-Identifier: Apache-2.0 OR MIT -# -# - -# convert the path to a windows style path using string replace because TO_NATIVE_PATH -# only works on real paths -string(REPLACE "/" "\\" _fixed_package_install_dir ${CPACK_PACKAGE_INSTALL_DIRECTORY}) - -# directory where the auto generated files live e.g /_CPack_Package/win64/WIX -set(_cpack_wix_out_dir ${CPACK_TOPLEVEL_DIRECTORY}) -set(_bootstrap_out_dir "${CPACK_TOPLEVEL_DIRECTORY}/bootstrap") - -set(_bootstrap_filename "${CPACK_PACKAGE_FILE_NAME}_installer.exe") -set(_bootstrap_output_file ${_cpack_wix_out_dir}/${_bootstrap_filename}) - -set(_ext_flags - -ext WixBalExtension -) - -set(_addtional_defines - -dCPACK_BOOTSTRAP_THEME_FILE=${CPACK_BINARY_DIR}/BootstrapperTheme - -dCPACK_BOOTSTRAP_UPGRADE_GUID=${CPACK_WIX_BOOTSTRAP_UPGRADE_GUID} - -dCPACK_DOWNLOAD_SITE=${CPACK_DOWNLOAD_SITE} - -dCPACK_LOCAL_INSTALLER_DIR=${_cpack_wix_out_dir} - -dCPACK_PACKAGE_FILE_NAME=${CPACK_PACKAGE_FILE_NAME} - -dCPACK_PACKAGE_INSTALL_DIRECTORY=${_fixed_package_install_dir} - -dCPACK_WIX_PRODUCT_LOGO=${CPACK_WIX_PRODUCT_LOGO} - -dCPACK_RESOURCE_PATH=${CPACK_SOURCE_DIR}/Platform/Windows/Packaging -) - -file(REAL_PATH "${CPACK_SOURCE_DIR}/.." _root_path) -file(TO_NATIVE_PATH "${_root_path}/scripts/signer/Platform/Windows/signer.ps1" _sign_script) - -if(CPACK_LICENSE_URL) - list(APPEND _addtional_defines -dCPACK_LICENSE_URL=${CPACK_LICENSE_URL}) -endif() - -set(_candle_command - ${CPACK_WIX_CANDLE_EXECUTABLE} - -nologo - -arch x64 - "-I${_cpack_wix_out_dir}" # to include cpack_variables.wxi - ${_addtional_defines} - ${_ext_flags} - "${CPACK_SOURCE_DIR}/Platform/Windows/Packaging/Bootstrapper.wxs" - -o "${_bootstrap_out_dir}/" -) - -set(_light_command - ${CPACK_WIX_LIGHT_EXECUTABLE} - -nologo - ${_ext_flags} - ${_bootstrap_out_dir}/*.wixobj - -o "${_bootstrap_output_file}" -) - -set(_signing_command - psexec.exe - -accepteula - -nobanner - -s - powershell.exe - -NoLogo - -ExecutionPolicy Bypass - -File ${_sign_script} -) - -message(STATUS "Signing package files in ${_cpack_wix_out_dir}") -execute_process( - COMMAND ${_signing_command} -packagePath ${_cpack_wix_out_dir} - RESULT_VARIABLE _signing_result - ERROR_VARIABLE _signing_errors - OUTPUT_VARIABLE _signing_output - ECHO_OUTPUT_VARIABLE -) - -if(NOT ${_signing_result} EQUAL 0) - message(FATAL_ERROR "An error occurred during signing package files. ${_signing_errors}") -endif() - -message(STATUS "Creating Bootstrap Installer...") -execute_process( - COMMAND ${_candle_command} - RESULT_VARIABLE _candle_result - ERROR_VARIABLE _candle_errors -) -if(NOT ${_candle_result} EQUAL 0) - message(FATAL_ERROR "An error occurred invoking candle.exe. ${_candle_errors}") -endif() - -execute_process( - COMMAND ${_light_command} - RESULT_VARIABLE _light_result - ERROR_VARIABLE _light_errors -) -if(NOT ${_light_result} EQUAL 0) - message(FATAL_ERROR "An error occurred invoking light.exe. ${_light_errors}") -endif() - -file(COPY ${_bootstrap_output_file} - DESTINATION ${CPACK_PACKAGE_DIRECTORY} -) - -message(STATUS "Bootstrap installer generated to ${CPACK_PACKAGE_DIRECTORY}/${_bootstrap_filename}") - -message(STATUS "Signing bootstrap installer in ${CPACK_PACKAGE_DIRECTORY}") -execute_process( - COMMAND ${_signing_command} -bootstrapPath ${CPACK_PACKAGE_DIRECTORY}/${_bootstrap_filename} - RESULT_VARIABLE _signing_result - ERROR_VARIABLE _signing_errors - OUTPUT_VARIABLE _signing_output - ECHO_OUTPUT_VARIABLE -) - -if(NOT ${_signing_result} EQUAL 0) - message(FATAL_ERROR "An error occurred during signing bootstrap installer. ${_signing_errors}") -endif() - -# use the internal default path if somehow not specified from cpack_configure_downloads -if(NOT CPACK_UPLOAD_DIRECTORY) - set(CPACK_UPLOAD_DIRECTORY ${CPACK_PACKAGE_DIRECTORY}/CPackUploads) -endif() - -# copy the artifacts intended to be uploaded to a remote server into the folder specified -# through cpack_configure_downloads. this mimics the same process cpack does natively for -# some other frameworks that have built-in online installer support. -message(STATUS "Copying installer artifacts to upload directory...") -file(REMOVE_RECURSE ${CPACK_UPLOAD_DIRECTORY}) -file(GLOB _artifacts "${_cpack_wix_out_dir}/*.msi" "${_cpack_wix_out_dir}/*.cab") -file(COPY ${_artifacts} - DESTINATION ${CPACK_UPLOAD_DIRECTORY} -) -message(STATUS "Artifacts copied to ${CPACK_UPLOAD_DIRECTORY}") - -if(NOT CPACK_UPLOAD_URL) - return() -endif() - -file(TO_NATIVE_PATH "${_cpack_wix_out_dir}" _cpack_wix_out_dir) -file(TO_NATIVE_PATH "${_root_path}/python/python.cmd" _python_cmd) -file(TO_NATIVE_PATH "${_root_path}/scripts/build/tools/upload_to_s3.py" _upload_script) - -function(upload_to_s3 in_url in_local_path in_file_regex) - - # strip the scheme and extract the bucket/key prefix from the URL - string(REPLACE "s3://" "" _stripped_url ${in_url}) - string(REPLACE "/" ";" _tokens ${_stripped_url}) - - list(POP_FRONT _tokens _bucket) - string(JOIN "/" _prefix ${_tokens}) - - set(_extra_args [[{"ACL":"bucket-owner-full-control"}]]) - - set(_upload_command - ${_python_cmd} -s - -u ${_upload_script} - --base_dir ${in_local_path} - --file_regex="${in_file_regex}" - --bucket ${_bucket} - --key_prefix ${_prefix} - --extra_args ${_extra_args} - ) - - if(CPACK_AWS_PROFILE) - list(APPEND _upload_command --profile ${CPACK_AWS_PROFILE}) - endif() - - execute_process( - COMMAND ${_upload_command} - RESULT_VARIABLE _upload_result - OUTPUT_VARIABLE _upload_output - OUTPUT_STRIP_TRAILING_WHITESPACE - ) - - if (NOT ${_upload_result} EQUAL 0) - message(FATAL_ERROR "An error occurred uploading to s3.\nOutput:\n${_upload_output}") - endif() -endfunction() - -message(STATUS "Uploading artifacts to ${CPACK_UPLOAD_URL}") -upload_to_s3( - ${CPACK_UPLOAD_URL} - ${_cpack_wix_out_dir} - ".*(cab|exe|msi)$" -) -message(STATUS "Artifact uploading complete!") - -# for auto tagged builds, we will also upload a second copy of just the boostrapper -# to a special "Latest" folder under the branch in place of the commit date/hash -if(CPACK_AUTO_GEN_TAG) - message(STATUS "Updating latest tagged build") - - # make sure we can extra the commit info from the URL first - string(REGEX MATCH "([0-9][0-9][0-9][0-9]-[0-9][0-9]-[0-9][0-9]-[0-9a-zA-Z]+)" - _commit_info ${CPACK_UPLOAD_URL} - ) - if(NOT _commit_info) - message(FATAL_ERROR "Failed to extract the build tag") - endif() - - set(_temp_dir ${_cpack_wix_out_dir}/temp) - if(NOT EXISTS ${_temp_dir}) - file(MAKE_DIRECTORY ${_temp_dir}) - endif() - - # strip the version number form the exe name in the one uploaded to latest - string(TOLOWER "${CPACK_PACKAGE_NAME}_installer.exe" _non_versioned_exe) - set(_temp_exe_copy ${_temp_dir}/${_non_versioned_exe}) - - file(COPY ${_bootstrap_output_file} DESTINATION ${_temp_dir}) - file(RENAME "${_temp_dir}/${_bootstrap_filename}" ${_temp_exe_copy}) - - # include the commit info in a text file that will live next to the exe - set(_temp_info_file ${_temp_dir}/build_tag.txt) - file(WRITE ${_temp_info_file} ${_commit_info}) - - # update the URL and upload - string(REPLACE - ${_commit_info} "Latest" - _latest_upload_url ${CPACK_UPLOAD_URL} - ) - - upload_to_s3( - ${_latest_upload_url} - ${_temp_dir} - ".*(${_non_versioned_exe}|build_tag.txt)$" - ) - - # cleanup the temp files - file(REMOVE_RECURSE ${_temp_dir}) - - message(STATUS "Latest build update complete!") -endif() diff --git a/cmake/Platform/Windows/PackagingPostBuild_windows.cmake b/cmake/Platform/Windows/PackagingPostBuild_windows.cmake new file mode 100644 index 0000000000..0993135c23 --- /dev/null +++ b/cmake/Platform/Windows/PackagingPostBuild_windows.cmake @@ -0,0 +1,166 @@ +# +# Copyright (c) Contributors to the Open 3D Engine Project. +# For complete copyright and license terms please see the LICENSE at the root of this distribution. +# +# SPDX-License-Identifier: Apache-2.0 OR MIT +# +# + +file(REAL_PATH "${CPACK_SOURCE_DIR}/.." LY_ROOT_FOLDER) +include(${LY_ROOT_FOLDER}/cmake/Platform/Common/PackagingPostBuild_common.cmake) + +# convert the path to a windows style path using string replace because TO_NATIVE_PATH +# only works on real paths +string(REPLACE "/" "\\" _fixed_package_install_dir ${CPACK_PACKAGE_INSTALL_DIRECTORY}) + +# directory where the auto generated files live e.g /_CPack_Package/win64/WIX +set(_cpack_wix_out_dir ${CPACK_TOPLEVEL_DIRECTORY}) +set(_bootstrap_out_dir "${CPACK_TOPLEVEL_DIRECTORY}/bootstrap") + +set(_bootstrap_filename "${CPACK_PACKAGE_FILE_NAME}_installer.exe") +set(_bootstrap_output_file ${_cpack_wix_out_dir}/${_bootstrap_filename}) + +set(_ext_flags + -ext WixBalExtension +) + +set(_addtional_defines + -dCPACK_BOOTSTRAP_THEME_FILE=${CPACK_BINARY_DIR}/BootstrapperTheme + -dCPACK_BOOTSTRAP_UPGRADE_GUID=${CPACK_WIX_BOOTSTRAP_UPGRADE_GUID} + -dCPACK_DOWNLOAD_SITE=${CPACK_DOWNLOAD_SITE} + -dCPACK_LOCAL_INSTALLER_DIR=${_cpack_wix_out_dir} + -dCPACK_PACKAGE_FILE_NAME=${CPACK_PACKAGE_FILE_NAME} + -dCPACK_PACKAGE_INSTALL_DIRECTORY=${_fixed_package_install_dir} + -dCPACK_WIX_PRODUCT_LOGO=${CPACK_WIX_PRODUCT_LOGO} + -dCPACK_RESOURCE_PATH=${CPACK_SOURCE_DIR}/Platform/Windows/Packaging +) + +if(CPACK_LICENSE_URL) + list(APPEND _addtional_defines -dCPACK_LICENSE_URL=${CPACK_LICENSE_URL}) +endif() + +set(_candle_command + ${CPACK_WIX_CANDLE_EXECUTABLE} + -nologo + -arch x64 + "-I${_cpack_wix_out_dir}" # to include cpack_variables.wxi + ${_addtional_defines} + ${_ext_flags} + "${CPACK_SOURCE_DIR}/Platform/Windows/Packaging/Bootstrapper.wxs" + -o "${_bootstrap_out_dir}/" +) + +set(_light_command + ${CPACK_WIX_LIGHT_EXECUTABLE} + -nologo + ${_ext_flags} + ${_bootstrap_out_dir}/*.wixobj + -o "${_bootstrap_output_file}" +) + +if(CPACK_UPLOAD_URL) # Skip signing if we are not uploading the package + file(TO_NATIVE_PATH "${LY_ROOT_FOLDER}/scripts/signer/Platform/Windows/signer.ps1" _sign_script) + + unset(_signing_command) + find_program(_psiexec_path psexec.exe) + if(_psiexec_path) + list(APPEND _signing_command + ${_psiexec_path} + -accepteula + -nobanner + -s + ) + endif() + + find_program(_powershell_path powershell.exe REQUIRED) + list(APPEND _signing_command + ${_powershell_path} + -NoLogo + -ExecutionPolicy Bypass + -File ${_sign_script} + ) + + message(STATUS "Signing package files in ${_cpack_wix_out_dir}") + execute_process( + COMMAND ${_signing_command} -packagePath ${_cpack_wix_out_dir} + RESULT_VARIABLE _signing_result + ERROR_VARIABLE _signing_errors + OUTPUT_VARIABLE _signing_output + ECHO_OUTPUT_VARIABLE + ) + + if(NOT ${_signing_result} EQUAL 0) + message(FATAL_ERROR "An error occurred during signing package files. ${_signing_errors}") + endif() +endif() + +message(STATUS "Creating Bootstrap Installer...") +execute_process( + COMMAND ${_candle_command} + RESULT_VARIABLE _candle_result + ERROR_VARIABLE _candle_errors +) +if(NOT ${_candle_result} EQUAL 0) + message(FATAL_ERROR "An error occurred invoking candle.exe. ${_candle_errors}") +endif() + +execute_process( + COMMAND ${_light_command} + RESULT_VARIABLE _light_result + ERROR_VARIABLE _light_errors +) +if(NOT ${_light_result} EQUAL 0) + message(FATAL_ERROR "An error occurred invoking light.exe. ${_light_errors}") +endif() + +message(STATUS "Bootstrap installer generated to ${_bootstrap_output_file}") + +if(CPACK_UPLOAD_URL) # Skip signing if we are not uploading the package + message(STATUS "Signing bootstrap installer in ${_bootstrap_output_file}") + execute_process( + COMMAND ${_signing_command} -bootstrapPath ${_bootstrap_output_file} + RESULT_VARIABLE _signing_result + ERROR_VARIABLE _signing_errors + OUTPUT_VARIABLE _signing_output + ECHO_OUTPUT_VARIABLE + ) + + if(NOT ${_signing_result} EQUAL 0) + message(FATAL_ERROR "An error occurred during signing bootstrap installer. ${_signing_errors}") + endif() +endif() + +# use the internal default path if somehow not specified from cpack_configure_downloads +if(NOT CPACK_UPLOAD_DIRECTORY) + set(CPACK_UPLOAD_DIRECTORY ${CPACK_PACKAGE_DIRECTORY}/CPackUploads) +endif() + +# Copy the artifacts intended to be uploaded to a remote server into the folder specified +# through CPACK_UPLOAD_DIRECTORY. This mimics the same process cpack does natively for +# some other frameworks that have built-in online installer support. +message(STATUS "Copying packaging artifacts to upload directory...") +file(REMOVE_RECURSE ${CPACK_UPLOAD_DIRECTORY}) +file(GLOB _artifacts + "${_cpack_wix_out_dir}/*.msi" + "${_cpack_wix_out_dir}/*.cab" + "${_cpack_wix_out_dir}/*.exe" +) +file(COPY ${_artifacts} + DESTINATION ${CPACK_UPLOAD_DIRECTORY} +) +message(STATUS "Artifacts copied to ${CPACK_UPLOAD_DIRECTORY}") + +if(CPACK_UPLOAD_URL) + file(TO_NATIVE_PATH "${_cpack_wix_out_dir}" _cpack_wix_out_dir) + ly_upload_to_url( + ${CPACK_UPLOAD_URL} + ${_cpack_wix_out_dir} + ".*(cab|exe|msi)$" + ) + + # for auto tagged builds, we will also upload a second copy of just the boostrapper + # to a special "Latest" folder under the branch in place of the commit date/hash + if(CPACK_AUTO_GEN_TAG) + ly_upload_to_latest(${CPACK_UPLOAD_URL} ${_bootstrap_output_file}) + endif() +endif() diff --git a/cmake/Platform/Windows/PackagingPreBuild.cmake b/cmake/Platform/Windows/PackagingPreBuild.cmake deleted file mode 100644 index d3924c7a02..0000000000 --- a/cmake/Platform/Windows/PackagingPreBuild.cmake +++ /dev/null @@ -1,37 +0,0 @@ -# -# Copyright (c) Contributors to the Open 3D Engine Project. -# For complete copyright and license terms please see the LICENSE at the root of this distribution. -# -# SPDX-License-Identifier: Apache-2.0 OR MIT -# -# - -file(REAL_PATH "${CPACK_SOURCE_DIR}/.." _root_path) -set(_cpack_wix_out_dir ${CPACK_TOPLEVEL_DIRECTORY}) -file(TO_NATIVE_PATH "${_root_path}/scripts/signer/Platform/Windows/signer.ps1" _sign_script) - -set(_signing_command - psexec.exe - -accepteula - -nobanner - -s - powershell.exe - -NoLogo - -ExecutionPolicy Bypass - -File ${_sign_script} -) - -message(STATUS "Signing executable files in ${_cpack_wix_out_dir}") -execute_process( - COMMAND ${_signing_command} -exePath ${_cpack_wix_out_dir} - RESULT_VARIABLE _signing_result - ERROR_VARIABLE _signing_errors - OUTPUT_VARIABLE _signing_output - ECHO_OUTPUT_VARIABLE -) - -if(NOT ${_signing_result} EQUAL 0) - message(FATAL_ERROR "An error occurred during signing executable files. ${_signing_errors}") -endif() - -message(STATUS "Signing exes complete!") diff --git a/cmake/Platform/Windows/PackagingPreBuild_windows.cmake b/cmake/Platform/Windows/PackagingPreBuild_windows.cmake new file mode 100644 index 0000000000..29995518da --- /dev/null +++ b/cmake/Platform/Windows/PackagingPreBuild_windows.cmake @@ -0,0 +1,60 @@ +# +# Copyright (c) Contributors to the Open 3D Engine Project. +# For complete copyright and license terms please see the LICENSE at the root of this distribution. +# +# SPDX-License-Identifier: Apache-2.0 OR MIT +# +# + +file(REAL_PATH "${CPACK_SOURCE_DIR}/.." LY_ROOT_FOLDER) +include(${LY_ROOT_FOLDER}/cmake/Platform/Common/PackagingPreBuild_common.cmake) + +if(NOT CPACK_UPLOAD_URL) # Skip signing if we are not uploading the package + return() +endif() + +file(REAL_PATH "${CPACK_SOURCE_DIR}/.." _root_path) +set(_cpack_wix_out_dir ${CPACK_TOPLEVEL_DIRECTORY}) +file(TO_NATIVE_PATH "${_root_path}/scripts/signer/Platform/Windows/signer.ps1" _sign_script) + +unset(_signing_command) +find_program(_psiexec_path psexec.exe) +if(_psiexec_path) + list(APPEND _signing_command + ${_psiexec_path} + -accepteula + -nobanner + -s + ) +endif() + +find_program(_powershell_path powershell.exe REQUIRED) +list(APPEND _signing_command + ${_powershell_path} + -NoLogo + -ExecutionPolicy Bypass + -File ${_sign_script} +) + +# This requires to have a valid local certificate. In continuous integration, these certificates are stored +# in the machine directly. +# You can generate a test certificate to be able to run this in a PowerShell elevated promp with: +# New-SelfSignedCertificate -DnsName foo.o3de.com -Type CodeSigning -CertStoreLocation Cert:\CurrentUser\My +# Export-Certificate -Cert (Get-ChildItem Cert:\CurrentUser\My\) -Filepath "c:\selfsigned.crt" +# Import-Certificate -FilePath "c:\selfsigned.crt" -Cert Cert:\CurrentUser\TrustedPublisher +# Import-Certificate -FilePath "c:\selfsigned.crt" -Cert Cert:\CurrentUser\Root + +message(STATUS "Signing executable files in ${_cpack_wix_out_dir}") +execute_process( + COMMAND ${_signing_command} -exePath ${_cpack_wix_out_dir} + RESULT_VARIABLE _signing_result + ERROR_VARIABLE _signing_errors + OUTPUT_VARIABLE _signing_output + ECHO_OUTPUT_VARIABLE +) + +if(NOT ${_signing_result} EQUAL 0) + message(FATAL_ERROR "An error occurred during signing executable files. ${_signing_errors}") +else() + message(STATUS "Signing exes complete!") +endif() diff --git a/cmake/Platform/Windows/Packaging_windows.cmake b/cmake/Platform/Windows/Packaging_windows.cmake index 4a03df2fd2..f24e9dee1c 100644 --- a/cmake/Platform/Windows/Packaging_windows.cmake +++ b/cmake/Platform/Windows/Packaging_windows.cmake @@ -23,16 +23,12 @@ set(CPACK_WIX_ROOT ${LY_INSTALLER_WIX_ROOT}) set(CPACK_GENERATOR WIX) -set(CPACK_THREADS 0) set(_cmake_package_name "cmake-${CPACK_DESIRED_CMAKE_VERSION}-windows-x86_64") set(CPACK_CMAKE_PACKAGE_FILE "${_cmake_package_name}.zip") set(CPACK_CMAKE_PACKAGE_HASH "15a49e2ab81c1822d75b1b1a92f7863f58e31f6d6aac1c4103eef2b071be3112") -# workaround for shortening the path cpack installs to by stripping the platform directory and forcing monolithic -# mode to strip out component folders. this unfortunately is the closest we can get to changing the install location -# as CPACK_PACKAGING_INSTALL_PREFIX/CPACK_SET_DESTDIR isn't supported for the WiX generator +# workaround for shortening the path cpack installs to by stripping the platform directory set(CPACK_TOPLEVEL_TAG "") -set(CPACK_MONOLITHIC_INSTALL ON) # CPack will generate the WiX product/upgrade GUIDs further down the chain if they weren't supplied # however, they are unique for each run. instead, let's do the auto generation here and add it to @@ -108,45 +104,35 @@ set(_raw_text_license [[ #(loc.InstallEulaAcceptance) ]]) -if(LY_INSTALLER_DOWNLOAD_URL) - set(WIX_THEME_WARNING_IMAGE ${CPACK_SOURCE_DIR}/Platform/Windows/Packaging/warning.png) +set(WIX_THEME_WARNING_IMAGE ${CPACK_SOURCE_DIR}/Platform/Windows/Packaging/warning.png) - if(LY_INSTALLER_LICENSE_URL) - set(WIX_THEME_INSTALL_LICENSE_ELEMENTS ${_hyperlink_license}) - set(WIX_THEME_EULA_ACCEPTANCE_TEXT "<a href=\"#\">Terms of Use</a>") - else() - set(WIX_THEME_INSTALL_LICENSE_ELEMENTS ${_raw_text_license}) - set(WIX_THEME_EULA_ACCEPTANCE_TEXT "Terms of Use above") - endif() - - # theme ux file - configure_file( - "${CPACK_SOURCE_DIR}/Platform/Windows/Packaging/BootstrapperTheme.xml.in" - "${CPACK_BINARY_DIR}/BootstrapperTheme.xml" - @ONLY - ) - - # theme localization file - configure_file( - "${CPACK_SOURCE_DIR}/Platform/Windows/Packaging/BootstrapperTheme.wxl.in" - "${CPACK_BINARY_DIR}/BootstrapperTheme.wxl" - @ONLY - ) - - set(_embed_artifacts "no") - - # the bootstrapper will at the very least need a different upgrade guid - generate_wix_guid(CPACK_WIX_BOOTSTRAP_UPGRADE_GUID "${_guid_seed_base}_Bootstrap_UpgradeCode") - - set(CPACK_PRE_BUILD_SCRIPTS - ${CPACK_SOURCE_DIR}/Platform/Windows/PackagingPreBuild.cmake - ) - - set(CPACK_POST_BUILD_SCRIPTS - ${CPACK_SOURCE_DIR}/Platform/Windows/PackagingPostBuild.cmake - ) +if(LY_INSTALLER_LICENSE_URL) + set(WIX_THEME_INSTALL_LICENSE_ELEMENTS ${_hyperlink_license}) + set(WIX_THEME_EULA_ACCEPTANCE_TEXT "<a href=\"#\">Terms of Use</a>") +else() + set(WIX_THEME_INSTALL_LICENSE_ELEMENTS ${_raw_text_license}) + set(WIX_THEME_EULA_ACCEPTANCE_TEXT "Terms of Use above") endif() +# theme ux file +configure_file( + "${CPACK_SOURCE_DIR}/Platform/Windows/Packaging/BootstrapperTheme.xml.in" + "${CPACK_BINARY_DIR}/BootstrapperTheme.xml" + @ONLY +) + +# theme localization file +configure_file( + "${CPACK_SOURCE_DIR}/Platform/Windows/Packaging/BootstrapperTheme.wxl.in" + "${CPACK_BINARY_DIR}/BootstrapperTheme.wxl" + @ONLY +) + +set(_embed_artifacts "no") + +# the bootstrapper will at the very least need a different upgrade guid +generate_wix_guid(CPACK_WIX_BOOTSTRAP_UPGRADE_GUID "${_guid_seed_base}_Bootstrap_UpgradeCode") + set(CPACK_WIX_CANDLE_EXTRA_FLAGS -dCPACK_EMBED_ARTIFACTS=${_embed_artifacts} -dCPACK_CMAKE_PACKAGE_NAME=${_cmake_package_name} diff --git a/cmake/Platform/Windows/platform_windows_files.cmake b/cmake/Platform/Windows/platform_windows_files.cmake index fcc47ab6eb..984d985380 100644 --- a/cmake/Platform/Windows/platform_windows_files.cmake +++ b/cmake/Platform/Windows/platform_windows_files.cmake @@ -15,6 +15,8 @@ set(FILES ../Common/MSVC/VisualStudio_common.cmake ../Common/Install_common.cmake ../Common/LYWrappers_default.cmake + ../Common/PackagingPostBuild_common.cmake + ../Common/PackagingPreBuild_common.cmake ../Common/TargetIncludeSystemDirectories_unsupported.cmake Configurations_windows.cmake LYTestWrappers_windows.cmake @@ -23,7 +25,8 @@ set(FILES PALDetection_windows.cmake Install_windows.cmake Packaging_windows.cmake - PackagingPostBuild.cmake + PackagingPostBuild_windows.cmake + PackagingPreBuild_windows.cmake Packaging/Bootstrapper.wxs Packaging/BootstrapperTheme.wxl.in Packaging/BootstrapperTheme.xml.in diff --git a/cmake/Version.cmake b/cmake/Version.cmake index 662e75c3db..de93ebefef 100644 --- a/cmake/Version.cmake +++ b/cmake/Version.cmake @@ -11,3 +11,8 @@ set(LY_VERSION_COPYRIGHT_YEAR ${current_year} CACHE STRING "Open 3D Engine's cop set(LY_VERSION_STRING "0.0.0.0" CACHE STRING "Open 3D Engine's version") set(LY_VERSION_BUILD_NUMBER 0 CACHE STRING "Open 3D Engine's build number") set(LY_VERSION_ENGINE_NAME "o3de" CACHE STRING "Open 3D Engine's engine name") + +if("$ENV{O3DE_VERSION}") + # Overriding through environment + set(LY_VERSION_STRING "$ENV{O3DE_VERSION}") +endif() diff --git a/cmake/install/ConfigurationType_config.cmake.in b/cmake/install/ConfigurationType_config.cmake.in index 074e034899..0a6940d7ff 100644 --- a/cmake/install/ConfigurationType_config.cmake.in +++ b/cmake/install/ConfigurationType_config.cmake.in @@ -8,4 +8,4 @@ include_guard(GLOBAL) -list(APPEND CMAKE_CONFIGURATION_TYPES @CMAKE_INSTALL_CONFIG_NAME@) +list(APPEND CMAKE_CONFIGURATION_TYPES @conf@) diff --git a/scripts/build/Platform/Android/build_config.json b/scripts/build/Platform/Android/build_config.json index c1fbb1dd87..5e2da44a3c 100644 --- a/scripts/build/Platform/Android/build_config.json +++ b/scripts/build/Platform/Android/build_config.json @@ -35,7 +35,7 @@ "PARAMETERS": { "CONFIGURATION":"debug", "OUTPUT_DIRECTORY":"build\\android", - "CMAKE_OPTIONS":"-G \"Ninja Multi-Config\" -DCMAKE_TOOLCHAIN_FILE=cmake\\Platform\\Android\\Toolchain_android.cmake -DANDROID_ABI=arm64-v8a -DANDROID_ARM_MODE=arm -DANDROID_ARM_NEON=FALSE -DANDROID_NATIVE_API_LEVEL=21 -DLY_NDK_DIR=\"!LY_3RDPARTY_PATH!\\android-ndk\\r21d\" -DLY_UNITY_BUILD=TRUE", + "CMAKE_OPTIONS":"-G \"Ninja Multi-Config\" -DCMAKE_TOOLCHAIN_FILE=cmake\\Platform\\Android\\Toolchain_android.cmake -DANDROID_ABI=arm64-v8a -DANDROID_ARM_MODE=arm -DANDROID_ARM_NEON=FALSE -DANDROID_NATIVE_API_LEVEL=21 -DLY_NDK_DIR=\"!LY_3RDPARTY_PATH!\\android-ndk\\r21d\"", "CMAKE_LY_PROJECTS":"AutomatedTesting", "CMAKE_TARGET":"all", "CMAKE_BUILD_ARGS":"-j!NUMBER_OF_PROCESSORS!" @@ -60,7 +60,7 @@ "PARAMETERS": { "CONFIGURATION":"profile", "OUTPUT_DIRECTORY":"build\\android", - "CMAKE_OPTIONS":"-G \"Ninja Multi-Config\" -DCMAKE_TOOLCHAIN_FILE=cmake\\Platform\\Android\\Toolchain_android.cmake -DANDROID_ABI=arm64-v8a -DANDROID_ARM_MODE=arm -DANDROID_ARM_NEON=FALSE -DANDROID_NATIVE_API_LEVEL=21 -DLY_NDK_DIR=\"!LY_3RDPARTY_PATH!\\android-ndk\\r21d\" -DLY_UNITY_BUILD=TRUE", + "CMAKE_OPTIONS":"-G \"Ninja Multi-Config\" -DCMAKE_TOOLCHAIN_FILE=cmake\\Platform\\Android\\Toolchain_android.cmake -DANDROID_ABI=arm64-v8a -DANDROID_ARM_MODE=arm -DANDROID_ARM_NEON=FALSE -DANDROID_NATIVE_API_LEVEL=21 -DLY_NDK_DIR=\"!LY_3RDPARTY_PATH!\\android-ndk\\r21d\"", "CMAKE_LY_PROJECTS":"AutomatedTesting", "CMAKE_TARGET":"all", "CMAKE_BUILD_ARGS":"-j!NUMBER_OF_PROCESSORS!" @@ -93,7 +93,7 @@ "PARAMETERS": { "CONFIGURATION":"profile", "OUTPUT_DIRECTORY":"build\\windows_vs2019", - "CMAKE_OPTIONS":"-G \"Visual Studio 16 2019\" -DCMAKE_SYSTEM_VERSION=10.0 -DLY_UNITY_BUILD=TRUE", + "CMAKE_OPTIONS":"-G \"Visual Studio 16 2019\" -DCMAKE_SYSTEM_VERSION=10.0", "CMAKE_LY_PROJECTS":"AutomatedTesting", "CMAKE_TARGET":"AssetProcessorBatch", "CMAKE_NATIVE_BUILD_ARGS": "/m /nologo", @@ -112,7 +112,7 @@ "PARAMETERS": { "CONFIGURATION":"release", "OUTPUT_DIRECTORY":"build\\android", - "CMAKE_OPTIONS":"-G \"Ninja Multi-Config\" -DCMAKE_TOOLCHAIN_FILE=cmake\\Platform\\Android\\Toolchain_android.cmake -DANDROID_ABI=arm64-v8a -DANDROID_ARM_MODE=arm -DANDROID_ARM_NEON=FALSE -DANDROID_NATIVE_API_LEVEL=21 -DLY_NDK_DIR=\"!LY_3RDPARTY_PATH!\\android-ndk\\r21d\" -DLY_UNITY_BUILD=TRUE", + "CMAKE_OPTIONS":"-G \"Ninja Multi-Config\" -DCMAKE_TOOLCHAIN_FILE=cmake\\Platform\\Android\\Toolchain_android.cmake -DANDROID_ABI=arm64-v8a -DANDROID_ARM_MODE=arm -DANDROID_ARM_NEON=FALSE -DANDROID_NATIVE_API_LEVEL=21 -DLY_NDK_DIR=\"!LY_3RDPARTY_PATH!\\android-ndk\\r21d\"", "CMAKE_LY_PROJECTS":"AutomatedTesting", "CMAKE_TARGET":"all", "CMAKE_BUILD_ARGS":"-j!NUMBER_OF_PROCESSORS!" @@ -128,7 +128,7 @@ "PARAMETERS": { "CONFIGURATION":"release", "OUTPUT_DIRECTORY":"build\\mono_android", - "CMAKE_OPTIONS":"-G \"Ninja Multi-Config\" -DCMAKE_TOOLCHAIN_FILE=cmake\\Platform\\Android\\Toolchain_android.cmake -DANDROID_ABI=arm64-v8a -DANDROID_ARM_MODE=arm -DANDROID_ARM_NEON=FALSE -DANDROID_NATIVE_API_LEVEL=21 -DLY_NDK_DIR=\"!LY_3RDPARTY_PATH!\\android-ndk\\r21d\" -DLY_MONOLITHIC_GAME=TRUE -DLY_UNITY_BUILD=TRUE", + "CMAKE_OPTIONS":"-G \"Ninja Multi-Config\" -DCMAKE_TOOLCHAIN_FILE=cmake\\Platform\\Android\\Toolchain_android.cmake -DANDROID_ABI=arm64-v8a -DANDROID_ARM_MODE=arm -DANDROID_ARM_NEON=FALSE -DANDROID_NATIVE_API_LEVEL=21 -DLY_NDK_DIR=\"!LY_3RDPARTY_PATH!\\android-ndk\\r21d\" -DLY_MONOLITHIC_GAME=TRUE", "CMAKE_LY_PROJECTS":"AutomatedTesting", "CMAKE_TARGET":"all", "CMAKE_BUILD_ARGS":"-j!NUMBER_OF_PROCESSORS!" diff --git a/scripts/build/Platform/Linux/build_config.json b/scripts/build/Platform/Linux/build_config.json index 84c5976215..97f8cb8b7e 100644 --- a/scripts/build/Platform/Linux/build_config.json +++ b/scripts/build/Platform/Linux/build_config.json @@ -37,7 +37,7 @@ "PARAMETERS": { "CONFIGURATION": "debug", "OUTPUT_DIRECTORY": "build/linux", - "CMAKE_OPTIONS": "-G 'Ninja Multi-Config' -DCMAKE_C_COMPILER=clang-12 -DCMAKE_CXX_COMPILER=clang++-12 -DLY_UNITY_BUILD=TRUE -DLY_PARALLEL_LINK_JOBS=4", + "CMAKE_OPTIONS": "-G 'Ninja Multi-Config' -DLY_PARALLEL_LINK_JOBS=4", "CMAKE_LY_PROJECTS": "AutomatedTesting", "CMAKE_TARGET": "all" } @@ -53,7 +53,7 @@ "PARAMETERS": { "CONFIGURATION": "profile", "OUTPUT_DIRECTORY": "build/linux", - "CMAKE_OPTIONS": "-G 'Ninja Multi-Config' -DCMAKE_C_COMPILER=clang-12 -DCMAKE_CXX_COMPILER=clang++-12 -DLY_UNITY_BUILD=TRUE -DLY_PARALLEL_LINK_JOBS=4", + "CMAKE_OPTIONS": "-G 'Ninja Multi-Config' -DLY_PARALLEL_LINK_JOBS=4", "CMAKE_LY_PROJECTS": "AutomatedTesting", "CMAKE_TARGET": "all" } @@ -66,7 +66,7 @@ "PARAMETERS": { "CONFIGURATION": "profile", "OUTPUT_DIRECTORY": "build/linux", - "CMAKE_OPTIONS": "-G 'Ninja Multi-Config' -DCMAKE_C_COMPILER=clang-12 -DCMAKE_CXX_COMPILER=clang++-12 -DLY_UNITY_BUILD=FALSE -DLY_PARALLEL_LINK_JOBS=4", + "CMAKE_OPTIONS": "-G 'Ninja Multi-Config' -DLY_UNITY_BUILD=FALSE -DLY_PARALLEL_LINK_JOBS=4", "CMAKE_LY_PROJECTS": "AutomatedTesting", "CMAKE_TARGET": "all" } @@ -80,7 +80,7 @@ "PARAMETERS": { "CONFIGURATION": "profile", "OUTPUT_DIRECTORY": "build/linux", - "CMAKE_OPTIONS": "-G 'Ninja Multi-Config' -DCMAKE_C_COMPILER=clang-12 -DCMAKE_CXX_COMPILER=clang++-12 -DLY_UNITY_BUILD=TRUE -DLY_PARALLEL_LINK_JOBS=4", + "CMAKE_OPTIONS": "-G 'Ninja Multi-Config' -DLY_PARALLEL_LINK_JOBS=4", "CMAKE_LY_PROJECTS": "AutomatedTesting", "CMAKE_TARGET": "all", "CTEST_OPTIONS": "-E Gem::EMotionFX.Editor.Tests -LE (SUITE_sandbox|SUITE_awsi) -L FRAMEWORK_googletest --no-tests=error", @@ -93,7 +93,7 @@ "PARAMETERS": { "CONFIGURATION": "profile", "OUTPUT_DIRECTORY": "build/linux", - "CMAKE_OPTIONS": "-G 'Ninja Multi-Config' -DCMAKE_C_COMPILER=clang-12 -DCMAKE_CXX_COMPILER=clang++-12 -DLY_UNITY_BUILD=FALSE -DLY_PARALLEL_LINK_JOBS=4", + "CMAKE_OPTIONS": "-G 'Ninja Multi-Config' -DLY_UNITY_BUILD=FALSE -DLY_PARALLEL_LINK_JOBS=4", "CMAKE_LY_PROJECTS": "AutomatedTesting", "CMAKE_TARGET": "all", "CTEST_OPTIONS": "-E Gem::EMotionFX.Editor.Tests -LE (SUITE_sandbox|SUITE_awsi) -L FRAMEWORK_googletest --no-tests=error", @@ -110,7 +110,7 @@ "PARAMETERS": { "CONFIGURATION": "profile", "OUTPUT_DIRECTORY": "build/linux", - "CMAKE_OPTIONS": "-G 'Ninja Multi-Config' -DCMAKE_C_COMPILER=clang-12 -DCMAKE_CXX_COMPILER=clang++-12 -DLY_UNITY_BUILD=TRUE -DLY_PARALLEL_LINK_JOBS=4", + "CMAKE_OPTIONS": "-G 'Ninja Multi-Config' -DLY_PARALLEL_LINK_JOBS=4", "CMAKE_LY_PROJECTS": "AutomatedTesting", "CMAKE_TARGET": "AssetProcessorBatch", "ASSET_PROCESSOR_BINARY": "bin/profile/AssetProcessorBatch", @@ -124,7 +124,7 @@ "PARAMETERS": { "CONFIGURATION": "profile", "OUTPUT_DIRECTORY": "build/linux", - "CMAKE_OPTIONS": "-G 'Ninja Multi-Config' -DCMAKE_C_COMPILER=clang-12 -DCMAKE_CXX_COMPILER=clang++-12 -DLY_UNITY_BUILD=FALSE -DLY_PARALLEL_LINK_JOBS=4", + "CMAKE_OPTIONS": "-G 'Ninja Multi-Config' -DLY_UNITY_BUILD=FALSE -DLY_PARALLEL_LINK_JOBS=4", "CMAKE_LY_PROJECTS": "AutomatedTesting", "CMAKE_TARGET": "AssetProcessorBatch", "ASSET_PROCESSOR_BINARY": "bin/profile/AssetProcessorBatch", @@ -142,7 +142,7 @@ "PARAMETERS": { "CONFIGURATION": "profile", "OUTPUT_DIRECTORY": "build/linux", - "CMAKE_OPTIONS": "-G 'Ninja Multi-Config' -DCMAKE_C_COMPILER=clang-12 -DCMAKE_CXX_COMPILER=clang++-12 -DLY_UNITY_BUILD=TRUE -DLY_PARALLEL_LINK_JOBS=4", + "CMAKE_OPTIONS": "-G 'Ninja Multi-Config' -DLY_PARALLEL_LINK_JOBS=4", "CMAKE_LY_PROJECTS": "AutomatedTesting", "CMAKE_TARGET": "TEST_SUITE_periodic", "CTEST_OPTIONS": "-L (SUITE_periodic) --no-tests=error", @@ -162,7 +162,7 @@ "PARAMETERS": { "CONFIGURATION": "profile", "OUTPUT_DIRECTORY": "build/linux", - "CMAKE_OPTIONS": "-G 'Ninja Multi-Config' -DCMAKE_C_COMPILER=clang-12 -DCMAKE_CXX_COMPILER=clang++-12 -DLY_UNITY_BUILD=TRUE -DLY_PARALLEL_LINK_JOBS=4 -DO3DE_HOME_PATH=\"${WORKSPACE}/home\" -DO3DE_REGISTER_ENGINE_PATH=\"${WORKSPACE}/o3de\" -DO3DE_REGISTER_THIS_ENGINE=TRUE", + "CMAKE_OPTIONS": "-G 'Ninja Multi-Config' -DLY_PARALLEL_LINK_JOBS=4", "CMAKE_LY_PROJECTS": "AutomatedTesting", "CMAKE_TARGET": "all", "CTEST_OPTIONS": "-L (SUITE_sandbox) --no-tests=error" @@ -178,7 +178,7 @@ "PARAMETERS": { "CONFIGURATION": "profile", "OUTPUT_DIRECTORY": "build/linux", - "CMAKE_OPTIONS": "-G 'Ninja Multi-Config' -DCMAKE_C_COMPILER=clang-12 -DCMAKE_CXX_COMPILER=clang++-12 -DLY_UNITY_BUILD=TRUE -DLY_PARALLEL_LINK_JOBS=4", + "CMAKE_OPTIONS": "-G 'Ninja Multi-Config' -DLY_PARALLEL_LINK_JOBS=4", "CMAKE_LY_PROJECTS": "AutomatedTesting", "CMAKE_TARGET": "TEST_SUITE_benchmark", "CTEST_OPTIONS": "-L (SUITE_benchmark) --no-tests=error", @@ -195,7 +195,7 @@ "PARAMETERS": { "CONFIGURATION": "release", "OUTPUT_DIRECTORY": "build/linux", - "CMAKE_OPTIONS": "-G 'Ninja Multi-Config' -DCMAKE_C_COMPILER=clang-12 -DCMAKE_CXX_COMPILER=clang++-12 -DLY_UNITY_BUILD=TRUE -DLY_PARALLEL_LINK_JOBS=4", + "CMAKE_OPTIONS": "-G 'Ninja Multi-Config' -DLY_PARALLEL_LINK_JOBS=4", "CMAKE_LY_PROJECTS": "AutomatedTesting", "CMAKE_TARGET": "all" } @@ -210,9 +210,67 @@ "PARAMETERS": { "CONFIGURATION": "release", "OUTPUT_DIRECTORY": "build/mono_linux", - "CMAKE_OPTIONS": "-G 'Ninja Multi-Config' -DCMAKE_C_COMPILER=clang-12 -DCMAKE_CXX_COMPILER=clang++-12 -DLY_MONOLITHIC_GAME=TRUE -DLY_UNITY_BUILD=TRUE -DLY_PARALLEL_LINK_JOBS=4", + "CMAKE_OPTIONS": "-G 'Ninja Multi-Config' -DLY_MONOLITHIC_GAME=TRUE -DLY_PARALLEL_LINK_JOBS=4", "CMAKE_LY_PROJECTS": "AutomatedTesting", "CMAKE_TARGET": "all" } + }, + "install_profile": { + "TAGS": [], + "COMMAND": "build_linux.sh", + "PARAMETERS": { + "CONFIGURATION": "profile", + "OUTPUT_DIRECTORY": "build/linux", + "CMAKE_OPTIONS": "-G 'Ninja Multi-Config' -DLY_PARALLEL_LINK_JOBS=4 -DLY_DISABLE_TEST_MODULES=TRUE", + "CMAKE_TARGET": "install" + } + }, + "installer": { + "TAGS": [ + "nightly-clean", + "nightly-installer" + ], + "COMMAND": "build_installer_linux.sh", + "PARAMETERS": { + "CONFIGURATION": "profile", + "OUTPUT_DIRECTORY": "build/linux", + "CMAKE_OPTIONS": "-G 'Ninja Multi-Config' -DLY_PARALLEL_LINK_JOBS=4 -DLY_DISABLE_TEST_MODULES=TRUE -DLY_VERSION_ENGINE_NAME=o3de-sdk", + "EXTRA_CMAKE_OPTIONS": "-DLY_INSTALLER_AUTO_GEN_TAG=TRUE -DLY_INSTALLER_DOWNLOAD_URL=${INSTALLER_DOWNLOAD_URL} -DLY_INSTALLER_LICENSE_URL=${INSTALLER_DOWNLOAD_URL}/license", + "CPACK_OPTIONS": "-D CPACK_UPLOAD_URL=${CPACK_UPLOAD_URL}", + "CMAKE_TARGET": "all" + } + }, + "install_profile_pipe": { + "TAGS": [ + "nightly-incremental", + "nightly-clean" + ], + "PIPELINE_ENV": { + "PROJECT_REPOSITORY_NAME": "TestProject" + }, + "steps": [ + "install_profile", + "project_generate", + "project_engineinstall_profile" + ] + }, + "project_generate": { + "TAGS": [], + "COMMAND": "python_linux.sh", + "PARAMETERS": { + "SCRIPT_PATH": "install/scripts/o3de.py", + "SCRIPT_PARAMETERS": "create-project -pp ${WORKSPACE}/${PROJECT_REPOSITORY_NAME} --force" + } + }, + "project_engineinstall_profile": { + "TAGS": [], + "COMMAND": "build_linux.sh", + "PARAMETERS": { + "COMMAND_CWD": "${WORKSPACE}/${PROJECT_REPOSITORY_NAME}", + "CONFIGURATION": "profile", + "OUTPUT_DIRECTORY": "build/linux", + "CMAKE_OPTIONS": "-G 'Ninja Multi-Config' -DLY_PARALLEL_LINK_JOBS=4 -DCMAKE_MODULE_PATH=${WORKSPACE}/o3de/install/cmake", + "CMAKE_TARGET": "all" + } } } diff --git a/scripts/build/Platform/Linux/build_installer_linux.sh b/scripts/build/Platform/Linux/build_installer_linux.sh new file mode 100755 index 0000000000..301eb5f16d --- /dev/null +++ b/scripts/build/Platform/Linux/build_installer_linux.sh @@ -0,0 +1,15 @@ +#!/usr/bin/env bash +# +# Copyright (c) Contributors to the Open 3D Engine Project. +# For complete copyright and license terms please see the LICENSE at the root of this distribution. +# +# SPDX-License-Identifier: Apache-2.0 OR MIT +# +# + +set -o errexit # exit on the first failure encountered + +BASEDIR=$(dirname "$0") +source $BASEDIR/build_linux.sh + +source $BASEDIR/installer_linux.sh diff --git a/scripts/build/Platform/Linux/build_linux.sh b/scripts/build/Platform/Linux/build_linux.sh index fd73e17a12..c14d4b5073 100755 --- a/scripts/build/Platform/Linux/build_linux.sh +++ b/scripts/build/Platform/Linux/build_linux.sh @@ -17,7 +17,10 @@ SOURCE_DIRECTORY=${PWD} pushd $OUTPUT_DIRECTORY LAST_CONFIGURE_CMD_FILE=ci_last_configure_cmd.txt -CONFIGURE_CMD="cmake ${SOURCE_DIRECTORY} ${CMAKE_OPTIONS} ${EXTRA_CMAKE_OPTIONS} -DLY_3RDPARTY_PATH=${LY_3RDPARTY_PATH} -DLY_PROJECTS='${CMAKE_LY_PROJECTS}'" +CONFIGURE_CMD="cmake ${SOURCE_DIRECTORY} ${CMAKE_OPTIONS} ${EXTRA_CMAKE_OPTIONS} -DLY_3RDPARTY_PATH=${LY_3RDPARTY_PATH}" +if [[ -n "$CMAKE_LY_PROJECTS" ]]; then + CONFIGURE_CMD="${CONFIGURE_CMD} -DLY_PROJECTS='${CMAKE_LY_PROJECTS}'" +fi if [[ ! -e "CMakeCache.txt" ]]; then echo [ci_build] First run, generating RUN_CONFIGURE=1 @@ -34,13 +37,13 @@ else fi if [[ ! -z "$RUN_CONFIGURE" ]]; then # have to use eval since $CMAKE_OPTIONS (${EXTRA_CMAKE_OPTIONS}) contains quotes that need to be processed - echo [ci_build] ${CONFIGURE_CMD} + eval echo [ci_build] ${CONFIGURE_CMD} eval ${CONFIGURE_CMD} # Save the run only if success - echo "${CONFIGURE_CMD}" > ${LAST_CONFIGURE_CMD_FILE} + eval echo "${CONFIGURE_CMD}" > ${LAST_CONFIGURE_CMD_FILE} fi -echo [ci_build] cmake --build . --target ${CMAKE_TARGET} --config ${CONFIGURATION} -j $(grep -c processor /proc/cpuinfo) -- ${CMAKE_NATIVE_BUILD_ARGS} -cmake --build . --target ${CMAKE_TARGET} --config ${CONFIGURATION} -j $(grep -c processor /proc/cpuinfo) -- ${CMAKE_NATIVE_BUILD_ARGS} +eval echo [ci_build] cmake --build . --target ${CMAKE_TARGET} --config ${CONFIGURATION} -j $(grep -c processor /proc/cpuinfo) -- ${CMAKE_NATIVE_BUILD_ARGS} +eval cmake --build . --target ${CMAKE_TARGET} --config ${CONFIGURATION} -j $(grep -c processor /proc/cpuinfo) -- ${CMAKE_NATIVE_BUILD_ARGS} popd diff --git a/scripts/build/Platform/Linux/env_linux.sh b/scripts/build/Platform/Linux/env_linux.sh index a03b9642fb..059bb119ff 100755 --- a/scripts/build/Platform/Linux/env_linux.sh +++ b/scripts/build/Platform/Linux/env_linux.sh @@ -18,3 +18,8 @@ if ! command -v ninja &> /dev/null; then echo "[ci_build] Ninja not found" exit 1 fi + +if [[ -n "${COMMAND_CWD}" ]]; then + echo $(eval echo [ci_build] Changing CWD to $COMMAND_CWD) + cd $(eval echo ${COMMAND_CWD}) +fi diff --git a/scripts/build/Platform/Linux/installer_linux.sh b/scripts/build/Platform/Linux/installer_linux.sh new file mode 100755 index 0000000000..3ded242522 --- /dev/null +++ b/scripts/build/Platform/Linux/installer_linux.sh @@ -0,0 +1,30 @@ +#!/usr/bin/env bash +# +# Copyright (c) Contributors to the Open 3D Engine Project. +# For complete copyright and license terms please see the LICENSE at the root of this distribution. +# +# SPDX-License-Identifier: Apache-2.0 OR MIT +# +# + +set -o errexit # exit on the first failure encountered + +BASEDIR=$(dirname "$0") +source $BASEDIR/env_linux.sh + +mkdir -p ${OUTPUT_DIRECTORY} +SOURCE_DIRECTORY=${PWD} +pushd $OUTPUT_DIRECTORY + +if ! command -v cpack &> /dev/null; then + echo "[ci_build] CPack not found" + exit 1 +fi + +echo [ci_build] cpack --version +cpack --version + +eval echo [ci_build] cpack -C ${CONFIGURATION} ${CPACK_OPTIONS} +eval cpack -C ${CONFIGURATION} ${CPACK_OPTIONS} + +popd diff --git a/scripts/build/Platform/Mac/build_config.json b/scripts/build/Platform/Mac/build_config.json index 7eb3cb5699..34b02a1aec 100644 --- a/scripts/build/Platform/Mac/build_config.json +++ b/scripts/build/Platform/Mac/build_config.json @@ -37,7 +37,7 @@ "PARAMETERS": { "CONFIGURATION": "debug", "OUTPUT_DIRECTORY": "build/mac", - "CMAKE_OPTIONS": "-G Xcode -DLY_UNITY_BUILD=TRUE", + "CMAKE_OPTIONS": "-G Xcode", "CMAKE_LY_PROJECTS": "AutomatedTesting", "CMAKE_TARGET": "ALL_BUILD" } @@ -51,7 +51,7 @@ "PARAMETERS": { "CONFIGURATION": "profile", "OUTPUT_DIRECTORY": "build/mac", - "CMAKE_OPTIONS": "-G Xcode -DLY_UNITY_BUILD=TRUE", + "CMAKE_OPTIONS": "-G Xcode", "CMAKE_LY_PROJECTS": "AutomatedTesting", "CMAKE_TARGET": "ALL_BUILD" } @@ -81,7 +81,7 @@ "PARAMETERS": { "CONFIGURATION": "profile", "OUTPUT_DIRECTORY": "build/mac", - "CMAKE_OPTIONS": "-G Xcode -DLY_UNITY_BUILD=TRUE", + "CMAKE_OPTIONS": "-G Xcode", "CMAKE_LY_PROJECTS": "AutomatedTesting", "CMAKE_TARGET": "AssetProcessorBatch", "ASSET_PROCESSOR_BINARY": "bin/profile/AssetProcessorBatch", @@ -99,7 +99,7 @@ "PARAMETERS": { "CONFIGURATION": "profile", "OUTPUT_DIRECTORY": "build/mac", - "CMAKE_OPTIONS": "-G Xcode -DLY_UNITY_BUILD=TRUE", + "CMAKE_OPTIONS": "-G Xcode", "CMAKE_LY_PROJECTS": "AutomatedTesting", "CMAKE_TARGET": "TEST_SUITE_periodic", "CTEST_OPTIONS": "-L \"(SUITE_periodic)\"", @@ -116,7 +116,7 @@ "PARAMETERS": { "CONFIGURATION": "profile", "OUTPUT_DIRECTORY": "build/mac", - "CMAKE_OPTIONS": "-G Xcode -DLY_UNITY_BUILD=TRUE", + "CMAKE_OPTIONS": "-G Xcode", "CMAKE_LY_PROJECTS": "AutomatedTesting", "CMAKE_TARGET": "TEST_SUITE_benchmark", "CTEST_OPTIONS": "-L \"(SUITE_benchmark)\"", @@ -133,7 +133,7 @@ "PARAMETERS": { "CONFIGURATION": "release", "OUTPUT_DIRECTORY": "build/mac", - "CMAKE_OPTIONS": "-G Xcode -DLY_UNITY_BUILD=TRUE", + "CMAKE_OPTIONS": "-G Xcode", "CMAKE_LY_PROJECTS": "AutomatedTesting", "CMAKE_TARGET": "ALL_BUILD" } @@ -148,7 +148,7 @@ "PARAMETERS": { "CONFIGURATION": "release", "OUTPUT_DIRECTORY": "build/mono_mac", - "CMAKE_OPTIONS": "-G Xcode -DLY_MONOLITHIC_GAME=TRUE -DLY_UNITY_BUILD=TRUE", + "CMAKE_OPTIONS": "-G Xcode -DLY_MONOLITHIC_GAME=TRUE", "CMAKE_LY_PROJECTS": "AutomatedTesting", "CMAKE_TARGET": "ALL_BUILD" } @@ -162,5 +162,50 @@ "SCRIPT_PATH": "scripts/build/package/package.py", "SCRIPT_PARAMETERS": "--platform Mac --type all" } + }, + "install_profile": { + "TAGS": [], + "COMMAND": "build_mac.sh", + "PARAMETERS": { + "CONFIGURATION": "profile", + "OUTPUT_DIRECTORY": "build/mac", + "CMAKE_OPTIONS": "-G Xcode -DLY_DISABLE_TEST_MODULES=TRUE", + "CMAKE_LY_PROJECTS": "", + "CMAKE_TARGET": "install" + } + }, + "install_profile_pipe": { + "TAGS": [ + "nightly-incremental", + "nightly-clean" + ], + "PIPELINE_ENV": { + "PROJECT_REPOSITORY_NAME": "TestProject" + }, + "steps": [ + "install_profile", + "project_generate", + "project_engineinstall_profile" + ] + }, + "project_generate": { + "TAGS": [], + "COMMAND": "python_mac.sh", + "PARAMETERS": { + "SCRIPT_PATH": "install/O3DE_SDK.app/Contents/Engine/scripts/o3de.py", + "SCRIPT_PARAMETERS": "create-project -pp ${WORKSPACE}/${PROJECT_REPOSITORY_NAME} --force" + } + }, + "project_engineinstall_profile": { + "TAGS": [], + "COMMAND": "build_mac.sh", + "PARAMETERS": { + "COMMAND_CWD": "${WORKSPACE}/${PROJECT_REPOSITORY_NAME}", + "CONFIGURATION": "profile", + "OUTPUT_DIRECTORY": "build/mac", + "CMAKE_OPTIONS": "-G Xcode -DCMAKE_MODULE_PATH=${WORKSPACE}/o3de/install/O3DE_SDK.app/Contents/Engine/cmake", + "CMAKE_LY_PROJECTS": "", + "CMAKE_TARGET": "ALL_BUILD" + } } } diff --git a/scripts/build/Platform/Mac/build_mac.sh b/scripts/build/Platform/Mac/build_mac.sh index cb271212d6..169e91c24f 100755 --- a/scripts/build/Platform/Mac/build_mac.sh +++ b/scripts/build/Platform/Mac/build_mac.sh @@ -17,7 +17,10 @@ SOURCE_DIRECTORY=${PWD} pushd $OUTPUT_DIRECTORY LAST_CONFIGURE_CMD_FILE=ci_last_configure_cmd.txt -CONFIGURE_CMD="cmake ${SOURCE_DIRECTORY} ${CMAKE_OPTIONS} ${EXTRA_CMAKE_OPTIONS} -DLY_3RDPARTY_PATH=${LY_3RDPARTY_PATH} -DLY_PROJECTS='${CMAKE_LY_PROJECTS}'" +CONFIGURE_CMD="cmake ${SOURCE_DIRECTORY} ${CMAKE_OPTIONS} ${EXTRA_CMAKE_OPTIONS} -DLY_3RDPARTY_PATH=${LY_3RDPARTY_PATH}" +if [[ -n "$CMAKE_LY_PROJECTS" ]]; then + CONFIGURE_CMD="${CONFIGURE_CMD} -DLY_PROJECTS='${CMAKE_LY_PROJECTS}'" +fi if [[ ! -e "CMakeCache.txt" ]]; then echo [ci_build] First run, generating RUN_CONFIGURE=1 diff --git a/scripts/build/Platform/Mac/env_mac.sh b/scripts/build/Platform/Mac/env_mac.sh index 2c974a1efe..f5fd9f5773 100755 --- a/scripts/build/Platform/Mac/env_mac.sh +++ b/scripts/build/Platform/Mac/env_mac.sh @@ -13,3 +13,8 @@ if ! command -v cmake &> /dev/null; then echo "[ci_build] CMake not found" exit 1 fi + +if [[ -n "${COMMAND_CWD}" ]]; then + echo $(eval echo [ci_build] Changing CWD to $COMMAND_CWD) + cd $(eval echo ${COMMAND_CWD}) +fi diff --git a/scripts/build/Platform/Windows/build_config.json b/scripts/build/Platform/Windows/build_config.json index 9eb9957729..6f1aaa1570 100644 --- a/scripts/build/Platform/Windows/build_config.json +++ b/scripts/build/Platform/Windows/build_config.json @@ -56,7 +56,7 @@ "COMMAND": "python_windows.cmd", "PARAMETERS": { "SCRIPT_PATH": "scripts/build/ci_build_metrics.py", - "SCRIPT_PARAMETERS": "--platform=Windows --repository=!REPOSITORY_NAME! --jobname=!JOB_NAME! --jobnumber=!BUILD_NUMBER! --jobnode=!NODE_LABEL! --changelist=!CHANGE_ID!" + "SCRIPT_PARAMETERS": "--platform=Windows --repository=%REPOSITORY_NAME% --jobname=%JOB_NAME% --jobnumber=%BUILD_NUMBER% --jobnode=%NODE_LABEL% --changelist=%CHANGE_ID%" } }, "windows_packaging_all": { @@ -88,7 +88,7 @@ "CONFIGURATION": "profile", "SCRIPT_PATH": "scripts/build/TestImpactAnalysis/tiaf_driver.py", "SCRIPT_PARAMETERS": - "--config=\"!OUTPUT_DIRECTORY!/bin/TestImpactFramework/profile/Persistent/tiaf.json\" --src-branch=!BRANCH_NAME! --dst-branch=!CHANGE_TARGET! --commit=!CHANGE_ID! --s3-bucket=!TEST_IMPACT_S3_BUCKET! --mars-index-prefix=jonawals --s3-top-level-dir=!REPOSITORY_NAME! --build-number=!BUILD_NUMBER! --suite=main --test-failure-policy=continue" + "--config=\"%OUTPUT_DIRECTORY%/bin/TestImpactFramework/profile/Persistent/tiaf.json\" --src-branch=%BRANCH_NAME% --dst-branch=%CHANGE_TARGET% --commit=%CHANGE_ID% --s3-bucket=%TEST_IMPACT_S3_BUCKET% --mars-index-prefix=jonawals --s3-top-level-dir=%REPOSITORY_NAME% --build-number=%BUILD_NUMBER% --suite=main --test-failure-policy=continue" } }, "debug_vs2019": { @@ -99,7 +99,7 @@ "PARAMETERS": { "CONFIGURATION": "debug", "OUTPUT_DIRECTORY": "build\\windows_vs2019", - "CMAKE_OPTIONS": "-G \"Visual Studio 16 2019\" -DCMAKE_SYSTEM_VERSION=10.0 -DLY_UNITY_BUILD=TRUE", + "CMAKE_OPTIONS": "-G \"Visual Studio 16 2019\" -DCMAKE_SYSTEM_VERSION=10.0", "CMAKE_LY_PROJECTS": "AutomatedTesting", "CMAKE_TARGET": "ALL_BUILD", "CMAKE_NATIVE_BUILD_ARGS": "/m /nologo" @@ -113,7 +113,7 @@ "PARAMETERS": { "CONFIGURATION": "debug", "OUTPUT_DIRECTORY": "build\\windows_vs2019", - "CMAKE_OPTIONS": "-G \"Visual Studio 16 2019\" -DCMAKE_SYSTEM_VERSION=10.0 -DLY_UNITY_BUILD=TRUE", + "CMAKE_OPTIONS": "-G \"Visual Studio 16 2019\" -DCMAKE_SYSTEM_VERSION=10.0", "CMAKE_LY_PROJECTS": "AutomatedTesting", "CMAKE_TARGET": "TEST_SUITE_smoke TEST_SUITE_main", "CMAKE_NATIVE_BUILD_ARGS": "/m /nologo", @@ -131,7 +131,7 @@ "PARAMETERS": { "CONFIGURATION": "profile", "OUTPUT_DIRECTORY": "build\\windows_vs2019", - "CMAKE_OPTIONS": "-G \"Visual Studio 16 2019\" -DCMAKE_SYSTEM_VERSION=10.0 -DLY_UNITY_BUILD=TRUE -DLY_TEST_IMPACT_INSTRUMENTATION_BIN=!TEST_IMPACT_WIN_BINARY!", + "CMAKE_OPTIONS": "-G \"Visual Studio 16 2019\" -DCMAKE_SYSTEM_VERSION=10.0 -DLY_TEST_IMPACT_INSTRUMENTATION_BIN=%TEST_IMPACT_WIN_BINARY%", "CMAKE_LY_PROJECTS": "AutomatedTesting", "CMAKE_TARGET": "ALL_BUILD", "CMAKE_NATIVE_BUILD_ARGS": "/m /nologo" @@ -162,7 +162,7 @@ "PARAMETERS": { "CONFIGURATION": "profile", "OUTPUT_DIRECTORY": "build\\windows_vs2019", - "CMAKE_OPTIONS": "-G \"Visual Studio 16 2019\" -DCMAKE_SYSTEM_VERSION=10.0 -DLY_UNITY_BUILD=TRUE", + "CMAKE_OPTIONS": "-G \"Visual Studio 16 2019\" -DCMAKE_SYSTEM_VERSION=10.0", "CMAKE_LY_PROJECTS": "AutomatedTesting", "CMAKE_TARGET": "TEST_SUITE_smoke TEST_SUITE_main", "CMAKE_NATIVE_BUILD_ARGS": "/m /nologo", @@ -183,7 +183,7 @@ "PARAMETERS": { "CONFIGURATION": "profile", "OUTPUT_DIRECTORY": "build\\windows_vs2019", - "CMAKE_OPTIONS": "-G \"Visual Studio 16 2019\" -DCMAKE_SYSTEM_VERSION=10.0 -DLY_UNITY_BUILD=TRUE", + "CMAKE_OPTIONS": "-G \"Visual Studio 16 2019\" -DCMAKE_SYSTEM_VERSION=10.0", "CMAKE_LY_PROJECTS": "AutomatedTesting", "CMAKE_TARGET": "TEST_SUITE_smoke TEST_SUITE_main", "CMAKE_NATIVE_BUILD_ARGS": "/m /nologo", @@ -203,7 +203,7 @@ "PARAMETERS": { "CONFIGURATION": "profile", "OUTPUT_DIRECTORY": "build\\windows_vs2019", - "CMAKE_OPTIONS": "-G \"Visual Studio 16 2019\" -DCMAKE_SYSTEM_VERSION=10.0 -DLY_UNITY_BUILD=TRUE", + "CMAKE_OPTIONS": "-G \"Visual Studio 16 2019\" -DCMAKE_SYSTEM_VERSION=10.0", "CMAKE_LY_PROJECTS": "AutomatedTesting", "CMAKE_TARGET": "AssetProcessorBatch", "CMAKE_NATIVE_BUILD_ARGS": "/m /nologo", @@ -234,7 +234,7 @@ "PARAMETERS": { "CONFIGURATION": "profile", "OUTPUT_DIRECTORY": "build\\windows_vs2019", - "CMAKE_OPTIONS": "-G \"Visual Studio 16 2019\" -DCMAKE_SYSTEM_VERSION=10.0 -DLY_UNITY_BUILD=TRUE", + "CMAKE_OPTIONS": "-G \"Visual Studio 16 2019\" -DCMAKE_SYSTEM_VERSION=10.0", "CMAKE_LY_PROJECTS": "AutomatedTesting", "CMAKE_TARGET": "TEST_SUITE_awsi", "CMAKE_NATIVE_BUILD_ARGS": "/m /nologo", @@ -253,7 +253,7 @@ "PARAMETERS": { "CONFIGURATION": "profile", "OUTPUT_DIRECTORY": "build\\windows_vs2019", - "CMAKE_OPTIONS": "-G \"Visual Studio 16 2019\" -DCMAKE_SYSTEM_VERSION=10.0 -DLY_UNITY_BUILD=TRUE", + "CMAKE_OPTIONS": "-G \"Visual Studio 16 2019\" -DCMAKE_SYSTEM_VERSION=10.0", "CMAKE_LY_PROJECTS": "AutomatedTesting", "CMAKE_TARGET": "TEST_SUITE_periodic", "CMAKE_NATIVE_BUILD_ARGS": "/m /nologo", @@ -275,7 +275,7 @@ "PARAMETERS": { "CONFIGURATION": "profile", "OUTPUT_DIRECTORY": "build\\windows_vs2019", - "CMAKE_OPTIONS": "-G \"Visual Studio 16 2019\" -DCMAKE_SYSTEM_VERSION=10.0 -DLY_UNITY_BUILD=TRUE", + "CMAKE_OPTIONS": "-G \"Visual Studio 16 2019\" -DCMAKE_SYSTEM_VERSION=10.0", "CMAKE_LY_PROJECTS": "AutomatedTesting", "CMAKE_TARGET": "TEST_SUITE_sandbox", "CMAKE_NATIVE_BUILD_ARGS": "/m /nologo", @@ -294,7 +294,7 @@ "PARAMETERS": { "CONFIGURATION": "profile", "OUTPUT_DIRECTORY": "build\\windows_vs2019", - "CMAKE_OPTIONS": "-G \"Visual Studio 16 2019\" -DCMAKE_SYSTEM_VERSION=10.0 -DLY_UNITY_BUILD=TRUE", + "CMAKE_OPTIONS": "-G \"Visual Studio 16 2019\" -DCMAKE_SYSTEM_VERSION=10.0", "CMAKE_LY_PROJECTS": "AutomatedTesting", "CMAKE_TARGET": "TEST_SUITE_benchmark", "CMAKE_NATIVE_BUILD_ARGS": "/m /nologo", @@ -314,7 +314,7 @@ "PARAMETERS": { "CONFIGURATION": "release", "OUTPUT_DIRECTORY": "build\\windows_vs2019", - "CMAKE_OPTIONS": "-G \"Visual Studio 16 2019\" -DCMAKE_SYSTEM_VERSION=10.0 -DLY_UNITY_BUILD=TRUE", + "CMAKE_OPTIONS": "-G \"Visual Studio 16 2019\" -DCMAKE_SYSTEM_VERSION=10.0", "CMAKE_LY_PROJECTS": "AutomatedTesting", "CMAKE_TARGET": "ALL_BUILD", "CMAKE_NATIVE_BUILD_ARGS": "/m /nologo" @@ -330,23 +330,19 @@ "PARAMETERS": { "CONFIGURATION": "release", "OUTPUT_DIRECTORY": "build\\mono_windows_vs2019", - "CMAKE_OPTIONS": "-G \"Visual Studio 16 2019\" -DCMAKE_SYSTEM_VERSION=10.0 -DLY_MONOLITHIC_GAME=TRUE -DLY_UNITY_BUILD=TRUE", + "CMAKE_OPTIONS": "-G \"Visual Studio 16 2019\" -DCMAKE_SYSTEM_VERSION=10.0 -DLY_MONOLITHIC_GAME=TRUE", "CMAKE_LY_PROJECTS": "AutomatedTesting", "CMAKE_TARGET": "ALL_BUILD", "CMAKE_NATIVE_BUILD_ARGS": "/m /nologo" } }, "install_profile_vs2019": { - "TAGS": [ - "nightly-incremental", - "nightly-clean" - ], + "TAGS": [], "COMMAND": "build_windows.cmd", "PARAMETERS": { "CONFIGURATION": "profile", "OUTPUT_DIRECTORY": "build\\windows_vs2019", - "CMAKE_OPTIONS": "-G \"Visual Studio 16 2019\" -DCMAKE_SYSTEM_VERSION=10.0 -DLY_UNITY_BUILD=TRUE -DLY_DISABLE_TEST_MODULES=TRUE", - "CMAKE_LY_PROJECTS": "", + "CMAKE_OPTIONS": "-G \"Visual Studio 16 2019\" -DCMAKE_SYSTEM_VERSION=10.0 -DLY_DISABLE_TEST_MODULES=TRUE", "CMAKE_TARGET": "INSTALL", "CMAKE_NATIVE_BUILD_ARGS": "/m /nologo" } @@ -363,14 +359,35 @@ "PARAMETERS": { "CONFIGURATION": "profile", "OUTPUT_DIRECTORY": "build\\windows_vs2019", - "CMAKE_OPTIONS": "-G \"Visual Studio 16 2019\" -DCMAKE_SYSTEM_VERSION=10.0 -DLY_UNITY_BUILD=TRUE -DLY_DISABLE_TEST_MODULES=TRUE -DLY_VERSION_ENGINE_NAME=o3de-sdk -DLY_VERSION_STRING=!O3DE_VERSION! -DLY_INSTALLER_WIX_ROOT=\"!WIX! \"", - "EXTRA_CMAKE_OPTIONS": "-DLY_INSTALLER_AUTO_GEN_TAG=ON -DLY_INSTALLER_DOWNLOAD_URL=!INSTALLER_DOWNLOAD_URL! -DLY_INSTALLER_LICENSE_URL=!INSTALLER_DOWNLOAD_URL!/license", - "CPACK_BUCKET": "!INSTALLER_BUCKET!", - "CMAKE_LY_PROJECTS": "", + "CMAKE_OPTIONS": "-G \"Visual Studio 16 2019\" -DCMAKE_SYSTEM_VERSION=10.0 -DLY_DISABLE_TEST_MODULES=TRUE -DLY_VERSION_ENGINE_NAME=o3de-sdk -DLY_INSTALLER_WIX_ROOT=\"!WIX! \"", + "EXTRA_CMAKE_OPTIONS": "-DLY_INSTALLER_AUTO_GEN_TAG=TRUE -DLY_INSTALLER_DOWNLOAD_URL=!INSTALLER_DOWNLOAD_URL! -DLY_INSTALLER_LICENSE_URL=!INSTALLER_DOWNLOAD_URL!/license", "CMAKE_TARGET": "ALL_BUILD", + "CPACK_OPTIONS": "-D CPACK_UPLOAD_URL=\"!CPACK_UPLOAD_URL!\"", "CMAKE_NATIVE_BUILD_ARGS": "/m /nologo" } }, + "install_profile_vs2019_pipe": { + "TAGS": [ + "nightly-incremental", + "nightly-clean" + ], + "PIPELINE_ENV": { + "PROJECT_REPOSITORY_NAME": "TestProject" + }, + "steps": [ + "install_profile_vs2019", + "project_generate", + "project_engineinstall_profile_vs2019" + ] + }, + "project_generate": { + "TAGS": [], + "COMMAND": "python_windows.cmd", + "PARAMETERS": { + "SCRIPT_PATH": "install\\scripts\\o3de.py", + "SCRIPT_PARAMETERS": "create-project -pp %WORKSPACE%\\%PROJECT_REPOSITORY_NAME% --force" + } + }, "project_enginesource_profile_vs2019": { "TAGS": [ "project" @@ -382,8 +399,7 @@ "PARAMETERS": { "CONFIGURATION": "profile", "OUTPUT_DIRECTORY": "build\\windows_vs2019", - "CMAKE_OPTIONS": "-G \"Visual Studio 16 2019\" -DCMAKE_SYSTEM_VERSION=10.0 -DLY_UNITY_BUILD=TRUE -DCMAKE_MODULE_PATH=!WORKSPACE!/o3de/cmake", - "CMAKE_LY_PROJECTS": "", + "CMAKE_OPTIONS": "-G \"Visual Studio 16 2019\" -DCMAKE_SYSTEM_VERSION=10.0 -DCMAKE_MODULE_PATH=%WORKSPACE%/o3de/cmake", "CMAKE_TARGET": "ALL_BUILD", "CMAKE_NATIVE_BUILD_ARGS": "/m /nologo" } @@ -395,10 +411,10 @@ }, "COMMAND": "build_windows.cmd", "PARAMETERS": { + "COMMAND_CWD": "%WORKSPACE%\\%PROJECT_REPOSITORY_NAME%", "CONFIGURATION": "profile", "OUTPUT_DIRECTORY": "build\\windows_vs2019", - "CMAKE_OPTIONS": "-G \"Visual Studio 16 2019\" -DCMAKE_SYSTEM_VERSION=10.0 -DLY_UNITY_BUILD=TRUE -DCMAKE_MODULE_PATH=!WORKSPACE!/o3de/install/cmake", - "CMAKE_LY_PROJECTS": "", + "CMAKE_OPTIONS": "-G \"Visual Studio 16 2019\" -DCMAKE_SYSTEM_VERSION=10.0 -DCMAKE_MODULE_PATH=%WORKSPACE%/o3de/install/cmake", "CMAKE_TARGET": "ALL_BUILD", "CMAKE_NATIVE_BUILD_ARGS": "/m /nologo" } diff --git a/scripts/build/Platform/Windows/build_windows.cmd b/scripts/build/Platform/Windows/build_windows.cmd index b5a0245d1a..6c3ce91397 100644 --- a/scripts/build/Platform/Windows/build_windows.cmd +++ b/scripts/build/Platform/Windows/build_windows.cmd @@ -25,18 +25,14 @@ IF ERRORLEVEL 1 ( exit /b 1 ) -REM Jenkins reports MSB8029 when TMP/TEMP is not defined, define a dummy folder -SET TMP=%cd%/temp -SET TEMP=%cd%/temp -IF NOT EXIST %TMP% ( - MKDIR temp -) - REM Compute half the amount of processors so some jobs can run SET /a HALF_PROCESSORS = NUMBER_OF_PROCESSORS / 2 SET LAST_CONFIGURE_CMD_FILE=ci_last_configure_cmd.txt -SET CONFIGURE_CMD=cmake %SOURCE_DIRECTORY% %CMAKE_OPTIONS% %EXTRA_CMAKE_OPTIONS% -DLY_3RDPARTY_PATH="%LY_3RDPARTY_PATH%" -DLY_PROJECTS=%CMAKE_LY_PROJECTS% +SET CONFIGURE_CMD=cmake %SOURCE_DIRECTORY% %CMAKE_OPTIONS% %EXTRA_CMAKE_OPTIONS% -DLY_3RDPARTY_PATH="%LY_3RDPARTY_PATH%" +IF NOT "%CMAKE_LY_PROJECTS%"=="" ( + SET CONFIGURE_CMD=!CONFIGURE_CMD! -DLY_PROJECTS="%CMAKE_LY_PROJECTS%" +) IF NOT EXIST CMakeCache.txt ( ECHO [ci_build] First run, generating SET RUN_CONFIGURE=1 diff --git a/scripts/build/Platform/Windows/env_windows.cmd b/scripts/build/Platform/Windows/env_windows.cmd index 1c54e36bfc..a78946caf6 100644 --- a/scripts/build/Platform/Windows/env_windows.cmd +++ b/scripts/build/Platform/Windows/env_windows.cmd @@ -7,12 +7,35 @@ REM SPDX-License-Identifier: Apache-2.0 OR MIT REM REM +REM To get recursive folder creation +SETLOCAL EnableExtensions +SETLOCAL EnableDelayedExpansion + where /Q cmake IF NOT %ERRORLEVEL%==0 ( ECHO [ci_build] CMake not found GOTO :error ) +IF NOT "%COMMAND_CWD%"=="" ( + ECHO [ci_build] Changing CWD to %COMMAND_CWD% + CD %COMMAND_CWD% +) + +REM Jenkins reports MSB8029 when TMP/TEMP is not defined, define a dummy folder +IF NOT "%TMP%"=="" ( + IF NOT "%WORKSPACE_TMP%"=="" ( + SET TMP=%WORKSPACE_TMP% + SET TEMP=%WORKSPACE_TMP% + ) ELSE ( + SET TMP=%cd%/temp + SET TEMP=%cd%/temp + ) +) +IF NOT EXIST "!TMP!" ( + MKDIR "!TMP!" +) + EXIT /b 0 :error diff --git a/scripts/build/Platform/Windows/installer_windows.cmd b/scripts/build/Platform/Windows/installer_windows.cmd index 87f53adc7f..bbde450973 100644 --- a/scripts/build/Platform/Windows/installer_windows.cmd +++ b/scripts/build/Platform/Windows/installer_windows.cmd @@ -17,10 +17,12 @@ IF NOT EXIST %OUTPUT_DIRECTORY% ( ) PUSHD %OUTPUT_DIRECTORY% -REM Override the temporary directory used by wix to the workspace -SET "WIX_TEMP=!WORKSPACE_TMP!/wix" -IF NOT EXIST "%WIX_TEMP%" ( - MKDIR "%WIX_TEMP%" +REM Override the temporary directory used by wix to the workspace (if we have a WORKSPACE_TMP) +IF NOT "%WORKSPACE_TMP%"=="" ( + SET "WIX_TEMP=!WORKSPACE_TMP!/wix" + IF NOT EXIST "!WIX_TEMP!" ( + MKDIR "!WIX_TEMP!" + ) ) REM Make sure we are using the CMake version of CPack and not the one that comes with chocolatey @@ -47,10 +49,6 @@ IF ERRORLEVEL 1 ( GOTO :popd_error ) -IF NOT "%CPACK_BUCKET%"=="" ( - SET "CPACK_OPTIONS=-D CPACK_UPLOAD_URL=s3://%CPACK_BUCKET% %CPACK_OPTIONS%" -) - ECHO [ci_build] "!CPACK_PATH!" -C %CONFIGURATION% %CPACK_OPTIONS% "!CPACK_PATH!" -C %CONFIGURATION% %CPACK_OPTIONS% IF NOT %ERRORLEVEL%==0 ( diff --git a/scripts/build/Platform/Windows/package_build_config.json b/scripts/build/Platform/Windows/package_build_config.json index 89431ad96e..5eb96f1e38 100644 --- a/scripts/build/Platform/Windows/package_build_config.json +++ b/scripts/build/Platform/Windows/package_build_config.json @@ -4,7 +4,7 @@ "PARAMETERS": { "CONFIGURATION":"profile", "OUTPUT_DIRECTORY":"windows_vs2019", - "CMAKE_OPTIONS":"-G \"Visual Studio 16 2019\" -DCMAKE_SYSTEM_VERSION=10.0 -DLY_UNITY_BUILD=TRUE", + "CMAKE_OPTIONS":"-G \"Visual Studio 16 2019\" -DCMAKE_SYSTEM_VERSION=10.0", "CMAKE_LY_PROJECTS":"AtomTest;AtomSampleViewer", "CMAKE_TARGET":"ALL_BUILD", "CMAKE_NATIVE_BUILD_ARGS": "/m /nologo" diff --git a/scripts/build/Platform/iOS/build_config.json b/scripts/build/Platform/iOS/build_config.json index 01f545ffb6..ec2b763dda 100644 --- a/scripts/build/Platform/iOS/build_config.json +++ b/scripts/build/Platform/iOS/build_config.json @@ -27,7 +27,7 @@ "PARAMETERS": { "CONFIGURATION": "debug", "OUTPUT_DIRECTORY": "build/ios", - "CMAKE_OPTIONS": "-G Xcode -DCMAKE_TOOLCHAIN_FILE=cmake/Platform/iOS/Toolchain_ios.cmake -DLY_MONOLITHIC_GAME=TRUE -DCMAKE_XCODE_ATTRIBUTE_CODE_SIGNING_REQUIRED=FALSE -DLY_IOS_CODE_SIGNING_IDENTITY=\"\" -DCMAKE_XCODE_ATTRIBUTE_CODE_SIGN_ENTITLEMENTS=\"\" -DCMAKE_XCODE_ATTRIBUTE_CODE_SIGNING_ALLOWED=FALSE -DLY_UNITY_BUILD=TRUE", + "CMAKE_OPTIONS": "-G Xcode -DCMAKE_TOOLCHAIN_FILE=cmake/Platform/iOS/Toolchain_ios.cmake -DLY_MONOLITHIC_GAME=TRUE -DCMAKE_XCODE_ATTRIBUTE_CODE_SIGNING_REQUIRED=FALSE -DLY_IOS_CODE_SIGNING_IDENTITY=\"\" -DCMAKE_XCODE_ATTRIBUTE_CODE_SIGN_ENTITLEMENTS=\"\" -DCMAKE_XCODE_ATTRIBUTE_CODE_SIGNING_ALLOWED=FALSE", "CMAKE_LY_PROJECTS": "AutomatedTesting", "CMAKE_TARGET": "ALL_BUILD", "CMAKE_NATIVE_BUILD_ARGS": "-destination generic/platform=iOS" @@ -44,7 +44,7 @@ "PARAMETERS": { "CONFIGURATION": "profile", "OUTPUT_DIRECTORY": "build/ios", - "CMAKE_OPTIONS": "-G Xcode -DCMAKE_TOOLCHAIN_FILE=cmake/Platform/iOS/Toolchain_ios.cmake -DLY_MONOLITHIC_GAME=TRUE -DCMAKE_XCODE_ATTRIBUTE_CODE_SIGNING_REQUIRED=FALSE -DLY_IOS_CODE_SIGNING_IDENTITY=\"\" -DCMAKE_XCODE_ATTRIBUTE_CODE_SIGN_ENTITLEMENTS=\"\" -DCMAKE_XCODE_ATTRIBUTE_CODE_SIGNING_ALLOWED=FALSE -DLY_UNITY_BUILD=TRUE", + "CMAKE_OPTIONS": "-G Xcode -DCMAKE_TOOLCHAIN_FILE=cmake/Platform/iOS/Toolchain_ios.cmake -DLY_MONOLITHIC_GAME=TRUE -DCMAKE_XCODE_ATTRIBUTE_CODE_SIGNING_REQUIRED=FALSE -DLY_IOS_CODE_SIGNING_IDENTITY=\"\" -DCMAKE_XCODE_ATTRIBUTE_CODE_SIGN_ENTITLEMENTS=\"\" -DCMAKE_XCODE_ATTRIBUTE_CODE_SIGNING_ALLOWED=FALSE", "CMAKE_LY_PROJECTS": "AutomatedTesting", "CMAKE_TARGET": "ALL_BUILD", "CMAKE_NATIVE_BUILD_ARGS": "-destination generic/platform=iOS" @@ -76,7 +76,7 @@ "PARAMETERS": { "CONFIGURATION": "profile", "OUTPUT_DIRECTORY": "build/mac", - "CMAKE_OPTIONS": "-G Xcode -DLY_UNITY_BUILD=TRUE -DO3DE_HOME_PATH=\"${WORKSPACE}/home\" -DO3DE_REGISTER_ENGINE_PATH=\"${WORKSPACE}/o3de\" -DO3DE_REGISTER_THIS_ENGINE=TRUE", + "CMAKE_OPTIONS": "-G Xcode", "CMAKE_LY_PROJECTS": "AutomatedTesting", "CMAKE_TARGET": "AssetProcessorBatch", "ASSET_PROCESSOR_BINARY": "bin/profile/AssetProcessorBatch", @@ -94,7 +94,7 @@ "PARAMETERS": { "CONFIGURATION": "release", "OUTPUT_DIRECTORY": "build/ios", - "CMAKE_OPTIONS": "-G Xcode -DCMAKE_TOOLCHAIN_FILE=cmake/Platform/iOS/Toolchain_ios.cmake -DLY_MONOLITHIC_GAME=TRUE -DCMAKE_XCODE_ATTRIBUTE_CODE_SIGNING_REQUIRED=FALSE -DLY_IOS_CODE_SIGNING_IDENTITY=\"\" -DCMAKE_XCODE_ATTRIBUTE_CODE_SIGN_ENTITLEMENTS=\"\" -DCMAKE_XCODE_ATTRIBUTE_CODE_SIGNING_ALLOWED=FALSE -DLY_UNITY_BUILD=TRUE", + "CMAKE_OPTIONS": "-G Xcode -DCMAKE_TOOLCHAIN_FILE=cmake/Platform/iOS/Toolchain_ios.cmake -DLY_MONOLITHIC_GAME=TRUE -DCMAKE_XCODE_ATTRIBUTE_CODE_SIGNING_REQUIRED=FALSE -DLY_IOS_CODE_SIGNING_IDENTITY=\"\" -DCMAKE_XCODE_ATTRIBUTE_CODE_SIGN_ENTITLEMENTS=\"\" -DCMAKE_XCODE_ATTRIBUTE_CODE_SIGNING_ALLOWED=FALSE", "CMAKE_LY_PROJECTS": "AutomatedTesting", "CMAKE_TARGET": "ALL_BUILD", "CMAKE_NATIVE_BUILD_ARGS": "-destination generic/platform=iOS" @@ -112,7 +112,7 @@ "PARAMETERS": { "CONFIGURATION": "profile", "OUTPUT_DIRECTORY": "build/ios_test", - "CMAKE_OPTIONS": "-G Xcode -DCMAKE_TOOLCHAIN_FILE=cmake/Platform/iOS/Toolchain_ios.cmake -DLY_MONOLITHIC_GAME=FALSE -DCMAKE_XCODE_ATTRIBUTE_CODE_SIGNING_REQUIRED=TRUE -DLY_IOS_CODE_SIGNING_IDENTITY=\"\" -DCMAKE_XCODE_ATTRIBUTE_CODE_SIGN_ENTITLEMENTS=\"\" -DCMAKE_XCODE_ATTRIBUTE_CODE_SIGNING_ALLOWED=TRUE -DLY_UNITY_BUILD=TRUE -DO3DE_HOME_PATH=\"${WORKSPACE}/home\" -DO3DE_REGISTER_ENGINE_PATH=\"${WORKSPACE}/o3de\" -DO3DE_REGISTER_THIS_ENGINE=TRUE", + "CMAKE_OPTIONS": "-G Xcode -DCMAKE_TOOLCHAIN_FILE=cmake/Platform/iOS/Toolchain_ios.cmake -DLY_MONOLITHIC_GAME=FALSE -DCMAKE_XCODE_ATTRIBUTE_CODE_SIGNING_REQUIRED=TRUE -DLY_IOS_CODE_SIGNING_IDENTITY=\"\" -DCMAKE_XCODE_ATTRIBUTE_CODE_SIGN_ENTITLEMENTS=\"\" -DCMAKE_XCODE_ATTRIBUTE_CODE_SIGNING_ALLOWED=TRUE", "CMAKE_TARGET": "ALL_BUILD", "CMAKE_NATIVE_BUILD_ARGS": "", "TARGET_DEVICE_NAME": "Lumberyard", diff --git a/scripts/build/build_node/Platform/Linux/package-list.ubuntu-bionic.txt b/scripts/build/build_node/Platform/Linux/package-list.ubuntu-bionic.txt index 625909e214..30259a6dc7 100644 --- a/scripts/build/build_node/Platform/Linux/package-list.ubuntu-bionic.txt +++ b/scripts/build/build_node/Platform/Linux/package-list.ubuntu-bionic.txt @@ -2,7 +2,7 @@ # Build Tools Packages cmake/3.20.1-0kitware1ubuntu18.04.1 # For cmake -clang-6.0 # For Ninja Build System +clang-12 # For Ninja Build System ninja-build # For the compiler and its dependencies java-11-amazon-corretto-jdk # For Jenkins and Android @@ -12,7 +12,12 @@ libxcb-xinerama0 # For Qt plugins at runtime libxcb-xinput0 # For Qt plugins at runtime libfontconfig1-dev # For Qt plugins at runtime libcurl4-openssl-dev # For HttpRequestor -libsdl2-dev # for WWise/Audio +# libsdl2-dev # For WWise/Audio +libxcb-xkb-dev # For xcb keyboard input +libxkbcommon-x11-dev # For xcb keyboard input +libxkbcommon-dev # For xcb keyboard input +libxcb-xfixes0-dev # For mouse input +libxcb-xinput-dev # For mouse input zlib1g-dev mesa-common-dev diff --git a/scripts/build/build_node/Platform/Linux/package-list.ubuntu-focal.txt b/scripts/build/build_node/Platform/Linux/package-list.ubuntu-focal.txt index 2cbbe58b38..71958d74bd 100644 --- a/scripts/build/build_node/Platform/Linux/package-list.ubuntu-focal.txt +++ b/scripts/build/build_node/Platform/Linux/package-list.ubuntu-focal.txt @@ -12,9 +12,11 @@ libxcb-xinerama0 # For Qt plugins at runtime libxcb-xinput0 # For Qt plugins at runtime libfontconfig1-dev # For Qt plugins at runtime libcurl4-openssl-dev # For HttpRequestor -libsdl2-dev # for WWise/Audio +# libsdl2-dev # for WWise/Audio libxcb-xkb-dev # For xcb keyboard input libxkbcommon-x11-dev # For xcb keyboard input libxkbcommon-dev # For xcb keyboard input +libxcb-xfixes0-dev # For mouse input +libxcb-xinput-dev # For mouse input zlib1g-dev mesa-common-dev From a0ab5920dafb3e20b29370f0cc63eda97c9d975b Mon Sep 17 00:00:00 2001 From: Steve Pham <82231385+spham-amzn@users.noreply.github.com> Date: Fri, 19 Nov 2021 18:04:15 -0800 Subject: [PATCH 09/23] Add trait to enable/disable the Resource Mapping Tool (#5814) * Add trait to enable/disable the Resource Mapping Tool Signed-off-by: spham <82231385+spham-amzn@users.noreply.github.com> * Moving ly_install_directory(DIRECTIORES Tools/ResourceMappingtool) into of the PAL_TRAIT_ENABLE_RESOURCE_MAPPING_TOOL block Signed-off-by: Steve Pham <82231385+spham-amzn@users.noreply.github.com> --- Gems/AWSCore/Code/CMakeLists.txt | 46 +++++++++++-------- .../Linux/PAL_traits_editor_linux.cmake | 9 ++++ .../Platform/Mac/PAL_traits_editor_mac.cmake | 9 ++++ .../Windows/PAL_traits_editor_windows.cmake | 9 ++++ 4 files changed, 54 insertions(+), 19 deletions(-) create mode 100644 Gems/AWSCore/Code/Platform/Linux/PAL_traits_editor_linux.cmake create mode 100644 Gems/AWSCore/Code/Platform/Mac/PAL_traits_editor_mac.cmake create mode 100644 Gems/AWSCore/Code/Platform/Windows/PAL_traits_editor_windows.cmake diff --git a/Gems/AWSCore/Code/CMakeLists.txt b/Gems/AWSCore/Code/CMakeLists.txt index d84f7814c3..f1521856e6 100644 --- a/Gems/AWSCore/Code/CMakeLists.txt +++ b/Gems/AWSCore/Code/CMakeLists.txt @@ -60,6 +60,9 @@ ly_create_alias( ) if (PAL_TRAIT_BUILD_HOST_TOOLS) + + include(${CMAKE_CURRENT_SOURCE_DIR}/Platform/${PAL_PLATFORM_NAME}/PAL_traits_editor_${PAL_PLATFORM_NAME_LOWERCASE}.cmake) + ly_add_target( NAME AWSCore.Editor.Static STATIC NAMESPACE Gem @@ -97,25 +100,31 @@ if (PAL_TRAIT_BUILD_HOST_TOOLS) Gem::AWSCore.Editor.Static ) - # This target is not a real gem module - # It is not meant to be loaded by the ModuleManager in C++ - ly_add_target( - NAME AWSCore.ResourceMappingTool MODULE - NAMESPACE Gem - OUTPUT_SUBDIRECTORY AWSCoreEditorQtBin - FILES_CMAKE - awscore_resourcemappingtool_files.cmake - INCLUDE_DIRECTORIES - PRIVATE - Include/Private - BUILD_DEPENDENCIES - PRIVATE - Gem::AWSCore.Editor.Static - RUNTIME_DEPENDENCIES - 3rdParty::pyside2 + if (PAL_TRAIT_ENABLE_RESOURCE_MAPPING_TOOL) - ) - ly_add_dependencies(AWSCore.Editor AWSCore.ResourceMappingTool) + # This target is not a real gem module + # It is not meant to be loaded by the ModuleManager in C++ + ly_add_target( + NAME AWSCore.ResourceMappingTool MODULE + NAMESPACE Gem + OUTPUT_SUBDIRECTORY AWSCoreEditorQtBin + FILES_CMAKE + awscore_resourcemappingtool_files.cmake + INCLUDE_DIRECTORIES + PRIVATE + Include/Private + BUILD_DEPENDENCIES + PRIVATE + Gem::AWSCore.Editor.Static + RUNTIME_DEPENDENCIES + 3rdParty::pyside2 + + ) + ly_add_dependencies(AWSCore.Editor AWSCore.ResourceMappingTool) + + ly_install_directory(DIRECTORIES Tools/ResourceMappingTool) + + endif() # Builders and Tools (such as the Editor use AWSCore.Editor) use the .Editor module above. ly_create_alias( @@ -192,4 +201,3 @@ if(PAL_TRAIT_BUILD_TESTS_SUPPORTED) endif() endif() -ly_install_directory(DIRECTORIES Tools/ResourceMappingTool) diff --git a/Gems/AWSCore/Code/Platform/Linux/PAL_traits_editor_linux.cmake b/Gems/AWSCore/Code/Platform/Linux/PAL_traits_editor_linux.cmake new file mode 100644 index 0000000000..deaaa60506 --- /dev/null +++ b/Gems/AWSCore/Code/Platform/Linux/PAL_traits_editor_linux.cmake @@ -0,0 +1,9 @@ +# +# Copyright (c) Contributors to the Open 3D Engine Project. +# For complete copyright and license terms please see the LICENSE at the root of this distribution. +# +# SPDX-License-Identifier: Apache-2.0 OR MIT +# +# + +set(PAL_TRAIT_ENABLE_RESOURCE_MAPPING_TOOL TRUE) diff --git a/Gems/AWSCore/Code/Platform/Mac/PAL_traits_editor_mac.cmake b/Gems/AWSCore/Code/Platform/Mac/PAL_traits_editor_mac.cmake new file mode 100644 index 0000000000..e953c95955 --- /dev/null +++ b/Gems/AWSCore/Code/Platform/Mac/PAL_traits_editor_mac.cmake @@ -0,0 +1,9 @@ +# +# Copyright (c) Contributors to the Open 3D Engine Project. +# For complete copyright and license terms please see the LICENSE at the root of this distribution. +# +# SPDX-License-Identifier: Apache-2.0 OR MIT +# +# + +set(PAL_TRAIT_ENABLE_RESOURCE_MAPPING_TOOL FALSE) diff --git a/Gems/AWSCore/Code/Platform/Windows/PAL_traits_editor_windows.cmake b/Gems/AWSCore/Code/Platform/Windows/PAL_traits_editor_windows.cmake new file mode 100644 index 0000000000..deaaa60506 --- /dev/null +++ b/Gems/AWSCore/Code/Platform/Windows/PAL_traits_editor_windows.cmake @@ -0,0 +1,9 @@ +# +# Copyright (c) Contributors to the Open 3D Engine Project. +# For complete copyright and license terms please see the LICENSE at the root of this distribution. +# +# SPDX-License-Identifier: Apache-2.0 OR MIT +# +# + +set(PAL_TRAIT_ENABLE_RESOURCE_MAPPING_TOOL TRUE) From e1b6054ff849d4376b98dc59ceaa838e3b33b056 Mon Sep 17 00:00:00 2001 From: AMZN-Phil Date: Fri, 19 Nov 2021 19:13:19 -0800 Subject: [PATCH 10/23] Fix Project Manager not finding CMake on Windows Signed-off-by: AMZN-Phil --- .../Platform/Windows/ProjectUtils_windows.cpp | 30 ++++++++++--------- .../Source/ProjectBuilderWorker.cpp | 5 +--- .../ProjectManager/Source/ProjectUtils.cpp | 4 --- .../ProjectManager/Source/ProjectUtils.h | 4 +-- 4 files changed, 18 insertions(+), 25 deletions(-) diff --git a/Code/Tools/ProjectManager/Platform/Windows/ProjectUtils_windows.cpp b/Code/Tools/ProjectManager/Platform/Windows/ProjectUtils_windows.cpp index d08da1d5e1..365aac7069 100644 --- a/Code/Tools/ProjectManager/Platform/Windows/ProjectUtils_windows.cpp +++ b/Code/Tools/ProjectManager/Platform/Windows/ProjectUtils_windows.cpp @@ -21,7 +21,7 @@ namespace O3DE::ProjectManager { namespace ProjectUtils { - AZ::Outcome GetCommandLineProcessEnvironment() + AZ::Outcome SetupCommandLineProcessEnvironment() { // Use the engine path to insert a path for cmake auto engineInfoResult = PythonBindingsInterface::Get()->GetEngineInfo(); @@ -31,26 +31,30 @@ namespace O3DE::ProjectManager } auto engineInfo = engineInfoResult.GetValue(); - QProcessEnvironment currentEnvironment(QProcessEnvironment::systemEnvironment()); - - // Append cmake path to PATH incase it is missing + // Append cmake path to the current environment PATH incase it is missing, since if + // we are starting CMake itself the current application needs to find it using Path + // This also takes affect for all child processes. QDir cmakePath(engineInfo.m_path); cmakePath.cd("cmake/runtime/bin"); - QString pathValue = currentEnvironment.value("PATH"); - pathValue += ";" + cmakePath.path(); - currentEnvironment.insert("PATH", pathValue); - return AZ::Success(currentEnvironment); + QString pathEnv = qEnvironmentVariable("Path"); + if (!pathEnv.contains(cmakePath.path())) + { + pathEnv += ";" + cmakePath.path(); + qputenv("Path", pathEnv.toStdString().c_str()); + } + + return AZ::Success(); } AZ::Outcome FindSupportedCompilerForPlatform() { // Validate that cmake is installed - auto cmakeProcessEnvResult = GetCommandLineProcessEnvironment(); + auto cmakeProcessEnvResult = SetupCommandLineProcessEnvironment(); if (!cmakeProcessEnvResult.IsSuccess()) { return AZ::Failure(cmakeProcessEnvResult.GetError()); } - auto cmakeVersionQueryResult = ExecuteCommandResult("cmake", QStringList{"--version"}, cmakeProcessEnvResult.GetValue()); + auto cmakeVersionQueryResult = ExecuteCommandResult("cmake", QStringList{"--version"}); if (!cmakeVersionQueryResult.IsSuccess()) { return AZ::Failure(QObject::tr("CMake not found. \n\n" @@ -104,7 +108,7 @@ namespace O3DE::ProjectManager AZ::Outcome OpenCMakeGUI(const QString& projectPath) { - AZ::Outcome processEnvResult = GetCommandLineProcessEnvironment(); + AZ::Outcome processEnvResult = SetupCommandLineProcessEnvironment(); if (!processEnvResult.IsSuccess()) { return AZ::Failure(processEnvResult.GetError()); @@ -118,7 +122,6 @@ namespace O3DE::ProjectManager } QProcess process; - process.setProcessEnvironment(processEnvResult.GetValue()); // if the project build path is relative, it should be relative to the project path process.setWorkingDirectory(projectPath); @@ -139,7 +142,6 @@ namespace O3DE::ProjectManager return ExecuteCommandResultModalDialog( "cmd.exe", QStringList{"/c", batPath}, - QProcessEnvironment::systemEnvironment(), QObject::tr("Running get_python script...")); } @@ -157,7 +159,7 @@ namespace O3DE::ProjectManager .arg(shortcutPath) .arg(targetPath) .arg(arguments.join(' ')); - auto createShortcutResult = ExecuteCommandResult(cmd, QStringList{"-Command", arg}, QProcessEnvironment::systemEnvironment()); + auto createShortcutResult = ExecuteCommandResult(cmd, QStringList{"-Command", arg}); if (!createShortcutResult.IsSuccess()) { return AZ::Failure(QObject::tr("Failed to create desktop shortcut %1

" diff --git a/Code/Tools/ProjectManager/Source/ProjectBuilderWorker.cpp b/Code/Tools/ProjectManager/Source/ProjectBuilderWorker.cpp index c6a6b20a1d..7ec691fd81 100644 --- a/Code/Tools/ProjectManager/Source/ProjectBuilderWorker.cpp +++ b/Code/Tools/ProjectManager/Source/ProjectBuilderWorker.cpp @@ -117,18 +117,16 @@ namespace O3DE::ProjectManager // Show some kind of progress with very approximate estimates UpdateProgress(++m_progressEstimate); - auto currentEnvironmentRequest = ProjectUtils::GetCommandLineProcessEnvironment(); + auto currentEnvironmentRequest = ProjectUtils::SetupCommandLineProcessEnvironment(); if (!currentEnvironmentRequest.IsSuccess()) { QStringToAZTracePrint(currentEnvironmentRequest.GetError()); return AZ::Failure(currentEnvironmentRequest.GetError()); } - QProcessEnvironment currentEnvironment = currentEnvironmentRequest.GetValue(); m_configProjectProcess = new QProcess(this); m_configProjectProcess->setProcessChannelMode(QProcess::MergedChannels); m_configProjectProcess->setWorkingDirectory(m_projectInfo.m_path); - m_configProjectProcess->setProcessEnvironment(currentEnvironment); auto cmakeGenerateArgumentsResult = ConstructCmakeGenerateProjectArguments(engineInfo.m_thirdPartyPath); if (!cmakeGenerateArgumentsResult.IsSuccess()) @@ -181,7 +179,6 @@ namespace O3DE::ProjectManager m_buildProjectProcess = new QProcess(this); m_buildProjectProcess->setProcessChannelMode(QProcess::MergedChannels); m_buildProjectProcess->setWorkingDirectory(m_projectInfo.m_path); - m_buildProjectProcess->setProcessEnvironment(currentEnvironment); auto cmakeBuildArgumentsResult = ConstructCmakeBuildCommandArguments(); if (!cmakeBuildArgumentsResult.IsSuccess()) diff --git a/Code/Tools/ProjectManager/Source/ProjectUtils.cpp b/Code/Tools/ProjectManager/Source/ProjectUtils.cpp index 4a0e1c153c..b7748d8aa2 100644 --- a/Code/Tools/ProjectManager/Source/ProjectUtils.cpp +++ b/Code/Tools/ProjectManager/Source/ProjectUtils.cpp @@ -520,12 +520,10 @@ namespace O3DE::ProjectManager AZ::Outcome ExecuteCommandResultModalDialog( const QString& cmd, const QStringList& arguments, - const QProcessEnvironment& processEnv, const QString& title) { QString resultOutput; QProcess execProcess; - execProcess.setProcessEnvironment(processEnv); execProcess.setProcessChannelMode(QProcess::MergedChannels); QProgressDialog dialog(title, QObject::tr("Cancel"), /*minimum=*/0, /*maximum=*/0); @@ -611,11 +609,9 @@ namespace O3DE::ProjectManager AZ::Outcome ExecuteCommandResult( const QString& cmd, const QStringList& arguments, - const QProcessEnvironment& processEnv, int commandTimeoutSeconds /*= ProjectCommandLineTimeoutSeconds*/) { QProcess execProcess; - execProcess.setProcessEnvironment(processEnv); execProcess.setProcessChannelMode(QProcess::MergedChannels); execProcess.start(cmd, arguments); if (!execProcess.waitForStarted()) diff --git a/Code/Tools/ProjectManager/Source/ProjectUtils.h b/Code/Tools/ProjectManager/Source/ProjectUtils.h index ee605b5117..d84b367d5b 100644 --- a/Code/Tools/ProjectManager/Source/ProjectUtils.h +++ b/Code/Tools/ProjectManager/Source/ProjectUtils.h @@ -47,7 +47,6 @@ namespace O3DE::ProjectManager AZ::Outcome ExecuteCommandResult( const QString& cmd, const QStringList& arguments, - const QProcessEnvironment& processEnv, int commandTimeoutSeconds = ProjectCommandLineTimeoutSeconds); /** @@ -61,10 +60,9 @@ namespace O3DE::ProjectManager AZ::Outcome ExecuteCommandResultModalDialog( const QString& cmd, const QStringList& arguments, - const QProcessEnvironment& processEnv, const QString& title); - AZ::Outcome GetCommandLineProcessEnvironment(); + AZ::Outcome SetupCommandLineProcessEnvironment(); AZ::Outcome GetProjectBuildPath(const QString& projectPath); AZ::Outcome OpenCMakeGUI(const QString& projectPath); AZ::Outcome RunGetPythonScript(const QString& enginePath); From 74e1ee1862aec8485245fd94870c842327ffbbaa Mon Sep 17 00:00:00 2001 From: AMZN-Phil Date: Sat, 20 Nov 2021 10:23:50 -0800 Subject: [PATCH 11/23] Fix non-Windows platforms Signed-off-by: AMZN-Phil --- .../Platform/Linux/ProjectUtils_linux.cpp | 5 ++--- .../Platform/Mac/ProjectUtils_mac.cpp | 15 +++++++++------ 2 files changed, 11 insertions(+), 9 deletions(-) diff --git a/Code/Tools/ProjectManager/Platform/Linux/ProjectUtils_linux.cpp b/Code/Tools/ProjectManager/Platform/Linux/ProjectUtils_linux.cpp index a7bd2dae08..f9a1906b8a 100644 --- a/Code/Tools/ProjectManager/Platform/Linux/ProjectUtils_linux.cpp +++ b/Code/Tools/ProjectManager/Platform/Linux/ProjectUtils_linux.cpp @@ -19,10 +19,9 @@ namespace O3DE::ProjectManager // The list of clang C/C++ compiler command lines to validate on the host Linux system const QStringList SupportedClangVersions = {"13", "12", "11", "10", "9", "8", "7", "6.0"}; - AZ::Outcome GetCommandLineProcessEnvironment() + AZ::Outcome SetupCommandLineProcessEnvironment() { - QProcessEnvironment currentEnvironment(QProcessEnvironment::systemEnvironment()); - return AZ::Success(currentEnvironment); + return AZ::Success(); } AZ::Outcome FindSupportedCompilerForPlatform() diff --git a/Code/Tools/ProjectManager/Platform/Mac/ProjectUtils_mac.cpp b/Code/Tools/ProjectManager/Platform/Mac/ProjectUtils_mac.cpp index 62011bf04b..24a8fc1ff8 100644 --- a/Code/Tools/ProjectManager/Platform/Mac/ProjectUtils_mac.cpp +++ b/Code/Tools/ProjectManager/Platform/Mac/ProjectUtils_mac.cpp @@ -18,17 +18,20 @@ namespace O3DE::ProjectManager { namespace ProjectUtils { - AZ::Outcome GetCommandLineProcessEnvironment() + AZ::Outcome GetCommandLineProcessEnvironment() { // For CMake on Mac, if its installed through home-brew, then it will be installed // under /usr/local/bin, which may not be in the system PATH environment. // Add that path for the command line process so that it will be able to locate // a home-brew installed version of CMake - QProcessEnvironment currentEnvironment(QProcessEnvironment::systemEnvironment()); - QString pathValue = currentEnvironment.value("PATH"); - pathValue += ":/usr/local/bin"; - currentEnvironment.insert("PATH", pathValue); - return AZ::Success(currentEnvironment); + QString pathEnv = qEnvironmentVariable("PATH"); + if (!pathEnv.contains("/usr/local/bin")) + { + pathEnv += ":/usr/local/bin"; + qputenv("PATH", pathEnv.toStdString().c_str()); + } + + return AZ::Success(); } AZ::Outcome FindSupportedCompilerForPlatform() From def5b3a65d9863cb981197b2bcc2c34d5e478b76 Mon Sep 17 00:00:00 2001 From: AMZN-Phil Date: Sat, 20 Nov 2021 10:37:55 -0800 Subject: [PATCH 12/23] Fix additional left over references to QProcessEnvironment Signed-off-by: AMZN-Phil --- .../Linux/ProjectBuilderWorker_linux.cpp | 4 ++-- .../Platform/Linux/ProjectUtils_linux.cpp | 10 ++++------ .../Platform/Mac/ProjectBuilderWorker_mac.cpp | 6 ++---- .../Platform/Mac/ProjectUtils_mac.cpp | 18 +++++++++--------- 4 files changed, 17 insertions(+), 21 deletions(-) diff --git a/Code/Tools/ProjectManager/Platform/Linux/ProjectBuilderWorker_linux.cpp b/Code/Tools/ProjectManager/Platform/Linux/ProjectBuilderWorker_linux.cpp index fdeaef93bb..5cade609d7 100644 --- a/Code/Tools/ProjectManager/Platform/Linux/ProjectBuilderWorker_linux.cpp +++ b/Code/Tools/ProjectManager/Platform/Linux/ProjectBuilderWorker_linux.cpp @@ -19,7 +19,7 @@ namespace O3DE::ProjectManager { // Attempt to use the Ninja build system if it is installed (described in the o3de documentation) if possible, // otherwise default to the the default for Linux (Unix Makefiles) - auto whichNinjaResult = ProjectUtils::ExecuteCommandResult("which", QStringList{"ninja"}, QProcessEnvironment::systemEnvironment()); + auto whichNinjaResult = ProjectUtils::ExecuteCommandResult("which", QStringList{"ninja"}); QString cmakeGenerator = (whichNinjaResult.IsSuccess()) ? "Ninja Multi-Config" : "Unix Makefiles"; bool compileProfileOnBuild = (whichNinjaResult.IsSuccess()); @@ -38,7 +38,7 @@ namespace O3DE::ProjectManager AZ::Outcome ProjectBuilderWorker::ConstructCmakeBuildCommandArguments() const { - auto whichNinjaResult = ProjectUtils::ExecuteCommandResult("which", QStringList{"ninja"}, QProcessEnvironment::systemEnvironment()); + auto whichNinjaResult = ProjectUtils::ExecuteCommandResult("which", QStringList{"ninja"}); bool compileProfileOnBuild = (whichNinjaResult.IsSuccess()); QString targetBuildPath = QDir(m_projectInfo.m_path).filePath(ProjectBuildPathPostfix); QString launcherTargetName = m_projectInfo.m_projectName + ".GameLauncher"; diff --git a/Code/Tools/ProjectManager/Platform/Linux/ProjectUtils_linux.cpp b/Code/Tools/ProjectManager/Platform/Linux/ProjectUtils_linux.cpp index f9a1906b8a..cb8ea843e5 100644 --- a/Code/Tools/ProjectManager/Platform/Linux/ProjectUtils_linux.cpp +++ b/Code/Tools/ProjectManager/Platform/Linux/ProjectUtils_linux.cpp @@ -27,7 +27,7 @@ namespace O3DE::ProjectManager AZ::Outcome FindSupportedCompilerForPlatform() { // Validate that cmake is installed and is in the command line - auto whichCMakeResult = ProjectUtils::ExecuteCommandResult("which", QStringList{ProjectCMakeCommand}, QProcessEnvironment::systemEnvironment()); + auto whichCMakeResult = ProjectUtils::ExecuteCommandResult("which", QStringList{ProjectCMakeCommand}); if (!whichCMakeResult.IsSuccess()) { return AZ::Failure(QObject::tr("CMake not found.

" @@ -38,8 +38,8 @@ namespace O3DE::ProjectManager // Look for the first compatible version of clang. The list below will contain the known clang compilers that have been tested for O3DE. for (const QString& supportClangVersion : SupportedClangVersions) { - auto whichClangResult = ProjectUtils::ExecuteCommandResult("which", QStringList{QString("clang-%1").arg(supportClangVersion)}, QProcessEnvironment::systemEnvironment()); - auto whichClangPPResult = ProjectUtils::ExecuteCommandResult("which", QStringList{QString("clang++-%1").arg(supportClangVersion)}, QProcessEnvironment::systemEnvironment()); + auto whichClangResult = ProjectUtils::ExecuteCommandResult("which", QStringList{QString("clang-%1").arg(supportClangVersion)}); + auto whichClangPPResult = ProjectUtils::ExecuteCommandResult("which", QStringList{QString("clang++-%1").arg(supportClangVersion)}); if (whichClangResult.IsSuccess() && whichClangPPResult.IsSuccess()) { return AZ::Success(QString("clang-%1").arg(supportClangVersion)); @@ -53,7 +53,7 @@ namespace O3DE::ProjectManager AZ::Outcome OpenCMakeGUI(const QString& projectPath) { - AZ::Outcome processEnvResult = GetCommandLineProcessEnvironment(); + AZ::Outcome processEnvResult = SetupCommandLineProcessEnvironment(); if (!processEnvResult.IsSuccess()) { return AZ::Failure(processEnvResult.GetError()); @@ -67,7 +67,6 @@ namespace O3DE::ProjectManager } QProcess process; - process.setProcessEnvironment(processEnvResult.GetValue()); // if the project build path is relative, it should be relative to the project path process.setWorkingDirectory(projectPath); @@ -87,7 +86,6 @@ namespace O3DE::ProjectManager return ExecuteCommandResultModalDialog( QString("%1/python/get_python.sh").arg(engineRoot), {}, - QProcessEnvironment::systemEnvironment(), QObject::tr("Running get_python script...")); } diff --git a/Code/Tools/ProjectManager/Platform/Mac/ProjectBuilderWorker_mac.cpp b/Code/Tools/ProjectManager/Platform/Mac/ProjectBuilderWorker_mac.cpp index ab412d84d8..2a8bbf4839 100644 --- a/Code/Tools/ProjectManager/Platform/Mac/ProjectBuilderWorker_mac.cpp +++ b/Code/Tools/ProjectManager/Platform/Mac/ProjectBuilderWorker_mac.cpp @@ -19,16 +19,14 @@ namespace O3DE::ProjectManager { AZ::Outcome QueryInstalledCmakeFullPath() { - auto environmentRequest = ProjectUtils::GetCommandLineProcessEnvironment(); + auto environmentRequest = ProjectUtils::SetupCommandLineProcessEnvironment(); if (!environmentRequest.IsSuccess()) { return AZ::Failure(environmentRequest.GetError()); } - auto currentEnvironment = environmentRequest.GetValue(); auto queryCmakeInstalled = ProjectUtils::ExecuteCommandResult("which", - QStringList{ProjectCMakeCommand}, - currentEnvironment); + QStringList{ProjectCMakeCommand}); if (!queryCmakeInstalled.IsSuccess()) { return AZ::Failure(QObject::tr("Unable to detect CMake on this host.")); diff --git a/Code/Tools/ProjectManager/Platform/Mac/ProjectUtils_mac.cpp b/Code/Tools/ProjectManager/Platform/Mac/ProjectUtils_mac.cpp index 24a8fc1ff8..430e8974b7 100644 --- a/Code/Tools/ProjectManager/Platform/Mac/ProjectUtils_mac.cpp +++ b/Code/Tools/ProjectManager/Platform/Mac/ProjectUtils_mac.cpp @@ -18,7 +18,7 @@ namespace O3DE::ProjectManager { namespace ProjectUtils { - AZ::Outcome GetCommandLineProcessEnvironment() + AZ::Outcome SetupCommandLineProcessEnvironment() { // For CMake on Mac, if its installed through home-brew, then it will be installed // under /usr/local/bin, which may not be in the system PATH environment. @@ -36,13 +36,14 @@ namespace O3DE::ProjectManager AZ::Outcome FindSupportedCompilerForPlatform() { - QProcessEnvironment currentEnvironment(QProcessEnvironment::systemEnvironment()); - QString pathValue = currentEnvironment.value("PATH"); - pathValue += ":/usr/local/bin"; - currentEnvironment.insert("PATH", pathValue); + AZ::Outcome processEnvResult = SetupCommandLineProcessEnvironment(); + if (!processEnvResult.IsSuccess()) + { + return AZ::Failure(processEnvResult.GetError()); + } // Validate that we have cmake installed first - auto queryCmakeInstalled = ExecuteCommandResult("which", QStringList{ProjectCMakeCommand}, currentEnvironment); + auto queryCmakeInstalled = ExecuteCommandResult("which", QStringList{ProjectCMakeCommand}); if (!queryCmakeInstalled.IsSuccess()) { return AZ::Failure(QObject::tr("Unable to detect CMake on this host.")); @@ -50,7 +51,7 @@ namespace O3DE::ProjectManager QString cmakeInstalledPath = queryCmakeInstalled.GetValue().split("\n")[0]; // Query the version of the installed cmake - auto queryCmakeVersionQuery = ExecuteCommandResult(cmakeInstalledPath, QStringList{"-version"}, currentEnvironment); + auto queryCmakeVersionQuery = ExecuteCommandResult(cmakeInstalledPath, QStringList{"-version"}); if (!queryCmakeVersionQuery.IsSuccess()) { return AZ::Failure(QObject::tr("Unable to determine the version of CMake on this host.")); @@ -58,7 +59,7 @@ namespace O3DE::ProjectManager AZ_TracePrintf("Project Manager", "Cmake version %s detected.", queryCmakeVersionQuery.GetValue().split("\n")[0].toUtf8().constData()); // Query for the version of xcodebuild (if installed) - auto queryXcodeBuildVersion = ExecuteCommandResult("xcodebuild", QStringList{"-version"}, currentEnvironment); + auto queryXcodeBuildVersion = ExecuteCommandResult("xcodebuild", QStringList{"-version"}); if (!queryCmakeInstalled.IsSuccess()) { return AZ::Failure(QObject::tr("Unable to detect XCodeBuilder on this host.")); @@ -107,7 +108,6 @@ namespace O3DE::ProjectManager return ExecuteCommandResultModalDialog( QString("%1/python/get_python.sh").arg(engineRoot), {}, - QProcessEnvironment::systemEnvironment(), QObject::tr("Running get_python script...")); } From c2145a63877e0606e0dd534b8fd4da01cdc00256 Mon Sep 17 00:00:00 2001 From: AMZN-Phil Date: Mon, 22 Nov 2021 08:31:12 -0800 Subject: [PATCH 13/23] Use QStringList to avoid false matches against a partial path Signed-off-by: AMZN-Phil --- Code/Tools/ProjectManager/Platform/Mac/ProjectUtils_mac.cpp | 3 ++- .../ProjectManager/Platform/Windows/ProjectUtils_windows.cpp | 3 ++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/Code/Tools/ProjectManager/Platform/Mac/ProjectUtils_mac.cpp b/Code/Tools/ProjectManager/Platform/Mac/ProjectUtils_mac.cpp index 430e8974b7..0c232d44d1 100644 --- a/Code/Tools/ProjectManager/Platform/Mac/ProjectUtils_mac.cpp +++ b/Code/Tools/ProjectManager/Platform/Mac/ProjectUtils_mac.cpp @@ -25,7 +25,8 @@ namespace O3DE::ProjectManager // Add that path for the command line process so that it will be able to locate // a home-brew installed version of CMake QString pathEnv = qEnvironmentVariable("PATH"); - if (!pathEnv.contains("/usr/local/bin")) + QStringList pathEnvList = pathEnv.split(":"); + if (!pathEnvList.contains("/usr/local/bin")) { pathEnv += ":/usr/local/bin"; qputenv("PATH", pathEnv.toStdString().c_str()); diff --git a/Code/Tools/ProjectManager/Platform/Windows/ProjectUtils_windows.cpp b/Code/Tools/ProjectManager/Platform/Windows/ProjectUtils_windows.cpp index 365aac7069..92863b955c 100644 --- a/Code/Tools/ProjectManager/Platform/Windows/ProjectUtils_windows.cpp +++ b/Code/Tools/ProjectManager/Platform/Windows/ProjectUtils_windows.cpp @@ -37,7 +37,8 @@ namespace O3DE::ProjectManager QDir cmakePath(engineInfo.m_path); cmakePath.cd("cmake/runtime/bin"); QString pathEnv = qEnvironmentVariable("Path"); - if (!pathEnv.contains(cmakePath.path())) + QStringList pathEnvList = pathEnv.split(";"); + if (!pathEnvList.contains(cmakePath.path())) { pathEnv += ";" + cmakePath.path(); qputenv("Path", pathEnv.toStdString().c_str()); From b3c0200345eb56d7a35b8a75deb12b479b0a839a Mon Sep 17 00:00:00 2001 From: Steve Pham <82231385+spham-amzn@users.noreply.github.com> Date: Mon, 22 Nov 2021 08:58:24 -0800 Subject: [PATCH 14/23] Restore missing variable 'target_filename_ext' needed to determine if RPATH fix is necessary or not (#5824) Signed-off-by: Steve Pham <82231385+spham-amzn@users.noreply.github.com> --- cmake/Platform/Linux/runtime_dependencies_linux.cmake.in | 1 + 1 file changed, 1 insertion(+) diff --git a/cmake/Platform/Linux/runtime_dependencies_linux.cmake.in b/cmake/Platform/Linux/runtime_dependencies_linux.cmake.in index 4ccf123e27..16445ef8d9 100644 --- a/cmake/Platform/Linux/runtime_dependencies_linux.cmake.in +++ b/cmake/Platform/Linux/runtime_dependencies_linux.cmake.in @@ -10,6 +10,7 @@ cmake_policy(SET CMP0012 NEW) # new policy for the if that evaluates a boolean o function(ly_copy source_file target_directory) cmake_path(GET source_file FILENAME target_filename) + cmake_PATH(GET source_file EXTENSION target_filename_ext) cmake_path(APPEND target_file "${target_directory}" "${target_filename}") cmake_path(COMPARE "${source_file}" EQUAL "${target_file}" same_location) if(NOT ${same_location}) From d958502f2c5c2cfa52b11dcf6478a875c14ccb1f Mon Sep 17 00:00:00 2001 From: AMZN-Phil Date: Mon, 22 Nov 2021 09:26:34 -0800 Subject: [PATCH 15/23] Check return value of qputenv Signed-off-by: AMZN-Phil --- Code/Tools/ProjectManager/Platform/Mac/ProjectUtils_mac.cpp | 5 ++++- .../ProjectManager/Platform/Windows/ProjectUtils_windows.cpp | 5 ++++- 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/Code/Tools/ProjectManager/Platform/Mac/ProjectUtils_mac.cpp b/Code/Tools/ProjectManager/Platform/Mac/ProjectUtils_mac.cpp index 0c232d44d1..07b08924f1 100644 --- a/Code/Tools/ProjectManager/Platform/Mac/ProjectUtils_mac.cpp +++ b/Code/Tools/ProjectManager/Platform/Mac/ProjectUtils_mac.cpp @@ -29,7 +29,10 @@ namespace O3DE::ProjectManager if (!pathEnvList.contains("/usr/local/bin")) { pathEnv += ":/usr/local/bin"; - qputenv("PATH", pathEnv.toStdString().c_str()); + if (!qputenv("PATH", pathEnv.toStdString().c_str())) + { + return AZ::Failure(QObject::tr("Failed to set PATH environment variable")); + } } return AZ::Success(); diff --git a/Code/Tools/ProjectManager/Platform/Windows/ProjectUtils_windows.cpp b/Code/Tools/ProjectManager/Platform/Windows/ProjectUtils_windows.cpp index 92863b955c..b8cfe65b1e 100644 --- a/Code/Tools/ProjectManager/Platform/Windows/ProjectUtils_windows.cpp +++ b/Code/Tools/ProjectManager/Platform/Windows/ProjectUtils_windows.cpp @@ -41,7 +41,10 @@ namespace O3DE::ProjectManager if (!pathEnvList.contains(cmakePath.path())) { pathEnv += ";" + cmakePath.path(); - qputenv("Path", pathEnv.toStdString().c_str()); + if (!qputenv("Path", pathEnv.toStdString().c_str())) + { + return AZ::Failure(QObject::tr("Failed to set Path environment variable")); + } } return AZ::Success(); From 1f2385ca1adb422380b52252925f6eb397a2172d Mon Sep 17 00:00:00 2001 From: Mike Balfour <82224783+mbalfour-amzn@users.noreply.github.com> Date: Mon, 22 Nov 2021 15:35:37 -0600 Subject: [PATCH 16/23] Added missing doc links. (#5841) Signed-off-by: Mike Balfour <82224783+mbalfour-amzn@users.noreply.github.com> --- .../EditorComponents/EditorTerrainHeightGradientListComponent.h | 2 +- .../EditorComponents/EditorTerrainLayerSpawnerComponent.h | 2 +- .../EditorTerrainSurfaceGradientListComponent.h | 2 +- .../EditorTerrainSurfaceMaterialsListComponent.h | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/Gems/Terrain/Code/Source/EditorComponents/EditorTerrainHeightGradientListComponent.h b/Gems/Terrain/Code/Source/EditorComponents/EditorTerrainHeightGradientListComponent.h index 2433eda009..623d58f1bc 100644 --- a/Gems/Terrain/Code/Source/EditorComponents/EditorTerrainHeightGradientListComponent.h +++ b/Gems/Terrain/Code/Source/EditorComponents/EditorTerrainHeightGradientListComponent.h @@ -27,6 +27,6 @@ namespace Terrain static constexpr const char* const s_componentDescription = "Provides height data for a region to the terrain system"; static constexpr const char* const s_icon = "Editor/Icons/Components/TerrainHeight.svg"; static constexpr const char* const s_viewportIcon = "Editor/Icons/Components/Viewport/TerrainHeight.svg"; - static constexpr const char* const s_helpUrl = ""; + static constexpr const char* const s_helpUrl = "https://o3de.org/docs/user-guide/components/reference/terrain/height_gradient_list/"; }; } diff --git a/Gems/Terrain/Code/Source/EditorComponents/EditorTerrainLayerSpawnerComponent.h b/Gems/Terrain/Code/Source/EditorComponents/EditorTerrainLayerSpawnerComponent.h index 1eb3413d52..4018e0d377 100644 --- a/Gems/Terrain/Code/Source/EditorComponents/EditorTerrainLayerSpawnerComponent.h +++ b/Gems/Terrain/Code/Source/EditorComponents/EditorTerrainLayerSpawnerComponent.h @@ -27,6 +27,6 @@ namespace Terrain static constexpr const char* const s_componentDescription = "Defines a terrain region for use by the terrain system"; static constexpr const char* const s_icon = "Editor/Icons/Components/TerrainLayerSpawner.svg"; static constexpr const char* const s_viewportIcon = "Editor/Icons/Components/Viewport/TerrainLayerSpawner.svg"; - static constexpr const char* const s_helpUrl = ""; + static constexpr const char* const s_helpUrl = "https://o3de.org/docs/user-guide/components/reference/terrain/layer_spawner/"; }; } diff --git a/Gems/Terrain/Code/Source/EditorComponents/EditorTerrainSurfaceGradientListComponent.h b/Gems/Terrain/Code/Source/EditorComponents/EditorTerrainSurfaceGradientListComponent.h index 3cf9e7fc47..58cb776823 100644 --- a/Gems/Terrain/Code/Source/EditorComponents/EditorTerrainSurfaceGradientListComponent.h +++ b/Gems/Terrain/Code/Source/EditorComponents/EditorTerrainSurfaceGradientListComponent.h @@ -27,6 +27,6 @@ namespace Terrain static constexpr const char* const s_componentDescription = "Provides a mapping between gradients and surface tags for use by the terrain system."; static constexpr const char* const s_icon = "Editor/Icons/Components/TerrainSurfaceGradientList.svg"; static constexpr const char* const s_viewportIcon = "Editor/Icons/Components/Viewport/TerrainSurfaceGradientList.svg"; - static constexpr const char* const s_helpUrl = ""; + static constexpr const char* const s_helpUrl = "https://o3de.org/docs/user-guide/components/reference/terrain/surface-gradient-list/"; }; } diff --git a/Gems/Terrain/Code/Source/TerrainRenderer/EditorComponents/EditorTerrainSurfaceMaterialsListComponent.h b/Gems/Terrain/Code/Source/TerrainRenderer/EditorComponents/EditorTerrainSurfaceMaterialsListComponent.h index 7fe8c82522..973e85a6d2 100644 --- a/Gems/Terrain/Code/Source/TerrainRenderer/EditorComponents/EditorTerrainSurfaceMaterialsListComponent.h +++ b/Gems/Terrain/Code/Source/TerrainRenderer/EditorComponents/EditorTerrainSurfaceMaterialsListComponent.h @@ -27,6 +27,6 @@ namespace Terrain static constexpr const char* const s_componentDescription = "Provides a mapping between surface tags and render materials."; static constexpr const char* const s_icon = "Editor/Icons/Components/TerrainSurfaceMaterials.svg"; static constexpr const char* const s_viewportIcon = "Editor/Icons/Components/Viewport/TerrainSurfaceMaterials.svg"; - static constexpr const char* const s_helpUrl = ""; + static constexpr const char* const s_helpUrl = "https://o3de.org/docs/user-guide/components/reference/terrain/surface-material-list/"; }; } From ba329378677590cdad0019c476cccccb5dec102f Mon Sep 17 00:00:00 2001 From: Steve Pham <82231385+spham-amzn@users.noreply.github.com> Date: Mon, 22 Nov 2021 15:32:54 -0800 Subject: [PATCH 17/23] Cherry pick release unused warning error into Stabilization/2110 (#5845) * Fixed unused variable warning in Release configuration in Linux. (#5830) Signed-off-by: moraaar * Fix unused variable errors (#5843) Signed-off-by: Steve Pham <82231385+spham-amzn@users.noreply.github.com> Co-authored-by: moraaar --- .../Linux/AzToolsFramework/API/PythonLoader_Linux.cpp | 6 +++--- .../Code/Source/BuilderSettings/BuilderSettingManager.cpp | 2 +- .../Code/Source/Platform/Linux/InitializeEmbeddedPyside2.h | 2 +- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/Code/Framework/AzToolsFramework/Platform/Linux/AzToolsFramework/API/PythonLoader_Linux.cpp b/Code/Framework/AzToolsFramework/Platform/Linux/AzToolsFramework/API/PythonLoader_Linux.cpp index 76fa36a048..351cf69c15 100644 --- a/Code/Framework/AzToolsFramework/Platform/Linux/AzToolsFramework/API/PythonLoader_Linux.cpp +++ b/Code/Framework/AzToolsFramework/Platform/Linux/AzToolsFramework/API/PythonLoader_Linux.cpp @@ -15,10 +15,10 @@ namespace AzToolsFramework::EmbeddedPython PythonLoader::PythonLoader() { constexpr char libPythonName[] = "libpython3.7m.so.1.0"; - if (m_embeddedLibPythonHandle = dlopen(libPythonName, RTLD_NOW | RTLD_GLOBAL); - m_embeddedLibPythonHandle == nullptr) + m_embeddedLibPythonHandle = dlopen(libPythonName, RTLD_NOW | RTLD_GLOBAL); + if (m_embeddedLibPythonHandle == nullptr) { - char* err = dlerror(); + [[maybe_unused]] const char* err = dlerror(); AZ_Error("PythonLoader", false, "Failed to load %s with error: %s\n", libPythonName, err ? err : "Unknown Error"); } } diff --git a/Gems/Atom/Asset/ImageProcessingAtom/Code/Source/BuilderSettings/BuilderSettingManager.cpp b/Gems/Atom/Asset/ImageProcessingAtom/Code/Source/BuilderSettings/BuilderSettingManager.cpp index 487c659ade..1ae406c6fd 100644 --- a/Gems/Atom/Asset/ImageProcessingAtom/Code/Source/BuilderSettings/BuilderSettingManager.cpp +++ b/Gems/Atom/Asset/ImageProcessingAtom/Code/Source/BuilderSettings/BuilderSettingManager.cpp @@ -52,7 +52,7 @@ namespace ImageProcessingAtom namespace { - static constexpr const char* const LogWindow = "Image Processing"; + [[maybe_unused]] static constexpr const char* const LogWindow = "Image Processing"; } #if defined(AZ_TOOLS_EXPAND_FOR_RESTRICTED_PLATFORMS) diff --git a/Gems/QtForPython/Code/Source/Platform/Linux/InitializeEmbeddedPyside2.h b/Gems/QtForPython/Code/Source/Platform/Linux/InitializeEmbeddedPyside2.h index f27b54810f..094a4f8548 100644 --- a/Gems/QtForPython/Code/Source/Platform/Linux/InitializeEmbeddedPyside2.h +++ b/Gems/QtForPython/Code/Source/Platform/Linux/InitializeEmbeddedPyside2.h @@ -38,7 +38,7 @@ namespace QtForPython void* moduleHandle = dlopen(moduleToLoad, RTLD_NOW | RTLD_GLOBAL); if (!moduleHandle) { - const char* loadError = dlerror(); + [[maybe_unused]] const char* loadError = dlerror(); AZ_Error("QtForPython", false, "Unable to load python library %s for Pyside2: %s", moduleToLoad, loadError ? loadError : "Unknown Error"); } From 81bf27c4e063caef087a9da8efb2e3c026dd1b87 Mon Sep 17 00:00:00 2001 From: carlitosan <82187351+carlitosan@users.noreply.github.com> Date: Mon, 22 Nov 2021 16:57:21 -0800 Subject: [PATCH 18/23] remove scripteventreference deprecated code Signed-off-by: carlitosan <82187351+carlitosan@users.noreply.github.com> --- .../ScriptEventReferencesComponent.cpp | 92 ------------------- .../ScriptEventReferencesComponent.h | 44 --------- .../Source/Editor/ScriptEventsEditorGem.cpp | 2 - .../Code/Source/ScriptEventsGem.cpp | 5 +- .../Code/scriptevents_common_files.cmake | 2 - 5 files changed, 1 insertion(+), 144 deletions(-) delete mode 100644 Gems/ScriptEvents/Code/Include/ScriptEvents/Components/ScriptEventReferencesComponent.cpp delete mode 100644 Gems/ScriptEvents/Code/Include/ScriptEvents/Components/ScriptEventReferencesComponent.h diff --git a/Gems/ScriptEvents/Code/Include/ScriptEvents/Components/ScriptEventReferencesComponent.cpp b/Gems/ScriptEvents/Code/Include/ScriptEvents/Components/ScriptEventReferencesComponent.cpp deleted file mode 100644 index 696d2af4d2..0000000000 --- a/Gems/ScriptEvents/Code/Include/ScriptEvents/Components/ScriptEventReferencesComponent.cpp +++ /dev/null @@ -1,92 +0,0 @@ -/* - * Copyright (c) Contributors to the Open 3D Engine Project. - * For complete copyright and license terms please see the LICENSE at the root of this distribution. - * - * SPDX-License-Identifier: Apache-2.0 OR MIT - * - */ - -#include "ScriptEventReferencesComponent.h" - -namespace ScriptEvents -{ - namespace Components - { - void ScriptEventReferencesComponent::Reflect(AZ::ReflectContext* context) - { - if (AZ::SerializeContext* serializeContext = azrtti_cast(context)) - { - // The Script Event References component is no longer necessary, as all Script Event assets - // will be properly loaded as needed. - serializeContext->ClassDeprecate("ScriptEventReferencesComponent", "{D0F440AC-32D4-49EC-8B93-860B188266A6}"); - } - } - - void ScriptEventReferencesComponent::Activate() - { - for (auto& scriptEventReferences : m_scriptEventAssets) - { - const auto& asset = scriptEventReferences.GetAsset(); - if (asset) - { - if (!AZ::Data::AssetBus::MultiHandler::BusIsConnectedId(asset.GetId())) - { - AZ::Data::AssetBus::MultiHandler::BusConnect(asset.GetId()); - } - - // Load the asset if it's not ready - if (!asset.IsReady()) - { - AZ::Data::AssetInfo assetInfo; - AZ::Data::AssetCatalogRequestBus::BroadcastResult(assetInfo, &AZ::Data::AssetCatalogRequests::GetAssetInfoById, asset.GetId()); - if (assetInfo.m_assetId.IsValid()) - { - AZ::Data::AssetManager::Instance().GetAsset(asset.GetId(), azrtti_typeid(), AZ::Data::AssetLoadBehavior::Default) - .BlockUntilLoadComplete(); - } - } - } - else - { - AZ_Warning("Script Events", false, "ScriptEventReferencesComponent could not find Script Event asset: %s", scriptEventReferences.GetDefinition() ? scriptEventReferences.GetDefinition()->GetName().c_str() : scriptEventReferences.GetAsset().GetId().ToString().c_str()); - } - } - } - - void ScriptEventReferencesComponent::Deactivate() - { - for (auto& scriptEventReferences : m_scriptEventAssets) - { - const auto& asset = scriptEventReferences.GetAsset(); - if (asset) - { - AZ::Data::AssetBus::MultiHandler::BusDisconnect(asset.GetId()); - } - } - } - - void ScriptEventReferencesComponent::GetProvidedServices(AZ::ComponentDescriptor::DependencyArrayType& provided) - { - provided.push_back(AZ_CRC("ScriptEventReference", 0x3df92d40)); - } - - void ScriptEventReferencesComponent::GetIncompatibleServices(AZ::ComponentDescriptor::DependencyArrayType& incompatible) - { - incompatible.push_back(AZ_CRC("ScriptEventReference", 0x3df92d40)); - } - - void ScriptEventReferencesComponent::GetDependentServices(AZ::ComponentDescriptor::DependencyArrayType& dependent) - { - dependent.push_back(AZ_CRC("LuaScriptService", 0x21d76c4b)); - } - - void ScriptEventReferencesComponent::OnAssetReady(AZ::Data::Asset asset) - { - if (ScriptEventsAsset* scriptEventAsset = asset.GetAs()) - { - scriptEventAsset->m_definition.RegisterInternal(); - } - } - - } -} diff --git a/Gems/ScriptEvents/Code/Include/ScriptEvents/Components/ScriptEventReferencesComponent.h b/Gems/ScriptEvents/Code/Include/ScriptEvents/Components/ScriptEventReferencesComponent.h deleted file mode 100644 index 562cab9b52..0000000000 --- a/Gems/ScriptEvents/Code/Include/ScriptEvents/Components/ScriptEventReferencesComponent.h +++ /dev/null @@ -1,44 +0,0 @@ -/* - * Copyright (c) Contributors to the Open 3D Engine Project. - * For complete copyright and license terms please see the LICENSE at the root of this distribution. - * - * SPDX-License-Identifier: Apache-2.0 OR MIT - * - */ - -#pragma once - -#include -#include - -namespace ScriptEvents -{ - namespace Components - { - class ScriptEventReferencesComponent - : public AZ::Component - , private AZ::Data::AssetBus::MultiHandler - - { - public: - - AZ_COMPONENT(ScriptEventReferencesComponent, "{D0F440AC-32D4-49EC-8B93-860B188266A6}", AZ::Component); - - ////////////////////////////////////////////////////////////////////////// - // AZ::Component - void Init() override {} - void Activate() override; - void Deactivate() override; - ////////////////////////////////////////////////////////////////////////// - - static void GetProvidedServices(AZ::ComponentDescriptor::DependencyArrayType& provided); - static void GetIncompatibleServices(AZ::ComponentDescriptor::DependencyArrayType& incompatible); - static void GetDependentServices(AZ::ComponentDescriptor::DependencyArrayType& dependent); - - void OnAssetReady(AZ::Data::Asset asset) override; - static void Reflect(AZ::ReflectContext* reflection); - - AZStd::vector m_scriptEventAssets; - }; - } -} diff --git a/Gems/ScriptEvents/Code/Source/Editor/ScriptEventsEditorGem.cpp b/Gems/ScriptEvents/Code/Source/Editor/ScriptEventsEditorGem.cpp index 8ab014ec15..3dec167f73 100644 --- a/Gems/ScriptEvents/Code/Source/Editor/ScriptEventsEditorGem.cpp +++ b/Gems/ScriptEvents/Code/Source/Editor/ScriptEventsEditorGem.cpp @@ -9,7 +9,6 @@ #include #include -#include #include #include @@ -74,7 +73,6 @@ namespace ScriptEvents m_descriptors.insert(m_descriptors.end(), { ScriptEventsEditor::ScriptEventEditorSystemComponent::CreateDescriptor(), - ScriptEvents::Components::ScriptEventReferencesComponent::CreateDescriptor(), ScriptEventsBuilder::ScriptEventsBuilderComponent::CreateDescriptor(), }); } diff --git a/Gems/ScriptEvents/Code/Source/ScriptEventsGem.cpp b/Gems/ScriptEvents/Code/Source/ScriptEventsGem.cpp index e4fb44f548..bc46993649 100644 --- a/Gems/ScriptEvents/Code/Source/ScriptEventsGem.cpp +++ b/Gems/ScriptEvents/Code/Source/ScriptEventsGem.cpp @@ -12,8 +12,6 @@ #include -#include - namespace ScriptEvents { ScriptEventsModule::ScriptEventsModule() @@ -23,8 +21,7 @@ namespace ScriptEvents ScriptEventModuleConfigurationRequestBus::Handler::BusConnect(); m_descriptors.insert(m_descriptors.end(), { - ScriptEvents::ScriptEventsSystemComponent::CreateDescriptor(), - ScriptEvents::Components::ScriptEventReferencesComponent::CreateDescriptor(), + ScriptEvents::ScriptEventsSystemComponent::CreateDescriptor() }); } diff --git a/Gems/ScriptEvents/Code/scriptevents_common_files.cmake b/Gems/ScriptEvents/Code/scriptevents_common_files.cmake index a7ecd9e049..a038bb2c90 100644 --- a/Gems/ScriptEvents/Code/scriptevents_common_files.cmake +++ b/Gems/ScriptEvents/Code/scriptevents_common_files.cmake @@ -42,6 +42,4 @@ set(FILES Include/ScriptEvents/Internal/BehaviorContextBinding/ScriptEventsBindingBus.h Include/ScriptEvents/Internal/BehaviorContextBinding/ScriptEventBinding.h Include/ScriptEvents/Internal/BehaviorContextBinding/ScriptEventBinding.cpp - Include/ScriptEvents/Components/ScriptEventReferencesComponent.h - Include/ScriptEvents/Components/ScriptEventReferencesComponent.cpp ) From 389f29f0e7cd9da96d23df8f1d054c2533602d1f Mon Sep 17 00:00:00 2001 From: AMZN-koppersr <82230785+AMZN-koppersr@users.noreply.github.com> Date: Tue, 23 Nov 2021 09:26:37 -0800 Subject: [PATCH 19/23] Performance improvement for fixed_vector AZStd::fixed_vector had all its functions marked with constexpr, but this requires all member variables to be fully initialized. This meant that the internal array used to store elements always has to be fully initialized. This was done for trivial classes but not for non-trivial classes. As a result trivial classes always did a memset (or more optimized versions for smaller buffers) while the non-trivial version couldn't actually be stored in a constexpr variable. Since AZStd::fixed_vector is meant to be dynamic the choice was made to remove the constexpr from all non-static member functions in favor of avoiding the overhead of memset, which profiling showed was a considerable overhead depending on the reserved size. If a truly constexpr array is needed than AZStd::array is a better choice as that's designed to not by dynamic. Signed-off-by: AMZN-koppersr <82230785+AMZN-koppersr@users.noreply.github.com> --- .../AzCore/std/containers/fixed_vector.h | 152 +++++++++--------- .../AzCore/Tests/AZStd/VectorAndArray.cpp | 42 ++--- 2 files changed, 97 insertions(+), 97 deletions(-) diff --git a/Code/Framework/AzCore/AzCore/std/containers/fixed_vector.h b/Code/Framework/AzCore/AzCore/std/containers/fixed_vector.h index 7c0cca0308..5a54c2a589 100644 --- a/Code/Framework/AzCore/AzCore/std/containers/fixed_vector.h +++ b/Code/Framework/AzCore/AzCore/std/containers/fixed_vector.h @@ -130,10 +130,11 @@ namespace AZStd::Internal //! Constructors - constexpr fixed_trivial_storage() = default; + fixed_trivial_storage() = default; template >> - constexpr fixed_trivial_storage(AZStd::initializer_list ilist) noexcept + fixed_trivial_storage(AZStd::initializer_list ilist) noexcept + : m_size(aznumeric_caster(ilist.size())) { AZSTD_CONTAINER_ASSERT(ilist.size() <= capacity(), "Initializer list cannot be larger than storage capacity"); size_t index{}; @@ -141,20 +142,19 @@ namespace AZStd::Internal { m_data[index++] = element; } - resize_no_construct(ilist.size()); } - constexpr pointer data() noexcept + pointer data() noexcept { return m_data; } - constexpr const_pointer data() const noexcept + const_pointer data() const noexcept { return m_data; } //! Number of elements currently stored. - constexpr size_type size() const noexcept + size_type size() const noexcept { return m_size; } @@ -164,12 +164,12 @@ namespace AZStd::Internal return Capacity; } //! Is the storage empty? - constexpr bool empty() const noexcept + bool empty() const noexcept { return size() == 0; } //! Is the storage full? - constexpr bool full() const noexcept + bool full() const noexcept { return size() == capacity(); } @@ -186,7 +186,7 @@ namespace AZStd::Internal //! Increases size of the storage by one. //! Always fails for empty storage. template >> - constexpr reference emplace_back(Args&&... args) noexcept + reference emplace_back(Args&&... args) noexcept { AZSTD_CONTAINER_ASSERT(!full(), "emplace_back cannot be invoked on full storage"); reference new_element = *(data() + size()); @@ -196,7 +196,7 @@ namespace AZStd::Internal } //! Removes the last element of the storage. //! Precondition: size is not empty - constexpr void pop_back() noexcept + void pop_back() noexcept { AZSTD_CONTAINER_ASSERT(!empty(), "pop_back cannot be invoked on empty storage"); resize_no_construct(size() - 1); @@ -205,7 +205,7 @@ namespace AZStd::Internal //! removing elements (unsafe). //! //! Updates the size of the container while checking that the new size is less than capacity - constexpr void resize_no_construct(size_t new_size) noexcept + void resize_no_construct(size_t new_size) noexcept { AZSTD_CONTAINER_ASSERT(new_size <= capacity(), "New size cannot be larger than capacity"); m_size = aznumeric_cast(new_size); @@ -215,19 +215,19 @@ namespace AZStd::Internal //! This does not modify the size of the storage //! This is a no-op for trivial types template >> - constexpr void unsafe_destroy(InputIt, InputIt) noexcept + void unsafe_destroy(InputIt, InputIt) noexcept { } //! Destructs all elements of the storage. //! This does not modify the size of the storage //! This is a no-op for trivial types - constexpr void unsafe_destroy_all() noexcept + void unsafe_destroy_all() noexcept { } private: - T m_data[Capacity]{}; + T m_data[Capacity]; size_type m_size{}; }; @@ -245,7 +245,7 @@ namespace AZStd::Internal using reference = T&; using const_reference = const T&; - constexpr fixed_non_trivial_storage() = default; + fixed_non_trivial_storage() = default; ~fixed_non_trivial_storage() noexcept { @@ -253,7 +253,7 @@ namespace AZStd::Internal } template >> - constexpr fixed_non_trivial_storage(AZStd::initializer_list ilist) noexcept(noexcept(emplace_back(AZStd::declval()))) + fixed_non_trivial_storage(AZStd::initializer_list ilist) noexcept(noexcept(emplace_back(AZStd::declval()))) { AZSTD_CONTAINER_ASSERT(ilist.size() <= capacity(), "Initializer list cannot be larger than storage capacity"); for (const U& element : ilist) @@ -272,7 +272,7 @@ namespace AZStd::Internal } //! Number of elements currently stored. - constexpr size_type size() const noexcept + size_type size() const noexcept { return m_size; } @@ -282,12 +282,12 @@ namespace AZStd::Internal return Capacity; } //! Is the storage empty? - constexpr bool empty() const noexcept + bool empty() const noexcept { return size() == 0; } //! Is the storage full? - constexpr bool full() const noexcept + bool full() const noexcept { return size() == capacity(); } @@ -325,7 +325,7 @@ namespace AZStd::Internal //! removing elements (unsafe). //! //! Updates the size of the container while checking that the new size is less than capacity - constexpr void resize_no_construct(size_t new_size) noexcept + void resize_no_construct(size_t new_size) noexcept { AZSTD_CONTAINER_ASSERT(new_size <= capacity(), "New size cannot be larger than capacity"); m_size = aznumeric_cast(new_size); @@ -402,23 +402,23 @@ namespace AZStd ////////////////////////////////////////////////////////////////////////// // 23.2.4.1 construct/copy/destroy - constexpr fixed_vector() = default; + fixed_vector() = default; - constexpr explicit fixed_vector(size_type numElements, const_reference value = value_type()) + explicit fixed_vector(size_type numElements, const_reference value = value_type()) { resize_no_construct(numElements); AZStd::uninitialized_fill_n(data(), numElements, value); } template >> - constexpr fixed_vector(InputIt first, InputIt last) + fixed_vector(InputIt first, InputIt last) { resize_no_construct(AZStd::distance(first, last)); AZStd::uninitialized_copy(first, last, data()); } - constexpr fixed_vector(const fixed_vector& rhs) + fixed_vector(const fixed_vector& rhs) { resize_no_construct(rhs.size()); AZStd::uninitialized_copy(rhs.data(), rhs.data() + rhs.size(), data()); @@ -428,7 +428,7 @@ namespace AZStd // It performs an AZStd::move on each of the fixed_vector elements instead // of swapping pointers to the allocted memory address // as it is unable to perform that operations due to the storage being baked into the container - constexpr fixed_vector(fixed_vector&& rhs) + fixed_vector(fixed_vector&& rhs) { resize_no_construct(rhs.size()); AZStd::uninitialized_move(rhs.data(), rhs.data() + rhs.size(), data()); @@ -440,7 +440,7 @@ namespace AZStd // into a fixed_vector given that the type in question isn't the same type as this fixed_vector type template && !AZStd::is_convertible_v>> - constexpr fixed_vector(VectorContainer&& rhs) + fixed_vector(VectorContainer&& rhs) { constexpr bool is_const_or_lvalue_reference = AZStd::is_lvalue_reference_v || AZStd::is_const_v; @@ -459,12 +459,12 @@ namespace AZStd } } - constexpr fixed_vector(AZStd::initializer_list ilist) + fixed_vector(AZStd::initializer_list ilist) : base_type(ilist) { } - constexpr fixed_vector& operator=(const fixed_vector& rhs) + fixed_vector& operator=(const fixed_vector& rhs) { if (this == &rhs) { @@ -475,7 +475,7 @@ namespace AZStd return assign_helper(rhs); } - constexpr fixed_vector& operator=(fixed_vector&& rhs) + fixed_vector& operator=(fixed_vector&& rhs) { if (this == &rhs) { @@ -487,23 +487,23 @@ namespace AZStd } template - constexpr AZStd::enable_if_t, fixed_vector>, fixed_vector>& operator=(VectorContainer&& rhs) + AZStd::enable_if_t, fixed_vector>, fixed_vector>& operator=(VectorContainer&& rhs) { return assign_helper(AZStd::forward(rhs)); } - constexpr iterator begin() { return iterator(data()); } - constexpr const_iterator begin() const { return const_iterator(data()); } - constexpr const_iterator cbegin() const { return const_iterator(data()); } - constexpr iterator end() { return iterator(data() + size()); } - constexpr const_iterator end() const { return const_iterator(data() + size()); } - constexpr const_iterator cend() const { return const_iterator(data() + size()); } - constexpr reverse_iterator rbegin() { return reverse_iterator(end()); } - constexpr const_reverse_iterator rbegin() const { return const_reverse_iterator(end()); } - constexpr const_reverse_iterator crbegin() const { return const_reverse_iterator(end()); } - constexpr reverse_iterator rend() { return reverse_iterator(begin()); } - constexpr const_reverse_iterator rend() const { return const_reverse_iterator(begin()); } - constexpr const_reverse_iterator crend() const { return const_reverse_iterator(begin()); } + iterator begin() { return iterator(data()); } + const_iterator begin() const { return const_iterator(data()); } + const_iterator cbegin() const { return const_iterator(data()); } + iterator end() { return iterator(data() + size()); } + const_iterator end() const { return const_iterator(data() + size()); } + const_iterator cend() const { return const_iterator(data() + size()); } + reverse_iterator rbegin() { return reverse_iterator(end()); } + const_reverse_iterator rbegin() const { return const_reverse_iterator(end()); } + const_reverse_iterator crbegin() const { return const_reverse_iterator(end()); } + reverse_iterator rend() { return reverse_iterator(begin()); } + const_reverse_iterator rend() const { return const_reverse_iterator(begin()); } + const_reverse_iterator crend() const { return const_reverse_iterator(begin()); } // bring in fixed_vector_storage functions into scope using base_type::data; @@ -514,7 +514,7 @@ namespace AZStd // extension method using base_type::resize_no_construct; - constexpr size_type size() const noexcept + size_type size() const noexcept { return base_type::size(); } @@ -527,12 +527,12 @@ namespace AZStd return base_type::max_size(); } - constexpr void resize(size_type newSize) + void resize(size_type newSize) { return resize(newSize, value_type{}); } - constexpr void resize(size_type newSize, const_reference value) + void resize(size_type newSize, const_reference value) { size_type dataSize = size(); if (dataSize < newSize) @@ -547,7 +547,7 @@ namespace AZStd // Removes unused capacity - For fixed_vector this only asserts // that the supplied capacity is not longer than the fixed_vector capacity - constexpr void reserve(size_type newCapacity) + void reserve(size_type newCapacity) { // No-op - Implemented to provide consistent std::vector AZSTD_CONTAINER_ASSERT(newCapacity <= capacity(), @@ -556,79 +556,79 @@ namespace AZStd } // Removes unused capacity - For fixed_vector this does nothing - constexpr void shrink_to_fit() + void shrink_to_fit() { // No-op - Implemented to provide consistent std::vector } - constexpr reference at(size_type position) + reference at(size_type position) { AZSTD_CONTAINER_ASSERT(position < size(), "AZStd::fixed_vector<>::at - position is out of range"); return *(data() + position); } - constexpr const_reference at(size_type position) const + const_reference at(size_type position) const { AZSTD_CONTAINER_ASSERT(position < size(), "AZStd::fixed_vector<>::at - position is out of range"); return *(data() + position); } - constexpr reference operator[](size_type position) + reference operator[](size_type position) { AZSTD_CONTAINER_ASSERT(position < size(), "AZStd::fixed_vector<>::at - position is out of range"); return *(data() + position); } - constexpr const_reference operator[](size_type position) const + const_reference operator[](size_type position) const { AZSTD_CONTAINER_ASSERT(position < size(), "AZStd::fixed_vector<>::at - position is out of range"); return *(data() + position); } - constexpr reference front() + reference front() { AZSTD_CONTAINER_ASSERT(!empty(), "AZStd::fixed_vector<>::front - container is empty!"); return *data(); } - constexpr const_reference front() const + const_reference front() const { AZSTD_CONTAINER_ASSERT(!empty(), "AZStd::fixed_vector<>::front - container is empty!"); return *data(); } - constexpr reference back() + reference back() { AZSTD_CONTAINER_ASSERT(!empty(), "AZStd::fixed_vector<>::back - container is empty!"); return *(data() + size() - 1); } - constexpr const_reference back() const + const_reference back() const { AZSTD_CONTAINER_ASSERT(!empty(), "AZStd::fixed_vector<>::back - container is empty!"); return *(data() + size() - 1); } - constexpr void push_back(const_reference value) + void push_back(const_reference value) { emplace_back(value); } - constexpr void assign(size_type numElements, const_reference value) + void assign(size_type numElements, const_reference value) { clear(); insert(end(), numElements, value); } template >> - constexpr void assign(InputIt first, InputIt last) + void assign(InputIt first, InputIt last) { clear(); insert(end(), first, last); } - constexpr void assign(AZStd::initializer_list ilist) + void assign(AZStd::initializer_list ilist) { assign(ilist.begin(), ilist.end()); } template >> - constexpr iterator emplace(const_iterator insertPos, Args&&... args) + iterator emplace(const_iterator insertPos, Args&&... args) { AZSTD_CONTAINER_ASSERT(!full(), "Cannot emplace on a full fixed_vector"); AZSTD_CONTAINER_ASSERT(insertPos >= cbegin() && insertPos <= cend(), "insert position must be in range of container"); @@ -645,18 +645,18 @@ namespace AZStd AZStd::construct_at(insertPosPtr, AZStd::forward(args)...); return iterator(insertPosPtr); } - constexpr iterator insert(const_iterator insertPos, const_reference value) + iterator insert(const_iterator insertPos, const_reference value) { AZSTD_CONTAINER_ASSERT(insertPos >= cbegin() && insertPos <= cend(), "insert position must be in range of container"); return emplace(insertPos, value); } - constexpr iterator insert(const_iterator insertPos, value_type&& value) + iterator insert(const_iterator insertPos, value_type&& value) { AZSTD_CONTAINER_ASSERT(insertPos >= cbegin() && insertPos <= cend(), "insert position must be in range of container"); return emplace(insertPos, AZStd::move(value)); } - constexpr void insert(const_iterator insertPos, size_type numElements, const_reference value) + void insert(const_iterator insertPos, size_type numElements, const_reference value) { if (numElements == 0) { @@ -708,24 +708,24 @@ namespace AZStd } template>> - constexpr void insert(const_iterator insertPos, InputIt first, InputIt last) + void insert(const_iterator insertPos, InputIt first, InputIt last) { // specialize for iterator categories. AZSTD_CONTAINER_ASSERT(insertPos >= cbegin() && insertPos <= cend(), "insert position must be in range of container"); insert_iter(insertPos, first, last, typename iterator_traits::iterator_category()); }; - constexpr void insert(const_iterator insertPos, AZStd::initializer_list ilist) + void insert(const_iterator insertPos, AZStd::initializer_list ilist) { insert(insertPos, ilist.begin(), ilist.end()); } - constexpr iterator erase(const_iterator elementIter) + iterator erase(const_iterator elementIter) { return erase(elementIter, elementIter + 1); } - constexpr iterator erase(const_iterator first, const_iterator last) + iterator erase(const_iterator first, const_iterator last) { AZSTD_CONTAINER_ASSERT(first >= cbegin() && last <= cend(), "erase iterator must be inside the range of fixed_vector container"); iterator dataStart = begin(); @@ -741,12 +741,12 @@ namespace AZStd return dataStart + offset; } - constexpr void clear() + void clear() { base_type::unsafe_destroy_all(); resize_no_construct(0); } - constexpr void swap(fixed_vector& rhs) + void swap(fixed_vector& rhs) { // Fixed containers cannot swap pointers, they need to do full copies. // The strategy is to extend the smaller fixed_vector to be the size @@ -776,12 +776,12 @@ namespace AZStd } // Validate container status. - constexpr bool validate() const + bool validate() const { return size() <= max_size(); } // Validate iterator. - constexpr int validate_iterator(const_iterator iter) const + int validate_iterator(const_iterator iter) const { const_pointer start = data(); const_pointer end = data() + size(); @@ -799,19 +799,19 @@ namespace AZStd } // pushes back an empty without a provided instance. - constexpr void push_back() + void push_back() { emplace_back(); } - constexpr void leak_and_reset() + void leak_and_reset() { resize_no_construct(0); } private: template - constexpr fixed_vector& assign_helper(VectorContainer&& rhs) + fixed_vector& assign_helper(VectorContainer&& rhs) { constexpr bool is_const_or_lvalue_reference = AZStd::is_lvalue_reference_v || AZStd::is_const_v; @@ -872,7 +872,7 @@ namespace AZStd } template - constexpr void insert_iter(const_iterator insertPos, Iterator first, Iterator last, const forward_iterator_tag&) + void insert_iter(const_iterator insertPos, Iterator first, Iterator last, const forward_iterator_tag&) { size_type numElements = AZStd::distance(first, last); if (numElements == 0) @@ -923,7 +923,7 @@ namespace AZStd } template - constexpr void insert_iter(const_iterator insertPos, Iterator first, Iterator last, const input_iterator_tag&) + void insert_iter(const_iterator insertPos, Iterator first, Iterator last, const input_iterator_tag&) { iterator dataStart = data(); size_type offset = AZStd::distance(dataStart, insertPos); diff --git a/Code/Framework/AzCore/Tests/AZStd/VectorAndArray.cpp b/Code/Framework/AzCore/Tests/AZStd/VectorAndArray.cpp index 47c3630091..b3eab244c4 100644 --- a/Code/Framework/AzCore/Tests/AZStd/VectorAndArray.cpp +++ b/Code/Framework/AzCore/Tests/AZStd/VectorAndArray.cpp @@ -753,7 +753,7 @@ namespace UnitTest TEST_F(Arrays, FixedVectorCanCopyAndMoveWithDifferentCapacity) { - constexpr AZStd::fixed_vector sourceVector{ 1,2,3,4,5 }; + AZStd::fixed_vector sourceVector{ 1,2,3,4,5 }; AZStd::fixed_vector copyConstructVector{ sourceVector }; EXPECT_EQ(sourceVector, copyConstructVector); @@ -768,32 +768,32 @@ namespace UnitTest AZStd::fixed_vector moveAssignVector = AZStd::move(moveConstructVector); - constexpr AZStd::fixed_vector expectedVector{ 1,2,3,4,5,6 }; + AZStd::fixed_vector expectedVector{ 1,2,3,4,5,6 }; EXPECT_EQ(expectedVector, moveAssignVector); } TEST_F(Arrays, FixedVectorComparisonOperatorsSucceedAsExpected) { - constexpr AZStd::fixed_vector testVector{ 1,2,3,4,5 }; - constexpr AZStd::fixed_vector equalVector{ 1,2,3,4,5 }; - constexpr AZStd::fixed_vector notEqualVectorDifferentSize{ 1,2,3,4,5,6 }; - constexpr AZStd::fixed_vector lessVector{ 1,2,3,4,4 }; - constexpr AZStd::fixed_vector greaterVectorDifferentSize{ 1,2,3,4,5, 1 }; + AZStd::fixed_vector testVector{ 1,2,3,4,5 }; + AZStd::fixed_vector equalVector{ 1,2,3,4,5 }; + AZStd::fixed_vector notEqualVectorDifferentSize{ 1,2,3,4,5,6 }; + AZStd::fixed_vector lessVector{ 1,2,3,4,4 }; + AZStd::fixed_vector greaterVectorDifferentSize{ 1,2,3,4,5, 1 }; - static_assert(testVector == equalVector); - static_assert(testVector != notEqualVectorDifferentSize); - static_assert(testVector != lessVector); - static_assert(lessVector < testVector); - static_assert(lessVector < greaterVectorDifferentSize); - static_assert(lessVector <= lessVector); - static_assert(lessVector <= testVector); - static_assert(lessVector <= greaterVectorDifferentSize); - static_assert(testVector > lessVector); - static_assert(testVector > lessVector); - static_assert(notEqualVectorDifferentSize > testVector); - static_assert(testVector >= testVector); - static_assert(testVector >= lessVector); - static_assert(greaterVectorDifferentSize > lessVector); + EXPECT_EQ(testVector, equalVector); + EXPECT_NE(testVector, notEqualVectorDifferentSize); + EXPECT_NE(testVector, lessVector); + EXPECT_LT(lessVector, testVector); + EXPECT_LT(lessVector, greaterVectorDifferentSize); + EXPECT_LE(lessVector, lessVector); + EXPECT_LE(lessVector, testVector); + EXPECT_LE(lessVector, greaterVectorDifferentSize); + EXPECT_GT(testVector, lessVector); + EXPECT_GT(testVector, lessVector); + EXPECT_GT(notEqualVectorDifferentSize, testVector); + EXPECT_GE(testVector, testVector); + EXPECT_GE(testVector, lessVector); + EXPECT_GT(greaterVectorDifferentSize, lessVector); } TEST_F(Arrays, VectorSwap) From 4ac8b5dc429b6c87b3bd9e743839c47f7a02c0ce Mon Sep 17 00:00:00 2001 From: Danilo Aimini <82231674+AMZN-daimini@users.noreply.github.com> Date: Tue, 23 Nov 2021 13:13:21 -0800 Subject: [PATCH 20/23] Display version number correctly in installer builds from branches that properly set the name on Jenkins. (#5856) Signed-off-by: Danilo Aimini <82231674+AMZN-daimini@users.noreply.github.com> --- Code/Editor/CMakeLists.txt | 2 +- Code/Editor/CryEdit.cpp | 8 ++------ 2 files changed, 3 insertions(+), 7 deletions(-) diff --git a/Code/Editor/CMakeLists.txt b/Code/Editor/CMakeLists.txt index bdfac373eb..e55498203c 100644 --- a/Code/Editor/CMakeLists.txt +++ b/Code/Editor/CMakeLists.txt @@ -131,7 +131,7 @@ ly_add_source_properties( PROPERTY COMPILE_DEFINITIONS VALUES O3DE_COPYRIGHT_YEAR=${LY_VERSION_COPYRIGHT_YEAR} - LY_BUILD=${LY_VERSION_BUILD_NUMBER} + LY_VERSION_BUILD_NUMBER=${LY_VERSION_BUILD_NUMBER} ${LY_PAL_TOOLS_DEFINES} ) ly_add_source_properties( diff --git a/Code/Editor/CryEdit.cpp b/Code/Editor/CryEdit.cpp index 8ef21425c8..dffe222f42 100644 --- a/Code/Editor/CryEdit.cpp +++ b/Code/Editor/CryEdit.cpp @@ -913,13 +913,9 @@ namespace QWidget* g_splashScreen = nullptr; } -QString FormatVersion(const SFileVersion& v) +QString FormatVersion([[maybe_unused]] const SFileVersion& v) { -#if defined(LY_BUILD) - return QObject::tr("Version %1.%2.%3.%4 - Build %5").arg(v[3]).arg(v[2]).arg(v[1]).arg(v[0]).arg(LY_BUILD); -#else - return QObject::tr("Version %1.%2.%3.%4").arg(v[3]).arg(v[2]).arg(v[1]).arg(v[0]); -#endif + return QObject::tr("Version %1").arg(LY_VERSION_BUILD_NUMBER); } QString FormatRichTextCopyrightNotice() From 75bb0f24ad06a16a17e4c13f2dfdb3c54c7c8c51 Mon Sep 17 00:00:00 2001 From: Esteban Papp <81431996+amznestebanpapp@users.noreply.github.com> Date: Tue, 23 Nov 2021 13:16:04 -0800 Subject: [PATCH 21/23] Msbuild warning fix for jenkins (#5818) --- .../build/Platform/Windows/env_windows.cmd | 28 +++++++++++-------- .../Platform/Windows/installer_windows.cmd | 8 ------ 2 files changed, 16 insertions(+), 20 deletions(-) diff --git a/scripts/build/Platform/Windows/env_windows.cmd b/scripts/build/Platform/Windows/env_windows.cmd index a78946caf6..78b5ca6c1a 100644 --- a/scripts/build/Platform/Windows/env_windows.cmd +++ b/scripts/build/Platform/Windows/env_windows.cmd @@ -8,8 +8,7 @@ REM REM REM To get recursive folder creation -SETLOCAL EnableExtensions -SETLOCAL EnableDelayedExpansion +SETLOCAL EnableExtensions EnableDelayedExpansion where /Q cmake IF NOT %ERRORLEVEL%==0 ( @@ -22,21 +21,26 @@ IF NOT "%COMMAND_CWD%"=="" ( CD %COMMAND_CWD% ) -REM Jenkins reports MSB8029 when TMP/TEMP is not defined, define a dummy folder -IF NOT "%TMP%"=="" ( - IF NOT "%WORKSPACE_TMP%"=="" ( - SET TMP=%WORKSPACE_TMP% - SET TEMP=%WORKSPACE_TMP% +REM Ending the local environment to be able to propagate the TMP/TEMP variables to the calling script +ENDLOCAL + +REM Jenkins does not defined TMP +IF "%TMP%"=="" ( + IF "%WORKSPACE%"=="" ( + SET TMP=%APPDATA%\Local\Temp + SET TEMP=%APPDATA%\Local\Temp ) ELSE ( - SET TMP=%cd%/temp - SET TEMP=%cd%/temp + SET TMP=%WORKSPACE%\Temp + SET TEMP=%WORKSPACE%\Temp + REM This folder may not be created in the workspace + IF NOT EXIST "!TMP!" ( + MKDIR "!TMP!" + ) ) ) -IF NOT EXIST "!TMP!" ( - MKDIR "!TMP!" -) EXIT /b 0 :error +ENDLOCAL EXIT /b 1 \ No newline at end of file diff --git a/scripts/build/Platform/Windows/installer_windows.cmd b/scripts/build/Platform/Windows/installer_windows.cmd index bbde450973..8dc111c256 100644 --- a/scripts/build/Platform/Windows/installer_windows.cmd +++ b/scripts/build/Platform/Windows/installer_windows.cmd @@ -17,14 +17,6 @@ IF NOT EXIST %OUTPUT_DIRECTORY% ( ) PUSHD %OUTPUT_DIRECTORY% -REM Override the temporary directory used by wix to the workspace (if we have a WORKSPACE_TMP) -IF NOT "%WORKSPACE_TMP%"=="" ( - SET "WIX_TEMP=!WORKSPACE_TMP!/wix" - IF NOT EXIST "!WIX_TEMP!" ( - MKDIR "!WIX_TEMP!" - ) -) - REM Make sure we are using the CMake version of CPack and not the one that comes with chocolatey SET CPACK_PATH= IF "%LY_CMAKE_PATH%"=="" ( From 28e2681b65fde3a7e63a7fe5acc685ab0192f603 Mon Sep 17 00:00:00 2001 From: Mike Chang Date: Tue, 23 Nov 2021 13:41:55 -0800 Subject: [PATCH 22/23] Add signer script and new gpg signing cert (#5847) * Add signer script and new gpg signing cert Signed-off-by: Mike Chang --- .../signer/Platform/Linux/o3de-releases.gpg | Bin 3228 -> 3980 bytes scripts/signer/Platform/Linux/signer.sh | 27 ++++++++++++++++++ 2 files changed, 27 insertions(+) create mode 100644 scripts/signer/Platform/Linux/signer.sh diff --git a/scripts/signer/Platform/Linux/o3de-releases.gpg b/scripts/signer/Platform/Linux/o3de-releases.gpg index 602d822673321c002c4abf2cce48431685dc2733..b5fbb00392ce60d63a1d519022901cc16390e745 100644 GIT binary patch literal 3980 zcmaLZWmFRk-^cMWMoJDOq((QQG)!PLZYUy%fOK~Zq`Mgn5=u@Qh0)~*k(?qW4Hu21 zgdiY{$Lo5|b?)apFYdR$^FRNWpYzQHQi3eAvN#E706W`l#jtk2+4R)q1>Su7`rCL^ z^w5gqMbA6C+ZUeo*!N{hmAAPQp=0JS80StY>ZK;uRUc~Zyu9iWLP8s& zYS9^YssDP%UWz$^^*&|hTyFx!y|QlMm{#}jPEcQ9yxaV;4~iCc{>(w>=Lh|>ch}Nl zFi2v3`6x@QHaNJ>_d1i@dvakoT1VcfYcoz4qoNWrhMwUIe%(P%k>CFhMT8slYqLUs(IBFYM&X6+5#9q-UZ~umStvC7Q`Q*MYH!-fAX3kX6_#8=U&}aoK#3US=R<6a$Y{5g zYwlr1!Ue^ncw|~0j38ZkkEyxUWl)LnLi(d$c2~@USmMKSCihnkCSG`q+c>3wsmomr zF?)w=-*uF~1}Qgj@&>ly!F);~-+sBaRP!PHM3O0jsx!2LK8k5?XMhX^lPD&&XJ>A` zlaOX|Q*}*tmV3J0p|J-Ih!GF4Dv=3{nq>QddlHK_za-WEf_Yf zh#`6f4(})IcUf(Q&WzqKPY292=8cB~XbAuWjVA6AHnvudZkAq-wn#B|FMEi0YMBvLINN=0gy3_ffHml3w%|b-7;ge{CiAmW`t(dsG@`j zXqm(E8$eD*^Y0REL48FklEXaScUjboZ-iFReuRH3C>VRn5RT)^rrqU=+YaMey%)_H z=J#8+?lYE4+QuX@cNZc796g$_^RrM((|B!{F}{h#oh(fbOYqtY%VtonD&`zBg`QB) zrH(3|1~GNX8B}V(w=onDS0ZVhK6p+og39 zW$q`O*-tE`kJ()yh$jK0f#nlbbJI_BKw6d-3gPZJQiuv1$-sn{f!DV!3$q@8&t ztK@GLE@%bh61PcuVa%T7dd;*o2ZV+8b4WTlb+42D6LmwgXyaqKtWBD>$ctnPv*yRm(K)BuMO=vtz3PmQJPrwj$y9x&k1xg9hxe-kCn-r z$0npS^OZxC;QrNXI}YE{W7pP}4I1{iN*88=Cr~|UO$U?2jG)mJ8P`zUG5M_d|P@9}Q9^z%+s-}XlHXI_?<~T2h#QJDD7;)ayGXJo z6&@yb=Z9|7-z%JXB`>01+V>T%2AFRJ$x?d%SVJ&{c!z7GFn)f(2h4wnTn6ik`9E zZXCOEiFI1>l6DjQ88cd5c>vRWPh5WSTid{ zl}OLtBQKWloHPpoGV-D&69D-oqjC9N_2Vj zyDGForR$QA&%Tpi-+^*O;b36~>eQJ^Ps&;#q^|X|QDS3fP_XsehUA3Z9BP?n(X{KY zTJn1|m=woPttX6`F~vp{>Q{qGH6k<~JcxI&>2)`ht;0)sr2~4{(u1F&KB`}U1s7!f zr*Xb3M}rx@!pFL1V%MT%L<|*W8Um$IL;u+6yIbOVGcyq<)D^efTmn4Ci(7`mBUe@r z>9~|uCU}ml_x7zUnX%%HSe|nrsO6_faN#@o@Ao;yfY~30TR&s3@Kj2)Tapvz)(=yA zXbn;YeF`MNno#BSp>bO^oaaECfrECrth$Rav%f;mjRh5jk?Qn{9y~P>!lQc;SOyGc z(R#L>T!woIDzO-K@VV~3j*Wa(kWj5@lIaScvUXZi)b~ek+4|ehu~&+^ymE^CRxW*i z18~ZdG31phUl9N1)Fo!{X5J4F?Kid6SVG(`ThsGCnZ2hkpOij#FbSwCVEyjm^oYcm zz2&~=l!Vg+tBOd?X6lDQKJ5@)b0vO{V&iBo{S#>1Btb{^gS}q$_=PVC9gzLG)fwuP z#TZIl-B`@Wf--ichAS*s{jO(&z6dm{kCwJ@97s?zM6I$y?(VGS0+ z^Y!dzPm@lvvcLk3Al+51;9pYZ~(8d)7$75TfOUZ zsDg-ldBK$C91r!21}IhLl!0Fs(;DkHGzIxHSbi~GR5xivu1}fpK<6|fq*BoZA6o^r z4e4V2U9fYoCO5=IQ20{P*+LS#pJM=(Nc0&6*^Q1`ZqKo28^Wb*T@0kvYK*YI%I{{0 zoWADfuX#g=CLiRWu&k<&F@KgmK0XP@Q$2b!og|<1zzeItBKzk%70kJih2gHlKQzF6;I~XT={pvPs+N* zEv_}k+n(Dn>O0B3hy#DBI*ow?%N|EFczYp`(~B!r_=vMy}6M;CPNrNa*8Ldv})7Rd+SVYGAwBs+P}$s@8^+Sc=q)t~u?K4s%Z>Uk{wNk znBQqnorJf%ZiYBfhA}yL{*yuRAg_NQ;RCV&{~ILQL}Y}0l7c%Ggs~S+SVNb~GsLs0MW+_PKYepShEXr#zNU?c-cA5IIowK<4i5?j)BmZ|a(x=@=b|u?T zwei!b4ywJZ={l|G%p)tdRUKp&w|kH#&$+VZ{D?n5`pm1*`&i6NCTf*LUOIHFqS0|v zNp{cf+Fx7sAf{!KH`{)305EOlnB2Ne{65EwK_~p)H!o9ppQo|QN>UNMlBe`{ zVuHzT@gN2K^QUU;A#E>S%vjjR^Diyy(>+j4v^rpBPk}c5X??G&QSz}q5ng}P+>r#U z^$c+Yhi)7iQSrg?z1*FUlRHH*?!!=-{AnDEP%h1$hG3dWos41ohxw&+gI%n=x8W4Y z7CVHE0ZMEi@3lhuSNkyWb2Fj4uMa94S{@@;=u1uRA4q4e0} zUEu(snNaHQT=3KHTcYPVdw}PB3 zjW_aOV1Nm_u;X6j+V$D4x7b__$7MzYkIAHGkO%-G&urRwK<*3 z!`V(eclJ&@Ki>@_wU_z|Uflp>jH(WyZD>er{@q zNmg@bg{bhPOXl;s{CZMRvkSSLG&@}A;ASDYvOPqoG@!!??B1kdc4gih2@PKW0@{m> z>Anr3z+8(z(ekH>4x^7iKHneAj! zh;4q~9du{WJ$e1CjBm90FC1@oYlf1lmGIgNQgP=aaE(BwJ=EL5(y?p1a2qGw+cMD0 b>GPn-c46$Z!rlJ!x3Pn1@O(oLmD>LS-Kb&Fn`u|1$0f5m}El!r>p%poi6;?7I8#iBYG}T?)I)^DPZ>b`U z<~=o8HE|y~iNKe99~nA2WFG-4e$sHnaIUYcOY%iM3i(FDRb`;iz7^aOSi~CRZwWRj zQHoZ5%pDnNpEZ5Lv~A8C5Yiw!@!2%9oYnCR&v6;#%!q1ZD#w-B5JLrz#(HIpD`eJ( zv08#t)%#u;HgDkG2dZ4cpw!h1D|p{?WZAWQA!#nEGd0P3Zg_?cEf8&ej!oCcz6`Iv z?OnvmsoQh_mIox4&d?Jm_>P~^4Q&xwPL<(drb8eyZob^>bD(ZQ&QK~ZeIQ?ul6TTt##4>vS$wuDBe zrWoDh58uo7M-QON%&3Z&tV-OSqsx$B z-ed5b8Hnbh3fJ#)dbl$Eq;k||G10uoVR+xf@gCn`>uMpuaVE#tEGV_2`18fg<#9!^-~H;sb|K$yfq4O*Lt5z{J%Y}(ov@hC$S7NoN8Vw48k?9N48 z=c;&YL~gLCvg$pIneUw0W8k>Uq_VqyDvOlbs=1_;sZYer;p!YBq<$jLU=o5H=S{Xq z=bHqlDsqcJQC-m4gal{?-a}WgtJBQ7y*9>b^}!uysWVHx0$LlrL*}7+D}@Rh$m_-z z%2()8+;ke8Z&U{Sk93Ko_%QzMM{mqYmDXoUUfgD@S=lEdJkNo`V~Lx~ghsa36io%s zn^^KiDvb{YJU^ko`TBK5GUvZAZhp@W?HiIqJl6cyn^vaEmm427q$0EYp;zbP@k|68 z^7{V%G7uo4cqvfFGhcHQDFVN1H?{_rv2VmCk;fPcZ;~;S>fwJ(r9#w2#XB(T!%Yq( zn(PM%3J_YRK;3XQG2z8cPzREWPA%j(+PycjZ9=;h-4nV;YFawaG*hn+ngs7(URZMk zkl5Rzccxf!4@+)_UT@^vEND~a1vx~E;e>FahknAz?HyA1po*&&noK?o#wEqI0Sv!# z{vza7=&0$ZiF%s6JW5ot7~?(=an~)}j^C_d$gY@`B8Feu6SH=pasH@NDpf7P*07kQS**IE%jyeK@O6xQnD`}%tv!8e#piNBHuO=`c1<)X zun}W~c4mKRz+tqZdVL^SuSlFyVriZb7y%0!zRN4XN2v%H8O03}_~~lX%4j>^(&PE% zr(P+@4g{hbM{zL6xe4rnWtXSPsW6o0Z+-Z7dw#CF(FvvLF#vq=sl0#ELN8#Hi#}(e z!lVj*$uGibZ1&7zV!p?-InFXhgsR$CoS`sLReh*gRvKqm{D=l3F?l5{jl)w_DHno7xRx2;qq$rpXuWu(i$5|vwl zlv{nuX;qZ~)vsaySd7+FP9N>% zVKz5=ZrrsnrbFJV`!?+@DhI4_uB5d9LmXUyys(`p>Zx`upG|tBGCOBI`SGzoYMC}Y z$JEez2S4Hgx@>xw&6 zozmA*mOGP~wPF5#daWXiZ3hs~D3rktoRvx~moz1g;_Q~xW44V0)=S@wsOhYScdKDc zA-KLH*frrU)KL+-A6^FZSrs590l%*xY+8G$ioTbSy_j`Jt z1AU6@qNWi+uRpt!Ym-E99cdwMPxE-enRl?yy991Tb#it4fTa-JUItmD>*r2?uz=g{ z?IH3kg4J2GFkAJW;6Of&arH>~)?>w5u$8K{$%&)goNHi#jCPSRhLf>SnGr}F@ApgnfIdlPieFE#1n7iYo>ulGi(K}j zOV*1+aZC}uaUTtm zUFv)>m{OY|y{ss_DMET#3G)@8pJyn_1P!yT>CLX|f-!&rO1b^vNHk*+hsqk7W`t;k zFlIF5)bawaAB&qEfI^9rRS1i&N34fbwEXca-M8}*Su7Y@ znc!O`+e`+KfN2O;YKRoWBuKWwz~pOauB#91&Y@>Wv0yy!V?!fVql3urs|C-0{{{X< QcjN&6ZWf{?{ExNcKd8DEw*UYD diff --git a/scripts/signer/Platform/Linux/signer.sh b/scripts/signer/Platform/Linux/signer.sh new file mode 100644 index 0000000000..b090012c5a --- /dev/null +++ b/scripts/signer/Platform/Linux/signer.sh @@ -0,0 +1,27 @@ +#!/bin/bash + +# +# Copyright (c) Contributors to the Open 3D Engine Project. +# For complete copyright and license terms please see the LICENSE at the root of this distribution. +# +# SPDX-License-Identifier: Apache-2.0 OR MIT +# +# + +set +x + +export GPG_TTY=$(tty) # Required to pass valid tty during ssh sessions +file=$1 + +# dpkg-sig depends on a valid and trusted GPG private key. This also assumes a private key password has already been cached via gpg-agent +# If you do need to pass a password, a gpg argument can be added to the command: +# dpkg-sig -k $fingerprint -g "--pinentry-mode loopback --passphrase $pass" --sign builder + +fingerprint=$(gpg --list-keys --with-colons | awk -F: '/fpr:/ {print $10}' | tail -n1) #Get the last certificate in the list, which is the signing cert +if [ -z $fingerprint ]; then + echo "No valid certs found. Exiting with 1" + exit 1 +fi +echo "Signing with $fingerprint" +dpkg-sig -k $fingerprint --sign builder $file +dpkg-sig --verify $file && echo "Signing $file complete!" From bbdf871a134fd5986b3b493d3164d635f9b4f81c Mon Sep 17 00:00:00 2001 From: Ken Pruiksma Date: Tue, 23 Nov 2021 17:07:29 -0600 Subject: [PATCH 23/23] Terrain detail material blending (#5714) * Added buffer for material properties of detail mateirals, storing them in a multi-indexed data vector. Updated shader with relevant struct and buffer, but the buffer will need to be moved out of the mateiral SRG to work. Signed-off-by: Ken Pruiksma * Added buffer for material properties of detail mateirals, storing them in a multi-indexed data vector. Updated shader with relevant struct and buffer, but the buffer will need to be moved out of the mateiral SRG to work. Signed-off-by: Ken Pruiksma * Added buffer for material properties of detail mateirals, storing them in a multi-indexed data vector. Updated shader with relevant struct and buffer, but the buffer will need to be moved out of the mateiral SRG to work. Signed-off-by: Ken Pruiksma * - Moved settings related to the detail material to a partial view srg owned by the terrain gem. - Added support for base color in detail materials. - Hooked up basic base color rendering of detail materials. - Corrected the way the material data was stored. - Added ref counting for detail materials so they can be released when no longer used. Signed-off-by: Ken Pruiksma * Added buffer for material properties of detail mateirals, storing them in a multi-indexed data vector. Updated shader with relevant struct and buffer, but the buffer will need to be moved out of the mateiral SRG to work. Signed-off-by: Ken Pruiksma * - Moved settings related to the detail material to a partial view srg owned by the terrain gem. - Added support for base color in detail materials. - Hooked up basic base color rendering of detail materials. - Corrected the way the material data was stored. - Added ref counting for detail materials so they can be released when no longer used. Signed-off-by: Ken Pruiksma * Detail materials now put textures into bindless array that's accessed in the shader. Shader now pulls all the detail materal information for a single mateiral but does no blending. Signed-off-by: Ken Pruiksma * Correcting rebase merge problem. Signed-off-by: Ken Pruiksma * Fix detail roughness fade out with distance. Signed-off-by: Ken Pruiksma * Adding tests for new MultiIndexedDataVector functions Signed-off-by: Ken Pruiksma * Updates to move bindless array to separate SRG - Exposed BindSrg() in renderpass so it's possible to add additional SRGs to a pass - Created a TerrainSrg for use by the terrain forward shader - Moved the bindless array out of the partial view SRG to the TerrainSrg Signed-off-by: Ken Pruiksma * Moved more properties out of the view srg to the terrain srg. Signed-off-by: Ken Pruiksma * Spelling fixes Signed-off-by: Ken Pruiksma * Fixing bug where the roughness min/max value were inverted. Also fixed bug where bad data would show for areas where there was no macro material. Signed-off-by: Ken Pruiksma * Detail material blending WIP. Mostly working, but small seams between each materila id pixel. Signed-off-by: Ken Pruiksma * Switching to using Load() for the detail material IDs and calculating the positions manually since Gather()'s precsion leaves seams along the edges. Signed-off-by: Ken Pruiksma * Updates from PR review Signed-off-by: Ken Pruiksma * Fixing case issues and updating function name due to a recent fix. Signed-off-by: Ken Pruiksma * Switching to using SampleGrad() instead of Sample() for detail textures to fix a bug where the incorrect mip level was chosen around the seams of the detail material id texture. Signed-off-by: Ken Pruiksma * Remove unneeded sampler and some debug settings in the shader. Condensing some duplicate code Signed-off-by: Ken Pruiksma * Updates from PR review and some minor improvements Signed-off-by: Ken Pruiksma * Updated with PR feedback. Fixed a fairly significant bug with blending. Also contains a few minor fixes, simplifications, and comments for clarity. Signed-off-by: Ken Pruiksma * Update weight adjustment equation to trust the compiler less Signed-off-by: Ken Pruiksma * fix bug Signed-off-by: Ken Pruiksma * Fixing bug in terrain normal factor. Adjusting normal calculation to avoid the need for an identity transform. Signed-off-by: Ken Pruiksma * Removing unused fields from the material SRG. Adding basecolor back in in the material type. Updating the default terrain material to not use fields that no longer exist. Signed-off-by: Ken Pruiksma --- .../Terrain/DefaultPbrTerrain.material | 7 +- .../Materials/Terrain/PbrTerrain.materialtype | 13 ++ .../Shaders/Terrain/TerrainCommon.azsli | 23 +-- .../Terrain/TerrainDetailHelpers.azsli | 173 +++++++++++++++--- .../Terrain/TerrainPBR_ForwardPass.azsl | 9 +- .../Terrain/TerrainPBR_ForwardPass.shader | 6 + .../Assets/Shaders/Terrain/TerrainSrg.azsli | 10 - 7 files changed, 178 insertions(+), 63 deletions(-) diff --git a/Gems/Terrain/Assets/Materials/Terrain/DefaultPbrTerrain.material b/Gems/Terrain/Assets/Materials/Terrain/DefaultPbrTerrain.material index 7cf249a10d..53f6fd5b9e 100644 --- a/Gems/Terrain/Assets/Materials/Terrain/DefaultPbrTerrain.material +++ b/Gems/Terrain/Assets/Materials/Terrain/DefaultPbrTerrain.material @@ -2,5 +2,10 @@ "description": "", "materialType": "PbrTerrain.materialtype", "parentMaterial": "", - "propertyLayoutVersion": 1 + "propertyLayoutVersion": 1, + "properties": { + "baseColor": { + "color": [ 0.18, 0.18, 0.18 ] + } + } } diff --git a/Gems/Terrain/Assets/Materials/Terrain/PbrTerrain.materialtype b/Gems/Terrain/Assets/Materials/Terrain/PbrTerrain.materialtype index a20ac23e17..1e7305cc11 100644 --- a/Gems/Terrain/Assets/Materials/Terrain/PbrTerrain.materialtype +++ b/Gems/Terrain/Assets/Materials/Terrain/PbrTerrain.materialtype @@ -88,6 +88,19 @@ } } ], + "baseColor": [ + { + "name": "color", + "displayName": "Color", + "description": "Color is displayed as sRGB but the values are stored as linear color.", + "type": "Color", + "defaultValue": [ 1.0, 1.0, 1.0 ], + "connection": { + "type": "ShaderInput", + "name": "m_baseColor" + } + } + ], "settings": [ { "id": "detailTextureMultiplier", diff --git a/Gems/Terrain/Assets/Shaders/Terrain/TerrainCommon.azsli b/Gems/Terrain/Assets/Shaders/Terrain/TerrainCommon.azsli index f5af598435..770f877ea8 100644 --- a/Gems/Terrain/Assets/Shaders/Terrain/TerrainCommon.azsli +++ b/Gems/Terrain/Assets/Shaders/Terrain/TerrainCommon.azsli @@ -93,10 +93,6 @@ ShaderResourceGroup ObjectSrg : SRG_PerObject ShaderResourceGroup TerrainMaterialSrg : SRG_PerMaterial { - float m_detailTextureMultiplier; - float m_detailFadeDistance; - float m_detailFadeLength; - Sampler m_sampler { AddressU = Wrap; @@ -109,22 +105,11 @@ ShaderResourceGroup TerrainMaterialSrg : SRG_PerMaterial // Base Color float3 m_baseColor; - float m_baseColorFactor; - Texture2D m_baseColorMap; - // Normal - Texture2D m_normalMap; - bool m_flipNormalX; - bool m_flipNormalY; - float m_normalFactor; - - // Roughness - Texture2D m_roughnessMap; - float m_roughnessFactor; - - // Specular - Texture2D m_specularF0Map; - float m_specularF0Factor; + // Detail Material Properties + float m_detailTextureMultiplier; + float m_detailFadeDistance; + float m_detailFadeLength; } option bool o_useTerrainSmoothing = false; diff --git a/Gems/Terrain/Assets/Shaders/Terrain/TerrainDetailHelpers.azsli b/Gems/Terrain/Assets/Shaders/Terrain/TerrainDetailHelpers.azsli index e5d5ff688d..33c817c0f9 100644 --- a/Gems/Terrain/Assets/Shaders/Terrain/TerrainDetailHelpers.azsli +++ b/Gems/Terrain/Assets/Shaders/Terrain/TerrainDetailHelpers.azsli @@ -57,7 +57,30 @@ DetailSurface GetDefaultDetailSurface() return surface; } +void WeightDetailSurface(inout DetailSurface surface, in float weight) +{ + surface.m_color *= weight; + surface.m_normal *= weight; + surface.m_roughness *= weight; + surface.m_specularF0 *= weight; + surface.m_metalness *= weight; + surface.m_occlusion *= weight; + surface.m_height *= weight; +} + +void AddDetailSurface(inout DetailSurface surface, in DetailSurface surfaceToAdd) +{ + surface.m_color += surfaceToAdd.m_color; + surface.m_normal += surfaceToAdd.m_normal; + surface.m_roughness += surfaceToAdd.m_roughness; + surface.m_specularF0 += surfaceToAdd.m_specularF0; + surface.m_metalness += surfaceToAdd.m_metalness; + surface.m_occlusion += surfaceToAdd.m_occlusion; + surface.m_height += surfaceToAdd.m_height; +} + // Detail material index getters + uint GetDetailColorIndex(TerrainSrg::DetailMaterialData materialData) { return materialData.m_colorNormalImageIndices & 0x0000FFFF; @@ -95,22 +118,22 @@ uint GetDetailHeightIndex(TerrainSrg::DetailMaterialData materialData) // Detail material value getters -float3 GetDetailColor(TerrainSrg::DetailMaterialData materialData, float2 uv) +float3 GetDetailColor(TerrainSrg::DetailMaterialData materialData, float2 uv, float2 ddx, float2 ddy) { float3 color = materialData.m_baseColor; if ((materialData.m_flags & DetailTextureFlags::UseTextureBaseColor) > 0) { - color = TerrainSrg::m_detailTextures[GetDetailColorIndex(materialData)].Sample(TerrainMaterialSrg::m_sampler, uv).rgb; + color = TerrainSrg::m_detailTextures[GetDetailColorIndex(materialData)].SampleGrad(TerrainMaterialSrg::m_sampler, uv, ddx, ddy).rgb; } return color * materialData.m_baseColorFactor; } -float3 GetDetailNormal(TerrainSrg::DetailMaterialData materialData, float2 uv) +float3 GetDetailNormal(TerrainSrg::DetailMaterialData materialData, float2 uv, float2 ddx, float2 ddy) { float2 normal = float2(0.0, 0.0); if ((materialData.m_flags & DetailTextureFlags::UseTextureNormal) > 0) { - normal = TerrainSrg::m_detailTextures[GetDetailNormalIndex(materialData)].Sample(TerrainMaterialSrg::m_sampler, uv).rg; + normal = TerrainSrg::m_detailTextures[GetDetailNormalIndex(materialData)].SampleGrad(TerrainMaterialSrg::m_sampler, uv, ddx, ddy).rg; } // X and Y are inverted here to be consistent with SampleNormalXY in NormalInput.azsli. @@ -125,53 +148,53 @@ float3 GetDetailNormal(TerrainSrg::DetailMaterialData materialData, float2 uv) return GetTangentSpaceNormal(normal, materialData.m_normalFactor); } -float GetDetailRoughness(TerrainSrg::DetailMaterialData materialData, float2 uv) +float GetDetailRoughness(TerrainSrg::DetailMaterialData materialData, float2 uv, float2 ddx, float2 ddy) { float roughness = materialData.m_roughnessScale; if ((materialData.m_flags & DetailTextureFlags::UseTextureRoughness) > 0) { - roughness = TerrainSrg::m_detailTextures[GetDetailRoughnessIndex(materialData)].Sample(TerrainMaterialSrg::m_sampler, uv).r; + roughness = TerrainSrg::m_detailTextures[GetDetailRoughnessIndex(materialData)].SampleGrad(TerrainMaterialSrg::m_sampler, uv, ddx, ddy).r; roughness = materialData.m_roughnessBias + roughness * materialData.m_roughnessScale; } return roughness; } -float GetDetailMetalness(TerrainSrg::DetailMaterialData materialData, float2 uv) +float GetDetailMetalness(TerrainSrg::DetailMaterialData materialData, float2 uv, float2 ddx, float2 ddy) { float metalness = 1.0; if ((materialData.m_flags & DetailTextureFlags::UseTextureMetallic) > 0) { - metalness = TerrainSrg::m_detailTextures[GetDetailMetalnessIndex(materialData)].Sample(TerrainMaterialSrg::m_sampler, uv).r; + metalness = TerrainSrg::m_detailTextures[GetDetailMetalnessIndex(materialData)].SampleGrad(TerrainMaterialSrg::m_sampler, uv, ddx, ddy).r; } return metalness * materialData.m_metalFactor; } -float GetDetailSpecularF0(TerrainSrg::DetailMaterialData materialData, float2 uv) +float GetDetailSpecularF0(TerrainSrg::DetailMaterialData materialData, float2 uv, float2 ddx, float2 ddy) { float specularF0 = 1.0; if ((materialData.m_flags & DetailTextureFlags::UseTextureSpecularF0) > 0) { - specularF0 = TerrainSrg::m_detailTextures[GetDetailSpecularF0Index(materialData)].Sample(TerrainMaterialSrg::m_sampler, uv).r; + specularF0 = TerrainSrg::m_detailTextures[GetDetailSpecularF0Index(materialData)].SampleGrad(TerrainMaterialSrg::m_sampler, uv, ddx, ddy).r; } return specularF0 * materialData.m_specularF0Factor; } -float GetDetailOcclusion(TerrainSrg::DetailMaterialData materialData, float2 uv) +float GetDetailOcclusion(TerrainSrg::DetailMaterialData materialData, float2 uv, float2 ddx, float2 ddy) { float occlusion = 1.0; if ((materialData.m_flags & DetailTextureFlags::UseTextureOcclusion) > 0) { - occlusion = TerrainSrg::m_detailTextures[GetDetailOcclusionIndex(materialData)].Sample(TerrainMaterialSrg::m_sampler, uv).r; + occlusion = TerrainSrg::m_detailTextures[GetDetailOcclusionIndex(materialData)].SampleGrad(TerrainMaterialSrg::m_sampler, uv, ddx, ddy).r; } return occlusion * materialData.m_occlusionFactor; } -float GetDetailHeight(TerrainSrg::DetailMaterialData materialData, float2 uv) +float GetDetailHeight(TerrainSrg::DetailMaterialData materialData, float2 uv, float2 ddx, float2 ddy) { float height = materialData.m_heightFactor; if ((materialData.m_flags & DetailTextureFlags::UseTextureHeight) > 0) { - height = TerrainSrg::m_detailTextures[GetDetailHeightIndex(materialData)].Sample(TerrainMaterialSrg::m_sampler, uv).r; + height = TerrainSrg::m_detailTextures[GetDetailHeightIndex(materialData)].SampleGrad(TerrainMaterialSrg::m_sampler, uv, ddx, ddy).r; height = materialData.m_heightOffset + height * materialData.m_heightFactor; } return height; @@ -181,15 +204,19 @@ void GetDetailSurfaceForMaterial(inout DetailSurface surface, uint materialId, f { TerrainSrg::DetailMaterialData detailMaterialData = TerrainSrg::m_detailMaterialData[materialId]; - surface.m_color = GetDetailColor(detailMaterialData, uv); - surface.m_normal = GetDetailNormal(detailMaterialData, uv); - surface.m_roughness = GetDetailRoughness(detailMaterialData, uv); - surface.m_specularF0 = GetDetailSpecularF0(detailMaterialData, uv); - surface.m_metalness = GetDetailMetalness(detailMaterialData, uv); - surface.m_occlusion = GetDetailOcclusion(detailMaterialData, uv); - surface.m_height = GetDetailHeight(detailMaterialData, uv); + float2 uvDdx = ddx(uv); + float2 uvDdy = ddy(uv); + + surface.m_color = GetDetailColor(detailMaterialData, uv, uvDdx, uvDdy); + surface.m_normal = GetDetailNormal(detailMaterialData, uv, uvDdx, uvDdy); + surface.m_roughness = GetDetailRoughness(detailMaterialData, uv, uvDdx, uvDdy); + surface.m_specularF0 = GetDetailSpecularF0(detailMaterialData, uv, uvDdx, uvDdy); + surface.m_metalness = GetDetailMetalness(detailMaterialData, uv, uvDdx, uvDdy); + surface.m_occlusion = GetDetailOcclusion(detailMaterialData, uv, uvDdx, uvDdy); + surface.m_height = GetDetailHeight(detailMaterialData, uv, uvDdx, uvDdy); } +// Debugs the detail material by choosing a random color per material ID and rendering it without blending. void GetDebugDetailSurface(inout DetailSurface surface, uint material1, uint material2, float blend, float2 idUv) { float3 material1Color = float3(0.1, 0.1, 0.1); @@ -210,7 +237,7 @@ void GetDebugDetailSurface(inout DetailSurface surface, uint material1, uint mat surface.m_color = lerp(material1Color, material2Color, blend); float seamBlend = 0.0; const float halfLineWidth = 1.0 / 2048.0; - if (any(abs(idUv) % 1.0 < halfLineWidth) || any(abs(idUv) % 1.0 > 1.0 - halfLineWidth)) + if (any(frac(abs(idUv)) < halfLineWidth) || any(frac(abs(idUv)) > 1.0 - halfLineWidth)) { seamBlend = 1.0; } @@ -225,26 +252,114 @@ void GetDebugDetailSurface(inout DetailSurface surface, uint material1, uint mat surface.m_height = 0.5; } -bool GetDetailSurface(inout DetailSurface surface, float2 idUv, float2 uv) +//Blend a single detail material sample (with two possible material ids) onto a DetailSurface. +void BlendDetailMaterial(inout DetailSurface surface, uint material1, uint material2, float blend, float2 detailUv, float weight) { - uint4 material1 = TerrainSrg::m_detailMaterialIdImage.GatherRed(TerrainSrg::DetailSampler, idUv, 0).xyzw; - uint4 material2 = TerrainSrg::m_detailMaterialIdImage.GatherGreen(TerrainSrg::DetailSampler, idUv, 0).xyzw; + DetailSurface tempSurface; + GetDetailSurfaceForMaterial(tempSurface, material1, detailUv); + WeightDetailSurface(tempSurface, weight * (1.0 - blend)); + AddDetailSurface(surface, tempSurface); + if (material2 != 0xFF) + { + GetDetailSurfaceForMaterial(tempSurface, material2, detailUv); + WeightDetailSurface(tempSurface, weight * blend); + AddDetailSurface(surface, tempSurface); + } +} - const float maxBlendAmount = 0xFF; +/* +Populates a DetailSurface with material data gathered form the 4 nearest samples to detailMaterialIdUv. The weight +of each detail material's contribution is calculated based on the distance to the center point for that sample (for +instance, if detailMaterialIdUv falls perfectly in-between all 4 samples, then each sample will be weighed at 25%). +Each sample can have two different detail materials defined with a blend value to determine their relative contribution. +The detailUv is used for sampling the textures of each detail material. +*/ +bool GetDetailSurface(inout DetailSurface surface, float2 detailMaterialIdUv, float2 detailUv) +{ + float2 textureSize; + TerrainSrg::m_detailMaterialIdImage.GetDimensions(textureSize.x, textureSize.y); + + float2 detailMaterialIdCoord = detailMaterialIdUv * textureSize; // uv -> pixel coordinate + + // detailMaterialIdCoord could be negative, so add textureSize to ensure it is positive + detailMaterialIdCoord += textureSize; + + // The detail material id texture wraps since the "center" point can be anywhere in the texture, so mod by texturesize + int2 detailMaterailIdTopLeft = int2(detailMaterialIdCoord) % textureSize; + int2 detailMaterailIdBottomRight = (int2(detailMaterialIdCoord) + 1) % textureSize; + + // Using Load() to gather the nearest 4 samples (Gather4() isn't used because of precision issues with uvs). + uint4 s1 = TerrainSrg::m_detailMaterialIdImage.Load(int3(detailMaterailIdTopLeft.x, detailMaterailIdBottomRight.y, 0)); + uint4 s2 = TerrainSrg::m_detailMaterialIdImage.Load(int3(detailMaterailIdBottomRight, 0)); + uint4 s3 = TerrainSrg::m_detailMaterialIdImage.Load(int3(detailMaterailIdBottomRight.x, detailMaterailIdTopLeft.y, 0)); + uint4 s4 = TerrainSrg::m_detailMaterialIdImage.Load(int3(detailMaterailIdTopLeft, 0)); + + uint4 material1 = uint4(s1.x, s2.x, s3.x, s4.x); + uint4 material2 = uint4(s1.y, s2.y, s3.y, s4.y); + // convert integer of 0-255 to float of 0-1. - float4 blends = float4(TerrainSrg::m_detailMaterialIdImage.GatherBlue(TerrainSrg::DetailSampler, idUv, 0).xyzw) / maxBlendAmount; + const float maxBlendAmount = 0xFF; + float4 blends = float4(s1.z, s2.z, s3.z, s4.z) / maxBlendAmount; + + // Calculate weight based on proximity to detail material samples + float2 gatherWeight = frac(detailMaterialIdCoord); + // Adjust the gather weight for better interpolation by (3x^2 - 2x^3). This helps avoid diamond-shaped artifacts in binlinear filtering. + gatherWeight = gatherWeight * gatherWeight * (3.0 - 2.0 * gatherWeight); if (o_debugDetailMaterialIds) { + float2 idUv = (detailMaterialIdCoord + gatherWeight - 0.5) / textureSize; GetDebugDetailSurface(surface, material1.x, material2.x, blends.x, idUv); return true; } - if (material1.x == 0xFF) + // If any sample has no materials, give up. + if (any(material1 == 0xFF)) { return false; } - GetDetailSurfaceForMaterial(surface, material1.x, uv); + if (all(material1.x == material1.yzw) && all(material2.x == material2.yzw)) + { + // Fast path for same material ids + GetDetailSurfaceForMaterial(surface, material1.x, detailUv); + if (material2.x != 0xFF) + { + float4 material2Blends = 1.0 - blends; + DetailSurface tempSurface; + float weight = + ((1.0 - gatherWeight.x) * gatherWeight.y * material2Blends.x) + + (gatherWeight.x * gatherWeight.y * material2Blends.y) + + (gatherWeight.x * (1.0 - gatherWeight.y) * material2Blends.z) + + ((1.0 - gatherWeight.x) * (1.0 - gatherWeight.y) * material2Blends.w); + WeightDetailSurface(surface, weight); + GetDetailSurfaceForMaterial(tempSurface, material2.x, detailUv); + WeightDetailSurface(tempSurface, 1.0 - weight); + AddDetailSurface(surface, tempSurface); + } + } + else + { + surface = (DetailSurface)0; + + // X + float weight = (1.0 - gatherWeight.x) * gatherWeight.y; + BlendDetailMaterial(surface, material1.x, material2.x, blends.x, detailUv, weight); + + // Y + weight = gatherWeight.x * gatherWeight.y; + BlendDetailMaterial(surface, material1.y, material2.y, blends.y, detailUv, weight); + + // Z + weight = gatherWeight.x * (1.0 - gatherWeight.y); + BlendDetailMaterial(surface, material1.z, material2.z, blends.z, detailUv, weight); + + // W + weight = (1.0 - gatherWeight.x) * (1.0 - gatherWeight.y); + BlendDetailMaterial(surface, material1.w, material2.w, blends.w, detailUv, weight); + } + + surface.m_normal = normalize(surface.m_normal); + return true; } diff --git a/Gems/Terrain/Assets/Shaders/Terrain/TerrainPBR_ForwardPass.azsl b/Gems/Terrain/Assets/Shaders/Terrain/TerrainPBR_ForwardPass.azsl index 6b68336a3f..ab9064e740 100644 --- a/Gems/Terrain/Assets/Shaders/Terrain/TerrainPBR_ForwardPass.azsl +++ b/Gems/Terrain/Assets/Shaders/Terrain/TerrainPBR_ForwardPass.azsl @@ -109,9 +109,10 @@ ForwardPassOutput TerrainPBR_MainPassPS(VSOutput IN) { bool flipX = ObjectSrg::m_macroMaterialData[i].m_flipNormalX; bool flipY = ObjectSrg::m_macroMaterialData[i].m_flipNormalY; - bool factor = ObjectSrg::m_macroMaterialData[i].m_normalFactor; - macroNormal = GetNormalInputTS(ObjectSrg::m_macroNormalMap[i], TerrainMaterialSrg::m_sampler, - macroUv, flipX, flipY, CreateIdentity3x3(), true, factor); + float factor = ObjectSrg::m_macroMaterialData[i].m_normalFactor; + + float2 sampledValue = SampleNormalXY(ObjectSrg::m_macroNormalMap[i], TerrainMaterialSrg::m_sampler, macroUv, flipX, flipY); + macroNormal = normalize(GetTangentSpaceNormal_Unnormalized(sampledValue.xy, factor)); } break; } @@ -129,7 +130,7 @@ ForwardPassOutput TerrainPBR_MainPassPS(VSOutput IN) // Check to make sure we're inside the detail texture's bounds and within where detail textures should be drawn. if (detailFactor < 1.0 && all(detailRegionUv > TerrainSrg::m_detailHalfPixelUv) && all(detailRegionUv < 1.0 - TerrainSrg::m_detailHalfPixelUv)) { - detailRegionUv += TerrainSrg::m_detailMaterialIdImageCenter - (0.5); + detailRegionUv += TerrainSrg::m_detailMaterialIdImageCenter - 0.5; hasDetailSurface = GetDetailSurface(detailSurface, detailRegionUv, detailUv); } diff --git a/Gems/Terrain/Assets/Shaders/Terrain/TerrainPBR_ForwardPass.shader b/Gems/Terrain/Assets/Shaders/Terrain/TerrainPBR_ForwardPass.shader index 0e6f0beb1d..66072567ec 100644 --- a/Gems/Terrain/Assets/Shaders/Terrain/TerrainPBR_ForwardPass.shader +++ b/Gems/Terrain/Assets/Shaders/Terrain/TerrainPBR_ForwardPass.shader @@ -1,6 +1,12 @@ { "Source" : "./TerrainPBR_ForwardPass.azsl", + "CompilerHints" : + { + "DisableOptimizations" : false, + "GenerateDebugInfo" : false + }, + "DepthStencilState" : { "Depth" : diff --git a/Gems/Terrain/Assets/Shaders/Terrain/TerrainSrg.azsli b/Gems/Terrain/Assets/Shaders/Terrain/TerrainSrg.azsli index c8ab04a5bc..f980e02b9d 100644 --- a/Gems/Terrain/Assets/Shaders/Terrain/TerrainSrg.azsli +++ b/Gems/Terrain/Assets/Shaders/Terrain/TerrainSrg.azsli @@ -17,16 +17,6 @@ ShaderResourceGroupSemantic SRG_Terrain ShaderResourceGroup TerrainSrg : SRG_Terrain { - - Sampler DetailSampler - { - AddressU = Wrap; - AddressV = Wrap; - MinFilter = Point; - MagFilter = Point; - MipFilter = Point; - }; - struct DetailMaterialData { // Uv