diff --git a/.gitignore b/.gitignore
index 5764bfe22c69e83c259b22d44153e3210877869c..c7fc052e80f239765f7ae852f2948b32c8c9307e 100644
--- a/.gitignore
+++ b/.gitignore
@@ -149,3 +149,8 @@ GSYMS
 /tools/cub-1.8.0/
 /tools/cub
 /tools/python/
+
+# These CMakeLists.txt files are all genareted on the fly at the moment.
+# They are added here to avoid accidently checkin.
+/src/**/CMakeLists.txt
+/build*
diff --git a/CMakeLists.txt b/CMakeLists.txt
new file mode 100644
index 0000000000000000000000000000000000000000..748d88a351fff46f3360325b0a875c7fd00e4972
--- /dev/null
+++ b/CMakeLists.txt
@@ -0,0 +1,195 @@
+cmake_minimum_required(VERSION 3.5)
+project(kaldi)
+
+set(CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/cmake;${CMAKE_MODULE_PATH}")
+include(GNUInstallDirs)
+include(Utils)
+include(third_party/get_third_party)
+
+message(STATUS "Running gen_cmake_skeleton.py")
+execute_process(COMMAND python
+    "${CMAKE_CURRENT_SOURCE_DIR}/cmake/gen_cmake_skeleton.py"
+    "${CMAKE_CURRENT_SOURCE_DIR}/src"
+    "--quiet"
+)
+
+set(CMAKE_CXX_STANDARD 14)
+set(CMAKE_CXX_EXTENSIONS OFF)
+set(CMAKE_INSTALL_MESSAGE LAZY) # hide "-- Up-to-date: ..."
+if(BUILD_SHARED_LIBS)
+    set(CMAKE_POSITION_INDEPENDENT_CODE ON)
+    if(WIN32)
+        set(CMAKE_WINDOWS_EXPORT_ALL_SYMBOLS ON)
+        message(FATAL_ERROR "DLL is not supported currently")
+    elseif(APPLE)
+        set(CMAKE_INSTALL_RPATH "@loader_path")
+    else()
+        set(CMAKE_INSTALL_RPATH "$ORIGIN;$ORIGIN/../lib")
+    endif()
+endif()
+
+set(MATHLIB "OpenBLAS" CACHE STRING "OpenBLAS|MKL|Accelerate")
+option(KALDI_BUILD_EXE "If disabled, will make add_kaldi_executable a no-op" ON)
+option(KALDI_BUILD_TEST "If disabled, will make add_kaldi_test_executable a no-op" ON)
+option(KALDI_USE_PATCH_NUMBER "Use MAJOR.MINOR.PATCH format, otherwise MAJOR.MINOR" OFF)
+
+link_libraries(${CMAKE_DL_LIBS})
+
+find_package(Threads)
+link_libraries(Threads::Threads)
+
+if(MATHLIB STREQUAL "OpenBLAS")
+    set(BLA_VENDOR "OpenBLAS")
+    find_package(LAPACK REQUIRED)
+    add_definitions(-DHAVE_CLAPACK=1)
+    include_directories(${CMAKE_CURRENT_SOURCE_DIR}/tools/CLAPACK)
+    link_libraries(${BLAS_LIBRARIES} ${LAPACK_LIBRARIES})
+elseif(MATHLIB STREQUAL "MKL")
+    set(BLA_VENDOR "Intel10_64lp")
+    # find_package(BLAS REQUIRED)
+    normalize_env_path(ENV{MKLROOT})
+    find_package(LAPACK REQUIRED)
+    add_definitions(-DHAVE_MKL=1)
+    include_directories($ENV{MKLROOT}/include) # TODO: maybe not use env, idk, find_package doesnt handle includes...
+    link_libraries(${BLAS_LIBRARIES} ${LAPACK_LIBRARIES})
+elseif(MATHLIB STREQUAL "Accelerate")
+    set(BLA_VENDOR "Apple")
+    find_package(BLAS REQUIRED)
+    find_package(LAPACK REQUIRED)
+    add_definitions(-DHAVE_CLAPACK=1)
+    link_libraries(${BLAS_LIBRARIES} ${LAPACK_LIBRARIES})
+else()
+    message(FATAL_ERROR "${MATHLIB} is not tested and supported, you are on your own now.")
+endif()
+
+if(MSVC)
+    # Added in source, but we actually should do it in build script, whatever...
+    # add_definitions(-DWIN32_LEAN_AND_MEAN=1)
+
+    add_compile_options(/permissive- /FS /wd4819 /EHsc /bigobj)
+
+    # some warnings related with fst
+    add_compile_options(/wd4018 /wd4244 /wd4267 /wd4291 /wd4305)
+
+    set(CUDA_USE_STATIC_CUDA_RUNTIME OFF CACHE INTERNAL "")
+    if(NOT DEFINED ENV{CUDAHOSTCXX})
+        set(ENV{CUDAHOSTCXX} ${CMAKE_CXX_COMPILER})
+    endif()
+    if(NOT DEFINED CUDA_HOST_COMPILER)
+        set(CUDA_HOST_COMPILER ${CMAKE_CXX_COMPILER})
+    endif()
+endif()
+
+find_package(CUDA)
+if(CUDA_FOUND)
+    set(CUB_ROOT_DIR "${PROJECT_SOURCE_DIR}/tools/cub")
+
+    set(CUDA_PROPAGATE_HOST_FLAGS ON)
+    set(KALDI_CUDA_NVCC_FLAGS "--default-stream=per-thread;-std=c++${CMAKE_CXX_STANDARD}")
+    if(MSVC)
+        list(APPEND KALDI_CUDA_NVCC_FLAGS "-Xcompiler /permissive-,/FS,/wd4819,/EHsc,/bigobj")
+        list(APPEND KALDI_CUDA_NVCC_FLAGS "-Xcompiler /wd4018,/wd4244,/wd4267,/wd4291,/wd4305")
+        if(BUILD_SHARED_LIBS)
+            list(APPEND CUDA_NVCC_FLAGS_RELEASE -Xcompiler /MD)
+            list(APPEND CUDA_NVCC_FLAGS_DEBUG -Xcompiler /MDd)
+        endif()
+    else()
+    #     list(APPEND KALDI_CUDA_NVCC_FLAGS "-Xcompiler -std=c++${CMAKE_CXX_STANDARD}")
+        list(APPEND KALDI_CUDA_NVCC_FLAGS "-Xcompiler -fPIC")
+    endif()
+    set(CUDA_NVCC_FLAGS ${KALDI_CUDA_NVCC_FLAGS} ${CUDA_NVCC_FLAGS})
+
+    add_definitions(-DHAVE_CUDA=1)
+    add_definitions(-DCUDA_API_PER_THREAD_DEFAULT_STREAM=1)
+    include_directories(${CUDA_INCLUDE_DIRS})
+    link_libraries(
+        ${CUDA_LIBRARIES}
+        ${CUDA_CUDA_LIBRARY}
+        ${CUDA_CUBLAS_LIBRARIES}
+        ${CUDA_CUFFT_LIBRARIES}
+        ${CUDA_curand_LIBRARY}
+        ${CUDA_cusolver_LIBRARY}
+        ${CUDA_cusparse_LIBRARY})
+
+    find_package(NvToolExt REQUIRED)
+    include_directories(${NvToolExt_INCLUDE_DIR})
+    link_libraries(${NvToolExt_LIBRARIES})
+
+    find_package(CUB REQUIRED)
+    include_directories(${CUB_INCLUDE_DIR})
+endif()
+
+add_definitions(-DKALDI_NO_PORTAUDIO=1)
+
+include(VersionHelper)
+get_version() # this will set KALDI_VERSION and KALDI_PATCH_NUMBER
+if(${KALDI_USE_PATCH_NUMBER})
+    set(KALDI_VERSION "${KALDI_VERSION}.${KALDI_PATCH_NUMBER}")
+endif()
+
+get_third_party(openfst)
+set(OPENFST_ROOT_DIR ${CMAKE_CURRENT_BINARY_DIR}/openfst)
+include(third_party/openfst_lib_target)
+link_libraries(fst)
+
+# add all native libraries
+add_subdirectory(src/base) # NOTE, we need to patch the target with version from outside
+set_property(TARGET kaldi-base PROPERTY COMPILE_DEFINITIONS "KALDI_VERSION=\"${KALDI_VERSION}\"")
+add_subdirectory(src/matrix)
+add_subdirectory(src/cudamatrix)
+add_subdirectory(src/util)
+add_subdirectory(src/feat)
+add_subdirectory(src/tree)
+add_subdirectory(src/gmm)
+add_subdirectory(src/transform)
+add_subdirectory(src/sgmm2)
+add_subdirectory(src/fstext)
+add_subdirectory(src/hmm)
+add_subdirectory(src/lm)
+add_subdirectory(src/decoder)
+add_subdirectory(src/lat)
+add_subdirectory(src/nnet)
+add_subdirectory(src/nnet2)
+add_subdirectory(src/nnet3)
+add_subdirectory(src/rnnlm)
+add_subdirectory(src/chain)
+add_subdirectory(src/ivector)
+add_subdirectory(src/online)
+add_subdirectory(src/online2)
+add_subdirectory(src/kws)
+
+add_subdirectory(src/itf)
+
+# add all cuda libraries
+if(CUDA_FOUND)
+    add_subdirectory(src/cudafeat)
+    add_subdirectory(src/cudadecoder)
+endif()
+
+# add all native executables
+add_subdirectory(src/gmmbin)
+add_subdirectory(src/featbin)
+add_subdirectory(src/onlinebin)
+
+# add all cuda executables
+if(CUDA_FOUND)
+    add_subdirectory(src/cudafeatbin)
+    add_subdirectory(src/cudadecoderbin)
+endif()
+
+include(CMakePackageConfigHelpers)
+# maybe we should put this into subfolder?
+configure_package_config_file(
+    ${CMAKE_CURRENT_SOURCE_DIR}/cmake/kaldi-config.cmake.in
+    ${CMAKE_BINARY_DIR}/cmake/kaldi-config.cmake
+    INSTALL_DESTINATION lib/cmake/kaldi
+)
+write_basic_package_version_file(
+    ${CMAKE_BINARY_DIR}/cmake/kaldi-config-version.cmake
+    VERSION ${KALDI_VERSION}
+    COMPATIBILITY AnyNewerVersion
+)
+install(FILES ${CMAKE_BINARY_DIR}/cmake/kaldi-config.cmake ${CMAKE_BINARY_DIR}/cmake/kaldi-config-version.cmake
+    DESTINATION lib/cmake/kaldi
+)
+install(EXPORT kaldi-targets DESTINATION ${CMAKE_INSTALL_PREFIX}/lib/cmake/kaldi)
diff --git a/INSTALL b/INSTALL
index 2dbf318118cb01a0d141b0694f13e5f9857b05c1..7beb79a7336e63e0c902ec7024d30d8dde498fbb 100644
--- a/INSTALL
+++ b/INSTALL
@@ -1,9 +1,16 @@
 This is the official Kaldi INSTALL. Look also at INSTALL.md for the git mirror installation.
-[for native Windows install, see windows/INSTALL]
+[Option 1 in the following does not apply to native Windows install, see windows/INSTALL or following Option 2]
 
-(1)
-go to tools/  and follow INSTALL instructions there.
+Option 1 (bash + makefile):
 
-(2) 
-go to src/ and follow INSTALL instructions there.
+  Steps:
+    (1)
+    go to tools/  and follow INSTALL instructions there.
 
+    (2)
+    go to src/ and follow INSTALL instructions there.
+
+Option 2 (cmake):
+
+    Go to cmake/ and follow INSTALL.md instructions there.
+    Note, it may not be well tested and some features are missing currently.
diff --git a/cmake/FindBLAS.cmake b/cmake/FindBLAS.cmake
new file mode 100644
index 0000000000000000000000000000000000000000..67676110c6d05b81e33ecb5ad00aacc1d123619f
--- /dev/null
+++ b/cmake/FindBLAS.cmake
@@ -0,0 +1,816 @@
+# Distributed under the OSI-approved BSD 3-Clause License.  See accompanying
+# file Copyright.txt or https://cmake.org/licensing for details.
+
+#[=======================================================================[.rst:
+FindBLAS
+--------
+
+Find Basic Linear Algebra Subprograms (BLAS) library
+
+This module finds an installed Fortran library that implements the
+BLAS linear-algebra interface (see http://www.netlib.org/blas/).  The
+list of libraries searched for is taken from the ``autoconf`` macro file,
+``acx_blas.m4`` (distributed at
+http://ac-archive.sourceforge.net/ac-archive/acx_blas.html).
+
+Input Variables
+^^^^^^^^^^^^^^^
+
+The following variables may be set to influence this module's behavior:
+
+``BLA_STATIC``
+  if ``ON`` use static linkage
+
+``BLA_VENDOR``
+  If set, checks only the specified vendor, if not set checks all the
+  possibilities.  List of vendors valid in this module:
+
+  * Goto
+  * OpenBLAS
+  * FLAME
+  * ATLAS PhiPACK
+  * CXML
+  * DXML
+  * SunPerf
+  * SCSL
+  * SGIMATH
+  * IBMESSL
+  * Intel10_32 (intel mkl v10 32 bit)
+  * Intel10_64lp (intel mkl v10+ 64 bit, threaded code, lp64 model)
+  * Intel10_64lp_seq (intel mkl v10+ 64 bit, sequential code, lp64 model)
+  * Intel10_64ilp (intel mkl v10+ 64 bit, threaded code, ilp64 model)
+  * Intel10_64ilp_seq (intel mkl v10+ 64 bit, sequential code, ilp64 model)
+  * Intel (obsolete versions of mkl 32 and 64 bit)
+  * ACML
+  * ACML_MP
+  * ACML_GPU
+  * Apple
+  * NAS
+  * Generic
+
+``BLA_F95``
+  if ``ON`` tries to find the BLAS95 interfaces
+
+``BLA_PREFER_PKGCONFIG``
+  if set ``pkg-config`` will be used to search for a BLAS library first
+  and if one is found that is preferred
+
+Result Variables
+^^^^^^^^^^^^^^^^
+
+This module defines the following variables:
+
+``BLAS_FOUND``
+  library implementing the BLAS interface is found
+``BLAS_LINKER_FLAGS``
+  uncached list of required linker flags (excluding ``-l`` and ``-L``).
+``BLAS_LIBRARIES``
+  uncached list of libraries (using full path name) to link against
+  to use BLAS (may be empty if compiler implicitly links BLAS)
+``BLAS95_LIBRARIES``
+  uncached list of libraries (using full path name) to link against
+  to use BLAS95 interface
+``BLAS95_FOUND``
+  library implementing the BLAS95 interface is found
+
+.. note::
+
+  C or CXX must be enabled to use Intel Math Kernel Library (MKL)
+
+  For example, to use Intel MKL libraries and/or Intel compiler:
+
+  .. code-block:: cmake
+
+    set(BLA_VENDOR Intel10_64lp)
+    find_package(BLAS)
+
+Hints
+^^^^^
+
+Set ``MKLROOT`` environment variable to a directory that contains an MKL
+installation.
+
+#]=======================================================================]
+
+include(CheckFunctionExists)
+include(CheckFortranFunctionExists)
+include(CMakePushCheckState)
+include(FindPackageHandleStandardArgs)
+cmake_push_check_state()
+set(CMAKE_REQUIRED_QUIET ${BLAS_FIND_QUIETLY})
+
+set(_blas_ORIG_CMAKE_FIND_LIBRARY_SUFFIXES ${CMAKE_FIND_LIBRARY_SUFFIXES})
+
+# Check the language being used
+if( NOT (CMAKE_C_COMPILER_LOADED OR CMAKE_CXX_COMPILER_LOADED OR CMAKE_Fortran_COMPILER_LOADED) )
+  if(BLAS_FIND_REQUIRED)
+    message(FATAL_ERROR "FindBLAS requires Fortran, C, or C++ to be enabled.")
+  else()
+    message(STATUS "Looking for BLAS... - NOT found (Unsupported languages)")
+    return()
+  endif()
+endif()
+
+if(BLA_PREFER_PKGCONFIG)
+  find_package(PkgConfig)
+  pkg_check_modules(PKGC_BLAS blas)
+  if(PKGC_BLAS_FOUND)
+    set(BLAS_FOUND ${PKGC_BLAS_FOUND})
+    set(BLAS_LIBRARIES "${PKGC_BLAS_LINK_LIBRARIES}")
+    return()
+  endif()
+endif()
+
+macro(Check_Fortran_Libraries LIBRARIES _prefix _name _flags _list _thread)
+  # This macro checks for the existence of the combination of fortran libraries
+  # given by _list.  If the combination is found, this macro checks (using the
+  # Check_Fortran_Function_Exists macro) whether can link against that library
+  # combination using the name of a routine given by _name using the linker
+  # flags given by _flags.  If the combination of libraries is found and passes
+  # the link test, LIBRARIES is set to the list of complete library paths that
+  # have been found.  Otherwise, LIBRARIES is set to FALSE.
+
+  # N.B. _prefix is the prefix applied to the names of all cached variables that
+  # are generated internally and marked advanced by this macro.
+
+  set(_libdir ${ARGN})
+
+  set(_libraries_work TRUE)
+  set(${LIBRARIES})
+  set(_combined_name)
+  if (NOT _libdir)
+    if (WIN32)
+      set(_libdir ENV LIB)
+    elseif (APPLE)
+      set(_libdir ENV DYLD_LIBRARY_PATH)
+    else ()
+      set(_libdir ENV LD_LIBRARY_PATH)
+    endif ()
+  endif ()
+
+  list(APPEND _libdir "${CMAKE_C_IMPLICIT_LINK_DIRECTORIES}")
+
+  foreach(_library ${_list})
+    set(_combined_name ${_combined_name}_${_library})
+    if(NOT "${_thread}" STREQUAL "")
+      set(_combined_name ${_combined_name}_thread)
+    endif()
+    if(_libraries_work)
+      if (BLA_STATIC)
+        if (WIN32)
+          set(CMAKE_FIND_LIBRARY_SUFFIXES .lib ${CMAKE_FIND_LIBRARY_SUFFIXES})
+        endif ()
+        if (APPLE)
+          set(CMAKE_FIND_LIBRARY_SUFFIXES .lib ${CMAKE_FIND_LIBRARY_SUFFIXES})
+        else ()
+          set(CMAKE_FIND_LIBRARY_SUFFIXES .a ${CMAKE_FIND_LIBRARY_SUFFIXES})
+        endif ()
+      else ()
+        if (CMAKE_SYSTEM_NAME STREQUAL "Linux")
+          # for ubuntu's libblas3gf and liblapack3gf packages
+          set(CMAKE_FIND_LIBRARY_SUFFIXES ${CMAKE_FIND_LIBRARY_SUFFIXES} .so.3gf)
+        endif ()
+      endif ()
+      find_library(${_prefix}_${_library}_LIBRARY
+        NAMES ${_library}
+        PATHS ${_libdir}
+        )
+      mark_as_advanced(${_prefix}_${_library}_LIBRARY)
+      set(${LIBRARIES} ${${LIBRARIES}} ${${_prefix}_${_library}_LIBRARY})
+      set(_libraries_work ${${_prefix}_${_library}_LIBRARY})
+    endif()
+  endforeach()
+  if(_libraries_work)
+    # Test this combination of libraries.
+    set(CMAKE_REQUIRED_LIBRARIES ${_flags} ${${LIBRARIES}} ${_thread})
+    #  message("DEBUG: CMAKE_REQUIRED_LIBRARIES = ${CMAKE_REQUIRED_LIBRARIES}")
+    if (CMAKE_Fortran_COMPILER_LOADED)
+      check_fortran_function_exists("${_name}" ${_prefix}${_combined_name}_WORKS)
+    else()
+      check_function_exists("${_name}_" ${_prefix}${_combined_name}_WORKS)
+    endif()
+    set(CMAKE_REQUIRED_LIBRARIES)
+    set(_libraries_work ${${_prefix}${_combined_name}_WORKS})
+  endif()
+  if(_libraries_work)
+    if("${_list}" STREQUAL "")
+      set(${LIBRARIES} "${LIBRARIES}-PLACEHOLDER-FOR-EMPTY-LIBRARIES")
+    else()
+      set(${LIBRARIES} ${${LIBRARIES}} ${_thread})  # for static link
+    endif()
+  else()
+    set(${LIBRARIES} FALSE)
+  endif()
+  #message("DEBUG: ${LIBRARIES} = ${${LIBRARIES}}")
+endmacro()
+
+set(BLAS_LINKER_FLAGS)
+set(BLAS_LIBRARIES)
+set(BLAS95_LIBRARIES)
+if (NOT $ENV{BLA_VENDOR} STREQUAL "")
+  set(BLA_VENDOR $ENV{BLA_VENDOR})
+else ()
+  if(NOT BLA_VENDOR)
+    set(BLA_VENDOR "All")
+  endif()
+endif ()
+
+if (BLA_VENDOR STREQUAL "All")
+  if(NOT BLAS_LIBRARIES)
+    # Implicitly linked BLAS libraries
+    check_fortran_libraries(
+      BLAS_LIBRARIES
+      BLAS
+      sgemm
+      ""
+      ""
+      ""
+      )
+  endif()
+endif ()
+
+#BLAS in intel mkl 10+ library? (em64t 64bit)
+if (BLA_VENDOR MATCHES "Intel" OR BLA_VENDOR STREQUAL "All")
+  if (NOT BLAS_LIBRARIES)
+
+    # System-specific settings
+    if (WIN32)
+      if (BLA_STATIC)
+        set(BLAS_mkl_DLL_SUFFIX "")
+      else()
+        set(BLAS_mkl_DLL_SUFFIX "_dll")
+      endif()
+    else()
+      # Switch to GNU Fortran support layer if needed (but not on Apple, where MKL does not provide it)
+      if(CMAKE_Fortran_COMPILER_LOADED AND CMAKE_Fortran_COMPILER_ID STREQUAL "GNU" AND NOT APPLE)
+          set(BLAS_mkl_INTFACE "gf")
+          set(BLAS_mkl_THREADING "gnu")
+          set(BLAS_mkl_OMP "gomp")
+      else()
+          set(BLAS_mkl_INTFACE "intel")
+          set(BLAS_mkl_THREADING "intel")
+          set(BLAS_mkl_OMP "iomp5")
+      endif()
+      set(BLAS_mkl_LM "-lm")
+      set(BLAS_mkl_LDL "-ldl")
+    endif()
+
+    if (BLA_VENDOR MATCHES "_64ilp")
+      set(BLAS_mkl_ILP_MODE "ilp64")
+    else ()
+      set(BLAS_mkl_ILP_MODE "lp64")
+    endif ()
+
+    if (CMAKE_C_COMPILER_LOADED OR CMAKE_CXX_COMPILER_LOADED)
+      if(BLAS_FIND_QUIETLY OR NOT BLAS_FIND_REQUIRED)
+        find_package(Threads)
+      else()
+        find_package(Threads REQUIRED)
+      endif()
+
+      set(BLAS_SEARCH_LIBS "")
+
+      if(BLA_F95)
+        set(BLAS_mkl_SEARCH_SYMBOL sgemm_f95)
+        set(_LIBRARIES BLAS95_LIBRARIES)
+        if (WIN32)
+          # Find the main file (32-bit or 64-bit)
+          set(BLAS_SEARCH_LIBS_WIN_MAIN "")
+          if (BLA_VENDOR STREQUAL "Intel10_32" OR BLA_VENDOR STREQUAL "All")
+            list(APPEND BLAS_SEARCH_LIBS_WIN_MAIN
+              "mkl_blas95${BLAS_mkl_DLL_SUFFIX} mkl_intel_c${BLAS_mkl_DLL_SUFFIX}")
+          endif()
+          if (BLA_VENDOR MATCHES "^Intel10_64i?lp" OR BLA_VENDOR STREQUAL "All")
+            list(APPEND BLAS_SEARCH_LIBS_WIN_MAIN
+              "mkl_blas95_${BLAS_mkl_ILP_MODE}${BLAS_mkl_DLL_SUFFIX} mkl_intel_${BLAS_mkl_ILP_MODE}${BLAS_mkl_DLL_SUFFIX}")
+          endif ()
+
+          # Add threading/sequential libs
+          set(BLAS_SEARCH_LIBS_WIN_THREAD "")
+          if (BLA_VENDOR MATCHES "_seq$" OR BLA_VENDOR STREQUAL "All")
+            list(APPEND BLAS_SEARCH_LIBS_WIN_THREAD
+              "mkl_sequential${BLAS_mkl_DLL_SUFFIX}")
+          endif()
+          if (NOT BLA_VENDOR MATCHES "_seq$" OR BLA_VENDOR STREQUAL "All")
+            # old version
+            list(APPEND BLAS_SEARCH_LIBS_WIN_THREAD
+              "libguide40 mkl_intel_thread${BLAS_mkl_DLL_SUFFIX}")
+            # mkl >= 10.3
+            list(APPEND BLAS_SEARCH_LIBS_WIN_THREAD
+              "libiomp5md mkl_intel_thread${BLAS_mkl_DLL_SUFFIX}")
+          endif()
+
+          # Cartesian product of the above
+          foreach (MAIN ${BLAS_SEARCH_LIBS_WIN_MAIN})
+            foreach (THREAD ${BLAS_SEARCH_LIBS_WIN_THREAD})
+              list(APPEND BLAS_SEARCH_LIBS
+                "${MAIN} ${THREAD} mkl_core${BLAS_mkl_DLL_SUFFIX}")
+            endforeach()
+          endforeach()
+        else ()
+          if (BLA_VENDOR STREQUAL "Intel10_32" OR BLA_VENDOR STREQUAL "All")
+            # old version
+            list(APPEND BLAS_SEARCH_LIBS
+              "mkl_blas95 mkl_${BLAS_mkl_INTFACE} mkl_${BLAS_mkl_THREADING}_thread mkl_core guide")
+
+            # mkl >= 10.3
+            list(APPEND BLAS_SEARCH_LIBS
+              "mkl_blas95 mkl_${BLAS_mkl_INTFACE} mkl_${BLAS_mkl_THREADING}_thread mkl_core ${BLAS_mkl_OMP}")
+          endif ()
+          if (BLA_VENDOR MATCHES "^Intel10_64i?lp$" OR BLA_VENDOR STREQUAL "All")
+            # old version
+            list(APPEND BLAS_SEARCH_LIBS
+              "mkl_blas95 mkl_${BLAS_mkl_INTFACE}_${BLAS_mkl_ILP_MODE} mkl_${BLAS_mkl_THREADING}_thread mkl_core guide")
+
+            # mkl >= 10.3
+            list(APPEND BLAS_SEARCH_LIBS
+              "mkl_blas95_${BLAS_mkl_ILP_MODE} mkl_${BLAS_mkl_INTFACE}_${BLAS_mkl_ILP_MODE} mkl_${BLAS_mkl_THREADING}_thread mkl_core ${BLAS_mkl_OMP}")
+          endif ()
+          if (BLA_VENDOR MATCHES "^Intel10_64i?lp_seq$" OR BLA_VENDOR STREQUAL "All")
+            list(APPEND BLAS_SEARCH_LIBS
+              "mkl_blas95_${BLAS_mkl_ILP_MODE} mkl_${BLAS_mkl_INTFACE}_${BLAS_mkl_ILP_MODE} mkl_sequential mkl_core")
+          endif ()
+        endif ()
+      else ()
+        set(BLAS_mkl_SEARCH_SYMBOL sgemm)
+        set(_LIBRARIES BLAS_LIBRARIES)
+        if (WIN32)
+          # Find the main file (32-bit or 64-bit)
+          set(BLAS_SEARCH_LIBS_WIN_MAIN "")
+          if (BLA_VENDOR STREQUAL "Intel10_32" OR BLA_VENDOR STREQUAL "All")
+            list(APPEND BLAS_SEARCH_LIBS_WIN_MAIN
+              "mkl_intel_c${BLAS_mkl_DLL_SUFFIX}")
+          endif()
+          if (BLA_VENDOR MATCHES "^Intel10_64i?lp" OR BLA_VENDOR STREQUAL "All")
+            list(APPEND BLAS_SEARCH_LIBS_WIN_MAIN
+              "mkl_intel_${BLAS_mkl_ILP_MODE}${BLAS_mkl_DLL_SUFFIX}")
+          endif ()
+
+          # Add threading/sequential libs
+          set(BLAS_SEARCH_LIBS_WIN_THREAD "")
+          if (NOT BLA_VENDOR MATCHES "_seq$" OR BLA_VENDOR STREQUAL "All")
+            # old version
+            list(APPEND BLAS_SEARCH_LIBS_WIN_THREAD
+              "libguide40 mkl_intel_thread${BLAS_mkl_DLL_SUFFIX}")
+            # mkl >= 10.3
+            list(APPEND BLAS_SEARCH_LIBS_WIN_THREAD
+              "libiomp5md mkl_intel_thread${BLAS_mkl_DLL_SUFFIX}")
+          endif()
+          if (BLA_VENDOR MATCHES "_seq$" OR BLA_VENDOR STREQUAL "All")
+            list(APPEND BLAS_SEARCH_LIBS_WIN_THREAD
+              "mkl_sequential${BLAS_mkl_DLL_SUFFIX}")
+          endif()
+
+          # Cartesian product of the above
+          foreach (MAIN ${BLAS_SEARCH_LIBS_WIN_MAIN})
+            foreach (THREAD ${BLAS_SEARCH_LIBS_WIN_THREAD})
+              list(APPEND BLAS_SEARCH_LIBS
+                "${MAIN} ${THREAD} mkl_core${BLAS_mkl_DLL_SUFFIX}")
+            endforeach()
+          endforeach()
+        else ()
+          if (BLA_VENDOR STREQUAL "Intel10_32" OR BLA_VENDOR STREQUAL "All")
+            # old version
+            list(APPEND BLAS_SEARCH_LIBS
+              "mkl_${BLAS_mkl_INTFACE} mkl_${BLAS_mkl_THREADING}_thread mkl_core guide")
+
+            # mkl >= 10.3
+            list(APPEND BLAS_SEARCH_LIBS
+              "mkl_${BLAS_mkl_INTFACE} mkl_${BLAS_mkl_THREADING}_thread mkl_core ${BLAS_mkl_OMP}")
+          endif ()
+          if (BLA_VENDOR MATCHES "^Intel10_64i?lp$" OR BLA_VENDOR STREQUAL "All")
+            # old version
+            list(APPEND BLAS_SEARCH_LIBS
+              "mkl_${BLAS_mkl_INTFACE}_${BLAS_mkl_ILP_MODE} mkl_${BLAS_mkl_THREADING}_thread mkl_core guide")
+
+            # mkl >= 10.3
+            list(APPEND BLAS_SEARCH_LIBS
+              "mkl_${BLAS_mkl_INTFACE}_${BLAS_mkl_ILP_MODE} mkl_${BLAS_mkl_THREADING}_thread mkl_core ${BLAS_mkl_OMP}")
+          endif ()
+          if (BLA_VENDOR MATCHES "^Intel10_64i?lp_seq$" OR BLA_VENDOR STREQUAL "All")
+            list(APPEND BLAS_SEARCH_LIBS
+              "mkl_${BLAS_mkl_INTFACE}_${BLAS_mkl_ILP_MODE} mkl_sequential mkl_core")
+          endif ()
+
+          #older vesions of intel mkl libs
+          if (BLA_VENDOR STREQUAL "Intel" OR BLA_VENDOR STREQUAL "All")
+            list(APPEND BLAS_SEARCH_LIBS
+              "mkl")
+            list(APPEND BLAS_SEARCH_LIBS
+              "mkl_ia32")
+            list(APPEND BLAS_SEARCH_LIBS
+              "mkl_em64t")
+          endif ()
+        endif ()
+      endif ()
+
+      if (DEFINED ENV{MKLROOT})
+        if (BLA_VENDOR STREQUAL "Intel10_32")
+          set(_BLAS_MKLROOT_LIB_DIR "$ENV{MKLROOT}/lib/ia32")
+        elseif (BLA_VENDOR MATCHES "^Intel10_64i?lp$" OR BLA_VENDOR MATCHES "^Intel10_64i?lp_seq$")
+          set(_BLAS_MKLROOT_LIB_DIR "$ENV{MKLROOT}/lib/intel64")
+        endif ()
+      endif ()
+      if (_BLAS_MKLROOT_LIB_DIR)
+        if (WIN32)
+          string(APPEND _BLAS_MKLROOT_LIB_DIR "_win")
+        elseif (APPLE)
+          string(APPEND _BLAS_MKLROOT_LIB_DIR "_mac")
+        else ()
+          string(APPEND _BLAS_MKLROOT_LIB_DIR "_lin")
+        endif ()
+      endif ()
+
+      foreach (IT ${BLAS_SEARCH_LIBS})
+        string(REPLACE " " ";" SEARCH_LIBS ${IT})
+        if (NOT ${_LIBRARIES})
+          check_fortran_libraries(
+            ${_LIBRARIES}
+            BLAS
+            ${BLAS_mkl_SEARCH_SYMBOL}
+            ""
+            "${SEARCH_LIBS}"
+            "${CMAKE_THREAD_LIBS_INIT};${BLAS_mkl_LM};${BLAS_mkl_LDL}"
+            "${_BLAS_MKLROOT_LIB_DIR}"
+            )
+        endif ()
+      endforeach ()
+
+    endif ()
+    unset(BLAS_mkl_ILP_MODE)
+    unset(BLAS_mkl_INTFACE)
+    unset(BLAS_mkl_THREADING)
+    unset(BLAS_mkl_OMP)
+    unset(BLAS_mkl_DLL_SUFFIX)
+    unset(BLAS_mkl_LM)
+    unset(BLAS_mkl_LDL)
+  endif ()
+endif ()
+
+if(BLA_F95)
+  find_package_handle_standard_args(BLAS REQUIRED_VARS BLAS95_LIBRARIES)
+  set(BLAS95_FOUND ${BLAS_FOUND})
+  if(BLAS_FOUND)
+    set(BLAS_LIBRARIES "${BLAS95_LIBRARIES}")
+  endif()
+endif()
+
+if (BLA_VENDOR STREQUAL "Goto" OR BLA_VENDOR STREQUAL "All")
+  if(NOT BLAS_LIBRARIES)
+    # gotoblas (http://www.tacc.utexas.edu/tacc-projects/gotoblas2)
+    check_fortran_libraries(
+      BLAS_LIBRARIES
+      BLAS
+      sgemm
+      ""
+      "goto2"
+      ""
+      )
+  endif()
+endif ()
+
+if (BLA_VENDOR STREQUAL "OpenBLAS" OR BLA_VENDOR STREQUAL "All")
+  if(NOT BLAS_LIBRARIES)
+    # OpenBLAS (http://www.openblas.net)
+    check_fortran_libraries(
+      BLAS_LIBRARIES
+      BLAS
+      sgemm
+      ""
+      "openblas"
+      ""
+      )
+  endif()
+  if(NOT BLAS_LIBRARIES)
+    find_package(Threads)
+    # OpenBLAS (http://www.openblas.net)
+    check_fortran_libraries(
+      BLAS_LIBRARIES
+      BLAS
+      sgemm
+      ""
+      "openblas"
+      "${CMAKE_THREAD_LIBS_INIT}"
+      )
+  endif()
+endif ()
+
+if (BLA_VENDOR STREQUAL "FLAME" OR BLA_VENDOR STREQUAL "All")
+  if(NOT BLAS_LIBRARIES)
+    # FLAME's blis library (https://github.com/flame/blis)
+    check_fortran_libraries(
+      BLAS_LIBRARIES
+      BLAS
+      sgemm
+      ""
+      "blis"
+      ""
+      )
+  endif()
+endif ()
+
+if (BLA_VENDOR STREQUAL "ATLAS" OR BLA_VENDOR STREQUAL "All")
+  if(NOT BLAS_LIBRARIES)
+    # BLAS in ATLAS library? (http://math-atlas.sourceforge.net/)
+    check_fortran_libraries(
+      BLAS_LIBRARIES
+      BLAS
+      dgemm
+      ""
+      "f77blas;atlas"
+      ""
+      )
+  endif()
+endif ()
+
+# BLAS in PhiPACK libraries? (requires generic BLAS lib, too)
+if (BLA_VENDOR STREQUAL "PhiPACK" OR BLA_VENDOR STREQUAL "All")
+  if(NOT BLAS_LIBRARIES)
+    check_fortran_libraries(
+      BLAS_LIBRARIES
+      BLAS
+      sgemm
+      ""
+      "sgemm;dgemm;blas"
+      ""
+      )
+  endif()
+endif ()
+
+# BLAS in Alpha CXML library?
+if (BLA_VENDOR STREQUAL "CXML" OR BLA_VENDOR STREQUAL "All")
+  if(NOT BLAS_LIBRARIES)
+    check_fortran_libraries(
+      BLAS_LIBRARIES
+      BLAS
+      sgemm
+      ""
+      "cxml"
+      ""
+      )
+  endif()
+endif ()
+
+# BLAS in Alpha DXML library? (now called CXML, see above)
+if (BLA_VENDOR STREQUAL "DXML" OR BLA_VENDOR STREQUAL "All")
+  if(NOT BLAS_LIBRARIES)
+    check_fortran_libraries(
+      BLAS_LIBRARIES
+      BLAS
+      sgemm
+      ""
+      "dxml"
+      ""
+      )
+  endif()
+endif ()
+
+# BLAS in Sun Performance library?
+if (BLA_VENDOR STREQUAL "SunPerf" OR BLA_VENDOR STREQUAL "All")
+  if(NOT BLAS_LIBRARIES)
+    check_fortran_libraries(
+      BLAS_LIBRARIES
+      BLAS
+      sgemm
+      "-xlic_lib=sunperf"
+      "sunperf;sunmath"
+      ""
+      )
+    if(BLAS_LIBRARIES)
+      set(BLAS_LINKER_FLAGS "-xlic_lib=sunperf")
+    endif()
+  endif()
+endif ()
+
+# BLAS in SCSL library?  (SGI/Cray Scientific Library)
+if (BLA_VENDOR STREQUAL "SCSL" OR BLA_VENDOR STREQUAL "All")
+  if(NOT BLAS_LIBRARIES)
+    check_fortran_libraries(
+      BLAS_LIBRARIES
+      BLAS
+      sgemm
+      ""
+      "scsl"
+      ""
+      )
+  endif()
+endif ()
+
+# BLAS in SGIMATH library?
+if (BLA_VENDOR STREQUAL "SGIMATH" OR BLA_VENDOR STREQUAL "All")
+  if(NOT BLAS_LIBRARIES)
+    check_fortran_libraries(
+      BLAS_LIBRARIES
+      BLAS
+      sgemm
+      ""
+      "complib.sgimath"
+      ""
+      )
+  endif()
+endif ()
+
+# BLAS in IBM ESSL library? (requires generic BLAS lib, too)
+if (BLA_VENDOR STREQUAL "IBMESSL" OR BLA_VENDOR STREQUAL "All")
+  if(NOT BLAS_LIBRARIES)
+    check_fortran_libraries(
+      BLAS_LIBRARIES
+      BLAS
+      sgemm
+      ""
+      "essl;blas"
+      ""
+      )
+  endif()
+endif ()
+
+#BLAS in acml library?
+if (BLA_VENDOR MATCHES "ACML" OR BLA_VENDOR STREQUAL "All")
+  if( ((BLA_VENDOR STREQUAL "ACML") AND (NOT BLAS_ACML_LIB_DIRS)) OR
+    ((BLA_VENDOR STREQUAL "ACML_MP") AND (NOT BLAS_ACML_MP_LIB_DIRS)) OR
+    ((BLA_VENDOR STREQUAL "ACML_GPU") AND (NOT BLAS_ACML_GPU_LIB_DIRS))
+    )
+  # try to find acml in "standard" paths
+  if( WIN32 )
+    file( GLOB _ACML_ROOT "C:/AMD/acml*/ACML-EULA.txt" )
+  else()
+    file( GLOB _ACML_ROOT "/opt/acml*/ACML-EULA.txt" )
+  endif()
+  if( WIN32 )
+    file( GLOB _ACML_GPU_ROOT "C:/AMD/acml*/GPGPUexamples" )
+  else()
+    file( GLOB _ACML_GPU_ROOT "/opt/acml*/GPGPUexamples" )
+  endif()
+  list(GET _ACML_ROOT 0 _ACML_ROOT)
+  list(GET _ACML_GPU_ROOT 0 _ACML_GPU_ROOT)
+  if( _ACML_ROOT )
+    get_filename_component( _ACML_ROOT ${_ACML_ROOT} PATH )
+    if( SIZEOF_INTEGER EQUAL 8 )
+      set( _ACML_PATH_SUFFIX "_int64" )
+    else()
+      set( _ACML_PATH_SUFFIX "" )
+    endif()
+    if( CMAKE_Fortran_COMPILER_ID STREQUAL "Intel" )
+      set( _ACML_COMPILER32 "ifort32" )
+      set( _ACML_COMPILER64 "ifort64" )
+    elseif( CMAKE_Fortran_COMPILER_ID STREQUAL "SunPro" )
+      set( _ACML_COMPILER32 "sun32" )
+      set( _ACML_COMPILER64 "sun64" )
+    elseif( CMAKE_Fortran_COMPILER_ID STREQUAL "PGI" )
+      set( _ACML_COMPILER32 "pgi32" )
+      if( WIN32 )
+        set( _ACML_COMPILER64 "win64" )
+      else()
+        set( _ACML_COMPILER64 "pgi64" )
+      endif()
+    elseif( CMAKE_Fortran_COMPILER_ID STREQUAL "Open64" )
+      # 32 bit builds not supported on Open64 but for code simplicity
+      # We'll just use the same directory twice
+      set( _ACML_COMPILER32 "open64_64" )
+      set( _ACML_COMPILER64 "open64_64" )
+    elseif( CMAKE_Fortran_COMPILER_ID STREQUAL "NAG" )
+      set( _ACML_COMPILER32 "nag32" )
+      set( _ACML_COMPILER64 "nag64" )
+    else()
+      set( _ACML_COMPILER32 "gfortran32" )
+      set( _ACML_COMPILER64 "gfortran64" )
+    endif()
+
+    if( BLA_VENDOR STREQUAL "ACML_MP" )
+      set(_ACML_MP_LIB_DIRS
+        "${_ACML_ROOT}/${_ACML_COMPILER32}_mp${_ACML_PATH_SUFFIX}/lib"
+        "${_ACML_ROOT}/${_ACML_COMPILER64}_mp${_ACML_PATH_SUFFIX}/lib" )
+    else()
+      set(_ACML_LIB_DIRS
+        "${_ACML_ROOT}/${_ACML_COMPILER32}${_ACML_PATH_SUFFIX}/lib"
+        "${_ACML_ROOT}/${_ACML_COMPILER64}${_ACML_PATH_SUFFIX}/lib" )
+    endif()
+  endif()
+elseif(BLAS_${BLA_VENDOR}_LIB_DIRS)
+  set(_${BLA_VENDOR}_LIB_DIRS ${BLAS_${BLA_VENDOR}_LIB_DIRS})
+endif()
+
+if( BLA_VENDOR STREQUAL "ACML_MP" )
+  foreach( BLAS_ACML_MP_LIB_DIRS ${_ACML_MP_LIB_DIRS})
+    check_fortran_libraries (
+      BLAS_LIBRARIES
+      BLAS
+      sgemm
+      "" "acml_mp;acml_mv" "" ${BLAS_ACML_MP_LIB_DIRS}
+      )
+    if( BLAS_LIBRARIES )
+      break()
+    endif()
+  endforeach()
+elseif( BLA_VENDOR STREQUAL "ACML_GPU" )
+  foreach( BLAS_ACML_GPU_LIB_DIRS ${_ACML_GPU_LIB_DIRS})
+    check_fortran_libraries (
+      BLAS_LIBRARIES
+      BLAS
+      sgemm
+      "" "acml;acml_mv;CALBLAS" "" ${BLAS_ACML_GPU_LIB_DIRS}
+      )
+    if( BLAS_LIBRARIES )
+      break()
+    endif()
+  endforeach()
+else()
+  foreach( BLAS_ACML_LIB_DIRS ${_ACML_LIB_DIRS} )
+    check_fortran_libraries (
+      BLAS_LIBRARIES
+      BLAS
+      sgemm
+      "" "acml;acml_mv" "" ${BLAS_ACML_LIB_DIRS}
+      )
+    if( BLAS_LIBRARIES )
+      break()
+    endif()
+  endforeach()
+endif()
+
+# Either acml or acml_mp should be in LD_LIBRARY_PATH but not both
+if(NOT BLAS_LIBRARIES)
+  check_fortran_libraries(
+    BLAS_LIBRARIES
+    BLAS
+    sgemm
+    ""
+    "acml;acml_mv"
+    ""
+    )
+endif()
+if(NOT BLAS_LIBRARIES)
+  check_fortran_libraries(
+    BLAS_LIBRARIES
+    BLAS
+    sgemm
+    ""
+    "acml_mp;acml_mv"
+    ""
+    )
+endif()
+if(NOT BLAS_LIBRARIES)
+  check_fortran_libraries(
+    BLAS_LIBRARIES
+    BLAS
+    sgemm
+    ""
+    "acml;acml_mv;CALBLAS"
+    ""
+    )
+endif()
+endif () # ACML
+
+# Apple BLAS library?
+if (BLA_VENDOR STREQUAL "Apple" OR BLA_VENDOR STREQUAL "All")
+  if(NOT BLAS_LIBRARIES)
+    check_fortran_libraries(
+      BLAS_LIBRARIES
+      BLAS
+      dgemm
+      ""
+      "Accelerate"
+      ""
+      )
+  endif()
+endif ()
+
+if (BLA_VENDOR STREQUAL "NAS" OR BLA_VENDOR STREQUAL "All")
+  if ( NOT BLAS_LIBRARIES )
+    check_fortran_libraries(
+      BLAS_LIBRARIES
+      BLAS
+      dgemm
+      ""
+      "vecLib"
+      ""
+      )
+  endif ()
+endif ()
+
+# Generic BLAS library?
+if (BLA_VENDOR STREQUAL "Generic" OR BLA_VENDOR STREQUAL "All")
+  if(NOT BLAS_LIBRARIES)
+    check_fortran_libraries(
+      BLAS_LIBRARIES
+      BLAS
+      sgemm
+      ""
+      "blas"
+      ""
+      )
+  endif()
+endif ()
+
+if(NOT BLA_F95)
+  find_package_handle_standard_args(BLAS REQUIRED_VARS BLAS_LIBRARIES)
+endif()
+
+# On compilers that implicitly link BLAS (such as ftn, cc, and CC on Cray HPC machines)
+# we used a placeholder for empty BLAS_LIBRARIES to get through our logic above.
+if (BLAS_LIBRARIES STREQUAL "BLAS_LIBRARIES-PLACEHOLDER-FOR-EMPTY-LIBRARIES")
+  set(BLAS_LIBRARIES "")
+endif()
+
+cmake_pop_check_state()
+set(CMAKE_FIND_LIBRARY_SUFFIXES ${_blas_ORIG_CMAKE_FIND_LIBRARY_SUFFIXES})
diff --git a/cmake/FindCUB.cmake b/cmake/FindCUB.cmake
new file mode 100644
index 0000000000000000000000000000000000000000..33c8a926f978a26497becdd06d01af08eb98ad41
--- /dev/null
+++ b/cmake/FindCUB.cmake
@@ -0,0 +1,25 @@
+# Try to find the CUB library and headers.
+#  CUB_ROOT_DIR     - where to find
+
+#  CUB_FOUND        - system has CUB
+#  CUB_INCLUDE_DIRS - the CUB include directory
+
+
+find_path(CUB_INCLUDE_DIR
+    NAMES cub/cub.cuh
+    HINTS ${CUB_ROOT_DIR}
+    DOC "The directory where CUB includes reside"
+)
+
+set(CUB_INCLUDE_DIRS ${CUB_INCLUDE_DIR})
+
+include(FindPackageHandleStandardArgs)
+find_package_handle_standard_args(CUB
+        FOUND_VAR CUB_FOUND
+        REQUIRED_VARS CUB_INCLUDE_DIR
+)
+
+mark_as_advanced(CUB_FOUND)
+
+add_library(CUB INTERFACE)
+target_include_directories(CUB INTERFACE ${CUB_INCLUDE_DIR})
diff --git a/cmake/FindICU.cmake b/cmake/FindICU.cmake
new file mode 100644
index 0000000000000000000000000000000000000000..8c460082c36639847d842d82457ebee63702a77a
--- /dev/null
+++ b/cmake/FindICU.cmake
@@ -0,0 +1,428 @@
+# Distributed under the OSI-approved BSD 3-Clause License.  See accompanying
+# file Copyright.txt or https://cmake.org/licensing for details.
+
+#[=======================================================================[.rst:
+FindICU
+-------
+
+Find the International Components for Unicode (ICU) libraries and
+programs.
+
+This module supports multiple components.
+Components can include any of: ``data``, ``i18n``, ``io``, ``le``,
+``lx``, ``test``, ``tu`` and ``uc``.
+
+Note that on Windows ``data`` is named ``dt`` and ``i18n`` is named
+``in``; any of the names may be used, and the appropriate
+platform-specific library name will be automatically selected.
+
+This module reports information about the ICU installation in
+several variables.  General variables::
+
+  ICU_VERSION - ICU release version
+  ICU_FOUND - true if the main programs and libraries were found
+  ICU_LIBRARIES - component libraries to be linked
+  ICU_INCLUDE_DIRS - the directories containing the ICU headers
+
+Imported targets::
+
+  ICU::<C>
+
+Where ``<C>`` is the name of an ICU component, for example
+``ICU::i18n``.
+
+ICU programs are reported in::
+
+  ICU_GENCNVAL_EXECUTABLE - path to gencnval executable
+  ICU_ICUINFO_EXECUTABLE - path to icuinfo executable
+  ICU_GENBRK_EXECUTABLE - path to genbrk executable
+  ICU_ICU-CONFIG_EXECUTABLE - path to icu-config executable
+  ICU_GENRB_EXECUTABLE - path to genrb executable
+  ICU_GENDICT_EXECUTABLE - path to gendict executable
+  ICU_DERB_EXECUTABLE - path to derb executable
+  ICU_PKGDATA_EXECUTABLE - path to pkgdata executable
+  ICU_UCONV_EXECUTABLE - path to uconv executable
+  ICU_GENCFU_EXECUTABLE - path to gencfu executable
+  ICU_MAKECONV_EXECUTABLE - path to makeconv executable
+  ICU_GENNORM2_EXECUTABLE - path to gennorm2 executable
+  ICU_GENCCODE_EXECUTABLE - path to genccode executable
+  ICU_GENSPREP_EXECUTABLE - path to gensprep executable
+  ICU_ICUPKG_EXECUTABLE - path to icupkg executable
+  ICU_GENCMN_EXECUTABLE - path to gencmn executable
+
+ICU component libraries are reported in::
+
+  ICU_<C>_FOUND - ON if component was found
+  ICU_<C>_LIBRARIES - libraries for component
+
+ICU datafiles are reported in::
+
+  ICU_MAKEFILE_INC - Makefile.inc
+  ICU_PKGDATA_INC - pkgdata.inc
+
+Note that ``<C>`` is the uppercased name of the component.
+
+This module reads hints about search results from::
+
+  ICU_ROOT - the root of the ICU installation
+
+The environment variable ``ICU_ROOT`` may also be used; the
+ICU_ROOT variable takes precedence.
+
+The following cache variables may also be set::
+
+  ICU_<P>_EXECUTABLE - the path to executable <P>
+  ICU_INCLUDE_DIR - the directory containing the ICU headers
+  ICU_<C>_LIBRARY - the library for component <C>
+
+.. note::
+
+  In most cases none of the above variables will require setting,
+  unless multiple ICU versions are available and a specific version
+  is required.
+
+Other variables one may set to control this module are::
+
+  ICU_DEBUG - Set to ON to enable debug output from FindICU.
+#]=======================================================================]
+
+# Written by Roger Leigh <rleigh@codelibre.net>
+
+set(icu_programs
+  gencnval
+  icuinfo
+  genbrk
+  icu-config
+  genrb
+  gendict
+  derb
+  pkgdata
+  uconv
+  gencfu
+  makeconv
+  gennorm2
+  genccode
+  gensprep
+  icupkg
+  gencmn)
+
+set(icu_data
+  Makefile.inc
+  pkgdata.inc)
+
+# The ICU checks are contained in a function due to the large number
+# of temporary variables needed.
+function(_ICU_FIND)
+  # Set up search paths, taking compiler into account.  Search ICU_ROOT,
+  # with ICU_ROOT in the environment as a fallback if unset.
+  if(ICU_ROOT)
+    list(APPEND icu_roots "${ICU_ROOT}")
+  else()
+    if(NOT "$ENV{ICU_ROOT}" STREQUAL "")
+      file(TO_CMAKE_PATH "$ENV{ICU_ROOT}" NATIVE_PATH)
+      list(APPEND icu_roots "${NATIVE_PATH}")
+      set(ICU_ROOT "${NATIVE_PATH}"
+          CACHE PATH "Location of the ICU installation" FORCE)
+    endif()
+  endif()
+
+  # Find include directory
+  list(APPEND icu_include_suffixes "include")
+  find_path(ICU_INCLUDE_DIR
+            NAMES "unicode/utypes.h"
+            HINTS ${icu_roots}
+            PATH_SUFFIXES ${icu_include_suffixes}
+            DOC "ICU include directory")
+  set(ICU_INCLUDE_DIR "${ICU_INCLUDE_DIR}" PARENT_SCOPE)
+
+  # Get version
+  if(ICU_INCLUDE_DIR AND EXISTS "${ICU_INCLUDE_DIR}/unicode/uvernum.h")
+    file(STRINGS "${ICU_INCLUDE_DIR}/unicode/uvernum.h" icu_header_str
+      REGEX "^#define[\t ]+U_ICU_VERSION[\t ]+\".*\".*")
+
+    string(REGEX REPLACE "^#define[\t ]+U_ICU_VERSION[\t ]+\"([^ \\n]*)\".*"
+      "\\1" icu_version_string "${icu_header_str}")
+    set(ICU_VERSION "${icu_version_string}")
+    set(ICU_VERSION "${icu_version_string}" PARENT_SCOPE)
+    unset(icu_header_str)
+    unset(icu_version_string)
+  endif()
+
+  if(CMAKE_SIZEOF_VOID_P EQUAL 8)
+    # 64-bit binary directory
+    set(_bin64 "bin64")
+    # 64-bit library directory
+    set(_lib64 "lib64")
+  endif()
+
+
+  # Find all ICU programs
+  list(APPEND icu_binary_suffixes "${_bin64}" "bin" "sbin")
+  foreach(program ${icu_programs})
+    string(TOUPPER "${program}" program_upcase)
+    set(cache_var "ICU_${program_upcase}_EXECUTABLE")
+    set(program_var "ICU_${program_upcase}_EXECUTABLE")
+    find_program("${cache_var}"
+      NAMES "${program}"
+      HINTS ${icu_roots}
+      PATH_SUFFIXES ${icu_binary_suffixes}
+      DOC "ICU ${program} executable"
+      NO_PACKAGE_ROOT_PATH
+      )
+    mark_as_advanced(cache_var)
+    set("${program_var}" "${${cache_var}}" PARENT_SCOPE)
+  endforeach()
+
+  # Find all ICU libraries
+  list(APPEND icu_library_suffixes "${_lib64}" "lib")
+  set(ICU_REQUIRED_LIBS_FOUND ON)
+  set(static_prefix )
+  # static icu libraries compiled with MSVC have the prefix 's'
+  if(MSVC)
+    set(static_prefix "s")
+  endif()
+  foreach(component ${ICU_FIND_COMPONENTS})
+    string(TOUPPER "${component}" component_upcase)
+    set(component_cache "ICU_${component_upcase}_LIBRARY")
+    set(component_cache_release "${component_cache}_RELEASE")
+    set(component_cache_debug "${component_cache}_DEBUG")
+    set(component_found "${component_upcase}_FOUND")
+    set(component_libnames "icu${component}")
+    set(component_debug_libnames "icu${component}d")
+
+    # Special case deliberate library naming mismatches between Unix
+    # and Windows builds
+    unset(component_libnames)
+    unset(component_debug_libnames)
+    list(APPEND component_libnames "icu${component}")
+    list(APPEND component_debug_libnames "icu${component}d")
+    if(component STREQUAL "data")
+      list(APPEND component_libnames "icudt")
+      # Note there is no debug variant at present
+      list(APPEND component_debug_libnames "icudtd")
+    endif()
+    if(component STREQUAL "dt")
+      list(APPEND component_libnames "icudata")
+      # Note there is no debug variant at present
+      list(APPEND component_debug_libnames "icudatad")
+    endif()
+    if(component STREQUAL "i18n")
+      list(APPEND component_libnames "icuin")
+      list(APPEND component_debug_libnames "icuind")
+    endif()
+    if(component STREQUAL "in")
+      list(APPEND component_libnames "icui18n")
+      list(APPEND component_debug_libnames "icui18nd")
+    endif()
+
+    if(static_prefix)
+      unset(static_component_libnames)
+      unset(static_component_debug_libnames)
+      foreach(component_libname ${component_libnames})
+        list(APPEND static_component_libnames
+          ${static_prefix}${component_libname})
+      endforeach()
+      foreach(component_libname ${component_debug_libnames})
+        list(APPEND static_component_debug_libnames
+          ${static_prefix}${component_libname})
+      endforeach()
+      list(APPEND component_libnames ${static_component_libnames})
+      list(APPEND component_debug_libnames ${static_component_debug_libnames})
+    endif()
+    find_library("${component_cache_release}"
+      NAMES ${component_libnames}
+      HINTS ${icu_roots}
+      PATH_SUFFIXES ${icu_library_suffixes}
+      DOC "ICU ${component} library (release)"
+      NO_PACKAGE_ROOT_PATH
+      )
+    find_library("${component_cache_debug}"
+      NAMES ${component_debug_libnames}
+      HINTS ${icu_roots}
+      PATH_SUFFIXES ${icu_library_suffixes}
+      DOC "ICU ${component} library (debug)"
+      NO_PACKAGE_ROOT_PATH
+      )
+    include(SelectLibraryConfigurations)
+    select_library_configurations(ICU_${component_upcase})
+    mark_as_advanced("${component_cache_release}" "${component_cache_debug}")
+    if(${component_cache})
+      set("${component_found}" ON)
+      list(APPEND ICU_LIBRARY "${${component_cache}}")
+    endif()
+    mark_as_advanced("${component_found}")
+    set("${component_cache}" "${${component_cache}}" PARENT_SCOPE)
+    set("${component_found}" "${${component_found}}" PARENT_SCOPE)
+    if(${component_found})
+      if (ICU_FIND_REQUIRED_${component})
+        list(APPEND ICU_LIBS_FOUND "${component} (required)")
+      else()
+        list(APPEND ICU_LIBS_FOUND "${component} (optional)")
+      endif()
+    else()
+      if (ICU_FIND_REQUIRED_${component})
+        set(ICU_REQUIRED_LIBS_FOUND OFF)
+        list(APPEND ICU_LIBS_NOTFOUND "${component} (required)")
+      else()
+        list(APPEND ICU_LIBS_NOTFOUND "${component} (optional)")
+      endif()
+    endif()
+  endforeach()
+  set(_ICU_REQUIRED_LIBS_FOUND "${ICU_REQUIRED_LIBS_FOUND}" PARENT_SCOPE)
+  set(ICU_LIBRARY "${ICU_LIBRARY}" PARENT_SCOPE)
+
+  # Find all ICU data files
+  if(CMAKE_LIBRARY_ARCHITECTURE)
+    list(APPEND icu_data_suffixes
+      "${_lib64}/${CMAKE_LIBRARY_ARCHITECTURE}/icu/${ICU_VERSION}"
+      "lib/${CMAKE_LIBRARY_ARCHITECTURE}/icu/${ICU_VERSION}"
+      "${_lib64}/${CMAKE_LIBRARY_ARCHITECTURE}/icu"
+      "lib/${CMAKE_LIBRARY_ARCHITECTURE}/icu")
+  endif()
+  list(APPEND icu_data_suffixes
+    "${_lib64}/icu/${ICU_VERSION}"
+    "lib/icu/${ICU_VERSION}"
+    "${_lib64}/icu"
+    "lib/icu")
+  foreach(data ${icu_data})
+    string(TOUPPER "${data}" data_upcase)
+    string(REPLACE "." "_" data_upcase "${data_upcase}")
+    set(cache_var "ICU_${data_upcase}")
+    set(data_var "ICU_${data_upcase}")
+    find_file("${cache_var}"
+      NAMES "${data}"
+      HINTS ${icu_roots}
+      PATH_SUFFIXES ${icu_data_suffixes}
+      DOC "ICU ${data} data file")
+    mark_as_advanced(cache_var)
+    set("${data_var}" "${${cache_var}}" PARENT_SCOPE)
+  endforeach()
+
+  if(NOT ICU_FIND_QUIETLY)
+    if(ICU_LIBS_FOUND)
+      message(STATUS "Found the following ICU libraries:")
+      foreach(found ${ICU_LIBS_FOUND})
+        message(STATUS "  ${found}")
+      endforeach()
+    endif()
+    if(ICU_LIBS_NOTFOUND)
+      message(STATUS "The following ICU libraries were not found:")
+      foreach(notfound ${ICU_LIBS_NOTFOUND})
+        message(STATUS "  ${notfound}")
+      endforeach()
+    endif()
+  endif()
+
+  if(ICU_DEBUG)
+    message(STATUS "--------FindICU.cmake search debug--------")
+    message(STATUS "ICU binary path search order: ${icu_roots}")
+    message(STATUS "ICU include path search order: ${icu_roots}")
+    message(STATUS "ICU library path search order: ${icu_roots}")
+    message(STATUS "----------------")
+  endif()
+endfunction()
+
+_ICU_FIND()
+
+include(FindPackageHandleStandardArgs)
+FIND_PACKAGE_HANDLE_STANDARD_ARGS(ICU
+                                  FOUND_VAR ICU_FOUND
+                                  REQUIRED_VARS ICU_INCLUDE_DIR
+                                                ICU_LIBRARY
+                                                _ICU_REQUIRED_LIBS_FOUND
+                                  VERSION_VAR ICU_VERSION
+                                  FAIL_MESSAGE "Failed to find all ICU components")
+
+unset(_ICU_REQUIRED_LIBS_FOUND)
+
+if(ICU_FOUND)
+  set(ICU_INCLUDE_DIRS "${ICU_INCLUDE_DIR}")
+  set(ICU_LIBRARIES "${ICU_LIBRARY}")
+  foreach(_ICU_component ${ICU_FIND_COMPONENTS})
+    string(TOUPPER "${_ICU_component}" _ICU_component_upcase)
+    set(_ICU_component_cache "ICU_${_ICU_component_upcase}_LIBRARY")
+    set(_ICU_component_cache_release "ICU_${_ICU_component_upcase}_LIBRARY_RELEASE")
+    set(_ICU_component_cache_debug "ICU_${_ICU_component_upcase}_LIBRARY_DEBUG")
+    set(_ICU_component_lib "ICU_${_ICU_component_upcase}_LIBRARIES")
+    set(_ICU_component_found "${_ICU_component_upcase}_FOUND")
+    set(_ICU_imported_target "ICU::${_ICU_component}")
+    if(${_ICU_component_found})
+      set("${_ICU_component_lib}" "${${_ICU_component_cache}}")
+      if(NOT TARGET ${_ICU_imported_target})
+        add_library(${_ICU_imported_target} UNKNOWN IMPORTED)
+        if(ICU_INCLUDE_DIR)
+          set_target_properties(${_ICU_imported_target} PROPERTIES
+            INTERFACE_INCLUDE_DIRECTORIES "${ICU_INCLUDE_DIR}")
+        endif()
+        if(EXISTS "${${_ICU_component_cache}}")
+          set_target_properties(${_ICU_imported_target} PROPERTIES
+            IMPORTED_LINK_INTERFACE_LANGUAGES "CXX"
+            IMPORTED_LOCATION "${${_ICU_component_cache}}")
+        endif()
+        if(EXISTS "${${_ICU_component_cache_release}}")
+          set_property(TARGET ${_ICU_imported_target} APPEND PROPERTY
+            IMPORTED_CONFIGURATIONS RELEASE)
+          set_target_properties(${_ICU_imported_target} PROPERTIES
+            IMPORTED_LINK_INTERFACE_LANGUAGES_RELEASE "CXX"
+            IMPORTED_LOCATION_RELEASE "${${_ICU_component_cache_release}}")
+        endif()
+        if(EXISTS "${${_ICU_component_cache_debug}}")
+          set_property(TARGET ${_ICU_imported_target} APPEND PROPERTY
+            IMPORTED_CONFIGURATIONS DEBUG)
+          set_target_properties(${_ICU_imported_target} PROPERTIES
+            IMPORTED_LINK_INTERFACE_LANGUAGES_DEBUG "CXX"
+            IMPORTED_LOCATION_DEBUG "${${_ICU_component_cache_debug}}")
+        endif()
+        if(CMAKE_DL_LIBS AND _ICU_component STREQUAL "uc")
+          set_target_properties(${_ICU_imported_target} PROPERTIES
+            INTERFACE_LINK_LIBRARIES "${CMAKE_DL_LIBS}")
+        endif()
+      endif()
+    endif()
+    unset(_ICU_component_upcase)
+    unset(_ICU_component_cache)
+    unset(_ICU_component_lib)
+    unset(_ICU_component_found)
+    unset(_ICU_imported_target)
+  endforeach()
+endif()
+
+if(ICU_DEBUG)
+  message(STATUS "--------FindICU.cmake results debug--------")
+  message(STATUS "ICU found: ${ICU_FOUND}")
+  message(STATUS "ICU_VERSION number: ${ICU_VERSION}")
+  message(STATUS "ICU_ROOT directory: ${ICU_ROOT}")
+  message(STATUS "ICU_INCLUDE_DIR directory: ${ICU_INCLUDE_DIR}")
+  message(STATUS "ICU_LIBRARIES: ${ICU_LIBRARIES}")
+
+  foreach(program IN LISTS icu_programs)
+    string(TOUPPER "${program}" program_upcase)
+    set(program_lib "ICU_${program_upcase}_EXECUTABLE")
+    message(STATUS "${program} program: ${${program_lib}}")
+    unset(program_upcase)
+    unset(program_lib)
+  endforeach()
+
+  foreach(data IN LISTS icu_data)
+    string(TOUPPER "${data}" data_upcase)
+    string(REPLACE "." "_" data_upcase "${data_upcase}")
+    set(data_lib "ICU_${data_upcase}")
+    message(STATUS "${data} data: ${${data_lib}}")
+    unset(data_upcase)
+    unset(data_lib)
+  endforeach()
+
+  foreach(component IN LISTS ICU_FIND_COMPONENTS)
+    string(TOUPPER "${component}" component_upcase)
+    set(component_lib "ICU_${component_upcase}_LIBRARIES")
+    set(component_found "${component_upcase}_FOUND")
+    message(STATUS "${component} library found: ${${component_found}}")
+    message(STATUS "${component} library: ${${component_lib}}")
+    unset(component_upcase)
+    unset(component_lib)
+    unset(component_found)
+  endforeach()
+  message(STATUS "----------------")
+endif()
+
+unset(icu_programs)
diff --git a/cmake/FindLAPACK.cmake b/cmake/FindLAPACK.cmake
new file mode 100644
index 0000000000000000000000000000000000000000..60fbf0726a04491af532db5785b2babf27fe17e9
--- /dev/null
+++ b/cmake/FindLAPACK.cmake
@@ -0,0 +1,430 @@
+# Distributed under the OSI-approved BSD 3-Clause License.  See accompanying
+# file Copyright.txt or https://cmake.org/licensing for details.
+
+#[=======================================================================[.rst:
+FindLAPACK
+----------
+
+Find Linear Algebra PACKage (LAPACK) library
+
+This module finds an installed fortran library that implements the
+LAPACK linear-algebra interface (see http://www.netlib.org/lapack/).
+
+The approach follows that taken for the autoconf macro file,
+``acx_lapack.m4`` (distributed at
+http://ac-archive.sourceforge.net/ac-archive/acx_lapack.html).
+
+Input Variables
+^^^^^^^^^^^^^^^
+
+The following variables may be set to influence this module's behavior:
+
+``BLA_STATIC``
+  if ``ON`` use static linkage
+
+``BLA_VENDOR``
+  If set, checks only the specified vendor, if not set checks all the
+  possibilities.  List of vendors valid in this module:
+
+  * ``Intel10_32`` (intel mkl v10 32 bit)
+  * ``Intel10_64lp`` (intel mkl v10+ 64 bit, threaded code, lp64 model)
+  * ``Intel10_64lp_seq`` (intel mkl v10+ 64 bit, sequential code, lp64 model)
+  * ``Intel10_64ilp`` (intel mkl v10+ 64 bit, threaded code, ilp64 model)
+  * ``Intel10_64ilp_seq`` (intel mkl v10+ 64 bit, sequential code, ilp64 model)
+  * ``Intel`` (obsolete versions of mkl 32 and 64 bit)
+  * ``OpenBLAS``
+  * ``FLAME``
+  * ``ACML``
+  * ``Apple``
+  * ``NAS``
+  * ``Generic``
+
+``BLA_F95``
+  if ``ON`` tries to find BLAS95/LAPACK95
+
+Result Variables
+^^^^^^^^^^^^^^^^
+
+This module defines the following variables:
+
+``LAPACK_FOUND``
+  library implementing the LAPACK interface is found
+``LAPACK_LINKER_FLAGS``
+  uncached list of required linker flags (excluding -l and -L).
+``LAPACK_LIBRARIES``
+  uncached list of libraries (using full path name) to link against
+  to use LAPACK
+``LAPACK95_LIBRARIES``
+  uncached list of libraries (using full path name) to link against
+  to use LAPACK95
+``LAPACK95_FOUND``
+  library implementing the LAPACK95 interface is found
+
+.. note::
+
+  C or CXX must be enabled to use Intel MKL
+
+  For example, to use Intel MKL libraries and/or Intel compiler:
+
+  .. code-block:: cmake
+
+    set(BLA_VENDOR Intel10_64lp)
+    find_package(LAPACK)
+#]=======================================================================]
+
+set(_lapack_ORIG_CMAKE_FIND_LIBRARY_SUFFIXES ${CMAKE_FIND_LIBRARY_SUFFIXES})
+
+# Check the language being used
+if( NOT (CMAKE_C_COMPILER_LOADED OR CMAKE_CXX_COMPILER_LOADED OR CMAKE_Fortran_COMPILER_LOADED) )
+  if(LAPACK_FIND_REQUIRED)
+    message(FATAL_ERROR "FindLAPACK requires Fortran, C, or C++ to be enabled.")
+  else()
+    message(STATUS "Looking for LAPACK... - NOT found (Unsupported languages)")
+    return()
+  endif()
+endif()
+
+if (CMAKE_Fortran_COMPILER_LOADED)
+include(CheckFortranFunctionExists)
+else ()
+include(CheckFunctionExists)
+endif ()
+include(CMakePushCheckState)
+
+cmake_push_check_state()
+set(CMAKE_REQUIRED_QUIET ${LAPACK_FIND_QUIETLY})
+
+set(LAPACK_FOUND FALSE)
+set(LAPACK95_FOUND FALSE)
+
+# TODO: move this stuff to separate module
+
+macro(Check_Lapack_Libraries LIBRARIES _prefix _name _flags _list _blas _threads)
+# This macro checks for the existence of the combination of fortran libraries
+# given by _list.  If the combination is found, this macro checks (using the
+# Check_Fortran_Function_Exists macro) whether can link against that library
+# combination using the name of a routine given by _name using the linker
+# flags given by _flags.  If the combination of libraries is found and passes
+# the link test, LIBRARIES is set to the list of complete library paths that
+# have been found.  Otherwise, LIBRARIES is set to FALSE.
+
+# N.B. _prefix is the prefix applied to the names of all cached variables that
+# are generated internally and marked advanced by this macro.
+
+set(_libraries_work TRUE)
+set(${LIBRARIES})
+set(_combined_name)
+if (NOT _libdir)
+  if (WIN32)
+    set(_libdir ENV LIB)
+  elseif (APPLE)
+    set(_libdir ENV DYLD_LIBRARY_PATH)
+  else ()
+    set(_libdir ENV LD_LIBRARY_PATH)
+  endif ()
+endif ()
+
+list(APPEND _libdir "${CMAKE_C_IMPLICIT_LINK_DIRECTORIES}")
+
+foreach(_library ${_list})
+  set(_combined_name ${_combined_name}_${_library})
+
+  if(_libraries_work)
+    if (BLA_STATIC)
+      if (WIN32)
+        set(CMAKE_FIND_LIBRARY_SUFFIXES .lib ${CMAKE_FIND_LIBRARY_SUFFIXES})
+      endif ()
+      if (APPLE)
+        set(CMAKE_FIND_LIBRARY_SUFFIXES .lib ${CMAKE_FIND_LIBRARY_SUFFIXES})
+      else ()
+        set(CMAKE_FIND_LIBRARY_SUFFIXES .a ${CMAKE_FIND_LIBRARY_SUFFIXES})
+      endif ()
+    else ()
+      if (CMAKE_SYSTEM_NAME STREQUAL "Linux")
+        # for ubuntu's libblas3gf and liblapack3gf packages
+        set(CMAKE_FIND_LIBRARY_SUFFIXES ${CMAKE_FIND_LIBRARY_SUFFIXES} .so.3gf)
+      endif ()
+    endif ()
+    find_library(${_prefix}_${_library}_LIBRARY
+      NAMES ${_library}
+      PATHS ${_libdir}
+      )
+    mark_as_advanced(${_prefix}_${_library}_LIBRARY)
+    set(${LIBRARIES} ${${LIBRARIES}} ${${_prefix}_${_library}_LIBRARY})
+    set(_libraries_work ${${_prefix}_${_library}_LIBRARY})
+  endif()
+endforeach()
+
+if(_libraries_work)
+  # Test this combination of libraries.
+  if(UNIX AND BLA_STATIC)
+    set(CMAKE_REQUIRED_LIBRARIES ${_flags} "-Wl,--start-group" ${${LIBRARIES}} ${_blas} "-Wl,--end-group" ${_threads})
+  else()
+    set(CMAKE_REQUIRED_LIBRARIES ${_flags} ${${LIBRARIES}} ${_blas} ${_threads})
+  endif()
+#  message("DEBUG: CMAKE_REQUIRED_LIBRARIES = ${CMAKE_REQUIRED_LIBRARIES}")
+  if (NOT CMAKE_Fortran_COMPILER_LOADED)
+    check_function_exists("${_name}_" ${_prefix}${_combined_name}_WORKS)
+  else ()
+    check_fortran_function_exists(${_name} ${_prefix}${_combined_name}_WORKS)
+  endif ()
+  set(CMAKE_REQUIRED_LIBRARIES)
+  set(_libraries_work ${${_prefix}${_combined_name}_WORKS})
+  #message("DEBUG: ${LIBRARIES} = ${${LIBRARIES}}")
+endif()
+
+if(_libraries_work)
+  set(${LIBRARIES} ${${LIBRARIES}} ${_blas} ${_threads})
+else()
+  set(${LIBRARIES} FALSE)
+endif()
+
+endmacro()
+
+
+set(LAPACK_LINKER_FLAGS)
+set(LAPACK_LIBRARIES)
+set(LAPACK95_LIBRARIES)
+
+
+if(LAPACK_FIND_QUIETLY OR NOT LAPACK_FIND_REQUIRED)
+  find_package(BLAS)
+else()
+  find_package(BLAS REQUIRED)
+endif()
+
+
+if(BLAS_FOUND)
+  set(LAPACK_LINKER_FLAGS ${BLAS_LINKER_FLAGS})
+  if (NOT $ENV{BLA_VENDOR} STREQUAL "")
+    set(BLA_VENDOR $ENV{BLA_VENDOR})
+  else ()
+    if(NOT BLA_VENDOR)
+      set(BLA_VENDOR "All")
+    endif()
+  endif ()
+
+#intel lapack
+if (BLA_VENDOR MATCHES "Intel" OR BLA_VENDOR STREQUAL "All")
+  if (NOT WIN32)
+    set(LAPACK_mkl_LM "-lm")
+    set(LAPACK_mkl_LDL "-ldl")
+  endif ()
+  if (CMAKE_C_COMPILER_LOADED OR CMAKE_CXX_COMPILER_LOADED)
+    if(LAPACK_FIND_QUIETLY OR NOT LAPACK_FIND_REQUIRED)
+      find_PACKAGE(Threads)
+    else()
+      find_package(Threads REQUIRED)
+    endif()
+
+    if (BLA_VENDOR MATCHES "_64ilp")
+      set(LAPACK_mkl_ILP_MODE "ilp64")
+    else ()
+      set(LAPACK_mkl_ILP_MODE "lp64")
+    endif ()
+
+    set(LAPACK_SEARCH_LIBS "")
+
+    if (BLA_F95)
+      set(LAPACK_mkl_SEARCH_SYMBOL "cheev_f95")
+      set(_LIBRARIES LAPACK95_LIBRARIES)
+      set(_BLAS_LIBRARIES ${BLAS95_LIBRARIES})
+
+      # old
+      list(APPEND LAPACK_SEARCH_LIBS
+        "mkl_lapack95")
+      # new >= 10.3
+      list(APPEND LAPACK_SEARCH_LIBS
+        "mkl_intel_c")
+      list(APPEND LAPACK_SEARCH_LIBS
+        "mkl_lapack95_${LAPACK_mkl_ILP_MODE}")
+    else()
+      set(LAPACK_mkl_SEARCH_SYMBOL "cheev")
+      set(_LIBRARIES LAPACK_LIBRARIES)
+      set(_BLAS_LIBRARIES ${BLAS_LIBRARIES})
+
+      # old
+      list(APPEND LAPACK_SEARCH_LIBS
+        "mkl_lapack")
+    endif()
+
+    # First try empty lapack libs
+    if (NOT ${_LIBRARIES})
+      check_lapack_libraries(
+        ${_LIBRARIES}
+        LAPACK
+        ${LAPACK_mkl_SEARCH_SYMBOL}
+        ""
+        ""
+        "${_BLAS_LIBRARIES}"
+        ""
+        )
+    endif ()
+    # Then try the search libs
+    foreach (IT ${LAPACK_SEARCH_LIBS})
+      if (NOT ${_LIBRARIES})
+        check_lapack_libraries(
+          ${_LIBRARIES}
+          LAPACK
+          ${LAPACK_mkl_SEARCH_SYMBOL}
+          ""
+          "${IT}"
+          "${_BLAS_LIBRARIES}"
+          "${CMAKE_THREAD_LIBS_INIT};${LAPACK_mkl_LM};${LAPACK_mkl_LDL}"
+          )
+      endif ()
+    endforeach ()
+
+    unset(LAPACK_mkl_ILP_MODE)
+    unset(LAPACK_mkl_SEARCH_SYMBOL)
+    unset(LAPACK_mkl_LM)
+    unset(LAPACK_mkl_LDL)
+  endif ()
+endif()
+
+if (BLA_VENDOR STREQUAL "Goto" OR BLA_VENDOR STREQUAL "All")
+ if(NOT LAPACK_LIBRARIES)
+  check_lapack_libraries(
+  LAPACK_LIBRARIES
+  LAPACK
+  cheev
+  ""
+  "goto2"
+  "${BLAS_LIBRARIES}"
+  ""
+  )
+ endif()
+endif ()
+
+if (BLA_VENDOR STREQUAL "OpenBLAS" OR BLA_VENDOR STREQUAL "All")
+ if(NOT LAPACK_LIBRARIES)
+  check_lapack_libraries(
+  LAPACK_LIBRARIES
+  LAPACK
+  cheev
+  ""
+  "openblas"
+  "${BLAS_LIBRARIES}"
+  ""
+  )
+ endif()
+endif ()
+
+if (BLA_VENDOR STREQUAL "FLAME" OR BLA_VENDOR STREQUAL "All")
+ if(NOT LAPACK_LIBRARIES)
+  check_lapack_libraries(
+  LAPACK_LIBRARIES
+  LAPACK
+  cheev
+  ""
+  "flame"
+  "${BLAS_LIBRARIES}"
+  ""
+  )
+ endif()
+endif ()
+
+#acml lapack
+if (BLA_VENDOR MATCHES "ACML" OR BLA_VENDOR STREQUAL "All")
+  if (BLAS_LIBRARIES MATCHES ".+acml.+")
+    set (LAPACK_LIBRARIES ${BLAS_LIBRARIES})
+  endif ()
+endif ()
+
+# Apple LAPACK library?
+if (BLA_VENDOR STREQUAL "Apple" OR BLA_VENDOR STREQUAL "All")
+  if(NOT LAPACK_LIBRARIES)
+    check_lapack_libraries(
+    LAPACK_LIBRARIES
+    LAPACK
+    cheev
+    ""
+    "Accelerate"
+    "${BLAS_LIBRARIES}"
+    ""
+    )
+  endif()
+endif ()
+if (BLA_VENDOR STREQUAL "NAS" OR BLA_VENDOR STREQUAL "All")
+  if ( NOT LAPACK_LIBRARIES )
+    check_lapack_libraries(
+    LAPACK_LIBRARIES
+    LAPACK
+    cheev
+    ""
+    "vecLib"
+    "${BLAS_LIBRARIES}"
+    ""
+    )
+  endif ()
+endif ()
+# Generic LAPACK library?
+if (BLA_VENDOR STREQUAL "Generic" OR
+    BLA_VENDOR STREQUAL "ATLAS" OR
+    BLA_VENDOR STREQUAL "All")
+  if ( NOT LAPACK_LIBRARIES )
+    check_lapack_libraries(
+    LAPACK_LIBRARIES
+    LAPACK
+    cheev
+    ""
+    "lapack"
+    "${BLAS_LIBRARIES}"
+    ""
+    )
+  endif ()
+endif ()
+
+else()
+  message(STATUS "LAPACK requires BLAS")
+endif()
+
+if(BLA_F95)
+  if(LAPACK95_LIBRARIES)
+    set(LAPACK95_FOUND TRUE)
+  else()
+    set(LAPACK95_FOUND FALSE)
+  endif()
+  if(NOT LAPACK_FIND_QUIETLY)
+    if(LAPACK95_FOUND)
+      message(STATUS "A library with LAPACK95 API found.")
+    else()
+      if(LAPACK_FIND_REQUIRED)
+        message(FATAL_ERROR
+        "A required library with LAPACK95 API not found. Please specify library location."
+        )
+      else()
+        message(STATUS
+        "A library with LAPACK95 API not found. Please specify library location."
+        )
+      endif()
+    endif()
+  endif()
+  set(LAPACK_FOUND "${LAPACK95_FOUND}")
+  set(LAPACK_LIBRARIES "${LAPACK95_LIBRARIES}")
+else()
+  if(LAPACK_LIBRARIES)
+    set(LAPACK_FOUND TRUE)
+  else()
+    set(LAPACK_FOUND FALSE)
+  endif()
+
+  if(NOT LAPACK_FIND_QUIETLY)
+    if(LAPACK_FOUND)
+      message(STATUS "A library with LAPACK API found.")
+    else()
+      if(LAPACK_FIND_REQUIRED)
+        message(FATAL_ERROR
+        "A required library with LAPACK API not found. Please specify library location."
+        )
+      else()
+        message(STATUS
+        "A library with LAPACK API not found. Please specify library location."
+        )
+      endif()
+    endif()
+  endif()
+endif()
+
+cmake_pop_check_state()
+set(CMAKE_FIND_LIBRARY_SUFFIXES ${_lapack_ORIG_CMAKE_FIND_LIBRARY_SUFFIXES})
diff --git a/cmake/FindNvToolExt.cmake b/cmake/FindNvToolExt.cmake
new file mode 100644
index 0000000000000000000000000000000000000000..5f2998e442a412227c35f99bc3ebc5472fe878b9
--- /dev/null
+++ b/cmake/FindNvToolExt.cmake
@@ -0,0 +1,35 @@
+# The following variables are optionally searched for defaults
+#  NvToolExt_ROOT_DIR:
+#
+# The following are set after configuration is done:
+#  NvToolExt_FOUND
+#  NvToolExt_INCLUDE_DIR
+#  NvToolExt_LIBRARIES
+#  NvToolExt_LIBRARY_DIR
+#  NvToolExt:                   a target
+
+include(FindPackageHandleStandardArgs)
+
+set(NvToolExt_SEARCH_DIRS ${CUDA_TOOLKIT_ROOT_DIR})
+if(WIN32)
+    list(APPEND NvToolExt_SEARCH_DIRS "C:/Program Files/NVIDIA Corporation/NvToolsExt")
+endif()
+set(NvToolExt_SEARCH_DIRS ${NvToolExt_ROOT_DIR} ${NvToolExt_SEARCH_DIRS})
+
+
+find_path(NvToolExt_INCLUDE_DIR nvToolsExt.h HINTS ${NvToolExt_SEARCH_DIRS} PATH_SUFFIXES include)
+
+# 32bit not considered
+set(NvToolExt_LIBNAME nvToolsExt libnvToolsExt.so libnvToolsExt.a libnvToolsExt.so nvToolsExt64_1.lib)
+find_library(NvToolExt_LIBRARIES NAMES ${NvToolExt_LIBNAME} HINTS ${NvToolExt_SEARCH_DIRS}
+    PATH_SUFFIXES lib lib64 cuda/lib cuda/lib64 lib/x64)
+
+find_package_handle_standard_args(NvToolExt REQUIRED_VARS NvToolExt_INCLUDE_DIR NvToolExt_LIBRARIES)
+
+add_library(NvToolExt INTERFACE)
+target_include_directories(NvToolExt INTERFACE ${NvToolExt_INCLUDE_DIR})
+# target_link_directories(NvToolExt INTERFACE ${NvToolExt_INCLUDE_DIR})
+target_link_libraries(NvToolExt INTERFACE ${NvToolExt_LIBRARIES})
+
+unset(NvToolExt_SEARCH_DIRS)
+unset(NvToolExt_LIBNAME)
diff --git a/cmake/INSTALL.md b/cmake/INSTALL.md
new file mode 100644
index 0000000000000000000000000000000000000000..0082212eb9b9938154e29d9c1aedf5c5fe2a3a55
--- /dev/null
+++ b/cmake/INSTALL.md
@@ -0,0 +1,49 @@
+# Install Instruction
+
+Execute following commands in the repo root.
+
+## Build with Old Style Make Generator
+```bash
+mkdir -p build && cd build
+cmake -DCMAKE_INSTALL_PREFIX=../dist .. # configure
+cmake --build . --target install -- -j8 # build && install, substitude -j8 with /m:8 if you are on Windows
+```
+
+## Build with Ninja Generator
+``` bash
+mkdir -p build && cd build
+cmake -GNinja -DCMAKE_INSTALL_PREFIX=../dist ..
+cmake --build . --target install
+```
+
+After built, you can find all installed files in <your_repo_root>/dist
+
+# For Advance Configuration
+
+Follow options are currently available:
+
+| Variable               | Available Options         | Default  |
+| ---------------------- | ------------------------- | -------- |
+| MATHLIB                | OpenBLAS, MKL, Accelerate | OpenBLAS |
+| KALDI_BUILD_EXE        | ON,OFF                    | ON |
+| KALDI_BUILD_TEST       | ON,OFF                    | ON |
+| KALDI_USE_PATCH_NUMBER | ON,OFF                    | OFF |
+| BUILD_SHARED_LIBS      | ON,OFF                    | OFF |
+
+Append `-D<Variable>=<Value>` to the configure command to use it, e.g.,
+`-DKALDI_BUILD_TEST=OFF` will disable building of test executables. For more
+information, please refers to
+[CMake Documentation](https://cmake.org/cmake/help/latest/manual/cmake.1.html).
+For quick learning CMake usage, LLVM's short introuction will do the trick:
+[Basic CMake usage](https://llvm.org/docs/CMake.html#usage),
+[Options and variables](https://llvm.org/docs/CMake.html#options-and-variables),
+[Frequently-used CMake variables](https://llvm.org/docs/CMake.html#frequently-used-cmake-variables).
+
+NOTE 1: Currently, BUILD_SHARED_LIBS does not work on Windows due to some symbols
+        (variables) are not properly exported.
+
+NOTE 2: For scripts users, since you are doing an out of source build, and the
+        install destination is at your disposal, the `$PATH` is not configured
+        properly in this case. Scripts will not work out of box. See how `$PATH`
+        is modified in [path.sh](../egs/wsj/s5/path.sh). You should add
+        `<installation_path>/bin` to your `$PATH` before running any scripts.
diff --git a/cmake/Utils.cmake b/cmake/Utils.cmake
new file mode 100644
index 0000000000000000000000000000000000000000..88dbefdacc902ef0af095fc2c14b8b6dcb7de651
--- /dev/null
+++ b/cmake/Utils.cmake
@@ -0,0 +1,46 @@
+if(NOT CMAKE_VERSION VERSION_LESS "3.10")
+    include_guard()
+endif()
+
+# For Windows, some env or vars are using backward slash for pathes, convert
+# them to forward slashes will fix some nasty problem in CMake.
+macro(normalize_path in_path)
+    file(TO_CMAKE_PATH "${${in_path}}" normalize_path_out_path)
+    set(${in_path} "${normalize_path_out_path}")
+    unset(normalize_path_out_path)
+endmacro()
+
+macro(normalize_env_path in_path)
+    file(TO_CMAKE_PATH "$${in_path}" normalize_env_path_out_path)
+    set(${in_path} "${normalize_env_path_out_path}")
+    unset(normalize_env_path_out_path)
+endmacro()
+
+
+macro(add_kaldi_executable)
+    if(${KALDI_BUILD_EXE})
+        cmake_parse_arguments(kaldi_exe "" "NAME" "SOURCES;DEPENDS" ${ARGN})
+        add_executable(${kaldi_exe_NAME} ${kaldi_exe_SOURCES})
+        target_link_libraries(${kaldi_exe_NAME} PRIVATE ${kaldi_exe_DEPENDS})
+        # list(APPEND KALDI_EXECUTABLES ${kaldi_exe_NAME})
+        install(TARGETS ${kaldi_exe_NAME} RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR})
+
+        unset(kaldi_exe_NAME)
+        unset(kaldi_exe_SOURCES)
+        unset(kaldi_exe_DEPENDS)
+    endif()
+endmacro()
+
+macro(add_kaldi_test_executable)
+    if(${KALDI_BUILD_TEST})
+        cmake_parse_arguments(kaldi_test_exe "" "NAME" "SOURCES;DEPENDS" ${ARGN})
+        add_executable(${kaldi_test_exe_NAME} ${kaldi_test_exe_SOURCES})
+        target_link_libraries(${kaldi_test_exe_NAME} PRIVATE ${kaldi_test_exe_DEPENDS})
+        # list(APPEND KALDI_TEST_EXECUTABLES ${kaldi_test_exe_NAME})
+        install(TARGETS ${kaldi_test_exe_NAME} RUNTIME DESTINATION testbin)
+
+        unset(kaldi_test_exe_NAME)
+        unset(kaldi_test_exe_SOURCES)
+        unset(kaldi_test_exe_DEPENDS)
+    endif()
+endmacro()
diff --git a/cmake/VersionHelper.cmake b/cmake/VersionHelper.cmake
new file mode 100644
index 0000000000000000000000000000000000000000..e494a2556633b9e97318e2da77e5a7ec5d42c0c3
--- /dev/null
+++ b/cmake/VersionHelper.cmake
@@ -0,0 +1,14 @@
+function(get_version)
+    file(READ ${CMAKE_CURRENT_SOURCE_DIR}/src/.version version)
+    string(STRIP ${version} version)
+    execute_process(COMMAND git log -n1 --format=%H src/.version
+                    WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}
+                    OUTPUT_VARIABLE version_commit
+                    OUTPUT_STRIP_TRAILING_WHITESPACE)
+    execute_process(COMMAND git rev-list --count "${version_commit}..HEAD"
+                    WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}
+                    OUTPUT_VARIABLE patch_number)
+
+    set(KALDI_VERSION ${version} PARENT_SCOPE)
+    set(KALDI_PATCH_NUMBER ${patch_number} PARENT_SCOPE)
+endfunction()
diff --git a/cmake/gen_cmake_skeleton.py b/cmake/gen_cmake_skeleton.py
new file mode 100644
index 0000000000000000000000000000000000000000..fa5069436623273fd4c910fdd50a8210a40a5ff0
--- /dev/null
+++ b/cmake/gen_cmake_skeleton.py
@@ -0,0 +1,310 @@
+import os
+import sys
+import re
+import argparse
+
+# earily parse, will refernece args globally
+parser = argparse.ArgumentParser()
+parser.add_argument("working_dir")
+parser.add_argument("--quiet", default=False, action="store_true")
+args = parser.parse_args()
+
+def print_wrapper(*args_, **kwargs):
+    if not args.quiet:
+        print(*args_, **kwargs)
+
+def get_subdirectories(d):
+    return [name for name in os.listdir(d) if os.path.isdir(os.path.join(d, name))]
+
+def is_bin_dir(d):
+    return d.endswith("bin")
+
+def get_files(d):
+    return [name for name in os.listdir(d) if os.path.isfile(os.path.join(d, name))]
+
+def is_header(f):
+    return f.endswith(".h")
+
+def is_cu_source(f):
+    return f.endswith(".cu")
+
+def is_test_source(f):
+    return f.endswith("-test.cc")
+
+def is_source(f):
+    return f.endswith(".cc") and not is_test_source(f)
+
+def dir_name_to_lib_target(dir_name):
+    return "kaldi-" + dir_name
+
+def wrap_notwin32_condition(should_wrap, lines):
+    if isinstance(lines, str):
+        lines = [lines]
+    if should_wrap:
+        return ["if(NOT WIN32)"] + list(map(lambda l: "    " + l, lines)) + ["endif()"]
+    else:
+        return lines
+
+
+def get_exe_additional_depends(t):
+    additional = {
+        "transform-feats" : ["transform"],
+        "interpolate-pitch" : ["transform"],
+        "post-to-feats" : ["hmm"],
+        "append-post-to-feats" : ["hmm"],
+        "gmm-est-fmllr-gpost": ["sgmm2", "hmm"],
+        "gmm-est-fmllr": ["hmm", "transform"],
+        "gmm-latgen-faster": ["decoder"],
+        "gmm-transform-means": ["hmm"],
+        "gmm-post-to-gpost": ["hmm"],
+        "gmm-init-lvtln": ["transform"],
+        "gmm-rescore-lattice": ["hmm", "lat"],
+        "gmm-est-fmllr-global": ["transform"],
+        "gmm-copy": ["hmm"],
+        "gmm-train-lvtln-special": ["transform", "hmm"],
+        "gmm-est-map": ["hmm"],
+        "gmm-acc-stats2": ["hmm"],
+        "gmm-decode-faster-regtree-mllr": ["decoder"],
+        "gmm-global-est-fmllr": ["transform"],
+        "gmm-est-basis-fmllr": ["hmm", "transform"],
+        "gmm-init-model": ["hmm"],
+        "gmm-est-weights-ebw": ["hmm"],
+        "gmm-init-biphone": ["hmm"],
+        "gmm-compute-likes": ["hmm"],
+        "gmm-est-fmllr-raw-gpost": ["hmm", "transform"],
+        # gmm-* is a bottom case, it will add link dependencies to all other
+        # target whose names start with gmm-, it is harmless, but will increase
+        # link time. Better to avoid it at best.
+        "gmm-*": ["hmm", "transform", "lat", "decoder"],
+    }
+    if t in additional:
+        return list(map(lambda name: dir_name_to_lib_target(name), additional[t]))
+    elif (t.split("-", 1)[0] + "-*") in additional:
+        wildcard = (t.split("-", 1)[0] + "-*")
+        return list(map(lambda name: dir_name_to_lib_target(name), additional[wildcard]))
+    else:
+        return []
+
+def disable_for_win32(t):
+    disabled = [
+        "online-audio-client",
+        "online-net-client",
+        "online2-tcp-nnet3-decode-faster",
+        "online-server-gmm-decode-faster",
+        "online-audio-server-decode-faster"
+    ]
+    return t in disabled
+
+class CMakeListsHeaderLibrary(object):
+    def __init__(self, dir_name):
+        self.dir_name = dir_name
+        self.target_name = dir_name_to_lib_target(self.dir_name)
+        self.header_list = []
+
+    def add_header(self, filename):
+        self.header_list.append(filename)
+
+    def add_source(self, filename):
+        pass
+
+    def add_cuda_source(self, filename):
+        pass
+
+    def add_test_source(self, filename):
+        pass
+
+    def gen_code(self):
+        ret = []
+        if len(self.header_list) > 0:
+            ret.append("set(PUBLIC_HEADERS")
+            for f in self.header_list:
+                ret.append("    " + f)
+            ret.append(")\n")
+
+        ret.append("add_library(" + self.target_name + " INTERFACE)")
+        ret.append("target_include_directories(" + self.target_name + " INTERFACE ")
+        ret.append("     $<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/..>")
+        ret.append("     $<INSTALL_INTERFACE:include/kaldi>")
+        ret.append(")\n")
+
+        ret.append("""
+install(TARGETS {tgt} EXPORT kaldi-targets)
+
+install(FILES ${{PUBLIC_HEADERS}} DESTINATION include/kaldi/{dir})
+""".format(tgt=self.target_name, dir=self.dir_name))
+
+        return "\n".join(ret)
+
+class CMakeListsLibrary(object):
+
+    def __init__(self, dir_name):
+        self.dir_name = dir_name
+        self.target_name = dir_name_to_lib_target(self.dir_name)
+        self.header_list = []
+        self.source_list = []
+        self.cuda_source_list = []
+        self.test_source_list = []
+        self.depends = []
+
+    def add_header(self, filename):
+        self.header_list.append(filename)
+
+    def add_source(self, filename):
+        self.source_list.append(filename)
+
+    def add_cuda_source(self, filename):
+        self.cuda_source_list.append(filename)
+
+    def add_test_source(self, filename):
+        self.test_source_list.append(filename)
+
+    def load_dependency_from_makefile(self, filename):
+        with open(filename) as f:
+            makefile = f.read()
+            if "ADDLIBS" not in makefile:
+                print_wrapper("WARNING: non-standard", filename)
+                return
+            libs = makefile.split("ADDLIBS")[-1].split("\n\n")[0]
+            libs = re.findall("[^\s\\\\=]+", libs)
+            for l in libs:
+                self.depends.append(os.path.splitext(os.path.basename(l))[0])
+
+    def gen_code(self):
+        ret = []
+
+        if len(self.header_list) > 0:
+            ret.append("set(PUBLIC_HEADERS")
+            for f in self.header_list:
+                ret.append("    " + f)
+            ret.append(")\n")
+
+        if len(self.cuda_source_list) > 0:
+            self.source_list.append("${CUDA_OBJS}")
+            ret.append("cuda_include_directories(${CMAKE_CURRENT_SOURCE_DIR}/..)")
+            ret.append("cuda_compile(CUDA_OBJS")
+            for f in self.cuda_source_list:
+                ret.append("    " + f)
+            ret.append(")\n")
+
+        ret.append("add_library(" + self.target_name)
+        for f in self.source_list:
+            ret.append("    " + f)
+        ret.append(")\n")
+        ret.append("target_include_directories(" + self.target_name + " PUBLIC ")
+        ret.append("     $<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/..>")
+        ret.append("     $<INSTALL_INTERFACE:include/kaldi>")
+        ret.append(")\n")
+
+        if len(self.depends) > 0:
+            ret.append("target_link_libraries(" + self.target_name + " PUBLIC")
+            for d in self.depends:
+                ret.append("    " + d)
+            ret.append(")\n")
+
+        def get_test_exe_name(filename):
+            exe_name = os.path.splitext(f)[0]
+            if self.dir_name.startswith("nnet") and exe_name.startswith("nnet"):
+                return self.dir_name + "-" + exe_name.split("-", 1)[1]
+            else:
+                return exe_name
+
+        if len(self.test_source_list) > 0:
+            ret.append("if(KALDI_BUILD_TEST)")
+            for f in self.test_source_list:
+                exe_target = get_test_exe_name(f)
+                depends = (self.target_name + " " + " ".join(get_exe_additional_depends(exe_target))).strip()
+                ret.extend(wrap_notwin32_condition(disable_for_win32(self.target_name),
+                    "    add_kaldi_test_executable(NAME " + exe_target + " SOURCES " + f + " DEPENDS " + depends + ")"))
+            ret.append("endif()")
+
+        ret.append("""
+install(TARGETS {tgt}
+    EXPORT kaldi-targets
+    ARCHIVE DESTINATION ${{CMAKE_INSTALL_LIBDIR}}
+    LIBRARY DESTINATION ${{CMAKE_INSTALL_LIBDIR}}
+    RUNTIME DESTINATION ${{CMAKE_INSTALL_BINDIR}}
+)
+
+install(FILES ${{PUBLIC_HEADERS}} DESTINATION include/kaldi/{dir})
+""".format(tgt=self.target_name, dir=self.dir_name))
+
+        return "\n".join(ret)
+
+
+
+class CMakeListsExecutable(object):
+
+    def __init__(self, dir_name, filename):
+        assert(dir_name.endswith("bin"))
+        self.list = []
+        exe_name = os.path.splitext(os.path.basename(filename))[0]
+        file_name = filename
+        depend = dir_name_to_lib_target(dir_name[:-3])
+        self.list.append((exe_name, file_name, depend))
+
+    def gen_code(self):
+        ret = []
+        for exe_name, file_name, depend in self.list:
+            depends = (depend + " " + " ".join(get_exe_additional_depends(exe_name))).strip()
+            ret.extend(wrap_notwin32_condition(disable_for_win32(exe_name),
+                       "add_kaldi_executable(NAME " + exe_name + " SOURCES " + file_name + " DEPENDS " + depends + ")"))
+
+        return "\n".join(ret)
+
+class CMakeListsFile(object):
+
+    GEN_CMAKE_HEADER = "# generated with cmake/gen_cmake_skeleton.py, DO NOT MODIFY.\n"
+
+    def __init__(self, directory):
+        self.path = os.path.realpath(os.path.join(directory, "CMakeLists.txt"))
+        self.sections = []
+
+    def add_section(self, section):
+        self.sections.append(section)
+
+    def write_file(self):
+        with open(self.path, "w", newline='\n') as f: # good luck for python2
+            f.write(CMakeListsFile.GEN_CMAKE_HEADER)
+            for s in self.sections:
+                code = s.gen_code()
+                f.write(code)
+                f.write("\n")
+        print_wrapper("  Writed", self.path)
+
+
+if __name__ == "__main__":
+    os.chdir(args.working_dir)
+    print_wrapper("Working in ", args.working_dir)
+
+    subdirs = get_subdirectories(".")
+    for d in subdirs:
+        cmakelists = CMakeListsFile(d)
+        if is_bin_dir(d):
+            for f in get_files(d):
+                if is_source(f):
+                    dir_name = os.path.basename(d)
+                    filename = os.path.basename(f)
+                    exe = CMakeListsExecutable(dir_name, filename)
+                    cmakelists.add_section(exe)
+        else:
+            dir_name = os.path.basename(d)
+            lib = None
+            makefile = os.path.join(d, "Makefile")
+            if not os.path.exists(makefile):
+                lib = CMakeListsHeaderLibrary(dir_name)
+            else:
+                lib = CMakeListsLibrary(dir_name)
+                lib.load_dependency_from_makefile(makefile)
+            cmakelists.add_section(lib)
+            for f in sorted(get_files(d)):
+                filename = os.path.basename(f)
+                if is_source(filename):
+                    lib.add_source(filename)
+                elif is_cu_source(filename):
+                    lib.add_cuda_source(filename)
+                elif is_test_source(filename):
+                    lib.add_test_source(filename)
+                elif is_header(filename):
+                    lib.add_header(filename)
+
+        cmakelists.write_file()
diff --git a/cmake/kaldi-config.cmake.in b/cmake/kaldi-config.cmake.in
new file mode 100644
index 0000000000000000000000000000000000000000..123f58c569915e4e197e0031418db595e02b9a5e
--- /dev/null
+++ b/cmake/kaldi-config.cmake.in
@@ -0,0 +1,7 @@
+@PACKAGE_INIT@
+
+find_package(Threads)
+
+if(NOT TARGET kaldi-base)
+    include(${CMAKE_CURRENT_LIST_DIR}/kaldi-targets.cmake)
+endif()
diff --git a/cmake/third_party/get_third_party.cmake b/cmake/third_party/get_third_party.cmake
new file mode 100644
index 0000000000000000000000000000000000000000..8e24dc9f6433dda6e4c1d1ea34e2821a3e515262
--- /dev/null
+++ b/cmake/third_party/get_third_party.cmake
@@ -0,0 +1,20 @@
+# Download and unpack a third-party library at configure time
+# The original code is at the README of google-test:
+# https://github.com/google/googletest/tree/master/googletest
+function(get_third_party name)
+    configure_file(
+        "${PROJECT_SOURCE_DIR}/cmake/third_party/${name}.cmake"
+        "${CMAKE_CURRENT_BINARY_DIR}/${name}-download/CMakeLists.txt")
+    execute_process(COMMAND ${CMAKE_COMMAND} -G "${CMAKE_GENERATOR}" .
+        RESULT_VARIABLE result
+        WORKING_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/${name}-download")
+    if(result)
+        message(FATAL_ERROR "CMake step for ${name} failed: ${result}")
+    endif()
+    execute_process(COMMAND ${CMAKE_COMMAND} --build .
+        RESULT_VARIABLE result
+        WORKING_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/${name}-download")
+    if(result)
+        message(FATAL_ERROR "Build step for ${name} failed: ${result}")
+    endif()
+endfunction()
diff --git a/cmake/third_party/openfst.cmake b/cmake/third_party/openfst.cmake
new file mode 100644
index 0000000000000000000000000000000000000000..19a7f527f8f954bfe64d91f626154b84d93eea2b
--- /dev/null
+++ b/cmake/third_party/openfst.cmake
@@ -0,0 +1,14 @@
+cmake_minimum_required(VERSION 2.8.2)
+project(openfst-download NONE)
+
+include(ExternalProject)
+ExternalProject_Add(openfst
+    GIT_REPOSITORY https://github.com/kkm000/openfst
+    GIT_TAG 0bca6e76d24647427356dc242b0adbf3b5f1a8d9 # tag win/1.7.2.1
+    SOURCE_DIR "${CMAKE_BINARY_DIR}/openfst"
+    BINARY_DIR ""
+    CONFIGURE_COMMAND ""
+    BUILD_COMMAND ""
+    INSTALL_COMMAND ""
+    TEST_COMMAND ""
+)
diff --git a/cmake/third_party/openfst_lib_target.cmake b/cmake/third_party/openfst_lib_target.cmake
new file mode 100644
index 0000000000000000000000000000000000000000..dde5efc402a0637041ec41c167fcc3d005837a18
--- /dev/null
+++ b/cmake/third_party/openfst_lib_target.cmake
@@ -0,0 +1,31 @@
+if(NOT OPENFST_ROOT_DIR)
+    message(FATAL_ERROR)
+endif()
+
+set(fst_source_dir ${OPENFST_ROOT_DIR}/src/lib)
+set(fst_include_dir ${OPENFST_ROOT_DIR}/src/include)
+
+include_directories(${fst_include_dir})
+file(GLOB fst_sources "${fst_source_dir}/*.cc")
+
+add_library(fst ${fst_sources})
+target_include_directories(fst PUBLIC
+     $<BUILD_INTERFACE:${fst_include_dir}>
+     $<INSTALL_INTERFACE:include/openfst>
+)
+
+install(TARGETS fst
+    EXPORT kaldi-targets
+    ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR}
+    LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}
+    RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}
+)
+
+install(DIRECTORY ${fst_include_dir}/fst
+    DESTINATION include/openfst
+    PATTERN "test/*.h" EXCLUDE
+)
+
+unset(fst_source_dir)
+unset(fst_include_dir)
+unset(fst_sources)
diff --git a/src/base/kaldi-error.cc b/src/base/kaldi-error.cc
index 2dbc73182098754fe3931496be62873c425e1ed0..12f972ee856308a6360174c47279fb9ce6a7b396 100644
--- a/src/base/kaldi-error.cc
+++ b/src/base/kaldi-error.cc
@@ -33,7 +33,11 @@
 
 #include "base/kaldi-common.h"
 #include "base/kaldi-error.h"
+
+// KALDI_GIT_HEAD is useless currently in full repo
+#if !defined(KALDI_VERSION)
 #include "base/version.h"
+#endif
 
 namespace kaldi {