diff --git a/CMake/External/CMakeLists.txt b/CMake/External/CMakeLists.txt
index df3f072e564744883accc5646cf0410b5cd051a6..d7738992615c6f69ec029e4cc8710ff0faf7e6d5 100644
--- a/CMake/External/CMakeLists.txt
+++ b/CMake/External/CMakeLists.txt
@@ -73,12 +73,11 @@ ExternalProject_Include_Dependencies( ${PROJECT_NAME}
   SUPERBUILD_VAR ${PROJECT_NAME}_SUPERBUILD
   )
 
-set(VTK_PATCH_COMMAND)
-if(NOT ${USE_SYSTEM_VTK} AND ${PROJECT_NAME}_VTK_REPO_SOURCE EQUAL "8.2")
-  set(VTK_PATCH_COMMAND ${CMAKE_COMMAND}
-    -DVTK_SOURCE_DIR=${VTK_SOURCE_DIR}
-    -DCMAKE_INSTALL_PREFIX=${CMAKE_INSTALL_PREFIX}
-    -P ${CMAKE_SOURCE_DIR}/CMake/External/Patches/vtk-8.2.cmake)
+set(EXTERNAL_PROJECT_OPTIONAL_CMAKE_CACHE_ARGS)
+if(WIN32)
+  list(APPEND EXTERNAL_PROJECT_OPTIONAL_CMAKE_CACHE_ARGS
+    -D${PROJECT_NAME}_ENABLE_AUDIO:BOOL=${${PROJECT_NAME}_AUDIO_ENABLED}
+    )
 endif()
 
 #-----------------------------------------------------------------------------
@@ -89,34 +88,21 @@ ExternalProject_Add( ${PROJECT_NAME}
   DOWNLOAD_COMMAND ""
   SOURCE_DIR ${${PROJECT_NAME}_SOURCE_DIR}
   BINARY_DIR ${CMAKE_BINARY_DIR}/Innerbuild
-  ${COMMON_CMAKE_EP_ARGS}
-  CMAKE_ARGS
+  CMAKE_CACHE_ARGS
     -D${PROJECT_NAME}_SUPERBUILD:BOOL=OFF
-    -D${PROJECT_NAME}_BUILD_EXAMPLES:BOOL=${${PROJECT_NAME}_BUILD_EXAMPLES}
-    -D${PROJECT_NAME}_BUILD_TESTING:BOOL=${${PROJECT_NAME}_BUILD_TESTING}
-    -D${PROJECT_NAME}_WRAP_CSHARP:BOOL=${${PROJECT_NAME}_WRAP_CSHARP}
-    -D${PROJECT_NAME}_USE_OpenHaptics:BOOL=${${PROJECT_NAME}_USE_OpenHaptics}
-    -D${PROJECT_NAME}_USE_MODEL_REDUCTION:BOOL=${${PROJECT_NAME}_USE_MODEL_REDUCTION}    
-    -D${PROJECT_NAME}_ENABLE_AUDIO:BOOL=${${PROJECT_NAME}_ENABLE_AUDIO}
-    -D${PROJECT_NAME}_USE_VRPN:BOOL=${${PROJECT_NAME}_USE_VRPN}
-    -D${PROJECT_NAME}_USE_PHYSX:BOOL=${${PROJECT_NAME}_USE_PHYSX}
-    -D${PROJECT_NAME}_COLOR_OUTPUT:BOOL=${${PROJECT_NAME}_COLOR_OUTPUT}
-    -D${PROJECT_NAME}_USE_VTK_OSMESA:BOOL=${${PROJECT_NAME}_USE_VTK_OSMESA}
-    -D${PROJECT_NAME}_COVERAGE:BOOL=${${PROJECT_NAME}_COVERAGE}
     # External Libraries
     -DEigen3_DIR:PATH=${Eigen3_DIR}    
     -DGTest_DIR:PATH=${GTest_DIR}
     -DVegaFEM_DIR:PATH=${VegaFEM_DIR}
     -DVTK_DIR:PATH=${VTK_DIR}
-    # I don't think this is needed by the inner build
-    # -DPHYSX_CONFIGURATION:STRING=${${PROJECT_NAME}_PHYSX_CONFIGURATION}
+    ${EXTERNAL_PROJECT_OPTIONAL_CMAKE_CACHE_ARGS}
   DEPENDS ${${PROJECT_NAME}_DEPENDENCIES}
-  PATCH_COMMAND 
-    COMMAND ${VTK_PATCH_COMMAND}
-    # Always build these non standard configurations
   )
 
-	#-----------------------------------------------------------------------------
-    # Add the target to Examples folder
-    #-----------------------------------------------------------------------------
-    SET_TARGET_PROPERTIES (${PROJECT_NAME} PROPERTIES FOLDER iMSTK)
+ExternalProject_AlwaysConfigure(${PROJECT_NAME})
+
+#-----------------------------------------------------------------------------
+# Add the target to iMSTK folder
+#-----------------------------------------------------------------------------
+set_target_properties(${PROJECT_NAME} PROPERTIES FOLDER iMSTK)
+
diff --git a/CMake/External/External_Assimp.cmake b/CMake/External/External_Assimp.cmake
index aaca9c0756abbc3f2e06786cc6bb2f24ba281e78..bcb924f04f466e83c4c5095d1a249f9ea6c87f86 100644
--- a/CMake/External/External_Assimp.cmake
+++ b/CMake/External/External_Assimp.cmake
@@ -2,9 +2,25 @@
 # Add External Project
 #-----------------------------------------------------------------------------
 include(imstkAddExternalProject)
