Repository: SINTEF/dlite (language: python)

Issue:
Ensure that all C source and header files are pure ASCII encoded
It seems that Visual Studio has issues with UTF-8 encoded sources. 

Change the encoding of the following files from UTF-8 to pure ASCII:
- ./examples/ex5d/tc_data_defs.h
- ./src/tests/minunit/minunit.h


Fix failing tests when cross-compiling with MinGW
Added two workarounds
* Copy all DLLs to the dlite Python package in binary dir, such
  that they can be found by the Python tests.
* Strip off initial "Z:" from paths when cross-compiling with MinGW.


Discussion / hints:

Fix patch:
diff --git a/.github/workflows/windows.yml b/.github/workflows/windows.yml
new file mode 100644
index 000000000..f6bc99b5f
--- /dev/null
+++ b/.github/workflows/windows.yml
@@ -0,0 +1,61 @@
+name: Build on Windows
+
+on: [push]
+
+jobs:
+  msvc:
+    name: Build dlite with MS Visual Studio
+    runs-on: ${{ matrix.os }}
+    strategy:
+      matrix:
+        #os: [windows-2019, windows-latest]
+        #python-version: [ '3.8', '3.9' ]
+        os: [windows-2019]
+        python-version: ['3.9']
+
+    steps:
+    - name: Fetch Sources
+      uses: actions/checkout@v2
+
+    - name: Setup Python
+      uses: actions/setup-python@v2
+      with:
+        python-version: ${{ matrix.python-version }}
+
+    - name: Install Python Dependencies
+      run: pip install -r requirements.txt
+
+    - name: Install SWIG
+      uses: crazy-max/ghaction-chocolatey@v1
+      with:
+        args: install swig -y
+
+    - name: Setup cmake
+      uses: jwlawson/actions-setup-cmake@v1.9
+      with:
+        cmake-version: '3.20.x'
+
+    - name: Prepare MSVC
+      uses: bus1/cabuild/action/msdevshell@v1
+
+    - name: Make build folder
+      run: mkdir build
+
+    - name: Check for NumPy
+      run: python -c "import numpy; print(numpy.get_include())"
+
+    - name: Use cmake
+      run: cmake -A x64 -DWITH_DOC=OFF -DWITH_HDF5=OFF -DCMAKE_CONFIGURATION_TYPES:STRING="Release" ..
+      working-directory: build
+
+    - name: Build
+      run: cmake --build . --config Release
+      working-directory: build
+
+    - name: Check dlite config settings
+      run: cmake --build . --config Release --target show
+      working-directory: build
+
+    - name: Test
+      run: ctest -C Release
+      working-directory: build
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 81f566d09..dfe504ce1 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -3,7 +3,7 @@
 cmake_minimum_required(VERSION 3.14)
 
 project(dlite
-  VERSION 0.3.1
+  VERSION 0.3.2
   DESCRIPTION "Lightweight data-centric framework for working with scientific data"
   HOMEPAGE_URL "https://github.com/SINTEF/dlite"
   LANGUAGES C
@@ -56,15 +56,15 @@ DLite is released under the MIT license.
 ")
 
 # Options
-option(WITH_PYTHON      "Whether to build Python 3 bindings"             ON)
-option(WITH_FORTRAN     "Whether to build Fortran bindings"              OFF)
-option(WITH_HDF5        "Whether to build with HDF5 support"             ON)
-option(WITH_JSON        "Whether to build with JSON support"             ON)
-option(WITH_REDLAND     "Whether to build with Redland (if available)"   ON)
-option(WITH_DOC         "Whether to build documentation using doxygen"   ON)
-option(WITH_EXAMPLES    "Whether to build/run examples during testing"   ON)
-option(FORCE_EXAMPLES   "Whether to force building/running examples"     OFF)
-option(ALLOW_WARNINGS   "Whether to not fail on compilation warnings"    OFF)
+option(WITH_PYTHON      "Whether to build Python 3 bindings"                ON)
+option(WITH_FORTRAN     "Whether to build Fortran bindings"                OFF)
+option(WITH_HDF5        "Whether to build with HDF5 support"                ON)
+option(WITH_JSON        "Whether to build with JSON support"                ON)
+option(WITH_REDLAND     "Whether to build with RDF support (using librdf)"  ON)
+option(WITH_DOC         "Whether to build documentation using doxygen"      ON)
+option(WITH_EXAMPLES    "Whether to build/run examples during testing"      ON)
+option(FORCE_EXAMPLES   "Whether to force building/running examples"       OFF)
+option(ALLOW_WARNINGS   "Whether to not fail on compilation warnings"       ON)
 
 
 # Append our cmake-modules to CMAKE_MODULE_PATH
@@ -110,6 +110,15 @@ if(CMAKE_COMPILER_IS_GNUCC AND CMAKE_SYSTEM_NAME STREQUAL "Windows")
   enable_c_compiler_flag_if_supported("-Wno-unknown-pragmas")
 endif()
 
+if(MSVC)
+  # Fix utf-8 handling for MSVC: Force utf-8 encoded source-code files
+  add_compile_options("$<$<C_COMPILER_ID:MSVC>:/utf-8>")
+  add_compile_options("$<$<CXX_COMPILER_ID:MSVC>:/utf-8>")
+
+  # Do not complain about strdup() and similar POSIX functions to be
+  # deprecated in MSVC
+  add_definitions("-D_CRT_NONSTDC_NO_DEPRECATE")
+endif()
 
 # Uncomment the lines below to compile with AddressSanitizer
 #set (CMAKE_C_FLAGS_DEBUG "${CMAKE_C_FLAGS_DEBUG} -fno-omit-frame-pointer -fsanitize=address")
@@ -148,6 +157,7 @@ if(WITH_HDF5)
   list(APPEND DLITE_CONFIG_VARS HDF5_LIBRARIES)
 endif()
 if(WITH_PYTHON)
+  #FIME: Python3_LIBRARIES is undefined here
   list(APPEND DLITE_CONFIG_VARS
     Python3_LIBRARIES
     DLITE_PYTHON_STORAGE_PLUGIN_DIRS
@@ -219,6 +229,7 @@ endif()
 # ======
 if(WITH_PYTHON)
 
+  message(STATUS "Looking for Python3")
   if(CROSS_TARGET AND MINGW)
     set(Python3_FIND_REGISTRY NEVER)
     set(Python3_FIND_STRATEGY LOCATION)
@@ -226,6 +237,8 @@ if(WITH_PYTHON)
   endif()
 
   if(WIN32)
+    set(Python3_FIND_REGISTRY NEVER)
+    set(Python3_FIND_STRATEGY LOCATION)
     set(Python3_USE_STATIC_LIBS TRUE)
   endif()
 
@@ -234,6 +247,26 @@ if(WITH_PYTHON)
   find_package(NumPy REQUIRED)
   unset(CMAKE_CROSSCOMPILING_EMULATOR)
 
+  message(STATUS "Python3_LIBRARIES = ${Python3_LIBRARIES}")
+  message(STATUS "Python3_EXECUTABLE = ${Python3_EXECUTABLE}")
+  message(STATUS "Python3_INCLUDE_DIRS = ${Python3_INCLUDE_DIRS}")
+  message(STATUS "Python3_NumPy_INCLUDE_DIRS = ${Python3_NumPy_INCLUDE_DIRS}")
+  if (WIN32)
+    # Prepare to workaround Anaconda issues on Windows
+    # https://github.com/pytorch/pytorch/issues/17051
+    # https://github.com/ContinuumIO/anaconda-issues/issues/11374
+    include(FindPythonAnaconda)
+    if (PYTHON_IS_ANACONDA)
+      if (PYTHON_IS_ANACONDA_BASE)
+        message(STATUS "Check Anaconda on Windows: Python3 is Anaconda - Root environment.")
+      else()
+        message(STATUS "Check Anaconda on Windows: Python3 is Anaconda - Virtual Environment.")
+      endif()
+    else()
+      message(STATUS "Check Anaconda on Windows: Python3 is NOT Anaconda.")
+    endif()
+  endif()
+
   # On mingw, python depends on libffi
   find_library(ffi ffi)
   mark_as_advanced(ffi)
@@ -349,6 +382,21 @@ endif()
 # Environment for running tests in build tree
 # -------------------------------------------
 
+# Name of all targets that produce a DLL that we have to take special
+# care of on Windows
+set(dll_targets
+  dlite
+  dlite-utils
+  dlite-plugins-json
+  dlite-plugins-python
+  )
+if(WITH_HDF5)
+  list(APPEND targets dlite-plugins-hdf5)
+endif()
+if(WITH_REDLAND)
+  list(APPEND targets dlite-plugins-rdf)
+endif()
+
 # Macro that appends build directories `dirs` to list `lst`
 #
 # Usage: build_append(<var> dirs...)
@@ -379,6 +427,10 @@ if(WIN32)
     build_append(dlite_PATH ${dlite_BINARY_DIR}/src/pyembed)
     list(APPEND dlite_PATH ${Python3_RUNTIME_LIBRARY_DIRS})
     list(APPEND dlite_PATH ${Python3_NumPy_LIBRARY_DIRS})
+    if (WIN32 AND PYTHON_IS_ANACONDA)
+      # Fix dll search path for Anaconda on Windows
+      list(APPEND dlite_PATH "${Python3_RUNTIME_LIBRARY_DIRS}/Library/bin")
+    endif()
   endif()
   if(WITH_FORTRAN)
     build_append(dlite_PATH ${dlite_BINARY_DIR}/bindings/fortran)
@@ -483,7 +535,6 @@ list(REMOVE_DUPLICATES dlite_TEMPLATES)
 # DLITE_STORAGES - DLite storages (inc. metadata)
 set(dlite_STORAGES
   ${dlite_SOURCE_DIR}/examples/storages/*.json
-  ${dlite_SOURCE_DIR}/storages/python/python-storage-plugins/*.json
   )
 list(REMOVE_DUPLICATES dlite_STORAGES)
 
@@ -513,6 +564,49 @@ make_platform_paths(
   #PATHSEP0
   )
 
+# Workaround for cross-compiling for Windows on Linux using MinGW.
+# Some paths in ${dlite_PATH} may start with "Z:/" which the
+# $<SHELL_PATH:...> generator expression complains about being a
+# relative path.  To fix this, we strip off the initial "Z:".
+if(CROSS_TARGET AND MINGW)
+  set(paths "")
+  foreach(path ${dlite_PATH})
+    string(REGEX REPLACE "^[A-Z]:(/.*)" "\\1" out ${path})
+    list(APPEND paths ${out})
+  endforeach()
+  set(dlite_PATH ${paths})
+endif()
+
+#set(dlite_STORAGE_PLUGIN1 "")
+#foreach(path ${dlite_PATH})
+#  list(APPEND dlite_STORAGE_PLUGIN1 $<SHELL_PATH:${path}>)
+#endforeach()
+#if(WIN32)
+#  string(REPLACE ";" "\;" dlite_STORAGE_PLUGIN "${dlite_STORAGE_PLUGIN1}")
+#else()
+#  string(REPLACE ";" ":" dlite_STORAGE_PLUGIN "${dlite_STORAGE_PLUGIN1}")
+#endif()
+#
+#set(dlite_MAPPING_PLUGIN1 "")
+#foreach(path ${dlite_PATH})
+#  list(APPEND dlite_MAPPING_PLUGIN1 $<SHELL_PATH:${path}>)
+#endforeach()
+#if(WIN32)
+#  string(REPLACE ";" "\;" dlite_MAPPING_PLUGIN "${dlite_MAPPING_PLUGIN1}")
+#else()
+#  string(REPLACE ";" ":" dlite_MAPPING_PLUGIN "${dlite_MAPPING_PLUGIN1}")
+#endif()
+
+set(dlite_PATH_NATIVE1 "")
+foreach(path ${dlite_PATH})
+  list(APPEND dlite_PATH_NATIVE1 $<SHELL_PATH:${path}>)
+endforeach()
+if(WIN32)
+  string(REPLACE ";" "\\\\;" dlite_PATH_NATIVE "${dlite_PATH_NATIVE1}")
+else()
+  string(REPLACE ";" ":" dlite_PATH_NATIVE "${dlite_PATH_NATIVE1}")
+endif()
+
 # Note, DLITE_STORAGES uses "|" as separator on all systems
 string(REPLACE ";" "|" dlite_STORAGES         "${dlite_STORAGES}")
 string(REPLACE ";" "|" dlite_STORAGES_NATIVE  "${dlite_STORAGES_NATIVE}")
@@ -523,9 +617,12 @@ string(REPLACE ";" "|" dlite_STORAGES_WINDOWS "${dlite_STORAGES_WINDOWS}")
 # Add target "show" for showing test environment
 set(test_env
   "========== Test environment ========="
+  "export DLITE_ROOT=${DLITE_ROOT}"
   "export PATH=${dlite_PATH}"
+  "dlite_PATH_NATIVE=${dlite_PATH_NATIVE}"
   "export LD_LIBRARY_PATH=${dlite_LD_LIBRARY_PATH}"
   "export PYTHONPATH=${dlite_PYTHONPATH}"
+  "PYTHONPATH_NATIVE=${dlite_PYTHONPATH_NATIVE}"
   "export DLITE_STORAGE_PLUGIN_DIRS=${dlite_STORAGE_PLUGINS}"
   "export DLITE_MAPPING_PLUGIN_DIRS=${dlite_MAPPING_PLUGINS}"
   "export DLITE_PYTHON_STORAGE_PLUGIN_DIRS=${dlite_PYTHON_STORAGE_PLUGINS}"
diff --git a/bindings/python/CMakeLists.txt b/bindings/python/CMakeLists.txt
index 3708bcd7c..03a7cafd1 100644
--- a/bindings/python/CMakeLists.txt
+++ b/bindings/python/CMakeLists.txt
@@ -83,12 +83,21 @@ foreach(source ${py_sources})
   list(APPEND abs_targets ${pkgdir}/${source})
 endforeach()
 
+# On windows, also copy all dlite DLLs to our Python package
+set(dlls)
+if(WINDOWS OR MINGW)
+  foreach(dll_target ${dll_targets})
+    list(APPEND dlls $<TARGET_FILE:${dll_target}>)
+  endforeach()
+endif()
+
 add_custom_command(
   TARGET ${SWIG_MODULE_dlite_REAL_NAME}
   POST_BUILD
   COMMAND ${CMAKE_COMMAND} -E make_directory ${pkgdir}
   COMMAND ${CMAKE_COMMAND} -E copy_if_different
     $<TARGET_FILE:${SWIG_MODULE_dlite_REAL_NAME}>
+    ${dlls}
     ${pkgdir}
   BYPRODUCTS
     ${pkgdir}
diff --git a/bindings/python/__init__.py b/bindings/python/__init__.py
index af807a735..51f7c6806 100644
--- a/bindings/python/__init__.py
+++ b/bindings/python/__init__.py
@@ -1,14 +1,28 @@
 import sys
+import os
 
-# For some reason setting PATH before calling Python, is not enough on
-# Windows for _dlite.pyd to find and load the DLLs it depends on.
-# This bug has also been recognised by the numpy cummunity;
-# https://github.com/numpy/numpy/issues/12667
-#
-# To work around, call AddDllDirectory() directly via ctypes to set the
-# search path on Windows
-if sys.platform == 'win32':
-    import os
+# For Anaconda Python on Windows, it is sufficient to set the PATH before
+# calling Python so that _dlite.pyd can find and load the DLLs it depends on.
+# The dll loading trick below is not working on Anaconda Python
+# https://github.com/pytorch/pytorch/issues/17051
+
+try:
+    import conda
+except:
+    is_conda_base = False
+    is_conda = os.path.exists(os.path.join(sys.prefix, 'conda-meta'))
+else:
+    assert os.path.exists(os.path.join(sys.prefix, 'conda-meta'))
+    is_conda_base = True
+    is_conda = True
+
+if (sys.platform == 'win32') and (not is_conda):
+    # For CPython, setting the PATH is not sufficient on Windows without Anaconda Python.
+    # This may be related to the following bug recognised by the numpy cummunity;
+    # https://github.com/numpy/numpy/issues/12667
+    #
+    # To work around, call AddDllDirectory() directly via ctypes to set the
+    # search path on Windows before importing dlite
     from pathlib import Path
     from ctypes import windll, c_wchar_p
     from ctypes.wintypes import DWORD
diff --git a/bindings/python/dlite-path.i b/bindings/python/dlite-path.i
index 0aed04f5c..358729398 100644
--- a/bindings/python/dlite-path.i
+++ b/bindings/python/dlite-path.i
@@ -54,16 +54,16 @@ Creates a _Path instance of type `pathtype`.
     return fu_paths_string($self);
   }
   int __len__(void) {
-    return $self->n;
+    return (int)$self->n;
   }
   const char *getitem(int index) {
-    if (index < 0) index += $self->n;
+    if (index < 0) index += (int)$self->n;
     if (index < 0 || index >= (int)$self->n)
       return dlite_err(1, "index out of range: %d", index), NULL;
     return $self->paths[index];
   }
   void __setitem__(int index, const char *path) {
-    if (index < 0) index += $self->n;
+    if (index < 0) index += (int)$self->n;
     if (index < 0 || index >= (int)$self->n) {
       dlite_err(1, "index out of range: %d", index);
     } else {
diff --git a/bootstrap-win.sh b/bootstrap-win.sh
deleted file mode 100644
index c808f9af5..000000000
--- a/bootstrap-win.sh
+++ /dev/null
@@ -1,117 +0,0 @@
-#
-# Check and modify the path of the variables below.
-#
-# To play nice with git, leave this file untouched and add your updated
-# variables to bootstrap-win-user.sh
-#
-# Run this script with (tested with git bash)
-#
-#     sh bootstrap-win.sh
-#
-#
-# Init environment variables
-#
-GENERATOR="Visual Studio 15 2017 Win64"
-BUILD_DIR=build-VS
-ROOT_PATH="$(realpath $(pwd)/..)"
-PATH="$CMAKE_PATH:$SWIG_PATH:$MAKE_PROGRAM_PATH:$ROOT_PATH/local/bin:$PATH"
-INSTALL_PREFIX="$ROOT_PATH/local"
-
-CMAKE_PATH="/c/Program Files/CMake/bin/cmake"
-
-WITH_HDF5=OFF
-HDF5_VERSION="1.10.4"
-
-WITH_PYTHON=ON
-SWIG_DIR="$INSTALL_PREFIX/swigwin-4.0.2/Lib"
-SWIG_EXECUTABLE="$INSTALL_PREFIX/swigwin-4.0.2/swig"
-
-SWIG_PATH="$HOME/source/repos/local/swigwin-4.0.1"
-
-
-#
-# Setup the shell
-#
-set -e  # Stop on first error
-set -x  # Print commands as they are executed
-
-
-#
-# You normally don't need to modify the lines below
-# =================================================
-
-#
-# Source user defaults from bootstrap-win-user.sh
-#
-if [ -f bootstrap-win-user.sh ]; then
-    source bootstrap-win-user.sh
-fi
-#
-# Build and install hdf5
-#
-if [ ! "$WITH_HDF5" = OFF ] && [ ! -f $INSTALL_PREFIX/lib/libhdf5.lib ]; then
-    cd $ROOT_PATH
-    if [ ! -d hdf5-$HDF5_VERSION ]; then
-        TARFILE=hdf5-$HDF5_VERSION.tar.gz
-        if [ ! -f $TARFILE ]; then
-            curl https://support.hdfgroup.org/ftp/HDF5/current/src/$TARFILE \
-                 --output $TARFILE
-        fi
-        tar -zxvf $TARFILE
-    fi
-    cd hdf5-$HDF5_VERSION
-    mkdir -p ${BUILD_DIR} && cd ${BUILD_DIR}
-    cmake \
-        -G "$GENERATOR" \
-        -DCMAKE_INSTALL_PREFIX:PATH="$INSTALL_PREFIX" \
-        -DCMAKE_POSITION_INDEPENDENT_CODE=ON \
-        -DBUILD_SHARED_LIBS=OFF \
-        ..
-    cmake --build . --config Debug --target install
-    cmake --build . --config Release --target install
-fi
-
-
-#
-# Configure and generate dlite project
-#
-cd $ROOT_PATH/dlite
-git submodule update --init
-mkdir -p ${BUILD_DIR} && cd ${BUILD_DIR}
-#
-# Set up environment
-config=Release
-export PATH="src/$config:src/utils/$config:$PATH"
-export LD_LIBRARY_PATH="src/$config:src/utils/$config:$LD_LIBRARY_PATH"
-export PYTHONPATH="bindings/python/dlite"
-export DLITE_STORAGE_PLUGIN_DIRS="storages/json/$config:storages/hdf5/$config:storages/python/$config"
-export DLITE_MAPPING_PLUGIN_DIRS="src/pyembed"
-export DLITE_PYTHON_STORAGE_PLUGIN_DIRS="storages/python/python-storage-plugins"
-export DLITE_PYTHON_MAPPING_PLUGIN_DIRS="bindings/python/mapping-plugins"
-export DLITE_TEMPLATE_DIRS="../tools/templates"
-export DLITE_STORAGES="../examples/storages/*.json"
-
-#
-# Build
-cmake \
-    -G "$GENERATOR" \
-    -DCMAKE_INSTALL_PREFIX:PATH="$INSTALL_PREFIX" \
-    -DCMAKE_POSITION_INDEPENDENT_CODE=ON \
-    -DWITH_HDF5=$WITH_HDF5 \
-    -DHDF5_DIR="$INSTALL_PREFIX/cmake/hdf5" \
-    -DHDF5_ROOT="$INSTALL_PREFIX" \
-    -DWITH_PYTHON=$WITH_PYTHON \
-    -DSWIG_DIR="$SWIG_DIR" \
-    -DSWIG_EXECUTABLE="$SWIG_EXECUTABLE" \
-    ..
-cmake --build . --config $config
-
-# Build in Debug mode doesn't work since we then will try to link to
-# python37_d.lib which doesn't exists
-#cmake --build . --config Debug
-
-
-#
-# Tests
-#
-ctest
diff --git a/cmake/FindNumPy.cmake b/cmake/FindNumPy.cmake
index 4a8ef95ff..a3e52855f 100644
--- a/cmake/FindNumPy.cmake
+++ b/cmake/FindNumPy.cmake
@@ -27,11 +27,8 @@ import os
 from pathlib import Path
 import numpy as np
 
-def basepath(path):
-    return Path(os.path.splitdrive(path)[1])
-
-incdir = basepath(np.get_include())
-coredir = basepath(np.__file__).parent / 'core'
+incdir = Path(np.get_include())
+coredir = Path(np.__file__).parent / 'core'
 
 print(np.version.version)
 print(incdir.as_posix())
diff --git a/cmake/FindPythonAnaconda.cmake b/cmake/FindPythonAnaconda.cmake
new file mode 100644
index 000000000..d86c6ce0e
--- /dev/null
+++ b/cmake/FindPythonAnaconda.cmake
@@ -0,0 +1,44 @@
+cmake_minimum_required(VERSION 3.7)
+# - Check if we are running anaconda python
+#   https://stackoverflow.com/questions/47608532/how-to-detect-from-within-python-whether-packages-are-managed-with-conda
+#
+# We assume that you include
+#
+#  include(FindPythonAnaconda)
+#
+# Once done this will define
+#
+#  PYTHON_IS_ANACONDA      - True in case we are running anaconda Python
+#  PYTHON_IS_ANACONDA_BASE - True in case we are running anaconda Python and are using the base environment
+#
+
+  set(script "
+import sys, os
+try:
+  import conda
+except:
+  is_conda_base = False
+  is_conda = os.path.exists(os.path.join(sys.prefix, 'conda-meta'))
+else:
+  assert os.path.exists(os.path.join(sys.prefix, 'conda-meta'))
+  is_conda_base = True
+  is_conda = True
+
+print(is_conda_base)
+print(is_conda)
+")
+
+  execute_process(
+    COMMAND ${RUNNER} "${Python3_EXECUTABLE}" -c "${script}"
+    RESULT_VARIABLE Python_is_anaconda_retval
+    OUTPUT_VARIABLE Python_is_anaconda_output
+    ERROR_VARIABLE Python_is_anaconda_error
+    )
+
+  if(${Python_is_anaconda_retval})
+    message(${Python_is_anaconda_error})
+  else()
+    string(REPLACE "\n" ";" lst ${Python_is_anaconda_output})
+    list(GET lst 0 PYTHON_IS_ANACONDA_BASE)
+    list(GET lst 1 PYTHON_IS_ANACONDA)
+  endif()
\ No newline at end of file
diff --git a/cmake/MakePlatformPaths.cmake b/cmake/MakePlatformPaths.cmake
index 9b178db91..9d30e8b8c 100644
--- a/cmake/MakePlatformPaths.cmake
+++ b/cmake/MakePlatformPaths.cmake
@@ -66,8 +66,7 @@ function(make_platform_paths)
     foreach(path ${${var}})
       file(TO_CMAKE_PATH path "${path}")
       list(APPEND ${var}_UNIX "${path}")
-
-      string(REGEX REPLACE "/([a-zA-Z])/" "\\1:\\\\" path "${path}")
+      string(REGEX REPLACE "^/([a-zA-Z])/" "\\1:\\\\" path "${path}") # /C/other/sub -> C:\other/sub
       string(REPLACE "/" "${win_dirsep}" path "${path}")
       list(APPEND ${var}_WINDOWS "${path}")
     endforeach()
diff --git a/doc/build-with-vs.md b/doc/build-with-vs.md
index 7db64d9f3..2167121da 100644
--- a/doc/build-with-vs.md
+++ b/doc/build-with-vs.md
@@ -1,77 +1,107 @@
 Build with Visual Studio
 ========================
 
-1. Install a recent version of [CMake][cmake]
-2. Install Visual Studio 14 2015 or Visual Studio 15 2017 with the
-   C/C++ components
-
-3. Prepare a directory structure for DLite and 3rd party libraries:
-
-     1. Select a root folder to create the directory structure. Ex:
-
-            "C:\Users\{username}\Documents\"
-
-     2. Create the following directory:
-
-            {root}\local
-
-     3. Clone the DLite repository in the root folder, creating the folder
-
-            {root}\dlite
-
-4. Download hdf5 library archive from
-   [https://support.hdfgroup.org/ftp/HDF5/current/src/][hdf5]
-
-5. Copy of the file
-
-            {root}\dlite\bootstrap-win.sh
-
-   into the root folder and edit it as follows:
-
-	1. Modify the variable CMAKE_PATH to the path of cmake directory
-	2. Modify the variable ROOT_PATH to your root folder
-	3. Modify the variable PYTHON_EXECUTABLE to Python version 3.x
-	   executable
-	4. Check the version number of hdf5 library
-    5. To build in Win64 mode, add '-G "Visual Studio 15 Win64"' after
-       cmake command when generating the solution (not building)
-
-6. Open a git-bash window:
-	1. Change the directory to your root folder
-	2. Type `sh bootstrap-win.sh` and press enter
-
-7. Open the file
-
-            {root}\dlite\build\dlite.sln
-
-   in Visual Studio
-
-8. In Visual Studio:
-
-    1. Select the solution configuration "Debug", then build the
-       solution (Menu Build -> Build solution)
-    2. Select the solution configuration "Release", then build the
-       solution (Menu Build -> Build solution)
-
-To run the tests, do
-
-    ctest -C Debug
-
-
-Summary to build and install DLite when hdf5 lib are installed
-in the given path LOCAL_DIR
-
-    LOCAL_DIR=/C/Users/tco/Documents/Programs/philib/local
-    PATH=$PATH:$LOCAL_DIR/bin
-    cd dlite
-    mkdir build && cd build
-    cmake -G "Visual Studio 14 2015 Win64" -DHDF5_DIR=$LOCAL_DIR/cmake/hdf5 -DCMAKE_INSTALL_PREFIX=$LOCAL_DIR/ ..
-    cmake --build . --config Debug --target doc
-    cmake --build . --config Debug --target install
-    cmake --build . --config Release --target install
-    ctest -C Debug
-    ctest -C Release
-
-
+1. Install "Visual Studio 14 2015", "Visual Studio 15 2017" or "Visual Studio 16 2019" with the
+   C/C++ components and cmake.
+
+   In case you want Python-bindings, make sure to use a "Visual Studio" version
+   that generates dlite-libraries which are compatible to the Python version you are using.
+   For Python>=3.5, any of the above versions will work: See [mscompilers] for a discussion on
+   binary compatibilty between Visual Studio compiler versions. For older versions of Python see
+   the correct versions here: [pythonwindows].
+
+   In the examples below, we use "Visual Studio 15 2017" which is the compiler version with which
+   Python>=3.7 is build on Windows.
+
+2. (Optional) Install SWIG in case you want to build Python-bindings as described
+   here [swig]. Add the swig-executable to your windows PATH
+
+3. (Optional) Check versions
+
+   $ swig -version
+     SWIG Version 4.0.2
+     Compiled with i686-w64-mingw32-g++ [i686-w64-mingw32]
+     Configured options: +pcre
+     Please see http://www.swig.org for reporting bugs and further information
+
+   $ cmake -version
+    cmake version 3.20.21032501-MSVC_2
+    CMake suite maintained and supported by Kitware (kitware.com/cmake).
+
+4. git clone dlite to a directory of your choice
+
+5. Build and test
+
+5.1. Build from the Windows commandline
+
+   When building with Python support, this will build against your default Python.
+   Make sure you have the following Python packages installed: numpy, pyyaml, pandas, psycopg2
+   Use `py -0p` to check the Python default.
+
+   $ mkdir .\out\build\x64-Release-vs15
+   $ cd .\out\build\x64-Release-vs15
+   $ cmake -G "Visual Studio 15 2017" ^
+           -A x64 ^
+           -DWITH_DOC=OFF ^
+           -DWITH_HDF5=OFF ^
+           -DCMAKE_CONFIGURATION_TYPES:STRING="Release" ^
+           -DCMAKE_INSTALL_PREFIX:PATH="%CD%\..\..\install\x64-Release-vs15" ^
+           ..\..\..
+
+    $ cmake --build . --config Release
+    $ cmake --install .
+    $ ctest -C Release
+
+5.2 Build from Visual Studio
+
+   When building with Python support, this will again build against your default Python.
+
+   Open the dlite directory with Visual Studio, it will be recognized as a CMake project.
+   Add a CMakeSettings.json file with the following minimum contents:
+
+    {
+      "configurations": [
+        {
+          "name": "x64-Release-vs15",
+          "generator": "Visual Studio 15 2017 Win64",
+          "configurationType": "Release",
+          "buildRoot": "${projectDir}\\out\\build\\${name}",
+          "installRoot": "${projectDir}\\out\\install\\${name}",
+          "cmakeCommandArgs": "-DWITH_DOC=OFF -DWITH_HDF5=OFF",
+          "buildCommandArgs": "",
+          "inheritEnvironments": [ "msvc_x64_x64" ]
+        }
+      ]
+    }
+
+    * Select the "x64-Release-vs15" configuration
+    * Right click on the top-level "CMakeLists.txt" -> "configure dlite"
+    * Right click on the top-level "CMakeLists.txt" -> "Build"
+    * Right click on the top-level "CMakeLists.txt" -> "Run Tests"
+
+5.3 Build against Python in a virtual environment (Recommended)
+
+   This example uses Anaconda Python and conda environemnts.
+
+   $ conda create --name=py38dlite python=3.8 numpy pyyaml pandas psycopg2
+   $ conda activate py38dlite
+
+   $ mkdir .\out\build\x64-Release-vs15
+   $ cd .\out\build\x64-Release-vs15
+   $ cmake -G "Visual Studio 15 2017" ^
+           -A x64 ^
+           -DWITH_DOC=OFF ^
+           -DWITH_HDF5=OFF ^
+           -DCMAKE_CONFIGURATION_TYPES:STRING="Release" ^
+           -DCMAKE_INSTALL_PREFIX:PATH="%CD%\..\..\install\x64-Release-vs15" ^
+           ..\..\..
+
+    $ cmake --build . --config Release
+    $ cmake --install .
+    $ ctest -C Release
 [cmake]: https://cmake.org/download/
 [hdf5]: https://support.hdfgroup.org/ftp/HDF5/current/src/
+[swig]: https://www.dev2qa.com/how-to-install-swig-on-macos-linux-and-windows/
+[pythonwindows]: https://pythondev.readthedocs.io/windows.html
+[mscompilers] https://docs.microsoft.com/en-us/cpp/porting/binary-compat-2015-2017
+
diff --git a/examples/CMakeLists.txt b/examples/CMakeLists.txt
index 355d9f9ac..d60e5ce0d 100644
--- a/examples/CMakeLists.txt
+++ b/examples/CMakeLists.txt
@@ -89,8 +89,10 @@ if(FORCE_EXAMPLES OR EXISTS ${CMAKE_INSTALL_PREFIX}/share/dlite/examples)
       ENVIRONMENT "PATH=${dlite_PATH_NATIVE}")
     set_property(TEST ${name} APPEND PROPERTY
       ENVIRONMENT "PYTHONPATH=${dlite_PYTHONPATH_NATIVE}")
-    set_property(TEST ${name} APPEND PROPERTY
+    if(NOT WIN32)
+      set_property(TEST ${name} APPEND PROPERTY
       ENVIRONMENT "LD_LIBRARY_PATH=${dlite_LD_LIBRARY_PATH_NATIVE}")
+    endif()
     set_property(TEST ${name} APPEND PROPERTY
       ENVIRONMENT "DLITE_USE_BUILD_ROOT=YES")
     set_property(TEST ${name} PROPERTY
diff --git a/examples/read-csv/readcsv.py b/examples/read-csv/readcsv.py
index 5376c0968..3a24bb909 100644
--- a/examples/read-csv/readcsv.py
+++ b/examples/read-csv/readcsv.py
@@ -8,7 +8,8 @@
 print(csv.uuid)
 
 
-csv.save('csv:newfile.csv')
+csv.save('csv://newfile.csv?mode=w')
+
 
 # Try to use the pandas hdf writer...
 csv.save('csv:newfile.h5?pandas_opts="key": "group", "index": False')
diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt
index 94acf41fb..494a17ce6 100644
--- a/src/CMakeLists.txt
+++ b/src/CMakeLists.txt
@@ -75,20 +75,9 @@ if(WITH_PYTHON)
 endif()
 
 
-# We are building both shared and static libraries.  User software will
-# normally link to the shared libraries.  However, to simplify the
-# library search (especially on Windows), the storage plugins will use
-# the static libraries.  For this to work, the static libraries will be
-# build position independent.
-#
-# FIXME
-# Linking storage plugins against static libraries is a VERY BAD IDEA!
-# It will create independent copies of global variables in the main
-# application and the storage plugins and break the uniqueness of
-# entities, mess up errors, +++.
-# We have to implement a robust way to find shared libraries on Windows,
-# probably by appending to the PATH environment variable before loading
-# any storage or mapping plugin.
+# We are building both shared and static libraries. User software will
+# normally link to the shared libraries.
+
 set(lib_args
   ${sources}
   ${CMAKE_CURRENT_BINARY_DIR}/config-paths.h
diff --git a/src/config-paths.h.in b/src/config-paths.h.in
index 86e9e83db..c0a0de348 100644
--- a/src/config-paths.h.in
+++ b/src/config-paths.h.in
@@ -3,21 +3,22 @@
 #ifndef _DLITE_CONFIG_PATHS_H
 #define _DLITE_CONFIG_PATHS_H
 
-#define dlite_PATH                   "@dlite_PATH_NATIVE@"
+#define dlite_PATH                   "@dlite_PATH@"
 #define dlite_PATH_EXTRA             "@dlite_PATH_EXTRA@"
-#define dlite_LD_LIBRARY_PATH        "@dlite_LD_LIBRARY_PATH_NATIVE@"
-#define dlite_PYTHONPATH             "@dlite_PYTHONPATH_NATIVE@"
+/* FIXME: This has no meaning for Windows but ./tools/dlite-env.c expects this and does not like backslashes */
+#define dlite_LD_LIBRARY_PATH        "@dlite_LD_LIBRARY_PATH@"
+#define dlite_PYTHONPATH             "@dlite_PYTHONPATH@"
 
 #define dlite_BUILD_ROOT             "@dlite_BUILD_ROOT_NATIVE@"
 #define dlite_INSTALL_ROOT           "@CMAKE_INSTALL_PREFIX@"
 
 /* hardcoded paths in build tree */
-#define dlite_STORAGE_PLUGINS        "@dlite_STORAGE_PLUGINS_NATIVE@"
-#define dlite_MAPPING_PLUGINS        "@dlite_MAPPING_PLUGINS_NATIVE@"
-#define dlite_PYTHON_STORAGE_PLUGINS "@dlite_PYTHON_STORAGE_PLUGINS_NATIVE@"
-#define dlite_PYTHON_MAPPING_PLUGINS "@dlite_PYTHON_MAPPING_PLUGINS_NATIVE@"
-#define dlite_TEMPLATES              "@dlite_TEMPLATES_NATIVE@"
-#define dlite_STORAGES               "@dlite_STORAGES_NATIVE@"
+#define dlite_STORAGE_PLUGINS        "@dlite_STORAGE_PLUGINS@"
+#define dlite_MAPPING_PLUGINS        "@dlite_MAPPING_PLUGINS@"
+#define dlite_PYTHON_STORAGE_PLUGINS "@dlite_PYTHON_STORAGE_PLUGINS@"
+#define dlite_PYTHON_MAPPING_PLUGINS "@dlite_PYTHON_MAPPING_PLUGINS@"
+#define dlite_TEMPLATES              "@dlite_TEMPLATES@"
+#define dlite_STORAGES               "@dlite_STORAGES@"
 
 
 #endif /* _DLITE_CONFIG_PATHS_H */
diff --git a/src/dlite-entity.c b/src/dlite-entity.c
index f223cbc66..718822b5a 100644
--- a/src/dlite-entity.c
+++ b/src/dlite-entity.c
@@ -517,9 +517,10 @@ DLiteInstance *dlite_instance_create_from_id(const char *metaid,
 /*
   Free's an instance and all arrays associated with dimensional properties.
  */
-static void dlite_instance_free(DLiteInstance *inst)
+static int dlite_instance_free(DLiteInstance *inst)
 {
   size_t i, nprops;
+  int stat;
   const DLiteMeta *meta = inst->meta;
   assert(meta);
 
@@ -527,7 +528,7 @@ static void dlite_instance_free(DLiteInstance *inst)
   if (meta->_deinit) meta->_deinit(inst);
 
   /* Remove from instance cache */
-  _instance_store_remove(inst->uuid);
+  stat = _instance_store_remove(inst->uuid);
 
   /* Standard free */
   nprops = meta->_nproperties;
@@ -555,6 +556,7 @@ static void dlite_instance_free(DLiteInstance *inst)
   free(inst);
 
   dlite_meta_decref((DLiteMeta *)meta);  /* decrease metadata refcount */
+  return stat;
 }
 
 
@@ -584,7 +586,9 @@ int dlite_instance_decref(DLiteInstance *inst)
             inst->_refcount, inst->_refcount-1,
             (inst->uri) ? inst->uri : inst->uuid);
   assert(inst->_refcount > 0);
-  if ((count = --inst->_refcount) <= 0) dlite_instance_free(inst);
+  if ((count = --inst->_refcount) == 0) {
+      if (dlite_instance_free(inst) == -1) return -1;
+  }
   return count;
 }
 
@@ -756,10 +760,16 @@ DLiteInstance *dlite_instance_load_url(const char *url)
   assert(url);
   if (!(str = strdup(url))) FAIL("allocation failure");
   if (dlite_split_url(str, &driver, &location, &options, &id)) goto fail;
-  if (id && *id && (inst = _instance_store_get(id))) {
-    dlite_instance_incref(inst);
+
+ ErrTry:
+  if (id && *id) inst = _instance_store_get(id);
+ ErrOther:
+  err_clear();
+ ErrEnd;
+
+ if (inst) {
+   dlite_instance_incref(inst);
   } else {
-    err_clear();
     if (!(s = dlite_storage_open(driver, location, options))) goto fail;
     if (!(inst = dlite_instance_load(s, id))) goto fail;
   }
diff --git a/src/dlite-json.c b/src/dlite-json.c
index d68442102..e6c1e4dd2 100644
--- a/src/dlite-json.c
+++ b/src/dlite-json.c
@@ -468,8 +468,10 @@ static DLiteInstance *parse_instance(const char *src, jsmntok_t *obj,
 
     /* -- infer name, version and namespace */
     if (dlite_instance_is_meta(inst)) {
-      if (dlite_split_meta_uri((uri) ? uri : id, &name, &version, &namespace))
-        FAIL1("cannot infer name, version and namespace from id: %s", id);
+      if (uri && dlite_split_meta_uri(uri, &name, &version, &namespace))
+        FAIL1("cannot infer name, version and namespace from uri '%s'", uri);
+      if (!name && id && dlite_split_meta_uri(id, &name, &version, &namespace))
+        FAIL1("cannot infer name, version and namespace from id '%s'", id);
     }
 
     /* -- assign uri */
@@ -831,9 +833,18 @@ DLiteJsonFormat dlite_jstore_loads(JStore *js, const char *src, int len)
     jsmntok_t *t = tokens + 1;
     int i;
     for (i=0; i < tokens->size; i++) {
-      jsmntok_t *v = t+1;
-      if (dlite_get_uuidn(uuid, src + t->start, t->end - t->start) < 0)
+      jsmntok_t *v = t + 1;
+
+      /* if `id` is not an uuid, add it as a label associated with uuid to the
+         jstore */
+      const char *id = src + t->start;
+      int len = t->end - t->start;
+      int uuidver = dlite_get_uuidn(uuid, id, len);
+      if (uuidver < 0)
         goto fail;
+      else if (uuidver > 0)
+        jstore_set_labeln(js, uuid, id, len);
+
       if (jstore_addn(js, uuid, DLITE_UUID_LENGTH,
                       src + v->start, v->end - v->start)) goto fail;
       t += jsmn_count(v) + 2;
diff --git a/src/dlite-mapping-plugins.c b/src/dlite-mapping-plugins.c
index 870905cd0..1ae49836c 100644
--- a/src/dlite-mapping-plugins.c
+++ b/src/dlite-mapping-plugins.c
@@ -53,14 +53,11 @@ static Globals *get_globals(void) {
                                                 "DLITE_MAPPING_PLUGIN_DIRS",
                                                 dlite_globals_get());
     if (!g->mapping_plugin_info) goto fail;
-
     fu_paths_set_platform(&g->mapping_plugin_info->paths, dlite_get_platform());
-
     if (dlite_use_build_root())
       plugin_path_extend(g->mapping_plugin_info, dlite_MAPPING_PLUGINS, NULL);
-    else
-      plugin_path_extend_prefix(g->mapping_plugin_info, dlite_root_get(),
-                                DLITE_ROOT "/" DLITE_MAPPING_PLUGIN_DIRS, NULL);
+    plugin_path_extend_prefix(g->mapping_plugin_info, dlite_root_get(),
+                              DLITE_ROOT "/" DLITE_MAPPING_PLUGIN_DIRS, NULL);
 
     /* Make sure that dlite DLLs are added to the library search path */
     dlite_add_dll_path();
diff --git a/src/pyembed/dlite-pyembed.c b/src/pyembed/dlite-pyembed.c
index ccf5c478e..22f2aaf7b 100644
--- a/src/pyembed/dlite-pyembed.c
+++ b/src/pyembed/dlite-pyembed.c
@@ -252,7 +252,8 @@ void *dlite_pyembed_get_address(const char *symbol)
     FAIL1("error calling ctypes.addressof(\"%s\")", symbol);
   if (!PyLong_Check(addr))
     FAIL2("address of \"%s\" in %s is not a long", symbol, filename);
-  ptr = (void *)PyLong_AsLong(addr);
+  size_t val = PyLong_AsLong(addr);
+    ptr = (void *)val;
 
   /* Seems that ctypes.addressof() returns the address where the pointer to
      `symbol` is stored, so we need an extra dereference... */
diff --git a/src/pyembed/dlite-python-mapping.c b/src/pyembed/dlite-python-mapping.c
index f2207b5c9..20507554b 100644
--- a/src/pyembed/dlite-python-mapping.c
+++ b/src/pyembed/dlite-python-mapping.c
@@ -287,10 +287,11 @@ const DLiteMappingPlugin *get_dlite_mapping_api(void *state, int *iter)
   if (!(mappings = dlite_python_mapping_load())) goto fail;
   assert(PyList_Check(mappings));
   n = (int)PyList_Size(mappings);
+  if (n == 0) return NULL;
 
   /* get class implementing the plugin API */
   if (*iter < 0 || *iter >= n)
-    FAIL1("API iterator index is out of range: %d", *iter);
+    FAIL1("Mapping API iterator index is out of range: %d", *iter);
   cls = PyList_GetItem(mappings, *iter);
   assert(cls);
   if (*iter < n - 1) (*iter)++;
diff --git a/src/utils/CMakeLists.txt b/src/utils/CMakeLists.txt
index bb953e1ef..450c9c62a 100644
--- a/src/utils/CMakeLists.txt
+++ b/src/utils/CMakeLists.txt
@@ -18,6 +18,7 @@ check_include_file(stdlib.h     HAVE_STDLIB_H)
 check_include_file(float.h      HAVE_FLOAT_H)
 check_include_file(inttypes.h   HAVE_INTTYPES_H)
 check_include_file(locale.h     HAVE_LOCALE_H)
+check_include_file(windows.h    HAVE_WINDOWS_H)
 
 # -- check for symbols
 set(CMAKE_C_FLAGS_saved ${CMAKE_C_FLAGS})
@@ -44,10 +45,12 @@ check_symbol_exists(stat                sys/stat.h   HAVE_STAT)
 check_symbol_exists(exec                unistd.h     HAVE_EXEC)
 check_symbol_exists(P_tmpdir            stdio.h      HAVE_P_TMPDIR)
 
-check_symbol_exists(GetFullPathNameW    fileapi.h    HAVE_GetFullPathNameW)
-check_symbol_exists(GetFullPathName     fileapi.h    HAVE_GetFullPathName)
-check_symbol_exists(GetFileAttributesW  fileapi.h    HAVE_GetFileAttributesW)
-check_symbol_exists(GetFileAttributes   fileapi.h    HAVE_GetFileAttributes)
+if(HAVE_WINDOWS_H)
+check_symbol_exists(GetFullPathNameW    windows.h    HAVE_GetFullPathNameW)
+check_symbol_exists(GetFullPathName     windows.h    HAVE_GetFullPathName)
+check_symbol_exists(GetFileAttributesW  windows.h    HAVE_GetFileAttributesW)
+check_symbol_exists(GetFileAttributes   windows.h    HAVE_GetFileAttributes)
+endif()
 list(APPEND CMAKE_REQUIRED_LIBRARIES shlwapi.lib)
 check_symbol_exists(PathFileExistsW     shlwapi.h    HAVE_PathFileExistsW)
 check_symbol_exists(PathFileExists      shlwapi.h    HAVE_PathFileExists)
@@ -284,6 +287,11 @@ add_definitions(
   -DHAVE_CONFIG_H
   )
 
+# FIXME - Should we add this here?
+#if(WINDOWS)
+#  add_definitions(-DDLLEXPORT)
+#endif()
+
 add_library(dlite-utils SHARED ${sources})
 add_library(dlite-utils-static STATIC ${sources})
 
diff --git a/src/utils/compat.c b/src/utils/compat.c
index ec6649fc2..a7b121603 100644
--- a/src/utils/compat.c
+++ b/src/utils/compat.c
@@ -170,7 +170,8 @@ int rpl_vasnpprintf(char **buf, size_t *size, size_t pos, const char *fmt,
   if (n < (int)PDIFF(*size, pos)) return n;  // success, buffer is large enough
 
   /* Reallocate buffer. Round up the size to the next power of two. */
-  newsize = 1L << (msb(n + pos) + 1);
+  newsize = (size_t)1L << (msb(n + pos) + 1);
+
   if (!(p = realloc(*buf, newsize))) return -1;
   *buf = p;
   *size = newsize;
diff --git a/src/utils/compat.h b/src/utils/compat.h
index 72751e72d..5b01b13d1 100644
--- a/src/utils/compat.h
+++ b/src/utils/compat.h
@@ -16,6 +16,10 @@
 #define _COMPAT_H
 
 #include <stdlib.h>
+#ifdef WIN32
+/* https://stackoverflow.com/questions/42536311/msvc-1900-and-define-vsnprintf */
+#include <stdio.h>
+#endif
 #include "config.h"
 
 /* Remove __attribute__ when we are not compiling with gcc */
diff --git a/src/utils/fileutils.c b/src/utils/fileutils.c
index 6ca8545dd..813d861da 100644
--- a/src/utils/fileutils.c
+++ b/src/utils/fileutils.c
@@ -393,7 +393,9 @@ const char *fu_nextpath(const char *paths, char **endptr, const char *pathsep)
     p = *endptr + 1;
 
   /* ignore repeated path separators */
-  while (strchr((pathsep) ? pathsep : ";:", *p)) p++;
+  if (*p) {
+    while (strchr((pathsep) ? pathsep : ";:", *p)) p++;
+  }
 
   if (pathsep) {
     *endptr = p + strcspn(p, pathsep);
@@ -1196,7 +1198,8 @@ FUIter *fu_pathsiter_init(const FUPaths *paths, const char *pattern)
   iter->pattern = pattern;
   iter->dirsep = DIRSEP[0];
   iter->origlen = paths->n;
-  if (!(iter->origpaths = strlist_copy(paths->paths))) goto fail;
+  if (!(iter->origpaths = (paths->paths) ? strlist_copy(paths->paths) : NULL))
+    goto fail;
   return iter;
  fail:
   if (iter) free(iter);
diff --git a/src/utils/floats.h.in b/src/utils/floats.h.in
index 01c06e277..0d6945943 100644
--- a/src/utils/floats.h.in
+++ b/src/utils/floats.h.in
@@ -42,14 +42,20 @@ typedef double double128_t;
 
 #ifdef HAVE_LONG_DOUBLE
 # if SIZEOF_LONG_DOUBLE == 8
-#  define HAVE_FLOAT64_T
+#  ifndef HAVE_FLOAT64_T
+#   define HAVE_FLOAT64_T
 typedef  long double float64_t;
+#  endif
 # elif SIZEOF_LONG_DOUBLE == 10
-#  define HAVE_FLOAT80_T
+#  ifndef HAVE_FLOAT80_T
+#   define HAVE_FLOAT80_T
 typedef long double float80_t;
+#  endif()
 # elif SIZEOF_LONG_DOUBLE == 16
-#  define HAVE_FLOAT128_T
+#  ifndef HAVE_FLOAT128_T
+#   define HAVE_FLOAT128_T
 typedef long double float128_t;
+#  endif
 #else
 #  error "Non-standard size of long double" # SIZEOF_DOUBLE
 # endif
diff --git a/src/utils/jstore.c b/src/utils/jstore.c
index 87d718baa..41b946a4c 100644
--- a/src/utils/jstore.c
+++ b/src/utils/jstore.c
@@ -15,7 +15,8 @@
 
 /* JSON store */
 struct _JStore {
-  map_str_t store;
+  map_str_t store;       // maps keys to json content
+  map_str_t labels;      // maps keys to associated label
 };
 
 
@@ -98,6 +99,7 @@ JStore *jstore_open(void)
   JStore *js = calloc(1, sizeof(JStore));
   if (!js) return err(1, "allocation failure"), NULL;
   map_init(&js->store);
+  map_init(&js->labels);
   return js;
 }
 
@@ -105,6 +107,7 @@ JStore *jstore_open(void)
 int jstore_close(JStore *js)
 {
   const char *key;
+
   map_iter_t miter = map_iter(&js->store);
   while ((key = map_next(&js->store, &miter))) {
     char **val = map_get(&js->store, key);
@@ -112,6 +115,15 @@ int jstore_close(JStore *js)
     free(*val);
   }
   map_deinit(&js->store);
+
+  map_iter_t liter = map_iter(&js->labels);
+  while ((key = map_next(&js->labels, &liter))) {
+    char **val = map_get(&js->labels, key);
+    assert(val);
+    free(*val);
+  }
+  map_deinit(&js->labels);
+
   free(js);
   return 0;
 }
@@ -318,3 +330,46 @@ int jstore_iter_deinit(JStoreIter *iter)
   (void)(iter);  // unused
   return 0;
 }
+
+
+/* Associate `label` with `key`.  If `len` is non-negative, it is the
+   length of `label`; otherwise `label` is assumed to be NUL-terminated.
+   If `key` already has a label, the old label is replaced.
+   Returns non-zero on error. */
+int jstore_set_labeln(JStore *js, const char *key, const char *label, int len)
+{
+  char **p, *s;
+  int stat;
+  if ((p = map_get(&js->labels, key))) free(*p);
+
+  if (len > 0)
+    s = strndup(label, len);
+  else if (len == 0)
+    s = strdup("");
+  else
+    s = strdup(label);
+  if (!s) return err(1, "allocation failure");
+
+  if ((stat = map_set(&js->labels, key, s))) {
+    errx(2, "error associating label '%s' to key '%s'", s, key);
+    free(s);
+  }
+  return stat;
+}
+
+/* Associate `label` with `key`.
+   If `key` already has a label, the old label is replaced.
+   Returns non-zero on error. */
+int jstore_set_label(JStore *js, const char *key, const char *label)
+{
+  return jstore_set_labeln(js, key, label, -1);
+}
+
+/* Returns a pointer to label associated with `key` or NULL if `key` has no
+   associated label. */
+const char *jstore_get_label(JStore *js, const char *key)
+{
+  char **p = map_get(&js->labels, key);
+  if (!p) return NULL;
+  return (const char *)*p;
+}
diff --git a/src/utils/jstore.h b/src/utils/jstore.h
index 9c655ba73..e907157b1 100644
--- a/src/utils/jstore.h
+++ b/src/utils/jstore.h
@@ -131,6 +131,22 @@ const char *jstore_iter_next(JStoreIter *iter);
     In the current implementation, this function does nothing. */
 int jstore_iter_deinit(JStoreIter *iter);
 
+
+/** Associate `label` with `key`.  If `len` is non-negative, it is the
+    length of `label`; otherwise `label` is assumed to be NUL-terminated.
+    If `key` already has a label, the old label is replaced.
+    Returns non-zero on error. */
+int jstore_set_labeln(JStore *js, const char *key, const char *label, int len);
+
+/** Associate `label` with `key`.
+    If `key` already has a label, the old label is replaced.
+    Returns non-zero on error. */
+int jstore_set_label(JStore *js, const char *key, const char *label);
+
+/** Returns a pointer to label associated with `key` or NULL if `key` has no
+    associated label. */
+const char *jstore_get_label(JStore *js, const char *key);
+
 /** @} */
 
 #endif  /* _JSTORE_H */
diff --git a/src/utils/plugin.c b/src/utils/plugin.c
index 29f1f7910..423e00b38 100644
--- a/src/utils/plugin.c
+++ b/src/utils/plugin.c
@@ -463,8 +463,11 @@ int plugin_path_extend(PluginInfo *info, const char *s, const char *pathsep)
   const char *p;
   char *endptr=NULL;
   int stat=0;
-  while ((p = fu_nextpath(s, &endptr, pathsep)))
-    if ((stat = plugin_path_appendn(info, p, endptr - p)) < 0) return stat;
+
+  while ((p = fu_nextpath(s, &endptr, pathsep))) {
+    if (*p && (stat = plugin_path_appendn(info, p, endptr - p)) < 0)
+      return stat;
+  }
   return stat;
 }
 
@@ -481,6 +484,7 @@ int plugin_path_extend_prefix(PluginInfo *info, const char *prefix,
   const char *p;
   char *endptr=NULL;
   int stat=0;
+
   while ((p = fu_nextpath(s, &endptr, pathsep))) {
     int len = endptr - p;
     if (fu_isabs(p)) {
diff --git a/src/utils/sha3.c b/src/utils/sha3.c
index 4b27aad64..10339025e 100644
--- a/src/utils/sha3.c
+++ b/src/utils/sha3.c
@@ -208,7 +208,7 @@ sha3_Update(void *priv, void const *bufIn, size_t len)
     SHA3_ASSERT(ctx->byteIndex == 0);
 
     words = len / sizeof(uint64_t);
-    tail = len - words * sizeof(uint64_t);
+    tail = (unsigned)(len - words * sizeof(uint64_t));
 
     SHA3_TRACE("have %d full words to process", (unsigned)words);
 
diff --git a/storages/hdf5/CMakeLists.txt b/storages/hdf5/CMakeLists.txt
index 03f1e8b72..dd43c0f65 100644
--- a/storages/hdf5/CMakeLists.txt
+++ b/storages/hdf5/CMakeLists.txt
@@ -9,8 +9,8 @@ add_definitions(-DHAVE_CONFIG_H)
 
 add_library(dlite-plugins-hdf5 SHARED ${sources})
 target_link_libraries(dlite-plugins-hdf5
-  dlite-static
-  dlite-utils-static
+  dlite
+  dlite-utils
   ${HDF5_LIBRARIES}
   )
 target_include_directories(dlite-plugins-hdf5 PUBLIC
diff --git a/storages/json/CMakeLists.txt b/storages/json/CMakeLists.txt
index a316edd1f..5484b7f90 100644
--- a/storages/json/CMakeLists.txt
+++ b/storages/json/CMakeLists.txt
@@ -9,8 +9,8 @@ add_definitions(-DHAVE_CONFIG_H)
 
 add_library(dlite-plugins-json SHARED ${sources})
 target_link_libraries(dlite-plugins-json
-  dlite-static
-  dlite-utils-static
+  dlite
+  dlite-utils
   )
 target_include_directories(dlite-plugins-json PUBLIC
   ${CMAKE_CURRENT_BINARY_DIR}
diff --git a/storages/json/dlite-json-storage.c b/storages/json/dlite-json-storage.c
index b82caec60..d61497729 100644
--- a/storages/json/dlite-json-storage.c
+++ b/storages/json/dlite-json-storage.c
@@ -173,7 +173,7 @@ int json_close(DLiteStorage *s)
 DLiteInstance *json_load(const DLiteStorage *s, const char *id)
 {
   DLiteJsonStorage *js = (DLiteJsonStorage *)s;
-  const char *buf=NULL;
+  const char *buf=NULL, *scanid;
   char uuid[DLITE_UUID_LENGTH+1];
 
   if (!id || !*id) {
@@ -191,7 +191,16 @@ DLiteInstance *json_load(const DLiteStorage *s, const char *id)
   }
   if (!buf && !(buf = jstore_get(js->jstore, id)))
     FAIL2("no instance with id \"%s\" in storage \"%s\"", id, s->location);
-  return dlite_json_sscan(buf, id, NULL);
+
+  if (dlite_get_uuid(uuid, id) == 0) {
+    /* the provided id is an uuid - check if a human readable id has been
+       assoicated with `id` as a label */
+    if (!(scanid = jstore_get_label(js->jstore, id))) scanid = id;
+  } else {
+    scanid = id;
+  }
+
+  return dlite_json_sscan(buf, scanid, NULL);
  fail:
   return NULL;
 }
diff --git a/storages/python/CMakeLists.txt b/storages/python/CMakeLists.txt
index 5b957ae10..c2decc6d5 100644
--- a/storages/python/CMakeLists.txt
+++ b/storages/python/CMakeLists.txt
@@ -9,8 +9,8 @@ set(sources
 
 add_library(dlite-plugins-python SHARED ${sources})
 target_link_libraries(dlite-plugins-python
-  dlite-static
-  dlite-utils-static
+  dlite
+  dlite-utils
   ${Python3_LIBRARIES}
   )
 target_include_directories(dlite-plugins-python PUBLIC
diff --git a/storages/rdf/CMakeLists.txt b/storages/rdf/CMakeLists.txt
index 9e5e241d8..9039822c2 100644
--- a/storages/rdf/CMakeLists.txt
+++ b/storages/rdf/CMakeLists.txt
@@ -11,8 +11,8 @@ add_library(dlite-plugins-rdf SHARED ${sources})
 target_link_libraries(dlite-plugins-rdf
   ${REDLAND_LIBRARIES}
   ${RAPTOR_LIBRARIES}
-  dlite-static
-  dlite-utils-static
+  dlite
+  dlite-utils
   )
 target_include_directories(dlite-plugins-rdf PUBLIC
   ${CMAKE_CURRENT_BINARY_DIR}


Test patch:
diff --git a/bindings/python/tests/CMakeLists.txt b/bindings/python/tests/CMakeLists.txt
index 1566abf59..2046b3fbc 100644
--- a/bindings/python/tests/CMakeLists.txt
+++ b/bindings/python/tests/CMakeLists.txt
@@ -22,9 +22,11 @@ foreach(test ${tests})
   set_property(TEST ${name} PROPERTY
     ENVIRONMENT "PATH=${dlite_PATH_NATIVE}")
   set_property(TEST ${name} APPEND PROPERTY
-    ENVIRONMENT "PYTHONPATH=${dlite_PYTHONPATH_NATIVE}")
+    ENVIRONMENT "PYTHONPATH=${dlite_PYTHONPATH}")
+  if (NOT WIN32)
   set_property(TEST ${name} APPEND PROPERTY
     ENVIRONMENT "LD_LIBRARY_PATH=${dlite_LD_LIBRARY_PATH_NATIVE}")
+  endif()
   set_property(TEST ${name} APPEND PROPERTY
     ENVIRONMENT "DLITE_USE_BUILD_ROOT=YES")
 
diff --git a/src/tests/CMakeLists.txt b/src/tests/CMakeLists.txt
index 8495e1e92..2be4b147b 100644
--- a/src/tests/CMakeLists.txt
+++ b/src/tests/CMakeLists.txt
@@ -1,5 +1,6 @@
 # -*- Mode: cmake -*-
-#
+project(dlite-src-tests C)
+
 
 set(tests
   test_misc
@@ -56,15 +57,30 @@ foreach(test ${tests})
 
   set_property(TEST ${test} PROPERTY
     ENVIRONMENT "PATH=${dlite_PATH_NATIVE}")
-  set_property(TEST ${test} APPEND PROPERTY
-    ENVIRONMENT "WINEPATH=${dlite_WINEPATH_NATIVE}")
+
+  if(MINGW)
+    set_property(TEST ${test} APPEND PROPERTY
+      ENVIRONMENT "WINEPATH=${dlite_WINEPATH_NATIVE}")
+  endif()
+
+  if(NOT WIN32)
+    set_property(TEST ${test} APPEND PROPERTY
+      ENVIRONMENT "LD_LIBRARY_PATH=${dlite_LD_LIBRARY_PATH_NATIVE}")
+  endif()
+
+  if(WIN32 AND PYTHON_IS_ANACONDA)
+    set_property(TEST ${test} APPEND PROPERTY
+      ENVIRONMENT "PYTHONHOME=${Python3_RUNTIME_LIBRARY_DIRS}")
+  endif()
+
   set_property(TEST ${test} APPEND PROPERTY
     ENVIRONMENT "PYTHONPATH=${dlite_PYTHONPATH_NATIVE}")
-  set_property(TEST ${test} APPEND PROPERTY
-    ENVIRONMENT "LD_LIBRARY_PATH=${dlite_LD_LIBRARY_PATH_NATIVE}")
+
   set_property(TEST ${test} APPEND PROPERTY
     ENVIRONMENT "DLITE_USE_BUILD_ROOT=YES")
+
+  # Needed by test_mapping
   set_property(TEST ${test} APPEND PROPERTY
-    ENVIRONMENT "DLITE_STORAGES='${CMAKE_CURRENT_SOURCE_DIR}/*.json'")
+    ENVIRONMENT "DLITE_MAPPING_PLUGIN_DIRS=$<SHELL_PATH:$<TARGET_FILE_DIR:mapA>>")
 
 endforeach()
diff --git a/src/tests/minunit/minunit.h b/src/tests/minunit/minunit.h
index 024c2b8c4..151dad452 100644
--- a/src/tests/minunit/minunit.h
+++ b/src/tests/minunit/minunit.h
@@ -189,10 +189,10 @@ static void (*minunit_teardown)(void) = NULL;
 	double minunit_tmp_e;\
 	double minunit_tmp_r;\
 	minunit_assert++;\
-	minunit_tmp_e = (expected);\
-	minunit_tmp_r = (result);\
+	minunit_tmp_e = (double)(expected);\
+	minunit_tmp_r = (double)(result);\
 	if (fabs(minunit_tmp_e-minunit_tmp_r) > MINUNIT_EPSILON) {\
-		int minunit_significant_figures = 1 - log10(MINUNIT_EPSILON);\
+                int minunit_significant_figures = 1 - (int)log10(MINUNIT_EPSILON); \
 		snprintf(minunit_last_message, MINUNIT_MESSAGE_LEN, "%s failed:\n\t%s:%d: %.*g expected but was %.*g", __func__, __FILE__, __LINE__, minunit_significant_figures, minunit_tmp_e, minunit_significant_figures, minunit_tmp_r);\
 		minunit_status = 1;\
 		return;\
diff --git a/src/tests/python/CMakeLists.txt b/src/tests/python/CMakeLists.txt
index e055ea254..0ac2b2aa1 100644
--- a/src/tests/python/CMakeLists.txt
+++ b/src/tests/python/CMakeLists.txt
@@ -33,12 +33,20 @@ foreach(test ${tests})
 
   set_property(TEST ${test} PROPERTY
     ENVIRONMENT "PATH=${dlite_PATH_NATIVE}")
-  set_property(TEST ${test} APPEND PROPERTY
-    ENVIRONMENT "WINEPATH=${dlite_WINEPATH_NATIVE}")
+  if(MINGW)
+    set_property(TEST ${test} APPEND PROPERTY
+      ENVIRONMENT "WINEPATH=${dlite_WINEPATH_NATIVE}")
+  endif()
+  if (WIN32 AND PYTHON_IS_ANACONDA)
+    set_property(TEST ${test} APPEND PROPERTY
+      ENVIRONMENT "PYTHONHOME=${Python3_RUNTIME_LIBRARY_DIRS}")
+  endif()
   set_property(TEST ${test} APPEND PROPERTY
     ENVIRONMENT "PYTHONPATH=${dlite_PYTHONPATH_NATIVE}")
+  if (NOT WIN32)
   set_property(TEST ${test} APPEND PROPERTY
     ENVIRONMENT "LD_LIBRARY_PATH=${dlite_LD_LIBRARY_PATH_NATIVE}")
+  endif()
   set_property(TEST ${test} APPEND PROPERTY
     ENVIRONMENT "DLITE_USE_BUILD_ROOT=YES")
 
diff --git a/src/tests/python/test_python_mapping.c b/src/tests/python/test_python_mapping.c
index e2bc79df4..d0e87511a 100644
--- a/src/tests/python/test_python_mapping.c
+++ b/src/tests/python/test_python_mapping.c
@@ -51,7 +51,7 @@ MU_TEST(test_map)
   inst3 = dlite_mapping("http://onto-ns.com/meta/0.1/ent3", instances, 1);
   mu_check(inst3);
   mu_check((p = dlite_instance_get_property(inst3, "c")));
-  mu_assert_double_eq(54.0, (double)*((float *)p));
+  mu_assert_double_eq(54.0, *(float *)p);
 
   dlite_instance_save_url("json://inst3.json", inst3);
 
diff --git a/src/tests/test_mapping.c b/src/tests/test_mapping.c
index c760d6215..7fa4cb8fb 100644
--- a/src/tests/test_mapping.c
+++ b/src/tests/test_mapping.c
@@ -4,6 +4,7 @@
 
 #include "dlite.h"
 #include "dlite-macros.h"
+#include "dlite-storage.h"
 #include "dlite-mapping.h"
 #include "dlite-mapping-plugins.h"
 
@@ -14,10 +15,37 @@
 MU_TEST(test_mapping_path)
 {
   char *mpath = STRINGIFY(dlite_BINARY_DIR) "/src/tests/mappings";
-  char *spath = STRINGIFY(dlite_SOURCE_DIR) "/src/tests/mappings/*.json";
+  char *spath1 = STRINGIFY(dlite_SOURCE_DIR) "/src/tests/*.json";
+  char *spath2 = STRINGIFY(dlite_SOURCE_DIR) "/src/tests/mappings/*.json";
 
   dlite_mapping_plugin_path_insert(0, mpath);
-  dlite_storage_paths_insert(0, spath);
+  dlite_storage_paths_insert(0, spath1);
+  dlite_storage_paths_insert(0, spath2);
+
+  const char **paths, **p;
+  printf("\nStorage plugin paths:\n");
+  paths = dlite_storage_plugin_paths();
+  for (p=paths; *p; p++)
+    printf("  - '%s'\n", *p);
+
+  printf("\nMapping plugin paths:\n");
+  paths = dlite_mapping_plugin_paths();
+  for (p=paths; *p; p++)
+    printf("  - '%s'\n", *p);
+
+  printf("\nStorages:\n");
+  paths = dlite_storage_paths_get();
+  for (p=paths; *p; p++)
+    printf("  - '%s'\n", *p);
+
+  printf("\nStorages (wildcard-expanded):\n");
+  const char *path;
+  DLiteStoragePathIter *iter = dlite_storage_paths_iter_start();
+  while ((path = dlite_storage_paths_iter_next(iter)))
+    printf("  - '%s'\n", path);
+  dlite_storage_paths_iter_stop(iter);
+
+  printf("\n");
 }
 
 
diff --git a/src/tests/test_property.c b/src/tests/test_property.c
index b740d431d..e05bdcbe3 100644
--- a/src/tests/test_property.c
+++ b/src/tests/test_property.c
@@ -51,7 +51,7 @@ MU_TEST(test_print)
   mu_assert_int_eq(2, m);
   mu_assert_string_eq("42", s);
 
-  float f = 3.14;
+  float f = 3.14f;
   prop.type = dliteFloat;
   prop.size = sizeof(f);
   m = dlite_property_aprint(&s, &size, n, &f, &prop, NULL, 0, -2, 0);
diff --git a/src/utils/tests/CMakeLists.txt b/src/utils/tests/CMakeLists.txt
index c0f40e0ae..3c2e93eef 100644
--- a/src/utils/tests/CMakeLists.txt
+++ b/src/utils/tests/CMakeLists.txt
@@ -56,8 +56,10 @@ foreach(test ${tests})
     )
   set_property(TEST ${test} PROPERTY
     ENVIRONMENT "PATH=${dlite_PATH_NATIVE}")
+  if (NOT WIN32)
   set_property(TEST ${test} APPEND PROPERTY
     ENVIRONMENT "LD_LIBRARY_PATH=${dlite_LD_LIBRARY_PATH_NATIVE}")
+  endif()
 
 endforeach()
 
diff --git a/src/utils/tests/test_jstore.c b/src/utils/tests/test_jstore.c
index 9fe953bbe..b4c405be3 100644
--- a/src/utils/tests/test_jstore.c
+++ b/src/utils/tests/test_jstore.c
@@ -117,6 +117,29 @@ MU_TEST(test_iter)
   jstore_iter_deinit(&iter);
 }
 
+MU_TEST(test_label)
+{
+  int stat;
+  const char *label;
+  stat = jstore_set_label(js, "key", "my label");
+  mu_assert_int_eq(0, stat);
+
+  stat = jstore_set_label(js, "key", "new label");
+  mu_assert_int_eq(0, stat);
+
+  stat = jstore_set_labeln(js, "key2", "another label", 7);
+  mu_assert_int_eq(0, stat);
+
+  label = jstore_get_label(js, "key");
+  mu_assert_string_eq("new label", label);
+
+  label = jstore_get_label(js, "key2");
+  mu_assert_string_eq("another", label);
+
+  label = jstore_get_label(js, "non-existing-key");
+  mu_assert_string_eq(NULL, label);
+}
+
 MU_TEST(test_close)
 {
   jstore_close(js);
@@ -140,6 +163,7 @@ MU_TEST_SUITE(test_suite)
   MU_RUN_TEST(test_to_file);
   MU_RUN_TEST(test_update_file);
   MU_RUN_TEST(test_iter);
+  MU_RUN_TEST(test_label);
   MU_RUN_TEST(test_close);
 }
 
diff --git a/storages/json/tests/CMakeLists.txt b/storages/json/tests/CMakeLists.txt
index f731aeef7..4931c17eb 100644
--- a/storages/json/tests/CMakeLists.txt
+++ b/storages/json/tests/CMakeLists.txt
@@ -17,6 +17,23 @@ add_custom_target(
     ${dlite_BINARY_DIR}/storages/json/tests
   )
 
+get_filename_component(Python3_LIBDIR ${Python3_LIBRARY_DIRS} DIRECTORY)
+set(dlite_PATH
+  $<TARGET_FILE_DIR:dlite>
+  $<TARGET_FILE_DIR:dlite-utils>
+  $<TARGET_FILE_DIR:dlite-plugins-json>
+  ${Python3_LIBDIR}
+  )
+set(dlite_PATH_NATIVE "")
+foreach(path ${dlite_PATH})
+  list(APPEND dlite_PATH_NATIVE1 $<SHELL_PATH:${path}>)
+endforeach()
+if(WIN32)
+  string(REPLACE ";" "\;" dlite_PATH_NATIVE "${dlite_PATH_NATIVE1}")
+else()
+  string(REPLACE ";" ":" dlite_PATH_NATIVE "${dlite_PATH_NATIVE1}")
+endif()
+
 foreach(test ${tests})
   add_executable(${test} ${test}.c)
   target_link_libraries(${test} dlite-plugins-json)
@@ -33,13 +50,30 @@ foreach(test ${tests})
 
   set_property(TEST ${test} PROPERTY
     ENVIRONMENT "PATH=${dlite_PATH_NATIVE}")
-  set_property(TEST ${test} APPEND PROPERTY
-    ENVIRONMENT "WINEPATH=${dlite_WINEPATH_NATIVE}")
+  if (WIN32 AND PYTHON_IS_ANACONDA)
+    set_property(TEST ${test} APPEND PROPERTY
+      ENVIRONMENT "PYTHONHOME=${Python3_RUNTIME_LIBRARY_DIRS}")
+  endif()
+  if(MINGW)
+    set_property(TEST ${test} APPEND PROPERTY
+      ENVIRONMENT "WINEPATH=${dlite_WINEPATH_NATIVE}")
+  endif()
   set_property(TEST ${test} APPEND PROPERTY
     ENVIRONMENT "PYTHONPATH=${dlite_PYTHONPATH_NATIVE}")
+  if (NOT WIN32)
   set_property(TEST ${test} APPEND PROPERTY
     ENVIRONMENT "LD_LIBRARY_PATH=${dlite_LD_LIBRARY_PATH_NATIVE}")
+  endif()
   set_property(TEST ${test} APPEND PROPERTY
     ENVIRONMENT "DLITE_USE_BUILD_ROOT=YES")
+  set_property(TEST ${test} APPEND PROPERTY
+    ENVIRONMENT "DLITE_STORAGES=$<SHELL_PATH:${dlite-src-tests_SOURCE_DIR}/*.json>")
+  if (WIN32)
+    set_property(TEST ${test} APPEND PROPERTY
+      ENVIRONMENT "PYTHONHOME=${Python3_RUNTIME_LIBRARY_DIRS}")
+  else()
+    set_property(TEST ${test} APPEND PROPERTY
+      ENVIRONMENT "LD_LIBRARY_PATH=${dlite_LD_LIBRARY_PATH_NATIVE}")
+  endif()
 
 endforeach()
diff --git a/storages/json/tests/test_json_storage.c b/storages/json/tests/test_json_storage.c
index 25c41a4f5..1517c75c2 100644
--- a/storages/json/tests/test_json_storage.c
+++ b/storages/json/tests/test_json_storage.c
@@ -24,19 +24,77 @@ void json_iter_free(void *iter);
 DLiteInstance *inst, *data3;
 
 
+MU_TEST(test_get_instance_from_in_memory_store)
+{
+    char* filename = STRINGIFY(DLITE_ROOT) "/src/tests/test-data.json";
+    DLiteStorage* s = NULL;
+    DLiteInstance* inst1, * inst0, *stat = NULL;
+    int r;
+    printf("\n--- test_get_instance_from_in_memory_store ---\n");
+
+    // Instance cannot be in store
+    stat = dlite_instance_has("204b05b2-4c89-43f4-93db-fd1cb70f54ef", 0);
+    mu_assert_int_eq(-1, (stat) ? 0 : -1);
+
+    s = dlite_storage_open("json", filename, "mode=r");
+    mu_check(s);
+    inst0 = json_load(s, "204b05b2-4c89-43f4-93db-fd1cb70f54ef");
+    mu_check(inst0);
+    r = dlite_storage_close(s);
+    mu_assert_int_eq(0, r);
+
+    // Should be in store now
+    stat = dlite_instance_has("204b05b2-4c89-43f4-93db-fd1cb70f54ef", 0);
+    mu_assert_int_eq(0, (stat) ? 0 : -1);
+    stat = dlite_instance_has(inst0->uuid, 0);
+    mu_assert_int_eq(0, (stat) ? 0 : -1);
+
+    // Now getting it from istore
+    inst1 = dlite_instance_get(inst0->uuid);
+    mu_check(inst1);
+    dlite_instance_debug(inst1);
+}
+
+MU_TEST(test_remove_last_instance)
+{
+    char* filename = STRINGIFY(DLITE_ROOT) "/src/tests/test-data.json";
+    DLiteStorage* s = NULL;
+    DLiteInstance* inst1, * inst0;
+    int r, stat;
+    printf("\n--- test_remove_last_instance ---\n");
+
+    s = dlite_storage_open("json", filename, "mode=r");
+    mu_check(s);
+
+    inst0 = json_load(s, "e076a856-e36e-5335-967e-2f2fd153c17d");
+    mu_check(inst0);
+    inst1 = json_load(s, "e076a856-e36e-5335-967e-2f2fd153c17d");
+    mu_check(inst1);
+    dlite_instance_debug(inst1);
+
+    r = dlite_storage_close(s);
+    mu_assert_int_eq(0, r);
+
+    stat = dlite_instance_decref(inst1);
+    mu_assert_int_eq(1, stat);
+    dlite_instance_debug(inst1);
+
+    stat = dlite_instance_decref(inst1);
+    mu_assert_int_eq(0, stat);
+}
 
 MU_TEST(test_load)
 {
   char *filename = STRINGIFY(DLITE_ROOT) "/src/tests/test-read-data.json";
   DLiteStorage *s = NULL;
   int r;
+  printf("\n--- test_load: dbd9d597-16b4-58f5-b10f-7e49cf85084b ---\n");
 
   s = dlite_storage_open("json", filename, "mode=r");
   mu_check(s);
 
   inst = json_load(s, "dbd9d597-16b4-58f5-b10f-7e49cf85084b");
   mu_check(inst);
-  printf("\n--- test_load: dbd9d597-16b4-58f5-b10f-7e49cf85084b ---\n");
   dlite_json_print(inst);
 
   r = dlite_storage_close(s);
@@ -46,8 +104,10 @@ MU_TEST(test_load)
 MU_TEST(test_load2)
 {
   int stat;
-  char *url = STRINGIFY(DLITE_ROOT) "/src/tests/test-read-data.json"
+  char *url = "json://" STRINGIFY(DLITE_ROOT) "/src/tests/test-read-data.json"
     "#dlite/1/test-c";
+  printf("\n--- test_load2: %s ---\n", url);
+
   DLiteInstance *inst2 = dlite_instance_load_url(url);
   mu_check(inst2);
   stat = dlite_instance_decref(inst2);
@@ -59,6 +119,8 @@ MU_TEST(test_load3)
   int stat;
   char *url = "json://" STRINGIFY(DLITE_ROOT) "/src/tests/test-read-data.json"
     "#4cd9ed73-cb8d-5b98-8f3c-db5c916c53a5";
+  printf("\n--- test_load3: %s ---\n", url);
+
   DLiteInstance *inst2 = dlite_instance_load_url(url);
   mu_check(inst2);
   stat = dlite_instance_decref(inst2);
@@ -68,7 +130,9 @@ MU_TEST(test_load3)
 MU_TEST(test_load4)
 {
   int stat;
-  char *url = STRINGIFY(DLITE_ROOT) "/src/tests/test-read-data.json#dlite/1/A";
+  char *url = "json://" STRINGIFY(DLITE_ROOT) "/src/tests/test-read-data.json#dlite/1/A";
+  printf("\n--- test_load4: %s ---\n", url);
+
   DLiteInstance *inst2 = dlite_instance_load_url(url);
   mu_check(inst2);
   stat = dlite_instance_decref(inst2);
@@ -77,20 +141,21 @@ MU_TEST(test_load4)
 
 MU_TEST(test_load_data3)
 {
-  char *url = STRINGIFY(DLITE_ROOT) "/src/tests/test-read-data.json#data3";
+  char *url = "json://" STRINGIFY(DLITE_ROOT) "/src/tests/test-read-data.json#data3";
+  printf("\n--- test_load_data3: %s ---\n", url);
+
   data3 = dlite_instance_load_url(url);
   mu_check(data3);
-  printf("\n--- test_load_data3 ---\n");
   dlite_json_print(data3);
 }
 
 
-
 MU_TEST(test_write)
 {
   int stat;
   DLiteStorage *s;
   assert(inst);
+  printf("\n--- test_write ---\n");
 
   s = dlite_storage_open("json", "test-json-write.json", "mode=w");
   mu_check(s);
@@ -110,6 +175,7 @@ MU_TEST(test_append)
 {
   DLiteStorage *s;
   int stat;
+  printf("\n--- test_append ---\n");
 
   s = dlite_storage_open("json", "test-json-write.json", "mode=a");
   mu_check(s);
@@ -132,11 +198,11 @@ MU_TEST(test_iter)
   void *iter;
   char uuid[DLITE_UUID_LENGTH+1];
   int r, n=0;
+  printf("\n--- test_iter ---\n");
 
   s = dlite_storage_open("json", filename, "mode=r");
   mu_check(s);
 
-  printf("\n--- test_iter ---\n");
   iter = json_iter_create(s, NULL);
   while ((r = json_iter_next(iter, uuid)) == 0) {
     dlite_errclr();
@@ -144,7 +210,7 @@ MU_TEST(test_iter)
     DLiteInstance *inst2 = dlite_instance_load(s, uuid);
     mu_check(inst2);
     dlite_json_print(inst2);
-    dlite_instance_decref(inst2);
+    //dlite_instance_decref(inst2);
     n++;
   }
   mu_assert_int_eq(1, r);
@@ -164,6 +230,8 @@ MU_TEST(test_iter)
 
 MU_TEST_SUITE(test_suite)
 {
+  MU_RUN_TEST(test_get_instance_from_in_memory_store);
+  MU_RUN_TEST(test_remove_last_instance);
   MU_RUN_TEST(test_load);
   MU_RUN_TEST(test_load2);
   MU_RUN_TEST(test_load3);
diff --git a/storages/python/tests/CMakeLists.txt b/storages/python/tests/CMakeLists.txt
index 2c8ca4134..1925214df 100644
--- a/storages/python/tests/CMakeLists.txt
+++ b/storages/python/tests/CMakeLists.txt
@@ -79,16 +79,25 @@ foreach(test ${tests})
     COMMAND ${RUNNER} ${test}
     )
 
+
   set_property(TEST ${test} PROPERTY
     ENVIRONMENT "PATH=${dlite_PATH_NATIVE}")
-  set_property(TEST ${test} APPEND PROPERTY
-    ENVIRONMENT "WINEPATH=${dlite_WINEPATH_NATIVE}")
+  if (WIN32 AND PYTHON_IS_ANACONDA)
+    set_property(TEST ${test} APPEND PROPERTY
+      ENVIRONMENT "PYTHONHOME=${Python3_RUNTIME_LIBRARY_DIRS}")
+  endif()
+  if(MINGW)
+    set_property(TEST ${test} APPEND PROPERTY
+      ENVIRONMENT "WINEPATH=${dlite_WINEPATH_NATIVE}")
+  endif()
   set_property(TEST ${test} APPEND PROPERTY
     ENVIRONMENT "PYTHONPATH=${dlite_PYTHONPATH_NATIVE}")
-  set_property(TEST ${test} APPEND PROPERTY
-    ENVIRONMENT "LD_LIBRARY_PATH=${dlite_LD_LIBRARY_PATH_NATIVE}")
   set_property(TEST ${test} APPEND PROPERTY
     ENVIRONMENT "DLITE_USE_BUILD_ROOT=YES")
+  if (NOT WIN32)
+  set_property(TEST ${test} APPEND PROPERTY
+    ENVIRONMENT "LD_LIBRARY_PATH=${dlite_LD_LIBRARY_PATH_NATIVE}")
+  endif()
   set_property(TEST ${test} APPEND PROPERTY
     ENVIRONMENT "DLITE_STORAGES=${CMAKE_CURRENT_SOURCE_DIR}/*.json|${dlite_SOURCE_DIR}/storages/python/python-storage-plugins/*.json")
 
diff --git a/tools/tests/CMakeLists.txt b/tools/tests/CMakeLists.txt
index 66d6cc3b0..ec1df01c1 100644
--- a/tools/tests/CMakeLists.txt
+++ b/tools/tests/CMakeLists.txt
@@ -70,10 +70,14 @@ if(WITH_JSON)
 
     set_property(TEST ${test} PROPERTY
       ENVIRONMENT "PATH=${dlite_PATH_NATIVE}")
-    set_property(TEST ${test} APPEND PROPERTY
-      ENVIRONMENT "WINEPATH=${dlite_WINEPATH_NATIVE}")
+    if(MINGW)
+      set_property(TEST ${test} APPEND PROPERTY
+        ENVIRONMENT "WINEPATH=${dlite_WINEPATH_NATIVE}")
+    endif()
+    if (NOT WIN32)
     set_property(TEST ${test} APPEND PROPERTY
       ENVIRONMENT "LD_LIBRARY_PATH=${dlite_LD_LIBRARY_PATH_NATIVE}")
+    endif()
     set_property(TEST ${test} APPEND PROPERTY
       ENVIRONMENT "DLITE_USE_BUILD_ROOT=YES")