#!/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? ?--cross? ?--install? ?--static? ?cc-options? ?-o modname? sources..." if {$msg ne ""} { puts stderr \n$msg } exit 1 } set linker "@CC@" set testmod 1 set cross @cross_compiling@ 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 "@CXX@" } --notest { # Don't test to see if the module can be loaded set testmod 0 } --cross { # Don't use standard include/lib paths if cross compiling set cross 1 } --install { # Install to $DESTDIR/@prefix@/lib/jim set install 1 } --static { # Build a static extension that can be linked set static 1 } --verbose { set verbose 1 } --keep { # Don't remove intermediate files 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" if {!$cross} { # If not cross compiling, add the standard location after any user include paths lappend includepaths -I@prefix@/include } # Work around Tcl's strange behaviour of exec failing if stderr is produced # proc exec-catch {verbose cmdlist} { if {$verbose} { puts [join $cmdlist] } flush stdout set rc [catch { exec {*}$cmdlist } msg errinfo] # Handle failed case. # Note that Tcl returns rc=1 if there is any stderr, # even if the exit code is 0 if {$rc} { if {[dict get $errinfo -errorcode] ne "NONE"} { if {!$verbose} { puts stderr [join $cmdlist] } puts stderr $msg return 1 } } if {$msg ne ""} { puts stderr $msg } return 0 } set CPPFLAGS "-D_GNU_SOURCE" set ljim "" set shobj_cflags "" set shobj_ldflags "" if {!$static} { set shobj_cflags "@SHOBJ_CFLAGS@" if {"@JIM_STATICLIB@" eq "1"} { puts stderr "Warning: libjim is static. Dynamic module may not work on some platforms.\n" set shobj_ldflags "@SHOBJ_LDFLAGS@" } else { # If shared, link against the shared libjim to resolve symbols set ljim -ljim set shobj_ldflags "@SHOBJ_LDFLAGS_R@" } } set objs {} foreach source $sources { set obj [file rootname [file tail $source]].o if {[string match *.c $source]} { set compiler "@CC@" } else { set compiler "@CXX@" } set compile "$compiler @CFLAGS@ $CPPFLAGS $shobj_cflags $includepaths $opts -c -o $obj $source" puts "Compile: $obj" lappend objs $obj set rc [exec-catch $verbose $compile] if {$rc} { file delete {*}$objs exit $rc } } if {$static} { set ar "@AR@ cq $target $objs" set ranlib "@RANLIB@ $target" puts "Ar: $target" set rc [exec-catch $verbose $ar] if {rc == 0} { set rc [exec-catch $verbose $ranlib] } file delete {*}$objs if {$rc} { file delete $target exit $rc } } else { if {!$cross} { # If not cross compiling, add the standard location after any user lib paths lappend libpaths -L@prefix@/lib } set link "$linker @CFLAGS@ @LDFLAGS@ $shobj_ldflags $libpaths $opts -o $target $objs $ljim @LIBS@ $libs" puts "Link: $target" set rc [exec-catch $verbose $link] if {!$keep} { file delete {*}$objs } if {$rc} { file delete $target exit $rc } if {$testmod && !$cross} { # 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 if {[info version] > 0.73 && [exists -command load]} { set testmod 1 } } msg] } set rc [catch { if {$testmod && !$cross} { puts "Test: load $target" load ./$target } if {$install} { set dest [env DESTDIR ""]@prefix@/lib/jim puts "Install: $target => $dest" file mkdir $dest file copy $target $dest/$target } puts "\nSuccess!" } msg] if {$rc} { puts stderr $msg exit 1 } }