#!/usr/bin/tclsh
#
set help \
{Run this TCL script to build and install the TCL interface library for
SQLite.  Run the script with the specific "tclsh" for which the installation
should occur.

There must be a valid "tclsqlite3.c" file in the working directory prior
to running this script.  Use "make tclsqlite3.c" to generate that file.

Options:

   --build-only         Only build the extension, don't install it
   --cc COMPILER        Build using this compiler
   --info               Show info on existing SQLite TCL extension installs
   --install-only       Install an extension previously build
   --uninstall          Uninstall the extension
   --version-check      Check extension version against this source tree
   --destdir DIR        Installation root (used by "make install DESTDIR=...")
  --tclConfig.sh FILE  Use this tclConfig.sh instead of looking for one
  --extlibs             LDFLAGS required for external libs, e.g. ICU.

Other options are retained and passed through into the compiler.}


set build 1
set install 1
set uninstall 0
set infoonly 0
set versioncheck 0
set CC {}
set OPTS {}
set DESTDIR ""    ; # --destdir "$(DESTDIR)"
set tclConfigSh ""; # --tclConfig.sh FILE
set LIBS {}       ; # --extlibs "-lx -ly ..."
for {set ii 0} {$ii<[llength $argv]} {incr ii} {
  set a0 [lindex $argv $ii]
  if {$a0=="--install-only"} {
    set build 0
  } elseif {$a0=="--build-only"} {
    set install 0
  } elseif {$a0=="--uninstall"} {
    set build 0
    set install 0
    set versioncheck 0
    set uninstall 1
  } elseif {$a0=="--info"} {
    set build 0
    set install 0
    set versioncheck 0
    set infoonly 1
  } elseif {$a0=="--version-check"} {
    set build 0
    set install 0
    set infoonly 0
    set versioncheck 1
  } elseif {$a0=="--cc" && $ii+1<[llength $argv]} {
    incr ii
    set CC [lindex $argv $ii]
  } elseif {$a0=="--destdir" && $ii+1<[llength $argv]} {
    incr ii
    set DESTDIR [lindex $argv $ii]
  } elseif {$a0=="--tclConfig.sh" && $ii+1<[llength $argv]} {
    incr ii
    set tclConfigSh [lindex $argv $ii]
  } elseif {$a0=="--extlibs" && $ii+1<[llength $argv]} {
    incr ii
    lappend LIBS [lindex $argv $ii]
  } elseif {[string match -* $a0]} {
    append OPTS " $a0"
  } else {
    puts stderr "Unknown option: \"$a0\"\n"
    puts stderr $help
    exit 1
  }
}

# Find the root of the SQLite source tree
#
set srcdir [file normalize [file dir $argv0]/..]

# Get the SQLite version number into $VERSION
#
set fd [open $srcdir/VERSION]
set VERSION [string trim [read $fd]]
close $fd

