diff --git a/Makefile b/Makefile
index 224a315f66dabe560983e740524ab792b1c313a6..f0e94d96675c12392a291e91daa65f17b3888400 100644
--- a/Makefile
+++ b/Makefile
@@ -66,7 +66,6 @@
 # e.g.: "make install prefix=/usr"
 
 include src/common.inc
-include src/version.inc
 
 RPM_BUILDDIR=rpmbuild
 DPKG_BUILDDIR=dpkgbuild
diff --git a/src/Makefile b/src/Makefile
index 4b50dd8b5d34a8024ba2de74145cbbd8daa05321..b301c01ecf5eb6f9567c4f8975349a7f04d3fea9 100644
--- a/src/Makefile
+++ b/src/Makefile
@@ -34,7 +34,6 @@
 #
 TOP := $(dir $(lastword $(MAKEFILE_LIST)))..
 include $(TOP)/src/common.inc
-include $(TOP)/src/version.inc
 
 TARGETS = libpmem libvmem libpmemblk libpmemlog libpmemobj libpmempool\
 		  libpmemcto libvmmalloc tools
diff --git a/src/common.inc b/src/common.inc
index f631745d411958dbfc41aba814d316b79e0c70e9..56bf0b468a7f0f4612a3509eaed01bda1c3c76af 100644
--- a/src/common.inc
+++ b/src/common.inc
@@ -54,6 +54,16 @@ COVERAGE = 0
 PKG_CONFIG ?= pkg-config
 HEADERS = $(wildcard *.h) $(wildcard *.hpp)
 
+ifeq ($(SRCVERSION),)
+export SRCVERSION := $(shell $(TOP)/utils/version.sh $(TOP))
+else
+export SRCVERSION
+endif
+
+ifeq ($(SRCVERSION),)
+$(error Cannot evaluate version)
+endif
+
 ifeq ($(CLANG_FORMAT),)
 ifeq ($(shell command -v clang-format-3.8 > /dev/null && echo y || echo n), y)
 export CLANG_FORMAT ?= clang-format-3.8
diff --git a/utils/SRCVERSION.ps1 b/utils/SRCVERSION.ps1
index e612ce6c6aaa143804e68f8f0592fc4dc2446f18..966c7450d79721f8c6b56743f7a0c006db8b3157 100644
--- a/utils/SRCVERSION.ps1
+++ b/utils/SRCVERSION.ps1
@@ -28,28 +28,38 @@
 # THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
 #
-# SRCVERSION.PS1 -- script to create SCRVERSION macro on windows
+# SRCVERSION.PS1 -- script to create SCRVERSION macro and generate srcversion.h
 #
 
 #
-# Expected Values:
-# +--------------------+-----+-----+-----+--------+------+-------+----------+
-# |git describe --long |MAJOR|MINOR|BUILD|REVISION|BUGFIX|PRIVATE|PRERELEASE|
-# +--------------------+-----+-----+-----+--------+------+-------+----------+
-# |1.2-0-12345678      |    1|    2|    0|    1000| false|  false|     false|
-# |1.2-32-123345678    |    1|    2|   32|    1000| false|   true|     false|
-# |1.2-XXX-0-12345678  |    1|    2|    0|       0| false|  false|      true|
-# |1.2-rc2-0-12345678  |    1|    2|    0|       2| false|  false|      true|
-# |1.2-rc3-32-12345678 |    1|    2|   32|       3| false|   true|      true|
-# |1.2+b3-0-12345678   |    1|    2|    0|    1003|  true|  false|     false|
-# |1.2+b2-327-12345678 |    1|    2|  327|    1002|  true|   true|     false|
-# +--------------------+-----+-----+-----+--------+------+-------+----------+
+# Windows dll versioning supports only fixed number of fields. The most
+# important are MAJOR, MINOR and REVISION. We have 3-compoment releases
+# (e.g. 1.4.1) with release candidates, so we have to encode this information
+# into this fixed number of fields. That's why we abuse REVISION to encode both
+# 3rd component and rc status.
+# REVISION = 3RDCOMP * 10000 + (!is_rc) * 1000 + rc.
+#
+# Examples:
+# +---------------------+-----+-----+--------+-----+------+-------+----------+
+# |git describe --long  |MAJOR|MINOR|REVISION|BUILD|BUGFIX|PRIVATE|PRERELEASE|
+# +---------------------+-----+-----+--------+-----+------+-------+----------+
+# |1.4-rc2-0-12345678   |    1|    4|       2|    0| false|  false|      true|
+# |1.4-rc3-6-12345678   |    1|    4|       3|    6| false|   true|      true|
+# |1.4-0-12345678       |    1|    4|    1000|    0| false|  false|     false|
+# |1.4-6-123345678      |    1|    4|    1000|    6| false|   true|     false|
+# |1.4.2-rc1-0-12345678 |    1|    4|   20001|    0|  true|  false|      true|
+# |1.4.2-rc4-6-12345678 |    1|    4|   20004|    6|  true|   true|      true|
+# |1.4.2-0-12345678     |    1|    4|   21000|    0|  true|  false|     false|
+# |1.4.2-6-12345678     |    1|    4|   21000|    6|  true|   true|     false|
+# +---------------------+-----+-----+--------+-----+------+-------+----------+
 #
 
 $scriptPath = Split-Path -parent $MyInvocation.MyCommand.Definition
 $file_path = $scriptPath + "\..\src\windows\include\srcversion.h"
 $git_version_file = $scriptPath + "\..\GIT_VERSION"
