# Tests for JNI code. # Compile a single C file and produce a .so file. OPTIONS is a list # of options to pass to the compiler. Returns 0 on failure, 1 on # success. proc gcj_jni_compile_c_to_so {file {options {}}} { global srcdir set name [file rootname [file tail $file]] set soname lib${name}.so lappend options "additional_flags=-shared -fPIC" # Find the generated header. lappend options "additional_flags=-I. -I.." # Find jni.h. lappend options "additional_flags=-I$srcdir/../include" set x [libjava_prune_warnings \ [target_compile $file $soname executable $options]] if {$x != ""} { verbose "target_compile failed: $x" 2 fail "$name.c compilation" return 0 } pass "$name.c compilation" return 1 } # Build a header file from a .class file. Return 0 on failure. proc gcj_jni_build_header {file} { set gcjh [find_gcjh] set file [file rootname $file] set x [string trim [libjava_prune_warnings \ [lindex [local_exec "$gcjh -jni $file" "" "" 300] 1]]] if {$x != ""} { verbose "local_exec failed: $x" 2 fail "$file header generation" return 0 } pass "$file header generation" return 1 } # Invoke the program and see what happens. Return 0 on failure. proc gcj_invoke {program expectFile ld_library_additions} { global env set lib_path $env(LD_LIBRARY_PATH) set newval . if {[llength $ld_library_additions] > 0} { append newval :[join $ld_library_additions :] } append newval :$lib_path setenv LD_LIBRARY_PATH $newval setenv SHLIB_PATH $newval verbose "LD_LIBRARY_PATH=$env(LD_LIBRARY_PATH)" set result [libjava_load ./$program] set status [lindex $result 0] set output [lindex $result 1] # Restore setting setenv LD_LIBRARY_PATH $lib_path setenv SHLIB_PATH $lib_path if {$status != "pass"} { verbose "got $output" fail "$program run" untested "$program output" return 0 } set id [open $expectFile r] set expected [read $id] close $id if {! [string compare $output $expected]} { pass "$program output" return 1 } else { fail "$program output" return 0 } } # Do all the work for a single JNI test. Return 0 on failure. proc gcj_jni_test_one {file} { global runtests # The base name. We use it for several purposes. set main [file rootname [file tail $file]] if {! [runtest_file_p $runtests $main]} { # Simply skip it. return 1 } if {! [bytecompile_file $file [pwd]]} { fail "bytecompile $file" # FIXME - should use `untested' on all remaining tests. # But that is hard. return 0 } pass "bytecompile $file" set bytefile [file rootname [file tail $file]].class if {! [gcj_jni_build_header $bytefile]} { # FIXME return 0 } set cfile [file rootname $file].c set cxxflags "" set cxxldlibflags {} # If there is no `.c' file, assume there is a `.cc' file. if {! [file exists $cfile]} { set cfile [file rootname $file].cc set cxxflaglist {} foreach arg [split [libjava_find_lib libstdc++-v3/src stdc++] " "] { switch -glob -- $arg { "-L*" { set arg [string range $arg 2 end] lappend cxxldlibflags $arg # Strip the `.libs' directory; we link with libtool which # doesn't need it. set arg "-L[file dirname $arg]" } } lappend cxxflaglist $arg } lappend cxxflaglist "-lstdc++" set cxxflags [join $cxxflaglist] } if {! [gcj_jni_compile_c_to_so $cfile]} { # FIXME return 0 } # We use -l$main because the .so is named the same as the main # program. set args [list "additional_flags=-fjni -L. -l$main $cxxflags"] if {! [gcj_link $main $main $file $args]} { # FIXME return 0 } if {! [gcj_invoke $main [file rootname $file].out $cxxldlibflags]} { # FIXME return 0 } # When we succeed we remove all our clutter. eval gcj_cleanup [glob -nocomplain -- ${main}.*] [list $main lib${main}.so] return 1 } # Run the JNI tests. proc gcj_jni_run {} { global srcdir subdir global build_triplet host_triplet # For now we only test JNI on native builds. if {$build_triplet == $host_triplet} { catch { lsort [glob -nocomplain ${srcdir}/${subdir}/*.java] } srcfiles foreach x $srcfiles { gcj_jni_test_one $x } } else { verbose "JNI tests not run in cross-compilation environment" } } gcj_jni_run