if {$tcl_platform(platform) eq "windows"} {
  # We are only able to install, uninstall, and list on Windows.
  # The build process is handled by the Makefile.msc, specifically
  # using "nmake /f Makefile.msc pkgIndex.tcl tclsqlite3.dll"
  #
  if {$build} {
    puts "Unable to build on Windows using the builttclext.tcl script."
    puts "To build, run\n"
    puts "   \"nmake /f Makefile.msc pkgIndex.tcl tclsqlite3.dll"
    exit 1
  }
  set OUT tclsqlite3.dll
} else {
  # Read the tclConfig.sh file into the $tclConfig variable
  #
  if {"" eq $tclConfigSh} {
    # Figure out the location of the tclConfig.sh file used by the
    # tclsh that is executing this script.
    #
    if {[catch {
      set LIBDIR [tcl::pkgconfig get libdir,install]
    }]} {
      puts stderr "$argv0: tclsh does not support tcl::pkgconfig."
      exit 1
    }
    if {![file exists $LIBDIR]} {
      puts stderr "$argv0: cannot find the tclConfig.sh file."
      puts stderr "$argv0: tclsh reported library directory \"$LIBDIR\"\
                 does not exist."
      exit 1
    }
    if {![file exists $LIBDIR/tclConfig.sh]
        || [file size $LIBDIR/tclConfig.sh]<5000} {
      set n1 $LIBDIR/tcl$::tcl_version
      if {[file exists $n1/tclConfig.sh]
          && [file size $n1/tclConfig.sh]>5000} {
        set LIBDIR $n1
      } else {
        puts stderr "$argv0: cannot find tclConfig.sh in either $LIBDIR or $n1"
        exit 1
      }
    }
    #puts "using $LIBDIR/tclConfig.sh"
    set fd [open $LIBDIR/tclConfig.sh rb]
    set tclConfig [read $fd]
    close $fd
  } else {
    # User-provided tclConfig.sh
    #
    set fd [open $tclConfigSh rb]
    set tclConfig [read $fd]
    close $fd
  }

  # Extract parameter we will need from the tclConfig.sh file
  #
  set TCLMAJOR 8
  regexp {TCL_MAJOR_VERSION='(\d)'} $tclConfig all TCLMAJOR
  set SUFFIX so
  regexp {TCL_SHLIB_SUFFIX='\.([^']+)'} $tclConfig all SUFFIX
  if {$CC==""} {
    set cc {}
    regexp {TCL_CC='([^']+)'} $tclConfig all cc
    if {$cc!=""} {
      set CC $cc
    }
  }
  if {$CC==""} {
    set CC gcc
  }
  set CFLAGS -fPIC
  regexp {TCL_SHLIB_CFLAGS='([^']+)'} $tclConfig all CFLAGS
  regexp {TCL_STUB_LIB_SPEC='([^']+)'} $tclConfig all LIBSTUB
  lappend LIBS $LIBSTUB
  set INC "-I$srcdir/src"
  set inc {}
  regexp {TCL_INCLUDE_SPEC='([^']+)'} $tclConfig all inc
  if {$inc!=""} {
    append INC " $inc"
  }
  set cmd {${CC} ${CFLAGS} ${LDFLAGS} -shared}
  regexp {TCL_SHLIB_LD='([^']+)(-Wl,--out-implib.*)?'} $tclConfig all cmd
  set LDFLAGS "$INC -DUSE_TCL_STUBS"
  if {[string length $OPTS]>1} {
    append LDFLAGS $OPTS
  }
  if {$tcl_platform(os) eq "Windows NT"} {
    set OUT cyg
  } else {
    set OUT lib
  }
  if {$TCLMAJOR>8} {
    set OUT ${OUT}tcl9sqlite$VERSION.$SUFFIX
  } else {
    set OUT ${OUT}sqlite$VERSION.$SUFFIX
  }
  set @ $OUT; # Workaround for https://sqlite.org/forum/forumpost/0683a49cb02f31a1
              # in which Gentoo edits their tclConfig.sh to include an soname
              # linker flag which includes ${@} (the target file's name).
  set CMD [subst $cmd]
}

