0029589: Configuration - allow MFC samples to be built when OCCT is linked statically
[occt.git] / adm / genproj.tcl
1 # =======================================================================
2 # Created on: 2014-07-24
3 # Created by: SKI
4 # Copyright (c) 2014 OPEN CASCADE SAS
5 #
6 # This file is part of Open CASCADE Technology software library.
7 #
8 # This library is free software; you can redistribute it and/or modify it under
9 # the terms of the GNU Lesser General Public License version 2.1 as published
10 # by the Free Software Foundation, with special exception defined in the file
11 # OCCT_LGPL_EXCEPTION.txt. Consult the file LICENSE_LGPL_21.txt included in OCCT
12 # distribution for complete text of the license and disclaimer of any warranty.
13 #
14 # Alternatively, this file may be used under the terms of Open CASCADE
15 # commercial license or contractual agreement.
16
17 # =======================================================================
18 # This script defines Tcl command genproj generating project files for 
19 # different IDEs and platforms. Run it with -help to get synopsis.
20 # =======================================================================
21
22 source [file join [file dirname [info script]] genconfdeps.tcl]
23
24 # the script is assumed to be run from CASROOT (or dependent Products root)
25 set path [file normalize .]
26 set THE_CASROOT ""
27 set fBranch ""
28 if { [info exists ::env(CASROOT)] } {
29   set THE_CASROOT [file normalize "$::env(CASROOT)"]
30 }
31
32 proc _get_options { platform type branch } {
33   set res ""
34   if {[file exists "$::THE_CASROOT/adm/CMPLRS"]} {
35     set fd [open "$::THE_CASROOT/adm/CMPLRS" rb]
36     set opts [split [read $fd] "\n"]
37     close $fd
38     foreach line $opts {
39       if {[regexp "^${platform} ${type} ${branch} (.+)$" $line dummy res]} {
40         while {[regexp {\(([^\(\)]+) ([^\(\)]+) ([^\(\)]+)\)(.+)} $res dummy p t b oldres]} {
41           set res "[_get_options $p $t $b] $oldres"
42         }
43       }
44     }
45   }
46   return $res
47 }
48
49 proc _get_type { name } {
50   set UDLIST {}
51   if {[file exists "$::path/adm/UDLIST"]} {
52     set fd [open "$::path/adm/UDLIST" rb]
53     set UDLIST [concat $UDLIST [split [read $fd] "\n"]]
54     close $fd
55   }
56   if { "$::path/adm/UDLIST" != "$::THE_CASROOT/adm/UDLIST" && [file exists "$::THE_CASROOT/adm/UDLIST"] } {
57     set fd [open "$::THE_CASROOT/adm/UDLIST" rb]
58     set UDLIST [concat $UDLIST [split [read $fd] "\n"]]
59     close $fd
60   }
61
62   foreach uitem $UDLIST {
63     set line [split $uitem]
64     if {[lindex $line 1] == "$name"} {
65       return [lindex $line 0]
66     }
67   }
68   return ""
69 }
70
71 proc _get_used_files { pk {inc true} {src true} } {
72   global path
73   set type [_get_type $pk]
74   set lret {}
75   set pk_path  "$path/src/$pk"
76   set FILES_path "$path/src/$pk/FILES"
77   set FILES {}
78   if {[file exists $FILES_path]} {
79     set fd [open $FILES_path rb]
80     set FILES [split [read $fd] "\n"]
81     close $fd
82   }
83   set FILES [lsearch -inline -all -not -exact $FILES ""]
84
85   set index -1
86   foreach line $FILES {
87     incr index
88     if {$inc && ([regexp {([^:\s]*\.[hgl]xx)$} $line dummy name] || [regexp {([^:\s]*\.h)$} $line dummy name]) && [file exists $pk_path/$name]} {
89       lappend lret "pubinclude $name $pk_path/$name"
90       continue
91     }
92     if {[regexp {:} $line]} {
93       regexp {[^:]*:+([^\s]*)} $line dummy line
94     }
95     regexp {([^\s]*)} $line dummy line
96     if {$src && [file exists $pk_path/$line]} {
97       lappend lret "source $line $pk_path/$line"
98     }
99   }
100   return $lret
101 }
102
103 # return location of the path within src directory
104 proc osutils:findSrcSubPath {theSubPath} {
105   if {[file exists "$::path/src/$theSubPath"]} {
106     return "$::path/src/$theSubPath"
107   }
108   return "$::THE_CASROOT/src/$theSubPath"
109 }
110
111 # Auxiliary tool comparing content of two files line-by-line.
112 proc osutils:isEqualContent { theContent1 theContent2 } {
113   set aLen1 [llength $theContent1]
114   set aLen2 [llength $theContent2]
115   if { $aLen1 != $aLen2 } {
116     return false
117   }
118
119   for {set aLineIter 0} {$aLineIter < $aLen1} {incr aLineIter} {
120     set aLine1 [lindex $theContent1 $aLineIter]
121     set aLine2 [lindex $theContent2 $aLineIter]
122     if { $aLine1 != $aLine2 } {
123       return false
124     }
125   }
126   return true
127 }
128
129 # Auxiliary function for writing new file content only if it has been actually changed
130 # (e.g. to preserve file timestamp on no change).
131 # Useful for automatically (re)generated files.
132 proc osutils:writeTextFile { theFile theContent {theEol lf} } {
133   if {[file exists "${theFile}"]} {
134     set aFileOld [open "${theFile}" rb]
135     fconfigure $aFileOld -translation crlf
136     set aLineListOld [split [read $aFileOld] "\n"]
137     close $aFileOld
138
139     # append empty line for proper comparison (which will be implicitly added by last puts below)
140     set aContent $theContent
141     lappend aContent ""
142     if { [osutils:isEqualContent $aLineListOld $aContent] == true } {
143       return false
144     }
145
146     file delete -force "${theFile}"
147   }
148
149   set anOutFile [open "$theFile" "w"]
150   fconfigure $anOutFile -translation $theEol
151   foreach aLine ${theContent} {
152     puts $anOutFile "${aLine}"
153   }
154   close $anOutFile
155   return true
156 }
157
158 # Function re-generating header files for specified text resource
159 proc genResources { theResource } {
160   global path
161
162   set aResFileList {}
163   set aResourceAbsPath [file normalize "${path}/src/${theResource}"]
164   set aResourceDirectory ""
165   set isResDirectory false
166
167   if {[file isdirectory "${aResourceAbsPath}"]} {
168     if {[file exists "${aResourceAbsPath}/FILES"]} {
169       set aFilesFile [open "${aResourceAbsPath}/FILES" rb]
170       set aResFileList [split [read $aFilesFile] "\n"]
171       close $aFilesFile
172     }
173     set aResFileList [lsearch -inline -all -not -exact $aResFileList ""]
174     set aResourceDirectory "${theResource}"
175     set isResDirectory true
176   } else {
177     set aResourceName [file tail "${theResource}"]
178     lappend aResFileList "res:::${aResourceName}"
179     set aResourceDirectory [file dirname "${theResource}"]
180   }
181
182   foreach aResFileIter ${aResFileList} {
183     if {![regexp {^[^:]+:::(.+)} "${aResFileIter}" dump aResFileIter]} {
184           continue
185         }
186
187     set aResFileName [file tail "${aResFileIter}"]
188     regsub -all {\.} "${aResFileName}" {_} aResFileName
189     set aHeaderFileName "${aResourceDirectory}_${aResFileName}.pxx"
190     if { $isResDirectory == true && [lsearch $aResFileList $aHeaderFileName] == -1 } {
191       continue
192     }
193
194     # generate
195     set aContent {}
196     lappend aContent "// This file has been automatically generated from resource file src/${aResourceDirectory}/${aResFileIter}"
197         lappend aContent ""
198
199     # generate necessary structures
200     set aLineList {}
201     if {[file exists "${path}/src/${aResourceDirectory}/${aResFileIter}"]} {
202       set anInputFile [open "${path}/src/${aResourceDirectory}/${aResFileIter}" rb]
203       fconfigure $anInputFile -translation crlf
204       set aLineList [split [read $anInputFile] "\n"]
205       close $anInputFile
206     }
207
208     # drop empty trailing line
209     set anEndOfFile ""
210     if { [lindex $aLineList end] == "" } {
211       set aLineList [lreplace $aLineList end end]
212       set anEndOfFile "\\n"
213     }
214
215     lappend aContent "static const char ${aResourceDirectory}_${aResFileName}\[\] ="
216     set aNbLines  [llength $aLineList]
217     set aLastLine [expr $aNbLines - 1]
218     for {set aLineIter 0} {$aLineIter < $aNbLines} {incr aLineIter} {
219       set aLine [lindex $aLineList $aLineIter]
220       regsub -all {\"} "${aLine}" {\\"} aLine
221       if { $aLineIter == $aLastLine } {
222         lappend aContent "  \"${aLine}${anEndOfFile}\";"
223       } else {
224         lappend aContent "  \"${aLine}\\n\""
225       }
226     }
227
228     # Save generated content to header file
229     set aHeaderFilePath "${path}/src/${aResourceDirectory}/${aHeaderFileName}"
230     if { [osutils:writeTextFile $aHeaderFilePath $aContent] == true } {
231       puts "Generating header file from resource file: ${path}/src/${aResourceDirectory}/${aResFileIter}"
232     } else {
233           #puts "Header file from resource ${path}/src/${aResourceDirectory}/${aResFileIter} is up-to-date"
234     }
235   }
236 }
237
238 # Function re-generating header files for all text resources
239 proc genAllResources {} {
240   global path
241   set aCasRoot [file normalize $path]
242   if {![file exists "$aCasRoot/adm/RESOURCES"]} {
243     puts "OCCT directory is not defined correctly: $aCasRoot"
244     return
245   }
246
247   set aFileResources [open "$aCasRoot/adm/RESOURCES" rb]
248   set anAdmResources [split [read $aFileResources] "\r\n"]
249   close $aFileResources
250   set anAdmResources [lsearch -inline -all -not -exact $anAdmResources ""]
251
252   foreach line $anAdmResources {
253     genResources "${line}"
254   }
255 }
256
257 # Wrapper-function to generate VS project files
258 proc genproj {theFormat args} {
259   set aSupportedFormats { "vc7" "vc8" "vc9" "vc10" "vc11" "vc12" "vc14" "vc141" "cbp" "xcd"}
260   set aSupportedPlatforms { "wnt" "uwp" "lin" "mac" "ios" "qnx" }
261   set isHelpRequire false
262
263   # check format argument
264   if { $theFormat == "-h" || $theFormat == "-help" || $theFormat == "--help" } {
265     set isHelpRequire true
266   } elseif { [lsearch -exact $aSupportedFormats $theFormat] < 0 } {
267     puts "Error: genproj: unrecognized project format \"$theFormat\""
268     set isHelpRequire true
269   }
270
271   # choice of compiler for Code::Blocks, currently hard-coded
272   set aCmpl "gcc"
273
274   # Determine default platform: wnt for vc*, mac for xcd, current for cbp
275   if { [regexp "^vc" $theFormat] } {
276     set aPlatform "wnt"
277   } elseif { $theFormat == "xcd" || $::tcl_platform(os) == "Darwin" } {
278     set aPlatform "mac"
279   } elseif { $::tcl_platform(platform) == "windows" } {
280     set aPlatform "wnt"
281   } elseif { $::tcl_platform(platform) == "unix" } {
282     set aPlatform "lin"
283   }
284
285   # Check optional arguments
286   set aLibType "dynamic"
287   foreach arg $args {
288     if { $arg == "-h" || $arg == "-help" || $arg == "--help" } {
289       set isHelpRequire true
290     } elseif { [lsearch -exact $aSupportedPlatforms $arg] >= 0 } {
291       set aPlatform $arg
292     } elseif { $arg == "-static" } {
293       set aLibType "static"
294       puts "Static build has been selected"
295     } elseif { $arg == "-dynamic" } {
296       set aLibType "dynamic"
297       puts "Dynamic build has been selected"
298     } else {
299       puts "Error: genproj: unrecognized option \"$arg\""
300       set isHelpRequire true
301     }
302   }
303
304   if {  $isHelpRequire == true } {
305     puts "usage: genproj Format \[Platform\] \[-static\] \[-h|-help|--help\]
306
307     Format must be one of:
308       vc8      -  Visual Studio 2005
309       vc9      -  Visual Studio 2008
310       vc10     -  Visual Studio 2010
311       vc11     -  Visual Studio 2012
312       vc12     -  Visual Studio 2013
313       vc14     -  Visual Studio 2015
314       vc141    -  Visual Studio 2017
315       cbp      -  CodeBlocks
316       xcd      -  XCode
317
318     Platform (optional):
319       wnt   -  Windows Desktop
320       uwp   -  Universal Windows Platform
321       lin   -  Linux
322       mac   -  OS X
323       ios   -  iOS
324       qnx   -  QNX
325
326     Option -static can be used with XCode to build static libraries
327     "
328     return
329   }
330
331   if { ! [info exists aPlatform] } {
332     puts "Error: genproj: Cannon identify default platform, please specify!"
333     return
334   }
335
336   puts "Preparing to generate $theFormat projects for $aPlatform platform..."
337
338   # base path to where to generate projects, hardcoded from current dir
339   set anAdmPath [file normalize "${::path}/adm"]
340
341   OS:MKPRC "$anAdmPath" "$theFormat" "$aLibType" "$aPlatform" "$aCmpl"
342
343   genprojbat "$theFormat" "$aPlatform"
344   genAllResources
345 }
346
347 # copy file providing warning if the target file exists and has 
348 # different date or size; if it is newer than source, save it as .bak
349 proc copy_with_warning {from to} {
350   if { [file exists "$to"] &&
351       ([file size   "$to"] != [file size  "$from"] ||
352        [file mtime  "$to"] != [file mtime "$from"]) } {
353     puts "Warning: file $to is updated (copied from $from)!"
354     if { [file mtime $to] > [file mtime $from] } {
355       puts "Info: old content of file $to is saved in ${to}.bak"
356       file copy -force -- "$to" "${to}.bak"
357     }
358   }
359
360   file copy -force -- "$from" "$to"
361 }
362
363 proc genprojbat {theFormat thePlatform} {
364   set aTargetPlatformExt sh
365   if { $thePlatform == "wnt" || $thePlatform == "uwp" } {
366     set aTargetPlatformExt bat
367   }
368
369   if {"$theFormat" != "cmake"} {
370     # copy env.bat/sh only if not yet present
371     if { ! [file exists "$::path/env.${aTargetPlatformExt}"] } {
372       set anEnvTmplFile [open "$::THE_CASROOT/adm/templates/env.${aTargetPlatformExt}" "r"]
373       set anEnvTmpl [read $anEnvTmplFile]
374       close $anEnvTmplFile
375
376       set aCasRoot ""
377       if { [file normalize "$::path"] != [file normalize "$::THE_CASROOT"] } {
378         set aCasRoot [relativePath "$::path" "$::THE_CASROOT"]
379       }
380
381       regsub -all -- {__CASROOT__}   $anEnvTmpl "$aCasRoot" anEnvTmpl
382
383       set anEnvFile [open "$::path/env.${aTargetPlatformExt}" "w"]
384       puts $anEnvFile $anEnvTmpl
385       close $anEnvFile
386     }
387
388     copy_with_warning "$::THE_CASROOT/adm/templates/draw.${aTargetPlatformExt}" "$::path/draw.${aTargetPlatformExt}"
389   }
390
391   if { [regexp {^vc} $theFormat] } {
392     copy_with_warning "$::THE_CASROOT/adm/templates/msvc.bat" "$::path/msvc.bat"
393   } else {
394     switch -exact -- "$theFormat" {
395       "cbp"   {
396         file copy -force -- "$::THE_CASROOT/adm/templates/codeblocks.sh"  "$::path/codeblocks.sh"
397         file copy -force -- "$::THE_CASROOT/adm/templates/codeblocks.bat" "$::path/codeblocks.bat"
398         # Code::Blocks 16.01 does not create directory for import libs, help him
399         file mkdir "$::path/$thePlatform/cbp/lib"
400         file mkdir "$::path/$thePlatform/cbp/libd"
401       }
402       "xcd"   { file copy -force -- "$::THE_CASROOT/adm/templates/xcode.sh"      "$::path/xcode.sh" }
403     }
404   }
405 }
406
407 ###### MSVC #############################################################33
408 proc removeAllOccurrencesOf { theObject theList } {
409   set aSortIndices [lsort -decreasing [lsearch -all -nocase $theList $theObject]]
410   foreach anIndex $aSortIndices {
411     set theList [lreplace $theList $anIndex $anIndex]
412   }
413   return $theList
414 }
415
416 set aTKNullKey "TKNull"
417 set THE_GUIDS_LIST($aTKNullKey) "{00000000-0000-0000-0000-000000000000}"
418
419 # Entry function to generate project files
420 # @param theOutDir   Root directory for project files
421 # @param theFormat   Project format name (vc.. for Visual Studio projects, cbp for Code::Blocks, xcd for XCode)
422 # @param theLibType  Library type - dynamic or static
423 # @param thePlatform Optional target platform for cross-compiling, e.g. ios for iOS
424 # @param theCmpl     Compiler option (msvc or gcc)
425 proc OS:MKPRC { theOutDir theFormat theLibType thePlatform theCmpl } {
426   global path
427   set anOutRoot $theOutDir
428   if { $anOutRoot == "" } {
429     error "Error : \"theOutDir\" is not initialized"
430   }
431
432   # Create output directory
433   set aWokStation "$thePlatform"
434   if { [regexp {^vc} $theFormat] } {
435     set aWokStation "msvc"
436   }
437   set aSuffix ""
438   set isUWP 0
439   if { $thePlatform == "uwp" } {
440     set aSuffix "-uwp"
441     set isUWP 1
442   }
443   set anOutDir "${anOutRoot}/${aWokStation}/${theFormat}${aSuffix}"
444
445   # read map of already generated GUIDs
446   set aGuidsFilePath [file join $anOutDir "wok_${theFormat}_guids.txt"]
447   if [file exists "$aGuidsFilePath"] {
448     set aFileIn [open "$aGuidsFilePath" r]
449     set aFileDataRaw [read $aFileIn]
450     close $aFileIn
451     set aFileData [split $aFileDataRaw "\n"]
452     foreach aLine $aFileData {
453       set aLineSplt [split $aLine "="]
454       if { [llength $aLineSplt] == 2 } {
455         set ::THE_GUIDS_LIST([lindex $aLineSplt 0]) [lindex $aLineSplt 1]
456       }
457     }
458   }
459
460   # make list of modules and platforms
461   set aModules [OS:init]
462   if { "$thePlatform" == "ios" } {
463     set goaway [list Draw]
464     set aModules [osutils:juststation $goaway $aModules]
465   }
466
467   # Draw module is turned off due to it is not supported on UWP
468   if { $isUWP } {
469     set aDrawIndex [lsearch -exact ${aModules} "Draw"]
470     if { ${aDrawIndex} != -1 } {
471       set aModules [lreplace ${aModules} ${aDrawIndex} ${aDrawIndex}]
472     }
473   }
474
475   # generate one solution for all projects if complete OS or VAS is processed
476   set anAllSolution "OCCT"
477
478   wokUtils:FILES:mkdir $anOutDir
479   if { ![file exists $anOutDir] } {
480     puts stderr "Error: Could not create output directory \"$anOutDir\""
481     return
482   }
483
484   # create the out dir if it does not exist
485   if (![file isdirectory $path/inc]) {
486     puts "$path/inc folder does not exists and will be created"
487     wokUtils:FILES:mkdir $path/inc
488   }
489
490   # collect all required header files
491   puts "Collecting required header files into $path/inc ..."
492   osutils:collectinc $aModules $path/inc
493
494   # Generating project files for the selected format
495   switch -exact -- "$theFormat" {
496     "vc7"   -
497     "vc8"   -
498     "vc9"   -
499     "vc10"  -
500     "vc11"  -
501     "vc12"  -
502     "vc14"  -
503     "vc141"    { OS:MKVC  $anOutDir $aModules $anAllSolution $theFormat $isUWP}
504     "cbp"      { OS:MKCBP $anOutDir $aModules $anAllSolution $thePlatform $theCmpl }
505     "xcd"      {
506       set ::THE_GUIDS_LIST($::aTKNullKey) "000000000000000000000000"
507       OS:MKXCD $anOutDir $aModules $anAllSolution $theLibType $thePlatform
508     }
509   }
510
511   # Store generated GUIDs map
512   set anOutFile [open "$aGuidsFilePath" "w"]
513   fconfigure $anOutFile -translation lf
514   foreach aKey [array names ::THE_GUIDS_LIST] {
515     set aValue $::THE_GUIDS_LIST($aKey)
516     puts $anOutFile "${aKey}=${aValue}"
517   }
518   close $anOutFile
519 }
520
521 # Function to generate Visual Studio solution and project files
522 proc OS:MKVC { theOutDir theModules theAllSolution theVcVer isUWP } {
523
524   puts stderr "Generating VS project files for $theVcVer"
525
526   # generate projects for toolkits and separate solution for each module
527   foreach aModule $theModules {
528     OS:vcsolution $theVcVer $aModule $aModule $theOutDir ::THE_GUIDS_LIST
529     OS:vcproj     $theVcVer $isUWP   $aModule $theOutDir ::THE_GUIDS_LIST
530   }
531
532   # generate single solution "OCCT" containing projects from all modules
533   if { "$theAllSolution" != "" } {
534     OS:vcsolution $theVcVer $theAllSolution $theModules $theOutDir ::THE_GUIDS_LIST
535   }
536
537   puts "The Visual Studio solution and project files are stored in the $theOutDir directory"
538 }
539
540 proc OS:init {{os {}}} {
541   set askplat $os
542   set aModules {}
543   if { "$os" == "" } {
544     set os $::tcl_platform(os)
545   }
546
547   if [file exists "$::path/src/VAS/Products.tcl"] {
548     source "$::path/src/VAS/Products.tcl"
549     foreach aModuleIter [VAS:Products] {
550       set aFileTcl "$::path/src/VAS/${aModuleIter}.tcl"
551       if [file exists $aFileTcl] {
552         source $aFileTcl
553         lappend aModules $aModuleIter
554       } else {
555         puts stderr "Definition file for module $aModuleIter is not found in unit VAS"
556       }
557     }
558     return $aModules
559   }
560
561   # Load list of OCCT modules and their definitions
562   source "$::path/src/OS/Modules.tcl"
563   foreach aModuleIter [OS:Modules] {
564     set aFileTcl "$::path/src/OS/${aModuleIter}.tcl"
565     if [file exists $aFileTcl] {
566       source $aFileTcl
567       lappend aModules $aModuleIter
568     } else {
569       puts stderr "Definition file for module $aModuleIter is not found in unit OS"
570     }
571   }
572
573   return $aModules
574 }
575
576 # topological sort. returns a list {  {a h} {b g} {c f} {c h} {d i}  } => { d a b c i g f h }
577 proc wokUtils:EASY:tsort { listofpairs } {
578     foreach x $listofpairs {
579         set e1 [lindex $x 0]
580         set e2 [lindex $x 1]
581         if ![info exists pcnt($e1)] {
582             set pcnt($e1) 0
583         }
584         if ![ info exists pcnt($e2)] {
585             set pcnt($e2) 1
586         } else {
587             incr pcnt($e2)
588         }
589         if ![info exists scnt($e1)] {
590             set scnt($e1) 1
591         } else {
592             incr scnt($e1)
593         }
594         set l {}
595         if [info exists slist($e1)] {
596             set l $slist($e1)
597         }
598         lappend l $e2
599         set slist($e1) $l
600     }
601     set nodecnt 0
602     set back 0
603     foreach node [array names pcnt] {
604         incr nodecnt
605         if { $pcnt($node) == 0 } {
606             incr back
607             set q($back) $node
608         }
609         if ![info exists scnt($node)] {
610             set scnt($node) 0
611         }
612     }
613     set res {}
614     for {set front 1} { $front <= $back } { incr front } {
615         lappend res [set node $q($front)]
616         for {set i 1} {$i <= $scnt($node) } { incr i } {
617             set ll $slist($node)
618             set j [expr {$i - 1}]
619             set u [expr { $pcnt([lindex $ll $j]) - 1 }]
620             if { [set pcnt([lindex $ll $j]) $u] == 0 } {
621                 incr back
622                 set q($back) [lindex $ll $j]
623             }
624         }
625     }
626     if { $back != $nodecnt } {
627         puts stderr "input contains a cycle"
628         return {}
629     } else {
630         return $res
631     }
632 }
633
634 proc wokUtils:LIST:Purge { l } {
635     set r {}
636      foreach e $l {
637          if ![info exist tab($e)] {
638              lappend r $e
639              set tab($e) {}
640          } 
641      }
642      return $r
643 }
644
645 # Read file pointed to by path
646 # 1. sort = 1 tri 
647 # 2. trim = 1 plusieurs blancs => 1 seul blanc
648 # 3. purge= not yet implemented.
649 # 4. emptl= dont process blank lines
650 proc wokUtils:FILES:FileToList { path {sort 0} {trim 0} {purge 0} {emptl 1} } {
651     if ![ catch { set id [ open $path r ] } ] {
652         set l  {}
653         while {[gets $id line] >= 0 } {
654             if { $trim } {
655                 regsub -all {[ ]+} $line " " line
656             }
657             if { $emptl } {
658                 if { [string length ${line}] != 0 } {
659                     lappend l $line
660                 }
661             } else {
662                 lappend l $line
663             }
664         }
665         close $id
666         if { $sort } {
667             return [lsort $l]
668         } else {
669             return $l
670         }
671     } else {
672         return {}
673     }
674 }
675
676 # retorn the list of executables in module.
677 proc OS:executable { module } {
678     set lret {}
679     foreach XXX  [${module}:ressources] {
680         if { "[lindex $XXX 1]" == "x" } {
681             lappend lret [lindex $XXX 2]
682         }
683     }
684     return $lret
685 }
686
687 # Topological sort of toolkits in tklm
688 proc osutils:tk:sort { tklm } {
689   set tkby2 {}
690   foreach tkloc $tklm {
691     set lprg [wokUtils:LIST:Purge [osutils:tk:close $tkloc]]
692     foreach tkx  $lprg {
693       if { [lsearch $tklm $tkx] != -1 } {
694         lappend tkby2 [list $tkx $tkloc]
695       } else {
696         lappend tkby2 [list $tkloc {}]
697       }
698     }
699   }
700   set lret {}
701   foreach e [wokUtils:EASY:tsort $tkby2] {
702     if { $e != {} } {
703       lappend lret $e
704     }
705   }
706   return $lret
707 }
708
709 #  close dependencies of ltk. (full wok pathes of toolkits)
710 # The CURRENT WOK LOCATION MUST contains ALL TOOLKITS required.
711 # (locate not performed.)
712 proc osutils:tk:close { ltk } {
713   set result {}
714   set recurse {}
715   foreach dir $ltk {
716     set ids [LibToLink $dir]
717 #    puts "osutils:tk:close($ltk) ids='$ids'"
718     set eated [osutils:tk:eatpk $ids]
719     set result [concat $result $eated]
720     set ids [LibToLink $dir]
721     set result [concat $result $ids]
722
723     foreach file $eated {
724       set kds [osutils:findSrcSubPath "$file/EXTERNLIB"]
725       if { [osutils:tk:eatpk $kds] !=  {} } {
726         lappend recurse $file
727       }
728     }
729   }
730   if { $recurse != {} } {
731     set result [concat $result [osutils:tk:close $recurse]]
732   }
733   return $result
734 }
735
736 proc osutils:tk:eatpk { EXTERNLIB  } {
737   set l [wokUtils:FILES:FileToList $EXTERNLIB]
738   set lret  {}
739   foreach str $l {
740     if ![regexp -- {(CSF_[^ ]*)} $str csf] {
741       lappend lret $str
742     }
743   }
744   return $lret
745 }
746 # Define libraries to link using only EXTERNLIB file
747
748 proc LibToLink {theTKit} {
749   regexp {^.*:([^:]+)$} $theTKit dummy theTKit
750   set type [_get_type $theTKit]
751   if {$type != "t" && $type != "x"} {
752     return
753   }
754   set aToolkits {}
755   set anExtLibList [osutils:tk:eatpk [osutils:findSrcSubPath "$theTKit/EXTERNLIB"]]
756   foreach anExtLib $anExtLibList {
757     set aFullPath [LocateRecur $anExtLib]
758     if { "$aFullPath" != "" && [_get_type $anExtLib] == "t" } {
759       lappend aToolkits $anExtLib
760     }
761   }
762   return $aToolkits
763 }
764 # Search unit recursively
765
766 proc LocateRecur {theName} {
767   set theNamePath [osutils:findSrcSubPath "$theName"]
768   if {[file isdirectory $theNamePath]} {
769     return $theNamePath
770   }
771   return ""
772 }
773
774 proc OS:genGUID { {theFormat "vc"} } {
775   if { "$theFormat" == "vc" } {
776     set p1 "[format %07X [expr { int(rand() * 268435456) }]][format %X [expr { int(rand() * 16) }]]"
777     set p2 "[format %04X [expr { int(rand() * 6536) }]]"
778     set p3 "[format %04X [expr { int(rand() * 6536) }]]"
779     set p4 "[format %04X [expr { int(rand() * 6536) }]]"
780     set p5 "[format %06X [expr { int(rand() * 16777216) }]][format %06X [expr { int(rand() * 16777216) }]]"
781     return "{$p1-$p2-$p3-$p4-$p5}"
782   } else {
783     set p1 "[format %04X [expr { int(rand() * 6536) }]]"
784     set p2 "[format %04X [expr { int(rand() * 6536) }]]"
785     set p3 "[format %04X [expr { int(rand() * 6536) }]]"
786     set p4 "[format %04X [expr { int(rand() * 6536) }]]"
787     set p5 "[format %04X [expr { int(rand() * 6536) }]]"
788     set p6 "[format %04X [expr { int(rand() * 6536) }]]"
789     return "$p1$p2$p3$p4$p5$p6"
790   }
791 }
792
793 # collect all include file that required for theModules in theOutDir
794 proc osutils:collectinc {theModules theIncPath} {
795   global path
796   set aCasRoot [file normalize $path]
797   set anIncPath [file normalize $theIncPath]
798
799   if {![file isdirectory $aCasRoot]} {
800     puts "OCCT directory is not defined correctly: $aCasRoot"
801     return
802   }
803
804   set anUsedToolKits {}
805   foreach aModule $theModules {
806     foreach aToolKit [${aModule}:toolkits] {
807       lappend anUsedToolKits $aToolKit
808
809       foreach aDependency [LibToLink $aToolKit] {
810         lappend anUsedToolKits $aDependency
811       }
812     }
813     foreach anExecutable [OS:executable ${aModule}] {
814       lappend anUsedToolKits $anExecutable
815
816       foreach aDependency [LibToLink $anExecutable] {
817         lappend anUsedToolKits $aDependency
818       }
819     }
820   }
821   set anUsedToolKits [lsort -unique $anUsedToolKits]
822
823   set anUnits {}
824   foreach anUsedToolKit $anUsedToolKits {
825     set anUnits [concat $anUnits [osutils:tk:units $anUsedToolKit]]
826   }
827   set anUnits [lsort -unique $anUnits]
828
829   # define copying style
830   set aCopyType "copy"
831   if { [info exists ::env(SHORTCUT_HEADERS)] } {
832     if { [string equal -nocase $::env(SHORTCUT_HEADERS) "hard"]
833       || [string equal -nocase $::env(SHORTCUT_HEADERS) "hardlink"] } {
834       set aCopyType "hardlink"
835     } elseif { [string equal -nocase $::env(SHORTCUT_HEADERS) "true"]
836             || [string equal -nocase $::env(SHORTCUT_HEADERS) "shortcut"] } {
837       set aCopyType "shortcut"
838     }
839   }
840
841   set allHeaderFiles {}
842   if { $aCopyType == "shortcut" } {
843     # template preparation
844     if { ![file exists $::THE_CASROOT/adm/templates/header.in] } {
845       puts "template file does not exist: $::THE_CASROOT/adm/templates/header.in"
846       return
847     }
848     set aHeaderTmpl [wokUtils:FILES:FileToString $::THE_CASROOT/adm/templates/header.in]
849
850     # relative anIncPath in connection with aCasRoot/src
851     set aFromBuildIncToSrcPath [relativePath "$anIncPath" "$aCasRoot/src"]
852
853     # create and copy short-cut header files
854     foreach anUnit $anUnits {
855       osutils:checksrcfiles ${anUnit}
856
857       set aHFiles [_get_used_files ${anUnit} true false]
858       foreach aHeaderFile ${aHFiles} {
859         set aHeaderFileName [lindex ${aHeaderFile} 1]
860         lappend allHeaderFiles "${aHeaderFileName}"
861
862         regsub -all -- {@OCCT_HEADER_FILE_CONTENT@} $aHeaderTmpl "#include \"$aFromBuildIncToSrcPath/$anUnit/$aHeaderFileName\"" aShortCutHeaderFileContent
863
864         if {[file exists "$theIncPath/$aHeaderFileName"] && [file readable "$theIncPath/$aHeaderFileName"]} {
865           set fp [open "$theIncPath/$aHeaderFileName" r]
866           set aHeaderContent [read $fp]
867           close $fp
868
869           # minus eof
870           set aHeaderLenght  [expr [string length $aHeaderContent] - 1]
871
872           if {$aHeaderLenght == [string length $aShortCutHeaderFileContent]} {
873             # remove eof from string
874             set aHeaderContent [string range $aHeaderContent 0 [expr $aHeaderLenght - 1]]
875
876             if {[string compare $aShortCutHeaderFileContent $aHeaderContent] == 0} {
877               continue
878             }
879           }
880           file delete -force "$theIncPath/$aHeaderFileName"
881         }
882
883         set aShortCutHeaderFile [open "$theIncPath/$aHeaderFileName" "w"]
884         fconfigure $aShortCutHeaderFile -translation lf
885         puts $aShortCutHeaderFile $aShortCutHeaderFileContent
886         close $aShortCutHeaderFile
887       }
888     }
889   } else {
890     set nbcopied 0
891     foreach anUnit $anUnits {
892       osutils:checksrcfiles ${anUnit}
893
894       set aHFiles [_get_used_files ${anUnit} true false]
895       foreach aHeaderFile ${aHFiles} {
896         set aHeaderFileName [lindex ${aHeaderFile} 1]
897         lappend allHeaderFiles "${aHeaderFileName}"
898
899         # copy file only if target does not exist or is older than original
900         set torig [file mtime $aCasRoot/src/$anUnit/$aHeaderFileName]
901         set tcopy 0
902         if { [file isfile $anIncPath/$aHeaderFileName] } {
903           set tcopy [file mtime $anIncPath/$aHeaderFileName]
904         }
905         if { $tcopy < $torig } {
906           incr nbcopied
907           if { $aCopyType == "hardlink" } {
908             if { $tcopy != 0 } {
909               file delete -force "$theIncPath/$aHeaderFileName"
910             }
911             file link -hard  $anIncPath/$aHeaderFileName $aCasRoot/src/$anUnit/$aHeaderFileName
912           } else {
913             file copy -force $aCasRoot/src/$anUnit/$aHeaderFileName $anIncPath/$aHeaderFileName
914           }
915         } elseif { $tcopy != $torig } {
916           puts "Warning: file $anIncPath/$aHeaderFileName is newer than $aCasRoot/src/$anUnit/$aHeaderFileName, not changed!"
917         }
918       }
919     }
920     puts "Info: $nbcopied files updated"
921   }
922
923   # remove header files not listed in FILES
924   set anIncFiles [glob -tails -nocomplain -dir ${anIncPath} "*"]
925   foreach anIncFile ${anIncFiles} {
926     if { [lsearch -exact ${allHeaderFiles} ${anIncFile}] == -1 } {
927       puts "Warning: file ${anIncPath}/${anIncFile} is not presented in the sources and will be removed from ${theIncPath}!"
928       file delete -force "${theIncPath}/${anIncFile}"
929     }
930   }
931 }
932
933 # Generate header for VS solution file
934 proc osutils:vcsolution:header { vcversion } {
935   if { "$vcversion" == "vc7" } {
936     append var \
937       "Microsoft Visual Studio Solution File, Format Version 8.00\n"
938   } elseif { "$vcversion" == "vc8" } {
939     append var \
940       "Microsoft Visual Studio Solution File, Format Version 9.00\n" \
941       "# Visual Studio 2005\n"
942   } elseif { "$vcversion" == "vc9" } {
943     append var \
944       "Microsoft Visual Studio Solution File, Format Version 10.00\n" \
945       "# Visual Studio 2008\n"
946   } elseif { "$vcversion" == "vc10" } {
947     append var \
948       "Microsoft Visual Studio Solution File, Format Version 11.00\n" \
949       "# Visual Studio 2010\n"
950   } elseif { "$vcversion" == "vc11" } {
951     append var \
952       "Microsoft Visual Studio Solution File, Format Version 12.00\n" \
953       "# Visual Studio 2012\n"
954   } elseif { "$vcversion" == "vc12" } {
955     append var \
956       "Microsoft Visual Studio Solution File, Format Version 12.00\n" \
957       "# Visual Studio 2013\n"
958   } elseif { "$vcversion" == "vc14"  || "$vcversion" == "vc141"} {
959     append var \
960       "Microsoft Visual Studio Solution File, Format Version 12.00\n" \
961       "# Visual Studio 14\n"
962   } else {
963     puts stderr "Error: Visual Studio version $vcversion is not supported by this function!"
964   }
965   return $var
966 }
967 # Returns extension (without dot) for project files of given version of VC
968
969 proc osutils:vcproj:ext { vcversion } {
970   if { "$vcversion" == "vc7" || "$vcversion" == "vc8" || "$vcversion" == "vc9" } {
971     return "vcproj"
972   } else {
973     return "vcxproj"
974   }
975 }
976 # Generate start of configuration section of VS solution file
977
978 proc osutils:vcsolution:config:begin { vcversion } {
979   if { "$vcversion" == "vc7" } {
980     append var \
981       "Global\n" \
982       "\tGlobalSection(SolutionConfiguration) = preSolution\n" \
983       "\t\tDebug = Debug\n" \
984       "\t\tRelease = Release\n" \
985       "\tEndGlobalSection\n" \
986       "\tGlobalSection(ProjectConfiguration) = postSolution\n"
987   } else {
988     append var \
989       "Global\n" \
990       "\tGlobalSection(SolutionConfigurationPlatforms) = preSolution\n" \
991       "\t\tDebug|Win32 = Debug|Win32\n" \
992       "\t\tRelease|Win32 = Release|Win32\n" \
993       "\t\tDebug|x64 = Debug|x64\n" \
994       "\t\tRelease|x64 = Release|x64\n" \
995       "\tEndGlobalSection\n" \
996       "\tGlobalSection(ProjectConfigurationPlatforms) = postSolution\n"
997   }
998   return $var
999 }
1000 # Generate part of configuration section of VS solution file describing one project
1001
1002 proc osutils:vcsolution:config:project { vcversion guid } {
1003   if { "$vcversion" == "vc7" } {
1004     append var \
1005       "\t\t$guid.Debug.ActiveCfg = Debug|Win32\n" \
1006       "\t\t$guid.Debug.Build.0 = Debug|Win32\n" \
1007       "\t\t$guid.Release.ActiveCfg = Release|Win32\n" \
1008       "\t\t$guid.Release.Build.0 = Release|Win32\n"
1009   } else {
1010     append var \
1011       "\t\t$guid.Debug|Win32.ActiveCfg = Debug|Win32\n" \
1012       "\t\t$guid.Debug|Win32.Build.0 = Debug|Win32\n" \
1013       "\t\t$guid.Release|Win32.ActiveCfg = Release|Win32\n" \
1014       "\t\t$guid.Release|Win32.Build.0 = Release|Win32\n" \
1015       "\t\t$guid.Debug|x64.ActiveCfg = Debug|x64\n" \
1016       "\t\t$guid.Debug|x64.Build.0 = Debug|x64\n" \
1017       "\t\t$guid.Release|x64.ActiveCfg = Release|x64\n" \
1018       "\t\t$guid.Release|x64.Build.0 = Release|x64\n"
1019   }
1020   return $var
1021 }
1022 # Generate start of configuration section of VS solution file
1023
1024 proc osutils:vcsolution:config:end { vcversion } {
1025   if { "$vcversion" == "vc7" } {
1026     append var \
1027       "\tEndGlobalSection\n" \
1028       "\tGlobalSection(ExtensibilityGlobals) = postSolution\n" \
1029       "\tEndGlobalSection\n" \
1030       "\tGlobalSection(ExtensibilityAddIns) = postSolution\n" \
1031       "\tEndGlobalSection\n"
1032   } else {
1033     append var \
1034       "\tEndGlobalSection\n" \
1035       "\tGlobalSection(SolutionProperties) = preSolution\n" \
1036       "\t\tHideSolutionNode = FALSE\n" \
1037       "\tEndGlobalSection\n"
1038   }
1039   return $var
1040 }
1041 # generate Visual Studio solution file
1042 # if module is empty, generates one solution for all known modules
1043
1044 proc OS:vcsolution { theVcVer theSolName theModules theOutDir theGuidsMap } {
1045   global path
1046   upvar $theGuidsMap aGuidsMap
1047
1048   # collect list of projects to be created
1049   set aProjects {}
1050   set aDependencies {}
1051   foreach aModule $theModules {
1052     # toolkits
1053     foreach aToolKit [osutils:tk:sort [${aModule}:toolkits]] {
1054       lappend aProjects $aToolKit
1055       lappend aProjectsInModule($aModule) $aToolKit
1056       lappend aDependencies [LibToLink $aToolKit]
1057     }
1058     # executables, assume one project per cxx file...
1059     foreach aUnit [OS:executable ${aModule}] {
1060       set aUnitLoc $aUnit
1061       set src_files [_get_used_files $aUnit false]
1062       set aSrcFiles {}
1063       foreach s $src_files {
1064         regexp {source ([^\s]+)} $s dummy name
1065         lappend aSrcFiles $name
1066       }
1067       foreach aSrcFile $aSrcFiles {
1068         set aFileExtension [file extension $aSrcFile]
1069         if { $aFileExtension == ".cxx" } {
1070           set aPrjName [file rootname $aSrcFile]
1071           lappend aProjects $aPrjName
1072           lappend aProjectsInModule($aModule) $aPrjName
1073           if {[file isdirectory $path/src/$aUnitLoc]} {
1074             lappend aDependencies [LibToLinkX $aUnitLoc [file rootname $aSrcFile]]
1075           } else {
1076             lappend aDependencies {}
1077           }
1078         }
1079       }
1080     }
1081   }
1082
1083 # generate GUIDs for projects (unless already known)
1084   foreach aProject $aProjects {
1085     if { ! [info exists aGuidsMap($aProject)] } {
1086       set aGuidsMap($aProject) [OS:genGUID]
1087     }
1088   }
1089
1090   # generate solution file
1091 #  puts "Generating Visual Studio ($theVcVer) solution file for $theSolName ($aProjects)"
1092   append aFileBuff [osutils:vcsolution:header $theVcVer]
1093
1094   # GUID identifying group projects in Visual Studio
1095   set VC_GROUP_GUID "{2150E333-8FDC-42A3-9474-1A3956D46DE8}"
1096
1097   # generate group projects -- one per module
1098   if { "$theVcVer" != "vc7" && [llength "$theModules"] > 1 } {
1099     foreach aModule $theModules {
1100       if { ! [info exists aGuidsMap(_$aModule)] } {
1101         set aGuidsMap(_$aModule) [OS:genGUID]
1102       }
1103       set aGuid $aGuidsMap(_$aModule)
1104       append aFileBuff "Project(\"${VC_GROUP_GUID}\") = \"$aModule\", \"$aModule\", \"$aGuid\"\nEndProject\n"
1105     }
1106   }
1107
1108   # extension of project files
1109   set aProjExt [osutils:vcproj:ext $theVcVer]
1110
1111   # GUID identifying C++ projects in Visual Studio
1112   set VC_CPP_GUID "{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}"
1113
1114   # generate normal projects
1115   set aProjsNb [llength $aProjects]
1116   for {set aProjId 0} {$aProjId < $aProjsNb} {incr aProjId} {
1117     set aProj [lindex $aProjects $aProjId]
1118     set aGuid $aGuidsMap($aProj)
1119     append aFileBuff "Project(\"${VC_CPP_GUID}\") = \"$aProj\", \"$aProj.${aProjExt}\", \"$aGuid\"\n"
1120     # write projects dependencies information (vc7 to vc9)
1121     set aDepGuids ""
1122     foreach aDepLib [lindex $aDependencies $aProjId] {
1123       if { $aDepLib != $aProj && [lsearch $aProjects $aDepLib] != "-1" } {
1124         set depGUID $aGuidsMap($aDepLib)
1125         append aDepGuids "\t\t$depGUID = $depGUID\n"
1126       }
1127     }
1128     if { "$aDepGuids" != "" } {
1129       append aFileBuff "\tProjectSection(ProjectDependencies) = postProject\n"
1130       append aFileBuff "$aDepGuids"
1131       append aFileBuff "\tEndProjectSection\n"
1132     }
1133     append aFileBuff "EndProject\n"
1134   }
1135
1136   # generate configuration section
1137   append aFileBuff [osutils:vcsolution:config:begin $theVcVer]
1138   foreach aProj $aProjects {
1139     append aFileBuff [osutils:vcsolution:config:project $theVcVer $aGuidsMap($aProj)]
1140   }
1141   append aFileBuff [osutils:vcsolution:config:end $theVcVer]
1142
1143   # write information of grouping of projects by module
1144   if { "$theVcVer" != "vc7" && [llength "$theModules"] > 1 } {
1145     append aFileBuff "  GlobalSection(NestedProjects) = preSolution\n"
1146     foreach aModule $theModules {
1147       if { ! [info exists aProjectsInModule($aModule)] } { continue }
1148       foreach aProject $aProjectsInModule($aModule) {
1149         append aFileBuff "              $aGuidsMap($aProject) = $aGuidsMap(_$aModule)\n"
1150       }
1151     }
1152     append aFileBuff "  EndGlobalSection\n"
1153   }
1154
1155   # final word (footer)
1156   append aFileBuff "EndGlobal"
1157
1158   # write solution
1159   set aFile [open [set fdsw [file join $theOutDir ${theSolName}.sln]] w]
1160   fconfigure $aFile -translation crlf
1161   puts $aFile $aFileBuff
1162   close $aFile
1163   return [file join $theOutDir ${theSolName}.sln]
1164 }
1165 # Generate Visual Studio projects for specified version
1166
1167 proc OS:vcproj { theVcVer isUWP theModules theOutDir theGuidsMap } {
1168   upvar $theGuidsMap aGuidsMap
1169
1170   set aProjectFiles {}
1171
1172   foreach aModule $theModules {
1173     foreach aToolKit [${aModule}:toolkits] {
1174       lappend aProjectFiles [osutils:vcproj  $theVcVer $isUWP $theOutDir $aToolKit     aGuidsMap]
1175     }
1176     foreach anExecutable [OS:executable ${aModule}] {
1177       lappend aProjectFiles [osutils:vcprojx $theVcVer $isUWP $theOutDir $anExecutable aGuidsMap]
1178     }
1179   }
1180   return $aProjectFiles
1181 }
1182 # generate template name and load it for given version of Visual Studio and platform
1183
1184 proc osutils:vcproj:readtemplate {theVcVer isUWP isExec} {
1185   set anExt $theVcVer
1186   if { "$theVcVer" != "vc7" && "$theVcVer" != "vc8" && "$theVcVer" != "vc9" } {
1187     set anExt vc10
1188   }
1189
1190   # determine versions of runtime and toolset
1191   set aVCRTVer $theVcVer 
1192   set aToolset "v[string range $theVcVer 2 3]0"
1193   if { $theVcVer == "vc141" } {
1194     set aVCRTVer "vc14"
1195     set aToolset "v141"
1196   }
1197
1198   set what "$theVcVer"
1199   set aCmpl32 ""
1200   set aCmpl64 ""
1201   set aCharSet "Unicode"
1202   if { $isExec } {
1203     set anExt "${anExt}x"
1204     set what "$what executable"
1205   }
1206   if { "$theVcVer" == "vc10" } {
1207     # SSE2 is enabled by default in vc11+, but not in vc10 for 32-bit target
1208     set aCmpl32 "<EnableEnhancedInstructionSet>StreamingSIMDExtensions2</EnableEnhancedInstructionSet>"
1209   }
1210   set aTmpl [osutils:readtemplate $anExt "MS VC++ project ($what)"]
1211
1212   if { $isUWP } {
1213     set UwpWinRt "<CompileAsWinRT>false</CompileAsWinRT>"
1214     foreach bitness {32 64} {
1215       set indent ""
1216       if {"[set aCmpl${bitness}]" != ""} {
1217         set indent "\n      "
1218       }
1219       set aCmpl${bitness} "[set aCmpl${bitness}]${indent}${UwpWinRt}"
1220     }
1221   }
1222
1223   set format_template "\[\\r\\n\\s\]*"
1224   foreach bitness {32 64} {
1225     set format_templateloc ""
1226     if {"[set aCmpl${bitness}]" == ""} {
1227       set format_templateloc "$format_template"
1228     }
1229     regsub -all -- "${format_templateloc}__VCMPL${bitness}__" $aTmpl "[set aCmpl${bitness}]" aTmpl
1230   }
1231
1232   set aDebugInfo "no"
1233   set aReleaseLnk ""
1234   if { "$::HAVE_RelWithDebInfo" == "true" } {
1235     set aDebugInfo "true"
1236     set aReleaseLnk "\n      <OptimizeReferences>true</OptimizeReferences>\n      <EnableCOMDATFolding>true</EnableCOMDATFolding>"
1237   }
1238
1239   regsub -all -- {__VCVER__}     $aTmpl $aVCRTVer aTmpl
1240   regsub -all -- {__VCVEREXT__}  $aTmpl $aToolset aTmpl
1241   regsub -all -- {__VCCHARSET__} $aTmpl $aCharSet aTmpl
1242   regsub -all -- {__VCReleasePDB__} $aTmpl $aDebugInfo aTmpl
1243   regsub -all -- "${format_template}__VCLNKREL__" $aTmpl "${aReleaseLnk}" aTmpl
1244
1245   return $aTmpl
1246 }
1247
1248 proc osutils:readtemplate {ext what} {
1249   set loc "$::THE_CASROOT/adm/templates/template.$ext"
1250   return [wokUtils:FILES:FileToString $loc]
1251 }
1252 # Read a file in a string as is.
1253
1254 proc wokUtils:FILES:FileToString { fin } {
1255     if { [catch { set in [ open $fin r ] } errin] == 0 } {
1256         set strin [read $in [file size $fin]]
1257         close $in
1258         return $strin
1259     } else {
1260         return {}
1261     }
1262 }
1263
1264 # List extensions of compilable files in OCCT
1265 proc osutils:compilable {thePlatform} {
1266   if { "$thePlatform" == "mac" || "$thePlatform" == "ios" } {
1267     return [list .c .cxx .cpp .mm]
1268   }
1269   return [list .c .cxx .cpp]
1270 }
1271
1272 proc osutils:commonUsedTK { theToolKit } {
1273   set anUsedToolKits [list]
1274   set aDepToolkits [LibToLink $theToolKit]
1275   foreach tkx $aDepToolkits {
1276     if {[_get_type $tkx] == "t"} {
1277       lappend anUsedToolKits "${tkx}"
1278     }
1279   }
1280   return $anUsedToolKits
1281 }
1282
1283 # Return the list of name *CSF_ in a EXTERNLIB description of a toolkit
1284 proc osutils:tk:csfInExternlib { EXTERNLIB } {
1285   set l [wokUtils:FILES:FileToList $EXTERNLIB]
1286   set lret  {STLPort}
1287   foreach str $l {
1288     if [regexp -- {(CSF_[^ ]*)} $str csf] {
1289       lappend lret $csf
1290     }
1291   }
1292   return $lret
1293 }
1294
1295 # Collect dependencies map depending on target OS (libraries for CSF_ codenames used in EXTERNLIB) .
1296 # @param theOS         - target OS
1297 # @param theCsfLibsMap - libraries  map
1298 # @param theCsfFrmsMap - frameworks map, OS X specific
1299 proc osutils:csfList { theOS theCsfLibsMap theCsfFrmsMap } {
1300   upvar $theCsfLibsMap aLibsMap
1301   upvar $theCsfFrmsMap aFrmsMap
1302
1303   unset theCsfLibsMap
1304   unset theCsfFrmsMap
1305
1306   set aLibsMap(CSF_FREETYPE)  "freetype"
1307   set aLibsMap(CSF_TclLibs)   "tcl8.6"
1308   set aLibsMap(CSF_TclTkLibs) "tk8.6"
1309   if { "$::HAVE_FREEIMAGE" == "true" } {
1310     if { "$theOS" == "wnt" } {
1311       set aLibsMap(CSF_FreeImagePlus) "FreeImage"
1312     } else {
1313       set aLibsMap(CSF_FreeImagePlus) "freeimage"
1314     }
1315   } elseif { "$theOS" == "wnt" } {
1316     set aLibsMap(CSF_FreeImagePlus) "windowscodecs"
1317   }
1318   if { "$::HAVE_FFMPEG" == "true" } {
1319     set aLibsMap(CSF_FFmpeg) "avcodec avformat swscale avutil"
1320   }
1321   if { "$::HAVE_GL2PS" == "true" } {
1322     set aLibsMap(CSF_GL2PS) "gl2ps"
1323   }
1324   if { "$::HAVE_TBB" == "true" } {
1325     set aLibsMap(CSF_TBB) "tbb tbbmalloc"
1326   }
1327   if { "$::HAVE_VTK" == "true" } {
1328     if { "$theOS" == "wnt" } {
1329       set aLibsMap(CSF_VTK) [osutils:vtkCsf "wnt"]
1330     } else {
1331       set aLibsMap(CSF_VTK) [osutils:vtkCsf "unix"]
1332     }
1333   }
1334   if { "$::HAVE_ZLIB" == "true" } {
1335     set aLibsMap(CSF_ZLIB) "zlib"
1336   }
1337   if { "$::HAVE_LIBLZMA" == "true" } {
1338     set aLibsMap(CSF_LIBLZMA) "liblzma"
1339   }
1340
1341   if { "$theOS" == "wnt" } {
1342     #  WinAPI libraries
1343     set aLibsMap(CSF_kernel32)     "kernel32"
1344     set aLibsMap(CSF_advapi32)     "advapi32"
1345     set aLibsMap(CSF_gdi32)        "gdi32"
1346     set aLibsMap(CSF_user32)       "user32 comdlg32"
1347     set aLibsMap(CSF_opengl32)     "opengl32"
1348     set aLibsMap(CSF_wsock32)      "wsock32"
1349     set aLibsMap(CSF_netapi32)     "netapi32"
1350     set aLibsMap(CSF_OpenGlLibs)   "opengl32"
1351     if { "$::HAVE_GLES2" == "true" } {
1352       set aLibsMap(CSF_OpenGlLibs) "libEGL libGLESv2"
1353     }
1354     set aLibsMap(CSF_psapi)        "Psapi"
1355     set aLibsMap(CSF_d3d9)         "d3d9"
1356
1357     # the naming is different on Windows
1358     set aLibsMap(CSF_TclLibs)      "tcl86"
1359     set aLibsMap(CSF_TclTkLibs)    "tk86"
1360
1361     set aLibsMap(CSF_QT)           "QtCore4 QtGui4"
1362
1363     # tbb headers define different pragma lib depending on debug/release
1364     set aLibsMap(CSF_TBB) ""
1365   } else {
1366     set aLibsMap(CSF_dl)           "dl"
1367     if { "$theOS" == "mac" } {
1368       set aLibsMap(CSF_objc)       "objc"
1369       set aFrmsMap(CSF_Appkit)     "AppKit"
1370       set aFrmsMap(CSF_IOKit)      "IOKit"
1371       set aFrmsMap(CSF_OpenGlLibs) "OpenGL"
1372       set aFrmsMap(CSF_TclLibs)    "Tcl"
1373       set aLibsMap(CSF_TclLibs)    ""
1374       set aFrmsMap(CSF_TclTkLibs)  "Tk"
1375       set aLibsMap(CSF_TclTkLibs)  ""
1376       set aLibsMap(CSF_QT)         "QtCore QtGui"
1377     } else {
1378       if { "$theOS" == "qnx" } {
1379         # CSF_ThreadLibs - pthread API is part of libc on QNX
1380         set aLibsMap(CSF_OpenGlLibs) "EGL GLESv2"
1381       } else {
1382         set aLibsMap(CSF_ThreadLibs) "pthread rt"
1383         set aLibsMap(CSF_OpenGlLibs) "GL"
1384         set aLibsMap(CSF_TclTkLibs)  "X11 tk8.6"
1385         set aLibsMap(CSF_XwLibs)     "X11 Xext Xmu Xi"
1386         set aLibsMap(CSF_MotifLibs)  "X11"
1387       }
1388
1389       if { "$::HAVE_GLES2" == "true" } {
1390         set aLibsMap(CSF_OpenGlLibs) "EGL GLESv2"
1391       }
1392     }
1393   }
1394 }
1395
1396 # Returns string of library dependencies for generation of Visual Studio project or make lists.
1397 proc osutils:vtkCsf {{theOS ""}} {
1398   set aVtkVer "6.1"
1399
1400   set aPathSplitter ":"
1401   if {"$theOS" == "wnt"} {
1402     set aPathSplitter ";"
1403   }
1404
1405   set anOptIncs [split $::env(CSF_OPT_INC) "$aPathSplitter"]
1406   foreach anIncItem $anOptIncs {
1407     if {[regexp -- "vtk-(.*)$" [file tail $anIncItem] dummy aFoundVtkVer]} {
1408       set aVtkVer $aFoundVtkVer
1409     }
1410   }
1411
1412   set aLibArray [list vtkCommonCore vtkCommonDataModel vtkCommonExecutionModel vtkCommonMath vtkCommonTransforms vtkRenderingCore \
1413                       vtkRenderingOpenGL  vtkFiltersGeneral vtkIOCore vtkIOImage vtkImagingCore vtkInteractionStyle]
1414
1415   # Additional suffices for the libraries
1416   set anIdx 0
1417   foreach anItem $aLibArray {
1418     lset aLibArray $anIdx $anItem-$aVtkVer
1419     incr anIdx
1420   }
1421
1422   return [join $aLibArray " "]
1423 }
1424
1425 # @param theLibsList   - dependencies (libraries  list)
1426 # @param theFrameworks - dependencies (frameworks list, OS X specific)
1427 proc osutils:usedOsLibs { theToolKit theOS theLibsList theFrameworks } {
1428   global path
1429   upvar $theLibsList   aLibsList
1430   upvar $theFrameworks aFrameworks
1431   set aLibsList   [list]
1432   set aFrameworks [list]
1433
1434   osutils:csfList $theOS aLibsMap aFrmsMap
1435
1436   foreach aCsfElem [osutils:tk:csfInExternlib "$path/src/${theToolKit}/EXTERNLIB"] {
1437     if [info exists aLibsMap($aCsfElem)] {
1438       foreach aLib [split "$aLibsMap($aCsfElem)"] {
1439         if { [lsearch $aLibsList $aLib] == "-1" } {
1440           lappend aLibsList $aLib
1441         }
1442       }
1443     }
1444     if [info exists aFrmsMap($aCsfElem)] {
1445       foreach aFrm [split "$aFrmsMap($aCsfElem)"] {
1446         if { [lsearch $aFrameworks $aFrm] == "-1" } {
1447           lappend aFrameworks $aFrm
1448         }
1449       }
1450     }
1451   }
1452 }
1453
1454 # Returns liste of UD in a toolkit. tkloc is a full path wok.
1455 proc osutils:tk:units { tkloc } {
1456   global path
1457   set l {}
1458   set PACKAGES "$path/src/$tkloc/PACKAGES"
1459   foreach u [wokUtils:FILES:FileToList $PACKAGES] {
1460     if {[file isdirectory "$path/src/$u"]} {
1461       lappend l $u
1462     }
1463   }
1464   if { $l == {} } {
1465     ;#puts stderr "Warning. No devunit included in $tkloc"
1466   }
1467   return $l
1468 }
1469
1470 proc osutils:justwnt { listloc } {
1471   # ImageUtility is required for support for old (<6.5.4) versions of OCCT
1472   set goaway [list Xdps Xw  ImageUtility WOKUnix]
1473   return [osutils:juststation $goaway $listloc]
1474 }
1475
1476 # remove from listloc OpenCascade units indesirables on NT
1477 proc osutils:juststation {goaway listloc} {
1478   global path
1479   set lret {}
1480   foreach u $listloc {
1481     if {([file isdirectory "$path/src/$u"] && [lsearch $goaway $u] == -1 )
1482      || (![file isdirectory "$path/src/$u"] && [lsearch $goaway $u] == -1 ) } {
1483       lappend lret $u
1484     }
1485   }
1486   return $lret
1487 }
1488
1489 # intersect3 - perform the intersecting of two lists, returning a list containing three lists.
1490 # The first list is everything in the first list that wasn't in the second,
1491 # the second list contains the intersection of the two lists, the third list contains everything
1492 # in the second list that wasn't in the first.
1493 proc osutils:intersect3 {list1 list2} {
1494   set la1(0) {} ; unset la1(0)
1495   set lai(0) {} ; unset lai(0)
1496   set la2(0) {} ; unset la2(0)
1497   foreach v $list1 {
1498     set la1($v) {}
1499   }
1500   foreach v $list2 {
1501     set la2($v) {}
1502   }
1503   foreach elem [concat $list1 $list2] {
1504     if {[info exists la1($elem)] && [info exists la2($elem)]} {
1505       unset la1($elem)
1506       unset la2($elem)
1507       set lai($elem) {}
1508     }
1509   }
1510   list [lsort [array names la1]] [lsort [array names lai]] [lsort [array names la2]]
1511 }
1512
1513 # Prepare relative path
1514 proc relativePath {thePathFrom thePathTo} {
1515   if { [file isdirectory "$thePathFrom"] == 0 } {
1516     return ""
1517   }
1518
1519   set aPathFrom [file normalize "$thePathFrom"]
1520   set aPathTo   [file normalize "$thePathTo"]
1521
1522   set aCutedPathFrom "${aPathFrom}/dummy"
1523   set aRelatedDeepPath ""
1524
1525   while { "$aCutedPathFrom" != [file normalize "$aCutedPathFrom/.."] } {
1526     set aCutedPathFrom [file normalize "$aCutedPathFrom/.."]
1527     # does aPathTo contain aCutedPathFrom?
1528     regsub -all $aCutedPathFrom $aPathTo "" aPathFromAfterCut
1529     if { "$aPathFromAfterCut" != "$aPathTo" } { # if so
1530       if { "$aCutedPathFrom" == "$aPathFrom" } { # just go higher, for example, ./somefolder/someotherfolder
1531         set aPathTo ".${aPathTo}"
1532       } elseif { "$aCutedPathFrom" == "$aPathTo" } { # remove the last "/"
1533         set aRelatedDeepPath [string replace $aRelatedDeepPath end end ""]
1534       }
1535       regsub -all $aCutedPathFrom $aPathTo $aRelatedDeepPath aPathToAfterCut
1536       regsub -all "//" $aPathToAfterCut "/" aPathToAfterCut
1537       return $aPathToAfterCut
1538     }
1539     set aRelatedDeepPath "$aRelatedDeepPath../"
1540
1541   }
1542
1543   return $thePathTo
1544 }
1545
1546 proc wokUtils:EASY:bs1 { s } {
1547     regsub -all {/} $s {\\} r
1548     return $r
1549 }
1550
1551 # Returs for a full path the liste of n last directory part
1552 # n = 1 => tail
1553 # n = 2 => dir/file.c
1554 # n = 3 => sdir/dir/file.c
1555 # etc..
1556 proc wokUtils:FILES:wtail { f n } {
1557     set ll [expr [llength [set lif [file split $f]]] -$n]
1558     return [join [lrange $lif $ll end] /]
1559 }
1560
1561 # Generate entry for one source file in Visual Studio 10 project file
1562 proc osutils:vcxproj:file { file params } {
1563   append text "    <ClCompile Include=\"..\\..\\..\\[wokUtils:EASY:bs1 [wokUtils:FILES:wtail $file 3]]\">\n"
1564   if { $params != "" } {
1565     append text "      <AdditionalOptions Condition=\"\'\$(Configuration)|\$(Platform)\'==\'Debug|Win32\'\">[string trim ${params}]  %(AdditionalOptions)</AdditionalOptions>\n"
1566   }
1567
1568   if { $params != "" } {
1569     append text "      <AdditionalOptions Condition=\"\'\$(Configuration)|\$(Platform)\'==\'Release|Win32\'\">[string trim ${params}]  %(AdditionalOptions)</AdditionalOptions>\n"
1570   }
1571
1572   if { $params != "" } {
1573     append text "      <AdditionalOptions Condition=\"\'\$(Configuration)|\$(Platform)\'==\'Debug|x64\'\">[string trim ${params}]  %(AdditionalOptions)</AdditionalOptions>\n"
1574   }
1575
1576   if { $params != "" } {
1577     append text "      <AdditionalOptions Condition=\"\'\$(Configuration)|\$(Platform)\'==\'Release|x64\'\">[string trim ${params}]  %(AdditionalOptions)</AdditionalOptions>\n"
1578   }
1579
1580   append text "    </ClCompile>\n"
1581   return $text
1582 }
1583
1584 # Generate Visual Studio 2010 project filters file
1585 proc osutils:vcxproj:filters { dir proj theFilesMap } {
1586   upvar $theFilesMap aFilesMap
1587
1588   # header
1589   append text "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n"
1590   append text "<Project ToolsVersion=\"4.0\" xmlns=\"http://schemas.microsoft.com/developer/msbuild/2003\">\n"
1591
1592   # list of "filters" (units)
1593   append text "  <ItemGroup>\n"
1594   append text "    <Filter Include=\"Source files\">\n"
1595   append text "      <UniqueIdentifier>[OS:genGUID]</UniqueIdentifier>\n"
1596   append text "    </Filter>\n"
1597   foreach unit $aFilesMap(units) {
1598     append text "    <Filter Include=\"Source files\\${unit}\">\n"
1599     append text "      <UniqueIdentifier>[OS:genGUID]</UniqueIdentifier>\n"
1600     append text "    </Filter>\n"
1601   }
1602   append text "  </ItemGroup>\n"
1603
1604   # list of files
1605   append text "  <ItemGroup>\n"
1606   foreach unit $aFilesMap(units) {
1607     foreach file $aFilesMap($unit) {
1608       append text "    <ClCompile Include=\"..\\..\\..\\[wokUtils:EASY:bs1 [wokUtils:FILES:wtail $file 3]]\">\n"
1609       append text "      <Filter>Source files\\${unit}</Filter>\n"
1610       append text "    </ClCompile>\n"
1611     }
1612   }
1613   append text "  </ItemGroup>\n"
1614
1615   # end
1616   append text "</Project>"
1617
1618   # write file
1619   set fp [open [set fvcproj [file join $dir ${proj}.vcxproj.filters]] w]
1620   fconfigure $fp -translation crlf
1621   puts $fp $text
1622   close $fp
1623
1624   return ${proj}.vcxproj.filters
1625 }
1626
1627 # Generate Visual Studio 2011 project filters file
1628 proc osutils:vcx1proj:filters { dir proj theFilesMap } {
1629   upvar $theFilesMap aFilesMap
1630
1631   # header
1632   append text "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n"
1633   append text "<Project ToolsVersion=\"4.0\" xmlns=\"http://schemas.microsoft.com/developer/msbuild/2003\">\n"
1634
1635   # list of "filters" (units)
1636   append text "  <ItemGroup>\n"
1637   append text "    <Filter Include=\"Source files\">\n"
1638   append text "      <UniqueIdentifier>[OS:genGUID]</UniqueIdentifier>\n"
1639   append text "    </Filter>\n"
1640   foreach unit $aFilesMap(units) {
1641     append text "    <Filter Include=\"Source files\\${unit}\">\n"
1642     append text "      <UniqueIdentifier>[OS:genGUID]</UniqueIdentifier>\n"
1643     append text "    </Filter>\n"
1644   }
1645   append text "  </ItemGroup>\n"
1646
1647   # list of files
1648   append text "  <ItemGroup>\n"
1649   foreach unit $aFilesMap(units) {
1650     foreach file $aFilesMap($unit) {
1651       append text "    <ClCompile Include=\"..\\..\\..\\[wokUtils:EASY:bs1 [wokUtils:FILES:wtail $file 3]]\">\n"
1652       append text "      <Filter>Source files\\${unit}</Filter>\n"
1653       append text "    </ClCompile>\n"
1654     }
1655   }
1656   append text "  </ItemGroup>\n"
1657
1658   append text "  <ItemGroup>\n"
1659   append text "    <ResourceCompile Include=\"${proj}.rc\" />"
1660   append text "  </ItemGroup>\n"
1661
1662   # end
1663   append text "</Project>"
1664
1665   # write file
1666   set fp [open [set fvcproj [file join $dir ${proj}.vcxproj.filters]] w]
1667   fconfigure $fp -translation crlf
1668   puts $fp $text
1669   close $fp
1670
1671   return ${proj}.vcxproj.filters
1672 }
1673
1674 # Generate RC file content for ToolKit from template
1675 proc osutils:readtemplate:rc {theOutDir theToolKit} {
1676   set aLoc "$::THE_CASROOT/adm/templates/template_dll.rc"
1677   set aBody [wokUtils:FILES:FileToString $aLoc]
1678   regsub -all -- {__TKNAM__} $aBody $theToolKit aBody
1679
1680   set aFile [open "${theOutDir}/${theToolKit}.rc" "w"]
1681   fconfigure $aFile -translation lf
1682   puts $aFile $aBody
1683   close $aFile
1684   return "${theOutDir}/${theToolKit}.rc"
1685 }
1686
1687 # Generate Visual Studio project file for ToolKit
1688 proc osutils:vcproj { theVcVer isUWP theOutDir theToolKit theGuidsMap } {
1689   set theProjTmpl [osutils:vcproj:readtemplate $theVcVer $isUWP 0]
1690
1691   set l_compilable [osutils:compilable wnt]
1692   regsub -all -- {__TKNAM__} $theProjTmpl $theToolKit theProjTmpl
1693
1694   upvar $theGuidsMap aGuidsMap
1695   if { ! [info exists aGuidsMap($theToolKit)] } {
1696     set aGuidsMap($theToolKit) [OS:genGUID]
1697   }
1698   regsub -all -- {__PROJECT_GUID__} $theProjTmpl $aGuidsMap($theToolKit) theProjTmpl
1699
1700   set theProjTmpl [osutils:uwp:proj $isUWP ${theProjTmpl}]
1701
1702   set aUsedLibs [list]
1703
1704   if { $isUWP } {
1705     lappend aUsedLibs "WindowsApp.lib"
1706   }
1707
1708   foreach tkx [osutils:commonUsedTK  $theToolKit] {
1709     lappend aUsedLibs "${tkx}.lib"
1710   }
1711
1712   osutils:usedOsLibs $theToolKit "wnt" aLibs aFrameworks
1713   foreach aLibIter $aLibs {
1714     lappend aUsedLibs "${aLibIter}.lib"
1715   }
1716
1717   # correct names of referred third-party libraries that are named with suffix
1718   # depending on VC version
1719   set aVCRTVer [string range $theVcVer 0 3]
1720   regsub -all -- {vc[0-9]+} $aUsedLibs $aVCRTVer aUsedLibs
1721
1722   # and put this list to project file
1723   #puts "$theToolKit requires  $aUsedLibs"
1724   if { "$theVcVer" != "vc7" && "$theVcVer" != "vc8" && "$theVcVer" != "vc9" } {
1725     set aUsedLibs [join $aUsedLibs {;}]
1726   }
1727   regsub -all -- {__TKDEP__} $theProjTmpl $aUsedLibs theProjTmpl
1728
1729   set anIncPaths "..\\..\\..\\inc"
1730 #  set aTKDefines ""
1731   set aFilesSection ""
1732   set aVcFilesX(units) ""
1733   set listloc [osutils:tk:units $theToolKit]
1734   set resultloc [osutils:justwnt $listloc]
1735   if [array exists written] { unset written }
1736   #puts "\t1 [wokparam -v %CMPLRS_CXX_Options [w_info -f]] father"
1737   #puts "\t2 [wokparam -v %CMPLRS_CXX_Options] branch"
1738   #puts "\t1 [wokparam -v %CMPLRS_C_Options [w_info -f]] father"
1739   #puts "\t2 [wokparam -v %CMPLRS_C_Options] branch"
1740   set fxloparamfcxx [lindex [osutils:intersect3 [_get_options wnt cmplrs_cxx f] [_get_options wnt cmplrs_cxx b]] 2]
1741   set fxloparamfc   [lindex [osutils:intersect3 [_get_options wnt cmplrs_c f] [_get_options wnt cmplrs_c b]] 2]
1742   set fxloparam ""
1743   foreach fxlo $resultloc {
1744     set xlo $fxlo
1745     set aSrcFiles [osutils:tk:files $xlo wnt]
1746         set fxlo_cmplrs_options_cxx [_get_options wnt cmplrs_cxx $fxlo]
1747     if {$fxlo_cmplrs_options_cxx == ""} {
1748       set fxlo_cmplrs_options_cxx [_get_options wnt cmplrs_cxx b]
1749     }
1750         set fxlo_cmplrs_options_c [_get_options wnt cmplrs_c $fxlo]
1751     if {$fxlo_cmplrs_options_c == ""} {
1752       set fxlo_cmplrs_options_c [_get_options wnt cmplrs_c b]
1753     }
1754     set fxloparam "$fxloparam [lindex [osutils:intersect3 [_get_options wnt cmplrs_cxx b] $fxlo_cmplrs_options_cxx] 2]"
1755     set fxloparam "$fxloparam [lindex [osutils:intersect3 [_get_options wnt cmplrs_c b] $fxlo_cmplrs_options_c] 2]"
1756         #puts "\t3 [wokparam -v %CMPLRS_CXX_Options] branch CXX "
1757         #puts "\t4 [wokparam -v %CMPLRS_CXX_Options $fxlo] $fxlo  CXX"
1758         #puts "\t5 [wokparam -v %CMPLRS_C_Options] branch C"
1759         #puts "\t6 [wokparam -v %CMPLRS_C_Options   $fxlo] $fxlo  C"
1760     set needparam ""
1761     foreach partopt $fxloparam {
1762       if {[string first "-I" $partopt] == "0"} {
1763         # this is an additional includes search path
1764         continue
1765       }
1766       set needparam "$needparam $partopt"
1767     }
1768
1769     # Format of projects in vc10+ is different from vc7-9
1770     if { "$theVcVer" != "vc7" && "$theVcVer" != "vc8" && "$theVcVer" != "vc9" } {
1771       foreach aSrcFile [lsort $aSrcFiles] {
1772         if { ![info exists written([file tail $aSrcFile])] } {
1773           set written([file tail $aSrcFile]) 1
1774           append aFilesSection [osutils:vcxproj:file $aSrcFile $needparam]
1775         } else {
1776           puts "Warning : in vcproj more than one occurences for [file tail $aSrcFile]"
1777         }
1778         if { ! [info exists aVcFilesX($xlo)] } { lappend aVcFilesX(units) $xlo }
1779         lappend aVcFilesX($xlo) $aSrcFile
1780       }
1781     } else {
1782       append aFilesSection "\t\t\t<Filter\n"
1783       append aFilesSection "\t\t\t\tName=\"${xlo}\"\n"
1784       append aFilesSection "\t\t\t\t>\n"
1785       foreach aSrcFile [lsort $aSrcFiles] {
1786         if { ![info exists written([file tail $aSrcFile])] } {
1787           set written([file tail $aSrcFile]) 1
1788           append aFilesSection [osutils:vcproj:file $theVcVer $aSrcFile $needparam]
1789         } else {
1790           puts "Warning : in vcproj more than one occurences for [file tail $aSrcFile]"
1791         }
1792       }
1793       append aFilesSection "\t\t\t</Filter>\n"
1794     }
1795
1796     # macros
1797 #    append aTKDefines ";__${xlo}_DLL"
1798     # common includes
1799 #    append anIncPaths ";..\\..\\..\\src\\${xlo}"
1800   }
1801
1802   regsub -all -- {__TKINC__}  $theProjTmpl $anIncPaths theProjTmpl
1803 #  regsub -all -- {__TKDEFS__} $theProjTmpl $aTKDefines theProjTmpl
1804   regsub -all -- {__FILES__}  $theProjTmpl $aFilesSection theProjTmpl
1805
1806   # write file
1807   set aFile [open [set aVcFiles [file join $theOutDir ${theToolKit}.[osutils:vcproj:ext $theVcVer]]] w]
1808   fconfigure $aFile -translation crlf
1809   puts $aFile $theProjTmpl
1810   close $aFile
1811
1812   # write filters file for vc10+
1813   if { "$theVcVer" == "vc7" || "$theVcVer" == "vc8" || "$theVcVer" == "vc9" } {
1814     # nothing
1815   } elseif { "$theVcVer" == "vc10" } {
1816     lappend aVcFiles [osutils:vcxproj:filters $theOutDir $theToolKit aVcFilesX]
1817   } else {
1818     lappend aVcFiles [osutils:vcx1proj:filters $theOutDir $theToolKit aVcFilesX]
1819   }
1820
1821   # write resource file
1822   lappend aVcFiles [osutils:readtemplate:rc $theOutDir $theToolKit]
1823
1824   return $aVcFiles
1825 }
1826
1827 # for a unit returns a map containing all its file in the current
1828 # workbench
1829 # local = 1 only local files
1830 proc osutils:tk:loadunit { loc map } {
1831   #puts $loc
1832   upvar $map TLOC
1833   catch { unset TLOC }
1834   set lfiles [_get_used_files $loc]
1835   foreach f $lfiles {
1836     #puts "\t$f"
1837     set t [lindex $f 0]
1838     set p [lindex $f 2]
1839     if [info exists TLOC($t)] {
1840       set l $TLOC($t)
1841       lappend l $p
1842       set TLOC($t) $l
1843     } else {
1844       set TLOC($t) $p
1845     }
1846   }
1847   return
1848 }
1849
1850 # Returns the list of all compilable files name in a toolkit, or devunit of any type
1851 # Tfiles lists for each unit the type of file that can be compiled.
1852 proc osutils:tk:files { tkloc thePlatform } {
1853   set Tfiles(source,nocdlpack)     {source pubinclude}
1854   set Tfiles(source,toolkit)       {}
1855   set Tfiles(source,executable)    {source pubinclude}
1856   set listloc [concat [osutils:tk:units $tkloc] $tkloc]
1857   #puts " listloc = $listloc"
1858
1859   set l_comp [osutils:compilable $thePlatform]
1860   set resultloc $listloc
1861   set lret {}
1862   foreach loc $resultloc {
1863     set utyp [_get_type $loc]
1864     #puts "\"$utyp\" \"$loc\""
1865     switch $utyp {
1866          "t" { set utyp "toolkit" }
1867          "n" { set utyp "nocdlpack" }
1868          "x" { set utyp "executable" }
1869     }
1870     if [array exists map] { unset map }
1871     osutils:tk:loadunit $loc map
1872     #puts " loc = $loc === > [array names map]"
1873     set LType $Tfiles(source,${utyp})
1874     foreach typ [array names map] {
1875       if { [lsearch $LType $typ] == -1 } {
1876         unset map($typ)
1877       }
1878     }
1879     foreach type [array names map] {
1880       #puts $type
1881       foreach f $map($type) {
1882         #puts $f
1883         if { [lsearch $l_comp [file extension $f]] != -1 } {
1884           lappend lret $f
1885         }
1886       }
1887     }
1888   }
1889   return $lret
1890 }
1891
1892 # Generate Visual Studio project file for executable
1893 proc osutils:vcprojx { theVcVer isUWP theOutDir theToolKit theGuidsMap } {
1894   set aVcFiles {}
1895   foreach f [osutils:tk:files $theToolKit wnt] {
1896     set aProjTmpl [osutils:vcproj:readtemplate $theVcVer $isUWP 1]
1897
1898     set aProjName [file rootname [file tail $f]]
1899     set l_compilable [osutils:compilable wnt]
1900     regsub -all -- {__XQTNAM__} $aProjTmpl $aProjName aProjTmpl
1901
1902     upvar $theGuidsMap aGuidsMap
1903     if { ! [info exists aGuidsMap($aProjName)] } {
1904       set aGuidsMap($aProjName) [OS:genGUID]
1905     }
1906     regsub -all -- {__PROJECT_GUID__} $aProjTmpl $aGuidsMap($aProjName) aProjTmpl
1907
1908     set aUsedLibs [list]
1909     foreach tkx [osutils:commonUsedTK  $theToolKit] {
1910       lappend aUsedLibs "${tkx}.lib"
1911     }
1912
1913     osutils:usedOsLibs $theToolKit "wnt" aLibs aFrameworks
1914     foreach aLibIter $aLibs {
1915       lappend aUsedLibs "${aLibIter}.lib"
1916     }
1917
1918     # correct names of referred third-party libraries that are named with suffix
1919     # depending on VC version
1920     set aVCRTVer [string range $theVcVer 0 3]
1921     regsub -all -- {vc[0-9]+} $aUsedLibs $aVCRTVer aUsedLibs
1922
1923 #    puts "$aProjName requires  $aUsedLibs"
1924     if { "$theVcVer" != "vc7" && "$theVcVer" != "vc8" && "$theVcVer" != "vc9" } {
1925       set aUsedLibs [join $aUsedLibs {;}]
1926     }
1927     regsub -all -- {__TKDEP__} $aProjTmpl $aUsedLibs aProjTmpl
1928
1929     set aFilesSection ""
1930     set aVcFilesX(units) ""
1931
1932     if { ![info exists written([file tail $f])] } {
1933       set written([file tail $f]) 1
1934
1935       if { "$theVcVer" != "vc7" && "$theVcVer" != "vc8" && "$theVcVer" != "vc9" } {
1936         append aFilesSection [osutils:vcxproj:file $f ""]
1937         if { ! [info exists aVcFilesX($theToolKit)] } { lappend aVcFilesX(units) $theToolKit }
1938         lappend aVcFilesX($theToolKit) $f
1939       } else {
1940         append aFilesSection "\t\t\t<Filter\n"
1941         append aFilesSection "\t\t\t\tName=\"$theToolKit\"\n"
1942         append aFilesSection "\t\t\t\t>\n"
1943         append aFilesSection [osutils:vcproj:file $theVcVer $f ""]
1944         append aFilesSection "\t\t\t</Filter>"
1945       }
1946     } else {
1947       puts "Warning : in vcproj there are than one occurences for [file tail $f]"
1948     }
1949     #puts "$aProjTmpl $aFilesSection"
1950 #    set aTKDefines ";__${theToolKit}_DLL"
1951     set anIncPaths "..\\..\\..\\inc"
1952     regsub -all -- {__TKINC__}  $aProjTmpl $anIncPaths    aProjTmpl
1953 #    regsub -all -- {__TKDEFS__} $aProjTmpl $aTKDefines    aProjTmpl
1954     regsub -all -- {__FILES__}  $aProjTmpl $aFilesSection aProjTmpl
1955     regsub -all -- {__CONF__}   $aProjTmpl Application    aProjTmpl
1956
1957     regsub -all -- {__XQTEXT__} $aProjTmpl "exe" aProjTmpl
1958
1959     set aFile [open [set aVcFilePath [file join $theOutDir ${aProjName}.[osutils:vcproj:ext $theVcVer]]] w]
1960     fconfigure $aFile -translation crlf
1961     puts $aFile $aProjTmpl
1962     close $aFile
1963
1964     set aCommonSettingsFile "$aVcFilePath.user"
1965     lappend aVcFiles $aVcFilePath
1966
1967     # write filters file for vc10
1968     if { "$theVcVer" != "vc7" && "$theVcVer" != "vc8" && "$theVcVer" != "vc9" } {
1969       lappend aVcFiles [osutils:vcxproj:filters $theOutDir $aProjName aVcFilesX]
1970     }
1971
1972     set aCommonSettingsFileTmpl ""
1973     if { "$theVcVer" == "vc7" || "$theVcVer" == "vc8" } {
1974       # nothing
1975     } elseif { "$theVcVer" == "vc9" } {
1976       set aCommonSettingsFileTmpl [wokUtils:FILES:FileToString "$::THE_CASROOT/adm/templates/vcproj.user.vc9x"]
1977     } else {
1978       set aCommonSettingsFileTmpl [wokUtils:FILES:FileToString "$::THE_CASROOT/adm/templates/vcxproj.user.vc10x"]
1979     }
1980     if { "$aCommonSettingsFileTmpl" != "" } {
1981       regsub -all -- {__VCVER__} $aCommonSettingsFileTmpl $aVCRTVer aCommonSettingsFileTmpl
1982
1983       set aFile [open [set aVcFilePath "$aCommonSettingsFile"] w]
1984       fconfigure $aFile -translation crlf
1985       puts $aFile $aCommonSettingsFileTmpl
1986       close $aFile
1987
1988       lappend aVcFiles "$aCommonSettingsFile"
1989     }
1990   }
1991   return $aVcFiles
1992 }
1993
1994 # Generate entry for one source file in Visual Studio 7 - 9 project file
1995 proc osutils:vcproj:file { theVcVer theFile theOptions } {
1996   append aText "\t\t\t\t<File\n"
1997   append aText "\t\t\t\t\tRelativePath=\"..\\..\\..\\[wokUtils:EASY:bs1 [wokUtils:FILES:wtail $theFile 3]]\">\n"
1998   if { $theOptions == "" } {
1999     append aText "\t\t\t\t</File>\n"
2000     return $aText
2001   }
2002
2003   append aText "\t\t\t\t\t<FileConfiguration\n"
2004   append aText "\t\t\t\t\t\tName=\"Release\|Win32\">\n"
2005   append aText "\t\t\t\t\t\t<Tool\n"
2006   append aText "\t\t\t\t\t\t\tName=\"VCCLCompilerTool\"\n"
2007   append aText "\t\t\t\t\t\t\tAdditionalOptions=\""
2008   foreach aParam $theOptions {
2009     append aText "$aParam "
2010   }
2011   append aText "\"\n"
2012   append aText "\t\t\t\t\t\t/>\n"
2013   append aText "\t\t\t\t\t</FileConfiguration>\n"
2014
2015   append aText "\t\t\t\t\t<FileConfiguration\n"
2016   append aText "\t\t\t\t\t\tName=\"Debug\|Win32\">\n"
2017   append aText "\t\t\t\t\t\t<Tool\n"
2018   append aText "\t\t\t\t\t\t\tName=\"VCCLCompilerTool\"\n"
2019   append aText "\t\t\t\t\t\t\tAdditionalOptions=\""
2020   foreach aParam $theOptions {
2021     append aText "$aParam "
2022   }
2023   append aText "\"\n"
2024   append aText "\t\t\t\t\t\t/>\n"
2025   append aText "\t\t\t\t\t</FileConfiguration>\n"
2026   if { "$theVcVer" == "vc7" } {
2027     append aText "\t\t\t\t</File>\n"
2028     return $aText
2029   }
2030
2031   append aText "\t\t\t\t\t<FileConfiguration\n"
2032   append aText "\t\t\t\t\t\tName=\"Release\|x64\">\n"
2033   append aText "\t\t\t\t\t\t<Tool\n"
2034   append aText "\t\t\t\t\t\t\tName=\"VCCLCompilerTool\"\n"
2035   append aText "\t\t\t\t\t\t\tAdditionalOptions=\""
2036   foreach aParam $theOptions {
2037     append aText "$aParam "
2038   }
2039   append aText "\"\n"
2040   append aText "\t\t\t\t\t\t/>\n"
2041   append aText "\t\t\t\t\t</FileConfiguration>\n"
2042
2043   append aText "\t\t\t\t\t<FileConfiguration\n"
2044   append aText "\t\t\t\t\t\tName=\"Debug\|x64\">\n"
2045   append aText "\t\t\t\t\t\t<Tool\n"
2046   append aText "\t\t\t\t\t\t\tName=\"VCCLCompilerTool\"\n"
2047   append aText "\t\t\t\t\t\t\tAdditionalOptions=\""
2048   foreach aParam $theOptions {
2049     append aText "$aParam "
2050   }
2051   append aText "\"\n"
2052   append aText "\t\t\t\t\t\t/>\n"
2053   append aText "\t\t\t\t\t</FileConfiguration>\n"
2054
2055   append aText "\t\t\t\t</File>\n"
2056   return $aText
2057 }
2058
2059 proc wokUtils:FILES:mkdir { d } {
2060     global tcl_version
2061     regsub -all {\.[^.]*} $tcl_version "" major
2062     if { $major == 8 } {
2063         file mkdir $d
2064     } else {
2065         if ![file exists $d] {
2066             if { "[info command mkdir]" == "mkdir" } {
2067                 mkdir -path $d
2068             } else {
2069                 puts stderr "wokUtils:FILES:mkdir : Error unable to find a mkdir command."
2070             }
2071         }
2072     }
2073     if [file exists $d] {
2074         return $d
2075     } else {
2076         return {}
2077     }
2078 }
2079
2080 # remove from listloc OpenCascade units indesirables on Unix
2081 proc osutils:justunix { listloc } {
2082   if { "$::tcl_platform(os)" == "Darwin" } {
2083     set goaway [list Xw WNT]
2084   } else {
2085     set goaway [list WNT]
2086   }
2087   return [osutils:juststation $goaway $listloc]
2088 }
2089
2090
2091 ####### CODEBLOCK ###################################################################
2092 # Function to generate Code Blocks workspace and project files
2093 proc OS:MKCBP { theOutDir theModules theAllSolution thePlatform theCmpl } {
2094   puts stderr "Generating project files for Code Blocks"
2095
2096   # Generate projects for toolkits and separate workspace for each module
2097   foreach aModule $theModules {
2098     OS:cworkspace          $aModule $aModule $theOutDir
2099     OS:cbp        $theCmpl $aModule          $theOutDir $thePlatform
2100   }
2101
2102   # Generate single workspace "OCCT" containing projects from all modules
2103   if { "$theAllSolution" != "" } {
2104     OS:cworkspace $theAllSolution $theModules $theOutDir
2105   }
2106
2107   puts "The Code Blocks workspace and project files are stored in the $theOutDir directory"
2108 }
2109
2110 # Generate Code Blocks projects
2111 proc OS:cbp { theCmpl theModules theOutDir thePlatform } {
2112   set aProjectFiles {}
2113   foreach aModule $theModules {
2114     foreach aToolKit [${aModule}:toolkits] {
2115       lappend aProjectFiles [osutils:cbptk $theCmpl $theOutDir $aToolKit $thePlatform]
2116     }
2117     foreach anExecutable [OS:executable ${aModule}] {
2118       lappend aProjectFiles [osutils:cbpx  $theCmpl $theOutDir $anExecutable $thePlatform]
2119     }
2120   }
2121   return $aProjectFiles
2122 }
2123
2124 # Generate Code::Blocks project file for ToolKit
2125 proc osutils:cbptk { theCmpl theOutDir theToolKit thePlatform} {
2126   set aUsedLibs     [list]
2127   set aFrameworks   [list]
2128   set anIncPaths    [list]
2129   set aTKDefines    [list]
2130   set aTKSrcFiles   [list]
2131
2132   # collect list of referred libraries to link with
2133   osutils:usedOsLibs $theToolKit $thePlatform aUsedLibs aFrameworks
2134   set aDepToolkits [wokUtils:LIST:Purge [osutils:tk:close $theToolKit]]
2135   foreach tkx $aDepToolkits {
2136     lappend aUsedLibs "${tkx}"
2137   }
2138
2139   lappend anIncPaths "../../../inc"
2140   set listloc [osutils:tk:units $theToolKit]
2141
2142   if { [llength $listloc] == 0 } {
2143     set listloc $theToolKit
2144   }
2145
2146   if { $thePlatform == "wnt" || $thePlatform == "uwp" } {
2147     set resultloc [osutils:justwnt  $listloc]
2148   } else {
2149     set resultloc [osutils:justunix $listloc]
2150   }
2151   if [array exists written] { unset written }
2152   foreach fxlo $resultloc {
2153     set xlo       $fxlo
2154     set aSrcFiles [osutils:tk:files $xlo $thePlatform]
2155     foreach aSrcFile [lsort $aSrcFiles] {
2156       if { ![info exists written([file tail $aSrcFile])] } {
2157         set written([file tail $aSrcFile]) 1
2158         lappend aTKSrcFiles "../../../[wokUtils:FILES:wtail $aSrcFile 3]"
2159       } else {
2160         puts "Warning : more than one occurences for [file tail $aSrcFile]"
2161       }
2162     }
2163
2164     # macros for correct DLL exports
2165 #    if { $thePlatform == "wnt" || $thePlatform == "uwp" } {
2166 #      lappend aTKDefines "__${xlo}_DLL"
2167 #    }
2168   }
2169
2170   return [osutils:cbp $theCmpl $theOutDir $theToolKit $thePlatform $aTKSrcFiles $aUsedLibs $aFrameworks $anIncPaths $aTKDefines]
2171 }
2172
2173 # Generates Code Blocks workspace.
2174 proc OS:cworkspace { theSolName theModules theOutDir } {
2175   global path
2176   set aWsFilePath "${theOutDir}/${theSolName}.workspace"
2177   set aFile [open $aWsFilePath "w"]
2178   set isActiveSet 0
2179   puts $aFile "<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"yes\" ?>"
2180   puts $aFile "<CodeBlocks_workspace_file>"
2181   puts $aFile "\t<Workspace title=\"${theSolName}\">"
2182
2183   # collect list of projects to be created
2184   foreach aModule $theModules {
2185     # toolkits
2186     foreach aToolKit [osutils:tk:sort [${aModule}:toolkits]] {
2187       set aDependencies [LibToLink $aToolKit]
2188       if { [llength $aDependencies] == 0 } {
2189         puts $aFile "\t\t<Project filename=\"${aToolKit}.cbp\" />"
2190       } else {
2191         puts $aFile "\t\t<Project filename=\"${aToolKit}.cbp\" >"
2192         foreach aDepTk $aDependencies {
2193           puts $aFile "\t\t\t<Depends filename=\"${aDepTk}.cbp\" />"
2194         }
2195         puts $aFile "\t\t</Project>"
2196       }
2197     }
2198
2199     # executables, assume one project per cxx file...
2200     foreach aUnit [OS:executable ${aModule}] {
2201       set aUnitLoc $aUnit
2202       set src_files [_get_used_files $aUnit false]
2203       set aSrcFiles {}
2204       foreach s $src_files { 
2205         regexp {source ([^\s]+)} $s dummy name
2206         lappend aSrcFiles $name
2207       }
2208       foreach aSrcFile $aSrcFiles {
2209         set aFileExtension [file extension $aSrcFile]
2210         if { $aFileExtension == ".cxx" } {
2211           set aPrjName [file rootname $aSrcFile]
2212           set aDependencies [list]
2213           if {[file isdirectory $path/src/$aUnitLoc]} {
2214             set aDependencies [LibToLinkX $aUnitLoc [file rootname $aSrcFile]]
2215           }
2216           set anActiveState ""
2217           if { $isActiveSet == 0 } {
2218             set anActiveState " active=\"1\""
2219             set isActiveSet 1
2220           }
2221           if { [llength $aDependencies] == 0 } {
2222             puts $aFile "\t\t<Project filename=\"${aPrjName}.cbp\"${anActiveState}/>"
2223           } else {
2224             puts $aFile "\t\t<Project filename=\"${aPrjName}.cbp\"${anActiveState}>"
2225             foreach aDepTk $aDependencies {
2226               puts $aFile "\t\t\t<Depends filename=\"${aDepTk}.cbp\" />"
2227             }
2228             puts $aFile "\t\t</Project>"
2229           }
2230         }
2231       }
2232     }
2233   }
2234
2235   puts $aFile "\t</Workspace>"
2236   puts $aFile "</CodeBlocks_workspace_file>"
2237   close $aFile
2238
2239   return $aWsFilePath
2240 }
2241
2242 # Generate Code::Blocks project file for Executable
2243 proc osutils:cbpx { theCmpl theOutDir theToolKit thePlatform } {
2244   global path
2245   set aWokArch    "$::env(ARCH)"
2246
2247   set aCbpFiles {}
2248   foreach aSrcFile [osutils:tk:files $theToolKit $thePlatform] {
2249     # collect list of referred libraries to link with
2250     set aUsedLibs     [list]
2251     set aFrameworks   [list]
2252     set anIncPaths    [list]
2253     set aTKDefines    [list]
2254     set aTKSrcFiles   [list]
2255     set aProjName [file rootname [file tail $aSrcFile]]
2256
2257     osutils:usedOsLibs $theToolKit $thePlatform aUsedLibs aFrameworks
2258
2259     set aDepToolkits [LibToLinkX $theToolKit $aProjName]
2260     foreach tkx $aDepToolkits {
2261       if {[_get_type $tkx] == "t"} {
2262         lappend aUsedLibs "${tkx}"
2263       }
2264       if {[lsearch [glob -tails -directory "$path/src" -types d *] $tkx] == "-1"} {
2265         lappend aUsedLibs "${tkx}"
2266       }
2267     }
2268
2269     set WOKSteps_exec_link [_get_options lin WOKSteps_exec_link $theToolKit]
2270     if { [regexp {WOKStep_DLLink} $WOKSteps_exec_link] || [regexp {WOKStep_Libink} $WOKSteps_exec_link] } {
2271       set isExecutable "false"
2272     } else {
2273       set isExecutable "true"
2274     }
2275
2276     if { ![info exists written([file tail $aSrcFile])] } {
2277       set written([file tail $aSrcFile]) 1
2278       lappend aTKSrcFiles "../../../[wokUtils:FILES:wtail $aSrcFile 3]"
2279     } else {
2280       puts "Warning : in cbp there are more than one occurences for [file tail $aSrcFile]"
2281     }
2282
2283     # macros for correct DLL exports
2284 #    if { $thePlatform == "wnt" || $thePlatform == "uwp" } {
2285 #      lappend aTKDefines "__${theToolKit}_DLL"
2286 #    }
2287
2288     # common include paths
2289     lappend anIncPaths "../../../inc"
2290
2291     lappend aCbpFiles [osutils:cbp $theCmpl $theOutDir $aProjName $thePlatform $aTKSrcFiles $aUsedLibs $aFrameworks $anIncPaths $aTKDefines $isExecutable]
2292   }
2293
2294   return $aCbpFiles
2295 }
2296
2297 # This function intended to generate Code::Blocks project file
2298 # @param theCmpl       - the compiler (gcc or msvc)
2299 # @param theOutDir     - output directory to place project file
2300 # @param theProjName   - project name
2301 # @param theSrcFiles   - list of source files
2302 # @param theLibsList   - dependencies (libraries  list)
2303 # @param theFrameworks - dependencies (frameworks list, Mac OS X specific)
2304 # @param theIncPaths   - header search paths
2305 # @param theDefines    - compiler macro definitions
2306 # @param theIsExe      - flag to indicate executable / library target
2307 proc osutils:cbp { theCmpl theOutDir theProjName thePlatform theSrcFiles theLibsList theFrameworks theIncPaths theDefines {theIsExe "false"} } {
2308   set aWokArch    "$::env(ARCH)"
2309
2310   set aCmplCbp "gcc"
2311   set aCmplFlags        [list]
2312   set aCmplFlagsRelease [list]
2313   set aCmplFlagsDebug   [list]
2314   set toPassArgsByFile 0
2315   set aLibPrefix "lib"
2316   if { "$thePlatform" == "wnt" || "$thePlatform" == "uwp" || "$thePlatform" == "qnx" } {
2317     set toPassArgsByFile 1
2318   }
2319   if { "$theCmpl" == "msvc" } {
2320     set aCmplCbp "msvc8"
2321     set aLibPrefix ""
2322   }
2323
2324   if { "$theCmpl" == "msvc" } {
2325     set aCmplFlags        "-arch:SSE2 -EHsc -W4 -MP"
2326     set aCmplFlagsRelease "-MD  -O2"
2327     set aCmplFlagsDebug   "-MDd -Od -Zi"
2328     lappend aCmplFlags    "-D_CRT_SECURE_NO_WARNINGS"
2329     lappend aCmplFlags    "-D_CRT_NONSTDC_NO_DEPRECATE"
2330   } elseif { "$theCmpl" == "gcc" } {
2331     if { "$thePlatform" != "qnx" } {
2332       set aCmplFlags      "-mmmx -msse -msse2 -mfpmath=sse"
2333     }
2334     set aCmplFlagsRelease "-O2"
2335     set aCmplFlagsDebug   "-O0 -g"
2336     if { "$thePlatform" == "wnt" || "$thePlatform" == "uwp" } {
2337       lappend aCmplFlags "-std=gnu++0x"
2338       lappend aCmplFlags "-D_WIN32_WINNT=0x0501"
2339     } else {
2340       lappend aCmplFlags "-std=c++0x"
2341       lappend aCmplFlags "-fPIC"
2342       lappend aCmplFlags "-DOCC_CONVERT_SIGNALS"
2343     }
2344     lappend aCmplFlags   "-Wall"
2345     lappend aCmplFlags   "-fexceptions"
2346   }
2347   lappend aCmplFlagsRelease "-DNDEBUG"
2348   lappend aCmplFlagsRelease "-DNo_Exception"
2349   lappend aCmplFlagsDebug   "-D_DEBUG"
2350   if { "$thePlatform" == "qnx" } {
2351     lappend aCmplFlags "-D_QNX_SOURCE"
2352   }
2353
2354   set aCbpFilePath    "${theOutDir}/${theProjName}.cbp"
2355   set aLnkFileName    "${theProjName}_obj.link"
2356   set aLnkDebFileName "${theProjName}_objd.link"
2357   set aLnkFilePath    "${theOutDir}/${aLnkFileName}"
2358   set aLnkDebFilePath "${theOutDir}/${aLnkDebFileName}"
2359   set aFile [open $aCbpFilePath "w"]
2360   puts $aFile "<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"yes\" ?>"
2361   puts $aFile "<CodeBlocks_project_file>"
2362   puts $aFile "\t<FileVersion major=\"1\" minor=\"6\" />"
2363   puts $aFile "\t<Project>"
2364   puts $aFile "\t\t<Option title=\"$theProjName\" />"
2365   puts $aFile "\t\t<Option pch_mode=\"2\" />"
2366   puts $aFile "\t\t<Option compiler=\"$aCmplCbp\" />"
2367   puts $aFile "\t\t<Build>"
2368
2369   # Release target configuration
2370   puts $aFile "\t\t\t<Target title=\"Release\">"
2371   if { "$theIsExe" == "true" } {
2372     puts $aFile "\t\t\t\t<Option output=\"../../../${thePlatform}/cbp/bin/${theProjName}\" prefix_auto=\"0\" extension_auto=\"0\" />"
2373     puts $aFile "\t\t\t\t<Option type=\"1\" />"
2374   } else {
2375     if { "$thePlatform" == "wnt" || "$thePlatform" == "uwp" } {
2376       puts $aFile "\t\t\t\t<Option output=\"../../../${thePlatform}/cbp/bin/${aLibPrefix}${theProjName}\" imp_lib=\"../../../${thePlatform}/cbp/lib/\$(TARGET_OUTPUT_BASENAME)\" prefix_auto=\"1\" extension_auto=\"1\" />"
2377     } else {
2378       puts $aFile "\t\t\t\t<Option output=\"../../../${thePlatform}/cbp/lib/lib${theProjName}.so\" prefix_auto=\"0\" extension_auto=\"0\" />"
2379     }
2380     puts $aFile "\t\t\t\t<Option type=\"3\" />"
2381   }
2382   puts $aFile "\t\t\t\t<Option object_output=\"../../../${thePlatform}/cbp/obj\" />"
2383   puts $aFile "\t\t\t\t<Option compiler=\"$aCmplCbp\" />"
2384   puts $aFile "\t\t\t\t<Option createDefFile=\"0\" />"
2385   if { "$thePlatform" == "wnt" || "$thePlatform" == "uwp" } {
2386     puts $aFile "\t\t\t\t<Option createStaticLib=\"1\" />"
2387   } else {
2388     puts $aFile "\t\t\t\t<Option createStaticLib=\"0\" />"
2389   }
2390
2391   # compiler options per TARGET (including defines)
2392   puts $aFile "\t\t\t\t<Compiler>"
2393   foreach aFlagIter $aCmplFlagsRelease {
2394     puts $aFile "\t\t\t\t\t<Add option=\"$aFlagIter\" />"
2395   }
2396   foreach aMacro $theDefines {
2397     puts $aFile "\t\t\t\t\t<Add option=\"-D${aMacro}\" />"
2398   }
2399   puts $aFile "\t\t\t\t</Compiler>"
2400
2401   puts $aFile "\t\t\t\t<Linker>"
2402   if { $toPassArgsByFile == 1 } {
2403     puts $aFile "\t\t\t\t\t<Add option=\"\@$aLnkFileName\" />"
2404   }
2405   puts $aFile "\t\t\t\t\t<Add directory=\"../../../${thePlatform}/cbp/lib\" />"
2406   if { "$thePlatform" == "mac" } {
2407     if { [ lsearch $theLibsList X11 ] >= 0} {
2408       puts $aFile "\t\t\t\t\t<Add directory=\"/usr/X11/lib\" />"
2409     }
2410   }
2411   puts $aFile "\t\t\t\t\t<Add option=\"\$(CSF_OPT_LNK${aWokArch})\" />"
2412   if { "$thePlatform" == "lin" } {
2413     puts $aFile "\t\t\t\t\t<Add option=\"-Wl,-rpath-link=../../../${thePlatform}/cbp/lib\" />"
2414   }
2415   puts $aFile "\t\t\t\t</Linker>"
2416
2417   puts $aFile "\t\t\t</Target>"
2418
2419   # Debug target configuration
2420   puts $aFile "\t\t\t<Target title=\"Debug\">"
2421   if { "$theIsExe" == "true" } {
2422     puts $aFile "\t\t\t\t<Option output=\"../../../${thePlatform}/cbp/bind/${theProjName}\" prefix_auto=\"0\" extension_auto=\"0\" />"
2423     puts $aFile "\t\t\t\t<Option type=\"1\" />"
2424   } else {
2425     if { "$thePlatform" == "wnt" || "$thePlatform" == "uwp" } {
2426       puts $aFile "\t\t\t\t<Option output=\"../../../${thePlatform}/cbp/bind/${aLibPrefix}${theProjName}\" imp_lib=\"../../../${thePlatform}/cbp/libd/\$(TARGET_OUTPUT_BASENAME)\" prefix_auto=\"1\" extension_auto=\"1\" />"
2427     } else {
2428       puts $aFile "\t\t\t\t<Option output=\"../../../${thePlatform}/cbp/libd/lib${theProjName}.so\" prefix_auto=\"0\" extension_auto=\"0\" />"
2429     }
2430     puts $aFile "\t\t\t\t<Option type=\"3\" />"
2431   }
2432   puts $aFile "\t\t\t\t<Option object_output=\"../../../${thePlatform}/cbp/objd\" />"
2433   puts $aFile "\t\t\t\t<Option compiler=\"$aCmplCbp\" />"
2434   puts $aFile "\t\t\t\t<Option createDefFile=\"0\" />"
2435   if { "$thePlatform" == "wnt" || "$thePlatform" == "uwp" } {
2436     puts $aFile "\t\t\t\t<Option createStaticLib=\"1\" />"
2437   } else {
2438     puts $aFile "\t\t\t\t<Option createStaticLib=\"0\" />"
2439   }
2440
2441   # compiler options per TARGET (including defines)
2442   puts $aFile "\t\t\t\t<Compiler>"
2443   foreach aFlagIter $aCmplFlagsDebug {
2444     puts $aFile "\t\t\t\t\t<Add option=\"$aFlagIter\" />"
2445   }
2446   foreach aMacro $theDefines {
2447     puts $aFile "\t\t\t\t\t<Add option=\"-D${aMacro}\" />"
2448   }
2449   puts $aFile "\t\t\t\t</Compiler>"
2450
2451   puts $aFile "\t\t\t\t<Linker>"
2452   if { $toPassArgsByFile == 1 } {
2453     puts $aFile "\t\t\t\t\t<Add option=\"\@$aLnkDebFileName\" />"
2454   }
2455   puts $aFile "\t\t\t\t\t<Add directory=\"../../../${thePlatform}/cbp/libd\" />"
2456   if { "$thePlatform" == "mac" } {
2457     if { [ lsearch $theLibsList X11 ] >= 0} {
2458       puts $aFile "\t\t\t\t\t<Add directory=\"/usr/X11/lib\" />"
2459     }
2460   }
2461   puts $aFile "\t\t\t\t\t<Add option=\"\$(CSF_OPT_LNK${aWokArch}D)\" />"
2462   if { "$thePlatform" == "lin" } {
2463     puts $aFile "\t\t\t\t\t<Add option=\"-Wl,-rpath-link=../../../${thePlatform}/cbp/libd\" />"
2464   }
2465   puts $aFile "\t\t\t\t</Linker>"
2466
2467   puts $aFile "\t\t\t</Target>"
2468
2469   puts $aFile "\t\t</Build>"
2470
2471   # COMMON compiler options
2472   puts $aFile "\t\t<Compiler>"
2473   foreach aFlagIter $aCmplFlags {
2474     puts $aFile "\t\t\t<Add option=\"$aFlagIter\" />"
2475   }
2476   puts $aFile "\t\t\t<Add option=\"\$(CSF_OPT_CMPL)\" />"
2477   foreach anIncPath $theIncPaths {
2478     puts $aFile "\t\t\t<Add directory=\"$anIncPath\" />"
2479   }
2480   puts $aFile "\t\t</Compiler>"
2481
2482   # COMMON linker options
2483   puts $aFile "\t\t<Linker>"
2484   if { "$thePlatform" == "wnt" && "$theCmpl" == "gcc" } {
2485     puts $aFile "\t\t\t<Add option=\"-Wl,--export-all-symbols\" />"
2486   }
2487   foreach aFrameworkName $theFrameworks {
2488     if { "$aFrameworkName" != "" } {
2489       puts $aFile "\t\t\t<Add option=\"-framework $aFrameworkName\" />"
2490     }
2491   }
2492   foreach aLibName $theLibsList {
2493     if { "$aLibName" != "" } {
2494       if { "$theCmpl" == "msvc" } {
2495         puts $aFile "\t\t\t<Add library=\"${aLibName}.lib\" />"
2496       } else {
2497         puts $aFile "\t\t\t<Add library=\"${aLibName}\" />"
2498       }
2499     }
2500   }
2501   puts $aFile "\t\t</Linker>"
2502
2503   # list of sources
2504
2505   set aFileLnkObj ""
2506   set aFileLnkObjd ""
2507   set isFirstSrcFile 1
2508   if { $toPassArgsByFile == 1 } {
2509     set aFileLnkObj  [open $aLnkFilePath    "w"]
2510     set aFileLnkObjd [open $aLnkDebFilePath "w"]
2511   }
2512
2513   foreach aSrcFile $theSrcFiles {
2514     if {[string equal -nocase [file extension $aSrcFile] ".mm"]} {
2515       puts $aFile "\t\t<Unit filename=\"$aSrcFile\">"
2516       puts $aFile "\t\t\t<Option compile=\"1\" />"
2517       puts $aFile "\t\t\t<Option link=\"1\" />"
2518       puts $aFile "\t\t</Unit>"
2519     } elseif {[string equal -nocase [file extension $aSrcFile] ".c"]} {
2520       puts $aFile "\t\t<Unit filename=\"$aSrcFile\">"
2521       puts $aFile "\t\t\t<Option compilerVar=\"CC\" />"
2522       puts $aFile "\t\t</Unit>"
2523     } elseif { $toPassArgsByFile == 1 && $isFirstSrcFile == 0 && [string equal -nocase [file extension $aSrcFile] ".cxx" ] } {
2524       # pass at list single source file to Code::Blocks as is
2525       # and pack the list of other files into the dedicated file to workaround process arguments limits on systems like Windows
2526       puts $aFile "\t\t<Unit filename=\"$aSrcFile\">"
2527       puts $aFile "\t\t\t<Option link=\"0\" />"
2528       puts $aFile "\t\t</Unit>"
2529
2530       set aFileObj  [string map {.cxx .o} [string map [list "/src/" "/$thePlatform/cbp/obj/src/"]  $aSrcFile]]
2531       set aFileObjd [string map {.cxx .o} [string map [list "/src/" "/$thePlatform/cbp/objd/src/"] $aSrcFile]]
2532       puts -nonewline $aFileLnkObj  "$aFileObj "
2533       puts -nonewline $aFileLnkObjd "$aFileObjd "
2534     } else {
2535       puts $aFile "\t\t<Unit filename=\"$aSrcFile\" />"
2536       set isFirstSrcFile 0
2537     }
2538   }
2539
2540   if { "$thePlatform" == "wnt" || "$thePlatform" == "uwp" } {
2541     close $aFileLnkObj
2542     close $aFileLnkObjd
2543   }
2544
2545   puts $aFile "\t</Project>"
2546   puts $aFile "</CodeBlocks_project_file>"
2547   close $aFile
2548
2549   return $aCbpFilePath
2550 }
2551
2552 # Define libraries to link using only EXTERNLIB file
2553 proc LibToLinkX {thePackage theDummyName} {
2554   set aToolKits [LibToLink $thePackage]
2555   return $aToolKits
2556 }
2557
2558 # Function to generate Xcode workspace and project files
2559 proc OS:MKXCD { theOutDir {theModules {}} {theAllSolution ""} {theLibType "dynamic"} {thePlatform ""} } {
2560
2561   puts stderr "Generating project files for Xcode"
2562
2563   # Generate projects for toolkits and separate workspace for each module
2564   foreach aModule $theModules {
2565     OS:xcworkspace $aModule $aModule $theOutDir
2566     OS:xcodeproj   $aModule          $theOutDir ::THE_GUIDS_LIST $theLibType $thePlatform
2567   }
2568
2569   # Generate single workspace "OCCT" containing projects from all modules
2570   if { "$theAllSolution" != "" } {
2571     OS:xcworkspace $theAllSolution $theModules $theOutDir
2572   }
2573 }
2574
2575 # Generates toolkits sections for Xcode workspace file.
2576 proc OS:xcworkspace:toolkits { theModule } {
2577   set aBuff ""
2578
2579   # Adding toolkits for module in workspace.
2580   foreach aToolKit [osutils:tk:sort [${theModule}:toolkits]] {
2581     append aBuff "         <FileRef\n"
2582     append aBuff "            location = \"group:${aToolKit}.xcodeproj\">\n"
2583     append aBuff "         </FileRef>\n"
2584   }
2585
2586   # Adding executables for module, assume one project per cxx file...
2587   foreach aUnit [OS:executable ${theModule}] {
2588     set aUnitLoc $aUnit
2589     set src_files [_get_used_files $aUnit false]
2590     set aSrcFiles {}
2591     foreach s $src_files {
2592       regexp {source ([^\s]+)} $s dummy name
2593       lappend aSrcFiles $name
2594     }
2595     foreach aSrcFile $aSrcFiles {
2596       set aFileExtension [file extension $aSrcFile]
2597       if { $aFileExtension == ".cxx" } {
2598         set aPrjName [file rootname $aSrcFile]
2599         append aBuff "         <FileRef\n"
2600         append aBuff "            location = \"group:${aPrjName}.xcodeproj\">\n"
2601         append aBuff "         </FileRef>\n"
2602       }
2603     }
2604   }
2605
2606   # Removing unnecessary newline character from the end.
2607   set aBuff [string replace $aBuff end end]
2608   return $aBuff
2609 }
2610
2611 # Generates workspace files for Xcode.
2612 proc OS:xcworkspace { theWorkspaceName theModules theOutDir } {
2613   # Creating workspace directory for Xcode.
2614   set aWorkspaceDir "${theOutDir}/${theWorkspaceName}.xcworkspace"
2615   wokUtils:FILES:mkdir $aWorkspaceDir
2616   if { ! [file exists $aWorkspaceDir] } {
2617     puts stderr "Error: Could not create workspace directory \"$aWorkspaceDir\""
2618     return
2619   }
2620
2621   # Creating workspace file.
2622   set aWsFilePath "${aWorkspaceDir}/contents.xcworkspacedata"
2623   set aFile [open $aWsFilePath "w"]
2624
2625   # Adding header and section for main Group.
2626   puts $aFile "<?xml version=\"1.0\" encoding=\"UTF-8\"?>"
2627   puts $aFile "<Workspace"
2628   puts $aFile "   version = \"1.0\">"
2629   puts $aFile "   <Group"
2630   puts $aFile "      location = \"container:\""
2631   puts $aFile "      name = \"${theWorkspaceName}\">"
2632
2633   # Adding modules.
2634   if { [llength "$theModules"] > 1 } {
2635     foreach aModule $theModules {
2636       puts $aFile "      <Group"
2637       puts $aFile "         location = \"container:\""
2638       puts $aFile "         name = \"${aModule}\">"
2639       puts $aFile [OS:xcworkspace:toolkits $aModule]
2640       puts $aFile "      </Group>"
2641     }
2642   } else {
2643     puts $aFile [OS:xcworkspace:toolkits $theModules]
2644   }
2645
2646   # Adding footer.
2647   puts $aFile "   </Group>"
2648   puts $aFile "</Workspace>"
2649   close $aFile
2650 }
2651
2652 # Generates Xcode project files.
2653 proc OS:xcodeproj { theModules theOutDir theGuidsMap theLibType thePlatform} {
2654   upvar $theGuidsMap aGuidsMap
2655
2656   set isStatic 0
2657   if { "$theLibType" == "static" } {
2658     set isStatic 1
2659   } elseif { "$thePlatform" == "ios" } {
2660     set isStatic 1
2661   }
2662
2663   set aProjectFiles {}
2664   foreach aModule $theModules {
2665     foreach aToolKit [${aModule}:toolkits] {
2666       lappend aProjectFiles [osutils:xcdtk $theOutDir $aToolKit     aGuidsMap $isStatic $thePlatform "dylib"]
2667     }
2668     foreach anExecutable [OS:executable ${aModule}] {
2669       lappend aProjectFiles [osutils:xcdtk $theOutDir $anExecutable aGuidsMap $isStatic $thePlatform "executable"]
2670     }
2671   }
2672   return $aProjectFiles
2673 }
2674
2675 # Generates dependencies section for Xcode project files.
2676 proc osutils:xcdtk:deps {theToolKit theTargetType theGuidsMap theFileRefSection theDepsGuids theDepsRefGuids theIsStatic} {
2677   upvar $theGuidsMap         aGuidsMap
2678   upvar $theFileRefSection   aFileRefSection
2679   upvar $theDepsGuids        aDepsGuids
2680   upvar $theDepsRefGuids     aDepsRefGuids
2681
2682   set aBuildFileSection ""
2683   set aUsedLibs         [wokUtils:LIST:Purge [osutils:tk:close $theToolKit]]
2684   set aDepToolkits      [lappend [wokUtils:LIST:Purge [osutils:tk:close $theToolKit]] $theToolKit]
2685
2686   if { "$theTargetType" == "executable" } {
2687     set aFile [osutils:tk:files $theToolKit mac]
2688     set aProjName [file rootname [file tail $aFile]]
2689     set aDepToolkits [LibToLinkX $theToolKit $aProjName]
2690   }
2691
2692   set aLibExt "dylib"
2693   if { $theIsStatic == 1 } {
2694     set aLibExt "a"
2695     if { "$theTargetType" != "executable" } {
2696       return $aBuildFileSection
2697     }
2698   }
2699
2700   osutils:usedOsLibs $theToolKit "mac" aLibs aFrameworks
2701   set aUsedLibs [concat $aUsedLibs $aLibs]
2702   set aUsedLibs [concat $aUsedLibs $aFrameworks]
2703   foreach tkx $aUsedLibs {
2704     set aDepLib    "${tkx}_Dep"
2705     set aDepLibRef "${tkx}_DepRef"
2706
2707     if { ! [info exists aGuidsMap($aDepLib)] } {
2708       set aGuidsMap($aDepLib) [OS:genGUID "xcd"]
2709     }
2710     if { ! [info exists aGuidsMap($aDepLibRef)] } {
2711       set aGuidsMap($aDepLibRef) [OS:genGUID "xcd"]
2712     }
2713
2714     append aBuildFileSection "\t\t$aGuidsMap($aDepLib) = \{isa = PBXBuildFile; fileRef = $aGuidsMap($aDepLibRef) ; \};\n"
2715     if {[lsearch -nocase $aFrameworks $tkx] == -1} {
2716       append aFileRefSection   "\t\t$aGuidsMap($aDepLibRef) = \{isa = PBXFileReference; lastKnownFileType = file; name = lib${tkx}.${aLibExt}; path = lib${tkx}.${aLibExt}; sourceTree = \"<group>\"; \};\n"
2717     } else {
2718       append aFileRefSection   "\t\t$aGuidsMap($aDepLibRef) = \{isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = ${tkx}.framework; path = /System/Library/Frameworks/${tkx}.framework; sourceTree = \"<absolute>\"; \};\n"
2719     }
2720     append aDepsGuids        "\t\t\t\t$aGuidsMap($aDepLib) ,\n"
2721     append aDepsRefGuids     "\t\t\t\t$aGuidsMap($aDepLibRef) ,\n"
2722   }
2723
2724   return $aBuildFileSection
2725 }
2726
2727 # Generates PBXBuildFile and PBXGroup sections for project file.
2728 proc osutils:xcdtk:sources {theToolKit theTargetType theSrcFileRefSection theGroupSection thePackageGuids theSrcFileGuids theGuidsMap theIncPaths} {
2729   upvar $theSrcFileRefSection aSrcFileRefSection
2730   upvar $theGroupSection      aGroupSection
2731   upvar $thePackageGuids      aPackagesGuids
2732   upvar $theSrcFileGuids      aSrcFileGuids
2733   upvar $theGuidsMap          aGuidsMap
2734   upvar $theIncPaths          anIncPaths
2735
2736   set listloc [osutils:tk:units $theToolKit]
2737   set resultloc [osutils:justunix $listloc]
2738   set aBuildFileSection ""
2739   set aPackages [lsort -nocase $resultloc]
2740   if { "$theTargetType" == "executable" } {
2741     set aPackages [list "$theToolKit"]
2742   }
2743
2744   # Generating PBXBuildFile, PBXGroup sections and groups for each package.
2745   foreach fxlo $aPackages {
2746     set xlo       $fxlo
2747     set aPackage "${xlo}_Package"
2748     set aSrcFileRefGuids ""
2749     if { ! [info exists aGuidsMap($aPackage)] } {
2750       set aGuidsMap($aPackage) [OS:genGUID "xcd"]
2751     }
2752
2753     set aSrcFiles [osutils:tk:files $xlo mac]
2754     foreach aSrcFile [lsort $aSrcFiles] {
2755       set aFileExt "sourcecode.cpp.cpp"
2756
2757       if { [file extension $aSrcFile] == ".c" } {
2758         set aFileExt "sourcecode.c.c"
2759       } elseif { [file extension $aSrcFile] == ".mm" } {
2760         set aFileExt "sourcecode.cpp.objcpp"
2761       }
2762
2763       if { ! [info exists aGuidsMap($aSrcFile)] } {
2764         set aGuidsMap($aSrcFile) [OS:genGUID "xcd"]
2765       }
2766       set aSrcFileRef "${aSrcFile}_Ref"
2767       if { ! [info exists aGuidsMap($aSrcFileRef)] } {
2768         set aGuidsMap($aSrcFileRef) [OS:genGUID "xcd"]
2769       }
2770       if { ! [info exists written([file tail $aSrcFile])] } {
2771         set written([file tail $aSrcFile]) 1
2772         append aBuildFileSection  "\t\t$aGuidsMap($aSrcFile) = \{isa = PBXBuildFile; fileRef = $aGuidsMap($aSrcFileRef) ;\};\n"
2773         append aSrcFileRefSection "\t\t$aGuidsMap($aSrcFileRef) = \{isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = ${aFileExt}; name = [wokUtils:FILES:wtail $aSrcFile 1]; path = ../../../[wokUtils:FILES:wtail $aSrcFile 3]; sourceTree = \"<group>\"; \};\n"
2774         append aSrcFileGuids      "\t\t\t\t$aGuidsMap($aSrcFile) ,\n"
2775         append aSrcFileRefGuids   "\t\t\t\t$aGuidsMap($aSrcFileRef) ,\n"
2776       } else {
2777         puts "Warning : more than one occurences for [file tail $aSrcFile]"
2778       }
2779     }
2780
2781     append aGroupSection "\t\t$aGuidsMap($aPackage) = \{\n"
2782     append aGroupSection "\t\t\tisa = PBXGroup;\n"
2783     append aGroupSection "\t\t\tchildren = (\n"
2784     append aGroupSection $aSrcFileRefGuids
2785     append aGroupSection "\t\t\t);\n"
2786     append aGroupSection "\t\t\tname = $xlo;\n"
2787     append aGroupSection "\t\t\tsourceTree = \"<group>\";\n"
2788     append aGroupSection "\t\t\};\n"
2789
2790     # Storing packages IDs for adding them later as a child of toolkit
2791     append aPackagesGuids "\t\t\t\t$aGuidsMap($aPackage) ,\n"
2792   }
2793
2794   # Removing unnecessary newline character from the end.
2795   set aPackagesGuids [string replace $aPackagesGuids end end]
2796
2797   return $aBuildFileSection
2798 }
2799
2800 # Creates folders structure and all necessary files for Xcode project.
2801 proc osutils:xcdtk { theOutDir theToolKit theGuidsMap theIsStatic thePlatform {theTargetType "dylib"} } {
2802   set aPBXBuildPhase "Headers"
2803   set aRunOnlyForDeployment "0"
2804   set aProductType "library.dynamic"
2805   set anExecExtension "\t\t\t\tEXECUTABLE_EXTENSION = dylib;"
2806   set anExecPrefix "\t\t\t\tEXECUTABLE_PREFIX = lib;"
2807   set aWrapperExtension "\t\t\t\tWRAPPER_EXTENSION = dylib;"
2808   set aTKDefines [list "OCC_CONVERT_SIGNALS"]
2809   if { $theIsStatic == 1 } {
2810     lappend aTKDefines "OCCT_NO_PLUGINS"
2811   }
2812
2813   if { "$theTargetType" == "executable" } {
2814     set aPBXBuildPhase "CopyFiles"
2815     set aRunOnlyForDeployment "1"
2816     set aProductType "tool"
2817     set anExecExtension ""
2818     set anExecPrefix ""
2819     set aWrapperExtension ""
2820   } elseif { $theIsStatic == 1 } {
2821     set aProductType "library.static"
2822     set anExecExtension "\t\t\t\tEXECUTABLE_EXTENSION = a;"
2823     set aWrapperExtension "\t\t\t\tWRAPPER_EXTENSION = a;"
2824   }
2825
2826   set aUsername [exec whoami]
2827
2828   # Creation of folders for Xcode projectP.
2829   set aToolkitDir "${theOutDir}/${theToolKit}.xcodeproj"
2830   wokUtils:FILES:mkdir $aToolkitDir
2831   if { ! [file exists $aToolkitDir] } {
2832     puts stderr "Error: Could not create project directory \"$aToolkitDir\""
2833     return
2834   }
2835
2836   set aUserDataDir "${aToolkitDir}/xcuserdata"
2837   wokUtils:FILES:mkdir $aUserDataDir
2838   if { ! [file exists $aUserDataDir] } {
2839     puts stderr "Error: Could not create xcuserdata directorty in \"$aToolkitDir\""
2840     return
2841   }
2842
2843   set aUserDataDir "${aUserDataDir}/${aUsername}.xcuserdatad"
2844   wokUtils:FILES:mkdir $aUserDataDir
2845   if { ! [file exists $aUserDataDir] } {
2846     puts stderr "Error: Could not create ${aUsername}.xcuserdatad directorty in \"$aToolkitDir\"/xcuserdata"
2847     return
2848   }
2849
2850   set aSchemesDir "${aUserDataDir}/xcschemes"
2851   wokUtils:FILES:mkdir $aSchemesDir
2852   if { ! [file exists $aSchemesDir] } {
2853     puts stderr "Error: Could not create xcschemes directorty in \"$aUserDataDir\""
2854     return
2855   }
2856   # End of folders creation.
2857
2858   # Generating GUID for tookit.
2859   upvar $theGuidsMap aGuidsMap
2860   if { ! [info exists aGuidsMap($theToolKit)] } {
2861     set aGuidsMap($theToolKit) [OS:genGUID "xcd"]
2862   }
2863
2864   # Creating xcscheme file for toolkit from template.
2865   set aXcschemeTmpl [osutils:readtemplate "xcscheme" "xcd"]
2866   regsub -all -- {__TOOLKIT_NAME__} $aXcschemeTmpl $theToolKit aXcschemeTmpl
2867   regsub -all -- {__TOOLKIT_GUID__} $aXcschemeTmpl $aGuidsMap($theToolKit) aXcschemeTmpl
2868   set aXcschemeFile [open "$aSchemesDir/${theToolKit}.xcscheme"  "w"]
2869   puts $aXcschemeFile $aXcschemeTmpl
2870   close $aXcschemeFile
2871
2872   # Creating xcschememanagement.plist file for toolkit from template.
2873   set aPlistTmpl [osutils:readtemplate "plist" "xcd"]
2874   regsub -all -- {__TOOLKIT_NAME__} $aPlistTmpl $theToolKit aPlistTmpl
2875   regsub -all -- {__TOOLKIT_GUID__} $aPlistTmpl $aGuidsMap($theToolKit) aPlistTmpl
2876   set aPlistFile [open "$aSchemesDir/xcschememanagement.plist"  "w"]
2877   puts $aPlistFile $aPlistTmpl
2878   close $aPlistFile
2879
2880   # Creating project.pbxproj file for toolkit.
2881   set aPbxprojFile [open "$aToolkitDir/project.pbxproj" "w"]
2882   puts $aPbxprojFile "// !\$*UTF8*\$!"
2883   puts $aPbxprojFile "\{"
2884   puts $aPbxprojFile "\tarchiveVersion = 1;"
2885   puts $aPbxprojFile "\tclasses = \{"
2886   puts $aPbxprojFile "\t\};"
2887   puts $aPbxprojFile "\tobjectVersion = 46;"
2888   puts $aPbxprojFile "\tobjects = \{\n"
2889
2890   # Begin PBXBuildFile section
2891   set aPackagesGuids ""
2892   set aGroupSection ""
2893   set aSrcFileRefSection ""
2894   set aSrcFileGuids ""
2895   set aDepsFileRefSection ""
2896   set aDepsGuids ""
2897   set aDepsRefGuids ""
2898   set anIncPaths [list "../../../inc"]
2899   set anLibPaths ""
2900
2901   if { [info exists ::env(CSF_OPT_INC)] } {
2902     set anIncCfg [split "$::env(CSF_OPT_INC)" ":"]
2903     foreach anIncCfgPath $anIncCfg {
2904       lappend anIncPaths $anIncCfgPath
2905     }
2906   }
2907   if { [info exists ::env(CSF_OPT_LIB64)] } {
2908     set anLibCfg [split "$::env(CSF_OPT_LIB64)" ":"]
2909     foreach anLibCfgPath $anLibCfg {
2910       lappend anLibPaths $anLibCfgPath
2911     }
2912   }
2913
2914   puts $aPbxprojFile [osutils:xcdtk:sources $theToolKit $theTargetType aSrcFileRefSection aGroupSection aPackagesGuids aSrcFileGuids aGuidsMap anIncPaths]
2915   puts $aPbxprojFile [osutils:xcdtk:deps    $theToolKit $theTargetType aGuidsMap aDepsFileRefSection aDepsGuids aDepsRefGuids $theIsStatic]
2916   # End PBXBuildFile section
2917
2918   # Begin PBXFileReference section
2919   set aToolkitLib "lib${theToolKit}.dylib"
2920   set aPath "$aToolkitLib"
2921   if { "$theTargetType" == "executable" } {
2922     set aPath "$theToolKit"
2923   } elseif { $theIsStatic == 1 } {
2924     set aToolkitLib "lib${theToolKit}.a"
2925   }
2926
2927   if { ! [info exists aGuidsMap($aToolkitLib)] } {
2928     set aGuidsMap($aToolkitLib) [OS:genGUID "xcd"]
2929   }
2930
2931   puts $aPbxprojFile "\t\t$aGuidsMap($aToolkitLib) = {isa = PBXFileReference; explicitFileType = \"compiled.mach-o.${theTargetType}\"; includeInIndex = 0; path = $aPath; sourceTree = BUILT_PRODUCTS_DIR; };\n"
2932   puts $aPbxprojFile $aSrcFileRefSection
2933   puts $aPbxprojFile $aDepsFileRefSection
2934   # End PBXFileReference section
2935
2936
2937   # Begin PBXFrameworksBuildPhase section
2938   set aTkFrameworks "${theToolKit}_Frameworks"
2939   if { ! [info exists aGuidsMap($aTkFrameworks)] } {
2940     set aGuidsMap($aTkFrameworks) [OS:genGUID "xcd"]
2941   }
2942
2943   puts $aPbxprojFile "\t\t$aGuidsMap($aTkFrameworks) = \{"
2944   puts $aPbxprojFile "\t\t\tisa = PBXFrameworksBuildPhase;"
2945   puts $aPbxprojFile "\t\t\tbuildActionMask = 2147483647;"
2946   puts $aPbxprojFile "\t\t\tfiles = ("
2947   puts $aPbxprojFile $aDepsGuids
2948   puts $aPbxprojFile "\t\t\t);"
2949   puts $aPbxprojFile "\t\t\trunOnlyForDeploymentPostprocessing = 0;"
2950   puts $aPbxprojFile "\t\t\};\n"
2951   # End PBXFrameworksBuildPhase section
2952
2953   # Begin PBXGroup section
2954   set aTkPBXGroup "${theToolKit}_PBXGroup"
2955   if { ! [info exists aGuidsMap($aTkPBXGroup)] } {
2956     set aGuidsMap($aTkPBXGroup) [OS:genGUID "xcd"]
2957   }
2958
2959   set aTkSrcGroup "${theToolKit}_SrcGroup"
2960   if { ! [info exists aGuidsMap($aTkSrcGroup)] } {
2961     set aGuidsMap($aTkSrcGroup) [OS:genGUID "xcd"]
2962   }
2963
2964   puts $aPbxprojFile $aGroupSection
2965   puts $aPbxprojFile "\t\t$aGuidsMap($aTkPBXGroup) = \{"
2966   puts $aPbxprojFile "\t\t\tisa = PBXGroup;"
2967   puts $aPbxprojFile "\t\t\tchildren = ("
2968   puts $aPbxprojFile $aDepsRefGuids
2969   puts $aPbxprojFile "\t\t\t\t$aGuidsMap($aTkSrcGroup) ,"
2970   puts $aPbxprojFile "\t\t\t\t$aGuidsMap($aToolkitLib) ,"
2971   puts $aPbxprojFile "\t\t\t);"
2972   puts $aPbxprojFile "\t\t\tsourceTree = \"<group>\";"
2973   puts $aPbxprojFile "\t\t\};"
2974   puts $aPbxprojFile "\t\t$aGuidsMap($aTkSrcGroup) = \{"
2975   puts $aPbxprojFile "\t\t\tisa = PBXGroup;"
2976   puts $aPbxprojFile "\t\t\tchildren = ("
2977   puts $aPbxprojFile $aPackagesGuids
2978   puts $aPbxprojFile "\t\t\t);"
2979   puts $aPbxprojFile "\t\t\tname = \"Source files\";"
2980   puts $aPbxprojFile "\t\t\tsourceTree = \"<group>\";"
2981   puts $aPbxprojFile "\t\t\};\n"
2982   # End PBXGroup section
2983
2984   # Begin PBXHeadersBuildPhase section
2985   set aTkHeaders "${theToolKit}_Headers"
2986   if { ! [info exists aGuidsMap($aTkHeaders)] } {
2987     set aGuidsMap($aTkHeaders) [OS:genGUID "xcd"]
2988   }
2989
2990   puts $aPbxprojFile "\t\t$aGuidsMap($aTkHeaders) = \{"
2991   puts $aPbxprojFile "\t\t\tisa = PBX${aPBXBuildPhase}BuildPhase;"
2992   puts $aPbxprojFile "\t\t\tbuildActionMask = 2147483647;"
2993   puts $aPbxprojFile "\t\t\tfiles = ("
2994   puts $aPbxprojFile "\t\t\t);"
2995   puts $aPbxprojFile "\t\t\trunOnlyForDeploymentPostprocessing = ${aRunOnlyForDeployment};"
2996   puts $aPbxprojFile "\t\t\};\n"
2997   # End PBXHeadersBuildPhase section
2998
2999   # Begin PBXNativeTarget section
3000   set aTkBuildCfgListNativeTarget "${theToolKit}_BuildCfgListNativeTarget"
3001   if { ! [info exists aGuidsMap($aTkBuildCfgListNativeTarget)] } {
3002     set aGuidsMap($aTkBuildCfgListNativeTarget) [OS:genGUID "xcd"]
3003   }
3004
3005   set aTkSources "${theToolKit}_Sources"
3006   if { ! [info exists aGuidsMap($aTkSources)] } {
3007     set aGuidsMap($aTkSources) [OS:genGUID "xcd"]
3008   }
3009
3010   puts $aPbxprojFile "\t\t$aGuidsMap($theToolKit) = \{"
3011   puts $aPbxprojFile "\t\t\tisa = PBXNativeTarget;"
3012   puts $aPbxprojFile "\t\t\tbuildConfigurationList = $aGuidsMap($aTkBuildCfgListNativeTarget) ;"
3013   puts $aPbxprojFile "\t\t\tbuildPhases = ("
3014   puts $aPbxprojFile "\t\t\t\t$aGuidsMap($aTkSources) ,"
3015   puts $aPbxprojFile "\t\t\t\t$aGuidsMap($aTkFrameworks) ,"
3016   puts $aPbxprojFile "\t\t\t\t$aGuidsMap($aTkHeaders) ,"
3017   puts $aPbxprojFile "\t\t\t);"
3018   puts $aPbxprojFile "\t\t\tbuildRules = ("
3019   puts $aPbxprojFile "\t\t\t);"
3020   puts $aPbxprojFile "\t\t\tdependencies = ("
3021   puts $aPbxprojFile "\t\t\t);"
3022   puts $aPbxprojFile "\t\t\tname = $theToolKit;"
3023   puts $aPbxprojFile "\t\t\tproductName = $theToolKit;"
3024   puts $aPbxprojFile "\t\t\tproductReference = $aGuidsMap($aToolkitLib) ;"
3025   puts $aPbxprojFile "\t\t\tproductType = \"com.apple.product-type.${aProductType}\";"
3026   puts $aPbxprojFile "\t\t\};\n"
3027   # End PBXNativeTarget section
3028
3029   # Begin PBXProject section
3030   set aTkProjectObj "${theToolKit}_ProjectObj"
3031   if { ! [info exists aGuidsMap($aTkProjectObj)] } {
3032     set aGuidsMap($aTkProjectObj) [OS:genGUID "xcd"]
3033   }
3034
3035   set aTkBuildCfgListProj "${theToolKit}_BuildCfgListProj"
3036   if { ! [info exists aGuidsMap($aTkBuildCfgListProj)] } {
3037     set aGuidsMap($aTkBuildCfgListProj) [OS:genGUID "xcd"]
3038   }
3039
3040   puts $aPbxprojFile "\t\t$aGuidsMap($aTkProjectObj) = \{"
3041   puts $aPbxprojFile "\t\t\tisa = PBXProject;"
3042   puts $aPbxprojFile "\t\t\tattributes = \{"
3043   puts $aPbxprojFile "\t\t\t\tLastUpgradeCheck = 0430;"
3044   puts $aPbxprojFile "\t\t\t\};"
3045   puts $aPbxprojFile "\t\t\tbuildConfigurationList = $aGuidsMap($aTkBuildCfgListProj) ;"
3046   puts $aPbxprojFile "\t\t\tcompatibilityVersion = \"Xcode 3.2\";"
3047   puts $aPbxprojFile "\t\t\tdevelopmentRegion = English;"
3048   puts $aPbxprojFile "\t\t\thasScannedForEncodings = 0;"
3049   puts $aPbxprojFile "\t\t\tknownRegions = ("
3050   puts $aPbxprojFile "\t\t\t\ten,"
3051   puts $aPbxprojFile "\t\t\t);"
3052   puts $aPbxprojFile "\t\t\tmainGroup = $aGuidsMap($aTkPBXGroup);"
3053   puts $aPbxprojFile "\t\t\tproductRefGroup = $aGuidsMap($aTkPBXGroup);"
3054   puts $aPbxprojFile "\t\t\tprojectDirPath = \"\";"
3055   puts $aPbxprojFile "\t\t\tprojectRoot = \"\";"
3056   puts $aPbxprojFile "\t\t\ttargets = ("
3057   puts $aPbxprojFile "\t\t\t\t$aGuidsMap($theToolKit) ,"
3058   puts $aPbxprojFile "\t\t\t);"
3059   puts $aPbxprojFile "\t\t\};\n"
3060   # End PBXProject section
3061
3062   # Begin PBXSourcesBuildPhase section
3063   puts $aPbxprojFile "\t\t$aGuidsMap($aTkSources) = \{"
3064   puts $aPbxprojFile "\t\t\tisa = PBXSourcesBuildPhase;"
3065   puts $aPbxprojFile "\t\t\tbuildActionMask = 2147483647;"
3066   puts $aPbxprojFile "\t\t\tfiles = ("
3067   puts $aPbxprojFile $aSrcFileGuids
3068   puts $aPbxprojFile "\t\t\t);"
3069   puts $aPbxprojFile "\t\t\trunOnlyForDeploymentPostprocessing = 0;"
3070   puts $aPbxprojFile "\t\t\};\n"
3071   # End PBXSourcesBuildPhase section
3072
3073   # Begin XCBuildConfiguration section
3074   set aTkDebugProject "${theToolKit}_DebugProject"
3075   if { ! [info exists aGuidsMap($aTkDebugProject)] } {
3076     set aGuidsMap($aTkDebugProject) [OS:genGUID "xcd"]
3077   }
3078
3079   set aTkReleaseProject "${theToolKit}_ReleaseProject"
3080   if { ! [info exists aGuidsMap($aTkReleaseProject)] } {
3081     set aGuidsMap($aTkReleaseProject) [OS:genGUID "xcd"]
3082   }
3083
3084   set aTkDebugNativeTarget "${theToolKit}_DebugNativeTarget"
3085   if { ! [info exists aGuidsMap($aTkDebugNativeTarget)] } {
3086     set aGuidsMap($aTkDebugNativeTarget) [OS:genGUID "xcd"]
3087   }
3088
3089   set aTkReleaseNativeTarget "${theToolKit}_ReleaseNativeTarget"
3090   if { ! [info exists aGuidsMap($aTkReleaseNativeTarget)] } {
3091     set aGuidsMap($aTkReleaseNativeTarget) [OS:genGUID "xcd"]
3092   }
3093
3094   # Debug target
3095   puts $aPbxprojFile "\t\t$aGuidsMap($aTkDebugProject) = \{"
3096   puts $aPbxprojFile "\t\t\tisa = XCBuildConfiguration;"
3097   puts $aPbxprojFile "\t\t\tbuildSettings = \{"
3098
3099   puts $aPbxprojFile "\t\t\t\tDEBUG_INFORMATION_FORMAT = dwarf;"
3100   puts $aPbxprojFile "\t\t\t\tALWAYS_SEARCH_USER_PATHS = NO;"
3101   if { "$thePlatform" == "ios" } {
3102     puts $aPbxprojFile "\t\t\t\t\"ARCHS\[sdk=iphoneos\*\]\" = \"\$(ARCHS_STANDARD)\";";
3103     puts $aPbxprojFile "\t\t\t\t\"ARCHS\[sdk=iphonesimulator\*\]\" = \"x86_64\";";
3104     puts $aPbxprojFile "\t\t\t\tCLANG_ENABLE_MODULES = YES;"
3105     puts $aPbxprojFile "\t\t\t\tCLANG_ENABLE_OBJC_ARC = YES;"
3106   }
3107   puts $aPbxprojFile "\t\t\t\tARCHS = \"\$(ARCHS_STANDARD_64_BIT)\";"
3108   puts $aPbxprojFile "\t\t\t\tCLANG_CXX_LIBRARY = \"libc++\";"
3109   puts $aPbxprojFile "\t\t\t\tCLANG_CXX_LANGUAGE_STANDARD = \"c++0x\";"
3110   puts $aPbxprojFile "\t\t\t\tCOPY_PHASE_STRIP = NO;"
3111   puts $aPbxprojFile "\t\t\t\tGCC_C_LANGUAGE_STANDARD = gnu99;"
3112   puts $aPbxprojFile "\t\t\t\tGCC_DYNAMIC_NO_PIC = NO;"
3113   puts $aPbxprojFile "\t\t\t\tGCC_ENABLE_OBJC_EXCEPTIONS = YES;"
3114   puts $aPbxprojFile "\t\t\t\tGCC_OPTIMIZATION_LEVEL = 0;"
3115   puts $aPbxprojFile "\t\t\t\tGCC_PREPROCESSOR_DEFINITIONS = ("
3116   puts $aPbxprojFile "\t\t\t\t\t\"DEBUG=1\","
3117   puts $aPbxprojFile "\t\t\t\t\t\"\$\(inherited\)\","
3118   puts $aPbxprojFile "\t\t\t\t);"
3119   puts $aPbxprojFile "\t\t\t\tGCC_SYMBOLS_PRIVATE_EXTERN = NO;"
3120   puts $aPbxprojFile "\t\t\t\tGCC_VERSION = com.apple.compilers.llvm.clang.1_0;"
3121   puts $aPbxprojFile "\t\t\t\tGCC_WARN_64_TO_32_BIT_CONVERSION = YES;"
3122   puts $aPbxprojFile "\t\t\t\tGCC_WARN_ABOUT_RETURN_TYPE = YES;"
3123   puts $aPbxprojFile "\t\t\t\tGCC_WARN_UNINITIALIZED_AUTOS = YES;"
3124   puts $aPbxprojFile "\t\t\t\tGCC_WARN_UNUSED_VARIABLE = YES;"
3125   puts $aPbxprojFile "\t\t\t\tOTHER_LDFLAGS = \"\$(CSF_OPT_LNK64D)\"; "
3126   if { "$thePlatform" == "ios" } {
3127     puts $aPbxprojFile "\t\t\t\tONLY_ACTIVE_ARCH = NO;"
3128     puts $aPbxprojFile "\t\t\t\tSDKROOT = iphoneos;"
3129   } else {
3130     puts $aPbxprojFile "\t\t\t\tONLY_ACTIVE_ARCH = YES;"
3131   }
3132   puts $aPbxprojFile "\t\t\t\};"
3133
3134   puts $aPbxprojFile "\t\t\tname = Debug;"
3135   puts $aPbxprojFile "\t\t\};"
3136
3137   # Release target
3138   puts $aPbxprojFile "\t\t$aGuidsMap($aTkReleaseProject) = \{"
3139   puts $aPbxprojFile "\t\t\tisa = XCBuildConfiguration;"
3140   puts $aPbxprojFile "\t\t\tbuildSettings = \{"
3141
3142   puts $aPbxprojFile "\t\t\t\tDEBUG_INFORMATION_FORMAT = \"dwarf-with-dsym\";"
3143   puts $aPbxprojFile "\t\t\t\tALWAYS_SEARCH_USER_PATHS = NO;"
3144   if { "$thePlatform" == "ios" } {
3145     puts $aPbxprojFile "\t\t\t\t\"ARCHS\[sdk=iphoneos\*\]\" = \"\$(ARCHS_STANDARD)\";";
3146     puts $aPbxprojFile "\t\t\t\t\"ARCHS\[sdk=iphonesimulator\*\]\" = \"x86_64\";";
3147     puts $aPbxprojFile "\t\t\t\tCLANG_ENABLE_MODULES = YES;"
3148     puts $aPbxprojFile "\t\t\t\tCLANG_ENABLE_OBJC_ARC = YES;"
3149   }
3150   puts $aPbxprojFile "\t\t\t\tARCHS = \"\$(ARCHS_STANDARD_64_BIT)\";"
3151   puts $aPbxprojFile "\t\t\t\tCLANG_CXX_LIBRARY = \"libc++\";"
3152   puts $aPbxprojFile "\t\t\t\tCLANG_CXX_LANGUAGE_STANDARD = \"c++0x\";"
3153   puts $aPbxprojFile "\t\t\t\tCOPY_PHASE_STRIP = YES;"
3154   puts $aPbxprojFile "\t\t\t\tGCC_C_LANGUAGE_STANDARD = gnu99;"
3155   puts $aPbxprojFile "\t\t\t\tGCC_ENABLE_OBJC_EXCEPTIONS = YES;"
3156   puts $aPbxprojFile "\t\t\t\tDEAD_CODE_STRIPPING = NO;"
3157   puts $aPbxprojFile "\t\t\t\tGCC_OPTIMIZATION_LEVEL = 2;"
3158   puts $aPbxprojFile "\t\t\t\tGCC_VERSION = com.apple.compilers.llvm.clang.1_0;"
3159   puts $aPbxprojFile "\t\t\t\tGCC_WARN_64_TO_32_BIT_CONVERSION = YES;"
3160   puts $aPbxprojFile "\t\t\t\tGCC_WARN_ABOUT_RETURN_TYPE = YES;"
3161   puts $aPbxprojFile "\t\t\t\tGCC_WARN_UNINITIALIZED_AUTOS = YES;"
3162   puts $aPbxprojFile "\t\t\t\tGCC_WARN_UNUSED_VARIABLE = YES;"
3163   puts $aPbxprojFile "\t\t\t\tOTHER_LDFLAGS = \"\$(CSF_OPT_LNK64)\";"
3164   if { "$thePlatform" == "ios" } {
3165     puts $aPbxprojFile "\t\t\t\tIPHONEOS_DEPLOYMENT_TARGET = 7.0;"
3166     puts $aPbxprojFile "\t\t\t\tSDKROOT = iphoneos;"
3167   }
3168   puts $aPbxprojFile "\t\t\t\};"
3169   puts $aPbxprojFile "\t\t\tname = Release;"
3170   puts $aPbxprojFile "\t\t\};"
3171   puts $aPbxprojFile "\t\t$aGuidsMap($aTkDebugNativeTarget) = \{"
3172   puts $aPbxprojFile "\t\t\tisa = XCBuildConfiguration;"
3173   puts $aPbxprojFile "\t\t\tbuildSettings = \{"
3174   puts $aPbxprojFile "${anExecExtension}"
3175   puts $aPbxprojFile "${anExecPrefix}"
3176   puts $aPbxprojFile "\t\t\t\tGCC_PREPROCESSOR_DEFINITIONS = ("
3177   foreach aMacro $aTKDefines {
3178     puts $aPbxprojFile "\t\t\t\t\t${aMacro} ,"
3179   }
3180   puts $aPbxprojFile "\t\t\t\t);"
3181
3182   puts $aPbxprojFile "\t\t\t\tHEADER_SEARCH_PATHS = ("
3183   foreach anIncPath $anIncPaths {
3184     puts $aPbxprojFile "\t\t\t\t\t${anIncPath},"
3185   }
3186   puts $aPbxprojFile "\t\t\t\t\t\"\$(CSF_OPT_INC)\","
3187   puts $aPbxprojFile "\t\t\t\t);"
3188
3189   puts $aPbxprojFile "\t\t\t\tLIBRARY_SEARCH_PATHS = ("
3190   foreach anLibPath $anLibPaths {
3191     puts $aPbxprojFile "\t\t\t\t\t${anLibPath},"
3192   }
3193   puts $aPbxprojFile "\t\t\t\t);"
3194
3195   puts $aPbxprojFile "\t\t\t\tOTHER_CFLAGS = ("
3196   puts $aPbxprojFile "\t\t\t\t\t\"\$(CSF_OPT_CMPL)\","
3197   puts $aPbxprojFile "\t\t\t\t);"
3198   puts $aPbxprojFile "\t\t\t\tOTHER_CPLUSPLUSFLAGS = ("
3199   puts $aPbxprojFile "\t\t\t\t\t\"\$(OTHER_CFLAGS)\","
3200   puts $aPbxprojFile "\t\t\t\t);"
3201   puts $aPbxprojFile "\t\t\t\tPRODUCT_NAME = \"\$(TARGET_NAME)\";"
3202   set anUserHeaderSearchPath "\t\t\t\tUSER_HEADER_SEARCH_PATHS = \""
3203   foreach anIncPath $anIncPaths {
3204     append anUserHeaderSearchPath " ${anIncPath}"
3205   }
3206   append anUserHeaderSearchPath "\";"
3207   puts $aPbxprojFile $anUserHeaderSearchPath
3208   puts $aPbxprojFile "${aWrapperExtension}"
3209   puts $aPbxprojFile "\t\t\t\};"
3210   puts $aPbxprojFile "\t\t\tname = Debug;"
3211   puts $aPbxprojFile "\t\t\};"
3212   puts $aPbxprojFile "\t\t$aGuidsMap($aTkReleaseNativeTarget) = \{"
3213   puts $aPbxprojFile "\t\t\tisa = XCBuildConfiguration;"
3214   puts $aPbxprojFile "\t\t\tbuildSettings = \{"
3215   puts $aPbxprojFile "${anExecExtension}"
3216   puts $aPbxprojFile "${anExecPrefix}"
3217   puts $aPbxprojFile "\t\t\t\tGCC_PREPROCESSOR_DEFINITIONS = ("
3218   foreach aMacro $aTKDefines {
3219     puts $aPbxprojFile "\t\t\t\t\t${aMacro} ,"
3220   }
3221   puts $aPbxprojFile "\t\t\t\t);"
3222   puts $aPbxprojFile "\t\t\t\tHEADER_SEARCH_PATHS = ("
3223   foreach anIncPath $anIncPaths {
3224     puts $aPbxprojFile "\t\t\t\t\t${anIncPath},"
3225   }
3226   puts $aPbxprojFile "\t\t\t\t\t\"\$(CSF_OPT_INC)\","
3227   puts $aPbxprojFile "\t\t\t\t);"
3228
3229   puts $aPbxprojFile "\t\t\t\tLIBRARY_SEARCH_PATHS = ("
3230   foreach anLibPath $anLibPaths {
3231     puts $aPbxprojFile "\t\t\t\t\t${anLibPath},"
3232   }
3233   puts $aPbxprojFile "\t\t\t\t);"
3234
3235   puts $aPbxprojFile "\t\t\t\tOTHER_CFLAGS = ("
3236   puts $aPbxprojFile "\t\t\t\t\t\"\$(CSF_OPT_CMPL)\","
3237   puts $aPbxprojFile "\t\t\t\t);"
3238   puts $aPbxprojFile "\t\t\t\tOTHER_CPLUSPLUSFLAGS = ("
3239   puts $aPbxprojFile "\t\t\t\t\t\"\$(OTHER_CFLAGS)\","
3240   puts $aPbxprojFile "\t\t\t\t);"
3241   puts $aPbxprojFile "\t\t\t\tPRODUCT_NAME = \"\$(TARGET_NAME)\";"
3242   puts $aPbxprojFile $anUserHeaderSearchPath
3243   puts $aPbxprojFile "${aWrapperExtension}"
3244   puts $aPbxprojFile "\t\t\t\};"
3245   puts $aPbxprojFile "\t\t\tname = Release;"
3246   puts $aPbxprojFile "\t\t\};\n"
3247   # End XCBuildConfiguration section
3248
3249   # Begin XCConfigurationList section
3250   puts $aPbxprojFile "\t\t$aGuidsMap($aTkBuildCfgListProj) = \{"
3251   puts $aPbxprojFile "\t\t\tisa = XCConfigurationList;"
3252   puts $aPbxprojFile "\t\tbuildConfigurations = ("
3253   puts $aPbxprojFile "\t\t\t\t$aGuidsMap($aTkDebugProject) ,"
3254   puts $aPbxprojFile "\t\t\t\t$aGuidsMap($aTkReleaseProject) ,"
3255   puts $aPbxprojFile "\t\t\t);"
3256   puts $aPbxprojFile "\t\t\tdefaultConfigurationIsVisible = 0;"
3257   puts $aPbxprojFile "\t\t\tdefaultConfigurationName = Release;"
3258   puts $aPbxprojFile "\t\t\};"
3259   puts $aPbxprojFile "\t\t$aGuidsMap($aTkBuildCfgListNativeTarget) = \{"
3260   puts $aPbxprojFile "\t\t\tisa = XCConfigurationList;"
3261   puts $aPbxprojFile "\t\t\tbuildConfigurations = ("
3262   puts $aPbxprojFile "\t\t\t\t$aGuidsMap($aTkDebugNativeTarget) ,"
3263   puts $aPbxprojFile "\t\t\t\t$aGuidsMap($aTkReleaseNativeTarget) ,"
3264   puts $aPbxprojFile "\t\t\t);"
3265   puts $aPbxprojFile "\t\t\tdefaultConfigurationIsVisible = 0;"
3266   puts $aPbxprojFile "\t\t\tdefaultConfigurationName = Release;"
3267   puts $aPbxprojFile "\t\t\};\n"
3268   # End XCConfigurationList section
3269
3270   puts $aPbxprojFile "\t\};"
3271   puts $aPbxprojFile "\trootObject = $aGuidsMap($aTkProjectObj) ;"
3272   puts $aPbxprojFile "\}"
3273
3274   close $aPbxprojFile
3275 }
3276
3277 proc osutils:xcdx { theOutDir theExecutable theGuidsMap } {
3278   set aUsername [exec whoami]
3279
3280   # Creating folders for Xcode project file.
3281   set anExecutableDir "${theOutDir}/${theExecutable}.xcodeproj"
3282   wokUtils:FILES:mkdir $anExecutableDir
3283   if { ! [file exists $anExecutableDir] } {
3284     puts stderr "Error: Could not create project directory \"$anExecutableDir\""
3285     return
3286   }
3287
3288   set aUserDataDir "${anExecutableDir}/xcuserdata"
3289   wokUtils:FILES:mkdir $aUserDataDir
3290   if { ! [file exists $aUserDataDir] } {
3291     puts stderr "Error: Could not create xcuserdata directorty in \"$anExecutableDir\""
3292     return
3293   }
3294
3295   set aUserDataDir "${aUserDataDir}/${aUsername}.xcuserdatad"
3296   wokUtils:FILES:mkdir $aUserDataDir
3297   if { ! [file exists $aUserDataDir] } {
3298     puts stderr "Error: Could not create ${aUsername}.xcuserdatad directorty in \"$anExecutableDir\"/xcuserdata"
3299     return
3300   }
3301
3302   set aSchemesDir "${aUserDataDir}/xcschemes"
3303   wokUtils:FILES:mkdir $aSchemesDir
3304   if { ! [file exists $aSchemesDir] } {
3305     puts stderr "Error: Could not create xcschemes directorty in \"$aUserDataDir\""
3306     return
3307   }
3308   # End folders creation.
3309
3310   # Generating GUID for tookit.
3311   upvar $theGuidsMap aGuidsMap
3312   if { ! [info exists aGuidsMap($theExecutable)] } {
3313     set aGuidsMap($theExecutable) [OS:genGUID "xcd"]
3314   }
3315
3316   # Creating xcscheme file for toolkit from template.
3317   set aXcschemeTmpl [osutils:readtemplate "xcscheme" "xcode"]
3318   regsub -all -- {__TOOLKIT_NAME__} $aXcschemeTmpl $theExecutable aXcschemeTmpl
3319   regsub -all -- {__TOOLKIT_GUID__} $aXcschemeTmpl $aGuidsMap($theExecutable) aXcschemeTmpl
3320   set aXcschemeFile [open "$aSchemesDir/${theExecutable}.xcscheme"  "w"]
3321   puts $aXcschemeFile $aXcschemeTmpl
3322   close $aXcschemeFile
3323
3324   # Creating xcschememanagement.plist file for toolkit from template.
3325   set aPlistTmpl [osutils:readtemplate "plist" "xcode"]
3326   regsub -all -- {__TOOLKIT_NAME__} $aPlistTmpl $theExecutable aPlistTmpl
3327   regsub -all -- {__TOOLKIT_GUID__} $aPlistTmpl $aGuidsMap($theExecutable) aPlistTmpl
3328   set aPlistFile [open "$aSchemesDir/xcschememanagement.plist"  "w"]
3329   puts $aPlistFile $aPlistTmpl
3330   close $aPlistFile
3331 }
3332
3333 # Returns available Windows SDKs versions
3334 proc osutils:sdk { theSdkMajorVer {isQuietMode false} {theSdkDirectories {}} } {
3335   if { ![llength ${theSdkDirectories}] } {
3336     foreach anEnvVar { "ProgramFiles" "ProgramFiles\(x86\)" "ProgramW6432" } {
3337       if {[ info exists ::env(${anEnvVar}) ]} {
3338         lappend theSdkDirectories "$::env(${anEnvVar})/Windows Kits/${theSdkMajorVer}/Include"
3339       }
3340     }
3341   }
3342
3343   set sdk_versions {}
3344   foreach sdk_dir ${theSdkDirectories} {
3345     if { [file isdirectory ${sdk_dir}] } {
3346       lappend sdk_versions [glob -tails -directory "${sdk_dir}" -type d *]
3347     }
3348   }
3349
3350   if {![llength ${sdk_versions}] && !${isQuietMode}} {
3351     error "Error : Could not find Windows SDK ${theSdkMajorVer}"
3352   }
3353
3354   return [join [lsort -unique ${sdk_versions}] " "]
3355 }
3356
3357 # Generate global properties to Visual Studio project file for UWP solution
3358 proc osutils:uwp:proj { isUWP theProjTmpl } {
3359
3360   set uwp_properties ""
3361   set uwp_generate_metadata ""
3362   set uwp_app_container ""
3363
3364   set format_template ""
3365
3366   if { $isUWP } {
3367     set sdk_versions [osutils:sdk 10]
3368     set sdk_max_ver [lindex ${sdk_versions} end]
3369
3370     set uwp_properties "<DefaultLanguage>en-US</DefaultLanguage>\n   \
3371 <ApplicationType>Windows Store</ApplicationType>\n   \
3372 <ApplicationTypeRevision>10.0</ApplicationTypeRevision>\n   \
3373 <MinimumVisualStudioVersion>14.0</MinimumVisualStudioVersion>\n   \
3374 <AppContainerApplication>true</AppContainerApplication>\n   \
3375 <WindowsTargetPlatformVersion>${sdk_max_ver}</WindowsTargetPlatformVersion>\n   \
3376 <WindowsTargetPlatformMinVersion>${sdk_max_ver}</WindowsTargetPlatformMinVersion>"
3377
3378     set uwp_generate_metadata        "<GenerateWindowsMetadata>false</GenerateWindowsMetadata>"
3379
3380     regsub -all -- {[\r\n\s]*<BasicRuntimeChecks>EnableFastChecks</BasicRuntimeChecks>} ${theProjTmpl} "" theProjTmpl
3381   } else {
3382     set format_template "\[\\r\\n\\s\]*"
3383   }
3384
3385   regsub -all -- "${format_template}__UWP_PROPERTIES__"        ${theProjTmpl} "${uwp_properties}" theProjTmpl
3386   regsub -all -- "${format_template}__UWP_GENERATE_METADATA__" ${theProjTmpl} "${uwp_generate_metadata}" theProjTmpl
3387
3388   return ${theProjTmpl}
3389 }
3390
3391 # Report all files found in package directory but not listed in FILES
3392 proc osutils:checksrcfiles { theUnit } {
3393   global path
3394   set aCasRoot [file normalize ${path}]
3395
3396   if {![file isdirectory ${aCasRoot}]} {
3397     puts "OCCT directory is not defined correctly: ${aCasRoot}"
3398     return
3399   }
3400
3401   set anUnitAbsPath [file normalize "${aCasRoot}/src/${theUnit}"]
3402
3403   if {[file exists "${anUnitAbsPath}/FILES"]} {
3404     set aFilesFile [open "${anUnitAbsPath}/FILES" rb]
3405     set aFilesFileList [split [read ${aFilesFile}] "\n"]
3406     close ${aFilesFile}
3407
3408     set aFilesFileList [lsearch -inline -all -not -exact ${aFilesFileList} ""]
3409
3410     # report all files not listed in FILES
3411     set anAllFiles [glob -tails -nocomplain -dir ${anUnitAbsPath} "*"]
3412     foreach aFile ${anAllFiles} {
3413       if { "${aFile}" == "FILES" } {
3414         continue
3415       }
3416       if { [lsearch -exact ${aFilesFileList} ${aFile}] == -1 } {
3417         puts "Warning: file ${anUnitAbsPath}/${aFile} is not listed in ${anUnitAbsPath}/FILES!"
3418       }
3419     }
3420   }
3421 }