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