#!/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 --destdir DIR Installation root (used by "make install DESTDIR=...") Other options are retained and passed through into the compiler.} set build 1 set install 1 set uninstall 0 set infoonly 0 set CC {} set OPTS {} set DESTDIR ""; # --destdir "$(DESTDIR)" 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 uninstall 1 } elseif {$a0=="--info"} { set build 0 set install 0 set infoonly 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 {[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)=="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 { # 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 } } # Read the tclConfig.sh file into the $tclConfig variable # #puts "using $LIBDIR/tclConfig.sh" set fd [open $LIBDIR/tclConfig.sh 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 set LIBS {} regexp {TCL_STUB_LIB_SPEC='([^']+)'} $tclConfig all LIBS 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='([^']+)'} $tclConfig all cmd set LDFLAGS "$INC -DUSE_TCL_STUBS" if {[string length $OPTS]>1} { append LDFLAGS $OPTS } if {$TCLMAJOR>8} { set OUT libtcl9sqlite$VERSION.$SUFFIX } else { set OUT libsqlite$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] } # 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 tclsqlite3.c -o $OUT $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 }