#!/usr/bin/env jimsh

# Separate command line arguments into options and source files
set opts {}
set sources {}

proc usage {{msg {}}} {
	puts stderr "Usage: build-jim-ext ?--notest? ?--install? ?--static? ?cc-options? ?-o modname? sources..."
	if {$msg ne ""} {
		puts stderr \n$msg
	}
	exit 1
}

proc readfile {filename {default_value ""}} {
	set result $default_value
	catch {
		set f [open $filename]
		set result [$f read -nonewline]
		$f close
	}
	return $result
}

set linker "cc"
set testmod 1
set install 0
set static 0
set verbose 0
set keep 0
set includepaths {}
set libpaths {}
set libs {}
for {set i 0} {$i < [llength $argv]} {incr i} {
	set arg [lindex $argv $i]
	switch -glob -- $arg {
		*.c {
			lappend sources $arg
		}
		*.cpp {
			lappend sources $arg
			set linker "c++"
		}
		--notest {
			set testmod 0
		}
		--install {
			set install 1
		}
		--static {
			set static 1
		}
		--verbose {
			set verbose 1
		}
		--keep {
			set keep 1
		}
		--help {
			usage "Easily builds dynamic (loadable) modules for jim"
		}
		-o {
			incr i
			set modname [file rootname [lindex $argv $i]]
			if {$modname eq ""} {
				usage "Option -o requires an argument"
			}
		}
		-I* {
			lappend includepaths $arg
			if {$arg eq "-I"} {
				lappend includepaths [lindex $argv $i]
			}
		}
		-L* {
			lappend libpaths $arg
			if {$arg eq "-L"} {
				lappend libpaths [lindex $argv $i]
			}
		}
		-l* {
			lappend libs $arg
		}
		-* {
			lappend opts $arg
		}
		default {
			usage "Unexpected '$arg'"
		}
	}
}

if {$sources eq ""} {
	usage "No sources provided"
}
if {![info exists modname]} {
	set modname [file rootname [file tail [lindex $sources 0]]]
	# Remove jim- prefix if one exists
	regsub "^jim-" $modname "" modname
}

if {$static} {
	set target libjim-$modname.a
} else {
	set target $modname.so
}
puts "Building $target from $sources\n"

# Now add the Jim location after any user include paths
lappend includepaths -I/usr/local/include/jim

set CPPFLAGS "-D_GNU_SOURCE"

set ljim ""
set shobj_cflags ""
set shobj_ldflags ""
if {!$static} {
	set shobj_cflags "-fpic"
	if {"@JIM_STATICLIB@" eq "1"} {
		puts stderr "Warning: libjim is static. Dynamic module may not work on some platforms.\n"
		set shobj_ldflags "-shared"
	} else {
		# If shared, link against the shared libjim to resolve symbols
		set ljim -ljim
		set shobj_ldflags "-shared"
	}
}

set objs {}
foreach source $sources {
	set obj [file rootname [file tail $source]].o
	if {[string match *.c $source]} {
		set compiler "cc"
	} else {
		set compiler "c++"
	}
	set compile "$compiler -O2 -pipe $CPPFLAGS $shobj_cflags $includepaths $opts -c -o $obj $source"
	puts "Compile: $obj"
	lappend objs $obj
	flush stdout
	set rc [catch {
		if {$verbose} {
			puts $compile
		}
		exec 2>jimerr.out {*}$compile
	} msg]

	set errmsg [readfile jimerr.out]
	file delete jimerr.out

	if {$rc} {
		if {!$verbose} {
			puts stderr $compile
		}
		puts stderr $msg
		if {$errmsg ne ""} {
			puts stderr $errmsg
		}
		file delete {*}$objs
		exit 1
	} else {
		if {$errmsg ne ""} {
			puts $errmsg
		}
	}
}

if {$static} {
	set ar "ar cq $target $objs"
	set ranlib "ranlib $target"

	puts "Ar:      $target"
	set rc [catch {
		file delete $target
		exec {*}$ar
		exec {*}$ranlib
		if {$verbose} {
			puts stderr $ar
		}
	} msg]

	file delete {*}$objs

	if {$rc} {
		puts stderr $ar
		puts stderr $ranlib
		puts stderr $msg
		file delete $target
		exit 1
	}
} else {
	# Add the standard location after any user lib paths
	lappend libpaths -L/usr/local/lib

	set link "$linker -O2 -pipe  $shobj_ldflags $libpaths $opts -o $target $objs $ljim  $libs"

	puts "Link:    $target"
	set rc [catch {
		if {$verbose} {
			puts stderr $link
		}
		exec 2>jimerr.out {*}$link
	} msg]

	set errmsg [readfile jimerr.out]
	file delete jimerr.out

	if {!$keep} {
		file delete {*}$objs
	}

	if {$rc} {
		file delete $target
		puts stderr $link
		puts stderr $msg
		if {$errmsg ne ""} {
			puts stderr $errmsg
		}
		exit 1
	}
	if {$errmsg ne ""} {
		puts $errmsg
	}

	if {$testmod} {
		# Now, is testing even possible?
		# We must be running a compatible jimsh with the load command at least
		set testmod 0
		set rc [catch {
			# This will avoid attempting on Tcl and on jimsh without load
			# How to tell if we are cross compiling?
			if {[info version] > 0.73 && [exists -command load]} {
				set testmod 1
			}
		} msg]
	}

	set rc [catch {
		if {$testmod} {
			puts "Test:    load $target"
			load ./$target
		}
		if {$install} {
			set dest [env DESTDIR ""]/usr/local/lib/jim
			puts "Install: $target => $dest"
			file mkdir $dest
			file copy $target $dest/$target
		}
		puts "\nSuccess!"
	} msg]
	if {$rc} {
		puts stderr $msg
		exit 1
	}
}
