diff --git a/flang-rt/CMakeLists.txt b/flang-rt/CMakeLists.txt
index df35e24ec28a..50d1a5cb2a59 100644
--- a/flang-rt/CMakeLists.txt
+++ b/flang-rt/CMakeLists.txt
@@ -115,6 +115,15 @@ endif ()
 extend_path(FLANG_RT_INSTALL_RESOURCE_LIB_PATH "${FLANG_RT_INSTALL_RESOURCE_PATH}" "${toolchain_lib_subdir}")
 cmake_path(NORMAL_PATH FLANG_RT_OUTPUT_RESOURCE_DIR)
 cmake_path(NORMAL_PATH FLANG_RT_INSTALL_RESOURCE_PATH)
+# FIXME: For the libflang_rt.so, the toolchain resource lib dir is not a good
+#        destination because it is not a ld.so default search path.
+#        The machine where the executable is eventually executed may not be the
+#        machine where the Flang compiler and its resource dir is installed, so
+#        setting RPath by the driver is not an solution. It should belong into
+#        /usr/lib/<triple>/libflang_rt.so, like e.g. libgcc_s.so.
+#        But the linker as invoked by the Flang driver also requires
+#        libflang_rt.so to be found when linking and the resource lib dir is
+#        the only reliable location.
 cmake_path(NORMAL_PATH FLANG_RT_OUTPUT_RESOURCE_LIB_DIR)
 cmake_path(NORMAL_PATH FLANG_RT_INSTALL_RESOURCE_LIB_PATH)
 
@@ -129,6 +138,27 @@ cmake_path(NORMAL_PATH FLANG_RT_INSTALL_RESOURCE_LIB_PATH)
 option(FLANG_RT_INCLUDE_TESTS "Generate build targets for the flang-rt unit and regression-tests." "${LLVM_INCLUDE_TESTS}")
 
 
