repo: Layer json version automation

Change-Id: I0f71808bf58997e58599b3cb00bb23b8dd179f3c
diff --git a/cmake/FindVulkanHeaders.cmake b/cmake/FindVulkanHeaders.cmake
index a1458fd..41afa9b 100644
--- a/cmake/FindVulkanHeaders.cmake
+++ b/cmake/FindVulkanHeaders.cmake
@@ -32,6 +32,13 @@
 #   VulkanRegistry_FOUND         - True if VulkanRegistry was found
 #   VulkanRegistry_DIRS          - directories for VulkanRegistry
 #
+#   VulkanHeaders_VERSION_MAJOR  - The Major API version of the latest version
+#                                  contained in the Vulkan header
+#   VulkanHeaders_VERSION_MINOR  - The Minor API version of the latest version
+#                                  contained in the Vulkan header
+#   VulkanHeaders_VERSION_PATCH  - The Patch API version of the latest version
+#                                  contained in the Vulkan header
+#
 # The module will also define two cache variables::
 #
 #   VulkanHeaders_INCLUDE_DIR    - the VulkanHeaders include directory
@@ -67,3 +74,61 @@
     VulkanRegistry_DIR)
 
 mark_as_advanced(VulkanHeaders_INCLUDE_DIR VulkanRegistry_DIR)
+
+# Determine the major/minor/patch version from the vulkan header
+set(VulkanHeaders_VERSION_MAJOR "0")
+set(VulkanHeaders_VERSION_MINOR "0")
+set(VulkanHeaders_VERSION_PATCH "0")
+
+# First, determine which header we need to grab the version information from.
+# Starting with Vulkan 1.1, we should use vulkan_core.h, but prior to that,
+# the information was in vulkan.h.
+if (EXISTS "${VulkanHeaders_INCLUDE_DIR}/vulkan/vulkan_core.h")
+    set(VulkanHeaders_main_header ${VulkanHeaders_INCLUDE_DIR}/vulkan/vulkan_core.h)
+else()
+    set(VulkanHeaders_main_header ${VulkanHeaders_INCLUDE_DIR}/vulkan/vulkan.h)
+endif()
+
+# Find all lines in the header file that contain any version we may be interested in
+#  NOTE: They start with #define and then have other keywords
+file(STRINGS
+        ${VulkanHeaders_main_header}
+        VulkanHeaders_lines
+        REGEX "^#define (VK_API_VERSION.*VK_MAKE_VERSION|VK_HEADER_VERSION)")
+
+foreach(VulkanHeaders_line ${VulkanHeaders_lines})
+
+    # First, handle the case where we have a major/minor version
+    #   Format is:
+    #        #define VK_API_VERSION_X_Y VK_MAKE_VERSION(X, Y, 0)
+    #   We grab the major version (X) and minor version (Y) out of the parentheses
+    string(REGEX MATCH "VK_MAKE_VERSION\\(.*\\)" VulkanHeaders_out ${VulkanHeaders_line})
+    string(REGEX MATCHALL "[0-9]+" VulkanHeaders_MAJOR_MINOR "${VulkanHeaders_out}")
+    if (VulkanHeaders_MAJOR_MINOR)
+        list (GET VulkanHeaders_MAJOR_MINOR 0 VulkanHeaders_cur_major)
+        list (GET VulkanHeaders_MAJOR_MINOR 1 VulkanHeaders_cur_minor)
+        if (${VulkanHeaders_cur_major} GREATER ${VulkanHeaders_VERSION_MAJOR})
+            set(VulkanHeaders_VERSION_MAJOR ${VulkanHeaders_cur_major})
+            set(VulkanHeaders_VERSION_MINOR ${VulkanHeaders_cur_minor})
+        endif()
+        if (${VulkanHeaders_cur_major} EQUAL ${VulkanHeaders_VERSION_MAJOR} AND
+            ${VulkanHeaders_cur_minor} GREATER ${VulkanHeaders_VERSION_MINOR})
+            set(VulkanHeaders_VERSION_MINOR ${VulkanHeaders_cur_minor})
+        endif()
+    endif()
+
+    # Second, handle the case where we have the patch version
+    #   Format is:
+    #      #define VK_HEADER_VERSION Z
+    #   Where Z is the patch version which we just grab off the end
+    string(REGEX MATCH "define.*VK_HEADER_VERSION.*[0-9]+" VulkanHeaders_out ${VulkanHeaders_line})
+    list(LENGTH VulkanHeaders_out VulkanHeaders_len)
+    if (VulkanHeaders_len)
+        string(REGEX MATCH "[0-9]+" VulkanHeaders_VERSION_PATCH "${VulkanHeaders_out}")
+    endif()
+
+endforeach()
+MESSAGE(STATUS
+        "Detected Vulkan Version ${VulkanHeaders_VERSION_MAJOR}."
+        "${VulkanHeaders_VERSION_MINOR}."
+        "${VulkanHeaders_VERSION_PATCH}")
diff --git a/icd/CMakeLists.txt b/icd/CMakeLists.txt
index c2c8b73..aefc3f7 100644
--- a/icd/CMakeLists.txt
+++ b/icd/CMakeLists.txt
@@ -65,6 +65,17 @@
 
 # Copy or link the JSON files to the binary directory for ease of use in the build tree.
 set(ICD_JSON_FILES VkICD_mock_icd)