+
+# Download options
+if(NOT DEFINED iMSTK_Assimp_GIT_SHA)
+  set(iMSTK_Assimp_GIT_SHA "fixCompilationError")
+endif()
+if(NOT DEFINED iMSTK_Assimp_GIT_REPOSITORY)
+  set(EXTERNAL_PROJECT_DOWNLOAD_OPTIONS
+    URL https://gitlab.kitware.com/iMSTK/assimp/-/archive/${iMSTK_Assimp_GIT_SHA}/assimp-${iMSTK_Assimp_GIT_SHA}.zip
+    URL_HASH MD5=fab081af9dbd73a9a5c61cd33dd93340
+    )
+else()
+  set(EXTERNAL_PROJECT_DOWNLOAD_OPTIONS
+    GIT_REPOSITORY ${iMSTK_Assimp_GIT_REPOSITORY}
+    GIT_TAG ${iMSTK_Assimp_GIT_SHA}
+    )
+endif()
+
 imstk_add_external_project( Assimp
-  URL https://gitlab.kitware.com/iMSTK/assimp/-/archive/fixCompilationError/assimp-fixCompilationError.zip
-  URL_MD5 fab081af9dbd73a9a5c61cd33dd93340
+  ${EXTERNAL_PROJECT_DOWNLOAD_OPTIONS}
   CMAKE_CACHE_ARGS
     -DCMAKE_POSITION_INDEPENDENT_CODE:BOOL=ON
     -DASSIMP_BUILD_ASSIMP_TOOLS:BOOL=OFF
diff --git a/CMake/External/External_Eigen3.cmake b/CMake/External/External_Eigen3.cmake
index 418c6406d8194c3773dadaacabab6ed842dbb4f7..0d3c303f320db4c76d74c7126c4121db4a58ec76 100644
--- a/CMake/External/External_Eigen3.cmake
+++ b/CMake/External/External_Eigen3.cmake
@@ -1,17 +1,48 @@
+
+include(imstkAddExternalProject)
+
+if(CMAKE_PROJECT_NAME STREQUAL "iMSTK")
+  set(Eigen3_INSTALL_DIR ${CMAKE_INSTALL_PREFIX})
+endif()
+
 #-----------------------------------------------------------------------------
 # Add External Project
 #-----------------------------------------------------------------------------
-include(imstkAddExternalProject)
+set(EXTERNAL_PROJECT_OPTIONAL_CMAKE_CACHE_ARGS)
+# After the external project updates its CMake minimum required version
+# to >= 3.15, package export is disabled by default (see policy CMP0090)
+# and explicitly setting this options will not be needed.
+list(APPEND EXTERNAL_PROJECT_OPTIONAL_CMAKE_CACHE_ARGS
+  -DCMAKE_EXPORT_NO_PACKAGE_REGISTRY:BOOL=ON
+  )
+
+# Download options
+if(NOT DEFINED iMSTK_Eigen3_GIT_SHA)
+  set(iMSTK_Eigen3_GIT_SHA "3.4.0")
+endif()
+if(NOT DEFINED iMSTK_Eigen3_GIT_REPOSITORY)
+  set(EXTERNAL_PROJECT_DOWNLOAD_OPTIONS
+    URL "https://gitlab.kitware.com/iMSTK/eigen/-/archive/${iMSTK_Eigen3_GIT_SHA}/eigen-${iMSTK_Eigen3_GIT_SHA}.tar.gz"
+    URL_HASH MD5=4c527a9171d71a72a9d4186e65bea559
+    )
+else()
+  set(EXTERNAL_PROJECT_DOWNLOAD_OPTIONS
+    GIT_REPOSITORY ${iMSTK_Eigen3_GIT_REPOSITORY}
+    GIT_TAG ${iMSTK_Eigen3_GIT_SHA}
+    )
+endif()
+
 imstk_add_external_project( Eigen3
-  URL "https://gitlab.kitware.com/iMSTK/eigen/-/archive/3.4.0/eigen-3.4.0.tar.gz"
-  URL_HASH MD5=4c527a9171d71a72a9d4186e65bea559
+  ${EXTERNAL_PROJECT_DOWNLOAD_OPTIONS}
   CMAKE_CACHE_ARGS
         -DBUILD_TESTING:BOOL=OFF
+        ${EXTERNAL_PROJECT_OPTIONAL_CMAKE_CACHE_ARGS}
   RELATIVE_INCLUDE_PATH ""
   DEPENDENCIES ""
   #VERBOSE
 )
+
 if(NOT USE_SYSTEM_Eigen3)
-  set(Eigen3_DIR ${CMAKE_INSTALL_PREFIX}/share/eigen3/cmake)
+  set(Eigen3_DIR ${Eigen3_INSTALL_DIR}/share/eigen3/cmake)
   #message(STATUS "Eigen3_DIR : ${Eigen3_DIR}")
 endif()
diff --git a/CMake/External/External_FTD2XX.cmake b/CMake/External/External_FTD2XX.cmake
index d3f6c7d8fc89fe05a3763b69683929cbefadbbd2..b67c0ea2db5faed79ea7bedff1a95b8716e0b7d8 100644
--- a/CMake/External/External_FTD2XX.cmake
+++ b/CMake/External/External_FTD2XX.cmake
@@ -4,65 +4,86 @@ if(NOT WIN32)
   return()
 endif()
 
-#-----------------------------------------------------------------------------
-# Set project prefix path
-#-----------------------------------------------------------------------------
-set(FTD2XX_PREFIX ${CMAKE_BINARY_DIR}/External/FTD2XX)
-set(FTD2XX_EXTRACT_DIR ${FTD2XX_PREFIX}/ftd2xx-2.12.18)
+include(imstkAddExternalProject)
+
+# Set FTD2XX_SOURCE_DIR and FTD2XX_PREFIX
+imstk_define_external_dirs( FTD2XX )
+
+# Directories and filenames specific to the FTD2XX archive layout
+set(_dll_dir "i386")
+set(_dll_name "ftd2xx.dll")
+set(_lib_dir "i386")
+set(_lib_name "ftd2xx.lib")
+if("${CMAKE_SIZEOF_VOID_P}" STREQUAL "8")
+  set(_dll_dir "amd64")
+  set(_dll_name "ftd2xx64.dll")
+  set(_lib_dir "amd64")
+  set(_lib_name "ftd2xx.lib")
+endif()
+
+# Directories and filenames specific to the FTD2XX install layout
+set(FTD2XX_DLL_DIR "bin")
+set(FTD2XX_DLL_NAME "${_dll_name}")
+set(FTD2XX_LIB_DIR "lib")
+set(FTD2XX_LIB_NAME "${_lib_name}")
 
 #-----------------------------------------------------------------------------
 # Set install commands
 #-----------------------------------------------------------------------------
-set(ftd2xx_libdir "i386")
-if("${CMAKE_SIZEOF_VOID_P}" STREQUAL "8")
-  set(ftd2xx_libdir "amd64")
+if(CMAKE_PROJECT_NAME STREQUAL "iMSTK")
+  set(FTD2XX_INSTALL_DIR ${CMAKE_INSTALL_PREFIX})
 endif()
 
 set(copy_ftd2xx_headers_command
   ${CMAKE_COMMAND} -E copy
-  ${FTD2XX_EXTRACT_DIR}/ftd2xx.h
-  ${CMAKE_INSTALL_PREFIX}/include/ftd2xx/ftd2xx.h
+  ${FTD2XX_SOURCE_DIR}/ftd2xx.h
+  ${FTD2XX_INSTALL_DIR}/include/ftd2xx/ftd2xx.h
   )
 set(copy_ftd2xx_lib_command
   ${CMAKE_COMMAND} -E copy
-  ${FTD2XX_EXTRACT_DIR}/${ftd2xx_libdir}/ftd2xx.lib
-  ${CMAKE_INSTALL_PREFIX}/lib/ftd2xx.lib
+  ${FTD2XX_SOURCE_DIR}/${_lib_dir}/${_lib_name}
+  ${FTD2XX_INSTALL_DIR}/${FTD2XX_LIB_DIR}/${_lib_name}
   )
-  
 set(copy_ftd2xx_dll_command
   ${CMAKE_COMMAND} -E copy
-  ${FTD2XX_EXTRACT_DIR}/${ftd2xx_libdir}/ftd2xx64.dll
-  ${CMAKE_INSTALL_PREFIX}/bin/ftd2xx64.dll
+  ${FTD2XX_SOURCE_DIR}/${_dll_dir}/${_dll_name}
+  ${FTD2XX_INSTALL_DIR}/${FTD2XX_DLL_DIR}/${_dll_name}
   )
 
-# HS 2021-aug-08 Some dependencies expect the dll name to 
-# be ftd2xx.dll rather than ftd2xx64.dll we're copying here
-# to the renamed version as the whole chain is built via 64 bit builds
-set(copy_ftd2xx_dll_command_rename
-  ${CMAKE_COMMAND} -E copy
-  ${FTD2XX_EXTRACT_DIR}/${ftd2xx_libdir}/ftd2xx64.dll
-  ${CMAKE_INSTALL_PREFIX}/bin/ftd2xx.dll
+set(FTD2XX_INSTALL_COMMAND
+  INSTALL_COMMAND
+    COMMAND ${copy_ftd2xx_headers_command}
+    COMMAND ${copy_ftd2xx_lib_command}
+    COMMAND ${copy_ftd2xx_dll_command}
   )
 
+if("${CMAKE_SIZEOF_VOID_P}" STREQUAL "8")
+  # HS 2021-aug-08 Some dependencies expect the dll name to
+  # be ftd2xx.dll rather than ftd2xx64.dll we're copying here
+  # to the renamed version as the whole chain is built via 64 bit builds
+  set(copy_ftd2xx_dll_command_rename
+    ${CMAKE_COMMAND} -E copy
+    ${FTD2XX_SOURCE_DIR}/${_lib_dir}/ftd2xx64.dll
+    ${FTD2XX_INSTALL_DIR}/bin/ftd2xx.dll
+    )
+
+  list(APPEND FTD2XX_INSTALL_COMMAND
+    COMMAND ${copy_ftd2xx_dll_command_rename}
+    )
+endif()
 
 #-----------------------------------------------------------------------------
 # Add External Project
 #-----------------------------------------------------------------------------
-include(imstkAddExternalProject)
 imstk_add_external_project( FTD2XX
   URL http://www.ftdichip.com/Drivers/CDM/CDM%20v2.12.18%20WHQL%20Certified.zip
   URL_MD5 e1a194765d7bcc58968d523484b74140
   DOWNLOAD_DIR ${FTD2XX_PREFIX}
-  SOURCE_DIR ${FTD2XX_EXTRACT_DIR}
-  BINARY_DIR ${FTD2XX_EXTRACT_DIR}
+  SOURCE_DIR ${FTD2XX_SOURCE_DIR}
   UPDATE_COMMAND ${SKIP_STEP_COMMAND}
   CONFIGURE_COMMAND ${SKIP_STEP_COMMAND}
   BUILD_COMMAND ${SKIP_STEP_COMMAND}
-  INSTALL_COMMAND
-    COMMAND ${copy_ftd2xx_headers_command}
-    COMMAND ${copy_ftd2xx_lib_command}
-    COMMAND ${copy_ftd2xx_dll_command}
-    COMMAND ${copy_ftd2xx_dll_command_rename}
+  ${FTD2XX_INSTALL_COMMAND}
   RELATIVE_INCLUDE_PATH "/"
   #VERBOSE
 )
diff --git a/CMake/External/External_GTest.cmake b/CMake/External/External_GTest.cmake
index cafbe2f9016fd7a7305a5f0998884daec4b4b1d4..564a6ed61621a2501d2110fc4d433d8af76ad47d 100644
--- a/CMake/External/External_GTest.cmake
+++ b/CMake/External/External_GTest.cmake
@@ -2,9 +2,25 @@
 # Add External Project
 #-----------------------------------------------------------------------------
 include(imstkAddExternalProject)
+
+# Download options
+if(NOT DEFINED iMSTK_GTest_GIT_SHA)
+  set(iMSTK_GTest_GIT_SHA "40dfd4b775a66979ad1bd19321cdfd0feadfea27")
+endif()
+if(NOT DEFINED iMSTK_GTest_GIT_REPOSITORY)
+  set(EXTERNAL_PROJECT_DOWNLOAD_OPTIONS
+    URL https://github.com/google/googletest/archive/${iMSTK_GTest_GIT_SHA}.zip
+    URL_HASH MD5=222793254ade8010fe6ff000f18c6b15
+    )
+else()
+  set(EXTERNAL_PROJECT_DOWNLOAD_OPTIONS
+    GIT_REPOSITORY ${iMSTK_GTest_GIT_REPOSITORY}
+    GIT_TAG ${iMSTK_GTest_GIT_SHA}
+    )
+endif()
+
 imstk_add_external_project( GTest
-   URL https://github.com/google/googletest/archive/40dfd4b775a66979ad1bd19321cdfd0feadfea27.zip
-   URL_MD5 222793254ade8010fe6ff000f18c6b15
+  ${EXTERNAL_PROJECT_DOWNLOAD_OPTIONS}
   CMAKE_CACHE_ARGS
     -DBUILD_GMOCK:BOOL=ON
     -DBUILD_GTEST:BOOL=ON
diff --git a/CMake/External/External_LibNiFalcon.cmake b/CMake/External/External_LibNiFalcon.cmake
index 2d8a7b06d194cc5ff2a2c91018449fe8d02e82d9..1d9ab0a6eaebba78a0d0c2d9ff73898b624a11fc 100644
--- a/CMake/External/External_LibNiFalcon.cmake
+++ b/CMake/External/External_LibNiFalcon.cmake
@@ -6,10 +6,25 @@ if(WIN32)
   list(APPEND LIBNIFALCON_DEPENDENCIES "FTD2XX")
 endif(WIN32)
 
+# Download options
+if(NOT DEFINED iMSTK_LibNiFalcon_GIT_SHA)
+  set(iMSTK_LibNiFalcon_GIT_SHA "libusb1-windows")
+endif()
+if(NOT DEFINED iMSTK_LibNiFalcon_GIT_REPOSITORY)
+  set(EXTERNAL_PROJECT_DOWNLOAD_OPTIONS
+    URL https://gitlab.kitware.com/iMSTK/libnifalcon/-/archive/${iMSTK_LibNiFalcon_GIT_SHA}/libnifalcon-${iMSTK_LibNiFalcon_GIT_SHA}.zip
+    URL_HASH MD5=6d5d68c92837388bfcd27f99a48b921d
+    )
+else()
+  set(EXTERNAL_PROJECT_DOWNLOAD_OPTIONS
+    GIT_REPOSITORY ${iMSTK_LibNiFalcon_GIT_REPOSITORY}
+    GIT_TAG ${iMSTK_LibNiFalcon_GIT_SHA}
+    )
+endif()
+
 include(imstkAddExternalProject)
 imstk_add_external_project( LibNiFalcon
-  URL https://gitlab.kitware.com/iMSTK/libnifalcon/-/archive/libusb1-windows/libnifalcon-libusb1-windows.zip
-  URL_MD5 6d5d68c92837388bfcd27f99a48b921d
+  ${EXTERNAL_PROJECT_DOWNLOAD_OPTIONS}
   CMAKE_CACHE_ARGS
     -DBUILD_TESTING:BOOL=OFF
     -DBUILD_EXAMPLES:BOOL=OFF
diff --git a/CMake/External/External_Libusb.cmake b/CMake/External/External_Libusb.cmake
index 047f5a0c38cc6acdfd951070b05102ead89debdb..d52eef2d260de3b7f8eb1d80dc7ac8bf00fa8954 100644
--- a/CMake/External/External_Libusb.cmake
+++ b/CMake/External/External_Libusb.cmake
@@ -1,56 +1,78 @@
 if(NOT WIN32)
-  message(WARNING "System not supported. Only Windows is supported for External_Libusb.cmake.")
-  message(WARNING "Libusb-1.0 should already be installed on your system.")
-  return()
+  set(USE_SYSTEM_Libusb TRUE)  # Variable name expected by imstkAddExternalProject.cmake
 endif()
 
-#-----------------------------------------------------------------------------
-# Set project prefix path
-#-----------------------------------------------------------------------------
-set(Libusb_PREFIX ${CMAKE_BINARY_DIR}/External/Libusb)
-set(Libusb_EXTRACT_DIR ${Libusb_PREFIX}/libusb-1.0.20)
+include(imstkAddExternalProject)
+
+# Set Libusb_SOURCE_DIR and Libusb_PREFIX
+imstk_define_external_dirs( Libusb )
+
+# Directories and filenames specific to the Libusb archive layout
+set(_dll_dir "MS32/dll")
+if("${CMAKE_SIZEOF_VOID_P}" STREQUAL "8")
+  set(_dll_dir "MS64/dll")
+endif()
+set(_dll_name "libusb-1.0.dll")
+set(_lib_dir "${_dll_dir}")
+set(_lib_name "libusb-1.0.lib")
+
+# Directories and filenames specific to the Libusb install layout
+set(Libusb_INC_DIR "include/libusb-1.0")
+set(Libusb_DLL_DIR "bin")
+set(Libusb_DLL_NAME "${_dll_name}")
+set(Libusb_LIB_DIR "lib")
+set(Libusb_LIB_NAME "${_lib_name}")
 
 #-----------------------------------------------------------------------------
 # Set install commands
 #-----------------------------------------------------------------------------
-set(libusb_libdir "MS32")
-if("${CMAKE_SIZEOF_VOID_P}" STREQUAL "8")
-  set(libusb_libdir "MS64")
+if(CMAKE_PROJECT_NAME STREQUAL "iMSTK")
+  set(Libusb_INSTALL_DIR ${CMAKE_INSTALL_PREFIX})
 endif()
 
 set(copy_libusb_headers_command
   ${CMAKE_COMMAND} -E copy_directory
-  ${Libusb_EXTRACT_DIR}/include
-  ${CMAKE_INSTALL_PREFIX}/include
+  ${Libusb_SOURCE_DIR}/include
+  ${Libusb_INSTALL_DIR}/include
   )
 set(copy_libusb_lib_command
   ${CMAKE_COMMAND} -E copy
-  ${Libusb_EXTRACT_DIR}/${libusb_libdir}/dll/libusb-1.0.lib
-  ${CMAKE_INSTALL_PREFIX}/lib/libusb-1.0.lib
+  ${Libusb_SOURCE_DIR}/${_lib_dir}/${_lib_name}
+  ${Libusb_INSTALL_DIR}/${Libusb_LIB_DIR}/${_lib_name}
   )
 set(copy_libusb_dll_command
   ${CMAKE_COMMAND} -E copy
-  ${Libusb_EXTRACT_DIR}/${libusb_libdir}/dll/libusb-1.0.dll
-  ${CMAKE_INSTALL_PREFIX}/bin/
+  ${Libusb_SOURCE_DIR}/${_dll_dir}/${_dll_name}
+  ${Libusb_INSTALL_DIR}/${Libusb_DLL_DIR}/${_dll_name}
   )
 
+set(Libusb_INSTALL_COMMAND
+  INSTALL_COMMAND
+    COMMAND ${copy_libusb_headers_command}
+    COMMAND ${copy_libusb_lib_command}
+    COMMAND ${copy_libusb_dll_command}
+  )
+
+if(USE_SYSTEM_Libusb)
+  unset(Libusb_INCLUDE_DIR CACHE)
+  unset(Libusb_LIBRARY_libusb-1.0-RELEASE CACHE)
+  unset(Libusb_LIBRARY_libusb-1.0-DEBUG CACHE)
+
+  find_package(Libusb REQUIRED)
+endif()
+
 #-----------------------------------------------------------------------------
 # Add External Project
 #-----------------------------------------------------------------------------
-include(imstkAddExternalProject)
 imstk_add_external_project( Libusb
   URL http://downloads.sourceforge.net/project/libusb/libusb-1.0/libusb-1.0.21/libusb-1.0.21.7z https://data.kitware.com/api/v1/item/59cbcefd8d777f7d33e9d9d7/download
   URL_MD5 7fbcf5580b8ffc88f3af6eddd638de9f
   DOWNLOAD_DIR ${Libusb_PREFIX}
-  SOURCE_DIR ${Libusb_EXTRACT_DIR}
-  BINARY_DIR ${Libusb_EXTRACT_DIR}
+  SOURCE_DIR ${Libusb_SOURCE_DIR}
   UPDATE_COMMAND ${SKIP_STEP_COMMAND}
   CONFIGURE_COMMAND ${SKIP_STEP_COMMAND}
   BUILD_COMMAND ${SKIP_STEP_COMMAND}
-  INSTALL_COMMAND
-    COMMAND ${copy_libusb_headers_command}
-    COMMAND ${copy_libusb_lib_command}
-    COMMAND ${copy_libusb_dll_command}
-  RELATIVE_INCLUDE_PATH "include/libusb-1.0"
+  ${Libusb_INSTALL_COMMAND}
+  RELATIVE_INCLUDE_PATH "${Libusb_INC_DIR}"
   #VERBOSE
 )
diff --git a/CMake/External/External_OpenHaptics.cmake b/CMake/External/External_OpenHaptics.cmake
index 989db0b7e88f15df483d033b9b10dbce36c3cd3d..6b2df195e70424f42d20d3ce5c9bace6e1c08106 100644
--- a/CMake/External/External_OpenHaptics.cmake
+++ b/CMake/External/External_OpenHaptics.cmake
@@ -1,18 +1,52 @@
 if(NOT WIN32)
-  message(WARNING "System not supported. Currently, only Windows is supported for External_OpenHaptics.cmake.")
+  message(WARNING "System not supported. Only Windows is supported for External_OpenHaptics.cmake.")
   return()
 endif()
 
-if(NOT DEFINED OPENHAPTICS_ROOT_DIR OR NOT EXISTS ${OPENHAPTICS_ROOT_DIR})
-  set(OPENHAPTICS_ROOT_DIR "$ENV{OH_SDK_BASE}" CACHE PATH "Path to OpenHaptics install directory." FORCE)
+# Attempt to initialize OPENHAPTICS_ROOT_DIR based on OH_SDK_BASE env. variable
+if(NOT DEFINED OPENHAPTICS_ROOT_DIR)
+
+  # Check if OH_SDK_BASE is defined
+  set(env_var_defined FALSE)
+  set(msg "Checking if OH_SDK_BASE env. variable is defined")
+  message(STATUS "${msg}")
+  if(DEFINED ENV{OH_SDK_BASE})
+    set(env_var_defined TRUE)
+  endif()
+  message(STATUS "${msg} - ${env_var_defined}")
+
+  # Check if path associated with OH_SDK_BASE exists
+  if(env_var_defined)
+    set(env_var_path_exist FALSE)
+    set(msg "Checking if OH_SDK_BASE env. variable is set to existing path")
+    message(STATUS "${msg}")
+    if(EXISTS "$ENV{OH_SDK_BASE}")
+      set(env_var_path_exist TRUE)
+    endif()
+    message(STATUS "${msg} - ${env_var_path_exist}")
+
+    if(env_var_path_exist)
+      set(OPENHAPTICS_ROOT_DIR "$ENV{OH_SDK_BASE}" CACHE PATH "Path to OpenHaptics install directory.")
+      message(STATUS "Setting OPENHAPTICS_ROOT_DIR to ${OPENHAPTICS_ROOT_DIR}")
+    endif()
+  endif()
+
+  unset(env_var_defined)
+  unset(env_var_path_exist)
 endif()
-if(NOT EXISTS ${OPENHAPTICS_ROOT_DIR})
-  message(FATAL_ERROR "\nCan not support Phantom Omni without OpenHaptics.\nSet OPENHAPTICS_ROOT_DIR to OpenHaptics installation directory.\n\n")
+
+# Sanity checks
+if(DEFINED OPENHAPTICS_ROOT_DIR AND NOT EXISTS ${OPENHAPTICS_ROOT_DIR})
+  message(FATAL_ERROR "OPENHAPTICS_ROOT_DIR variable is defined but corresponds to nonexistent directory")
 endif()
 
 #-----------------------------------------------------------------------------
 # Set install commands
 #-----------------------------------------------------------------------------
+if(CMAKE_PROJECT_NAME STREQUAL "iMSTK")
+  set(OpenHaptics_INSTALL_DIR ${CMAKE_INSTALL_PREFIX})
+endif()
+
 if(WIN32)
   set(open_haptics_libdir "Win32")
   if("${CMAKE_SIZEOF_VOID_P}" STREQUAL "8")
@@ -23,22 +57,31 @@ if(WIN32)
 endif()
 
 # Header Directories
-set(open_haptics_headers_dest ${CMAKE_INSTALL_PREFIX}/include/OpenHaptics)
+set(open_haptics_headers_dest ${OpenHaptics_INSTALL_DIR}/include/OpenHaptics)
 set(open_haptics_headers_dir ${OPENHAPTICS_ROOT_DIR}/include/)
 set(open_haptics_util_headers_dir ${OPENHAPTICS_ROOT_DIR}/utilities/include/)
+
 # Library Directories
-set(open_haptics_libs_dest ${CMAKE_INSTALL_PREFIX}/lib/)
+set(open_haptics_libs_dest ${OpenHaptics_INSTALL_DIR}/lib/)
 set(open_haptics_libs_dir ${OPENHAPTICS_ROOT_DIR}/lib/${open_haptics_libdir}/Release)
 set(open_haptics_util_libs_dir ${OPENHAPTICS_ROOT_DIR}/utilities/lib/${open_haptics_libdir}/Release)
+
 # Binary Directory
-set(open_haptics_bin_dest ${CMAKE_INSTALL_PREFIX}/bin/)
+set(open_haptics_bin_dest ${OpenHaptics_INSTALL_DIR}/bin/)
 
 #-----------------------------------------------------------------------------
 # Add External Project
 #-----------------------------------------------------------------------------
+
+# Workaround issue in "imstk_add_external_project" by explicitly set the
+# OpenHaptics_SOURCE_DIR variable.
+# This ensures the call to "imstk_define_external_dirs" done in "imstk_add_external_project"
+# is not setting a default value because OpenHaptics_DIR is not defined.
+set(OpenHaptics_SOURCE_DIR ${OPENHAPTICS_ROOT_DIR})
+
 include(imstkAddExternalProject)
 imstk_add_external_project( OpenHaptics
-  SOURCE_DIR ${OPENHAPTICS_ROOT_DIR}
+  SOURCE_DIR ${OpenHaptics_SOURCE_DIR}
   UPDATE_COMMAND ${SKIP_STEP_COMMAND}
   CONFIGURE_COMMAND ${SKIP_STEP_COMMAND}
   BUILD_COMMAND ${SKIP_STEP_COMMAND}
diff --git a/CMake/External/External_OpenVR.cmake b/CMake/External/External_OpenVR.cmake
new file mode 100644
index 0000000000000000000000000000000000000000..d7beeeaa0932805afc6cb6e584ef5ff6747f6d74
--- /dev/null
+++ b/CMake/External/External_OpenVR.cmake
@@ -0,0 +1,91 @@
+include(imstkAddExternalProject)
+
+# Set OpenVR_SOURCE_DIR and OpenVR_PREFIX
+imstk_define_external_dirs( OpenVR )
+
+# Directories and filenames specific to the OpenVR archive layout
+set(OpenVR_INC_DIR "headers")
+if(WIN32)
+  set(OpenVR_DLL_DIR "bin/win64")
+  set(OpenVR_DLL_NAME "openvr_api.dll")
+  set(OpenVR_LIB_DIR "lib/win64")
+  set(OpenVR_LIB_NAME "openvr_api.lib")
+elseif(APPLE)
+  set(OpenVR_DLL_DIR "bin/osx64")
+  set(OpenVR_DLL_NAME "OpenVR.framework")
+  set(OpenVR_LIB_DIR "lib/osx32")
+  set(OpenVR_LIB_NAME "libopenvr_api.dylib")
+elseif(UNIX)
+  set(OpenVR_DLL_DIR "bin/linux64")
+  set(OpenVR_DLL_NAME "libopenvr_api.so")
+  set(OpenVR_LIB_DIR "lib/linux64")
+  set(OpenVR_LIB_NAME "libopenvr_api.so")
+endif()
+
+#-----------------------------------------------------------------------------
+# Set install commands
+#-----------------------------------------------------------------------------
+if(CMAKE_PROJECT_NAME STREQUAL "iMSTK")
+  set(OpenVR_INSTALL_DIR ${CMAKE_INSTALL_PREFIX})
+
+  set(copy_openvr_headers_command
+    ${CMAKE_COMMAND} -E copy_directory
+      ${OpenVR_SOURCE_DIR}/${OpenVR_INC_DIR}
+      ${OpenVR_INSTALL_DIR}/include/OpenVR
+    )
+  set(copy_openvr_dll_command
+    ${CMAKE_COMMAND} -E copy
+      ${OpenVR_SOURCE_DIR}/${OpenVR_DLL_DIR}/${OpenVR_DLL_NAME}
+      ${OpenVR_INSTALL_DIR}/bin/${OpenVR_DLL_NAME}
+    )
+  set(copy_openvr_lib_command
+    ${CMAKE_COMMAND} -E copy
+      ${OpenVR_SOURCE_DIR}/${OpenVR_LIB_DIR}/${OpenVR_LIB_NAME}
+      ${OpenVR_INSTALL_DIR}/lib/${OpenVR_LIB_NAME}
+    )
+
+  set(OpenVR_INSTALL_COMMAND
+    INSTALL_COMMAND
+      COMMAND ${copy_openvr_headers_command}
+      COMMAND ${copy_openvr_lib_command}
+      COMMAND ${copy_openvr_dll_command}
+    )
+else()
+  set(OpenVR_INSTALL_COMMAND
+    INSTALL_COMMAND
+      COMMAND ${SKIP_STEP_COMMAND}
+    )
+endif()
+
+#-----------------------------------------------------------------------------
+# Add External Project
+#-----------------------------------------------------------------------------
+
+# Download options
+if(NOT DEFINED iMSTK_OpenVR_GIT_SHA)
+  set(iMSTK_OpenVR_GIT_SHA "v1.12.5")
+endif()
+if(NOT DEFINED iMSTK_OpenVR_GIT_REPOSITORY)
+  set(EXTERNAL_PROJECT_DOWNLOAD_OPTIONS
+    URL https://gitlab.kitware.com/iMSTK/openvr/-/archive/${iMSTK_OpenVR_GIT_SHA}/openvr-${iMSTK_OpenVR_GIT_SHA}.tar.gz
+    URL_HASH MD5=42c4d1c4a194860aaa4e793b009b99c0
+    )
+else()
+  set(EXTERNAL_PROJECT_DOWNLOAD_OPTIONS
+    GIT_REPOSITORY ${iMSTK_OpenVR_GIT_REPOSITORY}
+    GIT_TAG ${iMSTK_OpenVR_GIT_SHA}
+    )
+endif()
+
+imstk_add_external_project( OpenVR
+  ${EXTERNAL_PROJECT_DOWNLOAD_OPTIONS}
+  DOWNLOAD_DIR ${OpenVR_PREFIX}
+  SOURCE_DIR ${OpenVR_SOURCE_DIR}
+  UPDATE_COMMAND ${SKIP_STEP_COMMAND}
+  CONFIGURE_COMMAND ${SKIP_STEP_COMMAND}
+  BUILD_COMMAND ${SKIP_STEP_COMMAND}
+  ${OpenVR_INSTALL_COMMAND}
+  RELATIVE_INCLUDE_PATH "${OpenVR_INC_DIR}"
+  #VERBOSE
+)
+
diff --git a/CMake/External/External_PThreads.cmake b/CMake/External/External_PThreads.cmake
deleted file mode 100644
index 328630d21885ba7db9e82efcfc804b82ce51da21..0000000000000000000000000000000000000000
--- a/CMake/External/External_PThreads.cmake
+++ /dev/null
@@ -1,14 +0,0 @@
-#-----------------------------------------------------------------------------
-# Add External Project
-#-----------------------------------------------------------------------------
-include(imstkAddExternalProject)
-imstk_add_external_project( PThreads
-  URL https://gitlab.kitware.com/iMSTK/libpthread/-/archive/iMSTK/libpthread-iMSTK.zip
-  URL_MD5 9bc417d5ebb8ac0859eeb77a147569ba
-  # This is the iMSTK branch
-  CMAKE_CACHE_ARGS
-    -DBUILD_TESTING:BOOL=OFF
-  RELATIVE_INCLUDE_PATH "include"
-  DEPENDENCIES ""
-  #VERBOSE
-)
diff --git a/CMake/External/External_PhysX.cmake b/CMake/External/External_PhysX.cmake
index 1892f3b391efb1b6234a853ffa0a8ee174081f98..f3eff78397e467546ecc3e5edbed685594b1a8d7 100644
--- a/CMake/External/External_PhysX.cmake
+++ b/CMake/External/External_PhysX.cmake
@@ -58,9 +58,24 @@ set(PHYSX_iMSTK_INSTALL "${CMAKE_COMMAND}"
   -DiMSTK_INSTALL_DIR=${CMAKE_INSTALL_PREFIX}
   -P ${CMAKE_SOURCE_DIR}/CMake/External/Patches/physx.cmake)
 
+# Download options
+if(NOT DEFINED iMSTK_PhysX_GIT_SHA)
+  set(iMSTK_PhysX_GIT_SHA "b03d0a74c1244a97b83dea58dc201beeacd45cf4")
+endif()
+if(NOT DEFINED iMSTK_PhysX_GIT_REPOSITORY)
+  set(EXTERNAL_PROJECT_DOWNLOAD_OPTIONS
+    URL https://gitlab.kitware.com/iMSTK/PhysX/-/archive/${iMSTK_PhysX_GIT_SHA}/PhysX-${iMSTK_PhysX_GIT_SHA}.zip
+    URL_HASH MD5=9c17263ceec705eaf1ddd7c2ee796bac
+    )
+else()
+  set(EXTERNAL_PROJECT_DOWNLOAD_OPTIONS
+    GIT_REPOSITORY ${iMSTK_PhysX_GIT_REPOSITORY}
+    GIT_TAG ${iMSTK_PhysX_GIT_SHA}
+    )
+endif()
+
 imstk_add_external_project( PhysX
-  URL https://gitlab.kitware.com/iMSTK/PhysX/-/archive/b03d0a74c1244a97b83dea58dc201beeacd45cf4/archive.zip
-  URL_MD5 9c17263ceec705eaf1ddd7c2ee796bac
+  ${EXTERNAL_PROJECT_DOWNLOAD_OPTIONS}
   SOURCE_SUBDIR ./physx/compiler/public
   CMAKE_CACHE_ARGS
     -DPHYSX_CXX_FLAGS:STRING=${NO_MEMSET}
diff --git a/CMake/External/External_SFML.cmake b/CMake/External/External_SFML.cmake
index fd54e7fba440e11dd49464818bf0b3d97c86c408..c285b0f778a136a434a02ab89da3c19d16ca53fd 100644
--- a/CMake/External/External_SFML.cmake
+++ b/CMake/External/External_SFML.cmake
@@ -1,10 +1,26 @@
 #-----------------------------------------------------------------------------
 # Add SFML External Project
 #-----------------------------------------------------------------------------
+
+# Download options
+if(NOT DEFINED iMSTK_SFML_GIT_SHA)
+  set(iMSTK_SFML_GIT_SHA "2.4.2")
+endif()
+if(NOT DEFINED iMSTK_SFML_GIT_REPOSITORY)
+  set(EXTERNAL_PROJECT_DOWNLOAD_OPTIONS
+    URL https://github.com/SFML/SFML/archive/${iMSTK_SFML_GIT_SHA}.zip
+    URL_HASH MD5=b2e2cf6c43e9d2b578c4abd9aa28a6aa
+    )
+else()
+  set(EXTERNAL_PROJECT_DOWNLOAD_OPTIONS
+    GIT_REPOSITORY ${iMSTK_SFML_GIT_REPOSITORY}
+    GIT_TAG ${iMSTK_SFML_GIT_SHA}
+    )
+endif()
+
 include(imstkAddExternalProject)
 imstk_add_external_project( SFML
-  URL https://github.com/SFML/SFML/archive/2.4.2.zip
-  URL_MD5 b2e2cf6c43e9d2b578c4abd9aa28a6aa
+  ${EXTERNAL_PROJECT_DOWNLOAD_OPTIONS}
   CMAKE_CACHE_ARGS
     -DSFML_BUILD_AUDIO:BOOL=ON
     -DSFML_BUILD_GRAPHICS:BOOL=OFF
diff --git a/CMake/External/External_TBB.cmake b/CMake/External/External_TBB.cmake
new file mode 100644
index 0000000000000000000000000000000000000000..894925a95522ef6dc8965bd770b07d8d35cfde98
--- /dev/null
+++ b/CMake/External/External_TBB.cmake
@@ -0,0 +1,115 @@
+
+# Set TBB_SOURCE_DIR and TBB_PREFIX
+imstk_define_external_dirs( TBB )
+
+# Version used to copy files & directories, and download archive from GitHub
+set(TBB_VER "2019_20191006oss")
+
+#-----------------------------------------------------------------------------
+# Set install commands
+#-----------------------------------------------------------------------------
+if(CMAKE_PROJECT_NAME STREQUAL "iMSTK")
+  set(TBB_INSTALL_DIR ${CMAKE_INSTALL_PREFIX})
+
+  set(copy_tbb_config_command
+    ${CMAKE_COMMAND} -E copy
+      ${TBB_SOURCE_DIR}/tbb${TBB_VER}/cmake/TBBConfig.cmake
+      ${TBB_INSTALL_DIR}/cmake/TBBConfig.cmake
+    )
+
+  set(copy_tbb_headers_command
+    ${CMAKE_COMMAND} -E copy_directory
+      ${TBB_SOURCE_DIR}/tbb${TBB_VER}/include/tbb
+      ${TBB_INSTALL_DIR}/include/tbb
+    )
+
+  if(WIN32)
+    set(_subdir "intel64/vc14/")
+  elseif(APPLE)
+    set(_subdir "")
+  elseif(UNIX)
+    set(_subdir "intel64/gcc4.8/")
+  endif()
+
+  set(copy_tbb_libraries_command
+    ${CMAKE_COMMAND} -E copy_directory
+      ${TBB_SOURCE_DIR}/tbb${TBB_VER}/lib/${_subdir}
+      ${TBB_INSTALL_DIR}/lib/${_subdir}
+    )
+
+  set(TBB_INSTALL_COMMAND
+    INSTALL_COMMAND
+      COMMAND ${copy_tbb_config_command}
+      COMMAND ${copy_tbb_headers_command}
+      COMMAND ${copy_tbb_libraries_command}
+    )
+
+  if(WIN32)
+    set(copy_tbb_dll_to_bin_subdir_command
+      ${CMAKE_COMMAND} -E copy_directory
+        ${TBB_SOURCE_DIR}/tbb${TBB_VER}/bin/${_subdir}
+        ${TBB_INSTALL_DIR}/bin/${_subdir}
+      )
+    # Also copy dlls directly into bin folder to support
+    # calling "gtest_discover_tests" with working directory
+    # set to <CMAKE_INSTALL_PREFIX>/bin
+    set(copy_tbb_dll_to_bin_command
+      ${CMAKE_COMMAND} -E copy_directory
+        ${TBB_SOURCE_DIR}/tbb${TBB_VER}/bin/${_subdir}
+        ${TBB_INSTALL_DIR}/bin/
+      )
+    list(APPEND TBB_INSTALL_COMMAND
+      COMMAND ${copy_tbb_dll_to_bin_subdir_command}
+      COMMAND ${copy_tbb_dll_to_bin_command}
+      )
+  endif()
+
+else()
+  set(TBB_INSTALL_COMMAND
+    INSTALL_COMMAND
+      COMMAND ${SKIP_STEP_COMMAND}
+    )
+endif()
+
+#-----------------------------------------------------------------------------
+# Add External Project
+#-----------------------------------------------------------------------------
+include(imstkAddExternalProject)
+
+# Download options
+if(NOT DEFINED iMSTK_TBB_GIT_SHA)
+  set(iMSTK_TBB_GIT_SHA "2019_U9")
+endif()
+if(NOT DEFINED iMSTK_TBB_GIT_REPOSITORY)
+  if(WIN32)
+    set(tbb_file "tbb${TBB_VER}_win.zip")
+    set(tbb_md5 "a061a7c9821a374023201e8592860730")
+  elseif(APPLE)
+    set(tbb_file "tbb${TBB_VER}_mac.tgz")
+    set(tbb_md5 "43a0d6409317ee94f047622fd489a6c8")
+  else()
+    set(tbb_file "tbb${TBB_VER}_lin.tgz")
+    set(tbb_md5 "b5025847fa47040b4d2da8d6bdba0224")
+  endif()
+  set(EXTERNAL_PROJECT_DOWNLOAD_OPTIONS
+    URL https://github.com/oneapi-src/oneTBB/releases/download/${iMSTK_TBB_GIT_SHA}/${tbb_file}
+    URL_HASH MD5=${tbb_md5}
+    )
+else()
+  set(EXTERNAL_PROJECT_DOWNLOAD_OPTIONS
+    GIT_REPOSITORY ${iMSTK_TBB_GIT_REPOSITORY}
+    GIT_TAG ${iMSTK_TBB_GIT_SHA}
+    )
+endif()
+
+imstk_add_external_project(TBB
+  ${EXTERNAL_PROJECT_DOWNLOAD_OPTIONS}
+  DOWNLOAD_DIR ${TBB_PREFIX}
+  SOURCE_DIR ${TBB_SOURCE_DIR}
+  UPDATE_COMMAND ${SKIP_STEP_COMMAND}
+  CONFIGURE_COMMAND ${SKIP_STEP_COMMAND}
+  BUILD_COMMAND ${SKIP_STEP_COMMAND}
+  ${TBB_INSTALL_COMMAND}
+  #RELATIVE_INCLUDE_PATH ""
+  #VERBOSE
+)
diff --git a/CMake/External/External_Uncrustify.cmake b/CMake/External/External_Uncrustify.cmake
index f50fa8dbfed4df76152c3fb6f291873344891b63..139ddb61479a3bdc3a40de3c640ab25cbee2697f 100644
--- a/CMake/External/External_Uncrustify.cmake
+++ b/CMake/External/External_Uncrustify.cmake
@@ -2,10 +2,25 @@
 # Add External Project
 #-----------------------------------------------------------------------------
 
+# Download options
+if(NOT DEFINED iMSTK_Uncrustify_GIT_SHA)
+  set(iMSTK_Uncrustify_GIT_SHA "0.70.1")
+endif()
+if(NOT DEFINED iMSTK_Uncrustify_GIT_REPOSITORY)
+  set(EXTERNAL_PROJECT_DOWNLOAD_OPTIONS
+    URL https://github.com/uncrustify/uncrustify/archive/uncrustify-${iMSTK_Uncrustify_GIT_SHA}.zip
+    URL_HASH MD5=0f6bd2ca1a35efebac3bc8aee44f6532
+    )
+else()
+  set(EXTERNAL_PROJECT_DOWNLOAD_OPTIONS
+    GIT_REPOSITORY ${iMSTK_Uncrustify_GIT_REPOSITORY}
+    GIT_TAG ${iMSTK_Uncrustify_GIT_SHA}
+    )
+endif()
+
 include(imstkAddExternalProject)
 imstk_add_external_project( Uncrustify
-  URL https://github.com/uncrustify/uncrustify/archive/uncrustify-0.70.1.zip
-  URL_MD5 0f6bd2ca1a35efebac3bc8aee44f6532
+  ${EXTERNAL_PROJECT_DOWNLOAD_OPTIONS}
   CMAKE_CACHE_ARGS
   RELATIVE_INCLUDE_PATH ""
   DEPENDENCIES ""
diff --git a/CMake/External/External_VRPN.cmake b/CMake/External/External_VRPN.cmake
index 7c56de2dda86fe80ca7983e7cf8071e77045e4e0..7908bc3e03f13512c6892001de7131cb9780d52c 100644
--- a/CMake/External/External_VRPN.cmake
+++ b/CMake/External/External_VRPN.cmake
@@ -1,3 +1,15 @@
+
+#-----------------------------------------------------------------------------
+# Options
+#-----------------------------------------------------------------------------
+if(WIN32)
+  if(NOT DEFINED VRPN_USE_OpenHaptics)
+    set(VRPN_USE_OpenHaptics ${iMSTK_USE_OpenHaptics})
+  endif()
+else()
+  set(VRPN_USE_OpenHaptics OFF)
+endif()
+
 #-----------------------------------------------------------------------------
 # Dependencies
 #-----------------------------------------------------------------------------
@@ -6,38 +18,27 @@ if(WIN32)
   list(APPEND VRPN_DEPENDENCIES "Libusb")
   list(APPEND VRPN_DEPENDENCIES "FTD2XX")
 endif(WIN32)
-
-#-----------------------------------------------------------------------------
-# Phantom Omni
-#-----------------------------------------------------------------------------
-option(${PROJECT_NAME}_USE_OpenHaptics "Build OpenHaptics to support the Phantom Omni in VRPN." OFF)
-if(${${PROJECT_NAME}_USE_OpenHaptics})
-  message(STATUS "Superbuild -   VRPN => ENABLING Phantom Omni support")
-  if(NOT DEFINED OPENHAPTICS_ROOT_DIR OR NOT EXISTS ${OPENHAPTICS_ROOT_DIR})
-    set(OPENHAPTICS_ROOT_DIR "$ENV{OH_SDK_BASE}" CACHE PATH "Path to OpenHaptics install directory." FORCE)
-  endif()
-  if(NOT EXISTS ${OPENHAPTICS_ROOT_DIR})
-    message(FATAL_ERROR "\nCan not support Phantom Omni without OpenHaptics.\nSet OPENHAPTICS_ROOT_DIR to OpenHaptics installation directory.\n\n")
-  endif()
+if(VRPN_USE_OpenHaptics)
   list(APPEND VRPN_DEPENDENCIES "OpenHaptics")
-else()
-  message(STATUS "Superbuild -   VRPN => Phantom Omni support DISABLED")
-  if(DEFINED OPENHAPTICS_ROOT_DIR)
-    unset(OPENHAPTICS_ROOT_DIR CACHE)
-  endif()
-
 endif()
 
 #-----------------------------------------------------------------------------
 # Add External Project
 #-----------------------------------------------------------------------------
+
+# Download options
+if(NOT DEFINED iMSTK_VRPN_GIT_SHA)
+  set(iMSTK_VRPN_GIT_SHA "7a2845e4b1be2707ccb67dd1d388fb22a766e8f7") # vrpn-imstk-additions
+endif()
+if(NOT DEFINED iMSTK_VRPN_GIT_REPOSITORY)
+  set(iMSTK_VRPN_GIT_REPOSITORY "https://gitlab.kitware.com/iMSTK/vrpn.git")
+endif()
+
 include(imstkAddExternalProject)
 imstk_add_external_project( VRPN
-  GIT_REPOSITORY https://gitlab.kitware.com/iMSTK/vrpn.git
-  GIT_TAG 7a2845e4b1be2707ccb67dd1d388fb22a766e8f7
+  GIT_REPOSITORY ${iMSTK_VRPN_GIT_REPOSITORY}
+  GIT_TAG ${iMSTK_VRPN_GIT_SHA}
   # Cannot get a zip as vrpn uses submodules which are not pulled into the zip
-  #URL https://gitlab.kitware.com/iMSTK/vrpn/-/archive/improve-openhaptics-rebase/vrpn-improve-openhaptics-rebase.zip
-  #URL_MD5 f9f1f10b0844ee244d3478184d58da04
   CMAKE_CACHE_ARGS
     -DBUILD_TESTING:BOOL=OFF
     -DVRPN_SUBPROJECT_BUILD:BOOL=ON
@@ -51,10 +52,12 @@ imstk_add_external_project( VRPN
     -DVRPN_USE_HID:BOOL=ON
     -DVRPN_USE_LIBNIFALCON:BOOL=OFF
     -DVRPN_BUILD_SERVERS:BOOL=ON
-    -DVRPN_USE_PHANTOM_SERVER:BOOL=${iMSTK_USE_OPENHAPTICS}
-    -DVRPN_USE_HDAPI:BOOL=${iMSTK_USE_OPENHAPTICS}
+    -DVRPN_USE_PHANTOM_SERVER:BOOL=${VRPN_USE_OPENHAPTICS}
+    -DVRPN_USE_HDAPI:BOOL=${VRPN_USE_OPENHAPTICS}
     -DOPENHAPTICS_ROOT_DIR:PATH=${OPENHAPTICS_ROOT_DIR}
   DEPENDENCIES ${VRPN_DEPENDENCIES}
   RELATIVE_INCLUDE_PATH ""
   #VERBOSE
-)
\ No newline at end of file
+)
+
+ExternalProject_Message("VRPN" "VRPN: Phantom Omni support [${VRPN_USE_OpenHaptics}]")
diff --git a/CMake/External/External_VTK.cmake b/CMake/External/External_VTK.cmake
index 45901ad3431ff99b29036c1be2eb0a05ad820505..0ba8773017246adfd3163adaa212de8f1029d6db 100644
--- a/CMake/External/External_VTK.cmake
+++ b/CMake/External/External_VTK.cmake
@@ -1,7 +1,7 @@
 #-----------------------------------------------------------------------------
 # Dependencies
 #-----------------------------------------------------------------------------
-set(VTK_DEPENDENCIES "openvr")
+set(VTK_DEPENDENCIES "OpenVR")
 
 set(${PROJECT_NAME}_VTK_REPO_SOURCE "9.0" CACHE STRING "Select VTK Source Branch/Tag")
 set(VTK_SOURCES "9.0;master;release;nightly-master" CACHE INTERNAL "List of available VTK branch,tags to get")
diff --git a/CMake/External/External_VegaFEM.cmake b/CMake/External/External_VegaFEM.cmake
index 27b616ce183dc977365dd5a6b0349e0b80a5c3aa..49f7559ae0edf554d800e572e1964b9e2343848f 100644
--- a/CMake/External/External_VegaFEM.cmake
+++ b/CMake/External/External_VegaFEM.cmake
@@ -1,26 +1,53 @@
+
+include(imstkAddExternalProject)
+
+if(CMAKE_PROJECT_NAME STREQUAL "iMSTK")
+  set(VegaFEM_INSTALL_DIR ${CMAKE_INSTALL_PREFIX})
+endif()
+
 #-----------------------------------------------------------------------------
 # Add External Project
 #-----------------------------------------------------------------------------
 set(VegaFEM_DEPENDENCIES "")
-if(WIN32)
-  list(APPEND VegaFEM_DEPENDENCIES PThreads)
-endif(WIN32)
 
-include(imstkAddExternalProject)
+set(EXTERNAL_PROJECT_OPTIONAL_CMAKE_CACHE_ARGS)
+# After the external project updates its CMake minimum required version
+# to >= 3.15, package export is disabled by default (see policy CMP0090)
+# and explicitly setting this options will not be needed.
+list(APPEND EXTERNAL_PROJECT_OPTIONAL_CMAKE_CACHE_ARGS
+  -DCMAKE_EXPORT_NO_PACKAGE_REGISTRY:BOOL=ON
+  )
+
+# Download options
+if(NOT DEFINED iMSTK_VegaFEM_GIT_SHA)
+  set(iMSTK_VegaFEM_GIT_SHA "b10672cf1493349087a1982c8b5bf775a5f4e415") # master
+endif()
+if(NOT DEFINED iMSTK_VegaFEM_GIT_REPOSITORY)
+  set(EXTERNAL_PROJECT_DOWNLOAD_OPTIONS
+    URL https://gitlab.kitware.com/iMSTK/VegaFEM-CMake/-/archive/${iMSTK_VegaFEM_GIT_SHA}/VegaFEM-CMake-${iMSTK_VegaFEM_GIT_SHA}.zip
+    URL_HASH MD5=d945353d89dab31b2691851a17926b60
+    )
+else()
+  set(EXTERNAL_PROJECT_DOWNLOAD_OPTIONS
+    GIT_REPOSITORY ${iMSTK_VegaFEM_GIT_REPOSITORY}
+    GIT_TAG ${iMSTK_VegaFEM_GIT_SHA}
+    )
+endif()
+
 imstk_add_external_project( VegaFEM
-  URL https://gitlab.kitware.com/iMSTK/vegafemv4.0/-/archive/build_model_reduction/vegafemv4.0-build_model_reduction.zip
-  URL_MD5 3f04bb7c2ba080785bcadf44d1a462a3
+  ${EXTERNAL_PROJECT_DOWNLOAD_OPTIONS}
   CMAKE_CACHE_ARGS
-    -DVegaFEM_ENABLE_PTHREADS_SUPPORT:BOOL=ON
     -DVegaFEM_ENABLE_OpenGL_SUPPORT:BOOL=OFF
     -DVegaFEM_BUILD_MODEL_REDUCTION:BOOL=${${PROJECT_NAME}_USE_MODEL_REDUCTION}
     -DVegaFEM_BUILD_UTILITIES:BOOL=OFF
+    ${EXTERNAL_PROJECT_OPTIONAL_CMAKE_CACHE_ARGS}
   DEPENDENCIES ${VegaFEM_DEPENDENCIES}
   RELATIVE_INCLUDE_PATH ""
   #VERBOSE
 )
+
 if(NOT USE_SYSTEM_VegaFEM)
-  set(VegaFEM_DIR ${CMAKE_INSTALL_PREFIX}/lib/cmake/VegaFEM)
+  set(VegaFEM_DIR ${VegaFEM_INSTALL_DIR}/lib/cmake/VegaFEM)
   #message(STATUS "VegaFEM_DIR : ${VegaFEM_DIR}")
 endif()
 
diff --git a/CMake/External/External_g3log.cmake b/CMake/External/External_g3log.cmake
index 7c4766a3bfb586db7c9395f31c5c660df80b24aa..4630295be90f003eafe2a7aeb08780e6c3316049 100644
--- a/CMake/External/External_g3log.cmake
+++ b/CMake/External/External_g3log.cmake
@@ -3,32 +3,63 @@
 #-----------------------------------------------------------------------------
 
 include(imstkAddExternalProject)
+
+# Set g3log_SOURCE_DIR and g3log_BINARY_DIR
 imstk_define_external_dirs( g3log )
 
+#-----------------------------------------------------------------------------
+# Set install commands
+#-----------------------------------------------------------------------------
+if(CMAKE_PROJECT_NAME STREQUAL "iMSTK")
+  set(g3log_INSTALL_DIR ${CMAKE_INSTALL_PREFIX})
+endif()
+
 if(MSVC)
-  set(g3log_built_library ${CMAKE_COMMAND} -E copy 
+  set(g3log_built_library ${CMAKE_COMMAND} -E copy
                           ${g3log_BINARY_DIR}/$(Configuration)/g3logger$<$<CONFIG:Debug>:d>.lib
-                          ${CMAKE_INSTALL_PREFIX}/lib/)
+                          ${g3log_INSTALL_DIR}/lib/g3logger$<$<CONFIG:Debug>:d>.lib)
   set(g3log_built_shared)
 else()
-  set(g3log_built_library ${CMAKE_COMMAND} -E copy 
+  set(g3log_built_library ${CMAKE_COMMAND} -E copy
                           ${g3log_BINARY_DIR}/libg3logger.a
-                          ${CMAKE_INSTALL_PREFIX}/lib/)
-  set(g3log_built_shared ${CMAKE_COMMAND} -E copy 
+                          ${g3log_INSTALL_DIR}/lib/libg3logger.a)
+  set(g3log_built_shared ${CMAKE_COMMAND} -E copy
                          ${g3log_BINARY_DIR}/libg3logger.so
-                         ${CMAKE_INSTALL_PREFIX}/lib/)
+                         ${g3log_INSTALL_DIR}/lib/libg3logger.so)
 endif()
-set(g3log_hash 6c1698c4f7db6b9e4246ead38051f9866ea3ac06)
 
-imstk_add_external_project( g3log
-  URL https://gitlab.kitware.com/iMSTK/g3log/-/archive/6c1698c4f7db6b9e4246ead38051f9866ea3ac06/archive.zip
-  URL_MD5 3815bbfec2ff51dc473063c35eec0f36
-  CMAKE_CACHE_ARGS
-    -DADD_FATAL_EXAMPLE:BOOL=OFF
+set(g3log_INSTALL_COMMAND
   INSTALL_COMMAND
-    COMMAND ${CMAKE_COMMAND} -E copy_directory ${g3log_SOURCE_DIR}/src/g3log ${CMAKE_INSTALL_PREFIX}/include/g3log
+    COMMAND ${CMAKE_COMMAND} -E copy_directory ${g3log_SOURCE_DIR}/src/g3log ${g3log_INSTALL_DIR}/include/g3log
     COMMAND ${g3log_built_library}
     COMMAND ${g3log_built_shared}
+  )
+
+#-----------------------------------------------------------------------------
+# Add External Project
+#-----------------------------------------------------------------------------
+
+# Download options
+if(NOT DEFINED iMSTK_g3log_GIT_SHA)
+  set(iMSTK_g3log_GIT_SHA "6c1698c4f7db6b9e4246ead38051f9866ea3ac06")
+endif()
+if(NOT DEFINED iMSTK_g3log_GIT_REPOSITORY)
+  set(EXTERNAL_PROJECT_DOWNLOAD_OPTIONS
+    URL https://gitlab.kitware.com/iMSTK/g3log/-/archive/${iMSTK_g3log_GIT_SHA}/g3log-${iMSTK_g3log_GIT_SHA}.zip
+    URL_HASH MD5=3815bbfec2ff51dc473063c35eec0f36
+    )
+else()
+  set(EXTERNAL_PROJECT_DOWNLOAD_OPTIONS
+    GIT_REPOSITORY ${iMSTK_g3log_GIT_REPOSITORY}
+    GIT_TAG ${iMSTK_g3log_GIT_SHA}
+    )
+endif()
+
+imstk_add_external_project( g3log
+  ${EXTERNAL_PROJECT_DOWNLOAD_OPTIONS}
+  CMAKE_CACHE_ARGS
+    -DADD_FATAL_EXAMPLE:BOOL=OFF
+  ${g3log_INSTALL_COMMAND}
   RELATIVE_INCLUDE_PATH "src"
   DEPENDENCIES ""
   #VERBOSE
diff --git a/CMake/External/External_openvr.cmake b/CMake/External/External_openvr.cmake
deleted file mode 100644
index b83957b23948ca7799be43696402435fac10ef78..0000000000000000000000000000000000000000
--- a/CMake/External/External_openvr.cmake
+++ /dev/null
@@ -1,68 +0,0 @@
-#-----------------------------------------------------------------------------
-# Set project prefix path
-#-----------------------------------------------------------------------------
-set(OPENVR_PREFIX ${CMAKE_BINARY_DIR}/External/openvr)
-set(OPENVR_EXTRACT_DIR ${OPENVR_PREFIX}/v${_version})
-
-#-----------------------------------------------------------------------------
-# Set install commands
-#-----------------------------------------------------------------------------
-if(WIN32)
-  set(openvr_libdir "${OPENVR_EXTRACT_DIR}/lib/win64")
-  set(openvr_libname "openvr_api.lib")
-elseif(APPLE)
-  set(openvr_libdir "${OPENVR_EXTRACT_DIR}/lib/osx32")
-  set(openvr_libname "libopenvr_api.dylib")
-elseif(UNIX)
-  set(openvr_libdir "${OPENVR_EXTRACT_DIR}/lib/linux64")
-  set(openvr_libname "libopenvr_api.so")
-endif()
-
-if(WIN32)
-  set(openvr_dlldir "${OPENVR_EXTRACT_DIR}/bin/win64")
-  set(openvr_dllname "openvr_api.dll")
-elseif(APPLE)
-  set(openvr_dlldir "${OPENVR_EXTRACT_DIR}/bin/osx64")
-  set(openvr_dllname "OpenVR.framework")
-elseif(UNIX)
-  set(openvr_dlldir "${OPENVR_EXTRACT_DIR}/bin/linux64")
-  set(openvr_dllname "libopenvr_api.so")
-endif()
-
-set(copy_openvr_headers_command
-  ${CMAKE_COMMAND} -E copy_directory
-  ${OPENVR_EXTRACT_DIR}/headers
-  ${CMAKE_INSTALL_PREFIX}/include/openvr
-  )
-set(copy_openvr_dll_command
-  ${CMAKE_COMMAND} -E copy
-  ${openvr_dlldir}/${openvr_dllname}
-  ${CMAKE_INSTALL_PREFIX}/bin/${openvr_dllname}
-  )
-set(copy_openvr_lib_command
-  ${CMAKE_COMMAND} -E copy
-  ${openvr_libdir}/${openvr_libname}
-  ${CMAKE_INSTALL_PREFIX}/lib/${openvr_libname}
-  )
-
-#-----------------------------------------------------------------------------
-# Add External Project
-#-----------------------------------------------------------------------------
-include(imstkAddExternalProject)
-imstk_add_external_project( openvr
-  URL "https://gitlab.kitware.com/iMSTK/openvr/-/archive/v1.12.5/openvr-v1.12.5.tar.gz"
-  URL_MD5 "42c4d1c4a194860aaa4e793b009b99c0"
-  DOWNLOAD_DIR ${OPENVR_PREFIX}
-  SOURCE_DIR ${OPENVR_EXTRACT_DIR}
-  BINARY_DIR ${OPENVR_EXTRACT_DIR}
-  UPDATE_COMMAND ${SKIP_STEP_COMMAND}
-  CONFIGURE_COMMAND ${SKIP_STEP_COMMAND}
-  BUILD_COMMAND ${SKIP_STEP_COMMAND}
-  INSTALL_COMMAND
-    COMMAND ${copy_openvr_headers_command}
-    COMMAND ${copy_openvr_lib_command}
-    COMMAND ${copy_openvr_dll_command}
-  RELATIVE_INCLUDE_PATH "headers"
-  #VERBOSE
-)
-
diff --git a/CMake/External/External_tbb.cmake b/CMake/External/External_tbb.cmake
deleted file mode 100644
index 576917acd6bff383e0d3aa21a93e5a07bdb026bb..0000000000000000000000000000000000000000
--- a/CMake/External/External_tbb.cmake
+++ /dev/null
@@ -1,12 +0,0 @@
-#-----------------------------------------------------------------------------
-# Add External Project
-#-----------------------------------------------------------------------------
-include(imstkAddExternalProject)
-imstk_add_external_project(tbb
-  URL https://gitlab.kitware.com/iMSTK/TBB-CMake/-/archive/master/TBB-CMake-master.zip
-  URL_MD5 cf8edc032dc473668c6b3109cfee19e8
-  CMAKE_CACHE_ARGS
-    -DTBB_BUILD_TESTS:BOOL=OFF
-  RELATIVE_INCLUDE_PATH ""
-  #VERBOSE
-)
diff --git a/CMake/FindAssimp.cmake b/CMake/FindAssimp.cmake
index 6a85cff71e1a7e96601dc9a3de44099bf3bae924..1459daddbf1c6f891eb42035be3b4227ef31169b 100644
--- a/CMake/FindAssimp.cmake
+++ b/CMake/FindAssimp.cmake
@@ -5,8 +5,8 @@ include(imstkFind)
 
 imstk_find_header(Assimp assimp/Importer.hpp)
 imstk_find_libary(Assimp assimp)
-imstk_find_package(Assimp)
+imstk_find_package(Assimp Assimp::Assimp)
 
-#message(STATUS "Assimp include : ${ASSIMP_INCLUDE_DIRS}")
-#message(STATUS "Assimp libraries : ${ASSIMP_LIBRARIES}")
+#message(STATUS "Assimp include : ${Assimp_INCLUDE_DIRS}")
+#message(STATUS "Assimp libraries : ${Assimp_LIBRARIES}")
 
diff --git a/CMake/FindFTD2XX.cmake b/CMake/FindFTD2XX.cmake
index 2d8d3ec065b5e00e15e12203dd86d6bcc0537c43..c8b94479ff918435cada73aa280781acdb84ba2b 100644
--- a/CMake/FindFTD2XX.cmake
+++ b/CMake/FindFTD2XX.cmake
@@ -5,7 +5,7 @@ include(imstkFind)
 
 imstk_find_header(FTD2XX ftd2xx.h ftd2xx)
 imstk_find_libary(FTD2XX ftd2xx " ")#Use same library for debug)
-imstk_find_package(FTD2XX)
+imstk_find_package(FTD2XX FTD2XX::FTD2XX)
 
 #message(STATUS "FTD2XX include : ${FTD2XX_INCLUDE_DIRS}")
 #message(STATUS "FTD2XX libraries : ${FTD2XX_LIBRARIES}")
diff --git a/CMake/FindLibNiFalcon.cmake b/CMake/FindLibNiFalcon.cmake
index 38571cfd5b5da635e1276c2082a3f721d513a5d9..044f1062c5bddbd3342c6645bb9e7ab8e11ff798 100644
--- a/CMake/FindLibNiFalcon.cmake
+++ b/CMake/FindLibNiFalcon.cmake
@@ -5,8 +5,8 @@ include(imstkFind)
 
 imstk_find_header(LibNiFalcon falcon/core/FalconCore.h)
 imstk_find_libary(LibNiFalcon nifalcon)
-imstk_find_package(LibNiFalcon)
+imstk_find_package(LibNiFalcon LibNiFalcon::LibNiFalcon)
 
-#message(STATUS "LibNiFalcon include : ${LIBNIFALCON_INCLUDE_DIRS}")
-#message(STATUS "LibNiFalcon libraries : ${LIBNIFALCON_LIBRARIES}")
+#message(STATUS "LibNiFalcon include : ${LibNiFalcon_INCLUDE_DIRS}")
+#message(STATUS "LibNiFalcon libraries : ${LibNiFalcon_LIBRARIES}")
 
diff --git a/CMake/FindLibusb.cmake b/CMake/FindLibusb.cmake
index 444e8a1b30459b09b10a7d4a7045ea6f5339fcd0..4ff32a81294244e2e22bcdc48d2588da729c0a18 100644
--- a/CMake/FindLibusb.cmake
+++ b/CMake/FindLibusb.cmake
@@ -10,7 +10,7 @@ endif()
 
 imstk_find_header(Libusb libusb-1.0/libusb.h ${USE_SYSTEM})
 imstk_find_libary(Libusb libusb-1.0 " " ${USE_SYSTEM})#Use same library for debug
-imstk_find_package(Libusb)
+imstk_find_package(Libusb Libusb::Libusb)
 
-#message(STATUS "Libusb include : ${LIBUSB_INCLUDE_DIRS}")
-#message(STATUS "Libusb libraries : ${LIBUSB_LIBRARIES}")
+#message(STATUS "Libusb include : ${Libusb_INCLUDE_DIRS}")
+#message(STATUS "Libusb libraries : ${Libusb_LIBRARIES}")
diff --git a/CMake/FindOpenHapticsSDK.cmake b/CMake/FindOpenHapticsSDK.cmake
index e4d6ef5874f2442e62891fce8f7b5b00ef87fffd..8d6da5286f91a222d21485085abf8b695765a45d 100644
--- a/CMake/FindOpenHapticsSDK.cmake
+++ b/CMake/FindOpenHapticsSDK.cmake
@@ -9,7 +9,7 @@ imstk_find_libary(OpenHapticsSDK hl " ")#Use same library for debug
 imstk_find_libary(OpenHapticsSDK hdu " ")#Use same library for debug
 imstk_find_libary(OpenHapticsSDK hlu " ")#Use same library for debug
 
-imstk_find_package(OpenHapticsSDK)
+imstk_find_package(OpenHapticsSDK OpenHapticsSDK::OpenHapticsSDK)
 
-#message(STATUS "OpenHapticsSDK include : ${OPENHAPTICSSDK_INCLUDE_DIRS}")
-#message(STATUS "OpenHapticsSDK libraries : ${OPENHAPTICSSDK_LIBRARIES}")
+#message(STATUS "OpenHapticsSDK include : ${OpenHapticsSDK_INCLUDE_DIRS}")
+#message(STATUS "OpenHapticsSDK libraries : ${OpenHapticsSDK_LIBRARIES}")
diff --git a/CMake/FindOpenVR.cmake b/CMake/FindOpenVR.cmake
new file mode 100644
index 0000000000000000000000000000000000000000..ad25e18fa6610d55b58c9bad5ac3b33d0e99139d
--- /dev/null
+++ b/CMake/FindOpenVR.cmake
@@ -0,0 +1,16 @@
+include(imstkFind)
+#-----------------------------------------------------------------------------
+# Find All Headers and Libraries for openvr
+#-----------------------------------------------------------------------------
+
+set(_sub_dir "")
+if(NOT DEFINED OpenVR_ROOT_DIR)
+  set(_sub_dir "OpenVR")
+endif()
+
+imstk_find_header(OpenVR openvr.h ${_sub_dir})
+imstk_find_libary(OpenVR openvr_api " ")#Use same library for debug
+imstk_find_package(OpenVR OpenVR::OpenVR)
+
+#message(STATUS "OpenVR include : ${OpenVR_INCLUDE_DIRS}")
+#message(STATUS "OpenVR libraries : ${OpenVR_LIBRARIES}")
diff --git a/CMake/FindPThreads.cmake b/CMake/FindPThreads.cmake
deleted file mode 100644
index 68fb564b309fab8eef3f6f101ed368fc4afb9237..0000000000000000000000000000000000000000
--- a/CMake/FindPThreads.cmake
+++ /dev/null
@@ -1,11 +0,0 @@
-include(imstkFind)
-#-----------------------------------------------------------------------------
-# Find All Headers and Libraries for glm
-#-----------------------------------------------------------------------------
-
-imstk_find_header(PThreads pthread.h pthread)
-imstk_find_libary(PThreads pthread)
-imstk_find_package(PThreads Threads::Threads)
-
-#message(STATUS "PThreads include : ${PTHREADS_INCLUDE_DIRS}")
-#message(STATUS "PThreads libraries : ${PTHREADS_LIBRARIES}")
diff --git a/CMake/FindPhysX.cmake b/CMake/FindPhysX.cmake
index 6244495a436eb1c79ed51347357062e62e9738c9..9288d6795fa188fdcaaa43cb819ab4b3387296bc 100644
--- a/CMake/FindPhysX.cmake
+++ b/CMake/FindPhysX.cmake
@@ -21,7 +21,7 @@ imstk_find_libary(PhysX PhysXPvdSDK _static${physx_release_type}_64 _staticDEBUG
 #imstk_find_libary(PhysX PhysXCharacterKinematic _static${physx_release_type}_64 _staticDEBUG_64)#Different release and debug postfixes
 #imstk_find_libary(PhysX PhysXVehicle _static${physx_release_type}_64 _staticDEBUG_64)#Different release and debug postfixes
 
-imstk_find_package(PhysX)
+imstk_find_package(PhysX PhysX::PhysX)
 
-#message(STATUS "PhysX include : ${PHYSX_INCLUDE_DIRS}")
-#message(STATUS "PhysX libraries : ${PHYSX_LIBRARIES}")
+#message(STATUS "PhysX include : ${PhysX_INCLUDE_DIRS}")
+#message(STATUS "PhysX libraries : ${PhysX_LIBRARIES}")
diff --git a/CMake/FindSFML.cmake b/CMake/FindSFML.cmake
index be98c2b0c6ce7bbde89aa4703e36cf5925f705fb..2f98358412da58539d07853bc3d4114c20c9e83a 100644
--- a/CMake/FindSFML.cmake
+++ b/CMake/FindSFML.cmake
@@ -8,7 +8,7 @@ imstk_find_header(SFML Config.hpp SFML)
 imstk_find_libary(SFML sfml-system "-d")
 imstk_find_libary(SFML sfml-main "-d")
 imstk_find_libary(SFML sfml-audio "-d")
-imstk_find_package(SFML)
+imstk_find_package(SFML SFML::SFML)
 
 #message(STATUS "SFML include : ${SFML_INCLUDE_DIRS}")
 #message(STATUS "SFML libraries : ${SFML_LIBRARIES}")
diff --git a/CMake/FindVRPN.cmake b/CMake/FindVRPN.cmake
index 5f09584faf6f79b8210a4e352f768478c7b7e0ed..da478f952d2f3a841dafbfbdbdde48ecb0a2c3be 100644
--- a/CMake/FindVRPN.cmake
+++ b/CMake/FindVRPN.cmake
@@ -6,7 +6,7 @@ include(imstkFind)
 imstk_find_header(VRPN vrpn_Configure.h vrpn)
 imstk_find_libary(VRPN vrpn)#Use same library for debug
 imstk_find_libary(VRPN quat)
-imstk_find_package(VRPN)
+imstk_find_package(VRPN VRPN::VRPN)
 
 #message(STATUS "VRPN include : ${VRPN_INCLUDE_DIRS}")
 #message(STATUS "VRPN libraries : ${VRPN_LIBRARIES}")
diff --git a/CMake/Findg3log.cmake b/CMake/Findg3log.cmake
index ea5bc3a7b7c3af2c6c9cf0e0af9a3bdacec0ba1b..50d7ba974da728acbfee815b9a1935c144c7c54d 100644
--- a/CMake/Findg3log.cmake
+++ b/CMake/Findg3log.cmake
@@ -11,11 +11,11 @@ endif()
 
 imstk_find_header(g3log g3log/g3log.hpp)
 imstk_find_libary(g3log g3logger ${postfix})
-imstk_find_package(g3log)
+imstk_find_package(g3log g3log::g3log)
 
 if(WIN32)
-  target_link_libraries(g3log INTERFACE general dbghelp)
+  target_link_libraries(g3log::g3log INTERFACE general dbghelp)
 endif()
 
-#message(STATUS "g3log include : ${G3LOG_INCLUDE_DIRS}")
-#message(STATUS "g3log libraries : ${G3LOG_LIBRARIES}")
+#message(STATUS "g3log include : ${g3log_INCLUDE_DIRS}")
+#message(STATUS "g3log libraries : ${g3log_LIBRARIES}")
diff --git a/CMake/Findopenvr.cmake b/CMake/Findopenvr.cmake
deleted file mode 100644
index 8c8c3ea59a03dbe85cd61b3b9739b50c30a4f6e3..0000000000000000000000000000000000000000
--- a/CMake/Findopenvr.cmake
+++ /dev/null
@@ -1,11 +0,0 @@
-include(imstkFind)
-#-----------------------------------------------------------------------------
-# Find All Headers and Libraries for openvr
-#-----------------------------------------------------------------------------
-
-imstk_find_header(openvr openvr.h openvr)
-imstk_find_libary(openvr openvr_api " ")#Use same library for debug
-imstk_find_package(openvr)
-
-#message(STATUS "openvr include : ${OPENVR_INCLUDE_DIRS}")
-#message(STATUS "openvr libraries : ${OPENVR_LIBRARIES}")
diff --git a/CMake/Findtbb.cmake b/CMake/Findtbb.cmake
deleted file mode 100644
index 75e2e0500e75cf061cc3f44735d4bbe80f270264..0000000000000000000000000000000000000000
--- a/CMake/Findtbb.cmake
+++ /dev/null
@@ -1,11 +0,0 @@
-include(imstkFind)
-#-----------------------------------------------------------------------------
-# Find All Headers and Libraries for tbb
-#-----------------------------------------------------------------------------
-
-imstk_find_header(tbb tbb/tbb.h)
-imstk_find_libary(tbb tbb)
-imstk_find_package(tbb)
-
-#message(STATUS "tbb include : ${TBB_INCLUDE_DIRS}")
-#message(STATUS "tbb libraries : ${TBB_LIBRARIES}")
\ No newline at end of file
diff --git a/CMake/Utilities/imstkAddExternalProject.cmake b/CMake/Utilities/imstkAddExternalProject.cmake
index 0e3bf1f8442afe654762765145d4fa3553d953b5..f51f2b5b41d2c478913ebbedc9ab4a767b41cc1b 100644
--- a/CMake/Utilities/imstkAddExternalProject.cmake
+++ b/CMake/Utilities/imstkAddExternalProject.cmake
@@ -33,7 +33,7 @@ macro(imstk_define_external_dirs extProj)
   set(${extProj}_STAMP_DIR "${${extProj}_PREFIX}/stamp")
 endmacro()
 
-macro(imstk_add_external_project extProj)
+macro(imstk_add_external_project proj)
 
   #-----------------------------------------------------------------------------
   # Parse arguments
@@ -42,72 +42,80 @@ macro(imstk_add_external_project extProj)
   set(oneValueArgs RELATIVE_INCLUDE_PATH SOURCE_DIR BINARY_DIR)
   set(multiValueArgs DEPENDENCIES)
   include(CMakeParseArguments)
-  cmake_parse_arguments(${extProj} "${options}" "${oneValueArgs}" "${multiValueArgs}" ${ARGN} )
+  cmake_parse_arguments(_imstk_add_ep_${proj} "${options}" "${oneValueArgs}" "${multiValueArgs}" ${ARGN} )
 
   #-----------------------------------------------------------------------------
   # Verbose (display arguments)
   #-----------------------------------------------------------------------------
-  if(${extProj}_VERBOSE)
+  if(_imstk_add_ep_${proj}_VERBOSE)
     foreach(opt ${options} ${oneValueArgs} ${multiValueArgs})
-      message(STATUS "${extProj}_${opt}: ${${extProj}_${opt}}")
+      message(STATUS "_imstk_add_ep_${proj}_${opt}: ${_imstk_add_ep_${proj}_${opt}}")
     endforeach()
-    message(STATUS "${extProj}_UNPARSED_ARGUMENTS: ${${extProj}_UNPARSED_ARGUMENTS}")
+    message(STATUS "_imstk_add_ep_${proj}_UNPARSED_ARGUMENTS: ${_imstk_add_ep_${proj}_UNPARSED_ARGUMENTS}")
   endif()
 
   #-----------------------------------------------------------------------------
   # Sanity checks
   #-----------------------------------------------------------------------------
-  if(DEFINED ${extProj}_DIR AND NOT EXISTS ${${extProj}_DIR})
+  if(DEFINED ${proj}_DIR AND NOT EXISTS ${${proj}_DIR})
     message(FATAL_ERROR
-      "${extProj}_DIR variable is defined but corresponds to non-existing directory")
+      "${proj}_DIR variable is defined but corresponds to non-existing directory")
   endif()
 
   #-----------------------------------------------------------------------------
   # Solve dependencies
   #-----------------------------------------------------------------------------
-  set(PROJECT_VAR_TEMP ${extProj})
-  ExternalProject_Include_Dependencies( ${extProj}
-    PROJECT_VAR PROJECT_VAR_TEMP
-    EP_ARGS_VAR ${extProj}_EP_ARGS
-    DEPENDS_VAR ${extProj}_DEPENDENCIES
-    USE_SYSTEM_VAR USE_SYSTEM_${extProj}
+  set(proj ${proj})
+  ExternalProject_Include_Dependencies( ${proj}
+    PROJECT_VAR proj
+    EP_ARGS_VAR ${proj}_EP_ARGS
+    DEPENDS_VAR _imstk_add_ep_${proj}_DEPENDENCIES
+    USE_SYSTEM_VAR USE_SYSTEM_${proj}
     SUPERBUILD_VAR ${PROJECT_NAME}_SUPERBUILD
     )
 
   #-----------------------------------------------------------------------------
   # If needs to download and build
   #-----------------------------------------------------------------------------
-  if(NOT DEFINED ${extProj}_DIR AND NOT ${USE_SYSTEM_${extProj}})
-    #-----------------------------------------------------------------------------
-    # Ensure all generator info is passed to external library build
-    #-----------------------------------------------------------------------------
-    set (COMMON_CMAKE_EP_ARGS
-      CMAKE_GENERATOR ${CMAKE_GENERATOR}
-      CMAKE_GENERATOR_PLATFORM ${CMAKE_GENERATOR_PLATFORM}
-      CMAKE_GENERATOR_TOOLSET ${CMAKE_GENERATOR_TOOLSET}
-    )
+  if(NOT DEFINED ${proj}_DIR AND NOT USE_SYSTEM_${proj})
+
+    imstk_define_external_dirs( ${proj} )
 
-    imstk_define_external_dirs( ${extProj} )
+    # SOURCE_DIR and BINARY_DIR variables set in the caller scope or
+    # by "imstk_define_external_dirs" take precedence
+    if(DEFINED ${proj}_SOURCE_DIR)
+      set(_imstk_add_ep_${proj}_SOURCE_DIR ${${proj}_SOURCE_DIR})
+    endif()
+    if(DEFINED ${proj}_BINARY_DIR)
+      set(_imstk_add_ep_${proj}_BINARY_DIR ${${proj}_BINARY_DIR})
+    endif()
+
+    set(${proj}_CMAKE_CACHE_ARGS)
+    if(DEFINED ${proj}_INSTALL_DIR)
+      list(APPEND ${proj}_CMAKE_CACHE_ARGS
+        -DCMAKE_INSTALL_PREFIX:PATH=${${proj}_INSTALL_DIR}
+        )
+    endif()
 
     #-----------------------------------------------------------------------------
     # Add project
     #-----------------------------------------------------------------------------    
-    ExternalProject_add( ${extProj}
-      PREFIX ${${extProj}_PREFIX}
-      SOURCE_DIR ${${extProj}_SOURCE_DIR} # from above or parsed argument
-      BINARY_DIR ${${extProj}_BINARY_DIR} # from above or parsed argument
-      TMP_DIR ${${extProj}_TMP_DIR}       # from above
-      STAMP_DIR ${${extProj}_STAMP_DIR}   # from above
-      ${COMMON_CMAKE_EP_ARGS}             # from above
-      ${${extProj}_EP_ARGS}               # from ExternalProject_Include_Dependencies
-      ${${extProj}_UNPARSED_ARGUMENTS}    # from unparsed arguments of this macro
-      DEPENDS ${${extProj}_DEPENDENCIES}  # from parsed argument
+    ExternalProject_add( ${proj}
+      PREFIX ${${proj}_PREFIX} # from caller's scope (see imstk_define_external_dirs)
+      SOURCE_DIR ${_imstk_add_ep_${proj}_SOURCE_DIR} # from caller's scope (see imstk_define_external_dirs) or parsed argument
+      BINARY_DIR ${_imstk_add_ep_${proj}_BINARY_DIR} # from caller's scope (see imstk_define_external_dirs) or parsed argument
+      TMP_DIR ${${proj}_TMP_DIR}       # from caller's scope (see imstk_define_external_dirs)
+      STAMP_DIR ${${proj}_STAMP_DIR}   # from caller's scope (see imstk_define_external_dirs)
+      ${${proj}_EP_ARGS}               # from ExternalProject_Include_Dependencies
+      CMAKE_CACHE_ARGS ${${proj}_CMAKE_CACHE_ARGS} # from above
+      ${_imstk_add_ep_${proj}_UNPARSED_ARGUMENTS}    # from unparsed arguments of this macro
+      DEPENDS ${_imstk_add_ep_${proj}_DEPENDENCIES}  # from parsed argument
       )
     
     #-----------------------------------------------------------------------------
     # Add the target to ExternalDeps folder
     #-----------------------------------------------------------------------------
-    SET_TARGET_PROPERTIES (${extProj} PROPERTIES FOLDER ExternalDeps)
+    SET_TARGET_PROPERTIES (${proj} PROPERTIES FOLDER ExternalDeps)
 
   #-----------------------------------------------------------------------------
   # If project already built on system
@@ -117,14 +125,14 @@ macro(imstk_add_external_project extProj)
     #-----------------------------------------------------------------------------
     # Find package if USE_SYSTEM
     #-----------------------------------------------------------------------------
-    if( ${USE_SYSTEM_${extProj}} )
-      find_package( ${extProj} REQUIRED )
+    if( ${USE_SYSTEM_${proj}} )
+      find_package( ${proj} REQUIRED )
     endif()
 
     #-----------------------------------------------------------------------------
     # Add empty project (to solve dependencies)
     #-----------------------------------------------------------------------------
-    ExternalProject_Add_Empty(${extProj} DEPENDS ${${extProj}_DEPENDENCIES})
+    ExternalProject_Add_Empty(${proj} DEPENDS ${${proj}_DEPENDENCIES})
 
   endif()
 
@@ -132,7 +140,7 @@ macro(imstk_add_external_project extProj)
   # Keep track of include path for superbuild
   #-----------------------------------------------------------------------------
   list(APPEND CMAKE_INCLUDE_PATH
-     ${${extProj}_SOURCE_DIR}/${${extProj}_RELATIVE_INCLUDE_PATH}
+     ${_imstk_add_ep_${proj}_SOURCE_DIR}/${_imstk_add_ep_${proj}_RELATIVE_INCLUDE_PATH}
      )
 
 endmacro()
diff --git a/CMake/Utilities/imstkAddTest.cmake b/CMake/Utilities/imstkAddTest.cmake
index ec40c5ebb24678eb432ae8c42a4f15ff0ddce8aa..78cf530fe69e4c6a83821fca39d52adb031cb641 100644
--- a/CMake/Utilities/imstkAddTest.cmake
+++ b/CMake/Utilities/imstkAddTest.cmake
@@ -41,11 +41,10 @@ function(imstk_add_test_internal target kind)
   # Create test driver executable
   imstk_add_executable(${test_driver_executable} ${test_files})
 
-  # Link test driver against current target, gtest and pthread
+  # Link test driver against current target and GTest
   target_link_libraries(${test_driver_executable}
     ${target}
     Testing
-    Threads::Threads
     GTest::gtest
     GTest::gmock
 
@@ -71,3 +70,101 @@ endfunction()
 function(imstk_add_visual_test target)
   imstk_add_test_internal(${target} VisualTests)
 endfunction()
+
+#.rst:
+# .. cmake:command:: imstk_add_project_test
+#
+# .. code-block:: cmake
+#
+#  imstk_add_project_test(<test_name>
+#      SOURCE_DIR <source_dir>
+#      BINARY_DIR <binary_dir>
+#      [WORKING_DIR <working_dir>]
+#      [BUILD_OPTIONS <opt1> [...]]
+#    )
+#
+#
+# .. code-block:: cmake
+#
+#  SOURCE_DIR Source directory of the project to build
+#
+#  BINARY_DIR Binary directory of the project to build
+#
+#  WORKING_DIR Specify the working directory in which to execute the test. If not specified
+#              the test will be run with the current working directory set to `<binary_dir>`.
+#
+#  BUILD_OPTIONS List of options for configuring the project.
+#
+function(imstk_add_project_test name)
+  set(options)
+  set(oneValueArgs SOURCE_DIR BINARY_DIR WORKING_DIR)
+  set(multiValueArgs BUILD_OPTIONS)
+  cmake_parse_arguments(_iapt "${options}" "${oneValueArgs}" "${multiValueArgs}" ${ARGN} )
+
+  # Sanity checks
+  set(expected_nonempty_vars SOURCE_DIR BINARY_DIR)
+  foreach(var ${expected_nonempty_vars})
+    if("${_iapt_${var}}" STREQUAL "")
+      message(FATAL_ERROR "error: ${var} argument is either empty or not specified")
+    endif()
+  endforeach()
+
+  if(NOT _iapt_WORKING_DIR)
+    set(_iapt_WORKING_DIR ${_iapt_BINARY_DIR})
+  endif()
+
+  if(_iapt_UNPARSED_ARGUMENTS)
+    message(FATAL_ERROR "Unknown keywords given to imstk_add_project_test(): \"${_iapt_UNPARSED_ARGUMENTS}\"")
+  endif()
+
+  set(_testname ${name})
+  set(_test_source_dir ${_iapt_SOURCE_DIR})
+  set(_test_binary_dir ${_iapt_BINARY_DIR})
+
+  add_test(${_testname}_clean ${CMAKE_COMMAND}
+    -E remove_directory ${_test_binary_dir}
+    )
+
+  set(build_generator_args
+    --build-generator ${CMAKE_GENERATOR}
+    --build-makeprogram ${CMAKE_MAKE_PROGRAM}
+    )
+  if(CMAKE_GENERATOR_PLATFORM)
+    list(APPEND build_generator_args
+      --build-generator-platform ${CMAKE_GENERATOR_PLATFORM}
+      )
+  endif()
+  if(CMAKE_GENERATOR_TOOLSET)
+    list(APPEND build_generator_args
+      --build-generator-toolset ${CMAKE_GENERATOR_TOOLSET}
+      )
+  endif()
+
+  set(build_options_arg)
+  if(_iapt_BUILD_OPTIONS)
+    set(build_options_arg --build-options ${_iapt_BUILD_OPTIONS})
+  endif()
+
+  add_test(
+    NAME ${_testname}
+    COMMAND ${CMAKE_CTEST_COMMAND}
+      --build-and-test
+      "${_test_source_dir}"
+      "${_test_binary_dir}"
+      --build-config $<CONFIG>
+      ${build_generator_args}
+      --build-project ${project}
+      --build-exe-dir "${_test_binary_dir}"
+      --force-new-ctest-process
+      ${build_options_arg}
+      --test-command ${CMAKE_CTEST_COMMAND} -V
+    WORKING_DIRECTORY ${_iapt_WORKING_DIR}
+    )
+
+  set_tests_properties(${_testname}
+      PROPERTIES
+        DEPENDS ${_testname}_clean
+        LABELS "BuildSystem"
+      )
+endfunction()
+
diff --git a/CMake/Utilities/imstkAddUncrustifyCustomTarget.cmake b/CMake/Utilities/imstkAddUncrustifyCustomTarget.cmake
index 54fb34ee317f631cfe706a6d66a964a5a96dd0e8..570cefc87578db86a630a8f9e9328d09079d2b44 100644
--- a/CMake/Utilities/imstkAddUncrustifyCustomTarget.cmake
+++ b/CMake/Utilities/imstkAddUncrustifyCustomTarget.cmake
@@ -15,7 +15,7 @@
     add_test(NAME CodeFormatTest
       COMMAND ${Uncrustify_EXECUTABLE}
       -c ${CMAKE_CURRENT_LIST_DIR}/../../Utilities/Uncrustify/iMSTKUncrustify.cfg
-      -F ${CMAKE_CURRENT_BINARY_DIR}/Uncrustify.list
+      -F ${CMAKE_CURRENT_BINARY_DIR}/uncrustify.list
       --check
       #COMMENT "Run uncrustify in check mode"
       WORKING_DIRECTORY ${CMAKE_CURRENT_LIST_DIR}
diff --git a/CMake/Utilities/imstkFind.cmake b/CMake/Utilities/imstkFind.cmake
index ed741c476c14373be295a4c4e4cb6f83ef4fefd2..b8a4d33556aedd9c7ba49a3ec7b3cd053212cffb 100644
--- a/CMake/Utilities/imstkFind.cmake
+++ b/CMake/Utilities/imstkFind.cmake
@@ -8,9 +8,23 @@ endif()
 
 macro(imstk_find_header package header)
 
+  set(options
+    USE_SYSTEM
+    )
+  set(oneValueArgs
+    )
+  set(multiValueArgs
+    )
+  cmake_parse_arguments(IMSTK_FIND_HEADER
+    "${options}"
+    "${oneValueArgs}"
+    "${multiValueArgs}"
+    ${ARGN}
+    )
+
   # Subdir to the include directory is optional
   set(sub_dir "")
-  set (extra_macro_args ${ARGN})
+  set (extra_macro_args ${IMSTK_FIND_HEADER_UNPARSED_ARGUMENTS})
   # Did we get any optional args?
   list(LENGTH extra_macro_args num_extra_args)
   if (${num_extra_args} GREATER 0)
@@ -18,17 +32,15 @@ macro(imstk_find_header package header)
   endif ()
   
   # Should I look in system locations?
-  set(use_system)
-  foreach(arg IN LISTS extra_macro_args)
-    if(arg STREQUAL "USE_SYSTEM")
-      set(use_system TRUE)
-    endif()
-  endforeach()
+  set(use_system ${IMSTK_FIND_HEADER_USE_SYSTEM})
 
   if(NOT use_system)
     unset(_SEARCH_DIR)
     if(${package}_ROOT_DIR)
-      set(_SEARCH_DIR ${${package}_ROOT_DIR}/${sub_dir})
+      if(NOT DEFINED ${package}_INC_DIR)
+        set(${package}_INC_DIR "include")
+      endif()
+      set(_SEARCH_DIR ${${package}_ROOT_DIR}/${${package}_INC_DIR}/${sub_dir})
     else()
       set(_SEARCH_DIR ${PACKAGE_PREFIX_DIR}/include/${sub_dir})
     endif()
@@ -52,14 +64,13 @@ macro(imstk_find_header package header)
   
 
   if (EXISTS ${${package}_INCLUDE_DIR}/${header})
-    string(TOUPPER ${package} PACKAGE)
+    set(PACKAGE ${package})
     list(APPEND ${PACKAGE}_INCLUDE_DIRS ${${package}_INCLUDE_DIR})
     mark_as_advanced(${PACKAGE}_INCLUDE_DIRS)
   else()
     message(FATAL_ERROR "Could not find ${${package}_INCLUDE_DIR}/${header}")
   endif()
   #message(STATUS "${package}_INCLUDE_DIRS : ${${package}_INCLUDE_DIRS}")
-  unset(${package}_INCLUDE_DIR CACHE)
 endmacro()
 
 #-----------------------------------------------------------------------------
@@ -67,11 +78,24 @@ endmacro()
 #-----------------------------------------------------------------------------
 
 macro(imstk_find_libary package library)
+  set(options
+    USE_SYSTEM
+    )
+  set(oneValueArgs
+    )
+  set(multiValueArgs
+    )
+  cmake_parse_arguments(IMSTK_FIND_LIBRARY
+    "${options}"
+    "${oneValueArgs}"
+    "${multiValueArgs}"
+    ${ARGN}
+    )
 
   # Debug postfix argument is optional
   set(release_postfix)
   set(debug_postfix ${CMAKE_DEBUG_POSTFIX})
-  set (extra_macro_args ${ARGN})
+  set (extra_macro_args ${IMSTK_FIND_LIBRARY_UNPARSED_ARGUMENTS})
   # Did we get any optional args?
   list(LENGTH extra_macro_args num_extra_args)
   if (${num_extra_args} EQUAL 1)
@@ -87,30 +111,28 @@ macro(imstk_find_libary package library)
   endif()
   
   # Should I look in system locations?
-  set(use_system)
-  foreach(arg IN LISTS extra_macro_args)
-    if(arg STREQUAL "USE_SYSTEM")
-      set(use_system TRUE)
-    endif()
-  endforeach()
-  
+  set(use_system ${IMSTK_FIND_LIBRARY_USE_SYSTEM})
+
+  set(IMSTK_ORIG_FIND_LIBRARY_PREFIXES "${CMAKE_FIND_LIBRARY_PREFIXES}")
+  set(CMAKE_FIND_LIBRARY_PREFIXES "lib" "")
+
   if(NOT use_system)
     unset(_SEARCH_DIR)
     if(${package}_ROOT_DIR)
-      if(${package}_LIB_DIR)
-        set(_SEARCH_DIR ${${package}_ROOT_DIR}/${${package}_LIB_DIR})
+      if(NOT DEFINED ${package}_LIB_DIR)
+        set(${package}_LIB_DIR "lib")
       endif()
+      set(_SEARCH_DIR ${${package}_ROOT_DIR}/${${package}_LIB_DIR})
     else()
       set(_SEARCH_DIR ${PACKAGE_PREFIX_DIR}/lib)
     endif()
     #message(STATUS "Looking for ${package} libs in ${_SEARCH_DIR}")
     
     unset(${PACKAGE}_LIBRARY_${library}-RELEASE CACHE)
-    string(TOUPPER ${package} PACKAGE)
+    set(PACKAGE ${package})
     find_library(${PACKAGE}_LIBRARY_${library}-RELEASE
       NAMES
         ${library}${release_postfix}
-        lib${library}${release_postfix}
       PATHS
         ${_SEARCH_DIR}
         ${_SEARCH_DIR}/Release
@@ -121,7 +143,6 @@ macro(imstk_find_libary package library)
     find_library(${PACKAGE}_LIBRARY_${library}-DEBUG
       NAMES
         ${library}${debug_postfix}
-        lib${library}${debug_postfix}
       PATHS
         ${_SEARCH_DIR}
         ${_SEARCH_DIR}/Debug
@@ -133,7 +154,6 @@ macro(imstk_find_libary package library)
     find_library(${PACKAGE}_LIBRARY_${library}-RELEASE
       NAMES
         ${library}${release_postfix}
-        lib${library}${release_postfix}
     )
     
     unset(${PACKAGE}_LIBRARY_${library}-DEBUG CACHE)
@@ -145,6 +165,8 @@ macro(imstk_find_libary package library)
 
   endif()
 
+  set(CMAKE_FIND_LIBRARY_PREFIXES "${IMSTK_ORIG_FIND_LIBRARY_PREFIXES}")
+
   #message(STATUS "Looking for Release Library : ${library}${release_postfix} in ${_SEARCH_DIR}")
   if (EXISTS ${${PACKAGE}_LIBRARY_${library}-RELEASE})
     #message(STATUS "${PACKAGE}_LIBRARY_${library}-RELEASE : ${${PACKAGE}_LIBRARY_${library}-RELEASE}")
@@ -169,7 +191,7 @@ endmacro()
 #-----------------------------------------------------------------------------
 macro(imstk_find_package package)
 
-  string(TOUPPER ${package} PACKAGE)
+  set(PACKAGE ${package})
   if (${PACKAGE}_FOUND)
     return()
   endif()
@@ -206,7 +228,7 @@ endmacro()
 #-----------------------------------------------------------------------------
 macro(imstk_find_header_package package)
 
-  string(TOUPPER ${package} PACKAGE)
+  set(PACKAGE ${package})
   if (${PACKAGE}_FOUND)
     return()
   endif()
diff --git a/CMake/Utilities/imstkSolveDependencies.cmake b/CMake/Utilities/imstkSolveDependencies.cmake
index 361922c129bafd9147b7f64d68cdbcb4239e13fb..afa0e23e5a958ff92b6afd8f87bb5853591e57ca 100644
--- a/CMake/Utilities/imstkSolveDependencies.cmake
+++ b/CMake/Utilities/imstkSolveDependencies.cmake
@@ -1,15 +1,22 @@
 #.rst:
 # ExternalProjectDependency
 # -------------------------
+#
+# .. only:: html
+#
+#    .. contents::
 
 ###########################################################################
 #
-#  Program: 3D Slicer
+#  Library:   CTK
 #
 #  Copyright (c) Kitware Inc.
 #
-#  See COPYRIGHT.txt
-#  or http://www.slicer.org/copyright/copyright.txt for details.
+#  Licensed under the Apache License, Version 2.0 (the "License");
+#  you may not use this file except in compliance with the License.
+#  You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0.txt
 #
 #  Unless required by applicable law or agreed to in writing, software
 #  distributed under the License is distributed on an "AS IS" BASIS,
@@ -17,37 +24,109 @@
 #  See the License for the specific language governing permissions and
 #  limitations under the License.
 #
-#  This file was originally developed by Jean-Christophe Fillion-Robin, Kitware Inc.
-#  and was partially funded by NIH grant 3P41RR013218-12S1
-#
 ###########################################################################
 
 include(CMakeParseArguments)
 
-if(NOT DEFINED EP_LIST_SEPARATOR)
-  set(EP_LIST_SEPARATOR "^^")
-endif()
+#.rst:
+# Global Variables
+# ^^^^^^^^^^^^^^^^
 
 #.rst:
 # .. cmake:variable:: EXTERNAL_PROJECT_DIR
 #
+# This variable describes the directory in which external project files
+# matching ``<EXTERNAL_PROJECT_FILE_PREFIX><projectname>.cmake`` expression are globbed.
+#
 if(NOT EXISTS "${EXTERNAL_PROJECT_DIR}")
   set(EXTERNAL_PROJECT_DIR ${CMAKE_SOURCE_DIR}/SuperBuild)
 endif()
 
+#.rst:
+# .. cmake:variable:: EXTERNAL_PROJECT_ADDITIONAL_DIR
+#
+# If set, this variable represents an other directory in which external project files
+# are searched for if not already found in ``EXTERNAL_PROJECT_DIR``.
+
+#.rst:
+# .. cmake:variable:: EXTERNAL_PROJECT_ADDITIONAL_DIRS
+#
+# If set, this variable represents additional directories in which external project files
+# are searched for if not already found in ``EXTERNAL_PROJECT_DIR`` and
+# ``EXTERNAL_PROJECT_ADDITIONAL_DIR``.
+
 #.rst:
 # .. cmake:variable:: EXTERNAL_PROJECT_FILE_PREFIX
 #
+# This variable describes the prefix of the external project files looked up in
+# ``EXTERNAL_PROJECT_DIR``. It defaults to ``External_``.
+#
 if(NOT DEFINED EXTERNAL_PROJECT_FILE_PREFIX)
   set(EXTERNAL_PROJECT_FILE_PREFIX "External_")
 endif()
 
+#.rst:
+# .. cmake:variable:: SUPERBUILD_TOPLEVEL_PROJECT
+#
+# This variable can be set to explicitly identify the name of the top-level project.
+# If not set, it default to the value of ``CMAKE_PROJECT_NAME``.
+if(NOT DEFINED SUPERBUILD_TOPLEVEL_PROJECT)
+  if(NOT DEFINED CMAKE_PROJECT_NAME)
+    message(FATAL_ERROR "Failed to initialize variable SUPERBUILD_TOPLEVEL_PROJECT. Variable CMAKE_PROJECT_NAME is not defined.")
+  endif()
+  set(SUPERBUILD_TOPLEVEL_PROJECT ${CMAKE_PROJECT_NAME})
+endif()
+
+#.rst:
+# .. cmake:variable:: EP_LIST_SEPARATOR
+#
+# This variable is used to separate list items when passed in various external project
+# ``..._COMMAND`` options.
+#
+# If defaults to ``^^``.
+if(NOT DEFINED EP_LIST_SEPARATOR)
+  set(EP_LIST_SEPARATOR "^^")
+endif()
+
+
+#.rst:
+# .. cmake:variable:: EP_GIT_PROTOCOL
+#
+# The value of this variable is controlled by the option ``<SUPERBUILD_TOPLEVEL_PROJECT>_USE_GIT_PROTOCOL``
+# automatically defined by including this CMake module. Setting this option allows to update the value of
+# ``EP_GIT_PROTOCOL`` variable.
+#
+# If enabled, the variable ``EP_GIT_PROTOCOL`` is set to ``git``. Otherwise, it is set to ``https``.
+# The option is enabled by default.
+#
+# The variable ``EP_GIT_PROTOCOL`` can be used when adding external project. For example:
+#
+# .. code-block:: cmake
+#
+#   ExternalProject_Add(${proj}
+#     ${${proj}_EP_ARGS}
+#     GIT_REPOSITORY "${EP_GIT_PROTOCOL}://github.com/Foo/Foo.git"
+#     [...]
+#     )
+#
+option(${SUPERBUILD_TOPLEVEL_PROJECT}_USE_GIT_PROTOCOL "If behind a firewall turn this off to use https instead." ON)
+set(EP_GIT_PROTOCOL "git")
+if(NOT ${SUPERBUILD_TOPLEVEL_PROJECT}_USE_GIT_PROTOCOL)
+  set(EP_GIT_PROTOCOL "https")
+endif()
+
 # Compute -G arg for configuring external projects with the same CMake generator:
 if(CMAKE_EXTRA_GENERATOR)
   set(EP_CMAKE_GENERATOR "${CMAKE_EXTRA_GENERATOR} - ${CMAKE_GENERATOR}")
 else()
   set(EP_CMAKE_GENERATOR "${CMAKE_GENERATOR}")
 endif()
+set(EP_CMAKE_GENERATOR_PLATFORM "${CMAKE_GENERATOR_PLATFORM}")
+set(EP_CMAKE_GENERATOR_TOOLSET "${CMAKE_GENERATOR_TOOLSET}")
+
+#.rst:
+# Functions
+# ^^^^^^^^^
 
 #.rst:
 # .. cmake:function:: mark_as_superbuild
@@ -67,8 +146,7 @@ endif()
 # .. code-block:: cmake
 #
 #  PROJECTS corresponds to a list of <projectname> that will be added using 'ExternalProject_Add' function.
-#           If not specified and called within a project file, it defaults to the value of 'SUPERBUILD_TOPLEVEL_PROJECT'
-#           Otherwise, it defaults to 'CMAKE_PROJECT_NAME'.
+#           If not specified and called within a project file, it defaults to the value of 'SUPERBUILD_TOPLEVEL_PROJECT'.
 #           If instead 'ALL_PROJECTS' is specified, the variables and labels will be passed to all projects.
 #
 #  VARS is an expected list of variables specified as <varname>:<vartype> to pass to <projectname>
@@ -200,9 +278,15 @@ function(_sb_cmakevar_to_cmakearg cmake_varname_and_type cmake_arg_var has_cfg_i
   _sb_extract_varname_and_vartype(${cmake_varname_and_type} _varname _vartype)
 
   set(_var_value "${${_varname}}")
-  get_property(_value_set_in_cache CACHE ${_varname} PROPERTY VALUE SET)
-  if(_value_set_in_cache)
-    get_property(_var_value CACHE ${_varname} PROPERTY VALUE)
+
+  # Use cache value unless it is INTERNAL
+  if(_vartype STREQUAL "INTERNAL")
+    set(_vartype "STRING")
+  else()
+    get_property(_value_set_in_cache CACHE ${_varname} PROPERTY VALUE SET)
+    if(_value_set_in_cache)
+      get_property(_var_value CACHE ${_varname} PROPERTY VALUE)
+    endif()
   endif()
 
   set(_has_cfg_intdir FALSE)
@@ -215,6 +299,10 @@ function(_sb_cmakevar_to_cmakearg cmake_varname_and_type cmake_arg_var has_cfg_i
     endif()
   endif()
 
+  if(NOT _has_cfg_intdir)
+    string(REPLACE "\"" "\\\"" _var_value "${_var_value}")
+  endif()
+
   set(${cmake_arg_var} -D${_varname}:${_vartype}=${_var_value} PARENT_SCOPE)
   set(${has_cfg_intdir_var} ${_has_cfg_intdir} PARENT_SCOPE)
 
@@ -230,14 +318,13 @@ set(_ALL_PROJECT_IDENTIFIER "ALLALLALL")
 
 #
 #  _sb_append_to_cmake_args(
-#      VARS <varname1>:<vartype1> [<varname2>:<vartype2> [...]]
+#      [VARS <varname1>:<vartype1> [<varname2>:<vartype2> [...]]]
 #      [PROJECTS <projectname> [<projectname> [...]] | ALL_PROJECTS]
 #      [LABELS <label1> [<label2> [...]]]
 #    )
 #
 #  PROJECTS corresponds to a list of <projectname> that will be added using 'ExternalProject_Add' function.
-#           If not specified and called within a project file, it defaults to the value of 'SUPERBUILD_TOPLEVEL_PROJECT'
-#           Otherwise, it defaults to 'CMAKE_PROJECT_NAME'.
+#           If not specified and called within a project file, it defaults to the value of 'SUPERBUILD_TOPLEVEL_PROJECT'.
 #           If instead 'ALL_PROJECTS' is specified, the variables and labels will be passed to all projects.
 #
 #  VARS is an expected list of variables specified as <varname>:<vartype> to pass to <projectname>
@@ -255,11 +342,7 @@ function(_sb_append_to_cmake_args)
   cmake_parse_arguments(_sb "${options}" "${oneValueArgs}" "${multiValueArgs}" ${ARGN})
 
   if(NOT _sb_PROJECTS AND NOT _sb_ALL_PROJECTS)
-    if(SUPERBUILD_TOPLEVEL_PROJECT)
-      set(_sb_PROJECTS ${SUPERBUILD_TOPLEVEL_PROJECT})
-    else()
-      set(_sb_PROJECTS ${CMAKE_PROJECT_NAME})
-    endif()
+    set(_sb_PROJECTS ${SUPERBUILD_TOPLEVEL_PROJECT})
   endif()
 
   if(_sb_ALL_PROJECTS)
@@ -288,6 +371,46 @@ function(_sb_append_to_cmake_args)
   endforeach()
 endfunction()
 
+#.rst:
+# .. cmake:function:: ExternalProject_DeclareLabels
+#
+# .. code-block:: cmake
+#
+#  ExternalProject_DeclareLabels(
+#      [PROJECTS <projectname> [<projectname> [...]] | ALL_PROJECTS]
+#      LABELS <label1> [<label2> [...]]
+#    )
+#
+# .. code-block:: cmake
+#
+#  PROJECTS corresponds to a list of <projectname> that will be added using 'ExternalProject_Add' function.
+#           If not specified and called within a project file, it defaults to the value of 'SUPERBUILD_TOPLEVEL_PROJECT'.
+#           If instead 'ALL_PROJECTS' is specified, the variables and labels will be passed to all projects.
+#
+#  LABELS is a list of label to pass to the <projectname> as CMake CACHE args of the
+#           form -D<projectname>_EP_LABEL_<label>= unless specific variables
+#           have been associated with the labels using mark_as_superbuild.
+#
+function(ExternalProject_DeclareLabels)
+  set(options ALL_PROJECTS)
+  set(oneValueArgs)
+  set(multiValueArgs PROJECTS LABELS)
+  cmake_parse_arguments(_sb "${options}" "${oneValueArgs}" "${multiValueArgs}" ${ARGN})
+
+  if(_sb_PROJECTS AND _sb_ALL_PROJECTS)
+    message(FATAL_ERROR "Arguments 'PROJECTS' and 'ALL_PROJECTS' are mutually exclusive !")
+  endif()
+
+  if(_sb_ALL_PROJECTS)
+    set(optional_arg_ALL_PROJECTS "ALL_PROJECTS")
+  else()
+    set(optional_arg_ALL_PROJECTS PROJECTS ${_sb_PROJECTS})
+  endif()
+
+  _sb_append_to_cmake_args(
+    LABELS ${_sb_LABELS} ${optional_arg_ALL_PROJECTS})
+endfunction()
+
 function(_sb_get_external_project_arguments proj varname)
 
   mark_as_superbuild(${SUPERBUILD_TOPLEVEL_PROJECT}_USE_SYSTEM_${proj}:BOOL)
@@ -299,7 +422,9 @@ function(_sb_get_external_project_arguments proj varname)
       list(REMOVE_DUPLICATES _labels)
       foreach(label ${_labels})
         get_property(${proj}_EP_LABEL_${label} GLOBAL PROPERTY ${proj}_EP_LABEL_${label})
-        list(REMOVE_DUPLICATES ${proj}_EP_LABEL_${label})
+        if(${proj}_EP_LABEL_${label})
+          list(REMOVE_DUPLICATES ${proj}_EP_LABEL_${label})
+        endif()
         _sb_append_to_cmake_args(PROJECTS ${proj}
           VARS ${proj}_EP_LABEL_${label}:STRING)
       endforeach()
@@ -321,19 +446,67 @@ function(_sb_get_external_project_arguments proj varname)
   _sb_collect_args(${_ALL_PROJECT_IDENTIFIER})
 
   set(_ep_arguments "")
+
+  # Option CMAKE_FIND_USE_PACKAGE_REGISTRY was introduced in CMake 3.16
+  if(CMAKE_VERSION VERSION_GREATER "3.15")
+    if(NOT DEFINED CMAKE_FIND_USE_PACKAGE_REGISTRY)
+      set(CMAKE_FIND_USE_PACKAGE_REGISTRY OFF)
+    endif()
+  else()
+    if(NOT DEFINED CMAKE_FIND_PACKAGE_NO_PACKAGE_REGISTRY)
+      set(CMAKE_FIND_PACKAGE_NO_PACKAGE_REGISTRY ON)
+    endif()
+  endif()
+
+  # Set list of CMake options to propagate
+  set(_options
+    CMAKE_EXPORT_COMPILE_COMMANDS:BOOL
+    CMAKE_FIND_PACKAGE_NO_PACKAGE_REGISTRY:BOOL
+    CMAKE_JOB_POOL_COMPILE:STRING
+    CMAKE_JOB_POOL_LINK:STRING
+    CMAKE_JOB_POOLS:STRING
+    )
+  if(CMAKE_VERSION VERSION_GREATER "3.15")
+    list(APPEND _options
+      CMAKE_FIND_USE_PACKAGE_REGISTRY:BOOL
+      )
+  endif()
+
+  # Automatically propagate CMake options
+  foreach(_cmake_option_and_type IN LISTS _options)
+    _sb_extract_varname_and_vartype(${_cmake_option_and_type} _cmake_option _cmake_option_type)
+    if(DEFINED ${_cmake_option})
+      list(APPEND _ep_arguments CMAKE_CACHE_ARGS
+        -D${_cmake_option}:${_cmake_option_type}=${${_cmake_option}}
+        )
+    endif()
+  endforeach()
+
   foreach(property CMAKE_ARGS CMAKE_CACHE_ARGS)
     get_property(${proj}_EP_PROPERTY_${property} GLOBAL PROPERTY ${proj}_EP_PROPERTY_${property})
     get_property(${_ALL_PROJECT_IDENTIFIER}_EP_PROPERTY_${property} GLOBAL PROPERTY ${_ALL_PROJECT_IDENTIFIER}_EP_PROPERTY_${property})
     set(_all ${${proj}_EP_PROPERTY_${property}} ${${_ALL_PROJECT_IDENTIFIER}_EP_PROPERTY_${property}})
-    if(_all)
+    list(LENGTH _all _num_properties)
+    if(_num_properties GREATER 0)
       list(APPEND _ep_arguments ${property} ${_all})
     endif()
   endforeach()
 
   list(APPEND _ep_arguments LIST_SEPARATOR ${EP_LIST_SEPARATOR})
 
-  list(APPEND _ep_arguments CMAKE_GENERATOR ${EP_CMAKE_GENERATOR})
-
+  list(APPEND _ep_arguments CMAKE_GENERATOR ${_sb_CMAKE_GENERATOR})
+  if(CMAKE_VERSION VERSION_GREATER "3.0")
+    list(APPEND _ep_arguments CMAKE_GENERATOR_PLATFORM ${_sb_CMAKE_GENERATOR_PLATFORM})
+  endif()
+  list(APPEND _ep_arguments CMAKE_GENERATOR_TOOLSET ${_sb_CMAKE_GENERATOR_TOOLSET})
+  if(CMAKE_VERSION VERSION_EQUAL "3.4" OR CMAKE_VERSION VERSION_GREATER "3.4")
+    # USES_TERMINAL_* options were introduced in CMake 3.4
+    foreach(step IN ITEMS DOWNLOAD UPDATE CONFIGURE BUILD TEST INSTALL)
+      list(APPEND _ep_arguments
+        USES_TERMINAL_${step} 1
+        )
+    endforeach()
+  endif()
   set(${varname} ${_ep_arguments} PARENT_SCOPE)
 endfunction()
 
@@ -436,6 +609,41 @@ function(_sb_is_optional proj output_var)
   set(${output_var} ${optional} PARENT_SCOPE)
 endfunction()
 
+#.rst:
+# .. cmake:function:: ExternalProject_Add_Dependencies
+#
+# .. code-block:: cmake
+#
+#  ExternalProject_Add_Dependencies(<project_name>
+#      DEPENDS <dep1> [<dep2> [...]]
+#    )
+#
+#
+# .. code-block:: cmake
+#
+#  DEPENDS  List of additional dependencies to associat with `<project_name>`.
+#
+macro(ExternalProject_Add_Dependencies project_name)
+  set(options)
+  set(oneValueArgs)
+  set(multiValueArgs DEPENDS)
+  cmake_parse_arguments(_epad "${options}" "${oneValueArgs}" "${multiValueArgs}" ${ARGN})
+
+  # Sanity checks
+  if(x${project_name} STREQUAL xDEPENDS)
+    message(FATAL_ERROR "Argument <project_name> is missing !")
+  endif()
+  if(_epad_UNPARSED_ARGUMENTS)
+    message(FATAL_ERROR "Invalid arguments: ${_epad_UNPARSED_ARGUMENTS}")
+  endif()
+
+  if(NOT _epad_DEPENDS)
+    message(FATAL_ERROR "Argument DEPENDS is missing")
+  endif()
+
+  set_property(GLOBAL PROPERTY SB_${project_name}_ADDITIONAL_DEPENDS ${_epad_DEPENDS})
+endmacro()
+
 #.rst:
 # .. cmake:function:: ExternalProject_Include_Dependencies
 #
@@ -447,11 +655,45 @@ endfunction()
 #      [DEPENDS_VAR <depends_var>]
 #      [USE_SYSTEM_VAR <use_system_var>]
 #      [SUPERBUILD_VAR <superbuild_var>]
+#      [CMAKE_GENERATOR <cmake_generator>]
+#      [CMAKE_GENERATOR_PLATFORM <cmake_generator_platform>]
+#      [CMAKE_GENERATOR_TOOLSET <cmake_generator_toolset>]
 #    )
 #
+#
+# .. code-block:: cmake
+#
+#  PROJECT_VAR Name of the variable containing the name of the included project.
+#              By default, it is `proj` and it is set to `<project_name>`.
+#
+#  EP_ARGS_VAR Name of the variable listing arguments to pass to ExternalProject.
+#              If not specified, variable name default to `<project_name>_EP_ARGS`.
+#
+#  DEPENDS_VAR Name of the variable containing the dependency of the included project.
+#              By default, it is `<project_name>_DEPENDS`.
+#
+#
+#  USE_SYSTEM_VAR Name of the variable indicating if the system version of <project_name>
+#                 should be looked up. Lookup of the project is left to the developer implementing
+#                 the external project file.
+#                 By default, it is `<SUPERBUILD_TOPLEVEL_PROJECT>_USE_SYSTEM_<project_name>`.
+#
+#  SUPERBUILD_VAR Name of the variable indicating if the top-level or inner project is being built.
+#                 By default, it is `<SUPERBUILD_TOPLEVEL_PROJECT>_SUPERBUILD`.
+#
+#
+#  CMAKE_GENERATOR
+#  CMAKE_GENERATOR_PLATFORM
+#  CMAKE_GENERATOR_TOOLSET These three options allow to overwrite the values set in the top-level project that
+#                          would otherwise automatically be propagated to dependent projects.
+#
 macro(ExternalProject_Include_Dependencies project_name)
   set(options)
-  set(oneValueArgs PROJECT_VAR DEPENDS_VAR EP_ARGS_VAR USE_SYSTEM_VAR SUPERBUILD_VAR)
+  set(oneValueArgs PROJECT_VAR DEPENDS_VAR EP_ARGS_VAR USE_SYSTEM_VAR SUPERBUILD_VAR
+    CMAKE_GENERATOR
+    CMAKE_GENERATOR_PLATFORM
+    CMAKE_GENERATOR_TOOLSET
+    )
   set(multiValueArgs)
   cmake_parse_arguments(_sb "${options}" "${oneValueArgs}" "${multiValueArgs}" ${ARGN})
 
@@ -461,6 +703,9 @@ macro(ExternalProject_Include_Dependencies project_name)
       OR x${project_name} STREQUAL xDEPENDS_VAR
       OR x${project_name} STREQUAL xUSE_SYSTEM_VAR
       OR x${project_name} STREQUAL xSUPERBUILD_VAR
+      OR x${project_name} STREQUAL xCMAKE_GENERATOR
+      OR x${project_name} STREQUAL xCMAKE_GENERATOR_PLATFORM
+      OR x${project_name} STREQUAL xCMAKE_GENERATOR_TOOLSET
       )
     message(FATAL_ERROR "Argument <project_name> is missing !")
   endif()
@@ -514,12 +759,31 @@ macro(ExternalProject_Include_Dependencies project_name)
     #message("[${project_name}] Setting _sb_SUPERBUILD_VAR with default value '${_sb_SUPERBUILD_VAR}'")
   endif()
 
+  # Set default for optional CMAKE_GENERATOR_* parameters
+  foreach(varname IN ITEMS
+    "CMAKE_GENERATOR"
+    "CMAKE_GENERATOR_PLATFORM"
+    "CMAKE_GENERATOR_TOOLSET"
+    )
+    if(NOT _sb_${varname})
+      set(_sb_${varname} ${EP_${varname}})
+      #message("[${project_name}] Setting _sb_${varname} with default value '${_sb_${varname}}'")
+    else()
+      #message("[${project_name}] Setting _sb_${varname} to value '${_sb_${varname}}'")
+    endif()
+  endforeach()
+
   # Keeping track of variable name independently of the recursion
   if(NOT DEFINED _sb_SB_VAR)
     set(_sb_SB_VAR ${_sb_SUPERBUILD_VAR})
     #message("[${project_name}] Setting _sb_SB_VAR with default value '${_sb_SB_VAR}'")
   endif()
 
+  # Try to detect if superbuild variable was improperly passed
+  if("${_sb_SB_VAR}" STREQUAL "_SUPERBUILD")
+    message(FATAL_ERROR "SUPERBUILD_VAR value is incorrectly set to '_SUPERBUILD'")
+  endif()
+
   # Set local variables
   set(_sb_DEPENDS ${${_sb_DEPENDS_VAR}})
   set(_sb_USE_SYSTEM ${${_sb_USE_SYSTEM_VAR}})
@@ -541,6 +805,12 @@ macro(ExternalProject_Include_Dependencies project_name)
     set(SB_FIRST_PASS TRUE)
   endif()
 
+  # Extra dependencies specified using "ExternalProject_Add_Dependencies"
+  get_property(_sb_ADDITIONAL_DEPENDS GLOBAL PROPERTY SB_${_sb_proj}_ADDITIONAL_DEPENDS)
+  if(NOT "x${_sb_ADDITIONAL_DEPENDS}" STREQUAL "x")
+    list(APPEND _sb_DEPENDS ${_sb_ADDITIONAL_DEPENDS})
+  endif()
+
   set(_sb_REQUIRED_DEPENDS)
   foreach(dep ${_sb_DEPENDS})
     if(NOT ${_sb_proj} STREQUAL ${SUPERBUILD_TOPLEVEL_PROJECT})
@@ -581,21 +851,38 @@ macro(ExternalProject_Include_Dependencies project_name)
   set_property(GLOBAL PROPERTY SB_${_sb_proj}_USE_SYSTEM       ${_sb_USE_SYSTEM})
   set_property(GLOBAL PROPERTY SB_${_sb_proj}_USE_SYSTEM_VAR   ${_sb_USE_SYSTEM_VAR})
   set_property(GLOBAL PROPERTY SB_${_sb_proj}_PROJECT_VAR      ${_sb_PROJECT_VAR})
+  foreach(varname IN ITEMS
+      "CMAKE_GENERATOR"
+      "CMAKE_GENERATOR_PLATFORM"
+      "CMAKE_GENERATOR_TOOLSET"
+    )
+    set_property(GLOBAL PROPERTY SB_${_sb_proj}_${varname}  ${_sb_${varname}})
+  endforeach()
   superbuild_stack_push(SB_PROJECT_STACK ${_sb_proj})
 
   # Include dependencies
   foreach(dep ${_sb_DEPENDS})
     get_property(_included GLOBAL PROPERTY SB_${dep}_FILE_INCLUDED)
     if(NOT _included)
-      # XXX - Refactor - Add a single variable named 'EXTERNAL_PROJECT_DIRS'
       if(EXISTS "${EXTERNAL_PROJECT_DIR}/${EXTERNAL_PROJECT_FILE_PREFIX}${dep}.cmake")
         include(${EXTERNAL_PROJECT_DIR}/${EXTERNAL_PROJECT_FILE_PREFIX}${dep}.cmake)
       elseif(EXISTS "${${dep}_FILEPATH}")
+        # Originally implemented to support CTK buildsystem
         include(${${dep}_FILEPATH})
       elseif(EXISTS "${EXTERNAL_PROJECT_ADDITIONAL_DIR}/${EXTERNAL_PROJECT_FILE_PREFIX}${dep}.cmake")
         include(${EXTERNAL_PROJECT_ADDITIONAL_DIR}/${EXTERNAL_PROJECT_FILE_PREFIX}${dep}.cmake)
       else()
-        message(FATAL_ERROR "Can't find ${EXTERNAL_PROJECT_FILE_PREFIX}${dep}.cmake")
+        set(_found_ep_cmake FALSE)
+        foreach(_external_project_additional_dir ${EXTERNAL_PROJECT_ADDITIONAL_DIRS})
+          if(EXISTS "${_external_project_additional_dir}/${EXTERNAL_PROJECT_FILE_PREFIX}${dep}.cmake")
+            include(${_external_project_additional_dir}/${EXTERNAL_PROJECT_FILE_PREFIX}${dep}.cmake)
+            set(_found_ep_cmake TRUE)
+            break()
+          endif()
+        endforeach()
+        if(NOT _found_ep_cmake)
+          message(FATAL_ERROR "Can't find ${EXTERNAL_PROJECT_FILE_PREFIX}${dep}.cmake")
+        endif()
       endif()
       set_property(GLOBAL PROPERTY SB_${dep}_FILE_INCLUDED 1)
     endif()
@@ -603,6 +890,13 @@ macro(ExternalProject_Include_Dependencies project_name)
 
   # Restore variables
   superbuild_stack_pop(SB_PROJECT_STACK _sb_proj)
+  foreach(varname IN ITEMS
+      "CMAKE_GENERATOR"
+      "CMAKE_GENERATOR_PLATFORM"
+      "CMAKE_GENERATOR_TOOLSET"
+    )
+    get_property(_sb_${varname}  GLOBAL PROPERTY SB_${_sb_proj}_${varname})
+  endforeach()
   get_property(_sb_PROJECT_VAR      GLOBAL PROPERTY SB_${_sb_proj}_PROJECT_VAR)
   get_property(_sb_USE_SYSTEM_VAR   GLOBAL PROPERTY SB_${_sb_proj}_USE_SYSTEM_VAR)
   get_property(_sb_USE_SYSTEM       GLOBAL PROPERTY SB_${_sb_proj}_USE_SYSTEM)
@@ -635,12 +929,23 @@ macro(ExternalProject_Include_Dependencies project_name)
       set(${_sb_PROJECT_VAR} ${_sb_proj})
 
       set(SB_SECOND_PASS TRUE)
+      set(_ep_include_deps_EXTRA_ARGS )
+      foreach(varname IN ITEMS
+          "CMAKE_GENERATOR"
+          "CMAKE_GENERATOR_PLATFORM"
+          "CMAKE_GENERATOR_TOOLSET"
+        )
+        list(APPEND _ep_include_deps_EXTRA_ARGS
+          ${varname} ${_sb_${varname}}
+          )
+      endforeach()
       ExternalProject_Include_Dependencies(${_sb_proj}
         PROJECT_VAR ${_sb_PROJECT_VAR}
         DEPENDS_VAR ${_sb_DEPENDS_VAR}
         EP_ARGS_VAR ${_sb_EP_ARGS_VAR}
         USE_SYSTEM_VAR _sb_USE_SYSTEM
         SUPERBUILD_VAR ${_sb_SB_VAR}
+        ${_ep_include_deps_EXTRA_ARGS}
         )
       set(SB_SECOND_PASS FALSE)
     endif()
@@ -728,3 +1033,84 @@ function(ExternalProject_Install_CMake project_name)
 
   install(SCRIPT ${binary_dir}/cmake_install.cmake)
 endfunction()
+
+#.rst:
+# .. cmake:function:: ExternalProject_SetIfNotDefined
+#
+# Set a variable to its default value if not already defined.
+#
+# .. code-block:: cmake
+#
+#  ExternalProject_SetIfNotDefined(<var> <defaultvalue> [OBFUSCATE] [QUIET])
+#
+# If *NOT* already defined, the variable <var> is set with:
+#  (1) the value of the environment variable <var>, if defined.
+#  (2) the value of the local variable variable <var>, if defined.
+#  (3) if none of the above is defined, the <defaultvalue> passed as a parameter.
+#
+# Passing the optional parameter 'OBFUSCATE' will display 'OBFUSCATED' instead of the real value.
+# Passing the optional parameter 'QUIET' will not display any message.
+#
+# For convenience, the value of the cache variable named <var> will
+# be displayed if it was set and if QUIET has not been passed.
+macro(ExternalProject_SetIfNotDefined var defaultvalue)
+  set(_obfuscate FALSE)
+  set(_quiet FALSE)
+  foreach(arg ${ARGN})
+    if(arg STREQUAL "OBFUSCATE")
+      set(_obfuscate TRUE)
+    endif()
+    if(arg STREQUAL "QUIET")
+      set(_quiet TRUE)
+    endif()
+  endforeach()
+  if(DEFINED ENV{${var}} AND NOT DEFINED ${var})
+    set(_value "$ENV{${var}}")
+    if(_obfuscate)
+      set(_value "OBFUSCATED")
+    endif()
+    if(NOT _quiet)
+      message(STATUS "Setting '${var}' variable with environment variable value '${_value}'")
+    endif()
+    set(${var} $ENV{${var}})
+  endif()
+  if(NOT DEFINED ${var})
+    set(_value "${defaultvalue}")
+    if(_obfuscate)
+      set(_value "OBFUSCATED")
+    endif()
+    if(NOT _quiet)
+      message(STATUS "Setting '${var}' variable with default value '${_value}'")
+    endif()
+    set(${var} "${defaultvalue}")
+  endif()
+  get_property(_is_set CACHE ${var} PROPERTY VALUE SET)
+  if(_is_set AND NOT _quiet)
+    set(_value "${${var}}")
+    if(_obfuscate)
+      set(_value "OBFUSCATED")
+    endif()
+    message(STATUS "Cache variable '${var}' set to '${_value}'")
+  endif()
+endmacro()
+
+#.rst:
+# .. cmake:function:: ExternalProject_AlwaysConfigure
+#
+# Add a external project step named `forceconfigure` to `project_name` ensuring
+# the project will always be reconfigured.
+#
+# .. code-block:: cmake
+#
+#  ExternalProject_AlwaysConfigure(<project_name>)
+function(ExternalProject_AlwaysConfigure proj)
+  # This custom external project step forces the configure and later
+  # steps to run.
+  _ep_get_step_stampfile(${proj} "configure" stampfile)
+  ExternalProject_Add_Step(${proj} forceconfigure
+    COMMAND ${CMAKE_COMMAND} -E remove ${stampfile}
+    COMMENT "Forcing configure step for '${proj}'"
+    DEPENDEES build
+    ALWAYS 1
+    )
+endfunction()
diff --git a/CMake/iMSTKConfig.cmake.in b/CMake/iMSTKConfig.cmake.in
index fb41d63d50a51bba56cc46202715643c06bbd248..aa6a0e8501b99c5257c6dfb7ceb3ec6f45c75bb4 100644
--- a/CMake/iMSTKConfig.cmake.in
+++ b/CMake/iMSTKConfig.cmake.in
@@ -5,125 +5,102 @@ set(export_config_name "@export_config_name@")
 set_and_check(${export_config_name}Targets "${CMAKE_CURRENT_LIST_DIR}/${export_config_name}Targets.cmake")
 
 include(${${export_config_name}Targets})
-include(CMakeFindDependencyMacro)
 
-# iMSTK settings
+@CONFIG_CODE@
+
 set(iMSTK_ROOT ${PACKAGE_PREFIX_DIR})
 set(iMSTK_DATA_DIR ${PACKAGE_PREFIX_DIR}/data)
+
+# iMSTK settings
+set(iMSTK_AUDIO_ENABLED @iMSTK_AUDIO_ENABLED@)
 set(iMSTK_USE_OpenHaptics @iMSTK_USE_OpenHaptics@)
 set(iMSTK_USE_VTK_OSMESA @iMSTK_USE_VTK_OSMESA@)
 set(iMSTK_BUILD_TESTING @iMSTK_BUILD_TESTING@)
 set(iMSTK_USE_PHYSX @iMSTK_USE_PHYSX@)
 set(iMSTK_USE_VRPN @iMSTK_USE_VRPN@)
+set(iMSTK_VTK_DEPENDENCIES "@iMSTK_VTK_DEPENDENCIES@")
+
+# Save
+set(_iMSTK_ORIG_CMAKE_DEBUG_POSTFIX ${CMAKE_DEBUG_POSTFIX})
+set(_iMSTK_ORIG_CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH})
+
+set(CMAKE_DEBUG_POSTFIX @CMAKE_DEBUG_POSTFIX@)
 
 # Use the iMSTK modules to find all required packages
-set(CACHE_CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH})
-list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_LIST_DIR}/modules")
-include(${CMAKE_CURRENT_LIST_DIR}/modules/imstkFind.cmake)
+list(APPEND CMAKE_MODULE_PATH
+  "${CMAKE_CURRENT_LIST_DIR}/modules"
+  "@iMSTK_SOURCE_DIR@/CMake"
+  "@iMSTK_SOURCE_DIR@/CMake/Utilities"
+  )
+
 include(CMakeFindDependencyMacro)
-set(CMAKE_DEBUG_POSTFIX @CMAKE_DEBUG_POSTFIX@)
 
 # Assimp
-find_package( Assimp REQUIRED )
+find_dependency( Assimp )
 
 # Eigen3
-set(Eigen3_DIR "@Eigen3_DIR@")
-find_dependency( Eigen3 REQUIRED )
+find_dependency( Eigen3 )
 
 # FTD2XX
 if(WIN32)
-  find_package( FTD2XX REQUIRED )
+  find_dependency( FTD2XX )
 endif()
 
 # g3log
-find_package( g3log REQUIRED )
+find_dependency( g3log )
 
 # GTest
 if(iMSTK_BUILD_TESTING)
-  set(GTest_DIR "@GTest_DIR@")
-  find_dependency( GTest REQUIRED NO_DEFAULT_PATH )
+  find_dependency( GTest CONFIG )
 endif()
 
 # LibNiFalcon
-find_package( LibNiFalcon REQUIRED)
+find_dependency( LibNiFalcon )
 
 # Libusb
-find_package( Libusb REQUIRED)
+find_dependency( Libusb )
 
 # OpenVR
-find_package( openvr REQUIRED )
+find_dependency( OpenVR )
 
 # PhysX
 if (iMSTK_USE_PHYSX)
-  find_package(PhysX REQUIRED)
+  find_dependency(PhysX REQUIRED)
 endif()
 
 # SFML
-if(WIN32)
-  find_package( SFML REQUIRED )
+if(iMSTK_AUDIO_ENABLED)
+  find_dependency( SFML REQUIRED )
   add_definitions( -DiMSTK_AUDIO_ENABLED )
 endif()
 
-# tbb
-find_package(tbb REQUIRED)
-if (MSVC)
-  add_definitions(-D__TBB_NO_IMPLICIT_LINKAGE=1)
-endif()
+# TBB
+find_dependency(TBB)
 
 # VegaFEM
-set(VegaFEM_DIR "@VegaFEM_DIR@")
-find_dependency( VegaFEM REQUIRED CONFIG )
+find_dependency( VegaFEM )
 
 # VRPN
 if (iMSTK_USE_VRPN)
-  find_package( VRPN REQUIRED )
+  find_dependency( VRPN )
 endif()
 
 # OpenHaptics
 if(iMSTK_USE_OpenHaptics)
-  find_package( OpenHapticsSDK REQUIRED )
+  find_dependency( OpenHapticsSDK )
   add_definitions( -DiMSTK_USE_OPENHAPTICS )
 endif()
 
 # VTK
-list(GET OPENVR_INCLUDE_DIRS 0 OpenVR_INCLUDE_DIR)
-list(GET OPENVR_LIBRARIES 1 OpenVR_LIBRARY)
-set(OpenVR_INCLUDE_DIR ${OpenVR_INCLUDE_DIR} CACHE INTERNAL "")
-set(OpenVR_LIBRARY ${OpenVR_LIBRARY} CACHE INTERNAL "")
-set(VTK_DIR "@VTK_DIR@")
 find_dependency(VTK CONFIG)
-# modules are linked via `VTK::CommonCore`
-# vtk_module_autoinit is needed
-find_dependency(VTK COMPONENTS
-  ChartsCore
-  CommonCore
-  CommonDataModel
-  FiltersCore
-  FiltersExtraction
-  FiltersGeneral
-  FiltersModeling
-  FiltersSources
-  IOExport
-  IOImport
-  IOPLY
-  IOParallel
-  IOParallelXML
-  ImagingCore
-  ImagingGeneral
-  ImagingStencil
-  InteractionStyle
-  RenderingAnnotation
-  RenderingContext2D
-  RenderingContextOpenGL2
-  RenderingCore
-  RenderingExternal
-  RenderingOpenGL2
-  RenderingOpenVR
-  RenderingVolume
-  RenderingVolumeOpenGL2
-  ViewsContext2D)
-find_dependency(VTK COMPONENTS ${VTK_DEPENDENCIES})
+find_package(vtkRenderingOpenVR QUIET)
+find_package(vtkRenderingExternal QUIET)
+find_dependency(VTK COMPONENTS ${iMSTK_VTK_DEPENDENCIES})
+
 if(iMSTK_USE_VTK_OSMESA)
   add_definitions(-DiMSTK_USE_VTK_OSMESA)
 endif()
-set(CMAKE_MODULE_PATH ${CACHE_CMAKE_MODULE_PATH})
\ No newline at end of file
+
+# Restore
+set(CMAKE_DEBUG_POSTFIX ${_iMSTK_ORIG_CMAKE_DEBUG_POSTFIX})
+set(CMAKE_MODULE_PATH ${_iMSTK_ORIG_CMAKE_MODULE_PATH})
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 8d8b0e15feba7aa69eccd02b711413183181ec11..9d33aa2b6457f491e5c8cd208c7f0025976dc4dc 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -1,10 +1,6 @@
 cmake_minimum_required(VERSION 3.9)
 project(iMSTK VERSION 5.0.0 LANGUAGES C CXX)
 
-if(UNIX AND NOT APPLE)
-  set(LINUX TRUE)
-endif()
-
 #-----------------------------------------------------------------------------
 # Set a default build type if none was specified
 #-----------------------------------------------------------------------------
@@ -17,11 +13,6 @@ set(CMAKE_DEBUG_POSTFIX "d")
 
 set_property(GLOBAL PROPERTY USE_FOLDERS ON)
 
-if(CMAKE_INSTALL_PREFIX_INITIALIZED_TO_DEFAULT)
-  set(CMAKE_INSTALL_PREFIX ${CMAKE_BINARY_DIR}/install CACHE PATH "Install location" FORCE)
-endif()
-set(CMAKE_PREFIX_PATH ${CMAKE_INSTALL_PREFIX})
- 
 #-----------------------------------------------------------------------------
 # Project install directories
 #-----------------------------------------------------------------------------
@@ -35,7 +26,7 @@ file(MAKE_DIRECTORY ${CMAKE_INSTALL_PREFIX}/include)
 file(MAKE_DIRECTORY ${CMAKE_INSTALL_PREFIX}/lib) 
 
 #-----------------------------------------------------------------------------
-# Update CMake module path & cmake dir
+# Update CMake module path & CMake dir
 #-----------------------------------------------------------------------------
 set(CMAKE_MODULE_PATH
     ${CMAKE_CURRENT_SOURCE_DIR}/CMake
@@ -45,11 +36,23 @@ set(CMAKE_MODULE_PATH
     )
 set(${PROJECT_NAME}_CMAKE_DIR ${CMAKE_CURRENT_SOURCE_DIR}/CMake)
 
+# Add "mark_as_superbuild" CMake function to associate option with inner build
+include(imstkSolveDependencies)
+
 #-----------------------------------------------------------------------------
 # C++11 Support
 #-----------------------------------------------------------------------------
-set(CMAKE_CXX_STANDARD 14)
+set(_msg "Setting C++ standard")
+message(STATUS "${_msg}")
+if(NOT CMAKE_CXX_STANDARD)
+  set(CMAKE_CXX_STANDARD 14)
+endif()
 set(CMAKE_CXX_STANDARD_REQUIRED ON)
+message(STATUS "${_msg} - C++${CMAKE_CXX_STANDARD}")
+if(NOT CMAKE_CXX_STANDARD MATCHES "^(11|14|17)$")
+  message(FATAL_ERROR "CMAKE_CXX_STANDARD must be set to 11, 14 or 17")
+endif()
+
 set(THREADS_PREFER_PTHREAD_FLAG ON)
 
 # Prevents a compiler error for Visual Studio 15.8
@@ -67,9 +70,13 @@ endif()
 
 # SWIG 
 option(${PROJECT_NAME}_WRAP_CSHARP "Build iMSTK-C# wrapper code and lib" OFF)
+mark_as_superbuild(${PROJECT_NAME}_WRAP_CSHARP:BOOL)
+
 # SWIG will generate managed array using pinning if this option is ON. Otherwise using P/Invoke default array marshalling.
 option(${PROJECT_NAME}_SWIG_PINNED_ARRAY "Managed C# arrays using pinning" ON)
 mark_as_advanced(${PROJECT_NAME}_SWIG_PINNED_ARRAY)
+mark_as_superbuild(${PROJECT_NAME}_SWIG_PINNED_ARRAY:BOOL)
+
 if (${PROJECT_NAME}_WRAP_CSHARP)
   find_package(SWIG REQUIRED)
   set(CMAKE_POSITION_INDEPENDENT_CODE ON)
@@ -81,6 +88,7 @@ endif()
 
 # CUDA
 option(${PROJECT_NAME}_ENABLE_CUDA_BACKEND "Enable iMSTK CUDA backend" OFF)
+mark_as_superbuild(${PROJECT_NAME}_ENABLE_CUDA_BACKEND)
 if (${PROJECT_NAME}_ENABLE_CUDA_BACKEND)
   include(CheckLanguage)
   check_language(CUDA)
@@ -98,26 +106,75 @@ if (${PROJECT_NAME}_ENABLE_CUDA_BACKEND)
   endif()
 endif ()
 
+# Audio
+if(WIN32)
+  if(DEFINED ${PROJECT_NAME}_ENABLE_AUDIO)
+    set(_enable_audio ${${PROJECT_NAME}_ENABLE_AUDIO})
+    set(_reason "${PROJECT_NAME}_ENABLE_AUDIO is SET")
+  else()
+    set(_enable_audio ON)
+    set(_reason "default initialization")
+  endif()
+else()
+  set(_enable_audio OFF)
+  set(_reason "not supported")
+endif()
+set(_msg "${PROJECT_NAME} Audio support")
+message(STATUS "${_msg} - ${_enable_audio} (${_reason})")
+set(${PROJECT_NAME}_AUDIO_ENABLED ${_enable_audio})
+
 # General Options
 option(${PROJECT_NAME}_BUILD_EXAMPLES "Build iMSTK examples" ON)
+mark_as_superbuild(${PROJECT_NAME}_BUILD_EXAMPLES:BOOL)
+
 option(${PROJECT_NAME}_BUILD_TESTING "Build iMSTK tests" ON)
+mark_as_superbuild(${PROJECT_NAME}_BUILD_TESTING:BOOL)
+
 set(BUILD_TESTING OFF)
 if (${PROJECT_NAME}_BUILD_TESTING)
   set(BUILD_TESTING ON)
 endif ()
 if (UNIX)
   option(${PROJECT_NAME}_USE_MODEL_REDUCTION "Build with model reduction, requires a VegaFEM built with Intel MKL and arpack" OFF)
+  mark_as_superbuild(${PROJECT_NAME}_USE_MODEL_REDUCTION:BOOL)
+
   option(${PROJECT_NAME}_COLOR_OUTPUT "For coloring output in gcc" OFF)
+  mark_as_superbuild(${PROJECT_NAME}_COLOR_OUTPUT:BOOL)
+
   option(${PROJECT_NAME}_COVERAGE "Build for calculating coverage" OFF)
+  mark_as_superbuild(${PROJECT_NAME}_COVERAGE:BOOL)
+
   option(${PROJECT_NAME}_USE_VTK_OSMESA "Build with VTK OSMesa rendering" OFF)
+  mark_as_superbuild(${PROJECT_NAME}_USE_VTK_OSMESA:BOOL)
 
   if (${PROJECT_NAME}_COVERAGE AND NOT ${CMAKE_BUILD_TYPE} MATCHES [Dd][Ee][Bb][Uu][Gg])
     message(WARNING "Coverage requires a debug build forcing debug")
     set(CMAKE_BUILD_TYPE "DEBUG")
   endif()  
 endif()
+
 option(${PROJECT_NAME}_USE_VRPN "Build with VRPN support" OFF)
+mark_as_superbuild(${PROJECT_NAME}_USE_VRPN:BOOL)
+
 option(${PROJECT_NAME}_USE_PHYSX "Build with Physx support" OFF)
+mark_as_superbuild(iMSTK_USE_PHYSX:BOOL)
+if(iMSTK_USE_PHYSX)
+  set(PHYSX_CONFIGURATION "RELEASE" CACHE STRING "PhysX release library type")
+  mark_as_superbuild(PHYSX_CONFIGURATION:STRING)
+
+  # Set the possible values for cmake-gui
+  set_property(CACHE PHYSX_CONFIGURATION PROPERTY STRINGS
+    "RELEASE"
+    "CHECKED"
+    "PROFILE"
+    )
+endif()
+
+option(iMSTK_USE_OpenHaptics "Use OpenHaptic Support." OFF)
+mark_as_superbuild(iMSTK_USE_OpenHaptics:BOOL)
+if(NOT WIN32 AND iMSTK_USE_OpenHaptics)
+  message(FATAL_ERROR "Setting iMSTK_USE_OpenHaptics to ON is only supported on Windows")
+endif()
 
 #-----------------------------------------------------------------------------
 # CTest/Dashboards
@@ -130,16 +187,10 @@ endif ()
 #-----------------------------------------------------------------------------
 # SUPERBUILD
 #-----------------------------------------------------------------------------
-include(CMakePackageConfigHelpers)
 option(${PROJECT_NAME}_SUPERBUILD "Build ${PROJECT_NAME} and the projects it depends on." ON)
 
 if(${PROJECT_NAME}_SUPERBUILD)
 
-  # Select the release version of PhysX to use
-  set(${PROJECT_NAME}_PHYSX_CONFIGURATION "RELEASE" CACHE STRING "Select PhysX Library Type for Release and RelWithDebInfo builds")
-  set(PHYSX_RELEASE_TYPES "RELEASE;CHECKED;PROFILE" CACHE INTERNAL "List of available PhysX release library types")
-  set_property(CACHE ${PROJECT_NAME}_PHYSX_CONFIGURATION PROPERTY STRINGS ${PHYSX_RELEASE_TYPES})
-
   #-----------------------------------------------------------------------------
   # Define External dependencies
   #-----------------------------------------------------------------------------
@@ -158,18 +209,16 @@ if(${PROJECT_NAME}_SUPERBUILD)
       message(WARN "Uncrustify requires a python interpreter, please install python and rerun configure")
     endif()
   endif()
-
-  option(${PROJECT_NAME}_USE_OpenHaptics "Use OpenHaptic Support." OFF)
   
   imstk_define_dependency(Assimp)
   imstk_define_dependency(Eigen3)
   imstk_define_dependency(g3log)
   imstk_define_dependency(LibNiFalcon)
-  imstk_define_dependency(openvr)
+  imstk_define_dependency(OpenVR)
   if (${PROJECT_NAME}_USE_PHYSX)
     imstk_define_dependency(PhysX)
   endif()
-  imstk_define_dependency(tbb)
+  imstk_define_dependency(TBB)
   imstk_define_dependency(VegaFEM)
   imstk_define_dependency(VTK)
   if(${PROJECT_NAME}_USE_OpenHaptics)
@@ -180,14 +229,11 @@ if(${PROJECT_NAME}_SUPERBUILD)
   endif()
 
   if(WIN32)
-    imstk_define_dependency(PThreads)
     imstk_define_dependency(Libusb) #for VRPN
     imstk_define_dependency(FTD2XX) #for LibNiFalcon
-    imstk_define_dependency(SFML)
-    set(${PROJECT_NAME}_AUDIO_ENABLED "Windows OS detected: Building iMSTK with AUDIO support." ON)
-  else()
-    message("Warning: Building iMSTK WITHOUT audio support!")
-    set(${PROJECT_NAME}_AUDIO_ENABLED OFF)
+    if(${PROJECT_NAME}_AUDIO_ENABLED)
+      imstk_define_dependency(SFML)
+    endif()
   endif()
 
   if(${PROJECT_NAME}_BUILD_TESTING)
@@ -249,19 +295,18 @@ find_package( LibNiFalcon REQUIRED)
 # Libusb
 find_package( Libusb REQUIRED)
 # OpenVR
-find_package( openvr REQUIRED )
+find_package( OpenVR REQUIRED )
 
-# Select the release version of PhysX to use
-if (${PROJECT_NAME}_USE_PHYSX)
+# PhysX
+if (iMSTK_USE_PHYSX)
   add_compile_definitions(IMSTK_USE_PHYSX)
-  set(PHYSX_CONFIGURATION "${PHYSX_CONFIGURATION}" CACHE STRING "Select PhysX Library Type for Release and RelWithDebInfo builds")
-  set(PHYSX_RELEASE_TYPES "RELEASE;CHECKED;PROFILE" CACHE INTERNAL "List of available PhysX release library types")
-  set_property(CACHE PHYSX_CONFIGURATION PROPERTY STRINGS ${PHYSX_RELEASE_TYPES})
+  # Variable PHYSX_CONFIGURATION used in FindPhysX.cmake is set above where
+  # iMSTK_USE_PHYSX CMake option is defined.
   find_package(PhysX REQUIRED)
 endif()
 
 # SFML
-if(APPLE OR LINUX)
+if(NOT iMSTK_AUDIO_ENABLED)
   remove_definitions( -DiMSTK_AUDIO_ENABLED )
 else()
   find_package( SFML REQUIRED )
@@ -269,9 +314,7 @@ else()
 endif()
 
 # TBB
-find_package(tbb REQUIRED)
-# Define  __TBB_NO_IMPLICIT_LINKAGE so that MSVC will not always look for tbb_debug in debug mode
-add_definitions(-D__TBB_NO_IMPLICIT_LINKAGE)
+find_package(TBB REQUIRED)
 
 # VegaFEM
 find_package( VegaFEM REQUIRED CONFIG )
@@ -290,10 +333,14 @@ else()
 endif()
 
 # VTK
-find_package(VTK CONFIG)
+find_package(VTK REQUIRED CONFIG)
 # modules are linked via `VTK::CommonCore`
 # vtk_module_autoinit is needed
-list(APPEND VTK_DEPENDENCIES
+
+find_package(vtkRenderingOpenVR QUIET)
+find_package(vtkRenderingExternal QUIET)
+
+list(APPEND iMSTK_VTK_DEPENDENCIES
   ChartsCore
   CommonCore
   CommonDataModel
@@ -321,7 +368,7 @@ list(APPEND VTK_DEPENDENCIES
   RenderingVolume
   RenderingVolumeOpenGL2
   ViewsContext2D)
-find_package(VTK COMPONENTS ${VTK_DEPENDENCIES})
+find_package(VTK COMPONENTS ${iMSTK_VTK_DEPENDENCIES} REQUIRED)
 if(${PROJECT_NAME}_USE_VTK_OSMESA)
   add_definitions(-DiMSTK_USE_VTK_OSMESA)
 endif()
@@ -360,7 +407,7 @@ endif()
 # Testing
 #----------------------------------------------------------------------
 if(${PROJECT_NAME}_BUILD_TESTING)
-  find_package( GTest REQUIRED NO_DEFAULT_PATH)
+  find_package( GTest CONFIG REQUIRED )
 endif()
 
 #-----------------------------------------------------------------------------
@@ -417,6 +464,13 @@ if(${PROJECT_NAME}_BUILD_EXAMPLES)
     add_subdirectory(Examples)
 endif()
 
+#--------------------------------------------------------------------------
+# Testing
+#--------------------------------------------------------------------------
+if (${PROJECT_NAME}_BUILD_TESTING)
+  add_subdirectory(Testing)
+endif()
+
 #--------------------------------------------------------------------------
 # Add setup script for *nix systems
 #--------------------------------------------------------------------------
@@ -479,6 +533,55 @@ export(
   NAMESPACE ${PROJECT_NAMESPACE}
   )
 # Configure '${PROJECT_NAME}Config.cmake' for a build tree
+set(CONFIG_CODE "####### Expanded from \@CONFIG_CODE\@ #######\n")
+
+set(CONFIG_CODE "${CONFIG_CODE}set(Assimp_ROOT_DIR \"${Assimp_ROOT_DIR}\")\n")
+set(CONFIG_CODE "${CONFIG_CODE}set(Assimp_LIB_DIR \"${Assimp_LIB_DIR}\")\n")
+
+set(CONFIG_CODE "${CONFIG_CODE}set(Eigen3_DIR \"${Eigen3_DIR}\")\n")
+
+set(CONFIG_CODE "${CONFIG_CODE}set(g3log_ROOT_DIR \"${g3log_ROOT_DIR}\")\n")
+set(CONFIG_CODE "${CONFIG_CODE}set(g3log_LIB_DIR \"${g3log_LIB_DIR}\")\n")
+
+set(CONFIG_CODE "${CONFIG_CODE}set(GTest_DIR \"${GTest_DIR}\")\n")
+
+if(WIN32)
+  set(CONFIG_CODE "${CONFIG_CODE}# Required by FindFTD2XX CMake module used in and provided by the iMSTK project\n")
+  set(CONFIG_CODE "${CONFIG_CODE}set(FTD2XX_ROOT_DIR \"${FTD2XX_ROOT_DIR}\")\n")
+  set(CONFIG_CODE "${CONFIG_CODE}set(FTD2XX_LIB_DIR \"${FTD2XX_LIB_DIR}\")\n")
+  set(CONFIG_CODE "${CONFIG_CODE}# Required by Findlibftd2xx CMake module provided and used by the LibNiFalcon project\n")
+  set(CONFIG_CODE "${CONFIG_CODE}set(LIBFTD2XX_INCLUDE_DIR \"${LIBFTD2XX_INCLUDE_DIR}\")\n")
+  set(CONFIG_CODE "${CONFIG_CODE}set(LIBFTD2XX_LIBRARY \"${LIBFTD2XX_LIBRARY}\")\n")
+endif()
+
+set(CONFIG_CODE "${CONFIG_CODE}set(LibNiFalcon_ROOT_DIR \"${LibNiFalcon_ROOT_DIR}\")\n")
+set(CONFIG_CODE "${CONFIG_CODE}set(LibNiFalcon_LIB_DIR \"${LibNiFalcon_LIB_DIR}\")\n")
+
+if(WIN32)
+  set(CONFIG_CODE "${CONFIG_CODE}set(Libusb_ROOT_DIR \"${Libusb_ROOT_DIR}\")\n")
+  set(CONFIG_CODE "${CONFIG_CODE}set(Libusb_LIB_DIR \"${Libusb_LIB_DIR}\")\n")
+else()
+  set(CONFIG_CODE "${CONFIG_CODE}set(Libusb_INCLUDE_DIR \"${Libusb_INCLUDE_DIR}\")\n")
+  set(CONFIG_CODE "${CONFIG_CODE}set(Libusb_LIBRARY_libusb-1.0-RELEASE \"${Libusb_LIBRARY_libusb-1.0-RELEASE}\")\n")
+  set(CONFIG_CODE "${CONFIG_CODE}set(Libusb_LIBRARY_libusb-1.0-DEBUG \"${Libusb_LIBRARY_libusb-1.0-DEBUG}\")\n")
+endif()
+
+set(CONFIG_CODE "${CONFIG_CODE}# Add variables to CACHE to workaround issue related to use of\n")
+set(CONFIG_CODE "${CONFIG_CODE}# mark_as_advanced command in FindOpenVR and described in CMP0102\n")
+set(CONFIG_CODE "${CONFIG_CODE}# See https://cmake.org/cmake/help/latest/policy/CMP0102.html\n")
+set(CONFIG_CODE "${CONFIG_CODE}set(OpenVR_INCLUDE_DIR \"${OpenVR_INCLUDE_DIR}\" CACHE PATH \"\")\n")
+set(CONFIG_CODE "${CONFIG_CODE}set(OpenVR_LIBRARY \"${OpenVR_LIBRARY}\" CACHE FILEPATH \"\")\n")
+set(CONFIG_CODE "${CONFIG_CODE}set(OpenVR_ROOT_DIR \"${OpenVR_ROOT_DIR}\")\n")
+set(CONFIG_CODE "${CONFIG_CODE}set(OpenVR_LIB_DIR \"${OpenVR_LIB_DIR}\")\n")
+
+set(CONFIG_CODE "${CONFIG_CODE}set(TBB_DIR \"${TBB_DIR}\")\n")
+
+set(CONFIG_CODE "${CONFIG_CODE}set(VegaFEM_DIR \"${VegaFEM_DIR}\")\n")
+set(CONFIG_CODE "${CONFIG_CODE}set(VTK_DIR \"${VTK_DIR}\")\n")
+set(CONFIG_CODE "${CONFIG_CODE}set(vtkRenderingOpenVR_DIR \"${vtkRenderingOpenVR_DIR}\")\n")
+set(CONFIG_CODE "${CONFIG_CODE}set(vtkRenderingExternal_DIR \"${vtkRenderingExternal_DIR}\")\n")
+
+set(CONFIG_CODE "${CONFIG_CODE}##################################################")
 set(build_config ${CMAKE_BINARY_DIR}/${PROJECT_NAME}Config.cmake)
 configure_package_config_file(
   CMake/${PROJECT_NAME}Config.cmake.in
@@ -494,7 +597,23 @@ install(
   NAMESPACE ${PROJECT_NAMESPACE}
   DESTINATION ${${PROJECT_NAME}_INSTALL_CONFIG_DIR}
   )
-  
+# Configure '${PROJECT_NAME}Config.cmake' for an install tree
+set(CONFIG_CODE "####### Expanded from \@CONFIG_CODE\@ #######\n")
+# Note: iMSTK specific variables likes <proj>_ROOT_DIR and <proj>_LIB_DIR
+# are not set because the location of the corresponding project is automatically
+# inferred by Find<proj> CMake module provided by iSMTK.
+set(CONFIG_CODE "${CONFIG_CODE}set(Eigen3_DIR \"${Eigen3_DIR}\")\n")
+set(CONFIG_CODE "${CONFIG_CODE}set(GTest_DIR \"${GTest_DIR}\")\n")
+set(CONFIG_CODE "${CONFIG_CODE}set(TBB_DIR \"${TBB_DIR}\")\n")
+set(CONFIG_CODE "${CONFIG_CODE}set(VegaFEM_DIR \"${VegaFEM_DIR}\")\n")
+set(CONFIG_CODE "${CONFIG_CODE}set(VTK_DIR \"${VTK_DIR}\")\n")
+set(CONFIG_CODE "${CONFIG_CODE}# Add variables to CACHE to workaround issue related to use of\n")
+set(CONFIG_CODE "${CONFIG_CODE}# mark_as_advanced command in FindOpenVR and described in CMP0102\n")
+set(CONFIG_CODE "${CONFIG_CODE}# See https://cmake.org/cmake/help/latest/policy/CMP0102.html\n")
+set(CONFIG_CODE "${CONFIG_CODE}set(OpenVR_INCLUDE_DIR \"${OpenVR_INCLUDE_DIR}\" CACHE PATH \"\")\n")
+set(CONFIG_CODE "${CONFIG_CODE}set(OpenVR_LIBRARY \"${OpenVR_LIBRARY}\" CACHE FILEPATH \"\")\n")
+set(CONFIG_CODE "${CONFIG_CODE}##################################################")
+
 set(install_config ${PROJECT_BINARY_DIR}/CMakeFiles/${PROJECT_NAME}Config.cmake)
 configure_package_config_file(
   CMake/${PROJECT_NAME}Config.cmake.in 
diff --git a/Docs/Maintainance.md b/Docs/Maintainance.md
index 1173e387b4de4df678c4e1943819a76e796cf687..9ce06000372663cd8733c8c83c314da65bcf2a7f 100644
--- a/Docs/Maintainance.md
+++ b/Docs/Maintainance.md
@@ -45,20 +45,17 @@ This is executed in the innerbuild of `iMSTK`. It will enable the innerbuild to
 Add a Setting `${PROJECT_NAME}_USE_NewLib` as
 	
     option(${PROJECT_NAME}_USE_NewLib "Build with NewLib support" OFF)
+    mark_as_superbuild(${PROJECT_NAME}_USE_NewLib)
 	
 The state of the option (`ON`/`OFF`) should reflect whether the new library should be built by default or not. If a dependency is a required one, one may omit this. If the dependency is optional, one can conditionally execute other steps in the CMake build process by surrounding the statements with `if(${PROJECT_NAME}_USE_NewLib)` or `if(iMSTK_USE_NewLIb)`.
 
+Variables that need to be passed from the superbuild to the innerbuild need to be "marked" as such using `mark_as_superbuild`.
+
 **Step 4:** Edit CMake\External\CMakeLists.txt
 
 ---
 
-This CMake script adds the project that makes up the innerbuild to the superbuild, any variables that need to be passed from the superbuild to the innerbuild need to be set here. This means you will probably want to add 
-
-    -D${PROJECT_NAME}_USE_NewLib:BOOL=${${PROJECT_NAME}_USE_NewLib} 
-
-to the section in `ExternalProject_Add`, so that the appropriate option is visible inside the innerbuild.
-
-Additionally to enable CMake to find the library correctly _if_ the library already provides a `Config.cmake` or a `Find` pass the path to the library into the innerbuild, so use 
+To enable CMake to find the library correctly _if_ the library already provides a `Config.cmake` or a `Find` pass the path to the library into the innerbuild, so use 
 
     -DNewLib_DIR:PATH=${NewLib_DIR}  
 
@@ -67,9 +64,30 @@ Additionally to enable CMake to find the library correctly _if_ the library alre
 You will need to create this file which describes what files to download from where and how to build them to support your new library in the superbuild. In general this will mean customizing `imstk_add_external_project`.
 
     include(imstkAddExternalProject)
-	imstk_add_external_project(NewLib
-	  ....
-	)
+
+    # Download options
+    if(NOT DEFINED iMSTK_NewLib_GIT_SHA)
+      set(iMSTK_NewLib_GIT_SHA "...")
+    endif()
+    if(NOT DEFINED iMSTK_NewLib_GIT_REPOSITORY)
+      set(EXTERNAL_PROJECT_DOWNLOAD_OPTIONS
+        URL https://gitlab.kitware.com/iMSTK/newlib/-/archive/${iMSTK_NewLib_GIT_SHA}/newlib-${iMSTK_NewLib_GIT_SHA}.zip
+        URL_HASH MD5=...
+        )
+    else()
+      set(EXTERNAL_PROJECT_DOWNLOAD_OPTIONS
+        GIT_REPOSITORY ${iMSTK_NewLib_GIT_REPOSITORY}
+        GIT_TAG ${iMSTK_NewLib_GIT_SHA}
+        )
+    endif()
+
+    imstk_add_external_project(NewLib
+      ${EXTERNAL_PROJECT_DOWNLOAD_OPTIONS}
+      CMAKE_CACHE_ARGS
+        ...
+      DEPENDENCIES ${NewLib_DEPENDENCIES}
+      ...
+    )
 
 and customizing the build options for the new library by passing them via the `CMAKE_CACHE_ARGS` section. e.g.
 
diff --git a/Examples/BoneShaving/CMakeLists.txt b/Examples/BoneShaving/CMakeLists.txt
index f5951b4c7d0a6f4ac71c05f4500202a9c295a264..8232d23a11fde0eba1e557e95ffcdc203055d486 100644
--- a/Examples/BoneShaving/CMakeLists.txt
+++ b/Examples/BoneShaving/CMakeLists.txt
@@ -40,7 +40,8 @@ if(iMSTK_USE_OpenHaptics)
   else()
     target_link_libraries(${PROJECT_NAME}
     SimulationManager
-    SFML)
+    SFML::SFML
+    )
   endif()
   
 endif()
diff --git a/Source/Common/CMakeLists.txt b/Source/Common/CMakeLists.txt
index c79c608b43470756b3635d4df1d0f732a208abe0..4c2ca6755edd7f9c053d3ca5c7c37828f338699b 100644
--- a/Source/Common/CMakeLists.txt
+++ b/Source/Common/CMakeLists.txt
@@ -5,8 +5,8 @@ include(imstkAddLibrary)
 imstk_add_library( Common
   DEPENDS
     Eigen3::Eigen
-    g3log
-    tbb
+    g3log::g3log
+    TBB::tbb
   )
 
 #-----------------------------------------------------------------------------
diff --git a/Source/Common/imstkMath.h b/Source/Common/imstkMath.h
index c8c7346aff2c64c3d0e2d756684f6a7b6f223537..467954eed2da104c417373c58b984c4b8ae26ec6 100644
--- a/Source/Common/imstkMath.h
+++ b/Source/Common/imstkMath.h
@@ -31,6 +31,18 @@
 #include <Eigen/StdVector>
 #include <Eigen/Sparse>
 
+#if !defined(_MSC_VER) && __cplusplus <= 201103L
+namespace std
+{
+template<typename T, typename ... Args>
+std::unique_ptr<T>
+make_unique(Args&& ... args)
+{
+    return std::unique_ptr<T>(new T(std::forward<Args>(args) ...));
+}
+}
+#endif
+
 namespace imstk
 {
 // 2D vector
diff --git a/Source/Devices/CMakeLists.txt b/Source/Devices/CMakeLists.txt
index 3f054bfd2f875425319a87ecaad761756f292f0c..11f1586d8be3ba5eb0f71ccb83852e72103f8b5c 100644
--- a/Source/Devices/CMakeLists.txt
+++ b/Source/Devices/CMakeLists.txt
@@ -5,10 +5,10 @@
 list(APPEND Dependencies Common)
 
 if(iMSTK_USE_OpenHaptics)
-  list(APPEND Dependencies OpenHapticsSDK)
+  list(APPEND Dependencies OpenHapticsSDK::OpenHapticsSDK)
 endif()
 if(iMSTK_USE_VRPN)
-  list(APPEND Dependencies VRPN)
+  list(APPEND Dependencies VRPN::VRPN)
 endif()
 
 list(APPEND ExclusionFiles "")
diff --git a/Source/DynamicalModels/CMakeLists.txt b/Source/DynamicalModels/CMakeLists.txt
index b2cf408807c9280b3f2e171612093172064fea6e..34ceb94d366253aaa721b1f6599c8c28dbe7655a 100644
--- a/Source/DynamicalModels/CMakeLists.txt
+++ b/Source/DynamicalModels/CMakeLists.txt
@@ -32,7 +32,7 @@ else()
 endif()
 
 if (iMSTK_USE_PHYSX)
-  list(APPEND Dependencies PhysX)
+  list(APPEND Dependencies PhysX::PhysX)
 else()
   list(APPEND ExclusionFiles
     ObjectModels/imstkRigidBodyModel.h
diff --git a/Source/MeshIO/CMakeLists.txt b/Source/MeshIO/CMakeLists.txt
index 7efb068faacc158d7af23aab89196ce4c5cf473a..01ccfc2b468453b6c48f29527c69d0473ca712c1 100644
--- a/Source/MeshIO/CMakeLists.txt
+++ b/Source/MeshIO/CMakeLists.txt
@@ -6,7 +6,7 @@ imstk_add_library( MeshIO
   DEPENDS
     Common
 	Geometry    
-    Assimp    
+    Assimp::Assimp
     VegaFEM::volumetricMesh
     ${VTK_LIBRARIES}
   )
diff --git a/Source/Rendering/CMakeLists.txt b/Source/Rendering/CMakeLists.txt
index 16c20250c9d2d8f67371a8a9d19de68db6c4238d..b5c54fe0c0059097731ac5ea39da943cdb3ee339 100644
--- a/Source/Rendering/CMakeLists.txt
+++ b/Source/Rendering/CMakeLists.txt
@@ -49,7 +49,7 @@ set(RENDERING_SUBDIR
   VTKRenderer/RenderDelegate)
 set(RENDERING_DEPENDENCIES  
   Materials
-  openvr)
+  OpenVR::OpenVR)
 
 include(imstkAddLibrary)
 imstk_add_library( Rendering
diff --git a/Source/Wrappers/CMakeLists.txt b/Source/Wrappers/CMakeLists.txt
index 8b227a7c533b54a47a2b1126da3c15ed1ef7ba46..eeb250a96d65d90199709c48d86217fe9384a779 100644
--- a/Source/Wrappers/CMakeLists.txt
+++ b/Source/Wrappers/CMakeLists.txt
@@ -85,7 +85,7 @@ install( TARGETS iMSTKCWrapper EXPORT iMSTKCWrapperTargets
     LIBRARY DESTINATION lib COMPONENT RuntimeLibraries
     ARCHIVE DESTINATION lib COMPONENT Development)
 
-if (LINUX)
+if (UNIX AND NOT APPLE)
 	# Why use CODE and then execute COMMAND?
     install(CODE "execute_process(COMMAND ${CMAKE_COMMAND} -E create_symlink iMSTKCWrapper.so ${CMAKE_INSTALL_PREFIX}/lib/libiMSTKCWrapper.so)")
 endif()
diff --git a/Testing/CMakeLists.txt b/Testing/CMakeLists.txt
new file mode 100644
index 0000000000000000000000000000000000000000..7173b62f776b0b031b6738b5df93c63aeb3a55f2
--- /dev/null
+++ b/Testing/CMakeLists.txt
@@ -0,0 +1,28 @@
+include(FetchContent)
+
+
+# Download project template
+set(proj "iMSTKExternalProjectTemplate")
+set(templates_src_dir "${CMAKE_CURRENT_BINARY_DIR}/${proj}")
+FetchContent_Populate(${proj}
+  SOURCE_DIR     "${templates_src_dir}"
+  GIT_REPOSITORY https://gitlab.kitware.com/iMSTK/imstkexternalprojecttemplate
+  GIT_TAG        e71107a4ad9fc33a0460cfef7cae58155af57262
+  QUIET
+  )
+
+imstk_add_project_test(iMSTKBuildSystemTest.iMSTKProjectAgainstBuildTree
+  SOURCE_DIR ${templates_src_dir}/iMSTKProject
+  BINARY_DIR ${CMAKE_CURRENT_BINARY_DIR}/iMSTKProjectAgainstBuildTree
+  BUILD_OPTIONS
+    -DiMSTK_DIR:PATH=${iMSTK_BINARY_DIR}
+  WORKING_DIR ${CMAKE_INSTALL_PREFIX}/bin
+  )
+
+imstk_add_project_test(iMSTKBuildSystemTest.iMSTKProjectAgainstInstallTree
+  SOURCE_DIR ${templates_src_dir}/iMSTKProject
+  BINARY_DIR ${CMAKE_CURRENT_BINARY_DIR}/iMSTKProjectAgainstInstallTree
+  BUILD_OPTIONS
+    -DiMSTK_DIR:PATH=${CMAKE_INSTALL_PREFIX}/lib/cmake/iMSTK-${iMSTK_VERSION_MAJOR}.${iMSTK_VERSION_MINOR}
+  WORKING_DIR ${CMAKE_INSTALL_PREFIX}/bin
+  )