public function topoSort($rootTarget)
    {
        $rootTarget = (string) $rootTarget;
        $ret = [];
        $state = [];
        $visiting = [];

        // We first run a DFS based sort using the root as the starting node.
        // This creates the minimum sequence of Targets to the root node.
        // We then do a sort on any remaining unVISITED targets.
        // This is unnecessary for doing our build, but it catches
        // circular dependencies or missing Targets on the entire
        // dependency tree, not just on the Targets that depend on the
        // build Target.

        $this->_tsort($rootTarget, $state, $visiting, $ret);

        $retHuman = "";
        for ($i = 0, $_i = count($ret); $i < $_i; $i++) {
            $retHuman .= (string) $ret[$i] . " ";
        }
        $this->log("Build sequence for target '$rootTarget' is: $retHuman", Project::MSG_VERBOSE);

        $keys = array_keys($this->targets);
        while ($keys) {
            $curTargetName = (string) array_shift($keys);
            if (!isset($state[$curTargetName])) {
                $st = null;
            } else {
                $st = (string) $state[$curTargetName];
            }

            if ($st === null) {
                $this->_tsort($curTargetName, $state, $visiting, $ret);
            } elseif ($st === "VISITING") {
                throw new Exception("Unexpected node in visiting state: $curTargetName");
            }
        }

        $retHuman = "";
        for ($i = 0, $_i = count($ret); $i < $_i; $i++) {
            $retHuman .= (string) $ret[$i] . " ";
        }
        $this->log("Complete build sequence is: $retHuman", Project::MSG_VERBOSE);

        return $ret;
    }