+
+# The output file needs Unix "/" separators or Windows "\" separators
+# On top of that, Windows separators actually need to be doubled because the json format uses backslash escapes
+file(TO_NATIVE_PATH "./" RELATIVE_PATH_PREFIX)
+string(REPLACE "\\" "\\\\" RELATIVE_PATH_PREFIX "${RELATIVE_PATH_PREFIX}")
+
+# Run each .json.in file through the generator
+# We need to create the generator.cmake script so that the generator can be run at compile time, instead of configure time
+# Running at compile time lets us use cmake generator expressions (TARGET_FILE_NAME and TARGET_FILE_DIR, specifically)
+file(WRITE "${CMAKE_CURRENT_BINARY_DIR}/generator.cmake" "configure_file(\"\${INPUT_FILE}\" \"\${OUTPUT_FILE}\")")
+
 if(WIN32)
     # extra setup for out-of-tree builds
     if(NOT (CMAKE_CURRENT_SOURCE_DIR STREQUAL CMAKE_CURRENT_BINARY_DIR))
@@ -72,14 +83,28 @@
             foreach(config_file ${ICD_JSON_FILES})
                 file(TO_NATIVE_PATH ${CMAKE_CURRENT_SOURCE_DIR}/windows/${config_file}.json src_json)
                 file(TO_NATIVE_PATH ${CMAKE_CURRENT_BINARY_DIR}/$<CONFIGURATION>/${config_file}.json dst_json)
-                add_custom_target(${config_file}-json ALL COMMAND copy ${src_json} ${dst_json} VERBATIM)
+                set(CONFIG_DEFINES
+                    -DINPUT_FILE="${src_json}"
+                    -DVK_VERSION="${VulkanHeaders_VERSION_MAJOR}.${VulkanHeaders_VERSION_MINOR}.${VulkanHeaders_VERSION_PATCH}"
+                    -DOUTPUT_FILE="${dst_json}"
+                    -DRELATIVE_LAYER_BINARY="${RELATIVE_PATH_PREFIX}$<TARGET_FILE_NAME:${config_file}>"
+                )
+                add_custom_target(${config_file}-json ALL
+                    COMMAND ${CMAKE_COMMAND} ${CONFIG_DEFINES} -P "${CMAKE_CURRENT_BINARY_DIR}/generator.cmake")
                 set_target_properties(${config_file}-json PROPERTIES FOLDER ${TOOLS_TARGET_FOLDER})
             endforeach(config_file)
         else()
             foreach(config_file ${ICD_JSON_FILES})
                 file(TO_NATIVE_PATH ${CMAKE_CURRENT_SOURCE_DIR}/windows/${config_file}.json src_json)
                 file(TO_NATIVE_PATH ${CMAKE_CURRENT_BINARY_DIR}/${config_file}.json dst_json)
-                add_custom_target(${config_file}-json ALL COMMAND copy ${src_json} ${dst_json} VERBATIM)
+                set(CONFIG_DEFINES
+                    -DINPUT_FILE="${src_json}"
+                    -DVK_VERSION="${VulkanHeaders_VERSION_MAJOR}.${VulkanHeaders_VERSION_MINOR}.${VulkanHeaders_VERSION_PATCH}"
+                    -DOUTPUT_FILE="${dst_json}"
+                    -DRELATIVE_LAYER_BINARY="${RELATIVE_PATH_PREFIX}$<TARGET_FILE_NAME:${config_file}>"
+                )
+                add_custom_target(${config_file}-json ALL
+                    COMMAND ${CMAKE_COMMAND} ${CONFIG_DEFINES} -P "${CMAKE_CURRENT_BINARY_DIR}/generator.cmake")
             endforeach(config_file)
         endif()
     endif()
@@ -90,16 +115,30 @@
             add_custom_target(mk_icd_config_dir ALL
                               COMMAND ${CMAKE_COMMAND} -E make_directory ${CMAKE_CURRENT_BINARY_DIR}/$<CONFIG>)
             foreach(config_file ${ICD_JSON_FILES})
+                file(TO_NATIVE_PATH ${CMAKE_CURRENT_SOURCE_DIR}/macos/${config_file}.json src_json)
+                file(TO_NATIVE_PATH ${CMAKE_CURRENT_BINARY_DIR}/${config_file}.json dst_json)
+                set(CONFIG_DEFINES
+                    -DINPUT_FILE="${src_json}"
+                    -DVK_VERSION="${VulkanHeaders_VERSION_MAJOR}.${VulkanHeaders_VERSION_MINOR}.${VulkanHeaders_VERSION_PATCH}"
+                    -DOUTPUT_FILE="${dst_json}"
+                    -DRELATIVE_LAYER_BINARY="${RELATIVE_PATH_PREFIX}$<TARGET_FILE_NAME:${config_file}>"
+                )
                 add_custom_target(${config_file}-json ALL
                                   DEPENDS mk_icd_config_dir
-                                  COMMAND ln -sf ${CMAKE_CURRENT_SOURCE_DIR}/macos/${config_file}.json $<CONFIG>
-                                  VERBATIM)
+                                  COMMAND ${CMAKE_COMMAND} ${CONFIG_DEFINES} -P "${CMAKE_CURRENT_BINARY_DIR}/generator.cmake")
             endforeach(config_file)
         else()
             foreach(config_file ${ICD_JSON_FILES})
