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