#!/bin/sh # hack to restart using tclsh \ exec tclsh "$0" "$@" # Copyright (C) 2001-2023 Artifex Software, Inc. # All Rights Reserved. # # This software is provided AS-IS with no warranty, either express or # implied. # # This software is distributed under license and may not be copied, # modified or distributed except as expressly authorized under the terms # of the license contained in the file LICENSE in this distribution. # # Refer to licensing information at http://www.artifex.com or contact # Artifex Software, Inc., 39 Mesa Street, Suite 108A, San Francisco, # CA 94129, USA, for further information. # # tmake is intended to be a drop-in replacement for a large and # useful subset of 'make'. It compiles makefiles into Tcl scripts # (lazily) and then executes the scripts. It requires makefiles to be # well-behaved: # # - If a rule body modifies a file, then either that file is a # target of the rule, or the file is not a target or dependent # of any rule. # # - If a rule body reads a file, then either that file is a # dependent of the rule, or the file is not a target of any rule. # # - No target is the target of more than one rule. # # When tmake executes a build rule, it also optionally checks whether the # dependencies in the makefile are up to date. It can also do some # Ghostscript-specific checks: # # - The definition of xxx_h must be the list of files included # (directly or indirectly) by xxx.h. # # - If a rule command includes the word "-include", then for # dependency checking, .dev is appended to any further words in that # command. # Define the backward-compatibility version of this file. set TMAKE_VERSION 106 #****** -j doesn't work yet ******# # The following switches set the corresponding global variables used during # execution of the compiled makefile: set O(-d) {DEBUG o_01} ;# print a debugging trace set O(-i) {IGNORE_ERRORS o_01} ;# ignore errors in rule bodies set O(-j) {MAX_JOBS o_max} ;# maximum number of concurrent rule ;# executions (NYI) set O(-k) {KEEP_GOING o_01} ;# continue past errors, but don't build ;# anything affected set O(-l) {MAX_LOAD o_max} ;# maximum load for parallel execution set O(-n) {DRYRUN o_01} ;# just print commands, don't execute them set O(-s) {SILENT o_01} ;# don't print commands set O(--check-dependencies)\ {CHECK_DEPENDENCIES o_01};# check dependency lists against sources set O(--check-gs-dependencies)\ {CHECK_GS_DEPENDENCIES o_01};# check GS-specific dependencies set O(--warn-multiply-defined-variables)\ {WARN_MULTIPLE o_01} ;# warn about variables defined more than once, ;# even if the definitions are identical set O(--warn-redefined-variables)\ {WARN_REDEFINED o_01} ;# warn about redefined variables set O(--warn-undefined-variables)\ {WARN_UNDEFINED o_01} ;# warn about undefined variables (every time) set O(--warn-undefined-variables-once)\ {WARN_UNDEFINED_ONCE o_01};# warn about undefined variables (only once) # The following additional globals are defined during execution # MAKEFLAGS - flags for recursive invocations set CHECKS [list\ CHECK_DEPENDENCIES CHECK_GS_DEPENDENCIES\ ] set WARNINGS [list\ WARN_MULTIPLE WARN_REDEFINED WARN_UNDEFINED\ ] set OPTIONS {} foreach opt [array names O] {lappend OPTIONS [lindex $O($opt) 0]} set GLOBALS "$OPTIONS\ MAKEFLAGS\ " proc init_globals {} { global OPTIONS GLOBALS foreach v $GLOBALS {global $v} foreach v $OPTIONS {set $v 0} set MAKEFLAGS "" set MAX_JOBS 1 set MAX_LOAD 99999 } # ================ Compiled script conventions ================ # # Rule T1 ... Tk : D1 ... Dm # B1 # ... # Bn # becomes # L ; R "T1 ... Tk" "list D1 ... Dm" "list B1 ... Bn" # # Macro definition XYZ = DEF becomes # L ; P XYZ DEF # # Macro usage $(XYZ) becomes [_XYZ] so we can use Tcl's 'unknown' facility # to default macro values to the empty string, since Tcl apparently does # not provide a way to trap references to undefined variables. # # At run time, for each target or dependent ABC, the procedure [@ABC] # builds ABC (if necessary) and returns its build time. # ================ Command line processing ================ # # Argument type handlers proc o_01 {vvar argv} { upvar $vvar var set var 1 return 0 } proc o_max {vvar argv} { upvar $vvar var if {[llength $argv] > 1 && [regexp {^[0-9]+$} [lindex $argv 1]]} { set var [lindex $argv 1]; return 1 } else { set var 99999; return 0 } } proc tmake_args {args} { global O GLOBALS CHECKS COMPILE DEFINES JOBS MAKEFILE TARGETS WARNINGS foreach v $GLOBALS {global $v} set argv $args while {[llength $argv] > 0} { set n 0 set copy 1 set arg [lindex $argv 0] switch -glob -- $arg { -C { # -C is not implemented set copy 0 } --check-all { foreach v $CHECKS {set $v 1} } --compile-only { # compile-time switch only set COMPILE 1 } -f {set MAKEFILE [lindex $argv 1]; set n 1; set copy 0} -m { # -m is ignored for compatibility with GNU make; # also, because MAKEFLAGS omits the initial '-', we need a # dummy switch in case there are variable definitions (!). set copy 0 } --warn-all { foreach v $WARNINGS {set $v 1} } -* { if [info exists O($arg)] { set opt $O($arg) set n [[lindex $opt 1] [lindex $opt 0] $argv] } else { puts "Unknown option: $arg" puts {Usage: tmake (