diff --git a/Sources/CMakeLists.txt b/Sources/CMakeLists.txt
index ef235c43f..0c7af685c 100644
--- a/Sources/CMakeLists.txt
+++ b/Sources/CMakeLists.txt
@@ -12,6 +12,38 @@
 ##
 ##===----------------------------------------------------------------------===##
 
+add_library(FoundationBuildMacros INTERFACE)
+export(TARGETS FoundationBuildMacros
+    FILE
+        ${SwiftFoundation_BINARY_DIR}/cmake/modules/FoundationBuildMacros.cmake)
+if(SwiftFoundation_MACRO)
+    message(STATUS "SwiftFoundation_MACRO provided, using macros in ${SwiftFoundation_MACRO}")
+    target_compile_options(FoundationBuildMacros INTERFACE
+        "SHELL:$<BUILD_INTERFACE:$<$<COMPILE_LANGUAGE:Swift>:-plugin-path ${SwiftFoundation_MACRO}>>")
+else()
+    message(STATUS "NO SwiftFoundation_MACRO, building macros from scratch")
+    include(ExternalProject)
+    # The macros are required for building Swift-Foundation. Build them for the
+    # build machine.
+    ExternalProject_Add(FoundationMacros
+        SOURCE_DIR "${CMAKE_CURRENT_SOURCE_DIR}/FoundationMacros"
+        INSTALL_DIR "${CMAKE_CURRENT_BINARY_DIR}/FoundationMacros"
+        CMAKE_ARGS
+            -DCMAKE_BUILD_TYPE=Release
+            -DCMAKE_Swift_COMPILER=${CMAKE_Swift_COMPILER}
+            -DCMAKE_INSTALL_PREFIX=<INSTALL_DIR>
+            -DSwiftFoundation_BUILD_EXECUTABLE_MACROS=YES)
+    ExternalProject_Get_Property(FoundationMacros INSTALL_DIR)
+    add_dependencies(FoundationBuildMacros FoundationMacros)
+    if(CMAKE_HOST_WIN32)
+        set(_SwiftFoundation_HOST_EXECUTABLE_SUFFIX .exe)
+    endif()
+
+    target_compile_options(FoundationBuildMacros INTERFACE
+        "SHELL:$<BUILD_INTERFACE:$<$<COMPILE_LANGUAGE:Swift>:-load-plugin-executable ${INSTALL_DIR}/bin/FoundationMacros${_SwiftFoundation_HOST_EXECUTABLE_SUFFIX}#FoundationMacros>>")
+    unset(_SwiftFoundation_HOST_EXECUTABLE_SUFFIX)
+endif()
+
 add_subdirectory(_FoundationCShims)
 add_subdirectory(FoundationEssentials)
 add_subdirectory(FoundationInternationalization)
diff --git a/Sources/FoundationEssentials/CMakeLists.txt b/Sources/FoundationEssentials/CMakeLists.txt
index 9c1f5b462..1fc475380 100644
--- a/Sources/FoundationEssentials/CMakeLists.txt
+++ b/Sources/FoundationEssentials/CMakeLists.txt
@@ -49,29 +49,6 @@ add_subdirectory(String)
 add_subdirectory(TimeZone)
 add_subdirectory(URL)
 
-if(SwiftFoundation_MACRO)
-    message(STATUS "SwiftFoundation_MACRO provided, using macros in ${SwiftFoundation_MACRO}")
-    # A path to Foundation macros was provided, so we use that path
-    target_compile_options(FoundationEssentials PRIVATE
-        "SHELL:-plugin-path ${SwiftFoundation_MACRO}")
-else()
-    message(STATUS "SwiftFoundation_MACRO not provided, building Foundation macros locally for host")
-    # No path to Foundation macros was provided, so we must build it ourselves
-    set(FoundationMacros_BuildLocalExecutable YES)
-    FetchContent_Declare(FoundationMacros
-        SOURCE_DIR ${SwiftFoundation_SOURCE_DIR}/Sources/FoundationMacros)
-    FetchContent_MakeAvailable(FoundationMacros)
-    add_dependencies(FoundationEssentials FoundationMacros)
-    get_target_property(MacroDIR FoundationMacros RUNTIME_OUTPUT_DIRECTORY)
-    if(CMAKE_SYSTEM_NAME STREQUAL Windows)
-        set(MacroExecutable "${MacroDIR}/FoundationMacros.exe#FoundationMacros")
-    else()
-        set(MacroExecutable "${MacroDIR}/FoundationMacros#FoundationMacros")
-    endif()
-    target_compile_options(FoundationEssentials PUBLIC
-        "SHELL:$<$<COMPILE_LANGUAGE:Swift>:-load-plugin-executable ${MacroExecutable}>")
-endif()
-
 if(CMAKE_SYSTEM_NAME STREQUAL Linux OR CMAKE_SYSTEM_NAME STREQUAL Android)
     target_compile_options(FoundationEssentials PRIVATE
         "SHELL:$<$<COMPILE_LANGUAGE:Swift>:-Xfrontend -Xcc -Xfrontend -D_GNU_SOURCE>")