+                file(TO_NATIVE_PATH ${CMAKE_CURRENT_SOURCE_DIR}/macos/${config_file}.json src_json)
+                file(TO_NATIVE_PATH ${CMAKE_CURRENT_BINARY_DIR}/${config_file}.json dst_json)
+                set(CONFIG_DEFINES
+                    -DINPUT_FILE="${src_json}"
+                    -DVK_VERSION="${VulkanHeaders_VERSION_MAJOR}.${VulkanHeaders_VERSION_MINOR}.${VulkanHeaders_VERSION_PATCH}"
+                    -DOUTPUT_FILE="${dst_json}"
+                    -DRELATIVE_LAYER_BINARY="${RELATIVE_PATH_PREFIX}$<TARGET_FILE_NAME:${config_file}>"
+                )
                 add_custom_target(${config_file}-json ALL
-                                  COMMAND ln -sf ${CMAKE_CURRENT_SOURCE_DIR}/macos/${config_file}.json
-                                  VERBATIM)
+                                  COMMAND ${CMAKE_COMMAND} ${CONFIG_DEFINES} -P "${CMAKE_CURRENT_BINARY_DIR}/generator.cmake")
             endforeach(config_file)
         endif()
     endif()
@@ -107,7 +146,16 @@
     # extra setup for out-of-tree builds
     if(NOT (CMAKE_CURRENT_SOURCE_DIR STREQUAL CMAKE_CURRENT_BINARY_DIR))
         foreach(config_file ${ICD_JSON_FILES})
-            add_custom_target(${config_file}-json ALL COMMAND ln -sf ${CMAKE_CURRENT_SOURCE_DIR}/linux/${config_file}.json VERBATIM)
+            file(TO_NATIVE_PATH ${CMAKE_CURRENT_SOURCE_DIR}/linux/${config_file}.json src_json)
+            file(TO_NATIVE_PATH ${CMAKE_CURRENT_BINARY_DIR}/${config_file}.json dst_json)
+            set(CONFIG_DEFINES
+                -DINPUT_FILE="${src_json}"
+                -DVK_VERSION="${VulkanHeaders_VERSION_MAJOR}.${VulkanHeaders_VERSION_MINOR}.${VulkanHeaders_VERSION_PATCH}"
+                -DOUTPUT_FILE="${dst_json}"
+                -DRELATIVE_LAYER_BINARY="${RELATIVE_PATH_PREFIX}$<TARGET_FILE_NAME:${config_file}>"
+            )
+            add_custom_target(${config_file}-json ALL
+                COMMAND ${CMAKE_COMMAND} ${CONFIG_DEFINES} -P "${CMAKE_CURRENT_BINARY_DIR}/generator.cmake")
         endforeach(config_file)
     endif()
 endif()
diff --git a/icd/linux/VkICD_mock_icd.json b/icd/linux/VkICD_mock_icd.json
index f46060a..9315647 100644
--- a/icd/linux/VkICD_mock_icd.json
+++ b/icd/linux/VkICD_mock_icd.json
@@ -1,8 +1,8 @@
 {
     "file_format_version" : "1.0.1",
     "ICD": {
-        "library_path": "./libVkICD_mock_icd.so",
-        "api_version": "1.1.83"
+        "library_path": "@RELATIVE_LAYER_BINARY@",
+        "api_version": "@VK_VERSION@"
     }
 }
 
diff --git a/icd/macos/VkICD_mock_icd.json b/icd/macos/VkICD_mock_icd.json
index 8aebbf2..0a6fcad 100644
--- a/icd/macos/VkICD_mock_icd.json
+++ b/icd/macos/VkICD_mock_icd.json
@@ -1,8 +1,8 @@
 {
     "file_format_version" : "1.0.1",
     "ICD": {
-        "library_path": "./libVkICD_mock_icd.dylib",
-        "api_version": "1.1.83"
+        "library_path": "@RELATIVE_LAYER_BINARY@",
+        "api_version": "@VK_VERSION@",
     }
 }
 
diff --git a/icd/windows/VkICD_mock_icd.json b/icd/windows/VkICD_mock_icd.json
index 5549b4e..9315647 100644
--- a/icd/windows/VkICD_mock_icd.json
+++ b/icd/windows/VkICD_mock_icd.json
@@ -1,8 +1,8 @@
 {
     "file_format_version" : "1.0.1",
     "ICD": {
-        "library_path": ".\\VkICD_mock_icd.dll",
-        "api_version": "1.1.83"
+        "library_path": "@RELATIVE_LAYER_BINARY@",
+        "api_version": "@VK_VERSION@"
     }
 }