2 # Copyright (c) 2006-2011 WorkWare Systems http://www.workware.net.au/
6 dir
=`dirname "$0"`; exec "`$dir/find-tclsh`" "$0" "$@"
8 set autosetup
(version
) 0.6.5
10 # Can be set to 1 to debug early-init problems
11 set autosetup
(debug
) 0
13 ##################################################################
15 # Main flow of control, option handling
18 global autosetup define
20 # There are 3 potential directories involved:
21 # 1. The directory containing autosetup (this script)
22 # 2. The directory containing auto.def
23 # 3. The current directory
25 # From this we need to determine:
26 # a. The path to this script (and related support files)
27 # b. The path to auto.def
28 # c. The build directory, where output files are created
30 # This is also complicated by the fact that autosetup may
31 # have been run via the configure wrapper ([getenv WRAPPER] is set)
34 # a. This script is $::argv0
35 # => dir, prog, exe, libdir
36 # b. auto.def is in the directory containing the configure wrapper,
37 # otherwise it is in the current directory.
39 # c. The build directory is the current directory
42 # 'misc' is needed before we can do anything, so set a temporary libdir
43 # in case this is the development version
44 set autosetup
(libdir
) [file dirname $
::argv0
]/lib
48 set autosetup
(dir
) [realdir
[file dirname [realpath $
::argv0
]]]
49 set autosetup
(prog
) [file join $autosetup(dir
) [file tail $
::argv0
]]
50 set autosetup
(exe
) [getenv WRAPPER
$autosetup(prog
)]
51 if {$autosetup(installed
)} {
52 set autosetup
(libdir
) $autosetup(dir
)
54 set autosetup
(libdir
) [file join $autosetup(dir
) lib
]
56 autosetup_add_dep
$autosetup(prog
)
59 if {[getenv WRAPPER
""] eq
""} {
61 set autosetup
(srcdir
) [pwd]
63 # Invoked via the configure wrapper
64 set autosetup
(srcdir
) [file dirname $autosetup(exe
)]
66 set autosetup
(autodef
) [relative-path
$autosetup(srcdir
)/auto.def
]
69 set autosetup
(builddir
) [pwd]
71 set autosetup
(argv
) $argv
72 set autosetup
(cmdline
) {}
73 set autosetup
(options
) {}
74 set autosetup
(optionhelp
) {}
75 set autosetup
(showhelp
) 0
80 array
set ::useropts
[getopt argv
]
84 help:=local => "display help and options. Optionally specify a module name, such as --help=system"
85 version
=> "display the version of autosetup"
86 ref
:=text manual
:=text
87 reference
:=text
=> "display the autosetup command reference. 'text', 'wiki', 'asciidoc' or 'markdown'"
88 debug
=> "display debugging output as autosetup runs"
89 install:=.
=> "install autosetup to the current or given directory (in the 'autosetup/' subdirectory)"
90 force init
:=help => "create initial auto.def, etc. Use --init=help for known types"
91 # Undocumented options
100 if {[opt-bool version
]} {
101 puts
$autosetup(version
)
105 # autosetup --conf=alternate-auto.def
106 if {[opt-val conf
] ne
""} {
107 set autosetup
(autodef
) [opt-val conf
]
110 # Debugging output (set this early)
111 incr autosetup
(debug
) [opt-bool debug
]
112 incr autosetup
(force
) [opt-bool force
]
113 incr autosetup
(msg-quiet
) [opt-bool quiet
]
114 incr autosetup
(msg-timing
) [opt-bool timing
]
116 # If the local module exists, source it now to allow for
117 # project-local customisations
118 if {[file exists
$autosetup(libdir
)/local.tcl
]} {
122 # Now any auto-load modules
123 foreach
file [glob
-nocomplain $autosetup(libdir
)/*.auto
$autosetup(libdir
)/*/*.auto
] {
124 automf_load
source $file
127 if {[opt-val
help] ne
""} {
128 incr autosetup
(showhelp
)
130 autosetup_help
[opt-val
help]
133 if {[opt-val
{manual ref reference
}] ne
""} {
135 autosetup_reference
[opt-val
{manual ref reference
}]
138 if {[opt-val init
] ne
""} {
140 autosetup_init
[opt-val init
]
143 if {[opt-val
install] ne
""} {
145 autosetup_install
[opt-val
install]
148 if {![file exists
$autosetup(autodef
)]} {
149 # Check for invalid option first
151 user-error
"No auto.def found in \"$autosetup(srcdir)\" (use [file tail $::autosetup(exe)] --init to create one)"
154 # Parse extra arguments into autosetup(cmdline)
156 if {[regexp
{([^
=]*)=(.
*)} $arg -> n v
]} {
157 dict
set autosetup
(cmdline
) $n $v
160 user-error
"Unexpected parameter: $arg"
164 autosetup_add_dep
$autosetup(autodef
)
166 set cmd
[file-normalize
$autosetup(exe
)]
167 foreach arg
$autosetup(argv
) {
168 append cmd
" [quote-if-needed $arg]"
170 define AUTOREMAKE
$cmd
172 # Log how we were invoked
173 configlog
"Invoked as: [getenv WRAPPER $::argv0] [quote-argv $autosetup(argv)]"
175 # Note that auto.def is *not* loaded in the global scope
176 source $autosetup(autodef
)
178 # Could warn here if options {} was not specified
182 if {$autosetup(debug
)} {
183 msg-result
"Writing all defines to config.log"
184 configlog
"================ defines ======================"
185 foreach n
[lsort
[array names define
]] {
186 configlog
"define $n $define($n)"
193 # @opt-bool option ...
195 # Check each of the named, boolean options and return 1 if any of them have
196 # been set by the user.
198 proc opt-bool
{args
} {
199 option-check-names
{*}$args
200 opt_bool
::useropts
{*}$args
203 # @opt-val option-list ?default=""?
205 # Returns a list containing all the values given for the non-boolean options in 'option-list'.
206 # There will be one entry in the list for each option given by the user, including if the
207 # same option was used multiple times.
208 # If only a single value is required, use something like:
210 ## lindex [opt-val $names] end
212 # If no options were set, $default is returned (exactly, not as a list).
214 proc opt-val
{names
{default
""}} {
215 option-check-names
{*}$names
216 join [opt_val
::useropts
$names $default]
219 proc option-check-names
{args
} {
221 if {$o ni $
::autosetup
(options
)} {
222 autosetup-error
"Request for undeclared option --$o"
227 # Parse the option definition in $opts and update
228 # ::useropts() and ::autosetup(optionhelp) appropriately
230 proc options-add
{opts
{header
""}} {
231 global useropts autosetup
233 # First weed out comment lines
235 foreach line
[split $opts \n] {
236 if {![string match
"#*" [string trimleft
$line]]} {
237 append realopts
$line \n
242 for {set i
0} {$i < [llength
$opts]} {incr i
} {
243 set opt
[lindex
$opts $i]
244 if {[string match
=* $opt]} {
245 # This is a special heading
246 lappend autosetup
(optionhelp
) $opt ""
251 #puts "i=$i, opt=$opt"
252 regexp
{^
([^
:=]*)(:)?
(=)?
(.
*)$
} $opt -> name colon equal value
253 if {$name in $autosetup(options
)} {
254 autosetup-error
"Option $name already specified"
257 #puts "$opt => $name $colon $equal $value"
259 # Find the corresponding value in the user options
260 # and set the default if necessary
261 if {[string match
"-*" $opt]} {
262 # This is a documentation-only option, like "-C <dir>"
264 } elseif
{$colon eq
""} {
266 lappend autosetup
(options
) $name
268 if {![info exists useropts
($name)]} {
269 set useropts
($name) $value
272 set opthelp
"--disable-$name"
274 set opthelp
"--$name"
278 lappend autosetup
(options
) $name
281 if {[info exists useropts
($name)]} {
282 # If the user specified the option with no value, the value will be "1"
283 # Replace with the default
284 if {$useropts($name) eq
"1"} {
285 set useropts
($name) $value
288 set opthelp
"--$name?=$value?"
290 set opthelp
"--$name=$value"
294 # Now create the help for this option if appropriate
295 if {[lindex
$opts $i+1] eq
"=>"} {
296 set desc
[lindex
$opts $i+2]
297 #string match \n* $desc
299 lappend autosetup
(optionhelp
) $header ""
302 # A multi-line description
303 lappend autosetup
(optionhelp
) $opthelp $desc
309 # @module-options optionlist
311 # Like 'options', but used within a module.
312 proc module-options
{opts
} {
314 if {$
::autosetup
(showhelp
) > 1 && [llength
$opts]} {
315 set header
"Module Options:"
317 options-add
$opts $header
319 if {$
::autosetup
(showhelp
)} {
320 # Ensure that the module isn't executed on --help
321 # We are running under eval or source, so use break
322 # to prevent further execution
323 #return -code break -level 2
329 expr {$a > $b ?
$a : $b}
332 proc options-wrap-desc
{text length firstprefix nextprefix initial
} {
334 set space
$firstprefix
335 foreach word
[split $text] {
336 set word
[string trim
$word]
340 if {$len && [string length
$space$word] + $len >= $length} {
343 set space
$nextprefix
345 incr len
[string length
$space$word]
346 puts
-nonewline $space$word
354 proc options-show
{} {
355 # Determine the max option width
357 foreach
{opt desc
} $
::autosetup
(optionhelp
) {
358 if {[string match
=* $opt] ||
[string match
\n* $desc]} {
361 set max
[max
$max [string length
$opt]]
363 set indent
[string repeat
" " [expr $max+4]]
364 set cols
[getenv COLUMNS
80]
366 lassign
[exec stty size
] rows cols
370 foreach
{opt desc
} $
::autosetup
(optionhelp
) {
371 if {[string match
=* $opt]} {
372 puts
[string range
$opt 1 end
]
375 puts
-nonewline " [format %-${max}s $opt]"
376 if {[string match
\n* $desc]} {
379 options-wrap-desc
[string trim
$desc] $cols " " $indent [expr $max + 2]
384 # @options options-spec
386 # Specifies configuration-time options which may be selected by the user
387 # and checked with opt-val and opt-bool. The format of options-spec follows.
389 # A boolean option is of the form:
391 ## name[=0|1] => "Description of this boolean option"
393 # The default is name=0, meaning that the option is disabled by default.
394 # If name=1 is used to make the option enabled by default, the description should reflect
395 # that with text like "Disable support for ...".
397 # An argument option (one which takes a parameter) is of the form:
399 ## name:[=]value => "Description of this option"
401 # If the name:value form is used, the value must be provided with the option (as --name=myvalue).
402 # If the name:=value form is used, the value is optional and the given value is used as the default
403 # if is not provided.
405 # Undocumented options are also supported by omitting the "=> description.
406 # These options are not displayed with --help and can be useful for internal options or as aliases.
408 # For example, --disable-lfs is an alias for --disable=largefile:
410 ## lfs=1 largefile=1 => "Disable large file support"
412 proc options
{optlist
} {
413 # Allow options as a list or args
414 options-add
$optlist "Local Options:"
416 if {$
::autosetup
(showhelp
)} {
421 # Check for invalid options
422 if {[opt-bool option-checking
]} {
423 foreach o
[array names
::useropts
] {
424 if {$o ni $
::autosetup
(options
)} {
425 user-error
"Unknown option --$o"
431 proc config_guess
{} {
432 if {[file-isexec $
::autosetup
(dir
)/config.guess
]} {
433 exec-with-stderr sh $
::autosetup
(dir
)/config.guess
434 if {[catch
{exec-with-stderr sh $
::autosetup
(dir
)/config.guess
} alias]} {
439 configlog
"No config.guess, so using uname"
440 string tolower
[exec uname
-p]-unknown-[exec uname
-s][exec uname
-r]
444 proc config_sub
{alias} {
445 if {[file-isexec $
::autosetup
(dir
)/config.sub
]} {
446 if {[catch
{exec-with-stderr sh $
::autosetup
(dir
)/config.sub
$alias} alias]} {
453 # @define name ?value=1?
455 # Defines the named variable to the given value.
456 # These (name, value) pairs represent the results of the configuration check
457 # and are available to be checked, modified and substituted.
459 proc define
{name
{value
1}} {
460 set ::define
($name) $value
461 #dputs "$name <= $value"
464 # @define-append name value ...
466 # Appends the given value(s) to the given 'defined' variable.
467 # If the variable is not defined or empty, it is set to $value.
468 # Otherwise the value is appended, separated by a space.
469 # Any extra values are similarly appended.
470 # If any value is already contained in the variable (as a substring) it is omitted.
472 proc define-append
{name args
} {
473 if {[get-define
$name ""] ne
""} {
474 # Make a token attempt to avoid duplicates
476 if {[string first
$arg $
::define
($name)] == -1} {
477 append
::define
($name) " " $arg
481 set ::define
($name) [join $args]
483 #dputs "$name += [join $args] => $::define($name)"
486 # @get-define name ?default=0?
488 # Returns the current value of the 'defined' variable, or $default
491 proc get-define
{name
{default
0}} {
492 if {[info exists
::define
($name)]} {
493 #dputs "$name => $::define($name)"
494 return $
::define
($name)
496 #dputs "$name => $default"
502 # Returns 1 if the given variable is defined.
504 proc is-defined
{name
} {
505 info exists
::define
($name)
510 # Returns a dictionary (name value list) of all defined variables.
512 # This is suitable for use with 'dict', 'array set' or 'foreach'
513 # and allows for arbitrary processing of the defined variables.
515 proc all-defines
{} {
520 # @get-env name default
522 # If $name was specified on the command line, return it.
523 # If $name was set in the environment, return it.
524 # Otherwise return $default.
526 proc get-env
{name default
} {
527 if {[dict exists $
::autosetup
(cmdline
) $name]} {
528 return [dict get $
::autosetup
(cmdline
) $name]
530 getenv
$name $default
535 # Returns 1 if the $name was specified on the command line or in the environment.
536 # Note that an empty environment variable is not considered to be set.
538 proc env-is-set
{name
} {
539 if {[dict exists $
::autosetup
(cmdline
) $name]} {
542 if {[getenv
$name ""] ne
""} {
548 # @readfile filename ?default=""?
550 # Return the contents of the file, without the trailing newline.
551 # If the doesn't exist or can't be read, returns $default.
553 proc readfile
{filename
{default_value
""}} {
554 set result
$default_value
556 set f
[open
$filename]
557 set result
[read -nonewline $f]
563 # @writefile filename value
565 # Creates the given file containing $value.
566 # Does not add an extra newline.
568 proc writefile
{filename value
} {
569 set f
[open
$filename w
]
570 puts
-nonewline $f $value
574 proc quote-if-needed
{str
} {
575 if {[string match
{*[\" ]*} $str]} {
576 return \"[string map
[list
\" \\" \\ \\\\] $str]\"
581 proc quote-argv {argv} {
584 lappend args [quote-if-needed $arg]
591 # Takes a list and returns a new list with $suf appended
594 ## suffix .c {a b c} => {a.c b.c c.c}
596 proc suffix {suf list} {
599 lappend result $p$suf
606 # Takes a list and returns a new list with $pre prepended
609 ## prefix jim- {a.c b.c} => {jim-a.c jim-b.c}
611 proc prefix {pre list} {
614 lappend result $pre$p
619 # @find-executable name
621 # Searches the path for an executable with the given name.
622 # Note that the name may include some parameters, e.g. "cc
-mbig-endian",
623 # in which case the parameters are ignored.
624 # Returns 1 if found, or 0 if not.
626 proc find-executable {name} {
627 # Ignore any parameters
628 set name [lindex $name 0]
630 # The empty string is never a valid executable
633 foreach p [split-path] {
634 dputs "Looking
for $name in $p"
635 set exec [file join $p $name]
636 if {[file-isexec $exec]} {
637 dputs "Found
$name -> $exec"
644 # @find-an-executable ?-required? name ...
646 # Given a list of possible executable names,
647 # searches for one of these on the path.
649 # Returns the name found, or "" if none found.
650 # If the first parameter is '-required', an error is generated
651 # if no executable is found.
653 proc find-an-executable {args} {
655 if {[lindex $args 0] eq "-required"} {
656 set args [lrange $args 1 end]
660 if {[find-executable $name]} {
665 if {[llength $args] == 1} {
666 user-error "failed to
find: [join $args]"
668 user-error "failed to
find one of
: [join $args]"
676 # Writes the given message to the configuration log, config.log
678 proc configlog {msg} {
679 if {![info exists ::autosetup(logfh)]} {
680 set ::autosetup(logfh) [open config.log w]
682 puts $::autosetup(logfh) $msg
687 # Writes the message with no newline to stdout.
689 proc msg-checking {msg} {
690 if {$::autosetup(msg-quiet) == 0} {
693 set ::autosetup(msg-checking) 1
699 # Writes the message to stdout.
701 proc msg-result {msg} {
702 if {$::autosetup(msg-quiet) == 0} {
705 set ::autosetup(msg-checking) 0
710 # @msg-quiet command ...
712 # msg-quiet evaluates it's arguments as a command with output
713 # from msg-checking and msg-result suppressed.
715 # This is useful if a check needs to run a subcheck which isn't
716 # of interest to the user.
717 proc msg-quiet {args} {
718 incr ::autosetup(msg-quiet)
719 set rc [uplevel 1 $args]
720 incr ::autosetup(msg-quiet) -1
724 # Will be overridden by 'use misc'
725 proc error-stacktrace {msg} {
729 proc error-location {msg} {
733 ##################################################################
738 if {$::autosetup(debug)} {
743 ##################################################################
745 # User and system warnings and errors
747 # Usage errors such as wrong command line options
751 # Indicate incorrect usage to the user, including if required components
752 # or features are not found.
753 # autosetup exits with a non-zero return code.
755 proc user-error {msg} {
757 puts stderr "Error
: $msg"
758 puts stderr "Try
: '[file tail $::autosetup(exe)] --help' for options
"
764 # Output the given message to stderr.
766 proc user-notice {msg} {
767 lappend ::autosetup(notices) $msg
770 # Incorrect usage in the auto.def file. Identify the location.
771 proc autosetup-error {msg} {
772 autosetup-full-error [error-location $msg]
775 # Like autosetup-error, except $msg is the full error message.
776 proc autosetup-full-error {msg} {
782 proc show-notices {} {
783 if {$::autosetup(msg-checking)} {
785 set ::autosetup(msg-checking) 0
788 if {[info exists ::autosetup(notices)]} {
789 puts stderr [join $::autosetup(notices) \n]
790 unset ::autosetup(notices)
794 proc maybe-show-timestamp {} {
795 if {$::autosetup(msg-timing) && $::autosetup(msg-checking) == 0} {
796 puts -nonewline [format {[%6.2f] } [expr {([clock millis] - $::autosetup(start)) % 10000 / 1000.0}]]
800 proc autosetup_version {} {
801 return "autosetup v$
::autosetup
(version
)"
804 ##################################################################
806 # Directory/path handling
817 # Follow symlinks until we get to something which is not a symlink
818 proc realpath {path} {
821 set path [file link $path]
830 # Convert absolute path, $path into a path relative
831 # to the given directory (or the current dir, if not given).
833 proc relative-path {path {pwd {}}} {
838 set path [file-normalize $path]
842 set pwd [file-normalize $pwd]
849 # Try to make the filename relative to the current dir
850 foreach p [split $pwd /] f [split $path /] {
858 # Add .. for sibling or parent dir
866 if {$same == 1 || [llength $prefix] > 3} {
870 file join [join $prefix /] [join $newf /]
873 # Add filename as a dependency to rerun autosetup
874 # The name will be normalised (converted to a full path)
876 proc autosetup_add_dep {filename} {
877 lappend ::autosetup(deps) [file-normalize $filename]
880 ##################################################################
882 # Library module support
887 # Load the given library modules.
888 # e.g. 'use cc cc-shared'
890 # Note that module 'X' is implemented in either 'autosetup/X.tcl'
891 # or 'autosetup/X/init.tcl'
893 # The latter form is useful for a complex module which requires additional
894 # support file. In this form, '$::usedir' is set to the module directory
899 if {[info exists ::libmodule($m)]} {
902 set ::libmodule($m) 1
903 if {[info exists ::modsource($m)]} {
904 automf_load eval $::modsource($m)
906 set sources [list $::autosetup(libdir)/${m}.tcl $::autosetup(libdir)/${m}/init.tcl]
908 foreach source $sources {
909 if {[file exists $source]} {
915 # For the convenience of the "use
" source, point to the directory
916 # it is being loaded from
917 set ::usedir [file dirname $source]
918 automf_load source $source
919 autosetup_add_dep $source
921 autosetup-error "use
: No such module
: $m"
927 # Load module source in the global scope by executing the given command
928 proc automf_load {args} {
929 if {[catch [list uplevel #0 $args] msg opts] ni {0 2 3}} {
930 autosetup-full-error [error-dump $msg $opts $::autosetup(debug)]
935 set autosetup(exe) $::argv0
936 set autosetup(istcl) 1
937 set autosetup(start) [clock millis]
938 set autosetup(installed) 0
939 set autosetup(msg-checking) 0
940 set autosetup(msg-quiet) 0
942 # Embedded modules are inserted below here
943 set autosetup(installed) 1
944 # ----- module asciidoc-formatting -----
946 set modsource(asciidoc-formatting) {
947 # Copyright (c) 2010 WorkWare Systems http://www.workware.net.au/
948 # All rights reserved
950 # Module which provides text formatting
956 regsub -all "\
[ \t\n\
]+" [string trim $text] " "
959 underline [para $text] =
967 foreach line [parse_code_block $text] {
972 proc codelines {lines} {
973 foreach line $lines {
981 proc underline {text char} {
982 regexp "^
(\
[ \t\
]*)(.
*)" $text -> indent words
984 puts $indent[string repeat $char [string length $words]]
986 proc section {text} {
987 underline "[para
$text]" -
990 proc subsection {text} {
995 puts "* [para
$text]"
1001 proc defn {first args} {
1008 set defn [string trim [join $args \n]]
1009 regsub -all "\n\n" $defn "\n ::\n" defn
1014 # ----- module formatting -----
1016 set modsource(formatting) {
1017 # Copyright (c) 2010 WorkWare Systems http://www.workware.net.au/
1018 # All rights reserved
1020 # Module which provides common text formatting
1022 # This is designed for documenation which looks like:
1029 # In the second case, we need to work out the indenting
1030 # and strip it from all lines but preserve the remaining indenting.
1031 # Note that all lines need to be indented with the same initial
1034 # Returns a list of lines with the indenting removed.
1036 proc parse_code_block {text} {
1037 # If the text begins with newline, take the following text,
1038 # otherwise just return the original
1039 if {![regexp "^
\n(.
*)" $text -> text]} {
1040 return [list [string trim $text]]
1043 # And trip spaces off the end
1044 set text [string trimright $text]
1047 # Examine each line to determine the minimum indent
1048 foreach line [split $text \n] {
1050 # Ignore empty lines for the indent calculation
1053 regexp "^
(\
[ \t\
]*)" $line -> indent
1054 set len [string length $indent]
1060 # Now make a list of lines with this indent removed
1062 foreach line [split $text \n] {
1063 lappend lines [string range $line $min end]
1071 # ----- module getopt -----
1073 set modsource(getopt) {
1074 # Copyright (c) 2006 WorkWare Systems http://www.workware.net.au/
1075 # All rights reserved
1077 # Simple getopt module
1079 # Parse everything out of the argv list which looks like an option
1080 # Knows about --enable-thing and --disable-thing as alternatives for --thing=0 or --thing=1
1081 # Everything which doesn't look like an option, or is after --, is left unchanged
1082 proc getopt {argvname} {
1083 upvar $argvname argv
1086 for {set i 0} {$i < [llength $argv]} {incr i} {
1087 set arg [lindex $argv $i]
1094 lappend nargv {*}[lrange $argv $i end]
1098 if {[regexp {^--([^=][^=]+)=(.*)$} $arg -> name value]} {
1099 lappend opts($name) $value
1100 } elseif {[regexp {^--(enable-|disable-)?([^=]*)$} $arg -> prefix name]} {
1101 if {$prefix eq "disable-
"} {
1106 lappend opts($name) $value
1112 #puts "getopt
: argv
=[join $argv] => [join $nargv]"
1117 return [array get opts]
1120 proc opt_val {optarrayname options {default {}}} {
1121 upvar $optarrayname opts
1125 foreach o $options {
1126 if {[info exists opts($o)]} {
1127 lappend result {*}$opts($o)
1130 if {[llength $result] == 0} {
1136 proc opt_bool {optarrayname args} {
1137 upvar $optarrayname opts
1139 # Support the args being passed as a list
1140 if {[llength $args] == 1} {
1141 set args [lindex $args 0]
1145 if {[info exists opts($o)]} {
1146 if {"1" in $opts($o) || "yes" in $opts($o)} {
1155 # ----- module help -----
1157 set modsource(help) {
1158 # Copyright (c) 2010 WorkWare Systems http://workware.net.au/
1159 # All rights reserved
1161 # Module which provides usage, help and the command reference
1163 proc autosetup_help {what} {
1166 puts "Usage
: [file tail $
::autosetup
(exe
)] \
[options\
] \
[settings\
]\n"
1167 puts "This is
[autosetup_version
], a build environment
\"autoconfigurator
\""
1168 puts "See the documentation online
at http
://msteveb.github.com
/autosetup
/\n"
1170 if {$what eq "local"} {
1171 if {[file exists $::autosetup(autodef)]} {
1172 # This relies on auto.def having a call to 'options'
1173 # which will display options and quit
1174 source $::autosetup(autodef)
1179 incr ::autosetup(showhelp)
1180 if {[catch {use $what}]} {
1181 user-error "Unknown module
: $what"
1189 # If not already paged and stdout is a tty, pipe the output through the pager
1190 # This is done by reinvoking autosetup with --nopager added
1192 if {![opt-bool nopager] && [getenv PAGER ""] ne "" && [isatty? stdin] && [isatty? stdout]} {
1194 exec [info nameofexecutable] $::argv0 --nopager {*}$::argv |& [getenv PAGER] >@stdout <@stdin
1200 # Outputs the autosetup references in one of several formats
1201 proc autosetup_reference {{type text}} {
1205 switch -glob -- $type {
1206 wiki {use wiki-formatting}
1207 ascii* {use asciidoc-formatting}
1208 md - markdown {use markdown-formatting}
1209 default {use text-formatting}
1212 title "[autosetup_version
] -- Command Reference
"
1214 section {Introduction}
1217 See http://msteveb.github.com/autosetup/ for the online documentation for 'autosetup'
1221 'autosetup' provides a number of built-in commands which
1222 are documented below. These may be used from 'auto.def' to test
1223 for features, define variables, create files from templates and
1224 other similar actions.
1227 automf_command_reference
1232 proc autosetup_output_block {type lines} {
1233 if {[llength $lines]} {
1242 foreach line $lines {
1251 # Generate a command reference from inline documentation
1252 proc automf_command_reference {} {
1253 lappend files $::autosetup(prog)
1254 lappend files {*}[lsort [glob -nocomplain $::autosetup(libdir)/*.tcl]]
1256 section "Core Commands
"
1261 foreach file $files {
1266 # Find lines starting with "# @*" and continuing through the remaining comment lines
1267 if {![regexp
{^
# @(.*)} $line -> cmd]} {
1271 # Synopsis or command?
1272 if {$cmd eq
"synopsis:"} {
1273 section
"Module: [file rootname [file tail $file]]"
1281 # Now the description
1285 if {![regexp
{^
#(#)? ?(.*)} $line -> hash cmd]} {
1290 } elseif
{[regexp
{^
- (.
*)} $cmd -> cmd
]} {
1296 #puts "hash=$hash, oldhash=$oldhash, lines=[llength $lines], cmd=$cmd"
1298 if {$t ne
$type ||
$cmd eq
""} {
1299 # Finish the current block
1300 autosetup_output_block
$type $lines
1309 autosetup_output_block
$type $lines
1316 # ----- module init -----
1318 set modsource
(init
) {
1319 # Copyright (c) 2010 WorkWare Systems http://www.workware.net.au/
1320 # All rights reserved
1322 # Module to help create auto.def and configure
1324 proc autosetup_init
{type} {
1326 if {$type in {?
help}} {
1328 } elseif
{![dict exists $
::autosetup
(inittypes
) $type]} {
1329 puts
"Unknown type, --init=$type"
1333 puts
"Use one of the following types (e.g. --init=make)\n"
1334 foreach
type [lsort
[dict keys $
::autosetup
(inittypes
)]] {
1335 lassign
[dict get $
::autosetup
(inittypes
) $type] desc
1336 # XXX: Use the options-show code to wrap the description
1337 puts
[format
"%-10s %s" $type $desc]
1341 lassign
[dict get $
::autosetup
(inittypes
) $type] desc
script
1343 puts
"Initialising $type: $desc\n"
1345 # All initialisations happens in the top level srcdir
1346 cd $
::autosetup
(srcdir
)
1353 proc autosetup_add_init_type
{type desc
script} {
1354 dict
set ::autosetup
(inittypes
) $type [list
$desc $script]
1357 # This is for in creating build-system init scripts
1359 # If the file doesn't exist, create it containing $contents
1360 # If the file does exist, only overwrite if --force is specified.
1362 proc autosetup_check_create
{filename contents
} {
1363 if {[file exists
$filename]} {
1364 if {!$
::autosetup
(force
)} {
1365 puts
"I see $filename already exists."
1368 puts
"I will overwrite the existing $filename because you used --force."
1371 puts
"I don't see $filename, so I will create it."
1373 writefile
$filename $contents
1377 # ----- module install -----
1379 set modsource
(install) {
1380 # Copyright (c) 2006-2010 WorkWare Systems http://www.workware.net.au/
1381 # All rights reserved
1383 # Module which can install autosetup
1385 proc autosetup_install
{dir
} {
1388 file mkdir autosetup
1390 set f
[open autosetup
/autosetup w
]
1392 set publicmodules $
::autosetup
(libdir
)/default.auto
1394 # First the main script, but only up until "CUT HERE"
1395 set in [open $
::autosetup
(dir
)/autosetup
]
1396 while {[gets
$in buf
] >= 0} {
1397 if {$buf ne
"##-- CUT HERE --##"} {
1402 # Insert the static modules here
1403 # i.e. those which don't contain @synopsis:
1404 puts
$f "set autosetup(installed) 1"
1405 foreach
file [lsort
[glob $
::autosetup
(libdir
)/*.tcl
]] {
1406 set buf
[readfile
$file]
1407 if {[string match
"*\n# @synopsis:*" $buf]} {
1408 lappend publicmodules
$file
1411 set modname
[file rootname
[file tail $file]]
1412 puts
$f "# ----- module $modname -----"
1413 puts
$f "\nset modsource($modname) \{"
1420 exec chmod 755 autosetup
/autosetup
1422 # Install public modules
1423 foreach
file $publicmodules {
1424 autosetup_install_file
$file autosetup
1427 # Install support files
1428 foreach
file {config.guess config.sub jimsh0.c find-tclsh test-tclsh LICENSE
} {
1429 autosetup_install_file $
::autosetup
(dir
)/$file autosetup
1431 exec chmod 755 autosetup
/config.sub autosetup
/config.guess autosetup
/find-tclsh
1433 writefile autosetup
/README.autosetup \
1434 "This is [autosetup_version]. See http://msteveb.github.com/autosetup/\n"
1437 user-error
"Failed to install autosetup: $error"
1439 puts
"Installed [autosetup_version] to autosetup/"
1441 # Now create 'configure' if necessary
1442 autosetup_create_configure
1447 proc autosetup_create_configure
{} {
1448 if {[file exists configure
]} {
1449 if {!$
::autosetup
(force
)} {
1450 # Could this be an autosetup configure?
1451 if {![string match
"*\nWRAPPER=*" [readfile configure
]]} {
1452 puts
"I see configure, but not created by autosetup, so I won't overwrite it."
1453 puts
"Remove it or use --force to overwrite."
1457 puts
"I will overwrite the existing configure because you used --force."
1460 puts
"I don't see configure, so I will create it."
1462 writefile configure \
1464 dir
="`dirname "$0"`/autosetup"
1465 WRAPPER
="$0"; export WRAPPER
; exec "`$dir/find-tclsh`" "$dir/autosetup" "$@"
1467 catch
{exec chmod 755 configure
}
1470 # Append the contents of $file to filehandle $f
1471 proc autosetup_install_append
{f
file} {
1477 proc autosetup_install_file
{file dir
} {
1478 if {![file exists
$file]} {
1479 error
"Missing installation file '$file'"
1481 writefile
[file join $dir [file tail $file]] [readfile
$file]\n
1484 if {$
::autosetup
(installed
)} {
1485 user-error
"autosetup can only be installed from development source, not from installed copy"
1489 # ----- module markdown-formatting -----
1491 set modsource
(markdown-formatting
) {
1492 # Copyright (c) 2010 WorkWare Systems http://www.workware.net.au/
1493 # All rights reserved
1495 # Module which provides text formatting
1496 # markdown format (kramdown syntax)
1501 regsub
-all "\[ \t\n\]+" [string trim
$text] " " text
1502 regsub
-all {([^a-zA-Z
])'([^']*)'} $text {\1**`\2`**} text
1503 regsub -all {^'([^
']*)'} $text {**`\1`**} text
1504 regsub
-all {(http
[^
\t\n]*)} $text {[\
1](\
1)} text
1508 underline
[para
$text] =
1515 proc codelines
{lines
} {
1517 foreach line
$lines {
1525 foreach line
[parse_code_block
$text] {
1534 proc underline
{text char
} {
1535 regexp
"^(\[ \t\]*)(.*)" $text -> indent words
1537 puts
$indent[string repeat
$char [string length
$words]]
1539 proc section
{text
} {
1540 underline
"[para $text]" -
1543 proc subsection
{text
} {
1547 proc bullet
{text
} {
1548 puts
"* [para $text]"
1550 proc defn
{first args
} {
1552 set defn
[string trim
[join $args \n]]
1555 puts
-nonewline ": "
1556 regsub
-all "\n\n" $defn "\n: " defn
1562 # ----- module misc -----
1564 set modsource
(misc
) {
1565 # Copyright (c) 2007-2010 WorkWare Systems http://www.workware.net.au/
1566 # All rights reserved
1568 # Module containing misc procs useful to modules
1569 # Largely for platform compatibility
1571 set autosetup
(istcl
) [info exists
::tcl_library
]
1572 set autosetup
(iswin
) [string equal windows
$tcl_platform(platform
)]
1574 if {$autosetup(iswin
)} {
1575 # mingw/windows separates $PATH with semicolons
1576 # and doesn't have an executable bit
1577 proc split-path
{} {
1578 split [getenv PATH .
] {;}
1580 proc file-isexec
{exec} {
1581 # Basic test for windows. We ignore .bat
1582 if {[file isfile
$exec] ||
[file isfile
$exec.exe
]} {
1588 # unix separates $PATH with colons and has and executable bit
1589 proc split-path
{} {
1590 split [getenv PATH .
] :
1592 proc file-isexec
{exec} {
1593 file executable
$exec
1597 # Assume that exec can return stdout and stderr
1598 proc exec-with-stderr
{args
} {
1602 if {$autosetup(istcl
)} {
1603 # Tcl doesn't have the env command
1604 proc getenv
{name args
} {
1605 if {[info exists
::env
($name)]} {
1606 return $
::env
($name)
1608 if {[llength
$args]} {
1609 return [lindex
$args 0]
1611 return -code error
"environment variable \"$name\" does not exist"
1613 proc isatty?
{channel
} {
1614 dict exists
[fconfigure
$channel] -xchar
1617 if {$autosetup(iswin
)} {
1618 # On Windows, backslash convert all environment variables
1619 # (Assume that Tcl does this for us)
1620 proc getenv
{name args
} {
1621 string map
{\\ /} [env
$name {*}$args]
1624 # Jim on unix is simple
1627 proc isatty?
{channel
} {
1630 # isatty is a recent addition to Jim Tcl
1631 set tty
[$channel isatty
]
1637 # In case 'file normalize' doesn't exist
1639 proc file-normalize
{path
} {
1640 if {[catch
{file normalize
$path} result
]} {
1645 if {[file isdir
$path]} {
1649 cd [file dirname $path]
1650 set result
[file join [pwd] [file tail $path]]
1657 # If everything is working properly, the only errors which occur
1658 # should be generated in user code (e.g. auto.def).
1659 # By default, we only want to show the error location in user code.
1660 # We use [info frame] to achieve this, but it works differently on Tcl and Jim.
1662 # This is designed to be called for incorrect usage in auto.def, via autosetup-error
1664 proc error-location
{msg
} {
1665 if {$
::autosetup
(debug
)} {
1666 return -code error
$msg
1668 # Search back through the stack trace for the first error in a .def file
1669 for {set i
1} {$i < [info level
]} {incr i
} {
1670 if {$
::autosetup
(istcl
)} {
1671 array
set info
[info frame
-$i]
1673 lassign
[info frame
-$i] info
(caller
) info
(file) info
(line
)
1675 if {[string match
*.def
$info(file)]} {
1676 return "[relative-path $info(file)]:$info(line): Error: $msg"
1678 #puts "Skipping $info(file):$info(line)"
1683 # If everything is working properly, the only errors which occur
1684 # should be generated in user code (e.g. auto.def).
1685 # By default, we only want to show the error location in user code.
1686 # We use [info frame] to achieve this, but it works differently on Tcl and Jim.
1688 # This is designed to be called for incorrect usage in auto.def, via autosetup-error
1690 proc error-stacktrace
{msg
} {
1691 if {$
::autosetup
(debug
)} {
1692 return -code error
$msg
1694 # Search back through the stack trace for the first error in a .def file
1695 for {set i
1} {$i < [info level
]} {incr i
} {
1696 if {$
::autosetup
(istcl
)} {
1697 array
set info
[info frame
-$i]
1699 lassign
[info frame
-$i] info
(caller
) info
(file) info
(line
)
1701 if {[string match
*.def
$info(file)]} {
1702 return "[relative-path $info(file)]:$info(line): Error: $msg"
1704 #puts "Skipping $info(file):$info(line)"
1709 # Given the return from [catch {...} msg opts], returns an appropriate
1710 # error message. A nice one for Jim and a less-nice one for Tcl.
1711 # If 'fulltrace' is set, a full stack trace is provided.
1712 # Otherwise a simple message is provided.
1714 # This is designed for developer errors, e.g. in module code or auto.def code
1717 proc error-dump
{msg opts fulltrace
} {
1718 if {$
::autosetup
(istcl
)} {
1720 return "Error: [dict get $opts -errorinfo]"
1722 return "Error: $msg"
1725 lassign
$opts(-errorinfo) p f l
1727 set result
"$f:$l: Error: "
1729 append result
"$msg\n"
1731 append result
[stackdump
$opts(-errorinfo)]
1734 # Remove the trailing newline
1740 # ----- module text-formatting -----
1742 set modsource
(text-formatting
) {
1743 # Copyright (c) 2010 WorkWare Systems http://www.workware.net.au/
1744 # All rights reserved
1746 # Module which provides text formatting
1750 proc wordwrap
{text length
{firstprefix
""} {nextprefix
""}} {
1752 set space
$firstprefix
1753 foreach word
[split $text] {
1754 set word
[string trim
$word]
1758 if {$len && [string length
$space$word] + $len >= $length} {
1761 set space
$nextprefix
1763 incr len
[string length
$space$word]
1765 # Use man-page conventions for highlighting 'quoted' and *quoted*
1767 # Use x^Hx for *bold* and _^Hx for 'underline'.
1769 # less and more will both understand this.
1770 # Pipe through 'col -b' to remove them.
1771 if {[regexp
{^
'(.*)'([^a-zA-Z0-9_
]*)$
} $word -> bareword dot
]} {
1772 regsub
-all .
$bareword "_\b&" word
1774 } elseif
{[regexp
{^
[*](.
*)[*]([^a-zA-Z0-9_
]*)$
} $word -> bareword dot
]} {
1775 regsub
-all .
$bareword "&\b&" word
1778 puts
-nonewline $space$word
1786 underline
[string trim
$text] =
1793 proc codelines
{lines
} {
1794 foreach line
$lines {
1802 proc underline
{text char
} {
1803 regexp
"^(\[ \t\]*)(.*)" $text -> indent words
1805 puts
$indent[string repeat
$char [string length
$words]]
1807 proc section
{text
} {
1808 underline
"[string trim $text]" -
1811 proc subsection
{text
} {
1815 proc bullet
{text
} {
1816 wordwrap
$text 76 " * " " "
1818 proc indent
{text
} {
1819 wordwrap
$text 76 " " " "
1821 proc defn
{first args
} {
1823 underline
" $first" ~
1833 # ----- module wiki-formatting -----
1835 set modsource
(wiki-formatting
) {
1836 # Copyright (c) 2010 WorkWare Systems http://www.workware.net.au/
1837 # All rights reserved
1839 # Module which provides text formatting
1840 # wiki.tcl.tk format output
1844 proc joinlines
{text
} {
1846 foreach l
[split [string trim
$text] \n] {
1847 lappend lines
[string trim
$l]
1852 puts
[joinlines
$text]
1856 puts
"*** [joinlines $text] ***"
1859 proc codelines
{lines
} {
1861 foreach line
$lines {
1868 foreach line
[parse_code_block
$text] {
1875 proc section
{text
} {
1879 proc subsection
{text
} {
1883 proc bullet
{text
} {
1884 puts
" * [joinlines $text]"
1886 proc indent
{text
} {
1887 puts
" : [joinlines $text]"
1889 proc defn
{first args
} {
1901 ##################################################################
1905 if {$autosetup(debug
)} {
1908 if {[catch
{main
$argv} msg opts
] == 1} {
1910 autosetup-full-error
[error-dump
$msg $opts $
::autosetup
(debug
)]
1911 if {!$autosetup(debug
)} {
1912 puts stderr
"Try: '[file tail $autosetup(exe)] --debug' for a full stack trace"