+option(FLANG_RT_ENABLE_STATIC "Build Flang-RT as a static library." ON)
+if (WIN32)
+  # Windows DLL currently not implemented.
+  set(FLANG_RT_ENABLE_SHARED OFF)
+else ()
+  # TODO: Enable by default to increase test coverage, and which version of the
+  #       library should be the user's choice anyway.
+  #       Currently, the Flang driver adds `-L"libdir" -lflang_rt` as linker
+  #       argument, which leaves the choice which library to use to the linker.
+  #       Since most linkers prefer the shared library, this would constitute a
+  #       breaking change unless the driver is changed.
+  option(FLANG_RT_ENABLE_SHARED "Build Flang-RT as a shared library." OFF)
+endif ()
+if (NOT FLANG_RT_ENABLE_STATIC AND NOT FLANG_RT_ENABLE_SHARED)
+  message(FATAL_ERROR "
+      Must build at least one type of library
+      (FLANG_RT_ENABLE_STATIC=ON, FLANG_RT_ENABLE_SHARED=ON, or both)
+    ")
+endif ()
+
+
 set(FLANG_RT_EXPERIMENTAL_OFFLOAD_SUPPORT "" CACHE STRING "Compile Flang-RT with GPU support (CUDA or OpenMP)")
 set_property(CACHE FLANG_RT_EXPERIMENTAL_OFFLOAD_SUPPORT PROPERTY STRINGS
     ""
diff --git a/flang-rt/cmake/modules/AddFlangRT.cmake b/flang-rt/cmake/modules/AddFlangRT.cmake
index 630aeb3c6500..a43f1c332187 100644
--- a/flang-rt/cmake/modules/AddFlangRT.cmake
+++ b/flang-rt/cmake/modules/AddFlangRT.cmake
@@ -16,7 +16,8 @@
 #   STATIC
 #     Build a static (.a/.lib) library
 #   OBJECT
-#     Create only object files without static/dynamic library
+#     Always create an object library.
+#     Without SHARED/STATIC, build only the object library.
 #   INSTALL_WITH_TOOLCHAIN
 #     Install library into Clang's resource directory so it can be found by the
 #     Flang driver during compilation, including tests
@@ -50,17 +51,73 @@ function (add_flangrt_library name)
       ")
   endif ()
 
-  # Forward libtype to add_library
-  set(extra_args "")
-  if (ARG_SHARED)
-    list(APPEND extra_args SHARED)
+  # Internal names of libraries. If called with just single type option, use
+  # the default name for it. Name of targets must only depend on function
+  # arguments to be predictable for callers.
+  set(name_static "${name}.static")
+  set(name_shared "${name}.shared")
+  set(name_object "obj.${name}")
+  if (ARG_STATIC AND NOT ARG_SHARED)
+    set(name_static "${name}")
+  elseif (NOT ARG_STATIC AND ARG_SHARED)
+    set(name_shared "${name}")
+  elseif (NOT ARG_STATIC AND NOT ARG_SHARED AND ARG_OBJECT)
+    set(name_object "${name}")
+  elseif (NOT ARG_STATIC AND NOT ARG_SHARED AND NOT ARG_OBJECT)
+    # Only one of them will actually be built.
+    set(name_static "${name}")
+    set(name_shared "${name}")
   endif ()
-  if (ARG_STATIC)
-    list(APPEND extra_args STATIC)
+
+  # Determine what to build. If not explicitly specified, honor
+  # BUILD_SHARED_LIBS (e.g. for unittest libraries). If can build static and
+  # shared, use ENABLE_STATIC/ENABLE_SHARED setting.
+  if (ARG_STATIC AND ARG_SHARED)
+    set(build_static ${FLANG_RT_ENABLE_STATIC})
+    set(build_shared ${FLANG_RT_ENABLE_SHARED})
+  else ()
+    set(build_static ${ARG_STATIC})
+    set(build_shared ${ARG_SHARED})
   endif ()
+  if (NOT ARG_STATIC AND NOT ARG_SHARED AND NOT ARG_OBJECT)
+    if (BUILD_SHARED_LIBS)
+      set(build_shared ON)
+    else ()
+      set(build_static ON)
+    endif ()
+  endif ()
+
+  # Build an object library if building multiple libraries at once or if
+  # explicitly requested.
+  set(build_object OFF)
   if (ARG_OBJECT)
-    list(APPEND extra_args OBJECT)
+    set(build_object ON)
+  elseif (build_static AND build_shared)
+    set(build_object ON)
   endif ()
+
+  # srctargets: targets that contain source files
+  # libtargets: static/shared if they are built
+  # alltargets: any add_library target added by this function
+  set(srctargets "")
+  set(libtargets "")
+  set(alltargets "")
+  if (build_static)
+    list(APPEND srctargets "${name_static}")
+    list(APPEND libtargets "${name_static}")
+    list(APPEND alltargets "${name_static}")
+  endif ()
+  if (build_shared)
+    list(APPEND srctargets "${name_shared}")
+    list(APPEND libtargets "${name_shared}")
+    list(APPEND alltargets "${name_shared}")
+  endif ()
+  if (build_object)
+    set(srctargets "${name_object}")
+    list(APPEND alltargets "${name_object}")
+  endif ()
+
+  set(extra_args "")
   if (ARG_EXCLUDE_FROM_ALL)
     list(APPEND extra_args EXCLUDE_FROM_ALL)
   endif ()
@@ -68,132 +125,191 @@ function (add_flangrt_library name)
   # Also add header files to IDEs to list as part of the library.
   set_source_files_properties(${ARG_ADDITIONAL_HEADERS} PROPERTIES HEADER_FILE_ONLY ON)
 
-  add_library(${name} ${extra_args} ${ARG_ADDITIONAL_HEADERS} ${ARG_UNPARSED_ARGUMENTS})
-
-  if (ARG_INSTALL_WITH_TOOLCHAIN)
-    set_target_properties(${name} PROPERTIES FOLDER "Flang-RT/Toolchain Libraries")
-  elseif (ARG_OBJECT)
-    set_target_properties(${name} PROPERTIES FOLDER "Flang-RT/Object Libraries")
-  else ()
-    set_target_properties(${name} PROPERTIES FOLDER "Flang-RT/Libraries")
-  endif ()
-
-  # Minimum required C++ version for Flang-RT, even if CMAKE_CXX_STANDARD is defined to something else.
-  target_compile_features(${name} PRIVATE cxx_std_17)
-
-  # Use compiler-specific options to disable exceptions and RTTI.
-  if (LLVM_COMPILER_IS_GCC_COMPATIBLE)
-    target_compile_options(${name} PRIVATE
-        $<$<COMPILE_LANGUAGE:CXX>:-fno-exceptions -fno-rtti -fno-unwind-tables -fno-asynchronous-unwind-tables>
-      )
-  elseif (MSVC)
-    target_compile_options(${name} PRIVATE
-        $<$<COMPILE_LANGUAGE:CXX>:/EHs-c- /GR->
-      )
-  elseif (CMAKE_CXX_COMPILER_ID MATCHES "XL")
-    target_compile_options(${name} PRIVATE
-        $<$<COMPILE_LANGUAGE:CXX>:-qnoeh -qnortti>
+  # Create selected library types.
+  if (build_object)
+    add_library("${name_object}" OBJECT ${extra_args} ${ARG_ADDITIONAL_HEADERS} ${ARG_UNPARSED_ARGUMENTS})
+    set_target_properties(${name_object} PROPERTIES
+        POSITION_INDEPENDENT_CODE ON
+        FOLDER "Flang-RT/Object Libraries"
       )
+
+    # Replace arguments for the libraries we are going to create.
+    set(ARG_ADDITIONAL_HEADERS "")
+    set(ARG_UNPARSED_ARGUMENTS "$<TARGET_OBJECTS:${name_object}>")
+  endif ()
+  if (build_static)
+    add_library("${name_static}" STATIC ${extra_args} ${ARG_ADDITIONAL_HEADERS} ${ARG_UNPARSED_ARGUMENTS})
+  endif ()
+  if (build_shared)
+    add_library("${name_shared}" SHARED ${extra_args} ${ARG_ADDITIONAL_HEADERS} ${ARG_UNPARSED_ARGUMENTS})
   endif ()
 
-  # Also for CUDA source when compiling with FLANG_RT_EXPERIMENTAL_OFFLOAD_SUPPORT=CUDA
-  if (CMAKE_CUDA_COMPILER_ID MATCHES "NVIDIA")
-    # Assuming gcc as host compiler.
-    target_compile_options(${name} PRIVATE
-        $<$<COMPILE_LANGUAGE:CUDA>:--no-exceptions -Xcompiler -fno-rtti -Xcompiler -fno-unwind-tables -Xcompiler -fno-asynchronous-unwind-tables>
-      )
-  else ()
-    # Assuming a clang-compatible CUDA compiler.
-    target_compile_options(${name} PRIVATE
-        $<$<COMPILE_LANGUAGE:CUDA>:-fno-exceptions -fno-rtti -fno-unwind-tables -fno-asynchronous-unwind-tables>
-      )
-  endif ()
-
-  # Flang-RT's public headers
-  target_include_directories(${name} PUBLIC "${FLANG_RT_SOURCE_DIR}/include")
-
-  # For ISO_Fortran_binding.h to be found by the runtime itself (Accessed as #include "flang/ISO_Fortran_binding.h")
-  # User applications can use #include <ISO_Fortran_binding.h>
-  target_include_directories(${name} PUBLIC "${FLANG_SOURCE_DIR}/include")
-
-  # For Flang-RT's configured config.h to be found
-  target_include_directories(${name} PRIVATE "${FLANG_RT_BINARY_DIR}")
-
-  # Disable libstdc++/libc++ assertions, even in an LLVM_ENABLE_ASSERTIONS
-  # build, to avoid an unwanted dependency on libstdc++/libc++.so.
-  if (FLANG_RT_SUPPORTS_UNDEFINE_FLAG)
-    target_compile_options(${name} PUBLIC -U_GLIBCXX_ASSERTIONS)
-    target_compile_options(${name} PUBLIC -U_LIBCPP_ENABLE_ASSERTIONS)
-  endif ()
-
-  # When building the flang runtime if LTO is enabled the archive file
-  # contains LLVM IR rather than object code. Currently flang is not
-  # LTO aware so cannot link this file to compiled Fortran code.
-  if (FLANG_RT_HAS_FNO_LTO_FLAG)
-    target_compile_options(${name} PRIVATE -fno-lto)
-  endif ()
-
-  # Flang/Clang (including clang-cl) -compiled programs targeting the MSVC ABI
-  # should only depend on msvcrt/ucrt. LLVM still emits libgcc/compiler-rt
-  # functions in some cases like 128-bit integer math (__udivti3, __modti3,
-  # __fixsfti, __floattidf, ...) that msvc does not support. We are injecting a
-  # dependency to Compiler-RT's builtin library where these are implemented.
-  if (MSVC AND CMAKE_CXX_COMPILER_ID MATCHES "Clang")
-    if (FLANG_RT_BUILTINS_LIBRARY)
-      target_compile_options(${name} PRIVATE "$<$<COMPILE_LANGUAGE:CXX,C>:-Xclang>" "$<$<COMPILE_LANGUAGE:CXX,C>:--dependent-lib=${FLANG_RT_BUILTINS_LIBRARY}>")
-    endif ()
-  endif ()
-  if (MSVC AND CMAKE_Fortran_COMPILER_ID STREQUAL "LLVMFlang")
-    if (FLANG_RT_BUILTINS_LIBRARY)
-      target_compile_options(${name} PRIVATE "$<$<COMPILE_LANGUAGE:Fortran>:-Xflang>" "$<$<COMPILE_LANGUAGE:Fortran>:--dependent-lib=${FLANG_RT_BUILTINS_LIBRARY}>")
+  if (libtargets)
+    # Provide a default alias which exists in either setting.
+    if (BUILD_SHARED_LIBS)
+      if (build_shared)
+        set(default_target "${name_shared}")
+      else ()
+        set(default_target "${name_static}")
+      endif ()
     else ()
-      message(WARNING "Did not find libclang_rt.builtins.lib.
-        LLVM may emit builtins that are not implemented in msvcrt/ucrt and
-        instead falls back to builtins from Compiler-RT. Linking with ${name}
-        may result in a linker error.")
+      if (build_static)
+        set(default_target "${name_static}")
+      else ()
+        set(default_target "${name_shared}")
+      endif ()
+    endif ()
+    add_library(${name}.default ALIAS "${default_target}")
+
+    # Provide a build target that builds any enabled library.
+    # Not intended for target_link_libraries. Either use the ${name}.static,
+    # ${name}.shared variants, or ${name}.default to let BUILD_SHARED_LIBS
+    # decide.
+    if (NOT TARGET ${name})
+      add_custom_target(${name})
+      add_dependencies(${name} ${libtargets})
     endif ()
   endif ()
 
-  # Non-GTest unittests depend on LLVMSupport
-  if (ARG_LINK_TO_LLVM)
-    if (LLVM_LINK_LLVM_DYLIB)
-      set(llvm_libs LLVM)
-    else()
-      llvm_map_components_to_libnames(llvm_libs Support)
-    endif()
-    target_link_libraries(${name} PUBLIC ${llvm_libs})
-    target_include_directories(${name} PUBLIC ${LLVM_INCLUDE_DIRS})
-  endif ()
+  foreach (tgtname IN LISTS libtargets)
+    if (NOT WIN32)
+      # Use same stem name for .a and .so. Common in UNIX environments.
+      # Not possible in Windows environments.
+      set_target_properties(${tgtname} PROPERTIES OUTPUT_NAME "${name}")
+    endif ()
 
-  if (ARG_INCLUDE_DIRECTORIES)
-    target_include_directories(${name} ${ARG_INCLUDE_DIRECTORIES})
-  endif ()
+    if (ARG_INSTALL_WITH_TOOLCHAIN)
+      set_target_properties(${tgtname} PROPERTIES FOLDER "Flang-RT/Toolchain Libraries")
+    else ()
+      set_target_properties(${tgtname} PROPERTIES FOLDER "Flang-RT/Libraries")
+    endif ()
+  endforeach ()
 
-  if (ARG_LINK_LIBRARIES)
-    target_link_libraries(${name} PUBLIC ${ARG_LINK_LIBRARIES})
-  endif ()
+  # Define how to compile and link the library.
+  # Some conceptionally only apply to ${srctargets} or ${libtargets}, but we
+  # apply them to ${alltargets}. In worst case, they are ignored by CMake.
+  foreach (tgtname IN LISTS alltargets)
+    # Minimum required C++ version for Flang-RT, even if CMAKE_CXX_STANDARD is defined to something else.
+    target_compile_features(${tgtname} PRIVATE cxx_std_17)
 
-  # If this is part of the toolchain, put it into the compiler's resource
-  # directory. Otherwise it is part of testing and is not installed at all.
-  # TODO: Consider multi-configuration builds (MSVC_IDE, "Ninja Multi-Config")
-  if (ARG_INSTALL_WITH_TOOLCHAIN)
-    set_target_properties(${name}
-      PROPERTIES
-        ARCHIVE_OUTPUT_DIRECTORY "${FLANG_RT_OUTPUT_RESOURCE_LIB_DIR}"
-      )
+    # Use compiler-specific options to disable exceptions and RTTI.
+    if (LLVM_COMPILER_IS_GCC_COMPATIBLE)
+      target_compile_options(${tgtname} PRIVATE
+          $<$<COMPILE_LANGUAGE:CXX>:-fno-exceptions -fno-rtti -fno-unwind-tables -fno-asynchronous-unwind-tables>
+        )
+    elseif (MSVC)
+      target_compile_options(${tgtname} PRIVATE
+          $<$<COMPILE_LANGUAGE:CXX>:/EHs-c- /GR->
+        )
+    elseif (CMAKE_CXX_COMPILER_ID MATCHES "XL")
+      target_compile_options(${tgtname} PRIVATE
+          $<$<COMPILE_LANGUAGE:CXX>:-qnoeh -qnortti>
+        )
+    endif ()
 
-    install(TARGETS ${name}
-        ARCHIVE DESTINATION "${FLANG_RT_INSTALL_RESOURCE_LIB_PATH}"
-      )
-  endif ()
+    # Also for CUDA source when compiling with FLANG_RT_EXPERIMENTAL_OFFLOAD_SUPPORT=CUDA
+    if (CMAKE_CUDA_COMPILER_ID MATCHES "NVIDIA")
+      # Assuming gcc as host compiler.
+      target_compile_options(${tgtname} PRIVATE
+          $<$<COMPILE_LANGUAGE:CUDA>:--no-exceptions -Xcompiler -fno-rtti -Xcompiler -fno-unwind-tables -Xcompiler -fno-asynchronous-unwind-tables>
+        )
+    else ()
+      # Assuming a clang-compatible CUDA compiler.
+      target_compile_options(${tgtname} PRIVATE
+          $<$<COMPILE_LANGUAGE:CUDA>:-fno-exceptions -fno-rtti -fno-unwind-tables -fno-asynchronous-unwind-tables>
+        )
+    endif ()
 
-  if (ARG_TARGET_PROPERTIES)
-    set_target_properties(${name} PROPERTIES ${ARG_TARGET_PROPERTIES})
-  endif ()
+    # Flang-RT's public headers
+    target_include_directories(${tgtname} PUBLIC "${FLANG_RT_SOURCE_DIR}/include")
 
-  # flang-rt should build all the Flang-RT targets that are built in an
-  # 'all' build.
-  if (NOT ARG_EXCLUDE_FROM_ALL)
-    add_dependencies(flang-rt ${name})
-  endif ()
+    # For ISO_Fortran_binding.h to be found by the runtime itself (Accessed as #include "flang/ISO_Fortran_binding.h")
+      # User applications can use #include <ISO_Fortran_binding.h>
+  target_include_directories(${tgtname} PUBLIC "${FLANG_SOURCE_DIR}/include")
+
+    # For Flang-RT's configured config.h to be found
+    target_include_directories(${tgtname} PRIVATE "${FLANG_RT_BINARY_DIR}")
+
+    # Disable libstdc++/libc++ assertions, even in an LLVM_ENABLE_ASSERTIONS
+    # build, to avoid an unwanted dependency on libstdc++/libc++.so.
+    if (FLANG_RT_SUPPORTS_UNDEFINE_FLAG)
+      target_compile_options(${tgtname} PUBLIC -U_GLIBCXX_ASSERTIONS)
+      target_compile_options(${tgtname} PUBLIC -U_LIBCPP_ENABLE_ASSERTIONS)
+    endif ()
+
+    # When building the flang runtime if LTO is enabled the archive file
+    # contains LLVM IR rather than object code. Currently flang is not
+    # LTO aware so cannot link this file to compiled Fortran code.
+    if (FLANG_RT_HAS_FNO_LTO_FLAG)
+      target_compile_options(${tgtname} PRIVATE -fno-lto)
+    endif ()
+
+    # Flang/Clang (including clang-cl) -compiled programs targeting the MSVC ABI
+    # should only depend on msvcrt/ucrt. LLVM still emits libgcc/compiler-rt
+    # functions in some cases like 128-bit integer math (__udivti3, __modti3,
+    # __fixsfti, __floattidf, ...) that msvc does not support. We are injecting a
+    # dependency to Compiler-RT's builtin library where these are implemented.
+    if (MSVC AND CMAKE_CXX_COMPILER_ID MATCHES "Clang")
+      if (FLANG_RT_BUILTINS_LIBRARY)
+      target_compile_options(${tgtname} PRIVATE "$<$<COMPILE_LANGUAGE:CXX,C>:-Xclang>" "$<$<COMPILE_LANGUAGE:CXX,C>:--dependent-lib=${FLANG_RT_BUILTINS_LIBRARY}>")
+      endif ()
+    endif ()
+    if (MSVC AND CMAKE_Fortran_COMPILER_ID STREQUAL "LLVMFlang")
+      if (FLANG_RT_BUILTINS_LIBRARY)
+      target_compile_options(${tgtname} PRIVATE "$<$<COMPILE_LANGUAGE:Fortran>:-Xflang>" "$<$<COMPILE_LANGUAGE:Fortran>:--dependent-lib=${FLANG_RT_BUILTINS_LIBRARY}>")
+      else ()
+        message(WARNING "Did not find libclang_rt.builtins.lib.
+          LLVM may emit builtins that are not implemented in msvcrt/ucrt and
+          instead falls back to builtins from Compiler-RT. Linking with ${tgtname}
+          may result in a linker error.")
+      endif ()
+    endif ()
+
+    # Non-GTest unittests depend on LLVMSupport
+    if (ARG_LINK_TO_LLVM)
+      if (LLVM_LINK_LLVM_DYLIB)
+        set(llvm_libs LLVM)
+      else()
+        llvm_map_components_to_libnames(llvm_libs Support)
+      endif()
+      target_link_libraries(${tgtname} PUBLIC ${llvm_libs})
+      target_include_directories(${tgtname} PUBLIC ${LLVM_INCLUDE_DIRS})
+    endif ()
+
+    if (ARG_INCLUDE_DIRECTORIES)
+      target_include_directories(${tgtname} ${ARG_INCLUDE_DIRECTORIES})
+    endif ()
+
+    if (ARG_LINK_LIBRARIES)
+      target_link_libraries(${tgtname} PUBLIC ${ARG_LINK_LIBRARIES})
+    endif ()
+  endforeach ()
+
+  foreach (tgtname IN LISTS libtargets)
+    # If this is part of the toolchain, put it into the compiler's resource
+    # directory. Otherwise it is part of testing and is not installed at all.
+    # TODO: Consider multi-configuration builds (MSVC_IDE, "Ninja Multi-Config")
+    if (ARG_INSTALL_WITH_TOOLCHAIN)
+      set_target_properties(${tgtname}
+        PROPERTIES
+          ARCHIVE_OUTPUT_DIRECTORY "${FLANG_RT_OUTPUT_RESOURCE_LIB_DIR}"
+          LIBRARY_OUTPUT_DIRECTORY "${FLANG_RT_OUTPUT_RESOURCE_LIB_DIR}"
+        )
+
+      install(TARGETS ${tgtname}
+          ARCHIVE DESTINATION "${FLANG_RT_INSTALL_RESOURCE_LIB_PATH}"
+          LIBRARY DESTINATION "${FLANG_RT_INSTALL_RESOURCE_LIB_PATH}"
+        )
+    endif ()
+
+    if (ARG_TARGET_PROPERTIES)
+      set_target_properties(${tgtname} PROPERTIES ${ARG_TARGET_PROPERTIES})
+    endif ()
+
+    # flang-rt should build all the Flang-RT targets that are built in an
+    # 'all' build.
+    if (NOT ARG_EXCLUDE_FROM_ALL)
+      add_dependencies(flang-rt ${tgtname})
+    endif ()
+  endforeach ()
 endfunction (add_flangrt_library)
diff --git a/flang-rt/cmake/modules/AddFlangRTOffload.cmake b/flang-rt/cmake/modules/AddFlangRTOffload.cmake
index 4e4bd60c6354..6dd0d72dc3fd 100644
--- a/flang-rt/cmake/modules/AddFlangRTOffload.cmake
+++ b/flang-rt/cmake/modules/AddFlangRTOffload.cmake
@@ -8,9 +8,15 @@
 
 macro(enable_cuda_compilation name files)
   if (FLANG_RT_EXPERIMENTAL_OFFLOAD_SUPPORT STREQUAL "CUDA")
+    if (FLANG_RT_ENABLE_SHARED)
+      message(FATAL_ERROR
+        "FLANG_RT_ENABLE_SHARED is not supported for CUDA offload build of Flang-RT"
+        )
+    endif()
+
     enable_language(CUDA)
 
-    set_target_properties(${name}
+    set_target_properties(${name}.static
         PROPERTIES
           CUDA_SEPARABLE_COMPILATION ON
       )
@@ -54,7 +60,7 @@ macro(enable_cuda_compilation name files)
     # When using libcudacxx headers files, we have to use them
     # for all files of Flang-RT.
     if (EXISTS "${FLANG_RT_LIBCUDACXX_PATH}/include")
-      foreach (tgt IN ITEMS "${name}" "obj.${name}PTX")
+      foreach (tgt IN ITEMS "${name}.static" "obj.${name}PTX")
         target_include_directories(${tgt} AFTER PRIVATE "${FLANG_RT_LIBCUDACXX_PATH}/include")
         target_compile_definitions(${tgt} PRIVATE RT_USE_LIBCUDACXX=1)
       endforeach ()
@@ -66,6 +72,12 @@ macro(enable_omp_offload_compilation name files)
   if (FLANG_RT_EXPERIMENTAL_OFFLOAD_SUPPORT STREQUAL "OpenMP")
     # OpenMP offload build only works with Clang compiler currently.
 
+    if (FLANG_RT_ENABLE_SHARED)
+      message(FATAL_ERROR
+        "FLANG_RT_ENABLE_SHARED is not supported for OpenMP offload build of Flang-RT"
+        )
+    endif()
+
     if ("${CMAKE_CXX_COMPILER_ID}" MATCHES "Clang" AND
         "${CMAKE_C_COMPILER_ID}" MATCHES "Clang")
 
@@ -84,7 +96,7 @@ macro(enable_omp_offload_compilation name files)
       set_source_files_properties(${files} PROPERTIES COMPILE_OPTIONS
         "${OMP_COMPILE_OPTIONS}"
         )
-      target_link_options(${name} PUBLIC ${OMP_COMPILE_OPTIONS})
+      target_link_options(${name}.static PUBLIC ${OMP_COMPILE_OPTIONS})
 
       # Enable "declare target" in the source code.
       set_source_files_properties(${files}
diff --git a/flang-rt/examples/ExternalHelloWorld/CMakeLists.txt b/flang-rt/examples/ExternalHelloWorld/CMakeLists.txt
index 4fd04f8f2769..ccc39242745d 100644
--- a/flang-rt/examples/ExternalHelloWorld/CMakeLists.txt
+++ b/flang-rt/examples/ExternalHelloWorld/CMakeLists.txt
@@ -13,5 +13,5 @@ add_llvm_example(external-hello-world
 
 target_link_libraries(external-hello-world
   PRIVATE
-    flang_rt.runtime
+    flang_rt.runtime.default
   )
diff --git a/flang-rt/lib/cuda/CMakeLists.txt b/flang-rt/lib/cuda/CMakeLists.txt
index d5ca354c1029..fc9a95bc49dc 100644
--- a/flang-rt/lib/cuda/CMakeLists.txt
+++ b/flang-rt/lib/cuda/CMakeLists.txt
@@ -6,8 +6,7 @@
 #
 #===------------------------------------------------------------------------===#
 
-
-add_flangrt_library(flang_rt.cuda STATIC
+add_flangrt_library(flang_rt.cuda STATIC SHARED
   allocatable.cpp
   allocator.cpp
   descriptor.cpp
@@ -17,18 +16,27 @@ add_flangrt_library(flang_rt.cuda STATIC
   memory.cpp
   registration.cpp
 
-  # libflang_rt.runtime depends on a certain version of CUDA. To be able to have
-  # multiple build of this library with different CUDA version, the version is
-  # added to the library name.
   TARGET_PROPERTIES
+    # libflang_rt.runtime depends on a certain version of CUDA. To be able to have
+    # multiple build of this library with different CUDA version, the version is
+    # added to the library name.
     OUTPUT_NAME "flang_rt.cuda_${CUDAToolkit_VERSION_MAJOR}"
-
   INCLUDE_DIRECTORIES
     PRIVATE ${CUDAToolkit_INCLUDE_DIRS}
 )
 
-target_link_libraries(flang_rt.cuda
-  PUBLIC
-  flang_rt.runtime
-  CUDA::cudart_static
-)
+# For the static library, link-in the static dependencies as well.
+if (TARGET flang_rt.cuda.static)
+  target_link_libraries(flang_rt.cuda.static PUBLIC
+    flang_rt.runtime.static
+    CUDA::cudart_static
+  )
+endif ()
+
+# For the shared library, use the shared versions of the dependencies.
+if (TARGET flang_rt.cuda.shared)
+  target_link_libraries(flang_rt.cuda.shared PUBLIC
+    flang_rt.runtime.shared
+    CUDA::cudart
+  )
+endif ()
diff --git a/flang-rt/lib/runtime/CMakeLists.txt b/flang-rt/lib/runtime/CMakeLists.txt
index 0afcbf278353..589ee140485e 100644
--- a/flang-rt/lib/runtime/CMakeLists.txt
+++ b/flang-rt/lib/runtime/CMakeLists.txt
@@ -128,7 +128,7 @@ set(sources ${supported_sources} ${host_sources} ${f128_sources})
 
 
 if (NOT WIN32)
-  add_flangrt_library(flang_rt.runtime STATIC
+  add_flangrt_library(flang_rt.runtime STATIC SHARED
     ${sources}
     LINK_LIBRARIES ${Backtrace_LIBRARY}
     INSTALL_WITH_TOOLCHAIN
@@ -138,10 +138,9 @@ if (NOT WIN32)
   enable_cuda_compilation(flang_rt.runtime "${supported_sources}")
   enable_omp_offload_compilation(flang_rt.runtime "${supported_sources}")
 
-  # For unittests that depend on flang_rt. Should link to the static version
-  # of the library.
-  add_library(flang_rt.runtime.static ALIAS flang_rt.runtime)
-  add_library(flang_rt.runtime.unittest ALIAS flang_rt.runtime)
+  # Select a default runtime, which is used for unit and regression tests.
+  get_target_property(default_target flang_rt.runtime.default ALIASED_TARGET)
+  add_library(flang_rt.runtime.unittest ALIAS "${default_target}")
 else()
   # Target for building all versions of the runtime
   add_custom_target(flang_rt.runtime)
diff --git a/flang-rt/test/CMakeLists.txt b/flang-rt/test/CMakeLists.txt
index f5f7b8832d38..cb48d22d3acc 100644
--- a/flang-rt/test/CMakeLists.txt
+++ b/flang-rt/test/CMakeLists.txt
@@ -44,8 +44,8 @@ add_custom_target(flang-rt-test-depends)
 set_target_properties(flang-rt-test-depends PROPERTIES FOLDER "Flang-RT/Meta")
 add_dependencies(flang-rt-test-depends
     FlangRTUnitTests
-    flang_rt.runtime
     flang_rt.runtime.unittest
+    flang_rt.runtime
   )
 
 add_lit_testsuite(check-flang-rt "Running the Flang-RT regression tests"
diff --git a/flang-rt/test/lit.cfg.py b/flang-rt/test/lit.cfg.py
index 652da31e6438..032aeef2d5bf 100644
--- a/flang-rt/test/lit.cfg.py
+++ b/flang-rt/test/lit.cfg.py
@@ -92,7 +92,7 @@ config.substitutions.append(
     ("%include", os.path.join(config.flang_source_dir, "include"))
 )
 
-# Library path of libflang_rt.runtime.a (for lib search path when using non-Flang driver for linking)
+# Library path of libflang_rt.runtime.a/.so (for lib search path when using non-Flang driver for linking and LD_LIBRARY_PATH)
 config.substitutions.append(("%libdir", config.flang_rt_output_resource_lib_dir))
 
 # For CUDA offloading, additional steps (device linking) and libraries (cudart) are needed.
diff --git a/flang-rt/unittests/Runtime/CUDA/CMakeLists.txt b/flang-rt/unittests/Runtime/CUDA/CMakeLists.txt
index cd69a6f47287..2faacfda92a8 100644
--- a/flang-rt/unittests/Runtime/CUDA/CMakeLists.txt
+++ b/flang-rt/unittests/Runtime/CUDA/CMakeLists.txt
@@ -14,5 +14,5 @@ add_flangrt_unittest(FlangCufRuntimeTests
 
 target_link_libraries(FlangCufRuntimeTests
   PRIVATE
-  flang_rt.cuda
+  flang_rt.cuda.default
 )