diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml
new file mode 100644
index 0000000..6b75f78
--- /dev/null
+++ b/.github/workflows/ci.yml
@@ -0,0 +1,87 @@
+name: CI
+
+on:
+  workflow_dispatch:
+  pull_request:
+  push:
+    branches:
+    - master
+
+jobs:
+
+  standard:
+
+    strategy:
+      fail-fast: false
+      matrix:
+        runs-on: [ubuntu-latest, macos-latest, windows-latest]
+
+    defaults:
+      run:
+        shell: bash -l {0}
+
+    name: ${{ matrix.runs-on }} • x64 ${{ matrix.args }}
+    runs-on: ${{ matrix.runs-on }}
+
+    steps:
+
+    - name: Basic GitHub action setup
+      uses: actions/checkout@v2
+
+    - name: Set conda environment
+      uses: mamba-org/provision-with-micromamba@main
+      with:
+        environment-name: myenv
+        environment-file: environment-dev.yml
+        cache-env: true
+        extra-specs: |
+          ninja
+
+    - name: Configure using CMake
+      run: cmake -Bbuild -G "Ninja" -DCMAKE_INSTALL_PREFIX=$CONDA_PREFIX -DPYTHON_EXECUTABLE=`which python` -DDOWNLOAD_GTEST=ON
+
+    - name: Install
+      working-directory: build
+      run: cmake --install .
+
+    - name: Build xtensor-python
+      working-directory: build
+      run: cmake --build .
+
+    - name: Test xtensor-python
+      working-directory: build/test
+      run: ./test_xtensor_python
+
+    - name: Test xtensor-python (Python)
+      run: py.test -s
+
+    - name: Example - readme 1
+      working-directory: docs/source/examples/readme_example_1
+      run: |
+        cmake -Bbuild -DPython_EXECUTABLE=`which python`
+        cd build
+        cmake --build .
+        cp ../example.py .
+        python example.py
+        cd ..
+
+    - name: Example - Copy 'cast'
+      working-directory: docs/source/examples/copy_cast
+      run: |
+        cmake -Bbuild -DPython_EXECUTABLE=`which python`
+        cd build
+        cmake --build .
+        cp ../example.py .
+        python example.py
+        cd ..
+
+    - name: Example - SFINAE
+      working-directory: docs/source/examples/sfinae
+      run: |
+        cmake -Bbuild -DPython_EXECUTABLE=`which python`
+        cd build
+        cmake --build .
+        cp ../example.py .
+        python example.py
+        cd ..
+
diff --git a/CMakeLists.txt b/CMakeLists.txt
index e1bd077..aa7f454 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -25,7 +25,7 @@ foreach(ver ${xtensor_python_version_defines})
         set(XTENSOR_PYTHON_VERSION_${CMAKE_MATCH_1} "${CMAKE_MATCH_2}" CACHE INTERNAL "")
     endif()
 endforeach()
-set(${PROJECT_NAME}_VERSION 
+set(${PROJECT_NAME}_VERSION
     ${XTENSOR_PYTHON_VERSION_MAJOR}.${XTENSOR_PYTHON_VERSION_MINOR}.${XTENSOR_PYTHON_VERSION_PATCH})
 message(STATUS "xtensor-python v${${PROJECT_NAME}_VERSION}")
 
@@ -45,7 +45,7 @@ else()
     find_package(xtensor ${xtensor_REQUIRED_VERSION} REQUIRED)
     message(STATUS "Found xtensor: ${xtensor_INCLUDE_DIRS}/xtensor")
 endif()
-    
+
 # Currently no required version for pybind11
 if(TARGET pybind11 OR TARGET pybind11::headers)
     # pybind11 has a variable that indicates its version already, so use that
@@ -80,6 +80,12 @@ target_include_directories(xtensor-python INTERFACE
 target_link_libraries(xtensor-python INTERFACE xtensor)
 get_target_property(inc_dir xtensor-python INTERFACE_INCLUDE_DIRECTORIES)
 
+if(MSVC)
+    set_property(TARGET xtensor-python PROPERTY INTERFACE_COMPILE_OPTIONS /DHAVE_SNPRINTF)
+else()
+    set_property(TARGET xtensor-python PROPERTY INTERFACE_COMPILE_OPTIONS -DHAVE_SNPRINTF)
+endif()
+
 OPTION(BUILD_TESTS "xtensor test suite" OFF)
 OPTION(DOWNLOAD_GTEST "build gtest from downloaded sources" OFF)