diff options
Diffstat (limited to 'tksao/tclconfig/practcl.tcl')
-rw-r--r-- | tksao/tclconfig/practcl.tcl | 4923 |
1 files changed, 0 insertions, 4923 deletions
diff --git a/tksao/tclconfig/practcl.tcl b/tksao/tclconfig/practcl.tcl deleted file mode 100644 index ecabbf8..0000000 --- a/tksao/tclconfig/practcl.tcl +++ /dev/null @@ -1,4923 +0,0 @@ -### -# Practcl -# An object oriented templating system for stamping out Tcl API calls to C -### -puts [list LOADED practcl.tcl from [info script]] - -package require TclOO -### -# Seek out Tcllib if it's available -### -set tcllib_path {} -foreach path {.. ../.. ../../..} { - foreach path [glob -nocomplain [file join [file normalize $path] tcllib* modules]] { - set tclib_path $path - lappend ::auto_path $path - break - } - if {$tcllib_path ne {}} break -} - -### -# Build utility functions -### - - -### -# Extend http to follow redirects (ala Sourceforge downloads) -### -namespace eval ::http {} -proc ::http::_followRedirects {url args} { - while 1 { - set token [geturl $url -validate 1] - set ncode [ncode $token] - if { $ncode eq "404" } { - error "URL Not found" - } - switch -glob $ncode { - 30[1237] {### redirect - see below ###} - default {cleanup $token ; return $url} - } - upvar #0 $token state - array set meta [set ${token}(meta)] - cleanup $token - if {![info exists meta(Location)]} { - return $url - } - set url $meta(Location) - unset meta - } - return $url -} - -proc ::http::wget {url destfile {verbose 1}} { - package require http - set tmpchan [open $destfile w] - fconfigure $tmpchan -translation binary - if { $verbose } { - puts [list GETTING [file tail $destfile] from $url] - } - set real_url [_followRedirects $url] - set token [geturl $real_url -channel $tmpchan -binary yes] - if {[ncode $token] != "200"} { - error "DOWNLOAD FAILED" - } - cleanup $token - close $tmpchan -} - -namespace eval ::practcl {} - -### -# A command to do nothing. A handy way of -# negating an instruction without -# having to comment it completely out. -# It's also a handy attachment point for -# an object to be named later -### -if {[info command ::noop] eq {}} { - proc ::noop args {} -} - -proc ::practcl::debug args { - #puts $args - ::practcl::cputs ::DEBUG_INFO $args -} - -### -# Drop in a static copy of Tcl -### -proc ::practcl::doexec args { - puts [list {*}$args] - exec {*}$args >&@ stdout -} - -proc ::practcl::doexec_in {path args} { - set PWD [pwd] - cd $path - puts [list {*}$args] - exec {*}$args >&@ stdout - cd $PWD -} - -proc ::practcl::dotclexec args { - puts [list [info nameofexecutable] {*}$args] - exec [info nameofexecutable] {*}$args >&@ stdout -} - -proc ::practcl::domake {path args} { - set PWD [pwd] - cd $path - puts [list *** $path ***] - puts [list make {*}$args] - exec make {*}$args >&@ stdout - cd $PWD -} - -proc ::practcl::domake.tcl {path args} { - set PWD [pwd] - cd $path - puts [list *** $path ***] - puts [list make.tcl {*}$args] - exec [info nameofexecutable] make.tcl {*}$args >&@ stdout - cd $PWD -} - -proc ::practcl::fossil {path args} { - set PWD [pwd] - cd $path - puts [list {*}$args] - exec fossil {*}$args >&@ stdout - cd $PWD -} - - -proc ::practcl::fossil_status {dir} { - if {[info exists ::fosdat($dir)]} { - return $::fosdat($dir) - } - set result { -tags experimental -version {} - } - set pwd [pwd] - cd $dir - set info [exec fossil status] - cd $pwd - foreach line [split $info \n] { - if {[lindex $line 0] eq "checkout:"} { - set hash [lindex $line end-3] - set maxdate [lrange $line end-2 end-1] - dict set result hash $hash - dict set result maxdate $maxdate - regsub -all {[^0-9]} $maxdate {} isodate - dict set result isodate $isodate - } - if {[lindex $line 0] eq "tags:"} { - set tags [lrange $line 1 end] - dict set result tags $tags - break - } - } - set ::fosdat($dir) $result - return $result -} - -proc ::practcl::os {} { - return [${::practcl::MAIN} define get TEACUP_OS] -} - -if {[::package vcompare $::tcl_version 8.6] < 0} { - # Approximate ::zipfile::mkzip with exec calls - proc ::practcl::mkzip {exename barekit vfspath} { - set path [file dirname [file normalize $exename]] - set zipfile [file join $path [file rootname $exename].zip] - file copy -force $barekit $exename - set pwd [pwd] - cd $vfspath - exec zip -r $zipfile . - cd $pwd - set fout [open $exename a] - set fin [open $zipfile r] - chan configure $fout -translation binary - chan configure $fin -translation binary - chan copy $fin $fout - chan close $fin - chan close $fout - exec zip -A $exename - } - proc ::practcl::sort_dict list { - set result {} - foreach key [lsort -dictionary [dict keys $list]] { - dict set result $key [dict get $list $key] - } - return $result - } -} else { - proc ::practcl::mkzip {exename barekit vfspath} { - ::practcl::tcllib_require zipfile::mkzip - ::zipfile::mkzip::mkzip $exename -runtime $barekit -directory $vfspath - } - proc ::practcl::sort_dict list { - return [::lsort -stride 2 -dictionary $list] - } -} - -proc ::practcl::local_os {} { - # If we have already run this command, return - # a cached copy of the data - if {[info exists ::practcl::LOCAL_INFO]} { - return $::practcl::LOCAL_INFO - } - set result [array get ::practcl::CONFIG] - dict set result TEACUP_PROFILE unknown - dict set result TEACUP_OS unknown - dict set result EXEEXT {} - set windows 0 - if {$::tcl_platform(platform) eq "windows"} { - set windows 1 - } - if {$windows} { - set system "windows" - set arch ix86 - dict set result TEACUP_PROFILE win32-ix86 - dict set result TEACUP_OS windows - dict set result EXEEXT .exe - } else { - set system [exec uname -s]-[exec uname -r] - set arch unknown - dict set result TEACUP_OS generic - } - dict set result TEA_PLATFORM $system - dict set result TEA_SYSTEM $system - if {[info exists ::SANDBOX]} { - dict set result sandbox $::SANDBOX - } - switch -glob $system { - Linux* { - dict set result TEACUP_OS linux - set arch [exec uname -m] - dict set result TEACUP_PROFILE "linux-glibc2.3-$arch" - } - GNU* { - set arch [exec uname -m] - dict set result TEACUP_OS "gnu" - } - NetBSD-Debian { - set arch [exec uname -m] - dict set result TEACUP_OS "netbsd-debian" - } - OpenBSD-* { - set arch [exec arch -s] - dict set result TEACUP_OS "openbsd" - } - Darwin* { - set arch [exec uname -m] - dict set result TEACUP_OS "macosx" - if {$arch eq "x86_64"} { - dict set result TEACUP_PROFILE "macosx10.5-i386-x86_84" - } else { - dict set result TEACUP_PROFILE "macosx-universal" - } - } - OpenBSD* { - set arch [exec arch -s] - dict set result TEACUP_OS "openbsd" - } - } - if {$arch eq "unknown"} { - catch {set arch [exec uname -m]} - } - switch -glob $arch { - i*86 { - set arch "ix86" - } - amd64 { - set arch "x86_64" - } - } - dict set result TEACUP_ARCH $arch - if {[dict get $result TEACUP_PROFILE] eq "unknown"} { - dict set result TEACUP_PROFILE [dict get $result TEACUP_OS]-$arch - } - set OS [dict get $result TEACUP_OS] - dict set result os $OS - - # Look for a local preference file - set pathlist {} - set userhome [file normalize ~/tcl] - set local_install [file join $userhome lib] - switch $OS { - windows { - set userhome [file join [file normalize $::env(LOCALAPPDATA)] Tcl] - if {[file exists c:/Tcl/Teapot]} { - dict set result teapot c:/Tcl/Teapot - } - } - macosx { - set userhome [file join [file normalize {~/Library/Application Support/}] Tcl] - if {[file exists {~/Library/Application Support/ActiveState/Teapot/repository/}]} { - dict set result teapot [file normalize {~/Library/Application Support/ActiveState/Teapot/repository/}] - } - dict set result local_install [file normalize ~/Library/Tcl] - if {![dict exists $result sandbox]} { - dict set result sandbox [file normalize ~/Library/Tcl/sandbox] - } - } - default { - } - } - dict set result userhome $userhome - # Load user preferences - if {[file exists [file join $userhome practcl.rc]]} { - set dat [::practcl::cat [file join $path practcl.rc]] - } - if {![dict exists $result prefix]} { - dict set result prefix $userhome - } - - # Create a default path for the teapot - if {![dict exists $result teapot]} { - dict set result teapot [file join $userhome teapot] - } - # Create a default path for the local sandbox - if {![dict exists $result sandbox]} { - dict set result sandbox [file join $userhome sandbox] - } - # Create a default path for download folder - if {![dict exists $result download]} { - dict set result download [file join $userhome download] - } - # Path to install local packages - if {![dict exists $result local_install]} { - dict set result local_install [file join $userhome lib] - } - if {![dict exists result fossil_mirror] && [::info exists ::env(FOSSIL_MIRROR)]} { - dict set result fossil_mirror $::env(FOSSIL_MIRROR) - } - - set ::practcl::LOCAL_INFO $result - return $result -} - - -### -# Detect local platform -### -proc ::practcl::config.tcl {path} { - dict set result buildpath $path - set result [local_os] - set OS [dict get $result TEACUP_OS] - set windows 0 - dict set result USEMSVC 0 - if {[file exists [file join $path config.tcl]]} { - # We have a definitive configuration file. Read its content - # and take it as gospel - set cresult [read_rc_file [file join $path config.tcl]] - set cresult [::practcl::de_shell $cresult] - if {[dict exists $cresult srcdir] && ![dict exists $cresult sandbox]} { - dict set cresult sandbox [file dirname [dict get $cresult srcdir]] - } - set result [dict merge $result [::practcl::de_shell $cresult]] - } - if {[file exists [file join $path config.site]]} { - # No config.tcl file is present but we do seed - dict set result USEMSVC 0 - foreach {f v} [::practcl::de_shell [::practcl::read_sh_file [file join $path config.site]]] { - dict set result $f $v - dict set result XCOMPILE_${f} $v - } - dict set result CONFIG_SITE [file join $path config.site] - if {[dict exist $result XCOMPILE_CC] && [regexp mingw [dict get $result XCOMPILE_CC]]} { - set windows 1 - } - } elseif {[info exists ::env(VisualStudioVersion)]} { - set windows 1 - dict set result USEMSVC 1 - } - if {$windows && [dict get $result TEACUP_OS] ne "windows"} { - if {![dict exists exists $result TEACUP_ARCH]} { - dict set result TEACUP_ARCH ix86 - } - dict set result TEACUP_PROFILE win32-[dict get $result TEACUP_ARCH] - dict set result TEACUP_OS windows - dict set result EXEEXT .exe - } - return $result -} - - -### -# Convert an MSYS path to a windows native path -### -if {$::tcl_platform(platform) eq "windows"} { -proc ::practcl::msys_to_tclpath msyspath { - return [exec sh -c "cd $msyspath ; pwd -W"] -} -} else { -proc ::practcl::msys_to_tclpath msyspath { - return [file normalize $msyspath] -} -} - -### -# Bits stolen from fileutil -### -proc ::practcl::cat fname { - set fname [open $fname r] - set data [read $fname] - close $fname - return $data -} - -proc ::practcl::file_lexnormalize {sp} { - set spx [file split $sp] - - # Resolution of embedded relative modifiers (., and ..). - - if { - ([lsearch -exact $spx . ] < 0) && - ([lsearch -exact $spx ..] < 0) - } { - # Quick path out if there are no relative modifiers - return $sp - } - - set absolute [expr {![string equal [file pathtype $sp] relative]}] - # A volumerelative path counts as absolute for our purposes. - - set sp $spx - set np {} - set noskip 1 - - while {[llength $sp]} { - set ele [lindex $sp 0] - set sp [lrange $sp 1 end] - set islast [expr {[llength $sp] == 0}] - - if {[string equal $ele ".."]} { - if { - ($absolute && ([llength $np] > 1)) || - (!$absolute && ([llength $np] >= 1)) - } { - # .. : Remove the previous element added to the - # new path, if there actually is enough to remove. - set np [lrange $np 0 end-1] - } - } elseif {[string equal $ele "."]} { - # Ignore .'s, they stay at the current location - continue - } else { - # A regular element. - lappend np $ele - } - } - if {[llength $np] > 0} { - return [eval [linsert $np 0 file join]] - # 8.5: return [file join {*}$np] - } - return {} -} - -proc ::practcl::file_relative {base dst} { - # Ensure that the link to directory 'dst' is properly done relative to - # the directory 'base'. - - if {![string equal [file pathtype $base] [file pathtype $dst]]} { - return -code error "Unable to compute relation for paths of different pathtypes: [file pathtype $base] vs. [file pathtype $dst], ($base vs. $dst)" - } - - set base [file_lexnormalize [file join [pwd] $base]] - set dst [file_lexnormalize [file join [pwd] $dst]] - - set save $dst - set base [file split $base] - set dst [file split $dst] - - while {[string equal [lindex $dst 0] [lindex $base 0]]} { - set dst [lrange $dst 1 end] - set base [lrange $base 1 end] - if {![llength $dst]} {break} - } - - set dstlen [llength $dst] - set baselen [llength $base] - - if {($dstlen == 0) && ($baselen == 0)} { - # Cases: - # (a) base == dst - - set dst . - } else { - # Cases: - # (b) base is: base/sub = sub - # dst is: base = {} - - # (c) base is: base = {} - # dst is: base/sub = sub - - while {$baselen > 0} { - set dst [linsert $dst 0 ..] - incr baselen -1 - } - # 8.5: set dst [file join {*}$dst] - set dst [eval [linsert $dst 0 file join]] - } - - return $dst -} - -# Try to load a package, and failing that -# retrieve tcllib -proc ::practcl::tcllib_require {pkg args} { - # Try to load the package from the local environment - if {[catch [list ::package require $pkg {*}$args] err]==0} { - return $err - } - ::practcl::LOCAL tool tcllib load - uplevel #0 [list ::package require $pkg {*}$args] -} - -namespace eval ::practcl::platform {} - -proc ::practcl::platform::tcl_core_options {os} { - ### - # Download our required packages - ### - set tcl_config_opts {} - # Auto-guess options for the local operating system - switch $os { - windows { - #lappend tcl_config_opts --disable-stubs - } - linux { - } - macosx { - lappend tcl_config_opts --enable-corefoundation=yes --enable-framework=no - } - } - lappend tcl_config_opts --with-tzdata - return $tcl_config_opts -} - -proc ::practcl::platform::tk_core_options {os} { - ### - # Download our required packages - ### - set tk_config_opts {} - - # Auto-guess options for the local operating system - switch $os { - windows { - } - linux { - lappend tk_config_opts --enable-xft=no --enable-xss=no - } - macosx { - lappend tk_config_opts --enable-aqua=yes - } - } - return $tk_config_opts -} - -### -# Read a stylized key/value list stored in a file -### -proc ::practcl::read_rc_file {filename {localdat {}}} { - set result $localdat - set fin [open $filename r] - set bufline {} - set rawcount 0 - set linecount 0 - while {[gets $fin thisline]>=0} { - incr rawcount - append bufline \n $thisline - if {![info complete $bufline]} continue - set line [string trimleft $bufline] - set bufline {} - if {[string index [string trimleft $line] 0] eq "#"} continue - append result \n $line - #incr linecount - #set key [lindex $line 0] - #set value [lindex $line 1] - #dict set result $key $value - } - return $result -} - -### -# topic: e71f3f61c348d56292011eec83e95f0aacc1c618 -# description: Converts a XXX.sh file into a series of Tcl variables -### -proc ::practcl::read_sh_subst {line info} { - regsub -all {\x28} $line \x7B line - regsub -all {\x29} $line \x7D line - - #set line [string map $key [string trim $line]] - foreach {field value} $info { - catch {set $field $value} - } - if [catch {subst $line} result] { - return {} - } - set result [string trim $result] - return [string trim $result '] -} - -### -# topic: 03567140cca33c814664c7439570f669b9ab88e6 -### -proc ::practcl::read_sh_file {filename {localdat {}}} { - set fin [open $filename r] - set result {} - if {$localdat eq {}} { - set top 1 - set local [array get ::env] - dict set local EXE {} - } else { - set top 0 - set local $localdat - } - while {[gets $fin line] >= 0} { - set line [string trim $line] - if {[string index $line 0] eq "#"} continue - if {$line eq {}} continue - catch { - if {[string range $line 0 6] eq "export "} { - set eq [string first "=" $line] - set field [string trim [string range $line 6 [expr {$eq - 1}]]] - set value [read_sh_subst [string range $line [expr {$eq+1}] end] $local] - dict set result $field [read_sh_subst $value $local] - dict set local $field $value - } elseif {[string range $line 0 7] eq "include "} { - set subfile [read_sh_subst [string range $line 7 end] $local] - foreach {field value} [read_sh_file $subfile $local] { - dict set result $field $value - } - } else { - set eq [string first "=" $line] - if {$eq > 0} { - set field [read_sh_subst [string range $line 0 [expr {$eq - 1}]] $local] - set value [string trim [string range $line [expr {$eq+1}] end] '] - #set value [read_sh_subst [string range $line [expr {$eq+1}] end] $local] - dict set local $field $value - dict set result $field $value - } - } - } err opts - if {[dict get $opts -code] != 0} { - #puts $opts - puts "Error reading line:\n$line\nerr: $err\n***" - return $err {*}$opts - } - } - return $result -} - -### -# A simpler form of read_sh_file tailored -# to pulling data from (tcl|tk)Config.sh -### -proc ::practcl::read_Config.sh filename { - set fin [open $filename r] - set result {} - set linecount 0 - while {[gets $fin line] >= 0} { - set line [string trim $line] - if {[string index $line 0] eq "#"} continue - if {$line eq {}} continue - catch { - set eq [string first "=" $line] - if {$eq > 0} { - set field [string range $line 0 [expr {$eq - 1}]] - set value [string trim [string range $line [expr {$eq+1}] end] '] - #set value [read_sh_subst [string range $line [expr {$eq+1}] end] $local] - dict set result $field $value - incr $linecount - } - } err opts - if {[dict get $opts -code] != 0} { - #puts $opts - puts "Error reading line:\n$line\nerr: $err\n***" - return $err {*}$opts - } - } - return $result -} - -### -# A simpler form of read_sh_file tailored -# to pulling data from a Makefile -### -proc ::practcl::read_Makefile filename { - set fin [open $filename r] - set result {} - while {[gets $fin line] >= 0} { - set line [string trim $line] - if {[string index $line 0] eq "#"} continue - if {$line eq {}} continue - catch { - set eq [string first "=" $line] - if {$eq > 0} { - set field [string trim [string range $line 0 [expr {$eq - 1}]]] - set value [string trim [string trim [string range $line [expr {$eq+1}] end] ']] - switch $field { - PKG_LIB_FILE { - dict set result libfile $value - } - srcdir { - if {$value eq "."} { - dict set result srcdir [file dirname $filename] - } else { - dict set result srcdir $value - } - } - PACKAGE_NAME { - dict set result name $value - } - PACKAGE_VERSION { - dict set result version $value - } - LIBS { - dict set result PRACTCL_LIBS $value - } - PKG_LIB_FILE { - dict set result libfile $value - } - } - } - } err opts - if {[dict get $opts -code] != 0} { - #puts $opts - puts "Error reading line:\n$line\nerr: $err\n***" - return $err {*}$opts - } - # the Compile field is about where most TEA files start getting silly - if {$field eq "compile"} { - break - } - } - return $result -} - -## Append arguments to a buffer -# The command works like puts in that each call will also insert -# a line feed. Unlike puts, blank links in the interstitial are -# suppressed -proc ::practcl::cputs {varname args} { - upvar 1 $varname buffer - if {[llength $args]==1 && [string length [string trim [lindex $args 0]]] == 0} { - - } - if {[info exist buffer]} { - if {[string index $buffer end] ne "\n"} { - append buffer \n - } - } else { - set buffer \n - } - # Trim leading \n's - append buffer [string trimleft [lindex $args 0] \n] {*}[lrange $args 1 end] -} - - -proc ::practcl::tcl_to_c {body} { - set result {} - foreach rawline [split $body \n] { - set line [string map [list \" \\\" \\ \\\\] $rawline] - cputs result "\n \"$line\\n\" \\" - } - return [string trimright $result \\] -} - - -proc ::practcl::_tagblock {text {style tcl} {note {}}} { - if {[string length [string trim $text]]==0} { - return {} - } - set output {} - switch $style { - tcl { - ::practcl::cputs output "# BEGIN $note" - } - c { - ::practcl::cputs output "/* BEGIN $note */" - } - default { - ::practcl::cputs output "# BEGIN $note" - } - } - ::practcl::cputs output $text - switch $style { - tcl { - ::practcl::cputs output "# END $note" - } - c { - ::practcl::cputs output "/* END $note */" - } - default { - ::practcl::cputs output "# END $note" - } - } - return $output -} - -proc ::practcl::_isdirectory name { - return [file isdirectory $name] -} - -### -# Return true if the pkgindex file contains -# any statement other than "package ifneeded" -# and/or if any package ifneeded loads a DLL -### -proc ::practcl::_pkgindex_directory {path} { - set buffer {} - set pkgidxfile [file join $path pkgIndex.tcl] - if {![file exists $pkgidxfile]} { - # No pkgIndex file, read the source - foreach file [glob -nocomplain $path/*.tm] { - set file [file normalize $file] - set fname [file rootname [file tail $file]] - ### - # We used to be able to ... Assume the package is correct in the filename - # No hunt for a "package provides" - ### - set package [lindex [split $fname -] 0] - set version [lindex [split $fname -] 1] - ### - # Read the file, and override assumptions as needed - ### - set fin [open $file r] - set dat [read $fin] - close $fin - # Look for a teapot style Package statement - foreach line [split $dat \n] { - set line [string trim $line] - if { [string range $line 0 9] != "# Package " } continue - set package [lindex $line 2] - set version [lindex $line 3] - break - } - # Look for a package provide statement - foreach line [split $dat \n] { - set line [string trim $line] - if { [string range $line 0 14] != "package provide" } continue - set package [lindex $line 2] - set version [lindex $line 3] - break - } - append buffer "package ifneeded $package $version \[list source \[file join \$dir [file tail $file]\]\]" \n - } - foreach file [glob -nocomplain $path/*.tcl] { - if { [file tail $file] == "version_info.tcl" } continue - set fin [open $file r] - set dat [read $fin] - close $fin - if {![regexp "package provide" $dat]} continue - set fname [file rootname [file tail $file]] - # Look for a package provide statement - foreach line [split $dat \n] { - set line [string trim $line] - if { [string range $line 0 14] != "package provide" } continue - set package [lindex $line 2] - set version [lindex $line 3] - if {[string index $package 0] in "\$ \["} continue - if {[string index $version 0] in "\$ \["} continue - append buffer "package ifneeded $package $version \[list source \[file join \$dir [file tail $file]\]\]" \n - break - } - } - return $buffer - } - set fin [open $pkgidxfile r] - set dat [read $fin] - close $fin - set trace 0 - #if {[file tail $path] eq "tool"} { - # set trace 1 - #} - set thisline {} - foreach line [split $dat \n] { - append thisline $line \n - if {![info complete $thisline]} continue - set line [string trim $line] - if {[string length $line]==0} { - set thisline {} ; continue - } - if {[string index $line 0] eq "#"} { - set thisline {} ; continue - } - if {[regexp "if.*catch.*package.*Tcl.*return" $thisline]} { - if {$trace} {puts "[file dirname $pkgidxfile] Ignoring $thisline"} - set thisline {} ; continue - } - if {[regexp "if.*package.*vsatisfies.*package.*provide.*return" $thisline]} { - if {$trace} { puts "[file dirname $pkgidxfile] Ignoring $thisline" } - set thisline {} ; continue - } - if {![regexp "package.*ifneeded" $thisline]} { - # This package index contains arbitrary code - # source instead of trying to add it to the master - # package index - if {$trace} { puts "[file dirname $pkgidxfile] Arbitrary code $thisline" } - return {source [file join $dir pkgIndex.tcl]} - } - append buffer $thisline \n - set thisline {} - } - if {$trace} {puts [list [file dirname $pkgidxfile] $buffer]} - return $buffer -} - - -proc ::practcl::_pkgindex_path_subdir {path} { - set result {} - foreach subpath [glob -nocomplain [file join $path *]] { - if {[file isdirectory $subpath]} { - lappend result $subpath {*}[_pkgindex_path_subdir $subpath] - } - } - return $result -} -### -# Index all paths given as though they will end up in the same -# virtual file system -### -proc ::practcl::pkgindex_path args { - set stack {} - set buffer { -lappend ::PATHSTACK $dir - } - foreach base $args { - set base [file normalize $base] - set paths [::practcl::_pkgindex_path_subdir $base] - set i [string length $base] - # Build a list of all of the paths - foreach path $paths { - if {$path eq $base} continue - set path_indexed($path) 0 - } - set path_indexed($base) 1 - set path_indexed([file join $base boot tcl]) 1 - #set path_index([file join $base boot tk]) 1 - - foreach path $paths { - if {$path_indexed($path)} continue - set thisdir [file_relative $base $path] - #set thisdir [string range $path $i+1 end] - #append buffer "# DIR $thisdir" \n - set idxbuf [::practcl::_pkgindex_directory $path] - if {[string length $idxbuf]} { - incr path_indexed($path) - append buffer "set dir \[set PKGDIR \[file join \[lindex \$::PATHSTACK end\] $thisdir\]\]" \n - append buffer [string map {$dir $PKGDIR} [string trimright $idxbuf]] \n - } - } - } - append buffer { -set dir [lindex $::PATHSTACK end] -set ::PATHSTACK [lrange $::PATHSTACK 0 end-1] -} - return $buffer -} - -### -# topic: 64319f4600fb63c82b2258d908f9d066 -# description: Script to build the VFS file system -### -proc ::practcl::installDir {d1 d2} { - - puts [format {%*sCreating %s} [expr {4 * [info level]}] {} [file tail $d2]] - file delete -force -- $d2 - file mkdir $d2 - - foreach ftail [glob -directory $d1 -nocomplain -tails *] { - set f [file join $d1 $ftail] - if {[file isdirectory $f] && [string compare CVS $ftail]} { - installDir $f [file join $d2 $ftail] - } elseif {[file isfile $f]} { - file copy -force $f [file join $d2 $ftail] - if {$::tcl_platform(platform) eq {unix}} { - file attributes [file join $d2 $ftail] -permissions 0644 - } else { - file attributes [file join $d2 $ftail] -readonly 1 - } - } - } - - if {$::tcl_platform(platform) eq {unix}} { - file attributes $d2 -permissions 0755 - } else { - file attributes $d2 -readonly 1 - } -} - -proc ::practcl::copyDir {d1 d2 {toplevel 1}} { - if {$toplevel} { - puts [list ::practcl::copyDir $d1 -> $d2] - } - #file delete -force -- $d2 - file mkdir $d2 - - foreach ftail [glob -directory $d1 -nocomplain -tails *] { - set f [file join $d1 $ftail] - if {[file isdirectory $f] && [string compare CVS $ftail]} { - copyDir $f [file join $d2 $ftail] 0 - } elseif {[file isfile $f]} { - file copy -force $f [file join $d2 $ftail] - } - } -} - -::oo::class create ::practcl::metaclass { - superclass ::oo::object - - method script script { - eval $script - } - - method source filename { - source $filename - } - - method initialize {} {} - - method define {submethod args} { - my variable define - switch $submethod { - dump { - return [array get define] - } - add { - set field [lindex $args 0] - if {![info exists define($field)]} { - set define($field) {} - } - foreach arg [lrange $args 1 end] { - if {$arg ni $define($field)} { - lappend define($field) $arg - } - } - return $define($field) - } - remove { - set field [lindex $args 0] - if {![info exists define($field)]} { - return - } - set rlist [lrange $args 1 end] - set olist $define($field) - set nlist {} - foreach arg $olist { - if {$arg in $rlist} continue - lappend nlist $arg - } - set define($field) $nlist - return $nlist - } - exists { - set field [lindex $args 0] - return [info exists define($field)] - } - getnull - - get - - cget { - set field [lindex $args 0] - if {[info exists define($field)]} { - return $define($field) - } - return [lindex $args 1] - } - set { - if {[llength $args]==1} { - set arglist [lindex $args 0] - } else { - set arglist $args - } - array set define $arglist - if {[dict exists $arglist class]} { - my select - } - } - default { - array $submethod define {*}$args - } - } - } - - method graft args { - my variable organs - if {[llength $args] == 1} { - error "Need two arguments" - } - set object {} - foreach {stub object} $args { - dict set organs $stub $object - oo::objdefine [self] forward <${stub}> $object - oo::objdefine [self] export <${stub}> - } - return $object - } - - method organ {{stub all}} { - my variable organs - if {![info exists organs]} { - return {} - } - if { $stub eq "all" } { - return $organs - } - if {[dict exists $organs $stub]} { - return [dict get $organs $stub] - } - } - - method link {command args} { - my variable links - switch $command { - object { - foreach obj $args { - foreach linktype [$obj linktype] { - my link add $linktype $obj - } - } - } - add { - ### - # Add a link to an object that was externally created - ### - if {[llength $args] ne 2} { error "Usage: link add LINKTYPE OBJECT"} - lassign $args linktype object - if {[info exists links($linktype)] && $object in $links($linktype)} { - return - } - lappend links($linktype) $object - } - remove { - set object [lindex $args 0] - if {[llength $args]==1} { - set ltype * - } else { - set ltype [lindex $args 1] - } - foreach {linktype elements} [array get links $ltype] { - if {$object in $elements} { - set nlist {} - foreach e $elements { - if { $object ne $e } { lappend nlist $e } - } - set links($linktype) $nlist - } - } - } - list { - if {[llength $args]==0} { - return [array get links] - } - if {[llength $args] != 1} { error "Usage: link list LINKTYPE"} - set linktype [lindex $args 0] - if {![info exists links($linktype)]} { - return {} - } - return $links($linktype) - } - dump { - return [array get links] - } - } - } - - method select {} { - my variable define - set class {} - if {[info exists define(class)]} { - if {[info command $define(class)] ne {}} { - set class $define(class) - } elseif {[info command ::practcl::$define(class)] ne {}} { - set class ::practcl::$define(class) - } else { - switch $define(class) { - default { - set class ::practcl::object - } - } - } - } - if {$class ne {}} { - ::oo::objdefine [self] class $class - } - if {[::info exists define(oodefine)]} { - ::oo::objdefine [self] $define(oodefine) - unset define(oodefine) - } - } -} - -proc ::practcl::trigger {args} { - foreach name $args { - if {[dict exists $::make_objects $name]} { - [dict get $::make_objects $name] triggers - } - } -} - -proc ::practcl::depends {args} { - foreach name $args { - if {[dict exists $::make_objects $name]} { - [dict get $::make_objects $name] check - } - } -} - -proc ::practcl::target {name info} { - set obj [::practcl::target_obj new $name $info] - dict set ::make_objects $name $obj - if {[dict exists $info aliases]} { - foreach item [dict get $info aliases] { - if {![dict exists $::make_objects $item]} { - dict set ::make_objects $item $obj - } - } - } - set ::make($name) 0 - set ::trigger($name) 0 - set filename [$obj define get filename] - if {$filename ne {}} { - set ::target($name) $filename - } -} - -### Batch Tasks - -proc ::practcl::de_shell {data} { - set values {} - foreach flag {DEFS TCL_DEFS TK_DEFS} { - if {[dict exists $data $flag]} { - #set value {} - #foreach item [dict get $data $flag] { - # append value " " [string map {{ } {\ }} $item] - #} - dict set values $flag [dict get $data $flag] - } - } - set map {} - lappend map {${PKG_OBJECTS}} %LIBRARY_OBJECTS% - lappend map {$(PKG_OBJECTS)} %LIBRARY_OBJECTS% - lappend map {${PKG_STUB_OBJECTS}} %LIBRARY_STUB_OBJECTS% - lappend map {$(PKG_STUB_OBJECTS)} %LIBRARY_STUB_OBJECTS% - - if {[dict exists $data name]} { - lappend map %LIBRARY_NAME% [dict get $data name] - lappend map %LIBRARY_VERSION% [dict get $data version] - lappend map %LIBRARY_VERSION_NODOTS% [string map {. {}} [dict get $data version]] - if {[dict exists $data libprefix]} { - lappend map %LIBRARY_PREFIX% [dict get $data libprefix] - } else { - lappend map %LIBRARY_PREFIX% [dict get $data prefix] - } - } - foreach flag [dict keys $data] { - if {$flag in {TCL_DEFS TK_DEFS DEFS}} continue - set value [string trim [dict get $data $flag] \"] - dict set map "\$\{${flag}\}" $value - dict set map "\$\(${flag}\)" $value - #dict set map "\$${flag}" $value - dict set map "%${flag}%" $value - dict set values $flag [dict get $data $flag] - #dict set map "\$\{${flag}\}" $proj($flag) - } - set changed 1 - while {$changed} { - set changed 0 - foreach {field value} $values { - if {$field in {TCL_DEFS TK_DEFS DEFS}} continue - dict with values {} - set newval [string map $map $value] - if {$newval eq $value} continue - set changed 1 - dict set values $field $newval - } - } - return $values -} - -### -# Ancestor-less class intended to be a mixin -# which defines a family of build related behaviors -# that are modified when targetting either gcc or msvc -### -::oo::class create ::practcl::build { - ## method DEFS - # This method populates 4 variables: - # name - The name of the package - # version - The version of the package - # defs - C flags passed to the compiler - # includedir - A list of paths to feed to the compiler for finding headers - # - method build-cflags {PROJECT DEFS namevar versionvar defsvar} { - upvar 1 $namevar name $versionvar version NAME NAME $defsvar defs - set name [string tolower [${PROJECT} define get name [${PROJECT} define get pkg_name]]] - set NAME [string toupper $name] - set version [${PROJECT} define get version [${PROJECT} define get pkg_vers]] - if {$version eq {}} { - set version 0.1a - } - set defs $DEFS - foreach flag { - -DPACKAGE_NAME - -DPACKAGE_VERSION - -DPACKAGE_TARNAME - -DPACKAGE_STRING - } { - if {[set i [string first $flag $defs]] >= 0} { - set j [string first -D $flag [expr {$i+[string length $flag]}]] - set predef [string range $defs 0 [expr {$i-1}]] - set postdef [string range $defs $j end] - set defs "$predef $postdef" - } - } - append defs " -DPACKAGE_NAME=\"${name}\" -DPACKAGE_VERSION=\"${version}\"" - append defs " -DPACKAGE_TARNAME=\"${name}\" -DPACKAGE_STRING=\"${name}\x5c\x20${version}\"" - return $defs - } - - method build-tclkit_main {PROJECT PKG_OBJS} { - ### - # Build static package list - ### - set statpkglist {} - foreach cobj [list {*}${PKG_OBJS} $PROJECT] { - foreach {pkg info} [$cobj static-packages] { - dict set statpkglist $pkg $info - } - } - foreach {ofile info} [${PROJECT} compile-products] { - if {![dict exists $info object]} continue - set cobj [dict get $info object] - foreach {pkg info} [$cobj static-packages] { - dict set statpkglist $pkg $info - } - } - - set result {} - $PROJECT include {<tcl.h>} - $PROJECT include {"tclInt.h"} - $PROJECT include {"tclFileSystem.h"} - $PROJECT include {<assert.h>} - $PROJECT include {<stdio.h>} - $PROJECT include {<stdlib.h>} - $PROJECT include {<string.h>} - $PROJECT include {<math.h>} - - $PROJECT code header { -#ifndef MODULE_SCOPE -# define MODULE_SCOPE extern -#endif - -/* -** Provide a dummy Tcl_InitStubs if we are using this as a static -** library. -*/ -#ifndef USE_TCL_STUBS -# undef Tcl_InitStubs -# define Tcl_InitStubs(a,b,c) TCL_VERSION -#endif -#define STATIC_BUILD 1 -#undef USE_TCL_STUBS - -/* Make sure the stubbed variants of those are never used. */ -#undef Tcl_ObjSetVar2 -#undef Tcl_NewStringObj -#undef Tk_Init -#undef Tk_MainEx -#undef Tk_SafeInit -} - - # Build an area of the file for #define directives and - # function declarations - set define {} - set mainhook [$PROJECT define get TCL_LOCAL_MAIN_HOOK Tclkit_MainHook] - set mainfunc [$PROJECT define get TCL_LOCAL_APPINIT Tclkit_AppInit] - set mainscript [$PROJECT define get main.tcl main.tcl] - set vfsroot [$PROJECT define get vfsroot [file join [$PROJECT define get ZIPFS_VOLUME] app]] - set vfs_main "${vfsroot}/${mainscript}" - set vfs_tcl_library "${vfsroot}/boot/tcl" - set vfs_tk_library "${vfsroot}/boot/tk" - - set map {} - foreach var { - vfsroot mainhook mainfunc vfs_main vfs_tcl_library vfs_tk_library - } { - dict set map %${var}% [set $var] - } - set preinitscript { -set ::odie(boot_vfs) {%vfsroot%} -set ::SRCDIR {%vfsroot%} -if {[file exists {%vfs_tcl_library%}]} { - set ::tcl_library {%vfs_tcl_library%} - set ::auto_path {} -} -if {[file exists {%vfs_tk_library%}]} { - set ::tk_library {%vfs_tk_library%} -} -} ; # Preinitscript - - set zvfsboot { -/* - * %mainhook% -- - * Performs the argument munging for the shell - */ - } - ::practcl::cputs zvfsboot { - CONST char *archive; - Tcl_FindExecutable(*argv[0]); - archive=Tcl_GetNameOfExecutable(); - } - # We have to initialize the virtual filesystem before calling - # Tcl_Init(). Otherwise, Tcl_Init() will not be able to find - # its startup script files. - if {[$PROJECT define get tip_430 0]} { - ::practcl::cputs zvfsboot " if(!TclZipfsMount(NULL, archive, \"%vfsroot%\", NULL)) \x7B " - } else { - $PROJECT include {"tclZipfs.h"} - ::practcl::cputs zvfsboot { Tclzipfs_Init(NULL);} - ::practcl::cputs zvfsboot " if(!Tclzipfs_Mount(NULL, archive, \"%vfsroot%\", NULL)) \x7B " - } - ::practcl::cputs zvfsboot { - Tcl_Obj *vfsinitscript; - vfsinitscript=Tcl_NewStringObj("%vfs_main%",-1); - Tcl_IncrRefCount(vfsinitscript); - if(Tcl_FSAccess(vfsinitscript,F_OK)==0) { - /* Startup script should be set before calling Tcl_AppInit */ - Tcl_SetStartupScript(vfsinitscript,NULL); - } - } - ::practcl::cputs zvfsboot " TclSetPreInitScript([::practcl::tcl_to_c $preinitscript])\;" - ::practcl::cputs zvfsboot " \x7D else \x7B" - ::practcl::cputs zvfsboot " TclSetPreInitScript([::practcl::tcl_to_c { -foreach path { - ../tcl -} { - set p [file join $path library init.tcl] - if {[file exists [file join $path library init.tcl]]} { - set ::tcl_library [file normalize [file join $path library]] - break - } -} -foreach path { - ../tk -} { - if {[file exists [file join $path library tk.tcl]]} { - set ::tk_library [file normalize [file join $path library]] - break - } -} -}])\;" - - ::practcl::cputs zvfsboot " \x7D" - ::practcl::cputs zvfsboot " return TCL_OK;" - - if {[$PROJECT define get TEACUP_OS] eq "windows"} { - set header {int %mainhook%(int *argc, TCHAR ***argv)} - } else { - set header {int %mainhook%(int *argc, char ***argv)} - } - $PROJECT c_function [string map $map $header] [string map $map $zvfsboot] - - practcl::cputs appinit "int %mainfunc%(Tcl_Interp *interp) \x7B" - - # Build AppInit() - set appinit {} - practcl::cputs appinit { - if ((Tcl_Init)(interp) == TCL_ERROR) { - return TCL_ERROR; - } -} - set main_init_script {} - - foreach {statpkg info} $statpkglist { - set initfunc {} - if {[dict exists $info initfunc]} { - set initfunc [dict get $info initfunc] - } - if {$initfunc eq {}} { - set initfunc [string totitle ${statpkg}]_Init - } - if {![dict exists $info version]} { - error "$statpkg HAS NO VERSION" - } - # We employ a NULL to prevent the package system from thinking the - # package is actually loaded into the interpreter - $PROJECT code header "extern Tcl_PackageInitProc $initfunc\;\n" - set script [list package ifneeded $statpkg [dict get $info version] [list ::load {} $statpkg]] - append main_init_script \n [list set ::kitpkg(${statpkg}) $script] - if {[dict get $info autoload]} { - ::practcl::cputs appinit " if(${initfunc}(interp)) return TCL_ERROR\;" - ::practcl::cputs appinit " Tcl_StaticPackage(interp,\"$statpkg\",$initfunc,NULL)\;" - } else { - ::practcl::cputs appinit "\n Tcl_StaticPackage(NULL,\"$statpkg\",$initfunc,NULL)\;" - append main_init_script \n $script - } - } - append main_init_script \n { -if {[file exists [file join $::SRCDIR packages.tcl]]} { - #In a wrapped exe, we don't go out to the environment - set dir $::SRCDIR - source [file join $::SRCDIR packages.tcl] -} -# Specify a user-specific startup file to invoke if the application -# is run interactively. Typically the startup file is "~/.apprc" -# where "app" is the name of the application. If this line is deleted -# then no user-specific startup file will be run under any conditions. - } - append main_init_script \n [list set tcl_rcFileName [$PROJECT define get tcl_rcFileName ~/.tclshrc]] - practcl::cputs appinit " Tcl_Eval(interp,[::practcl::tcl_to_c $main_init_script]);" - practcl::cputs appinit { return TCL_OK;} - $PROJECT c_function [string map $map "int %mainfunc%(Tcl_Interp *interp)"] [string map $map $appinit] -} - -} - - -::oo::class create ::practcl::build.gcc { - superclass ::practcl::build - - method build-compile-sources {PROJECT COMPILE {CPPCOMPILE {}}} { - set EXTERN_OBJS {} - set OBJECTS {} - set result {} - set builddir [$PROJECT define get builddir] - file mkdir [file join $builddir objs] - set debug [$PROJECT define get debug 0] - if {$CPPCOMPILE eq {}} { - set CPPCOMPILE $COMPILE - } - set task [${PROJECT} compile-products] - ### - # Compile the C sources - ### - foreach {ofile info} $task { - dict set task $ofile done 0 - if {[dict exists $info external] && [dict get $info external]==1} { - dict set task $ofile external 1 - } else { - dict set task $ofile external 0 - } - if {[dict exists $info library]} { - dict set task $ofile done 1 - continue - } - # Products with no cfile aren't compiled - if {![dict exists $info cfile] || [set cfile [dict get $info cfile]] eq {}} { - dict set task $ofile done 1 - continue - } - set cfile [dict get $info cfile] - set ofilename [file join $builddir objs [file tail $ofile]] - if {$debug} { - set ofilename [file join $builddir objs [file rootname [file tail $ofile]].debug.o] - } - dict set task $ofile filename $ofilename - if {[file exists $ofilename] && [file mtime $ofilename]>[file mtime $cfile]} { - lappend result $ofilename - dict set task $ofile done 1 - continue - } - if {![dict exist $info command]} { - if {[file extension $cfile] in {.c++ .cpp}} { - set cmd $CPPCOMPILE - } else { - set cmd $COMPILE - } - if {[dict exists $info extra]} { - append cmd " [dict get $info extra]" - } - append cmd " -c $cfile" - append cmd " -o $ofilename" - dict set task $ofile command $cmd - } - } - set completed 0 - while {$completed==0} { - set completed 1 - foreach {ofile info} $task { - set waiting {} - if {[dict exists $info done] && [dict get $info done]} continue - if {[dict exists $info depend]} { - foreach file [dict get $info depend] { - if {[dict exists $task $file command] && [dict exists $task $file done] && [dict get $task $file done] != 1} { - set waiting $file - break - } - } - } - if {$waiting ne {}} { - set completed 0 - puts "$ofile waiting for $waiting" - continue - } - if {[dict exists $info command]} { - set cmd [dict get $info command] - puts "$cmd" - exec {*}$cmd >&@ stdout - } - lappend result [dict get $info filename] - dict set task $ofile done 1 - } - } - return $result -} - -method build-Makefile {path PROJECT} { - array set proj [$PROJECT define dump] - set path $proj(builddir) - cd $path - set includedir . - #lappend includedir [::practcl::file_relative $path $proj(TCL_INCLUDES)] - lappend includedir [::practcl::file_relative $path [file normalize [file join $proj(TCL_SRC_DIR) generic]]] - lappend includedir [::practcl::file_relative $path [file normalize [file join $proj(srcdir) generic]]] - foreach include [$PROJECT generate-include-directory] { - set cpath [::practcl::file_relative $path [file normalize $include]] - if {$cpath ni $includedir} { - lappend includedir $cpath - } - } - set INCLUDES "-I[join $includedir " -I"]" - set NAME [string toupper $proj(name)] - set result {} - set products {} - set libraries {} - set thisline {} - ::practcl::cputs result "${NAME}_DEFS = $proj(DEFS)\n" - ::practcl::cputs result "${NAME}_INCLUDES = -I\"[join $includedir "\" -I\""]\"\n" - ::practcl::cputs result "${NAME}_COMPILE = \$(CC) \$(CFLAGS) \$(PKG_CFLAGS) \$(${NAME}_DEFS) \$(${NAME}_INCLUDES) \$(INCLUDES) \$(AM_CPPFLAGS) \$(CPPFLAGS) \$(AM_CFLAGS)" - ::practcl::cputs result "${NAME}_CPPCOMPILE = \$(CXX) \$(CFLAGS) \$(PKG_CFLAGS) \$(${NAME}_DEFS) \$(${NAME}_INCLUDES) \$(INCLUDES) \$(AM_CPPFLAGS) \$(CPPFLAGS) \$(AM_CFLAGS)" - - foreach {ofile info} [$PROJECT compile-products] { - dict set products $ofile $info - if {[dict exists $info library]} { -lappend libraries $ofile -continue - } - if {[dict exists $info depend]} { - ::practcl::cputs result "\n${ofile}: [dict get $info depend]" - } else { - ::practcl::cputs result "\n${ofile}:" - } - set cfile [dict get $info cfile] - if {[file extension $cfile] in {.c++ .cpp}} { - set cmd "\t\$\(${NAME}_CPPCOMPILE\)" - } else { - set cmd "\t\$\(${NAME}_COMPILE\)" - } - if {[dict exists $info extra]} { - append cmd " [dict get $info extra]" - } - append cmd " -c [dict get $info cfile] -o \$@\n\t" - ::practcl::cputs result $cmd - } - - set map {} - lappend map %LIBRARY_NAME% $proj(name) - lappend map %LIBRARY_VERSION% $proj(version) - lappend map %LIBRARY_VERSION_NODOTS% [string map {. {}} $proj(version)] - lappend map %LIBRARY_PREFIX% [$PROJECT define getnull libprefix] - - if {[string is true [$PROJECT define get SHARED_BUILD]]} { - set outfile [$PROJECT define get libfile] - } else { - set outfile [$PROJECT shared_library] - } - $PROJECT define set shared_library $outfile - ::practcl::cputs result " -${NAME}_SHLIB = $outfile -${NAME}_OBJS = [dict keys $products] -" - - #lappend map %OUTFILE% {\[$]@} - lappend map %OUTFILE% $outfile - lappend map %LIBRARY_OBJECTS% "\$(${NAME}_OBJS)" - ::practcl::cputs result "$outfile: \$(${NAME}_OBJS)" - ::practcl::cputs result "\t[string map $map [$PROJECT define get PRACTCL_SHARED_LIB]]" - if {[$PROJECT define get PRACTCL_VC_MANIFEST_EMBED_DLL] ni {: {}}} { - ::practcl::cputs result "\t[string map $map [$PROJECT define get PRACTCL_VC_MANIFEST_EMBED_DLL]]" - } - ::practcl::cputs result {} - if {[string is true [$PROJECT define get SHARED_BUILD]]} { - #set outfile [$PROJECT static_library] - set outfile $proj(name).a - } else { - set outfile [$PROJECT define get libfile] - } - $PROJECT define set static_library $outfile - dict set map %OUTFILE% $outfile - ::practcl::cputs result "$outfile: \$(${NAME}_OBJS)" - ::practcl::cputs result "\t[string map $map [$PROJECT define get PRACTCL_STATIC_LIB]]" - ::practcl::cputs result {} - return $result -} - -### -# Produce a static or dynamic library -### -method build-library {outfile PROJECT} { - array set proj [$PROJECT define dump] - set path $proj(builddir) - cd $path - set includedir . - #lappend includedir [::practcl::file_relative $path $proj(TCL_INCLUDES)] - lappend includedir [::practcl::file_relative $path [file normalize [file join $proj(TCL_SRC_DIR) generic]]] - lappend includedir [::practcl::file_relative $path [file normalize [file join $proj(srcdir) generic]]] - if {[$PROJECT define get tk 0]} { - lappend includedir [::practcl::file_relative $path [file normalize [file join $proj(TK_SRC_DIR) generic]]] - lappend includedir [::practcl::file_relative $path [file normalize [file join $proj(TK_SRC_DIR) ttk]]] - lappend includedir [::practcl::file_relative $path [file normalize [file join $proj(TK_SRC_DIR) xlib]]] - lappend includedir [::practcl::file_relative $path [file normalize $proj(TK_BIN_DIR)]] - } - foreach include [$PROJECT generate-include-directory] { - set cpath [::practcl::file_relative $path [file normalize $include]] - if {$cpath ni $includedir} { - lappend includedir $cpath - } - } - my build-cflags $PROJECT $proj(DEFS) name version defs - set NAME [string toupper $name] - set debug [$PROJECT define get debug 0] - set os [$PROJECT define get TEACUP_OS] - - set INCLUDES "-I[join $includedir " -I"]" - if {$debug} { - set COMPILE "$proj(CC) $proj(CFLAGS_DEBUG) -ggdb \ -$proj(CFLAGS_WARNING) $INCLUDES $defs" - - if {[info exists proc(CXX)]} { - set COMPILECPP "$proj(CXX) $defs $INCLUDES $proj(CFLAGS_DEBUG) -ggdb \ - $defs $proj(CFLAGS_WARNING)" - } else { - set COMPILECPP $COMPILE - } - } else { - set COMPILE "$proj(CC) $proj(CFLAGS) $defs $INCLUDES " - - if {[info exists proc(CXX)]} { - set COMPILECPP "$proj(CXX) $defs $INCLUDES $proj(CFLAGS) $defs" - } else { - set COMPILECPP $COMPILE - } - } - - set products [my build-compile-sources $PROJECT $COMPILE $COMPILECPP] - - set map {} - lappend map %LIBRARY_NAME% $proj(name) - lappend map %LIBRARY_VERSION% $proj(version) - lappend map %LIBRARY_VERSION_NODOTS% [string map {. {}} $proj(version)] - lappend map %OUTFILE% $outfile - lappend map %LIBRARY_OBJECTS% $products - lappend map {${CFLAGS}} "$proj(CFLAGS_DEFAULT) $proj(CFLAGS_WARNING)" - - if {[string is true [$PROJECT define get SHARED_BUILD 1]]} { - set cmd [$PROJECT define get PRACTCL_SHARED_LIB] - append cmd " [$PROJECT define get PRACTCL_LIBS]" - set cmd [string map $map $cmd] - puts $cmd - exec {*}$cmd >&@ stdout - if {[$PROJECT define get PRACTCL_VC_MANIFEST_EMBED_DLL] ni {: {}}} { - set cmd [string map $map [$PROJECT define get PRACTCL_VC_MANIFEST_EMBED_DLL]] - puts $cmd - exec {*}$cmd >&@ stdout - } - } else { - set cmd [string map $map [$PROJECT define get PRACTCL_STATIC_LIB]] - puts $cmd - exec {*}$cmd >&@ stdout - } - set ranlib [$PROJECT define get RANLIB] - if {$ranlib ni {{} :}} { - catch {exec $ranlib $outfile} - } -} - -### -# Produce a static executable -### -method build-tclsh {outfile PROJECT} { - puts " BUILDING STATIC TCLSH " - set TCLOBJ [$PROJECT project TCLCORE] - set PKG_OBJS {} - foreach item [$PROJECT link list core.library] { - if {[string is true [$item define get static]]} { - lappend PKG_OBJS $item - } - } - foreach item [$PROJECT link list package] { - if {[string is true [$item define get static]]} { - lappend PKG_OBJS $item - } - } - array set TCL [$TCLOBJ config.sh] - - set TKOBJ [$PROJECT project tk] - if {[info command $TKOBJ] eq {}} { - set TKOBJ ::noop - $PROJECT define set static_tk 0 - } else { - array set TK [$TKOBJ config.sh] - $PROJECT define set static_tk [$TKOBJ define get static] - set TKSRCDIR [$TKOBJ define get srcdir] - } - set path [file dirname $outfile] - cd $path - ### - # For a static Tcl shell, we need to build all local sources - # with the same DEFS flags as the tcl core was compiled with. - # The DEFS produced by a TEA extension aren't intended to operate - # with the internals of a staticly linked Tcl - ### - my build-cflags $PROJECT $TCL(defs) name version defs - set debug [$PROJECT define get debug 0] - set NAME [string toupper $name] - set result {} - set libraries {} - set thisline {} - set OBJECTS {} - set EXTERN_OBJS {} - foreach obj $PKG_OBJS { - $obj compile - set config($obj) [$obj config.sh] - } - set os [$PROJECT define get TEACUP_OS] - set TCLSRCDIR [$TCLOBJ define get srcdir] - - set includedir . - foreach include [$TCLOBJ generate-include-directory] { - set cpath [::practcl::file_relative $path [file normalize $include]] - if {$cpath ni $includedir} { - lappend includedir $cpath - } - } - lappend includedir [::practcl::file_relative $path [file normalize ../tcl/compat/zlib]] - foreach include [$PROJECT generate-include-directory] { - set cpath [::practcl::file_relative $path [file normalize $include]] - if {$cpath ni $includedir} { - lappend includedir $cpath - } - } - - set INCLUDES "-I[join $includedir " -I"]" - if {$debug} { - set COMPILE "$TCL(cc) $TCL(shlib_cflags) $TCL(cflags_debug) -ggdb \ -$TCL(cflags_warning) $TCL(extra_cflags) $INCLUDES" - } else { - set COMPILE "$TCL(cc) $TCL(shlib_cflags) $TCL(cflags_optimize) \ -$TCL(cflags_warning) $TCL(extra_cflags) $INCLUDES" - } - append COMPILE " " $defs - lappend OBJECTS {*}[my build-compile-sources $PROJECT $COMPILE $COMPILE] - - set TCLSRC [file normalize $TCLSRCDIR] - - if {[${PROJECT} define get TEACUP_OS] eq "windows"} { - set windres [$PROJECT define get RC windres] - set RSOBJ [file join $path build tclkit.res.o] - set RCSRC [${PROJECT} define get kit_resource_file] - set cmd [list $windres -o $RSOBJ -DSTATIC_BUILD --include [::practcl::file_relative $path [file join $TCLSRC generic]]] - if {[$PROJECT define get static_tk]} { - if {$RCSRC eq {} || ![file exists $RCSRC]} { - set RCSRC [file join $TKSRCDIR win rc wish.rc] - } - set TKSRC [file normalize $TKSRCDIR] - lappend cmd --include [::practcl::file_relative $path [file join $TKSRC generic]] \ - --include [::practcl::file_relative $path [file join $TKSRC win]] \ - --include [::practcl::file_relative $path [file join $TKSRC win rc]] - } else { - if {$RCSRC eq {} || ![file exists $RCSRC]} { - set RCSRC [file join $TCLSRCDIR tclsh.rc] - } - } - foreach item [${PROJECT} define get resource_include] { - lappend cmd --include [::practcl::file_relative $path [file normalize $item]] - } - lappend cmd $RCSRC - ::practcl::doexec {*}$cmd - lappend OBJECTS $RSOBJ - set LDFLAGS_CONSOLE {-mconsole -pipe -static-libgcc} - set LDFLAGS_WINDOW {-mwindows -pipe -static-libgcc} - } else { - set LDFLAGS_CONSOLE {} - set LDFLAGS_WINDOW {} - } - puts "***" - if {$debug} { - set cmd "$TCL(cc) $TCL(shlib_cflags) $TCL(cflags_debug) \ -$TCL(cflags_warning) $TCL(extra_cflags) $INCLUDES" - } else { - set cmd "$TCL(cc) $TCL(shlib_cflags) $TCL(cflags_optimize) \ -$TCL(cflags_warning) $TCL(extra_cflags) $INCLUDES" - } - append cmd " $OBJECTS" - append cmd " $EXTERN_OBJS " - # On OSX it is impossibly to generate a completely static - # executable - if {[$PROJECT define get TEACUP_OS] ne "macosx"} { - append cmd " -static " - } - if {$debug} { - if {$os eq "windows"} { - append cmd " -L${TCL(src_dir)}/win -ltcl86g" - if {[$PROJECT define get static_tk]} { - append cmd " -L${TK(src_dir)}/win -ltk86g" - } - } else { - append cmd " -L${TCL(src_dir)}/unix -ltcl86g" - if {[$PROJECT define get static_tk]} { - append cmd " -L${TK(src_dir)}/unix -ltk86g" - } - } - } else { - append cmd " $TCL(build_lib_spec)" - if {[$PROJECT define get static_tk]} { - append cmd " $TK(build_lib_spec)" - } - } - foreach obj $PKG_OBJS { - append cmd " [$obj linker-products $config($obj)]" - } - append cmd " $TCL(libs) " - if {[$PROJECT define get static_tk]} { - append cmd " $TK(libs)" - } - foreach obj $PKG_OBJS { - append cmd " [$obj linker-external $config($obj)]" - } - if {$debug} { - if {$os eq "windows"} { - append cmd " -L${TCL(src_dir)}/win ${TCL(stub_lib_flag)}" - if {[$PROJECT define get static_tk]} { - append cmd " -L${TK(src_dir)}/win ${TK(stub_lib_flag)}" - } - } else { - append cmd " -L${TCL(src_dir)}/unix ${TCL(stub_lib_flag)}" - if {[$PROJECT define get static_tk]} { - append cmd " -L${TK(src_dir)}/unix ${TK(stub_lib_flag)}" - } - } - } else { - append cmd " $TCL(build_stub_lib_spec)" - if {[$PROJECT define get static_tk]} { - append cmd " $TK(build_stub_lib_spec)" - } - } - append cmd " -o $outfile $LDFLAGS_CONSOLE" - puts "LINK: $cmd" - exec {*}$cmd >&@ stdout -} -} - - -::oo::class create ::practcl::build.msvc { - superclass ::practcl::build - -} - -::oo::class create ::practcl::target_obj { - superclass ::practcl::metaclass - - constructor {name info} { - my variable define triggered domake - set triggered 0 - set domake 0 - set define(name) $name - set data [uplevel 2 [list subst $info]] - array set define $data - my select - my initialize - } - - method do {} { - my variable domake - return $domake - } - - method check {} { - my variable needs_make domake - if {$domake} { - return 1 - } - if {[info exists needs_make]} { - return $needs_make - } - set needs_make 0 - foreach item [my define get depends] { - if {![dict exists $::make_objects $item]} continue - set depobj [dict get $::make_objects $item] - if {$depobj eq [self]} { - puts "WARNING [self] depends on itself" - continue - } - if {[$depobj check]} { - set needs_make 1 - } - } - if {!$needs_make} { - set filename [my define get filename] - if {$filename ne {} && ![file exists $filename]} { - set needs_make 1 - } - } - return $needs_make - } - - method triggers {} { - my variable triggered domake define - if {$triggered} { - return $domake - } - set triggered 1 - foreach item [my define get depends] { - if {![dict exists $::make_objects $item]} continue - set depobj [dict get $::make_objects $item] - if {$depobj eq [self]} { - puts "WARNING [self] triggers itself" - continue - } else { - set r [$depobj check] - if {$r} { - $depobj triggers - } - } - } - if {[info exists ::make($define(name))] && $::make($define(name))} { - return - } - set ::make($define(name)) 1 - ::practcl::trigger {*}[my define get triggers] - } -} - - -### -# Define the metaclass -### -::oo::class create ::practcl::object { - superclass ::practcl::metaclass - - constructor {parent args} { - my variable links define - set organs [$parent child organs] - my graft {*}$organs - array set define $organs - array set define [$parent child define] - array set links {} - if {[llength $args]==1 && [file exists [lindex $args 0]]} { - my InitializeSourceFile [lindex $args 0] - } elseif {[llength $args] == 1} { - set data [uplevel 1 [list subst [lindex $args 0]]] - array set define $data - my select - my initialize - } else { - array set define [uplevel 1 [list subst $args]] - my select - my initialize - } - } - - - method include_dir args { - my define add include_dir {*}$args - } - - method include_directory args { - my define add include_dir {*}$args - } - - method Collate_Source CWD {} - - - method child {method} { - return {} - } - - method InitializeSourceFile filename { - my define set filename $filename - set class {} - switch [file extension $filename] { - .tcl { - set class ::practcl::dynamic - } - .h { - set class ::practcl::cheader - } - .c { - set class ::practcl::csource - } - .ini { - switch [file tail $filename] { - module.ini { - set class ::practcl::module - } - library.ini { - set class ::practcl::subproject - } - } - } - .so - - .dll - - .dylib - - .a { - set class ::practcl::clibrary - } - } - if {$class ne {}} { - oo::objdefine [self] class $class - my initialize - } - } - - method add args { - my variable links - set object [::practcl::object new [self] {*}$args] - foreach linktype [$object linktype] { - lappend links($linktype) $object - } - return $object - } - - method go {} { - ::practcl::debug [list [self] [self method] [self class] -- [my define get filename] [info object class [self]]] - my variable links - foreach {linktype objs} [array get links] { - foreach obj $objs { - $obj go - } - } - ::practcl::debug [list /[self] [self method] [self class]] - } - - method code {section body} { - my variable code - ::practcl::cputs code($section) $body - } - - method Ofile filename { - set lpath [my <module> define get localpath] - if {$lpath eq {}} { - set lpath [my <module> define get name] - } - return ${lpath}_[file rootname [file tail $filename]].o - } - - method compile-products {} { - set filename [my define get filename] - set result {} - if {$filename ne {}} { - if {[my define exists ofile]} { - set ofile [my define get ofile] - } else { - set ofile [my Ofile $filename] - my define set ofile $ofile - } - lappend result $ofile [list cfile $filename extra [my define get extra] external [string is true -strict [my define get external]] object [self]] - } - foreach item [my link list subordinate] { - lappend result {*}[$item compile-products] - } - return $result - } - - method generate-include-directory {} { - ::practcl::debug [list [self] [self method] [self class] -- [my define get filename] [info object class [self]]] - set result [my define get include_dir] - foreach obj [my link list product] { - foreach path [$obj generate-include-directory] { - lappend result $path - } - } - return $result - } - - method generate-debug {{spaces {}}} { - set result {} - ::practcl::cputs result "$spaces[list [self] [list class [info object class [self]] filename [my define get filename]] links [my link list]]" - foreach item [my link list subordinate] { - practcl::cputs result [$item generate-debug "$spaces "] - } - return $result - } - - # Empty template methods - method generate-cheader {} { - ::practcl::debug [list [self] [self method] [self class] -- [my define get filename] [info object class [self]]] - my variable code cfunct cstruct methods tcltype tclprocs - set result {} - if {[info exists code(header)]} { - ::practcl::cputs result $code(header) - } - foreach obj [my link list product] { - # Exclude products that will generate their own C files - if {[$obj define get output_c] ne {}} continue - set dat [$obj generate-cheader] - if {[string length [string trim $dat]]} { - ::practcl::cputs result "/* BEGIN [$obj define get filename] generate-cheader */" - ::practcl::cputs result $dat - ::practcl::cputs result "/* END [$obj define get filename] generate-cheader */" - } - } - ::practcl::debug [list cfunct [info exists cfunct]] - if {[info exists cfunct]} { - foreach {funcname info} $cfunct { - if {[dict get $info public]} continue - ::practcl::cputs result "[dict get $info header]\;" - } - } - ::practcl::debug [list tclprocs [info exists tclprocs]] - if {[info exists tclprocs]} { - foreach {name info} $tclprocs { - if {[dict exists $info header]} { - ::practcl::cputs result "[dict get $info header]\;" - } - } - } - ::practcl::debug [list methods [info exists methods] [my define get cclass]] - - if {[info exists methods]} { - set thisclass [my define get cclass] - foreach {name info} $methods { - if {[dict exists $info header]} { - ::practcl::cputs result "[dict get $info header]\;" - } - } - # Add the initializer wrapper for the class - ::practcl::cputs result "static int ${thisclass}_OO_Init(Tcl_Interp *interp)\;" - } - return $result - } - - method generate-public-define {} { - ::practcl::debug [list [self] [self method] [self class] -- [my define get filename] [info object class [self]]] - my variable code - set result {} - if {[info exists code(public-define)]} { - ::practcl::cputs result $code(public-define) - } - set result [::practcl::_tagblock $result c [my define get filename]] - foreach mod [my link list product] { - ::practcl::cputs result [$mod generate-public-define] - } - return $result - } - - method generate-public-macro {} { - ::practcl::debug [list [self] [self method] [self class] -- [my define get filename] [info object class [self]]] - my variable code - set result {} - if {[info exists code(public-macro)]} { - ::practcl::cputs result $code(public-macro) - } - set result [::practcl::_tagblock $result c [my define get filename]] - foreach mod [my link list product] { - ::practcl::cputs result [$mod generate-public-macro] - } - return $result - } - - method generate-public-typedef {} { - ::practcl::debug [list [self] [self method] [self class] -- [my define get filename] [info object class [self]]] - my variable code cstruct - set result {} - if {[info exists code(public-typedef)]} { - ::practcl::cputs result $code(public-typedef) - } - if {[info exists cstruct]} { - # Add defintion for native c data structures - foreach {name info} $cstruct { - if {[dict get $info public]==0} continue - ::practcl::cputs result "typedef struct $name ${name}\;" - if {[dict exists $info aliases]} { - foreach n [dict get $info aliases] { - ::practcl::cputs result "typedef struct $name ${n}\;" - } - } - } - } - set result [::practcl::_tagblock $result c [my define get filename]] - foreach mod [my link list product] { - ::practcl::cputs result [$mod generate-public-typedef] - } - return $result - } - - method generate-private-typedef {} { - ::practcl::debug [list [self] [self method] [self class] -- [my define get filename] [info object class [self]]] - my variable code cstruct - set result {} - if {[info exists code(private-typedef)]} { - ::practcl::cputs result $code(private-typedef) - } - if {[info exists cstruct]} { - # Add defintion for native c data structures - foreach {name info} $cstruct { - if {[dict get $info public]==1} continue - ::practcl::cputs result "typedef struct $name ${name}\;" - if {[dict exists $info aliases]} { - foreach n [dict get $info aliases] { - ::practcl::cputs result "typedef struct $name ${n}\;" - } - } - } - } - set result [::practcl::_tagblock $result c [my define get filename]] - foreach mod [my link list product] { - ::practcl::cputs result [$mod generate-private-typedef] - } - return $result - } - - method generate-public-structure {} { - ::practcl::debug [list [self] [self method] [self class] -- [my define get filename] [info object class [self]]] - my variable code cstruct - set result {} - if {[info exists code(public-structure)]} { - ::practcl::cputs result $code(public-structure) - } - if {[info exists cstruct]} { - foreach {name info} $cstruct { - if {[dict get $info public]==0} continue - if {[dict exists $info comment]} { - ::practcl::cputs result [dict get $info comment] - } - ::practcl::cputs result "struct $name \{[dict get $info body]\}\;" - } - } - set result [::practcl::_tagblock $result c [my define get filename]] - foreach mod [my link list product] { - ::practcl::cputs result [$mod generate-public-structure] - } - return $result - } - - - method generate-private-structure {} { - ::practcl::debug [list [self] [self method] [self class] -- [my define get filename] [info object class [self]]] - my variable code cstruct - set result {} - if {[info exists code(private-structure)]} { - ::practcl::cputs result $code(private-structure) - } - if {[info exists cstruct]} { - foreach {name info} $cstruct { - if {[dict get $info public]==1} continue - if {[dict exists $info comment]} { - ::practcl::cputs result [dict get $info comment] - } - ::practcl::cputs result "struct $name \{[dict get $info body]\}\;" - } - } - set result [::practcl::_tagblock $result c [my define get filename]] - foreach mod [my link list product] { - ::practcl::cputs result [$mod generate-private-structure] - } - return $result - } - - method generate-public-headers {} { - ::practcl::debug [list [self] [self method] [self class] -- [my define get filename] [info object class [self]]] - my variable code tcltype - set result {} - if {[info exists code(public-header)]} { - ::practcl::cputs result $code(public-header) - } - if {[info exists tcltype]} { - foreach {type info} $tcltype { - if {![dict exists $info cname]} { - set cname [string tolower ${type}]_tclobjtype - dict set tcltype $type cname $cname - } else { - set cname [dict get $info cname] - } - ::practcl::cputs result "extern const Tcl_ObjType $cname\;" - } - } - if {[info exists code(public)]} { - ::practcl::cputs result $code(public) - } - set result [::practcl::_tagblock $result c [my define get filename]] - foreach mod [my link list product] { - ::practcl::cputs result [$mod generate-public-headers] - } - return $result - } - - method generate-stub-function {} { - ::practcl::debug [list [self] [self method] [self class] -- [my define get filename] [info object class [self]]] - my variable code cfunct tcltype - set result {} - foreach mod [my link list product] { - foreach {funct def} [$mod generate-stub-function] { - dict set result $funct $def - } - } - if {[info exists cfunct]} { - foreach {funcname info} $cfunct { - if {![dict get $info export]} continue - dict set result $funcname [dict get $info header] - } - } - return $result - } - - method generate-public-function {} { - ::practcl::debug [list [self] [self method] [self class] -- [my define get filename] [info object class [self]]] - my variable code cfunct tcltype - set result {} - - if {[my define get initfunc] ne {}} { - ::practcl::cputs result "int [my define get initfunc](Tcl_Interp *interp);" - } - if {[info exists cfunct]} { - foreach {funcname info} $cfunct { - if {![dict get $info public]} continue - ::practcl::cputs result "[dict get $info header]\;" - } - } - set result [::practcl::_tagblock $result c [my define get filename]] - foreach mod [my link list product] { - ::practcl::cputs result [$mod generate-public-function] - } - return $result - } - - method generate-public-includes {} { - ::practcl::debug [list [self] [self method] [self class] -- [my define get filename] [info object class [self]]] - set includes {} - foreach item [my define get public-include] { - if {$item ni $includes} { - lappend includes $item - } - } - foreach mod [my link list product] { - foreach item [$mod generate-public-includes] { - if {$item ni $includes} { - lappend includes $item - } - } - } - return $includes - } - method generate-public-verbatim {} { - ::practcl::debug [list [self] [self method] [self class] -- [my define get filename] [info object class [self]]] - set includes {} - foreach item [my define get public-verbatim] { - if {$item ni $includes} { - lappend includes $item - } - } - foreach mod [my link list subordinate] { - foreach item [$mod generate-public-verbatim] { - if {$item ni $includes} { - lappend includes $item - } - } - } - return $includes - } - ### - # This methods generates the contents of an amalgamated .h file - # which describes the public API of this module - ### - method generate-h {} { - ::practcl::debug [list [self] [self method] [self class] -- [my define get filename] [info object class [self]]] - set result {} - set includes [my generate-public-includes] - foreach inc $includes { - if {[string index $inc 0] ni {< \"}} { - ::practcl::cputs result "#include \"$inc\"" - } else { - ::practcl::cputs result "#include $inc" - } - } - - foreach method { - generate-public-define - generate-public-macro - generate-public-typedef - generate-public-structure - } { - ::practcl::cputs result "/* BEGIN SECTION $method */" - ::practcl::cputs result [my $method] - ::practcl::cputs result "/* END SECTION $method */" - } - - foreach file [my generate-public-verbatim] { - ::practcl::cputs result "/* BEGIN $file */" - ::practcl::cputs result [::practcl::cat $file] - ::practcl::cputs result "/* END $file */" - } - - foreach method { - generate-public-headers - generate-public-function - } { - ::practcl::cputs result "/* BEGIN SECTION $method */" - ::practcl::cputs result [my $method] - ::practcl::cputs result "/* END SECTION $method */" - } - return $result - } - - method IncludeAdd {headervar args} { - upvar 1 $headervar headers - foreach inc $args { - if {[string index $inc 0] ni {< \"}} { - set inc "\"$inc\"" - } - if {$inc ni $headers} { - lappend headers $inc - } - } - } - - ### - # This methods generates the contents of an amalgamated .c file - # which implements the loader for a batch of tools - ### - method generate-c {} { - ::practcl::debug [list [self] [self method] [self class] -- [my define get filename] [info object class [self]]] - set result { -/* This file was generated by practcl */ - } - set includes {} - - foreach mod [my link list product] { - # Signal modules to formulate final implementation - $mod go - } - set headers {} - - my IncludeAdd headers <tcl.h> <tclOO.h> - if {[my define get tk 0]} { - my IncludeAdd headers <tk.h> - } - if {[my define get output_h] ne {}} { - my IncludeAdd headers [my define get output_h] - } - my IncludeAdd headers {*}[my define get include] - - foreach mod [my link list dynamic] { - my IncludeAdd headers {*}[$mod define get include] - } - foreach inc $headers { - ::practcl::cputs result "#include $inc" - } - foreach {method} { - generate-cheader - generate-private-typedef - generate-private-structure - generate-cstruct - generate-constant - generate-cfunct - generate-cmethod - } { - set dat [my $method] - if {[string length [string trim $dat]]} { - ::practcl::cputs result "/* BEGIN $method [my define get filename] */" - ::practcl::cputs result $dat - ::practcl::cputs result "/* END $method [my define get filename] */" - } - } - ::practcl::debug [list /[self] [self method] [self class] -- [my define get filename] [info object class [self]]] - return $result - } - - - method generate-loader {} { - ::practcl::debug [list [self] [self method] [self class] -- [my define get filename] [info object class [self]]] - set result {} - if {[my define get initfunc] eq {}} return - ::practcl::cputs result " -extern int DLLEXPORT [my define get initfunc]( Tcl_Interp *interp ) \{" - ::practcl::cputs result { - /* Initialise the stubs tables. */ - #ifdef USE_TCL_STUBS - if (Tcl_InitStubs(interp, "8.6", 0)==NULL) return TCL_ERROR; - if (TclOOInitializeStubs(interp, "1.0") == NULL) return TCL_ERROR; -} - if {[my define get tk 0]} { - ::practcl::cputs result { if (Tk_InitStubs(interp, "8.6", 0)==NULL) return TCL_ERROR;} - } - ::practcl::cputs result { #endif} - set TCLINIT [my generate-tcl-pre] - if {[string length $TCLINIT]} { - ::practcl::cputs result " if(Tcl_Eval(interp,[::practcl::tcl_to_c $TCLINIT])) return TCL_ERROR ;" - } - foreach item [my link list product] { - if {[$item define get output_c] ne {}} { - ::practcl::cputs result [$item generate-cinit-external] - } else { - ::practcl::cputs result [$item generate-cinit] - } - } - set TCLINIT [my generate-tcl-post] - if {[string length $TCLINIT]} { - ::practcl::cputs result " if(Tcl_Eval(interp,[::practcl::tcl_to_c $TCLINIT])) return TCL_ERROR ;" - } - if {[my define exists pkg_name]} { - ::practcl::cputs result " if (Tcl_PkgProvide(interp, \"[my define get pkg_name [my define get name]]\" , \"[my define get pkg_vers [my define get version]]\" )) return TCL_ERROR\;" - } - ::practcl::cputs result " return TCL_OK\;\n\}\n" - return $result - } - - ### - # This methods generates any Tcl script file - # which is required to pre-initialize the C library - ### - method generate-tcl-pre {} { - ::practcl::debug [list [self] [self method] [self class] -- [my define get filename] [info object class [self]]] - set result {} - my variable code - if {[info exists code(tcl)]} { - set result [::practcl::_tagblock $code(tcl) tcl [my define get filename]] - } - if {[info exists code(tcl-pre)]} { - set result [::practcl::_tagblock $code(tcl) tcl [my define get filename]] - } - foreach mod [my link list product] { - ::practcl::cputs result [$mod generate-tcl-pre] - } - return $result - } - - method generate-tcl-post {} { - ::practcl::debug [list [self] [self method] [self class] -- [my define get filename] [info object class [self]]] - set result {} - my variable code - if {[info exists code(tcl-post)]} { - set result [::practcl::_tagblock $code(tcl-post) tcl [my define get filename]] - } - foreach mod [my link list product] { - ::practcl::cputs result [$mod generate-tcl-post] - } - return $result - } - - method static-packages {} { - set result [my define get static_packages] - set statpkg [my define get static_pkg] - set initfunc [my define get initfunc] - if {$initfunc ne {}} { - set pkg_name [my define get pkg_name] - if {$pkg_name ne {}} { - dict set result $pkg_name initfunc $initfunc - dict set result $pkg_name version [my define get version [my define get pkg_vers]] - dict set result $pkg_name autoload [my define get autoload 0] - } - } - foreach item [my link list subordinate] { - foreach {pkg info} [$item static-packages] { - dict set result $pkg $info - } - } - return $result - } - - method target {method args} { - switch $method { - is_unix { return [expr {$::tcl_platform(platform) eq "unix"}] } - } - } - -} - -::oo::class create ::practcl::product { - superclass ::practcl::object - - method linktype {} { - return {subordinate product} - } - - method include header { - my define add include $header - } - - method cstructure {name definition {argdat {}}} { - my variable cstruct - dict set cstruct $name body $definition - foreach {f v} $argdat { - dict set cstruct $name $f $v - } - if {![dict exists $cstruct $name public]} { - dict set cstruct $name public 1 - } - } - - method generate-cinit {} { - ::practcl::debug [list [self] [self method] [self class] -- [my define get filename] [info object class [self]]] - my variable code - set result {} - if {[info exists code(cinit)]} { - ::practcl::cputs result $code(cinit) - } - if {[my define get initfunc] ne {}} { - ::practcl::cputs result " if([my define get initfunc](interp)!=TCL_OK) return TCL_ERROR\;" - } - set result [::practcl::_tagblock $result c [my define get filename]] - foreach obj [my link list product] { - ::practcl::cputs result [$obj generate-cinit] - } - return $result - } -} - -### -# Dynamic blocks do not generate their own .c files, -# instead the contribute to the amalgamation -# of the main library file -### -::oo::class create ::practcl::dynamic { - superclass ::practcl::product - - # Retrieve any additional source files required - - method compile-products {} { - set filename [my define get output_c] - set result {} - if {$filename ne {}} { - if {[my define exists ofile]} { - set ofile [my define get ofile] - } else { - set ofile [my Ofile $filename] - my define set ofile $ofile - } - lappend result $ofile [list cfile $filename extra [my define get extra] external [string is true -strict [my define get external]]] - } else { - set filename [my define get cfile] - if {$filename ne {}} { - if {[my define exists ofile]} { - set ofile [my define get ofile] - } else { - set ofile [my Ofile $filename] - my define set ofile $ofile - } - lappend result $ofile [list cfile $filename extra [my define get extra] external [string is true -strict [my define get external]]] - } - } - foreach item [my link list subordinate] { - lappend result {*}[$item compile-products] - } - return $result - } - - method implement path { - my go - my Collate_Source $path - if {[my define get output_c] eq {}} return - set filename [file join $path [my define get output_c]] - my define set cfile $filename - set fout [open $filename w] - puts $fout [my generate-c] - if {[my define get initfunc] ne {}} { - puts $fout "extern int DLLEXPORT [my define get initfunc]( Tcl_Interp *interp ) \x7B" - puts $fout [my generate-cinit] - if {[my define get pkg_name] ne {}} { - puts $fout " Tcl_PkgProvide(interp, \"[my define get pkg_name]\", \"[my define get pkg_vers]\");" - } - puts $fout " return TCL_OK\;" - puts $fout "\x7D" - } - close $fout - } - - method initialize {} { - set filename [my define get filename] - if {$filename eq {}} { - return - } - if {[my define get name] eq {}} { - my define set name [file tail [file rootname $filename]] - } - if {[my define get localpath] eq {}} { - my define set localpath [my <module> define get localpath]_[my define get name] - } - ::source $filename - } - - method linktype {} { - return {subordinate product dynamic} - } - - ### - # Populate const static data structures - ### - method generate-cstruct {} { - ::practcl::debug [list [self] [self method] [self class] -- [my define get filename] [info object class [self]]] - my variable code cstruct methods tcltype - set result {} - if {[info exists code(struct)]} { - ::practcl::cputs result $code(struct) - } - foreach obj [my link list dynamic] { - # Exclude products that will generate their own C files - if {[$obj define get output_c] ne {}} continue - ::practcl::cputs result [$obj generate-cstruct] - } - return $result - } - - method generate-constant {} { - ::practcl::debug [list [self] [self method] [self class] -- [my define get filename] [info object class [self]]] - set result {} - my variable code cstruct methods tcltype - if {[info exists code(constant)]} { - ::practcl::cputs result "/* [my define get filename] CONSTANT */" - ::practcl::cputs result $code(constant) - } - if {[info exists cstruct]} { - foreach {name info} $cstruct { - set map {} - lappend map @NAME@ $name - lappend map @MACRO@ GET[string toupper $name] - - if {[dict exists $info deleteproc]} { - lappend map @DELETEPROC@ [dict get $info deleteproc] - } else { - lappend map @DELETEPROC@ NULL - } - if {[dict exists $info cloneproc]} { - lappend map @CLONEPROC@ [dict get $info cloneproc] - } else { - lappend map @CLONEPROC@ NULL - } - ::practcl::cputs result [string map $map { -const static Tcl_ObjectMetadataType @NAME@DataType = { - TCL_OO_METADATA_VERSION_CURRENT, - "@NAME@", - @DELETEPROC@, - @CLONEPROC@ -}; -#define @MACRO@(OBJCONTEXT) (@NAME@ *) Tcl_ObjectGetMetadata(OBJCONTEXT,&@NAME@DataType) -}] - } - } - if {[info exists tcltype]} { - foreach {type info} $tcltype { - dict with info {} - ::practcl::cputs result "const Tcl_ObjType $cname = \{\n .freeIntRepProc = &${freeproc},\n .dupIntRepProc = &${dupproc},\n .updateStringProc = &${updatestringproc},\n .setFromAnyProc = &${setfromanyproc}\n\}\;" - } - } - - if {[info exists methods]} { - set mtypes {} - foreach {name info} $methods { - set callproc [dict get $info callproc] - set methodtype [dict get $info methodtype] - if {$methodtype in $mtypes} continue - lappend mtypes $methodtype - ### - # Build the data struct for this method - ### - ::practcl::cputs result "const static Tcl_MethodType $methodtype = \{" - ::practcl::cputs result " .version = TCL_OO_METADATA_VERSION_CURRENT,\n .name = \"$name\",\n .callProc = $callproc," - if {[dict exists $info deleteproc]} { - set deleteproc [dict get $info deleteproc] - } else { - set deleteproc NULL - } - if {$deleteproc ni { {} NULL }} { - ::practcl::cputs result " .deleteProc = $deleteproc," - } else { - ::practcl::cputs result " .deleteProc = NULL," - } - if {[dict exists $info cloneproc]} { - set cloneproc [dict get $info cloneproc] - } else { - set cloneproc NULL - } - if {$cloneproc ni { {} NULL }} { - ::practcl::cputs result " .cloneProc = $cloneproc\n\}\;" - } else { - ::practcl::cputs result " .cloneProc = NULL\n\}\;" - } - dict set methods $name methodtype $methodtype - } - } - foreach obj [my link list dynamic] { - # Exclude products that will generate their own C files - if {[$obj define get output_c] ne {}} continue - ::practcl::cputs result [$obj generate-constant] - } - return $result - } - - ### - # Generate code that provides subroutines called by - # Tcl API methods - ### - method generate-cfunct {} { - ::practcl::debug [list [self] [self method] [self class] -- [my define get filename] [info object class [self]]] - my variable code cfunct - set result {} - if {[info exists code(funct)]} { - ::practcl::cputs result $code(funct) - } - if {[info exists cfunct]} { - foreach {funcname info} $cfunct { - ::practcl::cputs result "/* $funcname */" - ::practcl::cputs result "\n[dict get $info header]\{[dict get $info body]\}" - } - } - foreach obj [my link list dynamic] { - # Exclude products that will generate their own C files - if {[$obj define get output_c] ne {}} { - continue - } - ::practcl::cputs result [$obj generate-cfunct] - } - return $result - } - - ### - # Generate code that provides implements Tcl API - # calls - ### - method generate-cmethod {} { - ::practcl::debug [list [self] [self method] [self class] -- [my define get filename] [info object class [self]]] - my variable code methods tclprocs - set result {} - if {[info exists code(method)]} { - ::practcl::cputs result $code(method) - } - - if {[info exists tclprocs]} { - foreach {name info} $tclprocs { - if {![dict exists $info body]} continue - set callproc [dict get $info callproc] - set header [dict get $info header] - set body [dict get $info body] - ::practcl::cputs result "/* Tcl Proc $name */" - ::practcl::cputs result "${header} \{${body}\}" - } - } - - - if {[info exists methods]} { - set thisclass [my define get cclass] - foreach {name info} $methods { - if {![dict exists $info body]} continue - set callproc [dict get $info callproc] - set header [dict get $info header] - set body [dict get $info body] - ::practcl::cputs result "/* OO Method $thisclass $name */" - ::practcl::cputs result "${header} \{${body}\}" - } - # Build the OO_Init function - ::practcl::cputs result "/* Loader for $thisclass */" - ::practcl::cputs result "static int ${thisclass}_OO_Init(Tcl_Interp *interp) \{" - ::practcl::cputs result [string map [list @CCLASS@ $thisclass @TCLCLASS@ [my define get class]] { - /* - ** Build the "@TCLCLASS@" class - */ - Tcl_Obj* nameObj; /* Name of a class or method being looked up */ - Tcl_Object curClassObject; /* Tcl_Object representing the current class */ - Tcl_Class curClass; /* Tcl_Class representing the current class */ - - /* - * Find the "@TCLCLASS@" class, and attach an 'init' method to it. - */ - - nameObj = Tcl_NewStringObj("@TCLCLASS@", -1); - Tcl_IncrRefCount(nameObj); - if ((curClassObject = Tcl_GetObjectFromObj(interp, nameObj)) == NULL) { - Tcl_DecrRefCount(nameObj); - return TCL_ERROR; - } - Tcl_DecrRefCount(nameObj); - curClass = Tcl_GetObjectAsClass(curClassObject); -}] - if {[dict exists $methods constructor]} { - set mtype [dict get $methods constructor methodtype] - ::practcl::cputs result [string map [list @MTYPE@ $mtype] { - /* Attach the constructor to the class */ - Tcl_ClassSetConstructor(interp, curClass, Tcl_NewMethod(interp, curClass, NULL, 1, &@MTYPE@, NULL)); - }] - } - foreach {name info} $methods { - dict with info {} - if {$name in {constructor destructor}} continue - ::practcl::cputs result [string map [list @NAME@ $name @MTYPE@ $methodtype] { - nameObj=Tcl_NewStringObj("@NAME@",-1); - Tcl_NewMethod(interp, curClass, nameObj, 1, &@MTYPE@, (ClientData) NULL); - Tcl_DecrRefCount(nameObj); -}] - if {[dict exists $info aliases]} { - foreach alias [dict get $info aliases] { - if {[dict exists $methods $alias]} continue - ::practcl::cputs result [string map [list @NAME@ $alias @MTYPE@ $methodtype] { - nameObj=Tcl_NewStringObj("@NAME@",-1); - Tcl_NewMethod(interp, curClass, nameObj, 1, &@MTYPE@, (ClientData) NULL); - Tcl_DecrRefCount(nameObj); -}] - } - } - } - ::practcl::cputs result " return TCL_OK\;\n\}\n" - } - foreach obj [my link list dynamic] { - # Exclude products that will generate their own C files - if {[$obj define get output_c] ne {}} continue - ::practcl::cputs result [$obj generate-cmethod] - } - return $result - } - - method generate-cinit-external {} { - if {[my define get initfunc] eq {}} { - return "/* [my define get filename] declared not initfunc */" - } - return " if([my define get initfunc](interp)) return TCL_ERROR\;" - } - - ### - # Generate code that runs when the package/module is - # initialized into the interpreter - ### - method generate-cinit {} { - ::practcl::debug [list [self] [self method] [self class] -- [my define get filename] [info object class [self]]] - set result {} - my variable code methods tclprocs - if {[info exists code(nspace)]} { - ::practcl::cputs result " \{\n Tcl_Namespace *modPtr;" - foreach nspace $code(nspace) { - ::practcl::cputs result [string map [list @NSPACE@ $nspace] { - modPtr=Tcl_FindNamespace(interp,"@NSPACE@",NULL,TCL_NAMESPACE_ONLY); - if(!modPtr) { - modPtr = Tcl_CreateNamespace(interp, "@NSPACE@", NULL, NULL); - } -}] - } - ::practcl::cputs result " \}" - } - if {[info exists code(tclinit)]} { - ::practcl::cputs result $code(tclinit) - } - if {[info exists code(cinit)]} { - ::practcl::cputs result $code(cinit) - } - if {[info exists code(initfuncts)]} { - foreach func $code(initfuncts) { - ::practcl::cputs result " if (${func}(interp) != TCL_OK) return TCL_ERROR\;" - } - } - if {[info exists tclprocs]} { - foreach {name info} $tclprocs { - set map [list @NAME@ $name @CALLPROC@ [dict get $info callproc]] - ::practcl::cputs result [string map $map { Tcl_CreateObjCommand(interp,"@NAME@",(Tcl_ObjCmdProc *)@CALLPROC@,NULL,NULL);}] - if {[dict exists $info aliases]} { - foreach alias [dict get $info aliases] { - set map [list @NAME@ $alias @CALLPROC@ [dict get $info callproc]] - ::practcl::cputs result [string map $map { Tcl_CreateObjCommand(interp,"@NAME@",(Tcl_ObjCmdProc *)@CALLPROC@,NULL,NULL);}] - } - } - } - } - - if {[info exists code(nspace)]} { - ::practcl::cputs result " \{\n Tcl_Namespace *modPtr;" - foreach nspace $code(nspace) { - ::practcl::cputs result [string map [list @NSPACE@ $nspace] { - modPtr=Tcl_FindNamespace(interp,"@NSPACE@",NULL,TCL_NAMESPACE_ONLY); - Tcl_CreateEnsemble(interp, modPtr->fullName, modPtr, TCL_ENSEMBLE_PREFIX); - Tcl_Export(interp, modPtr, "[a-z]*", 1); -}] - } - ::practcl::cputs result " \}" - } - set result [::practcl::_tagblock $result c [my define get filename]] - foreach obj [my link list product] { - # Exclude products that will generate their own C files - if {[$obj define get output_c] ne {}} { - ::practcl::cputs result [$obj generate-cinit-external] - } else { - ::practcl::cputs result [$obj generate-cinit] - } - } - return $result - } - - method c_header body { - my variable code - ::practcl::cputs code(header) $body - } - - method c_code body { - my variable code - ::practcl::cputs code(funct) $body - } - method c_function {header body {info {}}} { - set header [string map "\t \ \n \ \ \ \ " $header] - my variable code cfunct - foreach regexp { - {(.*) ([a-zA-Z_][a-zA-Z0-9_]*) *\((.*)\)} - {(.*) (\x2a[a-zA-Z_][a-zA-Z0-9_]*) *\((.*)\)} - } { - if {[regexp $regexp $header all keywords funcname arglist]} { - dict set cfunct $funcname header $header - dict set cfunct $funcname body $body - dict set cfunct $funcname keywords $keywords - dict set cfunct $funcname arglist $arglist - dict set cfunct $funcname inline [expr {"inline" ni $keywords}] - dict set cfunct $funcname public [expr {"static" ni $keywords}] - dict set cfunct $funcname export [expr {"STUB_EXPORT" in $keywords}] - foreach {f v} $info { - dict set cfunct $f $v - } - return - } - } - foreach {f v} $info { - dict set cfunct $f $v - } - ::practcl::cputs code(header) "$header\;" - # Could not parse that block as a function - # append it verbatim to our c_implementation - ::practcl::cputs code(funct) "$header [list $body]" - } - - - method cmethod {name body {arginfo {}}} { - my variable methods code - foreach {f v} $arginfo { - dict set methods $name $f $v - } - dict set methods $name body "Tcl_Object thisObject = Tcl_ObjectContextObject(objectContext); /* The current connection object */ -$body" - } - - method c_tclproc_nspace nspace { - my variable code - if {![info exists code(nspace)]} { - set code(nspace) {} - } - if {$nspace ni $code(nspace)} { - lappend code(nspace) $nspace - } - } - - method c_tclproc_raw {name body {arginfo {}}} { - my variable tclprocs code - - foreach {f v} $arginfo { - dict set tclprocs $name $f $v - } - dict set tclprocs $name body $body - } - - method go {} { - ::practcl::debug [list [self] [self method] [self class] -- [my define get filename] [info object class [self]]] - next - my variable methods code cstruct tclprocs - if {[info exists methods]} { - ::practcl::debug [self] methods [my define get cclass] - set thisclass [my define get cclass] - foreach {name info} $methods { - # Provide a callproc - if {![dict exists $info callproc]} { - set callproc [string map {____ _ ___ _ __ _} [string map {{ } _ : _} OOMethod_${thisclass}_${name}]] - dict set methods $name callproc $callproc - } else { - set callproc [dict get $info callproc] - } - if {[dict exists $info body] && ![dict exists $info header]} { - dict set methods $name header "static int ${callproc}(ClientData clientData, Tcl_Interp *interp, Tcl_ObjectContext objectContext ,int objc ,Tcl_Obj *const *objv)" - } - if {![dict exists $info methodtype]} { - set methodtype [string map {{ } _ : _} OOMethodType_${thisclass}_${name}] - dict set methods $name methodtype $methodtype - } - } - if {![info exists code(initfuncts)] || "${thisclass}_OO_Init" ni $code(initfuncts)} { - lappend code(initfuncts) "${thisclass}_OO_Init" - } - } - set thisnspace [my define get nspace] - - if {[info exists tclprocs]} { - ::practcl::debug [self] tclprocs [dict keys $tclprocs] - foreach {name info} $tclprocs { - if {![dict exists $info callproc]} { - set callproc [string map {____ _ ___ _ __ _} [string map {{ } _ : _} TclCmd_${thisnspace}_${name}]] - dict set tclprocs $name callproc $callproc - } else { - set callproc [dict get $info callproc] - } - if {[dict exists $info body] && ![dict exists $info header]} { - dict set tclprocs $name header "static int ${callproc}(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv\[\])" - } - } - } - ::practcl::debug [list /[self] [self method] [self class]] - } - - # Once an object marks itself as some - # flavor of dynamic, stop trying to morph - # it into something else - method select {} {} - - - method tcltype {name argdat} { - my variable tcltype - foreach {f v} $argdat { - dict set tcltype $name $f $v - } - if {![dict exists tcltype $name cname]} { - dict set tcltype $name cname [string tolower $name]_tclobjtype - } - lappend map @NAME@ $name - set info [dict get $tcltype $name] - foreach {f v} $info { - lappend map @[string toupper $f]@ $v - } - foreach {func fpat template} { - freeproc {@Name@Obj_freeIntRepProc} {void @FNAME@(Tcl_Obj *objPtr)} - dupproc {@Name@Obj_dupIntRepProc} {void @FNAME@(Tcl_Obj *srcPtr,Tcl_Obj *dupPtr)} - updatestringproc {@Name@Obj_updateStringRepProc} {void @FNAME@(Tcl_Obj *objPtr)} - setfromanyproc {@Name@Obj_setFromAnyProc} {int @FNAME@(Tcl_Interp *interp,Tcl_Obj *objPtr)} - } { - if {![dict exists $info $func]} { - error "$name does not define $func" - } - set body [dict get $info $func] - # We were given a function name to call - if {[llength $body] eq 1} continue - set fname [string map [list @Name@ [string totitle $name]] $fpat] - my c_function [string map [list @FNAME@ $fname] $template] [string map $map $body] - dict set tcltype $name $func $fname - } - } -} - -::oo::class create ::practcl::cheader { - superclass ::practcl::product - - method compile-products {} {} - method generate-cinit {} {} -} - -::oo::class create ::practcl::csource { - superclass ::practcl::product -} - -::oo::class create ::practcl::clibrary { - superclass ::practcl::product - - method linker-products {configdict} { - return [my define get filename] - } - -} - -### -# In the end, all C code must be loaded into a module -# This will either be a dynamically loaded library implementing -# a tcl extension, or a compiled in segment of a custom shell/app -### -::oo::class create ::practcl::module { - superclass ::practcl::dynamic - - method child which { - switch $which { - organs { - return [list project [my define get project] module [self]] - } - } - } - - method initialize {} { - set filename [my define get filename] - if {$filename eq {}} { - return - } - if {[my define get name] eq {}} { - my define set name [file tail [file dirname $filename]] - } - if {[my define get localpath] eq {}} { - my define set localpath [my <project> define get name]_[my define get name] - } - ::practcl::debug [self] SOURCE $filename - my source $filename - } - - method implement path { - my go - my Collate_Source $path - foreach item [my link list dynamic] { - if {[catch {$item implement $path} err]} { - puts "Skipped $item: $err" - } - } - foreach item [my link list module] { - if {[catch {$item implement $path} err]} { - puts "Skipped $item: $err" - } - } - ::practcl::debug [list [self] [self method] [self class] -- [my define get filename] [info object class [self]]] - set filename [my define get output_c] - if {$filename eq {}} { - ::practcl::debug [list /[self] [self method] [self class]] - return - } - set cout [open [file join $path [file rootname $filename].c] w] - puts $cout [subst {/* -** This file is generated by the [info script] script -** any changes will be overwritten the next time it is run -*/}] - puts $cout [my generate-c] - puts $cout [my generate-loader] - close $cout - ::practcl::debug [list /[self] [self method] [self class]] - } - - method linktype {} { - return {subordinate product dynamic module} - } -} - -::oo::class create ::practcl::autoconf { - - ### - # find or fake a key/value list describing this project - ### - method config.sh {} { - my variable conf_result - if {[info exists conf_result]} { - return $conf_result - } - set result {} - set name [my define get name] - set PWD $::CWD - set builddir [my define get builddir] - my unpack - set srcdir [my define get srcdir] - if {![file exists $builddir]} { - my Configure - } - set filename [file join $builddir config.tcl] - # Project uses the practcl template. Use the leavings from autoconf - if {[file exists $filename]} { - set dat [::practcl::config.tcl $builddir] - foreach {item value} [::practcl::sort_dict $dat] { - dict set result $item $value - } - set conf_result $result - return $result - } - set filename [file join $builddir ${name}Config.sh] - if {[file exists $filename]} { - set l [expr {[string length $name]+1}] - foreach {field dat} [::practcl::read_Config.sh $filename] { - set field [string tolower $field] - if {[string match ${name}_* $field]} { - set field [string range $field $l end] - } - dict set result $field $dat - } - set conf_result $result - return $result - } - ### - # Oh man... we have to guess - ### - set filename [file join $builddir Makefile] - if {![file exists $filename]} { - error "Could not locate any configuration data in $srcdir" - } - foreach {field dat} [::practcl::read_Makefile $filename] { - dict set result $field $dat - } - set conf_result $result - cd $PWD - return $result - } -} - - -::oo::class create ::practcl::project { - superclass ::practcl::module ::practcl::autoconf - - constructor args { - my variable define - if {[llength $args] == 1} { - set rawcontents [lindex $args 0] - } else { - set rawcontents $args - } - if {[catch {uplevel 1 [list subst $rawcontents]} contents]} { - set contents $rawcontents - } - ### - # The first instance of ::practcl::project (or its descendents) - # registers itself as the ::practcl::MAIN. If a project other - # than ::practcl::LOCAL is created, odds are that was the one - # the developer intended to be the main project - ### - if {$::practcl::MAIN eq "::practcl::LOCAL"} { - set ::practcl::MAIN [self] - } - # DEFS fields need to be passed unchanged and unsubstituted - # as we need to preserve their escape characters - foreach field {TCL_DEFS DEFS TK_DEFS} { - if {[dict exists $rawcontents $field]} { - dict set contents $field [dict get $rawcontents $field] - } - } - array set define $contents - my select - my initialize - } - - method add_project {pkg info {oodefine {}}} { - set os [my define get TEACUP_OS] - if {$os eq {}} { - set os [::practcl::os] - my define set os $os - } - set fossilinfo [list download [my define get download] tag trunk sandbox [my define get sandbox]] - if {[dict exists $info os] && ($os ni [dict get $info os])} return - # Select which tag to use here. - # For production builds: tag-release - set profile [my define get profile release]: - if {[dict exists $info profile $profile]} { - dict set info tag [dict get $info profile $profile] - } - if {[my define get USEMSVC 0]} { - dict set info USEMSVC 1 - } - set obj [namespace current]::PROJECT.$pkg - if {[info command $obj] eq {}} { - set obj [::practcl::subproject create $obj [self] [dict merge $fossilinfo [list name $pkg pkg_name $pkg static 0 class subproject.binary] $info]] - } - my link object $obj - oo::objdefine $obj $oodefine - $obj define set masterpath $::CWD - $obj go - return $obj - } - - method add_tool {pkg info {oodefine {}}} { - set info [dict merge [::practcl::local_os] $info] - set os [dict get $info TEACUP_OS] - set fossilinfo [list download [my define get download] tag trunk sandbox [my define get sandbox]] - if {[dict exists $info os] && ($os ni [dict get $info os])} return - # Select which tag to use here. - # For production builds: tag-release - set profile [my define get profile release]: - if {[dict exists $info profile $profile]} { - dict set info tag [dict get $info profile $profile] - } - set obj [namespace current]::TOOL.$pkg - if {[info command $obj] eq {}} { - set obj [::practcl::tool create $obj [self] [dict merge $fossilinfo [list name $pkg pkg_name $pkg static 0] $info]] - } - my link object $obj - oo::objdefine $obj $oodefine - $obj define set masterpath $::CWD - $obj go - return $obj - } - - method child which { - switch $which { - organs { - # A library can be a project, it can be a module. Any - # subordinate modules will indicate their existance - return [list project [self] module [self]] - } - } - } - - method linktype {} { - return project - } - - # Exercise the methods of a sub-object - method project {pkg args} { - set obj [namespace current]::PROJECT.$pkg - if {[llength $args]==0} { - return $obj - } - ${obj} {*}$args - } - - method select {} { - next - ### - # Select the toolset to use for this project - ### - my variable define - set class {} - if {[info exists define(toolset)]} { - if {[info command $define(toolset)] ne {}} { - set class $define(toolset) - } elseif {[info command ::practcl::$define(toolset)] ne {}} { - set class ::practcl::$define(toolset) - } else { - switch $define(toolset) { - default { - set class ::practcl::build.gcc - } - } - } - } else { - if {[info exists ::env(VisualStudioVersion)]} { - set class ::practcl::build.msvc - } else { - set class ::practcl::build.gcc - } - } - ::oo::objdefine [self] mixin $class - } - - method tool {pkg args} { - set obj [namespace current]::TOOL.$pkg - if {[llength $args]==0} { - return $obj - } - ${obj} {*}$args - } -} - -::oo::class create ::practcl::library { - superclass ::practcl::project - - method compile-products {} { - set result {} - foreach item [my link list subordinate] { - lappend result {*}[$item compile-products] - } - set filename [my define get output_c] - if {$filename ne {}} { - set ofile [file rootname [file tail $filename]]_main.o - lappend result $ofile [list cfile $filename extra [my define get extra] external [string is true -strict [my define get external]]] - } - return $result - } - - method generate-tcl-loader {} { - set result {} - set PKGINIT [my define get pkginit] - set PKG_NAME [my define get name [my define get pkg_name]] - set PKG_VERSION [my define get pkg_vers [my define get version]] - if {[string is true [my define get SHARED_BUILD 0]]} { - set LIBFILE [my define get libfile] - ::practcl::cputs result [string map \ - [list @LIBFILE@ $LIBFILE @PKGINIT@ $PKGINIT @PKG_NAME@ $PKG_NAME @PKG_VERSION@ $PKG_VERSION] { -# Shared Library Style -load [file join [file dirname [file join [pwd] [info script]]] @LIBFILE@] @PKGINIT@ -package provide @PKG_NAME@ @PKG_VERSION@ -}] - } else { - ::practcl::cputs result [string map \ - [list @PKGINIT@ $PKGINIT @PKG_NAME@ $PKG_NAME @PKG_VERSION@ $PKG_VERSION] { -# Tclkit Style -load {} @PKGINIT@ -package provide @PKG_NAME@ @PKG_VERSION@ -}] - } - return $result - } - - method go {} { - ::practcl::debug [list [self] [self method] [self class] -- [my define get filename] [info object class [self]]] - set name [my define getnull name] - if {$name eq {}} { - set name generic - my define name generic - } - if {[my define get tk] eq {@TEA_TK_EXTENSION@}} { - my define set tk 0 - } - set output_c [my define getnull output_c] - if {$output_c eq {}} { - set output_c [file rootname $name].c - my define set output_c $output_c - } - set output_h [my define getnull output_h] - if {$output_h eq {}} { - set output_h [file rootname $output_c].h - my define set output_h $output_h - } - set output_tcl [my define getnull output_tcl] - #if {$output_tcl eq {}} { - # set output_tcl [file rootname $output_c].tcl - # my define set output_tcl $output_tcl - #} - #set output_mk [my define getnull output_mk] - #if {$output_mk eq {}} { - # set output_mk [file rootname $output_c].mk - # my define set output_mk $output_mk - #} - set initfunc [my define getnull initfunc] - if {$initfunc eq {}} { - set initfunc [string totitle $name]_Init - my define set initfunc $initfunc - } - set output_decls [my define getnull output_decls] - if {$output_decls eq {}} { - set output_decls [file rootname $output_c].decls - my define set output_decls $output_decls - } - my variable links - foreach {linktype objs} [array get links] { - foreach obj $objs { - $obj go - } - } - ::practcl::debug [list /[self] [self method] [self class] -- [my define get filename] [info object class [self]]] - } - - method implement path { - my go - my Collate_Source $path - foreach item [my link list dynamic] { - if {[catch {$item implement $path} err]} { - puts "Skipped $item: $err" - } - } - foreach item [my link list module] { - if {[catch {$item implement $path} err]} { - puts "Skipped $item: $err" - } - } - set cout [open [file join $path [my define get output_c]] w] - puts $cout [subst {/* -** This file is generated by the [info script] script -** any changes will be overwritten the next time it is run -*/}] - puts $cout [my generate-c] - puts $cout [my generate-loader] - close $cout - - set macro HAVE_[string toupper [file rootname [my define get output_h]]]_H - set hout [open [file join $path [my define get output_h]] w] - puts $hout [subst {/* -** This file is generated by the [info script] script -** any changes will be overwritten the next time it is run -*/}] - puts $hout "#ifndef ${macro}" - puts $hout "#define ${macro}" - puts $hout [my generate-h] - puts $hout "#endif" - close $hout - - set output_tcl [my define get output_tcl] - if {$output_tcl ne {}} { - set tclout [open [file join $path [my define get output_tcl]] w] - puts $tclout "### -# This file is generated by the [info script] script -# any changes will be overwritten the next time it is run -###" - puts $tclout [my generate-tcl-pre] - puts $tclout [my generate-tcl-loader] - puts $tclout [my generate-tcl-post] - close $tclout - } - } - - method generate-decls {pkgname path} { - ::practcl::debug [list [self] [self method] [self class] -- [my define get filename] [info object class [self]]] - set outfile [file join $path/$pkgname.decls] - - ### - # Build the decls file - ### - set fout [open $outfile w] - puts $fout [subst {### - # $outfile - # - # This file was generated by [info script] - ### - - library $pkgname - interface $pkgname - }] - - ### - # Generate list of functions - ### - set stubfuncts [my generate-stub-function] - set thisline {} - set functcount 0 - foreach {func header} $stubfuncts { - puts $fout [list declare [incr functcount] $header] - } - puts $fout [list export "int [my define get initfunc](Tcl_Inter *interp)"] - puts $fout [list export "char *[string totitle [my define get name]]_InitStubs(Tcl_Inter *interp, char *version, int exact)"] - - close $fout - - ### - # Build [package]Decls.h - ### - set hout [open [file join $path ${pkgname}Decls.h] w] - - close $hout - - set cout [open [file join $path ${pkgname}StubInit.c] w] -puts $cout [string map [list %pkgname% $pkgname %PkgName% [string totitle $pkgname]] { -#ifndef USE_TCL_STUBS -#define USE_TCL_STUBS -#endif -#undef USE_TCL_STUB_PROCS - -#include "tcl.h" -#include "%pkgname%.h" - - /* - ** Ensure that Tdom_InitStubs is built as an exported symbol. The other stub - ** functions should be built as non-exported symbols. - */ - -#undef TCL_STORAGE_CLASS -#define TCL_STORAGE_CLASS DLLEXPORT - -%PkgName%Stubs *%pkgname%StubsPtr; - - /* - **---------------------------------------------------------------------- - ** - ** %PkgName%_InitStubs -- - ** - ** Checks that the correct version of %PkgName% is loaded and that it - ** supports stubs. It then initialises the stub table pointers. - ** - ** Results: - ** The actual version of %PkgName% that satisfies the request, or - ** NULL to indicate that an error occurred. - ** - ** Side effects: - ** Sets the stub table pointers. - ** - **---------------------------------------------------------------------- - */ - -char * -%PkgName%_InitStubs (Tcl_Interp *interp, char *version, int exact) -{ - char *actualVersion; - actualVersion = Tcl_PkgRequireEx(interp, "%pkgname%", version, exact,(ClientData *) &%pkgname%StubsPtr); - if (!actualVersion) { - return NULL; - } - if (!%pkgname%StubsPtr) { - Tcl_SetResult(interp,"This implementation of %PkgName% does not support stubs",TCL_STATIC); - return NULL; - } - return actualVersion; -} -}] - close $cout - } - - # Backward compadible call - method generate-make path { - my build-Makefile $path [self] - } - - method install-headers {} { - set result {} - return $result - } - - method linktype {} { - return library - } - - # Create a "package ifneeded" - # Args are a list of aliases for which this package will answer to - method package-ifneeded {args} { - set result {} - set name [my define get pkg_name [my define get name]] - set version [my define get pkg_vers [my define get version]] - if {$version eq {}} { - set version 0.1a - } - set output_tcl [my define get output_tcl] - if {$output_tcl ne {}} { - set script "\[list source \[file join \$dir $output_tcl\]\]" - } elseif {[string is true -strict [my define get SHARED_BUILD]]} { - set script "\[list load \[file join \$dir [my define get libfile]\] $name\]" - } else { - # Provide a null passthrough - set script "\[list package provide $name $version\]" - } - set result "package ifneeded [list $name] [list $version] $script" - foreach alias $args { - set script "package require $name $version \; package provide $alias $version" - append result \n\n [list package ifneeded $alias $version $script] - } - return $result - } - - - method shared_library {} { - set name [string tolower [my define get name [my define get pkg_name]]] - set NAME [string toupper $name] - set version [my define get version [my define get pkg_vers]] - set map {} - lappend map %LIBRARY_NAME% $name - lappend map %LIBRARY_VERSION% $version - lappend map %LIBRARY_VERSION_NODOTS% [string map {. {}} $version] - lappend map %LIBRARY_PREFIX% [my define getnull libprefix] - set outfile [string map $map [my define get PRACTCL_NAME_LIBRARY]][my define get SHLIB_SUFFIX] - return $outfile - } -} - -::oo::class create ::practcl::tclkit { - superclass ::practcl::library - - method Collate_Source CWD { - set name [my define get name] - # Assume a static shell - if {[my define exists SHARED_BUILD]} { - my define exists SHARED_BUILD 0 - } - if {![my define exists TCL_LOCAL_APPINIT]} { - my define set TCL_LOCAL_APPINIT Tclkit_AppInit - } - if {![my define exists TCL_LOCAL_MAIN_HOOK]} { - my define set TCL_LOCAL_MAIN_HOOK Tclkit_MainHook - } - set PROJECT [self] - set os [$PROJECT define get TEACUP_OS] - if {[my define get SHARED_BUILD]} { - puts [list BUILDING TCLSH FOR OS $os] - } else { - puts [list BUILDING KIT FOR OS $os] - } - set TCLOBJ [$PROJECT project TCLCORE] - set TCLSRCDIR [$TCLOBJ define get srcdir] - set PKG_OBJS {} - foreach item [$PROJECT link list core.library] { - if {[string is true [$item define get static]]} { - lappend PKG_OBJS $item - } - } - foreach item [$PROJECT link list package] { - if {[string is true [$item define get static]]} { - lappend PKG_OBJS $item - } - } - # Arrange to build an main.c that utilizes TCL_LOCAL_APPINIT and TCL_LOCAL_MAIN_HOOK - if {$os eq "windows"} { - set PLATFORM_SRC_DIR win - if {[my define get SHARED_BUILD]} { - my add class csource filename [file join $TCLSRCDIR win tclWinReg.c] initfunc Registry_Init pkg_name registry pkg_vers 1.3.1 autoload 1 - my add class csource filename [file join $TCLSRCDIR win tclWinDde.c] initfunc Dde_Init pkg_name dde pkg_vers 1.4.0 autoload 1 - } - my add class csource ofile [my define get name]_appinit.o filename [file join $TCLSRCDIR win tclAppInit.c] extra [list -DTCL_LOCAL_MAIN_HOOK=[my define get TCL_LOCAL_MAIN_HOOK Tclkit_MainHook] -DTCL_LOCAL_APPINIT=[my define get TCL_LOCAL_APPINIT Tclkit_AppInit]] - } else { - set PLATFORM_SRC_DIR unix - my add class csource ofile [my define get name]_appinit.o filename [file join $TCLSRCDIR unix tclAppInit.c] extra [list -DTCL_LOCAL_MAIN_HOOK=[my define get TCL_LOCAL_MAIN_HOOK Tclkit_MainHook] -DTCL_LOCAL_APPINIT=[my define get TCL_LOCAL_APPINIT Tclkit_AppInit]] - } - - if {[my define get SHARED_BUILD]} { - ### - # Add local static Zlib implementation - ### - set cdir [file join $TCLSRCDIR compat zlib] - foreach file { - adler32.c compress.c crc32.c - deflate.c infback.c inffast.c - inflate.c inftrees.c trees.c - uncompr.c zutil.c - } { - my add [file join $cdir $file] - } - } - ### - # Pre 8.7, Tcl doesn't include a Zipfs implementation - # in the core. Grab the one from odielib - ### - set zipfs [file join $TCLSRCDIR generic tclZipfs.c] - if {![$PROJECT define exists ZIPFS_VOLUME]} { - $PROJECT define set ZIPFS_VOLUME "//zipfs:/" - } - $PROJECT code header "#define ZIPFS_VOLUME \"[$PROJECT define get ZIPFS_VOLUME]\"" - if {[file exists $zipfs]} { - $TCLOBJ define set tip_430 1 - my define set tip_430 1 - } else { - # The Tclconfig project maintains a mirror of the version - # released with the Tcl core - my define set tip_430 0 - ::practcl::LOCAL tool odie load - set COMPATSRCROOT [::practcl::LOCAL tool odie define get srcdir] - set cdir [file join $COMPATSRCROOT compat zipfs] - my define add include_dir $cdir - set zipfs [file join $cdir tclZipfs.c] - my add class csource filename $zipfs initfunc Tclzipfs_Init pkg_name zipfs pkg_vers 1.1 autoload 1 extra "-DZIPFS_VOLUME=\"[$PROJECT define get ZIPFS_VOLUME]\"" - } - - my define add include_dir [file join $TCLSRCDIR generic] - my define add include_dir [file join $TCLSRCDIR $PLATFORM_SRC_DIR] - # This file will implement TCL_LOCAL_APPINIT and TCL_LOCAL_MAIN_HOOK - my build-tclkit_main $PROJECT $PKG_OBJS - } - - ## Wrap an executable - # - method wrap {PWD exename vfspath args} { - cd $PWD - if {![file exists $vfspath]} { - file mkdir $vfspath - } - foreach item [my link list core.library] { - set name [$item define get name] - set libsrcdir [$item define get srcdir] - if {[file exists [file join $libsrcdir library]]} { - ::practcl::copyDir [file join $libsrcdir library] [file join $vfspath boot $name] - } - } - # Assume the user will populate the VFS path - #if {[my define get installdir] ne {}} { - # ::practcl::copyDir [file join [my define get installdir] [string trimleft [my define get prefix] /] lib] [file join $vfspath lib] - #} - foreach arg $args { - ::practcl::copyDir $arg $vfspath - } - - set fout [open [file join $vfspath packages.tcl] w] - puts $fout { - set ::PKGIDXFILE [info script] - set dir [file dirname $::PKGIDXFILE] - } - #set BASEVFS [my define get BASEVFS] - set EXEEXT [my define get EXEEXT] - - set tclkit_bare [my define get tclkit_bare] - - set buffer [::practcl::pkgindex_path $vfspath] - puts $fout $buffer - puts $fout { - # Advertise statically linked packages - foreach {pkg script} [array get ::kitpkg] { - eval $script - } - } - close $fout - ::practcl::mkzip ${exename}${EXEEXT} $tclkit_bare $vfspath - if { [my define get TEACUP_OS] ne "windows" } { - file attributes ${exename}${EXEEXT} -permissions a+x - } - } -} - -### -# Standalone class to manage code distribution -# This class is intended to be mixed into another class -# (Thus the lack of ancestors) -### -oo::class create ::practcl::distribution { - - method DistroMixIn {} { - my define set scm none - } - - method Sandbox {} { - if {[my define exists sandbox]} { - return [my define get sandbox] - } - if {[my organ project] ni {::noop {}}} { - set sandbox [my <project> define get sandbox] - if {$sandbox ne {}} { - my define set sandbox $sandbox - return $sandbox - } - } - set sandbox [file normalize [file join $::CWD .. $pkg]] - my define set sandbox $sandbox - return $sandbox - } - - method SrcDir {} { - set pkg [my define get name] - if {[my define exists srcdir]} { - return [my define get srcdir] - } - set sandbox [my Sandbox] - set srcdir [file join [my Sandbox] $pkg] - my define set srcdir $srcdir - return $srcdir - } - - method ScmSelect {} { - if {[my define exists scm]} { - return [my define get scm] - } - set srcdir [my SrcDir] - set classprefix ::practcl::distribution. - if {[file exists $srcdir]} { - foreach class [::info commands ${classprefix}*] { - if {[$class claim_path $srcdir]} { - oo::objdefine [self] mixin $class - my define set scm [string range $class [string length ::practcl::distribution.] end] - } - } - } - foreach class [::info commands ${classprefix}*] { - if {[$class claim_object [self]]} { - oo::objdefine [self] mixin $class - my define set scm [string range $class [string length ::practcl::distribution.] end] - } - } - if {[my define get scm] eq {} && [my define exists file_url]} { - set class - } - - if {[my define get scm] eq {}} { - error "No SCM selected" - } - return [my define get scm] - } - - method ScmTag {} {} - method ScmClone {} {} - method ScmUnpack {} {} - method ScmUpdate {} {} - - method unpack {} { - my ScmSelect - set srcdir [my SrcDir] - if {[file exists $srcdir]} { - return - } - set pkg [my define get name] - if {[my define exists download]} { - # Utilize a staged download - set download [my define get download] - if {[file exists [file join $download $pkg.zip]]} { - ::practcl::tcllib_require zipfile::decode - ::zipfile::decode::unzipfile [file join $download $pkg.zip] $srcdir - return - } - } - my ScmUnpack - } - - method update {} { - my ScmSelect - my ScmUpdate - } -} - -oo::objdefine ::practcl::distribution { - method claim_path path { - return false - } - method claim_object object { - return false - } -} - -oo::class create ::practcl::distribution.snapshot { - superclass ::practcl::distribution - method ScmUnpack {} { - set srcdir [my SrcDir] - if {[file exists [file join $srcdir .download]]} { - return 0 - } - set dpath [::practcl::LOCAL define get download] - set url [my define get file_url] - set fname [file tail $url] - set archive [file join $dpath $fname] - if {![file exists $archive]} { - ::http::wget $url $archive - } - set CWD [pwd] - switch [file extension $fname] { - .zip { - # Zipfile - - } - .tar { - ::practcl::tcllib_require tar - } - .tgz - - .gz { - # Tarball - ::practcl::tcllib_require tcl::transform::zlib - ::practcl::tcllib_require tar - set fh [::open $archive] - fconfigure $fh -encoding binary -translation lf -eofchar {} - ::tcl::transform::zlib $fh - } - } - set fosdb [my ScmClone] - set tag [my ScmTag] - file mkdir $srcdir - ::practcl::fossil $srcdir open $fosdb $tag - return 1 - } -} - -oo::objdefine ::practcl::distribution.snapshot { - method claim_path path { - if {[file exists [file join $path .download]]} { - return true - } - return false - } - method claim_object object { - return false - } -} - - -oo::class create ::practcl::distribution.fossil { - superclass ::practcl::distribution - - # Clone the source - method ScmClone {} { - set srcdir [my SrcDir] - if {[file exists [file join $srcdir .fslckout]]} { - return - } - if {[file exists [file join $srcdir _FOSSIL_]]} { - return - } - if {![::info exists ::practcl::fossil_dbs]} { - # Get a list of local fossil databases - set ::practcl::fossil_dbs [exec fossil all list] - } - set pkg [my define get name] - # Return an already downloaded fossil repo - foreach line [split $::practcl::fossil_dbs \n] { - set line [string trim $line] - if {[file rootname [file tail $line]] eq $pkg} { - return $line - } - } - set download [::practcl::LOCAL define get download] - set fosdb [file join $download $pkg.fos] - if {[file exists $fosdb]} { - return $fosdb - } - - file mkdir [file join $download fossil] - set fosdb [file join $download fossil $pkg.fos] - if {[file exists $fosdb]} { - return $fosdb - } - - set cloned 0 - # Attempt to clone from a local network mirror - if {[::practcl::LOCAL define exists fossil_mirror]} { - set localmirror [::practcl::LOCAL define get fossil_mirror] - catch { - ::practcl::doexec fossil clone $localmirror/$pkg $fosdb - set cloned 1 - } - if {$cloned} { - return $fosdb - } - } - # Attempt to clone from the canonical source - if {[my define get fossil_url] ne {}} { - catch { - ::practcl::doexec fossil clone [my define get fossil_url] $fosdb - set cloned 1 - } - if {$cloned} { - return $fosdb - } - } - # Fall back to the fossil mirror on the island of misfit toys - ::practcl::doexec fossil clone http://fossil.etoyoc.com/fossil/$pkg $fosdb - return $fosdb - } - - method ScmTag {} { - if {[my define exists scm_tag]} { - return [my define get scm_tag] - } - if {[my define exists tag]} { - set tag [my define get tag] - } else { - set tag trunk - } - my define set scm_tag $tag - return $tag - } - - method ScmUnpack {} { - set srcdir [my SrcDir] - if {[file exists [file join $srcdir .fslckout]]} { - return 0 - } - if {[file exists [file join $srcdir _FOSSIL_]]} { - return 0 - } - set CWD [pwd] - set fosdb [my ScmClone] - set tag [my ScmTag] - file mkdir $srcdir - ::practcl::fossil $srcdir open $fosdb $tag - return 1 - } - - method ScmUpdate {} { - if {[my ScmUnpack]} { - return - } - set srcdir [my SrcDir] - set tag [my ScmTag] - ::practcl::fossil $srcdir update $tag - } -} - -oo::objdefine ::practcl::distribution.fossil { - - # Check for markers in the source root - method claim_path path { - if {[file exists [file join $path .fslckout]]} { - return true - } - if {[file exists [file join $path _FOSSIL_]]} { - return true - } - return false - } - - # Check for markers in the metadata - method claim_object obj { - set path [$obj define get srcdir] - if {[my claim_path $path]} { - return true - } - if {[$obj define get fossil_url] ne {}} { - return true - } - return false - } -} - -oo::class create ::practcl::distribution.git { - - method ScmTag {} { - if {[my define exists scm_tag]} { - return [my define get scm_tag] - } - if {[my define exists tag]} { - set tag [my define get tag] - } else { - set tag master - } - my define set scm_tag $tag - return $tag - } - - method ScmUnpack {} { - set srcdir [my SrcDir] - if {[file exists [file join $srcdir .git]]} { - return 0 - } - set CWD [pwd] - set tag [my ScmTag] - set pkg [my define get name] - if {[my define exists git_url]} { - ::practcl::doexec git clone --branch $tag [my define get git_url] $srcdir - } else { - ::practcl::doexec git clone --branch $tag https://github.com/eviltwinskippy/$pkg $srcdir - } - return 1 - } - - method ScmUpdate {} { - if {[my ScmUnpack]} { - return - } - set srcdir [my SrcDir] - set tag [my ScmTag] - ::practcl::doexec_in $srcdir git pull $tag - cd $CWD - } - -} -oo::objdefine ::practcl::distribution.git { - method claim_path path { - if {[file exists [file join $path .git]]} { - return true - } - return false - } - method claim_object obj { - set path [$obj define get srcdir] - if {[my claim_path $path]} { - return true - } - if {[$obj define get git_url] ne {}} { - return true - } - return false - } -} - -### -# Meta repository -# The default is an inert source code block -### -oo::class create ::practcl::subproject { - superclass ::practcl::object ::practcl::distribution - - method compile {} {} - - method critcl args { - if {![info exists critcl]} { - ::pratcl::LOCAL tool critcl load - set critcl [file join [::pratcl::LOCAL tool critcl define get srcdir] main.tcl - } - set srcdir [my SourceRoot] - set PWD [pwd] - cd $srcdir - ::pratcl::dotclexec $critcl {*}$args - cd $PWD - } - - method go {} { - set name [my define get name] - set srcdir [my SrcDir] - my define set localsrcdir $srcdir - my define add include_dir [file join $srcdir generic] - my sources - } - - # Install project into the local build system - method install args {} - - method linktype {} { - return {subordinate package} - } - - method linker-products {configdict} {} - - method linker-external {configdict} { - if {[dict exists $configdict PRACTCL_PKG_LIBS]} { - return [dict get $configdict PRACTCL_PKG_LIBS] - } - } - - method sources {} {} -} - -### -# A project which the kit compiles and integrates -# the source for itself -### -oo::class create ::practcl::subproject.source { - superclass ::practcl::subproject ::practcl::library - - method linktype {} { - return {subordinate package source} - } - -} - -# a copy from the teapot -oo::class create ::practcl::subproject.teapot { - superclass ::practcl::subproject - - method install-local {} { - my install-vfs - } - - method install DEST { - set pkg [my define get pkg_name [my define get name]] - set download [my <project> define get download] - my unpack - set prefix [string trimleft [my <project> define get prefix] /] - ::practcl::tcllib_require zipfile::decode - ::zipfile::decode::unzipfile [file join $download $pkg.zip] [file join $DEST $prefix lib $pkg] - } -} - -oo::class create ::practcl::subproject.kettle { - superclass ::practcl::subproject - - method install-local {} { - my install-vfs - } - - method kettle {path args} { - my variable kettle - if {![info exists kettle]} { - ::pratcl::LOCAL tool kettle load - set kettle [file join [::pratcl::LOCAL tool kettle define get srcdir] kettle] - } - set srcdir [my SourceRoot] - ::pratcl::dotclexec $kettle -f [file join $srcdir build.tcl] {*}$args - } - - method install DEST { - my kettle reinstall --prefix $DEST - } -} - -oo::class create ::practcl::subproject.critcl { - superclass ::practcl::subproject - - method install-local {} { - my install-vfs - } - - method install DEST { - my critcl -pkg [my define get name] - set srcdir [my SourceRoot] - ::pratcl::copyDir [file join $srcdir [my define get name]] [file join $DEST lib [my define get name]] - } -} - - -oo::class create ::practcl::subproject.sak { - superclass ::practcl::subproject - - method install-local {} { - my install-vfs - } - - method install DEST { - ### - # Handle teapot installs - ### - set pkg [my define get pkg_name [my define get name]] - my unpack - set prefix [string trimleft [my <project> define get prefix] /] - set srcdir [my define get srcdir] - ::practcl::dotclexec [file join $srcdir installer.tcl] \ - -pkg-path [file join $DEST $prefix lib $pkg] \ - -no-examples -no-html -no-nroff \ - -no-wait -no-gui -no-apps - } -} - -### -# A binary package -### -oo::class create ::practcl::subproject.binary { - superclass ::practcl::subproject ::practcl::autoconf - - method compile-products {} {} - - method ConfigureOpts {} { - set opts {} - set builddir [my define get builddir] - if {[my define get broken_destroot 0]} { - set PREFIX [my <project> define get prefix_broken_destdir] - } else { - set PREFIX [my <project> define get prefix] - } - if {[my <project> define get CONFIG_SITE] != {}} { - lappend opts --host=[my <project> define get HOST] - lappend opts --with-tclsh=[info nameofexecutable] - } - if {[my <project> define exists tclsrcdir]} { - ### - # On Windows we are probably running under MSYS, which doesn't deal with - # spaces in filename well - ### - set TCLSRCDIR [::practcl::file_relative [file normalize $builddir] [file normalize [file join $::CWD [my <project> define get tclsrcdir]]]] - set TCLGENERIC [::practcl::file_relative [file normalize $builddir] [file normalize [file join $::CWD [my <project> define get tclsrcdir] .. generic]]] - lappend opts --with-tcl=$TCLSRCDIR --with-tclinclude=$TCLGENERIC - } - if {[my <project> define exists tksrcdir]} { - set TKSRCDIR [::practcl::file_relative [file normalize $builddir] [file normalize [file join $::CWD [my <project> define get tksrcdir]]]] - set TKGENERIC [::practcl::file_relative [file normalize $builddir] [file normalize [file join $::CWD [my <project> define get tksrcdir] .. generic]]] - lappend opts --with-tk=$TKSRCDIR --with-tkinclude=$TKGENERIC - } - lappend opts {*}[my define get config_opts] - if {![regexp -- "--prefix" $opts]} { - lappend opts --prefix=$PREFIX - } - #--exec_prefix=$PREFIX - #if {$::tcl_platform(platform) eq "windows"} { - # lappend opts --disable-64bit - #} - if {[my define get static 1]} { - lappend opts --disable-shared --disable-stubs - # - } else { - lappend opts --enable-shared - } - return $opts - } - - method ComputeInstall {} { - if {[my define exists install]} { - switch [my define get install] { - static { - my define set static 1 - my define set autoload 0 - } - static-autoload { - my define set static 1 - my define set autoload 1 - } - vfs { - my define set static 0 - my define set autoload 0 - my define set vfsinstall 1 - } - null { - my define set static 0 - my define set autoload 0 - my define set vfsinstall 0 - } - default { - - } - } - } - } - - method go {} { - next - my ComputeInstall - my define set builddir [my BuildDir [my define get masterpath]] - } - - method linker-products {configdict} { - if {![my define get static 0]} { - return {} - } - set srcdir [my define get builddir] - if {[dict exists $configdict libfile]} { - return " [file join $srcdir [dict get $configdict libfile]]" - } - } - - method static-packages {} { - if {![my define get static 0]} { - return {} - } - set result [my define get static_packages] - set statpkg [my define get static_pkg] - set initfunc [my define get initfunc] - if {$initfunc ne {}} { - set pkg_name [my define get pkg_name] - if {$pkg_name ne {}} { - dict set result $pkg_name initfunc $initfunc - set version [my define get version] - if {$version eq {}} { - set info [my config.sh] - set version [dict get $info version] - set pl {} - if {[dict exists $info patch_level]} { - set pl [dict get $info patch_level] - append version $pl - } - my define set version $version - } - dict set result $pkg_name version $version - dict set result $pkg_name autoload [my define get autoload 0] - } - } - foreach item [my link list subordinate] { - foreach {pkg info} [$item static-packages] { - dict set result $pkg $info - } - } - return $result - } - - method BuildDir {PWD} { - set name [my define get name] - return [my define get builddir [file join $PWD pkg.$name]] - } - - method compile {} { - set name [my define get name] - set PWD $::CWD - cd $PWD - my unpack - set srcdir [file normalize [my SrcDir]] - my Collate_Source $PWD - - ### - # Build a starter VFS for both Tcl and wish - ### - set srcdir [my define get srcdir] - if {[my define get static 1]} { - puts "BUILDING Static $name $srcdir" - } else { - puts "BUILDING Dynamic $name $srcdir" - } - if {[my define get USEMSVC 0]} { - cd $srcdir - ::practcl::doexec nmake -f makefile.vc INSTALLDIR=[my <project> define get installdir] release - } else { - cd $::CWD - set builddir [file normalize [my define get builddir]] - file mkdir $builddir - if {![file exists [file join $builddir Makefile]]} { - my Configure - } - if {[file exists [file join $builddir make.tcl]]} { - ::practcl::domake.tcl $builddir library - } else { - ::practcl::domake $builddir all - } - } - cd $PWD - } - - method Configure {} { - cd $::CWD - my unpack - set srcdir [file normalize [my define get srcdir]] - set builddir [file normalize [my define get builddir]] - file mkdir $builddir - if {[my define get USEMSVC 0]} { - return - } - if {[file exists [file join $builddir practcl.log]]} { - file delete [file join $builddir practcl.log] - } - if {![file exists [file join $srcdir configure]]} { - if {[file exists [file join $srcdir autogen.sh]]} { - cd $srcdir - catch {exec sh autogen.sh >>& [file join $builddir practcl.log]} - cd $::CWD - } - } - if {![file exists [file join $srcdir tclconfig install-sh]]} { - # ensure we have tclconfig with all of the trimmings - set teapath {} - if {[file exists [file join $srcdir .. tclconfig install-sh]]} { - set teapath [file join $srcdir .. tclconfig] - } else { - set tclConfigObj [::practcl::LOCAL tool tclconfig] - $tclConfigObj load - set teapath [$tclConfigObj define get srcdir] - } - set teapath [file normalize $teapath] - #file mkdir [file join $srcdir tclconfig] - if {[catch {file link -symbolic [file join $srcdir tclconfig] $teapath}]} { - ::practcl::copyDir [file join $teapath] [file join $srcdir tclconfig] - } - } - - set opts [my ConfigureOpts] - puts [list PKG [my define get name] CONFIGURE {*}$opts] - cd $builddir - if {[my <project> define get CONFIG_SITE] ne {}} { - set ::env(CONFIG_SITE) [my <project> define get CONFIG_SITE] - } - catch {exec sh [file join $srcdir configure] {*}$opts >>& [file join $builddir practcl.log]} - cd $::CWD - } - - method install DEST { - set PWD [pwd] - set PREFIX [my <project> define get prefix] - ### - # Handle teapot installs - ### - set pkg [my define get pkg_name [my define get name]] - if {[my <project> define get teapot] ne {}} { - set TEAPOT [my <project> define get teapot] - set found 0 - foreach ver [my define get pkg_vers [my define get version]] { - set teapath [file join $TEAPOT $pkg$ver] - if {[file exists $teapath]} { - set dest [file join $DEST [string trimleft $PREFIX /] lib [file tail $teapath]] - ::practcl::copyDir $teapath $dest - return - } - } - } - my compile - if {[my define get USEMSVC 0]} { - set srcdir [my define get srcdir] - cd $srcdir - puts "[self] VFS INSTALL $DEST" - ::practcl::doexec nmake -f makefile.vc INSTALLDIR=$DEST install - } else { - set builddir [my define get builddir] - if {[file exists [file join $builddir make.tcl]]} { - # Practcl builds can inject right to where we need them - puts "[self] VFS INSTALL $DEST (Practcl)" - ::practcl::domake.tcl $builddir install-package $DEST - } elseif {[my define get broken_destroot 0] == 0} { - # Most modern TEA projects understand DESTROOT in the makefile - puts "[self] VFS INSTALL $DEST (TEA)" - ::practcl::domake $builddir install DESTDIR=$DEST - } else { - # But some require us to do an install into a fictitious filesystem - # and then extract the gooey parts within. - # (*cough*) TkImg - set PREFIX [my <project> define get prefix] - set BROKENROOT [::practcl::msys_to_tclpath [my <project> define get prefix_broken_destdir]] - file delete -force $BROKENROOT - file mkdir $BROKENROOT - ::practcl::domake $builddir $install - ::practcl::copyDir $BROKENROOT [file join $DEST [string trimleft $PREFIX /]] - file delete -force $BROKENROOT - } - } - cd $PWD - } - - method Autoconf {} { - ### - # Re-run autoconf for this project - # Not a good idea in practice... but in the right hands it can be useful - ### - set pwd [pwd] - set srcdir [file normalize [my define get srcdir]] - cd $srcdir - foreach template {configure.ac configure.in} { - set input [file join $srcdir $template] - if {[file exists $input]} { - puts "autoconf -f $input > [file join $srcdir configure]" - exec autoconf -f $input > [file join $srcdir configure] - } - } - cd $pwd - } -} - -# An external library -oo::class create ::practcl::subproject.external { - superclass ::practcl::subproject.binary - method install DEST { - my compile - } -} - -oo::class create ::practcl::subproject.core { - superclass ::practcl::subproject.binary - - # On the windows platform MinGW must build - # from the platform directory in the source repo - method BuildDir {PWD} { - return [my define get localsrcdir] - } - - method Configure {} { - if {[my define get USEMSVC 0]} { - return - } - set opts [my ConfigureOpts] - set builddir [file normalize [my define get builddir]] - set localsrcdir [file normalize [my define get localsrcdir]] - puts [list PKG [my define get name] CONFIGURE {*}$opts] - cd $localsrcdir - if {[my <project> define get CONFIG_SITE] ne {}} { - set ::env(CONFIG_SITE) [my <project> define get CONFIG_SITE] - } - catch {exec sh [file join $localsrcdir configure] {*}$opts >& [file join $builddir practcl.log]} - } - - method ConfigureOpts {} { - set opts {} - set builddir [file normalize [my define get builddir]] - set PREFIX [my <project> define get prefix] - if {[my <project> define get CONFIG_SITE] != {}} { - lappend opts --host=[my <project> define get HOST] - lappend opts --with-tclsh=[info nameofexecutable] - } - lappend opts {*}[my define get config_opts] - if {![regexp -- "--prefix" $opts]} { - lappend opts --prefix=$PREFIX - } - #--exec_prefix=$PREFIX - lappend opts --disable-shared - return $opts - } - - method go {} { - set name [my define get name] - set os [my <project> define get TEACUP_OS] - my ComputeInstall - set srcdir [my SrcDir] - my define add include_dir [file join $srcdir generic] - switch $os { - windows { - my define set localsrcdir [file join $srcdir win] - my define add include_dir [file join $srcdir win] - } - default { - my define set localsrcdir [file join $srcdir unix] - my define add include_dir [file join $srcdir $name unix] - } - } - my define set builddir [my BuildDir [my define get masterpath]] - } - - method linktype {} { - return {subordinate core.library} - } -} - - -### -# Classes to manage tools that needed in the local environment -# to compile and/or installed other packages -### -oo::class create ::practcl::tool { - superclass ::practcl::object ::practcl::distribution - - method critcl args { - if {![info exists critcl]} { - ::pratcl::LOCAL tool critcl load - set critcl [file join [::pratcl::LOCAL tool critcl define get srcdir] main.tcl - } - set srcdir [my SourceRoot] - set PWD [pwd] - cd $srcdir - ::pratcl::dotclexec $critcl {*}$args - cd $PWD - } - - method SourceRoot {} { - set info [my define dump] - set result $info - if {![my define exists srcdir]} { - if {[dict exists $info srcdir]} { - set srcdir [dict get $info srcdir] - } elseif {[dict exists $info sandbox]} { - set srcdir [file join [dict get $info sandbox] $pkg] - } else { - set srcdir [file join $::CWD .. $pkg] - } - dict set result srcdir $srcdir - my define set srcdir $srcdir - } - return [my define get srcdir] - } - - method linktype {} { - return tool - } - - # Return boolean if present - method present {} { - return 1 - } - - # Procedure to install in the local environment - method install {} { - my unpack - } - - # Procedure to load into the local interpreter - method load {} { - my variable loaded - if {[info exists loaded]} { - return 0 - } - if {![my present]} { - my install - } - my LocalLoad - set loaded 1 - } - - method LocalLoad {} {} -} - -oo::class create ::practcl::tool.source { - superclass ::practcl::tool - - method present {} { - return [file exists [my define get srcdir]] - } - - method toplevel_script {} { - my load - return [file join [my SourceRoot] [my define get toplevel_script]] - } - - method LocalLoad {} { - set LibraryRoot [file join [my define get srcdir] [my define get module_root modules]] - if {[file exists $LibraryRoot] && $LibraryRoot ni $::auto_path} { - set ::auto_path [linsert $::auto_path 0 $LibraryRoot] - } - } -} - -### -# Create an object to represent the local environment -### -set ::practcl::MAIN ::practcl::LOCAL -# Defer the creation of the ::pratcl::LOCAL object until it is called -# in order to allow packages to -set ::auto_index(::practcl::LOCAL) { - puts "Building LOCAL" - ::practcl::project create ::practcl::LOCAL - ::practcl::LOCAL define set [::practcl::local_os] - # Until something better comes along, use ::practcl::LOCAL - # as our main project - # Add tclconfig as a project of record - ::practcl::LOCAL add_tool tclconfig { - tag trunk class tool.source fossil_url http://core.tcl.tk/tclconfig - } - # Add tcllib as a project of record - ::practcl::LOCAL add_tool tcllib { - tag trunk class tool.source fossil_url http://core.tcl.tk/tcllib - } - ::practcl::LOCAL add_tool kettle { - tag trunk class tool.source fossil_url http://fossil.etoyoc.com/fossil/kettle - } - ::practcl::LOCAL add_tool critcl { - tag trunk class tool.source - git_url http://github.com/andreas-kupries/critcl - } - ::practcl::LOCAL add_tool odie { - tag trunk class tool.source - fossil_url http://fossil.etoyoc.com/fossil/odie - } -} -package provide practcl 0.8a1 |