Browse Source

CMake referenced Gems external_subdirectories fixes (#12051)

This is to fix a limitation with external_subdirectories recurse logic when
gathering the list of external_subdirectories to visit for any gems
referenced indirectly in the project.json/engine.json via the
"gem_names" field.

The limitation was that only the gem paths of the referenced "gem_names"
had cmake `add_subdirectory` command called on them.
If thoses gems contained additional external subdirectories referenced
in the "external_subdirectories" field in the gem.json, those
subdirectories were NOT added to CMake via `add_subdirectory`

The change here is to create a mapping of <gem-name> (via the
`O3DE_EXTERNAL_SUBDIRS_GEM_<gem_name>` property) to all external
subdirectories that are descendents for all gems.

Then when a gem is referenced by "gem_name", not only is the gem path
queried, but the external subdirectories associated with that gem as
well.

Next refactored the Subdirectories.cmake to remove the
duplicate logic for gathering the project, engine and o3de_manifest
external_subdirectories.

The functions that perform the gathering has been consolidated into
functions which are parameterized to except the o3de object type,
o3de object "<object>_name" value and the name of the json file for the
object type (i.e engine.json, project.json, o3de_manifest.json).

Signed-off-by: lumberyard-employee-dm <[email protected]>

Signed-off-by: lumberyard-employee-dm <[email protected]>
lumberyard-employee-dm 2 years ago
parent
commit
19619553dd
3 changed files with 108 additions and 131 deletions
  1. 2 2
      CMakeLists.txt
  2. 2 2
      cmake/GeneralSettings.cmake
  3. 104 127
      cmake/Subdirectories.cmake

+ 2 - 2
CMakeLists.txt

@@ -47,14 +47,14 @@ include(cmake/Subdirectories.cmake)
 include(cmake/TestImpactFramework/LYTestImpactFramework.cmake) # Put at end as nothing else depends on it
 
 # Gather the list of o3de_manifest external Subdirectories
-# into the LY_EXTERNAL_SUBDIRS_O3DE_MANIFEST_PROPERTY
+# into the O3DE_EXTERNAL_SUBDIRS_O3DE_MANIFEST_PROPERTY
 add_o3de_manifest_json_external_subdirectories()
 
 # Add the projects first so the Launcher can find them
 include(cmake/Projects.cmake)
 
 # Add external subdirectories listed in the engine.json.
-# LY_EXTERNAL_SUBDIRS is a cache variable so the user can add extra
+# O3DE_EXTERNAL_SUBDIRS is a cache variable so the user can add extra
 # external subdirectories.
 add_engine_json_external_subdirectories()
 

+ 2 - 2
cmake/GeneralSettings.cmake

@@ -12,7 +12,7 @@
 set_property(GLOBAL PROPERTY USE_FOLDERS ON)
 ly_set(CMAKE_WARN_DEPRECATED ON)
 
-set(LY_EXTERNAL_SUBDIRS "" CACHE STRING "Additional list of subdirectory to recurse into via the cmake `add_subdirectory()` command. \
+set(O3DE_EXTERNAL_SUBDIRS "" CACHE STRING "Additional list of subdirectory to recurse into via the cmake `add_subdirectory()` command. \
     The subdirectories are included after the restricted platform folders have been visited by a call to `add_subdirectory(restricted/\${restricted_platform})`")
 
-ly_set(LY_ROOT_FOLDER ${CMAKE_CURRENT_SOURCE_DIR})
+ly_set(LY_ROOT_FOLDER ${CMAKE_CURRENT_SOURCE_DIR})

+ 104 - 127
cmake/Subdirectories.cmake

@@ -13,163 +13,131 @@ include_guard()
 ################################################################################
 
 # Add a GLOBAL property which can be used to quickly determine if a directory is an external subdirectory
-get_property(cache_external_subdirs CACHE LY_EXTERNAL_SUBDIRS PROPERTY VALUE)
+get_property(cache_external_subdirs CACHE O3DE_EXTERNAL_SUBDIRS PROPERTY VALUE)
 foreach(cache_external_subdir IN LISTS cache_external_subdirs)
     file(REAL_PATH ${cache_external_subdir} real_external_subdir)
     set_property(GLOBAL PROPERTY "O3DE_SUBDIRECTORY_${real_external_subdir}" TRUE)
 endforeach()
 
-# The following functions is for gathering the list of external subdirectories
-# provided by the engine.json
-function(add_engine_gem_json_external_subdirectories gem_path)
+# The visited_gem_name_set is used to append the external_subdirectories found
+# within descendant gems to the parants to the globl O3DE_EXTERNAL_SUBDIRS_GEM_<gem_name> property
+# i.e If `GemA` "external_subdirectories" points to `GemB` and `GemB` external_subdirectories
+# points to `GemC`.
+# Then O3DE_EXTERNAL_SUBDIRS_GEM_GemA = [<AbsPath GemB>, <AbsPath GemC>]
+# And O3DE_EXTERNAL_SUBDIRS_GEM_GemB = [<AbsPath GemC>]
+#! add_o3de_object_gem_json_external_subdirectories : Recurses through external subdirectories
+#! originally found in the add_*_json_external_subdirectories command
+function(add_o3de_object_gem_json_external_subdirectories object_type object_name gem_path visited_gem_name_set_ref)
     set(gem_json_path ${gem_path}/gem.json)
     if(EXISTS ${gem_json_path})
+        o3de_read_json_external_subdirs(gem_external_subdirs ${gem_path}/gem.json)
         # Read the gem_name from the gem.json and map it to the gem path
         o3de_read_json_key(gem_name "${gem_path}/gem.json" "gem_name")
         if (gem_name)
             set_property(GLOBAL PROPERTY "@GEMROOT:${gem_name}@" "${gem_path}")
         endif()
 
-        o3de_read_json_external_subdirs(gem_external_subdirs "${gem_path}/gem.json")
+        # Push the gem name onto the visited set
+        list(APPEND ${visited_gem_name_set_ref} ${gem_name})
         foreach(gem_external_subdir IN LISTS gem_external_subdirs)
             file(REAL_PATH ${gem_external_subdir} real_external_subdir BASE_DIRECTORY ${gem_path})
 
-            # Append external subdirectory ONLY to LY_EXTERNAL_SUBDIRS_ENGINE PROPERTY
-            get_property(current_external_subdirs GLOBAL PROPERTY LY_EXTERNAL_SUBDIRS_ENGINE)
-            if(NOT real_external_subdir IN_LIST current_external_subdirs)
-                set_property(GLOBAL APPEND PROPERTY LY_EXTERNAL_SUBDIRS_ENGINE ${real_external_subdir})
-                set_property(GLOBAL PROPERTY "O3DE_SUBDIRECTORY_${real_external_subdir}" TRUE)
-                add_engine_gem_json_external_subdirectories(${real_external_subdir})
+            if(NOT object_name STREQUAL "")
+                # Append external subdirectory to the O3DE_EXTERNAL_SUBDIRS_${object_type}_${object_name} PROPERTY
+                set(object_external_subdir_property_name O3DE_EXTERNAL_SUBDIRS_${object_type}_${object_name})
+            else()
+                # Append external subdirectory to the O3DE_EXTERNAL_SUBDIRS_${object_type} PROPERTY
+                set(object_external_subdir_property_name O3DE_EXTERNAL_SUBDIRS_${object_type})
             endif()
-        endforeach()
-    endif()
-endfunction()
 
-function(add_engine_json_external_subdirectories)
-    set(engine_json_path ${LY_ROOT_FOLDER}/engine.json)
-    if(EXISTS ${engine_json_path})
-        o3de_read_json_external_subdirs(engine_external_subdirs ${engine_json_path})
-        foreach(engine_external_subdir IN LISTS engine_external_subdirs)
-            file(REAL_PATH ${engine_external_subdir} real_external_subdir BASE_DIRECTORY ${LY_ROOT_FOLDER})
-
-            # Append external subdirectory ONLY to LY_EXTERNAL_SUBDIRS_ENGINE PROPERTY
-            get_property(current_external_subdirs GLOBAL PROPERTY LY_EXTERNAL_SUBDIRS_ENGINE)
+            get_property(current_external_subdirs GLOBAL PROPERTY ${object_external_subdir_property_name})
             if(NOT real_external_subdir IN_LIST current_external_subdirs)
-                set_property(GLOBAL APPEND PROPERTY LY_EXTERNAL_SUBDIRS_ENGINE ${real_external_subdir})
+                set_property(GLOBAL APPEND PROPERTY ${object_external_subdir_property_name} "${real_external_subdir}")
                 set_property(GLOBAL PROPERTY "O3DE_SUBDIRECTORY_${real_external_subdir}" TRUE)
-                add_engine_gem_json_external_subdirectories(${real_external_subdir})
+                foreach(visited_gem_name IN LISTS ${visited_gem_name_set_ref})
+                    # Append the external subdirectories that come with the gem to
+                    # the visited_gem_set O3DE_EXTERNAL_SUBDIRS_GEM_<gem-name> properties as well
+                    set_property(GLOBAL APPEND PROPERTY O3DE_EXTERNAL_SUBDIRS_GEM_${visited_gem_name} ${real_external_subdir})
+                endforeach()
+                add_o3de_object_gem_json_external_subdirectories("${object_type}" "${object_name}" "${real_external_subdir}" "${visited_gem_name_set_ref}")
             endif()
         endforeach()
+        # Pop the gem name from the visited set
+        list(POP_BACK ${visited_gem_name_set_ref})
     endif()
 endfunction()
 
-
-# The following functions is for gathering the list of external subdirectories
-# provided by the project.json
-function(add_project_gem_json_external_subdirectories gem_path project_name)
-    set(gem_json_path ${gem_path}/gem.json)
-    if(EXISTS ${gem_json_path})
-        o3de_read_json_external_subdirs(gem_external_subdirs ${gem_path}/gem.json)
-        # Read the gem_name from the gem.json and map it to the gem path
-        o3de_read_json_key(gem_name "${gem_path}/gem.json" "gem_name")
-        if (gem_name)
-            set_property(GLOBAL PROPERTY "@GEMROOT:${gem_name}@" "${gem_path}")
-        endif()
-
-        foreach(gem_external_subdir IN LISTS gem_external_subdirs)
-            file(REAL_PATH ${gem_external_subdir} real_external_subdir BASE_DIRECTORY ${gem_path})
-
-            # Append external subdirectory ONLY to LY_EXTERNAL_SUBDIRS_${project_name} PROPERTY
-            get_property(current_external_subdirs GLOBAL PROPERTY LY_EXTERNAL_SUBDIRS_${project_name})
-            if(NOT real_external_subdir IN_LIST current_external_subdirs)
-                set_property(GLOBAL APPEND PROPERTY LY_EXTERNAL_SUBDIRS_${project_name} ${real_external_subdir})
-                set_property(GLOBAL PROPERTY "O3DE_SUBDIRECTORY_${real_external_subdir}" TRUE)
-                add_project_gem_json_external_subdirectories(${real_external_subdir} "${project_name}")
+#! add_o3de_object_json_external_subdirectories:
+#! Returns the external_subdirectories referenced by the supplied <o3de_object>.json
+#! This will recurse through to check for gem.json external_subdirectories
+#! via calling the *_gem_json_extenal_subdirectories variant of this function
+function(add_o3de_object_json_external_subdirectories object_type object_name object_path object_json_filename)
+    set(object_json_path ${object_path}/${object_json_filename})
+    if(EXISTS ${object_json_path})
+        o3de_read_json_external_subdirs(object_external_subdirs ${object_json_path})
+        foreach(object_external_subdir IN LISTS object_external_subdirs)
+            file(REAL_PATH ${object_external_subdir} real_external_subdir BASE_DIRECTORY ${object_path})
+
+            # Append external subdirectory ONLY to O3DE_EXTERNAL_SUBDIRS_PROJECT_${project_name} PROPERTY
+            if(NOT object_name STREQUAL "")
+                # Append external subdirectory to the O3DE_EXTERNAL_SUBDIRS_${object_type}_${object_name} PROPERTY
+                set(object_external_subdir_property_name O3DE_EXTERNAL_SUBDIRS_${object_type}_${object_name})
+            else()
+                # Append external subdirectory to the O3DE_EXTERNAL_SUBDIRS_${object_type} PROPERTY
+                set(object_external_subdir_property_name O3DE_EXTERNAL_SUBDIRS_${object_type})
             endif()
-        endforeach()
-    endif()
-endfunction()
 
-function(add_project_json_external_subdirectories project_path project_name)
-    set(project_json_path ${project_path}/project.json)
-    if(EXISTS ${project_json_path})
-        o3de_read_json_external_subdirs(project_external_subdirs ${project_path}/project.json)
-        foreach(project_external_subdir IN LISTS project_external_subdirs)
-            file(REAL_PATH ${project_external_subdir} real_external_subdir BASE_DIRECTORY ${project_path})
-
-            # Append external subdirectory ONLY to LY_EXTERNAL_SUBDIRS_${project_name} PROPERTY
-            get_property(current_external_subdirs GLOBAL PROPERTY LY_EXTERNAL_SUBDIRS_${project_name})
+            get_property(current_external_subdirs GLOBAL PROPERTY ${object_external_subdir_property_name})
             if(NOT real_external_subdir IN_LIST current_external_subdirs)
-                set_property(GLOBAL APPEND PROPERTY LY_EXTERNAL_SUBDIRS_${project_name} ${real_external_subdir})
+                set_property(GLOBAL APPEND PROPERTY ${object_external_subdir_property_name} "${real_external_subdir}")
                 set_property(GLOBAL PROPERTY "O3DE_SUBDIRECTORY_${real_external_subdir}" TRUE)
-                add_project_gem_json_external_subdirectories(${real_external_subdir} "${project_name}")
+                set(visited_gem_name_set)
+                add_o3de_object_gem_json_external_subdirectories("${object_type}" "${object_name}" "${real_external_subdir}" visited_gem_name_set)
             endif()
         endforeach()
     endif()
 endfunction()
 
+# The following functions is for gathering the list of external subdirectories
+# provided by the engine.json
+function(add_engine_json_external_subdirectories)
+    add_o3de_object_json_external_subdirectories("ENGINE" "" "${LY_ROOT_FOLDER}" "engine.json")
+endfunction()
 
-#! add_o3de_manifest_gem_json_external_subdirectories : Recurses through external subdirectories
-#! originally found in the add_o3de_manifest_json_external_subdirectories command
-function(add_o3de_manifest_gem_json_external_subdirectories gem_path)
-    set(gem_json_path ${gem_path}/gem.json)
-    if(EXISTS ${gem_json_path})
-        o3de_read_json_external_subdirs(gem_external_subdirs ${gem_path}/gem.json)
-        # Read the gem_name from the gem.json and map it to the gem path
-        o3de_read_json_key(gem_name "${gem_path}/gem.json" "gem_name")
-        if (gem_name)
-            set_property(GLOBAL PROPERTY "@GEMROOT:${gem_name}@" "${gem_path}")
-        endif()
-
-        foreach(gem_external_subdir IN LISTS gem_external_subdirs)
-            file(REAL_PATH ${gem_external_subdir} real_external_subdir BASE_DIRECTORY ${gem_path})
 
-            # Append external subdirectory ONLY to LY_EXTERNAL_SUBDIRS_O3DE_MANIFEST PROPERTY
-            get_property(current_external_subdirs GLOBAL PROPERTY LY_EXTERNAL_SUBDIRS_O3DE_MANIFEST)
-            if(NOT real_external_subdir IN_LIST current_external_subdirs)
-                set_property(GLOBAL APPEND PROPERTY LY_EXTERNAL_SUBDIRS_O3DE_MANIFEST ${real_external_subdir})
-                set_property(GLOBAL PROPERTY "O3DE_SUBDIRECTORY_${real_external_subdir}" TRUE)
-                add_o3de_manifest_gem_json_external_subdirectories(${real_external_subdir})
-            endif()
-        endforeach()
-    endif()
+# The following functions is for gathering the list of external subdirectories
+# provided by the project.json
+function(add_project_json_external_subdirectories project_path project_name)
+    add_o3de_object_json_external_subdirectories("PROJECT" "${project_name}" "${project_path}" "project.json")
 endfunction()
 
 #! add_o3de_manifest_json_external_subdirectories : Adds the list of external_subdirectories
-#! in the user o3de_manifest.json to the LY_EXTERNAL_SUBDIRS_O3DE_MANIFEST property
+#! in the user o3de_manifest.json to the O3DE_EXTERNAL_SUBDIRS_O3DE_MANIFEST property
 function(add_o3de_manifest_json_external_subdirectories)
+    # Retrieves the path to the o3de_manifest.json(includes the name)
     o3de_get_manifest_path(manifest_path)
-    if(EXISTS ${manifest_path})
-        o3de_read_json_external_subdirs(o3de_manifest_external_subdirs ${manifest_path})
-        foreach(manifest_external_subdir IN LISTS o3de_manifest_external_subdirs)
-            file(REAL_PATH ${manifest_external_subdir} real_external_subdir BASE_DIRECTORY ${LY_ROOT_FOLDER})
+    # Separate the o3de_manifest.json from the path to it
+    cmake_path(GET manifest_path FILENAME manifest_json_name)
+    cmake_path(GET manifest_path PARENT_PATH manifest_path)
 
-            # Append external subdirectory ONLY to LY_EXTERNAL_SUBDIRS_O3DE_MANIFEST PROPERTY
-            get_property(current_external_subdirs GLOBAL PROPERTY LY_EXTERNAL_SUBDIRS_O3DE_MANIFEST)
-            if(NOT real_external_subdir IN_LIST current_external_subdirs)
-                set_property(GLOBAL APPEND PROPERTY LY_EXTERNAL_SUBDIRS_O3DE_MANIFEST ${real_external_subdir})
-                set_property(GLOBAL PROPERTY "O3DE_SUBDIRECTORY_${real_external_subdir}" TRUE)
-                add_o3de_manifest_gem_json_external_subdirectories(${real_external_subdir})
-            endif()
-        endforeach()
-    endif()
+    add_o3de_object_json_external_subdirectories("O3DE_MANIFEST" "" "${manifest_path}" "${manifest_json_name}")
 endfunction()
 
 #! Gather unique_list of all external subdirectories that is union
 #! of the engine.json, project.json, o3de_manifest.json and any gem.json files found visiting
 function(get_all_external_subdirectories output_subdirs)
     # Gather user supplied external subdirectories via the Cache Variable
-    get_property(all_external_subdirs GLOBAL PROPERTY LY_EXTERNAL_SUBDIRS)
-    get_property(manifest_external_subdirs GLOBAL PROPERTY LY_EXTERNAL_SUBDIRS_O3DE_MANIFEST)
+    get_property(all_external_subdirs GLOBAL PROPERTY O3DE_EXTERNAL_SUBDIRS)
+    get_property(manifest_external_subdirs GLOBAL PROPERTY O3DE_EXTERNAL_SUBDIRS_O3DE_MANIFEST)
     list(APPEND all_external_subdirs ${manifest_external_subdirs})
-    get_property(engine_external_subdirs GLOBAL PROPERTY LY_EXTERNAL_SUBDIRS_ENGINE)
+    get_property(engine_external_subdirs GLOBAL PROPERTY O3DE_EXTERNAL_SUBDIRS_ENGINE)
     list(APPEND all_external_subdirs ${engine_external_subdirs})
 
     # Gather the list of every configured project external subdirectory
     # and and append them to the list of external subdirectories
     get_property(project_names GLOBAL PROPERTY O3DE_PROJECTS_NAME)
     foreach(project_name IN LISTS project_names)
-        get_property(project_external_subdirs GLOBAL PROPERTY LY_EXTERNAL_SUBDIRS_${project_name})
+        get_property(project_external_subdirs GLOBAL PROPERTY O3DE_EXTERNAL_SUBDIRS_PROJECT_${project_name})
         list(APPEND all_external_subdirs ${project_external_subdirs})
     endforeach()
 
@@ -275,51 +243,60 @@ function(reorder_dependent_gems_before_external_subdirs output_gem_subdirs subdi
     set(${output_gem_subdirs} ${output_external_dirs} PARENT_SCOPE)
 endfunction()
 
-#! Gather unique_list of all external subdirectories that the project provides or uses
+#! Gather unique_list of all external subdirectories that the o3de object provides or uses
 #! The list is made up of the following
-#! - The paths of gems referenced in the project.json "gem_names" key. Those paths are queried
+#! - The paths of gems referenced in the <o3de_object>.json "gem_names" key. Those paths are queried
 #!   from the "external_subdirectories" in o3de_manifest.json
-#! - The project path
-#! - The list of external_subdirectories found by recursively visting the project.json "external_subdirectories"
-function(get_all_external_subdirectories_for_project output_subdirs project_name project_path)
-    # Append the gems referenced by name from "gem_names" field in the project.json
+#! - The <o3de_object> path
+#! - The list of external_subdirectories found by recursively visting the <o3de_object>.json "external_subdirectories"
+function(get_all_external_subdirectories_for_o3de_object output_subdirs object_type object_name object_path object_json_filename)
+    # Append the gems referenced by name from "gem_names" field in the <object>.json
     # These gems are registered in the users o3de_manifest.json
-    o3de_read_json_array(gem_names ${project_path}/project.json "gem_names")
-    add_registered_gems_to_external_subdirs(project_gem_reference_dirs "${gem_names}")
-    list(APPEND subdirs_for_project ${project_gem_reference_dirs})
+    o3de_read_json_array(gem_names ${object_path}/${object_json_filename} "gem_names")
+    add_registered_gems_to_external_subdirs(object_gem_reference_dirs "${gem_names}")
+    list(APPEND subdirs_for_object ${object_gem_reference_dirs})
+
+    # Also append the array the "external_subdirectories" from each gem referenced through the "gem_names"
+    # field
+    foreach(gem_name IN LISTS gem_names)
+        get_property(gem_real_external_subdirs GLOBAL PROPERTY O3DE_EXTERNAL_SUBDIRS_GEM_${gem_name})
+        list(APPEND subdirs_for_object ${gem_real_external_subdirs})
+    endforeach()
 
-    # Append the project root path to the list of external subdirectories so that it is visited
-    list(APPEND subdirs_for_project ${project_path})
+    # Append the list of external_subdirectories that come with the object
+    if(NOT object_name STREQUAL "")
+        # query the O3DE_EXTERNAL_SUBDIRS_${object_type}_${object_name} PROPERTY
+        set(object_external_subdir_property_name O3DE_EXTERNAL_SUBDIRS_${object_type}_${object_name})
+    else()
+        # query the O3DE_EXTERNAL_SUBDIRS_${object_type} PROPERTY
+        set(object_external_subdir_property_name O3DE_EXTERNAL_SUBDIRS_${object_type})
+    endif()
 
-    # Append the list of external_subdirectories that come with the project
-    get_property(project_external_subdirs GLOBAL PROPERTY LY_EXTERNAL_SUBDIRS_${project_name})
-    list(APPEND subdirs_for_project ${project_external_subdirs})
+    get_property(object_external_subdirs GLOBAL PROPERTY ${object_external_subdir_property_name})
+    list(APPEND subdirs_for_object ${object_external_subdirs})
 
-    list(REMOVE_DUPLICATES subdirs_for_project)
-    set(${output_subdirs} ${subdirs_for_project} PARENT_SCOPE)
+    list(REMOVE_DUPLICATES subdirs_for_object)
+    set(${output_subdirs} ${subdirs_for_object} PARENT_SCOPE)
 endfunction()
 
 #! Gather the unqiue list of all external subdirectories that the engine provides("external_subdirectories")
 #! plus all external subdirectories that every active project provides("external_subdirectories")
 #! or references("gem_names")
 function(get_external_subdirectories_in_use output_subdirs)
-    # Gather the list of external subdirectories set through the LY_EXTERNAL_SUBDIRS Cache Variable
-    get_property(all_external_subdirs CACHE LY_EXTERNAL_SUBDIRS PROPERTY VALUE)
+    # Gather the list of external subdirectories set through the O3DE_EXTERNAL_SUBDIRS Cache Variable
+    get_property(all_external_subdirs CACHE O3DE_EXTERNAL_SUBDIRS PROPERTY VALUE)
     # Append the list of external subdirectories from the engine.json
-    get_property(engine_external_subdirs GLOBAL PROPERTY LY_EXTERNAL_SUBDIRS_ENGINE)
+    get_all_external_subdirectories_for_o3de_object(engine_external_subdirs "ENGINE" "" ${LY_ROOT_FOLDER} "engine.json")
     list(APPEND all_external_subdirs ${engine_external_subdirs})
-    # Append the gems referenced by name from "gem_names" field in the engine.json
-    # These gems are registered in the users o3de_manifest.json
-    o3de_read_json_array(gem_names ${LY_ROOT_FOLDER}/engine.json "gem_names")
-    add_registered_gems_to_external_subdirs(engine_gem_reference_dirs "${gem_names}")
-    list(APPEND all_external_subdirs ${engine_gem_reference_dirs})
 
     # Visit each LY_PROJECTS entry and append the external subdirectories
     # the project provides and references
     get_property(O3DE_PROJECTS_NAME GLOBAL PROPERTY O3DE_PROJECTS_NAME)
     foreach(project_name project_path IN ZIP_LISTS O3DE_PROJECTS_NAME LY_PROJECTS)
         file(REAL_PATH ${project_path} full_directory_path BASE_DIRECTORY ${CMAKE_SOURCE_DIR})
-        get_all_external_subdirectories_for_project(external_subdirs ${project_name} ${full_directory_path} )
+        # Append the project root path to the list of external subdirectories so that it is visited
+        list(APPEND all_external_subdirs ${project_path})
+        get_all_external_subdirectories_for_o3de_object(external_subdirs "PROJECT" "${project_name}" ${full_directory_path} "project.json")
         list(APPEND all_external_subdirs ${external_subdirs})
     endforeach()