Tcl · Module 27
Shared Setup Scripts
Factoring the common setup out is the easy part and the demonstration is an edit count. The part worth thinking about is what a shared file does to the scripts that source it.
Intermediate19 min readtcledapart-iiinfrastructuresetupmaintainability
Part II · Module 27 · Chapter 27.3 · Shared Setup Scripts
Every flow script in a project needs the same handful of things: where the libraries are, which tool to use, what the default effort is, and the shared procedures from Chapter 27.7.
Copying that preamble into each script works until the day one of those facts changes.
1. The cost of the copy
The effort of three edits is not the problem. The problem is the copy somebody misses: place_flow.tcl keeps the old library path, runs successfully, produces plausible numbers against the wrong library, and nothing reports it. That is Chapter 24.2 §6's incomparable-numbers argument arriving through a maintenance route.
2. One file
# setup.tcl — the setup every flow script in this project sources.
set SETUP_SCRIPT [file normalize [info script]]
set FLOW_ROOT [file dirname [file dirname $SETUP_SCRIPT]]
# -------- the project's settings, in ONE place --------------------------
set LIB_PATH /proj/libs/tech7nm/v2.4
set SDC_DIR [file join $FLOW_ROOT .. constraints]
set TOOL_NAME alpha
set EFFORT high
# -------- the shared libraries, sourced once -----------------------------
foreach f {vars.tcl log.tcl helpers.tcl tool.tcl} {
source [file join $FLOW_ROOT lib $f]
}And each flow script begins the same two lines:
set FLOW_ROOT [file dirname [file dirname [file normalize [info script]]]]
source [file join $FLOW_ROOT lib setup.tcl]3. The demonstration is an edit count
=== three flow scripts, each sourcing the shared setup ===
synth_flow sees LIB_PATH /proj/libs/tech7nm/v2.4 TOOL alpha
place_flow sees LIB_PATH /proj/libs/tech7nm/v2.4 TOOL alpha
route_flow sees LIB_PATH /proj/libs/tech7nm/v2.4 TOOL alpha
=== change line 8 of setup.tcl — one line, one file ===
8:set LIB_PATH /proj/libs/tech5nm/v3.1
=== the same three scripts, unmodified ===
synth_flow sees LIB_PATH /proj/libs/tech5nm/v3.1 TOOL alpha
place_flow sees LIB_PATH /proj/libs/tech5nm/v3.1 TOOL alpha
route_flow sees LIB_PATH /proj/libs/tech5nm/v3.1 TOOL alpha
=== how many files were edited? ===
setup.tcl : 1 line
flow scripts : 0That is the whole argument for a shared setup, and it is worth having the number rather than the intuition.
4. What a shared setup file actually is
Here is the part that does not appear in the pitch.
A second, quieter version of the same hazard: setup.tcl sources four library files, so every script that sources it gets all four, whether it uses them or not. That is convenient and it means nobody can tell which script needs which library. When tool.tcl changes, the set of scripts affected is "all of them" — not because they all use it, but because nobody recorded which do.
5. Why setup.tcl locates itself
set SETUP_SCRIPT [file normalize [info script]]
set FLOW_ROOT [file dirname [file dirname $SETUP_SCRIPT]]setup.tcl computes FLOW_ROOT from its own location, not from the variable the caller set. The reason is the same as Chapter 27.1 §3's: info script inside a sourced file returns that file's path, so a setup file can locate itself regardless of who sourced it or from where.
That matters because it makes the shared file usable from three different kinds of caller — a batch driver in flow/bin/, an interactive session anywhere, and another library — without any of them having to agree on how to describe the tree.
The file normalize is load-bearing here for exactly the reason it was there: without it, a later cd changes what FLOW_ROOT means, and the failure arrives long after the line that caused it.
6. Sourcing is not importing
Being honest about the mechanism, because source is weaker than it looks.
There is no encapsulation. source evaluates the file in the current scope (Chapter 15.1), so every variable it sets lands wherever the source happened. Inside a procedure that means they are locals and vanish on return — the asymmetry Chapter 15.1 documents, and the reason a setup file must be sourced at the global level or explicitly set ::-qualified names.
There is no versioning. Nothing records which revision of setup.tcl a run used. A log line naming it, with its modification time or git revision, is the cheapest fix and it is Chapter 24.2 §6's provenance argument again.
There is no dependency declaration. setup.tcl sources four files in a fixed order because one of them needs another to exist first. That order is load-bearing and unwritten; package require (Chapter 15.8) is the mechanism that makes it explicit, at the cost of needing a pkgIndex.tcl that a vendor interpreter may or may not cooperate with.
A second source re-runs every line. For proc definitions that is harmless — redefinition replaces. For lappend, incr or anything accumulating, it is the duplication demonstrated in Chapter 27.7 §2. A setup file is a script people source twice by accident, so it has the same idempotency obligation as any other helper.
7. Exercises
Exercise 1. What is the real cost of copy-pasted setup — the effort, or something else?
Exercise 2. What did the demonstration measure, and what were the two numbers?
Exercise 3. In what sense is a shared setup file a shared mutable global?
Exercise 4. Trace the four-step failure sequence from an undeclared dependency.
Exercise 5. Why was step 2 of that sequence not visibly wrong?
Exercise 6. What is the second, quieter hazard of sourcing four libraries from one file?
Exercise 7. Why does setup.tcl compute FLOW_ROOT from info script rather than from the caller's variable?
Exercise 8. What happens if a setup file is sourced inside a procedure?
Exercise 9. Name three things source does not give you that an import would.
Exercise 10. Why must validation run after the override file, not before?
Where this fits
Part of the Tcl curriculum.
