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