+$version_file = $scriptPath + "\..\VERSION"
 $git = Get-Command -Name git -ErrorAction SilentlyContinue
 
 if (Test-Path $file_path) {
@@ -84,6 +94,9 @@ $CUSTOM = $false
 if ($null -ne $args[0]) {
     $version = $args[0]
     $ver_array = $version.split("-+")
+} elseif (Test-Path $version_file) {
+    $version = Get-Content $version_file
+    $ver_array = $version.split("-+")
 } elseif ($null -ne $git) {
     $version = $(git describe)
     $ver_array = $(git describe --long).split("-+")
@@ -111,30 +124,33 @@ if ($null -ne $args[0]) {
 }
 
 if ($null -ne $ver_array) {
-    $MAJOR = $ver_array[0].split(".")[0]
-    $MINOR = $ver_array[0].split(".")[1]
+    $ver_dots = $ver_array[0].split(".")
+    $MAJOR = $ver_dots[0]
+    $MINOR = $ver_dots[1]
+    if ($ver_dots.length -ge 3) {
+        $REV = $ver_dots[2]
+        $BUGFIX = $true
+    } else {
+        $REV = 0
+    }
+
+    $REVISION = 10000 * $REV
     $BUILD = $ver_array[$ver_array.length - 2]
 
     if ($ver_array.length -eq 4) {
-        # <MAJOR>.<MINOR>-<SUFFIX><REVISION>-<BUILDNUMBER>-<HASH>
-        # <MAJOR>.<MINOR>+<SUFFIX><REVISION>-<BUILDNUMBER>-<HASH>
+        # <MAJOR>.<MINOR>[.<BUGFIX>]-<SUFFIX><REVISION>-<BUILD>-<HASH>
 
         if ($ver_array[1].StartsWith("rc")) {
-            # <MAJOR>.<MINOR>-rc<REVISION>-<BUILDNUMBER>-<HASH>
-            $REVISION = $ver_array[1].Substring("rc".Length)
+            # <MAJOR>.<MINOR>[.<BUGFIX>]-rc<REVISION>-<BUILD>-<HASH>
+            $REVISION += $ver_array[1].Substring("rc".Length)
             $PRERELEASE = $true
-        } elseif ($ver_array[1].StartsWith("b")) {
-            # <MAJOR>.<MINOR>+b<REVISION>-<BUILDNUMBER>-<HASH>
-            $REVISION = 1000 + $ver_array[1].Substring("b".Length)
-            $BUGFIX = $true
         } else {
-            # <MAJOR>.<MINOR>-<SUFFIX><REVISION>-<BUILDNUMBER>-<HASH>
-            $REVISION = 0
-            $PRERELEASE = $true
+            # <MAJOR>.<MINOR>[.<BUGFIX>]-<SOMETHING>-<BUILD>-<HASH>
+            throw "Unknown version format"
         }
     } else {
-        # <MAJOR>.<MINOR>-<BUILDNUMBER>-<HASH>
-        $REVISION = 1000
+        # <MAJOR>.<MINOR>[.<BUGFIX>]-<BUILD>-<HASH>
+        $REVISION += 1000
     }
 
     if ($BUILD -eq 0) {
diff --git a/src/version.inc b/utils/version.sh
old mode 100644
new mode 100755
similarity index 55%
rename from src/version.inc
rename to utils/version.sh
index 62758ad42ffc00c30dbb7c7398fb92a736f57624..29d939a0942820d5941509f114a337aeb9a34c22
--- a/src/version.inc
+++ b/utils/version.sh
@@ -1,5 +1,6 @@
+#!/usr/bin/env bash
 #
-# Copyright 2017, Intel Corporation
+# Copyright 2017-2018, Intel Corporation
 #
 # Redistribution and use in source and binary forms, with or without
 # modification, are permitted provided that the following conditions
@@ -28,35 +29,60 @@
 # THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
 #
-# src/version.inc -- common version rules for PMDK makefiles
+# utils/version.sh -- determine project's version
 #
+set -e
 
-TOP := $(dir $(lastword $(MAKEFILE_LIST)))..
+if [ -f "$1/VERSION" ]; then
+	cat "$1/VERSION"
+	exit 0
+fi
 
-VERSION = $(TOP)/.version
-GIT_VERSION = $(TOP)/.git_version
+if [ -f $1/GIT_VERSION ]; then
+	echo -n "\$Format:%h %d\$" | cmp -s $1/GIT_VERSION - && true
+	if [ $? -eq 0 ]; then
+		PARSE_GIT_VERSION=0
+	else
+		PARSE_GIT_VERSION=1
+	fi
+else
+	PARSE_GIT_VERSION=0
+fi
 
-GIT_VERSION_TAG=$(shell cat $(TOP)/GIT_VERSION | grep tag: | sed 's/.*tag: \([0-9a-z.+-]*\).*/\1/')
-GIT_VERSION_HASH=$(shell cat $(TOP)/GIT_VERSION | sed -e 's/.Format:%h %d.//g' -e 's/ .*//')
+if [ $PARSE_GIT_VERSION -eq 1 ]; then
+	GIT_VERSION_TAG=$(cat $1/GIT_VERSION | grep tag: | sed 's/.*tag: \([0-9a-z.+-]*\).*/\1/')
+	GIT_VERSION_HASH=$(cat $1/GIT_VERSION | sed -e 's/ .*//')
 
-ifneq ($(GIT_VERSION_TAG),)
-$(shell echo "$(GIT_VERSION_TAG)" > $(GIT_VERSION))
-else
-ifneq ($(GIT_VERSION_HASH),)
-$(shell echo "$(GIT_VERSION_HASH)" > $(GIT_VERSION))
-else
-$(shell rm -f $(GIT_VERSION))
-endif
-endif
-
-export SRCVERSION = $(shell git describe 2>/dev/null ||\
-			cat $(VERSION) 2>/dev/null ||\
-			git log -1 --format=%h 2>/dev/null ||\
-			cat $(GIT_VERSION) 2>/dev/null ||\
-			(basename `realpath $(TOP)` | sed 's/pmdk[-]*\([0-9a-z.+-]*\).*/\1/'))
-
-ifeq ($(SRCVERSION),)
-$(error Cannot evaluate version)
-endif
+	if [ -n "$GIT_VERSION_TAG" ]; then
+		echo "$GIT_VERSION_TAG"
+		exit 0
+	fi
+
+	if [ -n "$GIT_VERSION_HASH" ]; then
+		echo "$GIT_VERSION_HASH"
+		exit 0
+	fi
+fi
+
+GIT_DESCRIBE=$(git -C $1 describe 2>/dev/null) && true
+if [ -n "$GIT_DESCRIBE" ]; then
+	echo "$GIT_DESCRIBE"
+	exit 0
+fi
+
+# try commit it, git describe can fail when there are no tags (e.g. with shallow clone, like on Travis)
+GIT_COMMIT=$(git -C $1 log -1 --format=%h) && true
+if [ -n "$GIT_COMMIT" ]; then
+	echo "$GIT_COMMIT"
+	exit 0
+fi
+
+# If nothing works, try to get version from directory name
+VER=$(basename `realpath $1` | sed 's/pmdk[-]*\([0-9a-z.+-]*\).*/\1/')
+if [ -n "$VER" ]; then
+	echo "$VER"
+	exit 0
+fi
+
+exit 1