0028417: Using PRECOMPILED HEADER to speed up compilation time
[occt.git] / adm / genproj.tcl
index 237f05a..ef2f7e3 100644 (file)
@@ -108,9 +108,155 @@ proc osutils:findSrcSubPath {theSubPath} {
   return "$::THE_CASROOT/src/$theSubPath"
 }
 
+# Auxiliary tool comparing content of two files line-by-line.
+proc osutils:isEqualContent { theContent1 theContent2 } {
+  set aLen1 [llength $theContent1]
+  set aLen2 [llength $theContent2]
+  if { $aLen1 != $aLen2 } {
+    return false
+  }
+
+  for {set aLineIter 0} {$aLineIter < $aLen1} {incr aLineIter} {
+    set aLine1 [lindex $theContent1 $aLineIter]
+    set aLine2 [lindex $theContent2 $aLineIter]
+    if { $aLine1 != $aLine2 } {
+      return false
+    }
+  }
+  return true
+}
+
+# Auxiliary function for writing new file content only if it has been actually changed
+# (e.g. to preserve file timestamp on no change).
+# Useful for automatically (re)generated files.
+proc osutils:writeTextFile { theFile theContent {theEol lf} } {
+  if {[file exists "${theFile}"]} {
+    set aFileOld [open "${theFile}" rb]
+    fconfigure $aFileOld -translation crlf
+    set aLineListOld [split [read $aFileOld] "\n"]
+    close $aFileOld
+
+    # append empty line for proper comparison (which will be implicitly added by last puts below)
+    set aContent $theContent
+    lappend aContent ""
+    if { [osutils:isEqualContent $aLineListOld $aContent] == true } {
+      return false
+    }
+
+    file delete -force "${theFile}"
+  }
+
+  set anOutFile [open "$theFile" "w"]
+  fconfigure $anOutFile -translation $theEol
+  foreach aLine ${theContent} {
+    puts $anOutFile "${aLine}"
+  }
+  close $anOutFile
+  return true
+}
+
+# Function re-generating header files for specified text resource
+proc genResources { theResource } {
+  global path
+
+  set aResFileList {}
+  set aResourceAbsPath [file normalize "${path}/src/${theResource}"]
+  set aResourceDirectory ""
+  set isResDirectory false
+
+  if {[file isdirectory "${aResourceAbsPath}"]} {
+    if {[file exists "${aResourceAbsPath}/FILES"]} {
+      set aFilesFile [open "${aResourceAbsPath}/FILES" rb]
+      set aResFileList [split [read $aFilesFile] "\n"]
+      close $aFilesFile
+    }
+    set aResFileList [lsearch -inline -all -not -exact $aResFileList ""]
+    set aResourceDirectory "${theResource}"
+    set isResDirectory true
+  } else {
+    set aResourceName [file tail "${theResource}"]
+    lappend aResFileList "res:::${aResourceName}"
+    set aResourceDirectory [file dirname "${theResource}"]
+  }
+
+  foreach aResFileIter ${aResFileList} {
+    if {![regexp {^[^:]+:::(.+)} "${aResFileIter}" dump aResFileIter]} {
+         continue
+       }
+
+    set aResFileName [file tail "${aResFileIter}"]
+    regsub -all {\.} "${aResFileName}" {_} aResFileName
+    set aHeaderFileName "${aResourceDirectory}_${aResFileName}.pxx"
+    if { $isResDirectory == true && [lsearch $aResFileList $aHeaderFileName] == -1 } {
+      continue
+    }
+
+    # generate
+    set aContent {}
+    lappend aContent "// This file has been automatically generated from resource file src/${aResourceDirectory}/${aResFileIter}"
+       lappend aContent ""
+
+    # generate necessary structures
+    set aLineList {}
+    if {[file exists "${path}/src/${aResourceDirectory}/${aResFileIter}"]} {
+      set anInputFile [open "${path}/src/${aResourceDirectory}/${aResFileIter}" rb]
+      fconfigure $anInputFile -translation crlf
+      set aLineList [split [read $anInputFile] "\n"]
+      close $anInputFile
+    }
+
+    # drop empty trailing line
+    set anEndOfFile ""
+    if { [lindex $aLineList end] == "" } {
+      set aLineList [lreplace $aLineList end end]
+      set anEndOfFile "\\n"
+    }
+
+    lappend aContent "static const char ${aResourceDirectory}_${aResFileName}\[\] ="
+    set aNbLines  [llength $aLineList]
+    set aLastLine [expr $aNbLines - 1]
+    for {set aLineIter 0} {$aLineIter < $aNbLines} {incr aLineIter} {
+      set aLine [lindex $aLineList $aLineIter]
+      regsub -all {\"} "${aLine}" {\\"} aLine
+      if { $aLineIter == $aLastLine } {
+        lappend aContent "  \"${aLine}${anEndOfFile}\";"
+      } else {
+        lappend aContent "  \"${aLine}\\n\""
+      }
+    }
+
+    # Save generated content to header file
+    set aHeaderFilePath "${path}/src/${aResourceDirectory}/${aHeaderFileName}"
+    if { [osutils:writeTextFile $aHeaderFilePath $aContent] == true } {
+      puts "Generating header file from resource file: ${path}/src/${aResourceDirectory}/${aResFileIter}"
+    } else {
+         #puts "Header file from resource ${path}/src/${aResourceDirectory}/${aResFileIter} is up-to-date"
+    }
+  }
+}
+
+# Function re-generating header files for all text resources
+proc genAllResources {} {
+  global path
+  set aCasRoot [file normalize $path]
+  if {![file exists "$aCasRoot/adm/RESOURCES"]} {
+    puts "OCCT directory is not defined correctly: $aCasRoot"
+    return
+  }
+
+  set aFileResources [open "$aCasRoot/adm/RESOURCES" rb]
+  set anAdmResources [split [read $aFileResources] "\r\n"]
+  close $aFileResources
+  set anAdmResources [lsearch -inline -all -not -exact $anAdmResources ""]
+
+  foreach line $anAdmResources {
+    genResources "${line}"
+  }
+}
+
 # Wrapper-function to generate VS project files
 proc genproj {theIDE args} {
-  set aSupportedIDEs { "vc7" "vc8" "vc9" "vc10" "vc11" "vc12" "vc14" "cbp" "xcd" }
+  set aSupportedIDEs { "vc7" "vc8" "vc9" "vc10" "vc11" "vc12" "vc14" "vc14-uwp" "cbp" "xcd"}
   set aSupportedPlatforms { "wnt" "lin" "mac" "ios" "qnx" }
   set isHelpRequire false
 
@@ -159,14 +305,15 @@ proc genproj {theIDE args} {
     puts "usage: genproj IDE \[Platform\] \[-static\] \[-h|-help|--help\]
 
     IDE must be one of:
-      vc8   -  Visual Studio 2005
-      vc9   -  Visual Studio 2008
-      vc10  -  Visual Studio 2010
-      vc11  -  Visual Studio 2012
-      vc12  -  Visual Studio 2013
-      vc14  -  Visual Studio 2015
-      cbp   -  CodeBlocks
-      xcd   -  XCode
+      vc8      -  Visual Studio 2005
+      vc9      -  Visual Studio 2008
+      vc10     -  Visual Studio 2010
+      vc11     -  Visual Studio 2012
+      vc12     -  Visual Studio 2013
+      vc14     -  Visual Studio 2015
+      vc14-uwp -  Visual Studio 2015 for Universal Windows Platform project
+      cbp      -  CodeBlocks
+      xcd      -  XCode
 
     Platform (optional, only for CodeBlocks and XCode):
       wnt   -  Windows
@@ -193,6 +340,7 @@ proc genproj {theIDE args} {
   OS:MKPRC "$anAdmPath" "$theIDE" "$aLibType" "$aPlatform" "$aCmpl"
 
   genprojbat "$theIDE" $aPlatform
+  genAllResources
 }
 
 proc genprojbat {theIDE thePlatform} {
@@ -223,7 +371,7 @@ proc genprojbat {theIDE thePlatform} {
     file copy -force -- "$::THE_CASROOT/adm/templates/draw.${aTargetPlatformExt}" "$::path/draw.${aTargetPlatformExt}"
   }
 
-  if {[regexp {(vc)[0-9]*$} $theIDE] == 1} {
+  if {[regexp {(vc)[0-9]*$} $theIDE] == 1 || [regexp {(vc)[0-9]*-uwp$} $theIDE] == 1} {
     file copy -force -- "$::THE_CASROOT/adm/templates/msvc.bat" "$::path/msvc.bat"
   } else {
     switch -exact -- "$theIDE" {
@@ -266,7 +414,7 @@ proc OS:MKPRC { theOutDir theIDE theLibType thePlatform theCmpl } {
 
   # Create output directory
   set aWokStation "$thePlatform"
-  if { [lsearch -exact {vc7 vc8 vc9 vc10 vc11 vc12 vc14} $theIDE] != -1 } {
+  if { [lsearch -exact {vc7 vc8 vc9 vc10 vc11 vc12 vc14 vc14-uwp} $theIDE] != -1 } {
     set aWokStation "msvc"
   }
 
@@ -294,6 +442,14 @@ proc OS:MKPRC { theOutDir theIDE theLibType thePlatform theCmpl } {
     set aModules [osutils:juststation $goaway $aModules]
   }
 
+  # Draw module is turned off due to it is not supported on UWP
+  if { [regexp {(vc)[0-9]*-uwp$} $theIDE] == 1 } {
+    set aDrawIndex [lsearch -exact ${aModules} "Draw"]
+    if { ${aDrawIndex} != -1 } {
+      set aModules [lreplace ${aModules} ${aDrawIndex} ${aDrawIndex}]
+    }
+  }
+
   # generate one solution for all projects if complete OS or VAS is processed
   set anAllSolution "OCCT"
 
@@ -318,12 +474,13 @@ proc OS:MKPRC { theOutDir theIDE theLibType thePlatform theCmpl } {
     "vc7"   -
     "vc8"   -
     "vc9"   -
-    "vc10"   -
-    "vc11"   -
-    "vc12"   -
-    "vc14"  { OS:MKVC  $anOutDir $aModules $anAllSolution $theIDE }
-    "cbp"   { OS:MKCBP $anOutDir $aModules $anAllSolution $thePlatform $theCmpl }
-    "xcd"   {
+    "vc10"  -
+    "vc11"  -
+    "vc12"  -
+    "vc14"  -
+    "vc14-uwp" { OS:MKVC  $anOutDir $aModules $anAllSolution $theIDE }
+    "cbp"      { OS:MKCBP $anOutDir $aModules $anAllSolution $thePlatform $theCmpl }
+    "xcd"      {
       set ::THE_GUIDS_LIST($::aTKNullKey) "000000000000000000000000"
       OS:MKXCD $anOutDir $aModules $anAllSolution $theLibType $thePlatform
     }
@@ -659,6 +816,7 @@ proc osutils:collectinc {theModules theIncPath} {
     }
   }
 
+  set allHeaderFiles {}
   if { $aCopyType == "shortcut" } {
     # template preparation
     if { ![file exists $::THE_CASROOT/adm/templates/header.in] } {
@@ -672,11 +830,14 @@ proc osutils:collectinc {theModules theIncPath} {
 
     # create and copy short-cut header files
     foreach anUnit $anUnits {
-      set aHFiles [glob -nocomplain -dir $aCasRoot/src/$anUnit "*.h"]
-      foreach aHeaderFile [concat [glob -nocomplain -dir $aCasRoot/src/$anUnit "*.\[hgl\]xx"] $aHFiles] {
-        set aHeaderFileName [file tail $aHeaderFile]
+      osutils:checksrcfiles ${anUnit}
+
+      set aHFiles [_get_used_files ${anUnit} true false]
+      foreach aHeaderFile ${aHFiles} {
+        set aHeaderFileName [lindex ${aHeaderFile} 1]
+        lappend allHeaderFiles "${aHeaderFileName}"
 
-        regsub -all -- {@OCCT_HEADER_FILE@} $aHeaderTmpl "$aFromBuildIncToSrcPath/$anUnit/$aHeaderFileName" aShortCutHeaderFileContent
+        regsub -all -- {@OCCT_HEADER_FILE_CONTENT@} $aHeaderTmpl "#include \"$aFromBuildIncToSrcPath/$anUnit/$aHeaderFileName\"" aShortCutHeaderFileContent
 
         if {[file exists "$theIncPath/$aHeaderFileName"] && [file readable "$theIncPath/$aHeaderFileName"]} {
           set fp [open "$theIncPath/$aHeaderFileName" r]
@@ -706,12 +867,15 @@ proc osutils:collectinc {theModules theIncPath} {
   } else {
     set nbcopied 0
     foreach anUnit $anUnits {
-      set aHFiles [glob -nocomplain -dir $aCasRoot/src/$anUnit "*.h"]
-      foreach aHeaderFile [concat [glob -nocomplain -dir $aCasRoot/src/$anUnit "*.\[hgl\]xx"] $aHFiles] {
-        set aHeaderFileName [file tail $aHeaderFile]
+      osutils:checksrcfiles ${anUnit}
+
+      set aHFiles [_get_used_files ${anUnit} true false]
+      foreach aHeaderFile ${aHFiles} {
+        set aHeaderFileName [lindex ${aHeaderFile} 1]
+        lappend allHeaderFiles "${aHeaderFileName}"
 
         # copy file only if target does not exist or is older than original
-        set torig [file mtime $aHeaderFile]
+        set torig [file mtime $aCasRoot/src/$anUnit/$aHeaderFileName]
         set tcopy 0
         if { [file isfile $anIncPath/$aHeaderFileName] } {
           set tcopy [file mtime $anIncPath/$aHeaderFileName]
@@ -722,17 +886,26 @@ proc osutils:collectinc {theModules theIncPath} {
             if { $tcopy != 0 } {
               file delete -force "$theIncPath/$aHeaderFileName"
             }
-            file link -hard  $anIncPath/$aHeaderFileName $aHeaderFile
+            file link -hard  $anIncPath/$aHeaderFileName $aCasRoot/src/$anUnit/$aHeaderFileName
           } else {
-            file copy -force $aHeaderFile $anIncPath/$aHeaderFileName
+            file copy -force $aCasRoot/src/$anUnit/$aHeaderFileName $anIncPath/$aHeaderFileName
           }
         } elseif { $tcopy != $torig } {
-          puts "Warning: file $anIncPath/$aHeaderFileName is newer than $aHeaderFile, not changed!"
+          puts "Warning: file $anIncPath/$aHeaderFileName is newer than $aCasRoot/src/$anUnit/$aHeaderFileName, not changed!"
         }
       }
     }
     puts "Info: $nbcopied files updated"
   }
+
+  # remove header files not listed in FILES
+  set anIncFiles [glob -tails -nocomplain -dir ${anIncPath} "*"]
+  foreach anIncFile ${anIncFiles} {
+    if { [lsearch -exact ${allHeaderFiles} ${anIncFile}] == -1 } {
+      puts "Warning: file ${anIncPath}/${anIncFile} is not presented in the sources and will be removed from ${theIncPath}!"
+      file delete -force "${theIncPath}/${anIncFile}"
+    }
+  }
 }
 
 # Generate header for VS solution file
@@ -760,7 +933,7 @@ proc osutils:vcsolution:header { vcversion } {
     append var \
       "Microsoft Visual Studio Solution File, Format Version 13.00\n" \
       "# Visual Studio 2013\n"
-  } elseif { "$vcversion" == "vc14" } {
+  } elseif { "$vcversion" == "vc14"  || "$vcversion" == "vc14-uwp"} {
     append var \
       "Microsoft Visual Studio Solution File, Format Version 12.00\n" \
       "# Visual Studio 14\n"
@@ -997,19 +1170,51 @@ proc osutils:vcproj:readtemplate {theVcVer isexec} {
   set aVerExt "v${aVerExt}0"
   set aCmpl32 ""
   set aCmpl64 ""
+  set aCharSet "Unicode"
   if { $isexec } {
     set anExt "${anExt}x"
     set what "$what executable"
   }
   if { "$theVcVer" == "vc10" } {
     # SSE2 is enabled by default in vc11+, but not in vc10 for 32-bit target
-    set aCmpl32 "\n      <EnableEnhancedInstructionSet>StreamingSIMDExtensions2</EnableEnhancedInstructionSet>"
+    set aCmpl32 "<EnableEnhancedInstructionSet>StreamingSIMDExtensions2</EnableEnhancedInstructionSet>"
   }
   set aTmpl [osutils:readtemplate $anExt "MS VC++ project ($what)"]
-  regsub -all -- {__VCVER__}    $aTmpl $theVcVer aTmpl
-  regsub -all -- {__VCVEREXT__} $aTmpl $aVerExt  aTmpl
-  regsub -all -- {__VCMPL32__}  $aTmpl $aCmpl32  aTmpl
-  regsub -all -- {__VCMPL64__}  $aTmpl $aCmpl64  aTmpl
+
+  if { $theVcVer == "vc14-uwp" } {
+    set aVerExt "v140"
+    set UwpWinRt "<CompileAsWinRT>false</CompileAsWinRT>"
+    foreach bitness {32 64} {
+      set indent ""
+      if {"[set aCmpl${bitness}]" != ""} {
+        set indent "\n      "
+      }
+      set aCmpl${bitness} "[set aCmpl${bitness}]${indent}${UwpWinRt}"
+    }
+  }
+
+  set format_template "\[\\r\\n\\s\]*"
+  foreach bitness {32 64} {
+    set format_templateloc ""
+    if {"[set aCmpl${bitness}]" == ""} {
+      set format_templateloc "$format_template"
+    }
+    regsub -all -- "${format_templateloc}__VCMPL${bitness}__" $aTmpl "[set aCmpl${bitness}]" aTmpl
+  }
+
+  set aDebugInfo "no"
+  set aReleaseLnk ""
+  if { "$::HAVE_RelWithDebInfo" == "true" } {
+    set aDebugInfo "true"
+    set aReleaseLnk "\n      <OptimizeReferences>true</OptimizeReferences>\n      <EnableCOMDATFolding>true</EnableCOMDATFolding>"
+  }
+
+  regsub -all -- {__VCVER__}     $aTmpl $theVcVer aTmpl
+  regsub -all -- {__VCVEREXT__}  $aTmpl $aVerExt  aTmpl
+  regsub -all -- {__VCCHARSET__} $aTmpl $aCharSet aTmpl
+  regsub -all -- {__VCReleasePDB__} $aTmpl $aDebugInfo aTmpl
+  regsub -all -- "${format_template}__VCLNKREL__" $aTmpl "${aReleaseLnk}" aTmpl
+
   return $aTmpl
 }
 
@@ -1081,6 +1286,9 @@ proc osutils:csfList { theOS theCsfLibsMap theCsfFrmsMap } {
       set aLibsMap(CSF_FreeImagePlus) "freeimage"
     }
   }
+  if { "$::HAVE_FFMPEG" == "true" } {
+    set aLibsMap(CSF_FFmpeg) "avcodec avformat swscale avutil"
+  }
   if { "$::HAVE_GL2PS" == "true" } {
     set aLibsMap(CSF_GL2PS) "gl2ps"
   }
@@ -1094,6 +1302,12 @@ proc osutils:csfList { theOS theCsfLibsMap theCsfFrmsMap } {
       set aLibsMap(CSF_VTK) [osutils:vtkCsf "unix"]
     }
   }
+  if { "$::HAVE_ZLIB" == "true" } {
+    set aLibsMap(CSF_ZLIB) "zlib"
+  }
+  if { "$::HAVE_LIBLZMA" == "true" } {
+    set aLibsMap(CSF_LIBLZMA) "liblzma"
+  }
 
   if { "$theOS" == "wnt" } {
     #  WinAPI libraries
@@ -1104,12 +1318,10 @@ proc osutils:csfList { theOS theCsfLibsMap theCsfFrmsMap } {
     set aLibsMap(CSF_opengl32)     "opengl32"
     set aLibsMap(CSF_wsock32)      "wsock32"
     set aLibsMap(CSF_netapi32)     "netapi32"
-    set aLibsMap(CSF_AviLibs)      "ws2_32 vfw32"
     set aLibsMap(CSF_OpenGlLibs)   "opengl32"
     if { "$::HAVE_GLES2" == "true" } {
       set aLibsMap(CSF_OpenGlLibs) "libEGL libGLESv2"
     }
-    set aLibsMap(CSF_winspool)     "Winspool"
     set aLibsMap(CSF_psapi)        "Psapi"
     set aLibsMap(CSF_d3d9)         "d3d9"
 
@@ -1454,7 +1666,14 @@ proc osutils:vcproj { theVcVer theOutDir theToolKit theGuidsMap {theProjTmpl {}
   }
   regsub -all -- {__PROJECT_GUID__} $theProjTmpl $aGuidsMap($theToolKit) theProjTmpl
 
+  set theProjTmpl [osutils:uwp:proj ${theVcVer} ${theProjTmpl}]
+
   set aUsedLibs [list]
+
+  if { "$theVcVer" == "vc14-uwp" } {
+    lappend aUsedLibs "WindowsApp.lib"
+  }
+
   foreach tkx [osutils:commonUsedTK  $theToolKit] {
     lappend aUsedLibs "${tkx}.lib"
   }
@@ -2853,12 +3072,12 @@ proc osutils:xcdtk { theOutDir theToolKit theGuidsMap theIsStatic thePlatform {t
   if { "$thePlatform" == "ios" } {
     puts $aPbxprojFile "\t\t\t\t\"ARCHS\[sdk=iphoneos\*\]\" = \"\$(ARCHS_STANDARD)\";";
     puts $aPbxprojFile "\t\t\t\t\"ARCHS\[sdk=iphonesimulator\*\]\" = \"x86_64\";";
-    puts $aPbxprojFile "\t\t\t\tCLANG_CXX_LIBRARY = \"libc++\";"
     puts $aPbxprojFile "\t\t\t\tCLANG_ENABLE_MODULES = YES;"
     puts $aPbxprojFile "\t\t\t\tCLANG_ENABLE_OBJC_ARC = YES;"
   }
   puts $aPbxprojFile "\t\t\t\tARCHS = \"\$(ARCHS_STANDARD_64_BIT)\";"
-  puts $aPbxprojFile "\t\t\t\tCLANG_CXX_LANGUAGE_STANDARD = \"gnu++0x\";"
+  puts $aPbxprojFile "\t\t\t\tCLANG_CXX_LIBRARY = \"libc++\";"
+  puts $aPbxprojFile "\t\t\t\tCLANG_CXX_LANGUAGE_STANDARD = \"c++0x\";"
   puts $aPbxprojFile "\t\t\t\tCOPY_PHASE_STRIP = NO;"
   puts $aPbxprojFile "\t\t\t\tGCC_C_LANGUAGE_STANDARD = gnu99;"
   puts $aPbxprojFile "\t\t\t\tGCC_DYNAMIC_NO_PIC = NO;"
@@ -2896,12 +3115,12 @@ proc osutils:xcdtk { theOutDir theToolKit theGuidsMap theIsStatic thePlatform {t
   if { "$thePlatform" == "ios" } {
     puts $aPbxprojFile "\t\t\t\t\"ARCHS\[sdk=iphoneos\*\]\" = \"\$(ARCHS_STANDARD)\";";
     puts $aPbxprojFile "\t\t\t\t\"ARCHS\[sdk=iphonesimulator\*\]\" = \"x86_64\";";
-    puts $aPbxprojFile "\t\t\t\tCLANG_CXX_LIBRARY = \"libc++\";"
     puts $aPbxprojFile "\t\t\t\tCLANG_ENABLE_MODULES = YES;"
     puts $aPbxprojFile "\t\t\t\tCLANG_ENABLE_OBJC_ARC = YES;"
   }
   puts $aPbxprojFile "\t\t\t\tARCHS = \"\$(ARCHS_STANDARD_64_BIT)\";"
-  puts $aPbxprojFile "\t\t\t\tCLANG_CXX_LANGUAGE_STANDARD = \"gnu++0x\";"
+  puts $aPbxprojFile "\t\t\t\tCLANG_CXX_LIBRARY = \"libc++\";"
+  puts $aPbxprojFile "\t\t\t\tCLANG_CXX_LANGUAGE_STANDARD = \"c++0x\";"
   puts $aPbxprojFile "\t\t\t\tCOPY_PHASE_STRIP = YES;"
   puts $aPbxprojFile "\t\t\t\tGCC_C_LANGUAGE_STANDARD = gnu99;"
   puts $aPbxprojFile "\t\t\t\tGCC_ENABLE_OBJC_EXCEPTIONS = YES;"
@@ -3081,3 +3300,93 @@ proc osutils:xcdx { theOutDir theExecutable theGuidsMap } {
   puts $aPlistFile $aPlistTmpl
   close $aPlistFile
 }
+
+# Returns available Windows SDKs versions
+proc osutils:sdk { theSdkMajorVer {isQuietMode false} {theSdkDirectories {}} } {
+  if { ![llength ${theSdkDirectories}] } {
+    foreach anEnvVar { "ProgramFiles" "ProgramFiles\(x86\)" "ProgramW6432" } {
+      if {[ info exists ::env(${anEnvVar}) ]} {
+        lappend theSdkDirectories "$::env(${anEnvVar})/Windows Kits/${theSdkMajorVer}/Include"
+      }
+    }
+  }
+
+  set sdk_versions {}
+  foreach sdk_dir ${theSdkDirectories} {
+    if { [file isdirectory ${sdk_dir}] } {
+      lappend sdk_versions [glob -tails -directory "${sdk_dir}" -type d *]
+    }
+  }
+
+  if {![llength ${sdk_versions}] && !${isQuietMode}} {
+    error "Error : Could not find Windows SDK ${theSdkMajorVer}"
+  }
+
+  return [join [lsort -unique ${sdk_versions}] " "]
+}
+
+# Generate global properties to Visual Studio project file for UWP solution
+proc osutils:uwp:proj { theVcVer theProjTmpl } {
+
+  set uwp_properties ""
+  set uwp_generate_metadata ""
+  set uwp_app_container ""
+
+  set format_template ""
+
+  if { ${theVcVer} == "vc14-uwp" } {
+    set sdk_versions [osutils:sdk 10]
+    set sdk_max_ver [lindex ${sdk_versions} end]
+
+    set uwp_properties "<DefaultLanguage>en-US</DefaultLanguage>\n   \
+<ApplicationType>Windows Store</ApplicationType>\n   \
+<ApplicationTypeRevision>10.0</ApplicationTypeRevision>\n   \
+<MinimumVisualStudioVersion>14.0</MinimumVisualStudioVersion>\n   \
+<AppContainerApplication>true</AppContainerApplication>\n   \
+<WindowsTargetPlatformVersion>${sdk_max_ver}</WindowsTargetPlatformVersion>\n   \
+<WindowsTargetPlatformMinVersion>${sdk_max_ver}</WindowsTargetPlatformMinVersion>"
+
+    set uwp_generate_metadata        "<GenerateWindowsMetadata>false</GenerateWindowsMetadata>"
+
+    regsub -all -- {[\r\n\s]*<BasicRuntimeChecks>EnableFastChecks</BasicRuntimeChecks>} ${theProjTmpl} "" theProjTmpl
+  } else {
+    set format_template "\[\\r\\n\\s\]*"
+  }
+
+  regsub -all -- "${format_template}__UWP_PROPERTIES__"        ${theProjTmpl} "${uwp_properties}" theProjTmpl
+  regsub -all -- "${format_template}__UWP_GENERATE_METADATA__" ${theProjTmpl} "${uwp_generate_metadata}" theProjTmpl
+
+  return ${theProjTmpl}
+}
+
+# Report all files found in package directory but not listed in FILES
+proc osutils:checksrcfiles { theUnit } {
+  global path
+  set aCasRoot [file normalize ${path}]
+
+  if {![file isdirectory ${aCasRoot}]} {
+    puts "OCCT directory is not defined correctly: ${aCasRoot}"
+    return
+  }
+
+  set anUnitAbsPath [file normalize "${aCasRoot}/src/${theUnit}"]
+
+  if {[file exists "${anUnitAbsPath}/FILES"]} {
+    set aFilesFile [open "${anUnitAbsPath}/FILES" rb]
+    set aFilesFileList [split [read ${aFilesFile}] "\n"]
+    close ${aFilesFile}
+
+    set aFilesFileList [lsearch -inline -all -not -exact ${aFilesFileList} ""]
+
+    # report all files not listed in FILES
+    set anAllFiles [glob -tails -nocomplain -dir ${anUnitAbsPath} "*"]
+    foreach aFile ${anAllFiles} {
+      if { "${aFile}" == "FILES" } {
+        continue
+      }
+      if { [lsearch -exact ${aFilesFileList} ${aFile}] == -1 } {
+        puts "Warning: file ${anUnitAbsPath}/${aFile} is not listed in ${anUnitAbsPath}/FILES!"
+      }
+    }
+  }
+}