@@ -88,6 +65,7 @@ target_compile_options(FoundationEssentials PRIVATE ${_SwiftFoundation_wasi_libc
 target_compile_options(FoundationEssentials PRIVATE -package-name "SwiftFoundation")
 
 target_link_libraries(FoundationEssentials PUBLIC
+    FoundationBuildMacros
     _FoundationCShims
     _FoundationCollections)
 target_link_libraries(FoundationEssentials PUBLIC ${_SwiftFoundation_wasi_libc_libraries})
diff --git a/Sources/FoundationMacros/CMakeLists.txt b/Sources/FoundationMacros/CMakeLists.txt
index 98b90c0df..0815b5884 100644
--- a/Sources/FoundationMacros/CMakeLists.txt
+++ b/Sources/FoundationMacros/CMakeLists.txt
@@ -26,6 +26,9 @@ endif()
 project(FoundationMacros
   LANGUAGES Swift)
 
+option(SwiftFoundation_BUILD_EXECUTABLE_MACROS
+  "Build the FoundationMacros as an executable" NO)
+
 if(NOT SWIFT_SYSTEM_NAME)
   if(CMAKE_SYSTEM_NAME STREQUAL Darwin)
     set(SWIFT_SYSTEM_NAME macosx)
@@ -49,13 +52,13 @@ else()
   message(STATUS "SwiftSyntax_DIR provided, using swift-syntax from ${SwiftSyntax_DIR}")
 endif()
 
-if(NOT FoundationMacros_BuildLocalExecutable)
-    add_library(FoundationMacros SHARED)
-    target_compile_definitions(FoundationMacros PRIVATE FOUNDATION_MACROS_LIBRARY)
-else()
+if(SwiftFoundation_BUILD_EXECUTABLE_MACROS)
     add_executable(FoundationMacros)
     target_link_libraries(FoundationMacros PUBLIC
         SwiftSyntax::SwiftCompilerPlugin)
+else()
+    add_library(FoundationMacros SHARED)
+    target_compile_definitions(FoundationMacros PRIVATE FOUNDATION_MACROS_LIBRARY)
 endif()
 
 # Parse the module as a library, even if it's an executable, because it uses an `@main` type to define its entry point.
@@ -90,8 +93,6 @@ set_target_properties(FoundationMacros PROPERTIES
     INSTALL_RPATH "$ORIGIN/../../../swift/${SWIFT_SYSTEM_NAME}:$ORIGIN/.."
     INSTALL_REMOVE_ENVIRONMENT_RPATH ON)
 
-if(NOT FoundationMacros_BuildLocalExecutable)
-    install(TARGETS FoundationMacros
-        LIBRARY DESTINATION lib/swift/host/plugins
-        RUNTIME DESTINATION bin)
-endif()
+install(TARGETS FoundationMacros
+    LIBRARY DESTINATION lib/swift/host/plugins
+    RUNTIME DESTINATION bin)
diff --git a/cmake/modules/CMakeLists.txt b/cmake/modules/CMakeLists.txt
index 996788612..2c498378e 100644
--- a/cmake/modules/CMakeLists.txt
+++ b/cmake/modules/CMakeLists.txt
@@ -12,6 +12,7 @@
 ##
 ##===----------------------------------------------------------------------===##
 
+set(SWIFT_FOUNDATION_BUILD_MACROS_FILE ${CMAKE_CURRENT_BINARY_DIR}/FoundationBuildMacros.cmake)
 set(SWIFT_FOUNDATION_EXPORTS_FILE ${CMAKE_CURRENT_BINARY_DIR}/SwiftFoundationExports.cmake)
 set(SWIFT_FOUNDATION_ICU_EXPORTS_FILE ${SwiftFoundationICU_BINARY_DIR}/cmake/modules/SwiftFoundationICUExports.cmake)
 set(SWIFT_COLLECTIONS_EXPORTS_FILE ${SwiftCollections_BINARY_DIR}/cmake/modules/SwiftCollectionsExports.cmake)
diff --git a/cmake/modules/SwiftFoundationConfig.cmake.in b/cmake/modules/SwiftFoundationConfig.cmake.in
index 1692f34ca..ad5bff33d 100644
--- a/cmake/modules/SwiftFoundationConfig.cmake.in
+++ b/cmake/modules/SwiftFoundationConfig.cmake.in
@@ -13,6 +13,7 @@
 ##===----------------------------------------------------------------------===##
 
 if(NOT TARGET SwiftFoundation)
+    include(@SWIFT_FOUNDATION_BUILD_MACROS_FILE@)
     include(@SWIFT_FOUNDATION_ICU_EXPORTS_FILE@)
     include(@SWIFT_COLLECTIONS_EXPORTS_FILE@)
     include(@SWIFT_FOUNDATION_EXPORTS_FILE@)