# Check the SQLite TCL extension that is loaded by default by this running
# TCL interpreter to see if it has the same SQLITE_SOURCE_ID as the source
# code in the directory holding this script.
#
if {$versioncheck} {
  if {[catch {package require sqlite3} msg]} {
    puts stderr "No SQLite TCL extension available: $msg"
    exit 1
  }
  sqlite3 db :memory:
  set extvers [db one {SELECT sqlite_source_id()}]
  db close
  set fd [open sqlite3.h rb]
  set sqlite3h [read $fd]
  close $fd
  regexp {#define SQLITE_SOURCE_ID +"([^"]+)"} $sqlite3h all srcvers
  set srcvers [string range $srcvers 0 78]
  set extvers [string range $extvers 0 78]
  if {$srcvers==$extvers} {
    puts "source code and extension versions aligned:\n$extvers"
    exit 0
  }
  puts stderr "source code and extension versions differ"
  puts stderr "source: $srcvers\nextension: $extvers"
  exit 1
}

# Show information about prior installs
#
if {$infoonly} {
  set cnt 0
  foreach dir $auto_path {
    foreach subdir [glob -nocomplain -types d $dir/sqlite3*] {
      if {[file exists $subdir/pkgIndex.tcl]} {
        puts $subdir
        incr cnt
      }
    }
  }
  if {$cnt==0} {
    puts "no current installations of the SQLite TCL extension"
  }
  exit
}

# Uninstall the extension
#
if {$uninstall} {
  set cnt 0
  foreach dir $auto_path {
    if {[file isdirectory $dir/sqlite$VERSION]} {
      incr cnt
      if {![file writable $dir] || ![file writable $dir/sqlite$VERSION]} {
        puts "cannot uninstall $dir/sqlite$VERSION - permission denied"
      } else {
        puts "uninstalling $dir/sqlite$VERSION..."
        file delete -force $dir/sqlite$VERSION
      }
    }
  }
  if {$cnt==0} {
    puts "nothing to uninstall"
  }
  exit
}

if {$install} {
  # Figure out where the extension will be installed.  Put the extension
  # in the first writable directory on $auto_path.
  #
  set DEST {}
  foreach dir $auto_path {
    if {[string match //*:* $dir]} {
      # We can't install to //zipfs: paths
      continue
    } elseif {"" ne $DESTDIR && ![file writable $DESTDIR]} {
      # In the common case, ${DESTDIR}${dir} will not exist when we
      # get to this point of the installation, and the "is writable?"
      # check just below this will fail for that case.
      #
      # Assumption made for simplification's sake: if ${DESTDIR} is
      # not writable, no part of the remaining path will
      # be. ${DESTDIR} is typically used by OS package maintainers,
      # not normal installations, and it "shouldn't" ever happen that
      # the DESTDIR is read-only while the target ${DESTDIR}${prefix}
      # is not, as it's typical for such installations to create
      # ${prefix} on-demand under ${DESTDIR}.
      break
    }
    set dir ${DESTDIR}$dir
    if {[file writable $dir] || "" ne $DESTDIR} {
      # the dir will be created later ^^^^^^^^
      set DEST $dir
      break
    } elseif {[glob -nocomplain $dir/sqlite3*/pkgIndex.tcl]!=""} {
      set conflict [lindex [glob $dir/sqlite3*/pkgIndex.tcl] 0]
      puts "Unable to install. There is already a conflicting version"
      puts "of the SQLite TCL Extension that cannot be overwritten at\n"
      puts "   [file dirname $conflict]\n"
      puts "Consider running using sudo to work around this problem."
      exit 1
    }
  }
  if {$DEST==""} {
    puts "None of the directories on \$auto_path are writable by this process,"
    puts "so the installation cannot take place.  Consider running using sudo"
    puts "to work around this problem.\n"
    puts "These are the (unwritable) \$auto_path directories:\n"
    foreach dir $auto_path {
      puts "  *  ${DESTDIR}$dir"
    }
    exit 1
  }
}

if {$build} {
  # Generate the pkgIndex.tcl file
  #
  puts "generating pkgIndex.tcl..."
  set fd [open pkgIndex.tcl w]
  puts $fd [subst -nocommands {# -*- tcl -*-
# Tcl package index file, version ???
#
package ifneeded sqlite3 $VERSION \\
    [list load [file join \$dir $OUT] Sqlite3]
}]
  close $fd

  # Generate and execute the command with which to do the compilation.
  #
  set cmd "$CMD -DUSE_TCL_STUBS tclsqlite3.c -o $OUT [join $LIBS { }]"
  puts $cmd
  file delete -force $OUT
  catch {exec {*}$cmd} errmsg
  if {$errmsg!="" && ![file exists $OUT]} {
    puts $errmsg
    exit 1
  }
}


if {$install} {
  # Install the extension
  set DEST2 $DEST/sqlite$VERSION
  file mkdir $DEST2
  puts "installing $DEST2/pkgIndex.tcl"
  file copy -force pkgIndex.tcl $DEST2
  puts "installing $DEST2/$OUT"
  file copy -force $OUT $DEST2
}
