| 1 | # Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003 Free Software Foundation
|
|---|
| 2 |
|
|---|
| 3 | load_lib "libgloss.exp"
|
|---|
| 4 |
|
|---|
| 5 | # GCJ_UNDER_TEST is the compiler under test.
|
|---|
| 6 |
|
|---|
| 7 | global tmpdir
|
|---|
| 8 |
|
|---|
| 9 | if ![info exists tmpdir] {
|
|---|
| 10 | set tmpdir "/tmp"
|
|---|
| 11 | }
|
|---|
| 12 |
|
|---|
| 13 | # This is like `prune_warnings', but it also prunes away a warning
|
|---|
| 14 | # from the bytecode front end that we don't care about.
|
|---|
| 15 | proc libjava_prune_warnings {text} {
|
|---|
| 16 | set text [prune_warnings $text]
|
|---|
| 17 | set tlist [split $text \n]
|
|---|
| 18 | set len [llength $tlist]
|
|---|
| 19 | for {set i [expr {$len - 1}]} {$i >= 2} {incr i -1} {
|
|---|
| 20 | if {[string match "*unreachable bytecode*" [lindex $tlist $i]]} {
|
|---|
| 21 | # Delete this line, all other unreachable warnings and the previous
|
|---|
| 22 | # two lines containing the method and class.
|
|---|
| 23 | set j [expr {$i - 1}]
|
|---|
| 24 | while {[string match "*unreachable bytecode*" [lindex $tlist $j]]} {
|
|---|
| 25 | incr j -1
|
|---|
| 26 | }
|
|---|
| 27 | incr j -1
|
|---|
| 28 | set tlist [lreplace $tlist $j $i]
|
|---|
| 29 | set i $j
|
|---|
| 30 | }
|
|---|
| 31 | }
|
|---|
| 32 | return [join $tlist \n]
|
|---|
| 33 | }
|
|---|
| 34 |
|
|---|
| 35 | # This is like `target_compile' but it does some surgery to work
|
|---|
| 36 | # around stupid DejaGNU bugs. In particular DejaGNU has very poor
|
|---|
| 37 | # quoting, so for instance a `$' will be re-evaluated at spawn time.
|
|---|
| 38 | # We don't want that.
|
|---|
| 39 | proc libjava_tcompile {source destfile type options} {
|
|---|
| 40 | # This strange-looking expression really does quote the `$'.
|
|---|
| 41 | regsub -all -- {\$} $source {\$} source
|
|---|
| 42 | regsub -all -- {\$} $destfile {\$} destfile
|
|---|
| 43 | return [target_compile $source $destfile $type $options]
|
|---|
| 44 | }
|
|---|
| 45 |
|
|---|
| 46 | # Read an `xfail' file if it exists. Returns a list of xfail tokens.
|
|---|
| 47 | proc libjava_read_xfail {file} {
|
|---|
| 48 | if {! [file exists $file]} {
|
|---|
| 49 | return ""
|
|---|
| 50 | }
|
|---|
| 51 | set fd [open $file r]
|
|---|
| 52 | set tokens [string trim [read $fd]]
|
|---|
| 53 | close $fd
|
|---|
| 54 | return $tokens
|
|---|
| 55 | }
|
|---|
| 56 |
|
|---|
| 57 | # Find a particular executable. FIXME: this relies on DejaGnu
|
|---|
| 58 | # internals. These should probably be exposed in a better way.
|
|---|
| 59 | proc libjava_find_program {prog} {
|
|---|
| 60 | global tool_root_dir
|
|---|
| 61 |
|
|---|
| 62 | set file [lookfor_file $tool_root_dir $prog]
|
|---|
| 63 | if { $file == "" } {
|
|---|
| 64 | set file [lookfor_file $tool_root_dir gcc/$prog];
|
|---|
| 65 | }
|
|---|
| 66 | if {$file == ""} {
|
|---|
| 67 | set file $prog
|
|---|
| 68 | }
|
|---|
| 69 | return $file
|
|---|
| 70 | }
|
|---|
| 71 |
|
|---|
| 72 | # Find `jv-scan'.
|
|---|
| 73 | proc find_jvscan {} {
|
|---|
| 74 | return [libjava_find_program jv-scan]
|
|---|
| 75 | }
|
|---|
| 76 |
|
|---|
| 77 | # Find `gcjh'.
|
|---|
| 78 | proc find_gcjh {} {
|
|---|
| 79 | return [libjava_find_program gcjh]
|
|---|
| 80 | }
|
|---|
| 81 |
|
|---|
| 82 | proc find_javac {} {
|
|---|
| 83 | global SUN_JAVAC GCJ_UNDER_TEST env libgcj_jar
|
|---|
| 84 | # If JDK doesn't run on your platform but some other
|
|---|
| 85 | # JDK-compatible javac does, you may set SUN_JAVAC to point to it.
|
|---|
| 86 | # One of the most important properties of a SUN_JAVAC is that it
|
|---|
| 87 | # must create class-files even for classes that have not been
|
|---|
| 88 | # specified in the command line, but that were needed to compile
|
|---|
| 89 | # those that have. For example, Pizza won't do it, but you can
|
|---|
| 90 | # use `kaffe sun.tools.javac.Main', if you have Sun's classes.zip
|
|---|
| 91 | # in the kaffe's default search path.
|
|---|
| 92 | if {![info exists SUN_JAVAC]} {
|
|---|
| 93 | if {[info exists env(SUN_JAVAC)]} {
|
|---|
| 94 | set SUN_JAVAC $env(SUN_JAVAC)
|
|---|
| 95 | } else {
|
|---|
| 96 | set SUN_JAVAC "$GCJ_UNDER_TEST -C -I$libgcj_jar"
|
|---|
| 97 | }
|
|---|
| 98 | }
|
|---|
| 99 | return $SUN_JAVAC
|
|---|
| 100 | }
|
|---|
| 101 |
|
|---|
| 102 | proc bytecompile_file { file objdir {classpath {}} } {
|
|---|
| 103 | global env
|
|---|
| 104 | set dirname [file dirname $file]
|
|---|
| 105 |
|
|---|
| 106 | set javac [find_javac]
|
|---|
| 107 | if {$classpath != ""} then {
|
|---|
| 108 | set env(CLASSPATH) $classpath
|
|---|
| 109 | }
|
|---|
| 110 | set here [pwd]
|
|---|
| 111 | cd $dirname
|
|---|
| 112 | if {[catch {
|
|---|
| 113 | set q [eval exec "$javac [list $file] -d $objdir 2>@ stdout"]
|
|---|
| 114 | } msg]} then {
|
|---|
| 115 | verbose "couldn't compile $file: $msg"
|
|---|
| 116 | set r 0
|
|---|
| 117 | } else {
|
|---|
| 118 | set r 1
|
|---|
| 119 | }
|
|---|
| 120 | cd $here
|
|---|
| 121 | return $r
|
|---|
| 122 | }
|
|---|
| 123 |
|
|---|
| 124 | set libjava_initialized 0
|
|---|
| 125 |
|
|---|
| 126 | #
|
|---|
| 127 | # Build the status wrapper library as needed.
|
|---|
| 128 | #
|
|---|
| 129 | proc libjava_init { args } {
|
|---|
| 130 | global wrapper_file;
|
|---|
| 131 | global wrap_compile_flags;
|
|---|
| 132 | global libjava_initialized libjava_uses_threads
|
|---|
| 133 | global GCJ_UNDER_TEST
|
|---|
| 134 | global TOOL_EXECUTABLE
|
|---|
| 135 | global original_ld_library_path
|
|---|
| 136 | global env objdir
|
|---|
| 137 | global env libgcj_jar
|
|---|
| 138 | global tool_root_dir
|
|---|
| 139 | global libjava_libgcc_s_path
|
|---|
| 140 |
|
|---|
| 141 | if { $libjava_initialized == 1 } { return; }
|
|---|
| 142 |
|
|---|
| 143 | if ![info exists GCJ_UNDER_TEST] {
|
|---|
| 144 | if [info exists TOOL_EXECUTABLE] {
|
|---|
| 145 | set GCJ_UNDER_TEST $TOOL_EXECUTABLE;
|
|---|
| 146 | } else {
|
|---|
| 147 | if [info exists env(GCJ)] {
|
|---|
| 148 | set GCJ_UNDER_TEST $env(GCJ)
|
|---|
| 149 | } else {
|
|---|
| 150 | set GCJ_UNDER_TEST "[find_gcj]"
|
|---|
| 151 | }
|
|---|
| 152 | }
|
|---|
| 153 | }
|
|---|
| 154 |
|
|---|
| 155 | # Find the libgcj jar file.
|
|---|
| 156 | set libgcj_jar [glob $objdir/../libgcj-*.jar]
|
|---|
| 157 | verbose "jar file is $libgcj_jar"
|
|---|
| 158 |
|
|---|
| 159 | # FIXME: This finds libgcj.spec for the default multilib.
|
|---|
| 160 | # If thread models differ between multilibs, this has to be moved
|
|---|
| 161 | # to libjava_arguments
|
|---|
| 162 | set specdir [libjava_find_spec]
|
|---|
| 163 |
|
|---|
| 164 | # The -B is so we find libgcj.spec.
|
|---|
| 165 | set text [eval exec "$GCJ_UNDER_TEST -B$specdir -v 2>@ stdout"]
|
|---|
| 166 | regexp -- "Thread model: (\[^\n\]+)\n" $text ignore model
|
|---|
| 167 | set libjava_uses_threads [expr {! ($model == "no"
|
|---|
| 168 | || $model == "none"
|
|---|
| 169 | || $model == "single")}]
|
|---|
| 170 |
|
|---|
| 171 | # Always set encoding used by gcj.
|
|---|
| 172 | append GCJ_UNDER_TEST " --encoding=UTF-8"
|
|---|
| 173 |
|
|---|
| 174 | if [info exists env(LD_LIBRARY_PATH)] {
|
|---|
| 175 | set original_ld_library_path $env(LD_LIBRARY_PATH)
|
|---|
| 176 | } else {
|
|---|
| 177 | if [info exists env(SHLIB_PATH)] {
|
|---|
| 178 | set original_ld_library_path $env(SHLIB_PATH)
|
|---|
| 179 | } else {
|
|---|
| 180 | set original_ld_library_path ""
|
|---|
| 181 | }
|
|---|
| 182 | }
|
|---|
| 183 |
|
|---|
| 184 | set wrapper_file "";
|
|---|
| 185 | set wrap_compile_flags "";
|
|---|
| 186 | if [target_info exists needs_status_wrapper] {
|
|---|
| 187 | set result [build_wrapper "testglue.o"];
|
|---|
| 188 | if { $result != "" } {
|
|---|
| 189 | set wrapper_file [lindex $result 0];
|
|---|
| 190 | set wrap_compile_flags [lindex $result 1];
|
|---|
| 191 | } else {
|
|---|
| 192 | warning "Status wrapper failed to build."
|
|---|
| 193 | }
|
|---|
| 194 | }
|
|---|
| 195 |
|
|---|
| 196 | # Finally, add the gcc build directory so that we can find the
|
|---|
| 197 | # shared libgcc. This, like much of dejagnu, is hideous.
|
|---|
| 198 | set libjava_libgcc_s_path {}
|
|---|
| 199 | set gccdir [lookfor_file $tool_root_dir gcc/libgcc_s.so]
|
|---|
| 200 | if {$gccdir != ""} {
|
|---|
| 201 | set gccdir [file dirname $gccdir]
|
|---|
| 202 | lappend libjava_libgcc_s_path $gccdir
|
|---|
| 203 | set compiler ${gccdir}/xgcc
|
|---|
| 204 | if { [is_remote host] == 0 && [which $compiler] != 0 } {
|
|---|
| 205 | foreach i "[exec $compiler --print-multi-lib]" {
|
|---|
| 206 | set mldir ""
|
|---|
| 207 | regexp -- "\[a-z0-9=/\.-\]*;" $i mldir
|
|---|
| 208 | set mldir [string trimright $mldir "\;@"]
|
|---|
| 209 | if { "$mldir" == "." } {
|
|---|
| 210 | continue
|
|---|
| 211 | }
|
|---|
| 212 | if { [llength [glob -nocomplain ${gccdir}/${mldir}/libgcc_s*.so.*]] == 1 } {
|
|---|
| 213 | lappend libjava_libgcc_s_path "${gccdir}/${mldir}"
|
|---|
| 214 | }
|
|---|
| 215 | }
|
|---|
| 216 | }
|
|---|
| 217 | }
|
|---|
| 218 |
|
|---|
| 219 | set libjava_initialized 1
|
|---|
| 220 | }
|
|---|
| 221 |
|
|---|
| 222 | # Find a library. We know where libtool puts the actual libraries,
|
|---|
| 223 | # and we look there. The implementation is fairly hacky. We can't
|
|---|
| 224 | # compile with -nodefaultlibs, because that will also eliminate the
|
|---|
| 225 | # system libraries we need. In order to have gcj still work, it must
|
|---|
| 226 | # find the appropriate libraries so we must add -L options for their
|
|---|
| 227 | # paths. However we can't simply use those libraries; we still need
|
|---|
| 228 | # libtool for linking.
|
|---|
| 229 | # Don't return the the lib${name}.la files here, since this causes the
|
|---|
| 230 | # libraries to be linked twice: once as lib${name}.so and another time
|
|---|
| 231 | # via gcj's implicit -l${name}. This is both unnecessary and causes the
|
|---|
| 232 | # Solaris ld to warn: attempted multiple inclusion of file. This warning
|
|---|
| 233 | # is not ignored by the dejagnu framework and cannot be disabled.
|
|---|
| 234 | proc libjava_find_lib {dir name} {
|
|---|
| 235 | global base_dir
|
|---|
| 236 | set gp [get_multilibs]
|
|---|
| 237 | foreach sub {.libs _libs} {
|
|---|
| 238 | if {$gp != ""} {
|
|---|
| 239 | if {[file exists $gp/$dir/$sub/lib${name}.a]} then {
|
|---|
| 240 | # Just return the `-L' option. The library itself
|
|---|
| 241 | # will be picked up via the spec file.
|
|---|
| 242 | return "-L$gp/$dir/$sub"
|
|---|
| 243 | }
|
|---|
| 244 | }
|
|---|
| 245 | # Just return the `-L' option. The library itself will be
|
|---|
| 246 | # picked up via the spec file.
|
|---|
| 247 | set lib [findfile $base_dir/../../$dir/$sub/lib${name}.a \
|
|---|
| 248 | "-L$base_dir/../../$dir/$sub" \
|
|---|
| 249 | ""]
|
|---|
| 250 | if {$lib != ""} {
|
|---|
| 251 | return $lib
|
|---|
| 252 | }
|
|---|
| 253 | }
|
|---|
| 254 | return ""
|
|---|
| 255 | }
|
|---|
| 256 |
|
|---|
| 257 | # Find libgcj.spec. We need to use the file corresponding to the multilib
|
|---|
| 258 | # under test since they might differ. Append a trailing slash since this
|
|---|
| 259 | # is used with -B.
|
|---|
| 260 | proc libjava_find_spec {} {
|
|---|
| 261 | global objdir
|
|---|
| 262 | set gp [get_multilibs]
|
|---|
| 263 |
|
|---|
| 264 | if {[file exists $gp/libjava/libgcj.spec]} then {
|
|---|
| 265 | return "$gp/libjava/"
|
|---|
| 266 | }
|
|---|
| 267 | return "$objdir/../"
|
|---|
| 268 | }
|
|---|
| 269 |
|
|---|
| 270 | # Find `gij'.
|
|---|
| 271 | proc libjava_find_gij {} {
|
|---|
| 272 | global base_dir
|
|---|
| 273 | set gp [get_multilibs]
|
|---|
| 274 | if {$gp != ""} {
|
|---|
| 275 | set file $gp/libjava/gij
|
|---|
| 276 | } else {
|
|---|
| 277 | set file $base_dir/../gij
|
|---|
| 278 | }
|
|---|
| 279 |
|
|---|
| 280 | if {[file exists $file]} {
|
|---|
| 281 | return $file
|
|---|
| 282 | }
|
|---|
| 283 | return gij
|
|---|
| 284 | }
|
|---|
| 285 |
|
|---|
| 286 | # Remove a bunch of files.
|
|---|
| 287 | proc gcj_cleanup {args} {
|
|---|
| 288 | foreach file $args {
|
|---|
| 289 | if {[string match *.o $file]} {
|
|---|
| 290 | verbose "removing [file rootname $file].lo"
|
|---|
| 291 | file delete -force [file rootname $file].lo
|
|---|
| 292 | }
|
|---|
| 293 | file delete -force -- $file
|
|---|
| 294 | verbose "removing $file"
|
|---|
| 295 | }
|
|---|
| 296 | # It is simplest to do this instead of trying to figure out what
|
|---|
| 297 | # bits in .libs ought to be removed.
|
|---|
| 298 | catch {system "rm -rf .libs"}
|
|---|
| 299 | }
|
|---|
| 300 |
|
|---|
| 301 | # Compute arguments needed for compiler. MODE is a libtool mode:
|
|---|
| 302 | # either compile or link.
|
|---|
| 303 | proc libjava_arguments {{mode compile}} {
|
|---|
| 304 | global base_dir
|
|---|
| 305 | global LIBJAVA
|
|---|
| 306 | global LIBGC
|
|---|
| 307 | global LIBQTHREADS
|
|---|
| 308 | global LIBZ
|
|---|
| 309 | global srcdir subdir objdir
|
|---|
| 310 | global TOOL_OPTIONS
|
|---|
| 311 | global GCJ_UNDER_TEST
|
|---|
| 312 | global tmpdir
|
|---|
| 313 | global runtests
|
|---|
| 314 | global env
|
|---|
| 315 | global tool_root_dir
|
|---|
| 316 | global libgcj_jar
|
|---|
| 317 | global libjava_libgcc_s_path
|
|---|
| 318 |
|
|---|
| 319 | if [info exists LIBJAVA] {
|
|---|
| 320 | set libjava $LIBJAVA;
|
|---|
| 321 | } else {
|
|---|
| 322 | set libjava [libjava_find_lib libjava gcj]
|
|---|
| 323 | }
|
|---|
| 324 |
|
|---|
| 325 | if [info exists LIBGC] {
|
|---|
| 326 | set libgc $LIBGC;
|
|---|
| 327 | } else {
|
|---|
| 328 | set libgc [libjava_find_lib boehm-gc gcjgc]
|
|---|
| 329 | }
|
|---|
| 330 |
|
|---|
| 331 | if [info exists LIBQTHREADS] {
|
|---|
| 332 | set libqthreads $LIBQTHREADS
|
|---|
| 333 | } else {
|
|---|
| 334 | set libqthreads [libjava_find_lib qthreads gcjcoop]
|
|---|
| 335 | }
|
|---|
| 336 |
|
|---|
| 337 | if [info exists LIBZ] {
|
|---|
| 338 | set libz $LIBZ
|
|---|
| 339 | } else {
|
|---|
| 340 | set libz [libjava_find_lib zlib zgcj]
|
|---|
| 341 | }
|
|---|
| 342 |
|
|---|
| 343 | # FIXME: there's no way to determine whether -lpthread is
|
|---|
| 344 | # required. We should get this info from configure, or it should
|
|---|
| 345 | # just be in the compiler driver.
|
|---|
| 346 |
|
|---|
| 347 | verbose "using LIBJAVA = $libjava" 2
|
|---|
| 348 | verbose "using LIBGC = $libgc" 2
|
|---|
| 349 | verbose "using LIBQTHREADS = $libqthreads" 2
|
|---|
| 350 | verbose "using LIBZ = $libz" 2
|
|---|
| 351 | set args ""
|
|---|
| 352 |
|
|---|
| 353 | # Basically we want to build up a colon separated path list from
|
|---|
| 354 | # the value of $libjava.
|
|---|
| 355 |
|
|---|
| 356 | set lpath {}
|
|---|
| 357 | foreach dir [list $libjava $libgc $libz] {
|
|---|
| 358 | foreach item [split $dir " "] {
|
|---|
| 359 | switch -glob -- $item {
|
|---|
| 360 | "-L*" {
|
|---|
| 361 | lappend lpath [string range $item 2 end]
|
|---|
| 362 | }
|
|---|
| 363 | }
|
|---|
| 364 | }
|
|---|
| 365 | }
|
|---|
| 366 |
|
|---|
| 367 | set lpath [concat $lpath $libjava_libgcc_s_path]
|
|---|
| 368 | set ld_library_path [join $lpath :]
|
|---|
| 369 |
|
|---|
| 370 | # That's enough to make things work for the normal case.
|
|---|
| 371 | # If we wanted to handle an arbitrary value of libjava,
|
|---|
| 372 | # then we'd have to do a lot more work.
|
|---|
| 373 |
|
|---|
| 374 | # Set variables the dynamic linker looks at.
|
|---|
| 375 | global original_ld_library_path
|
|---|
| 376 | setenv LD_LIBRARY_PATH "$ld_library_path:$original_ld_library_path"
|
|---|
| 377 | setenv SHLIB_PATH "$ld_library_path:$original_ld_library_path"
|
|---|
| 378 |
|
|---|
| 379 | verbose "LD_LIBRARY_PATH = $env(LD_LIBRARY_PATH)"
|
|---|
| 380 |
|
|---|
| 381 | # Set the CLASSPATH environment variable
|
|---|
| 382 | verbose "CLASSPATH is .:$srcdir/$subdir:$objdir:$libgcj_jar"
|
|---|
| 383 | global env
|
|---|
| 384 | set env(CLASSPATH) ".:$srcdir/$subdir:$objdir:$libgcj_jar"
|
|---|
| 385 |
|
|---|
| 386 | if {$mode == "link"} {
|
|---|
| 387 | global wrapper_file wrap_compile_flags;
|
|---|
| 388 | lappend args "additional_flags=$wrap_compile_flags";
|
|---|
| 389 | lappend args "libs=$wrapper_file";
|
|---|
| 390 | lappend args "libs=$libjava";
|
|---|
| 391 | lappend args "libs=$libgc";
|
|---|
| 392 | lappend args "libs=$libqthreads"
|
|---|
| 393 | lappend args "libs=$libz"
|
|---|
| 394 | lappend args debug
|
|---|
| 395 | }
|
|---|
| 396 |
|
|---|
| 397 | if { [target_info needs_status_wrapper]!="" && [info exists gluefile] } {
|
|---|
| 398 | lappend args "libs=${gluefile}"
|
|---|
| 399 | lappend args "ldflags=$wrap_flags"
|
|---|
| 400 | }
|
|---|
| 401 |
|
|---|
| 402 | if [info exists TOOL_OPTIONS] {
|
|---|
| 403 | lappend args "additional_flags=$TOOL_OPTIONS"
|
|---|
| 404 | }
|
|---|
| 405 |
|
|---|
| 406 | # Determine libgcj.spec corresponding to multilib under test.
|
|---|
| 407 | set specdir [libjava_find_spec]
|
|---|
| 408 |
|
|---|
| 409 | # Search for libtool. We need it to link.
|
|---|
| 410 | set found_compiler 0
|
|---|
| 411 | set d [absolute $objdir]
|
|---|
| 412 | foreach x {. .. ../.. ../../..} {
|
|---|
| 413 | if {[file exists $d/$x/libtool]} then {
|
|---|
| 414 | # We have to run silently to avoid DejaGNU lossage.
|
|---|
| 415 | lappend args \
|
|---|
| 416 | "compiler=$d/$x/libtool --silent --tag=GCJ --mode=$mode $GCJ_UNDER_TEST -B$specdir"
|
|---|
| 417 | set found_compiler 1
|
|---|
| 418 | break
|
|---|
| 419 | }
|
|---|
| 420 | }
|
|---|
| 421 | if {! $found_compiler} {
|
|---|
| 422 | # Append -B$specdir so that we find libgcj.spec before it
|
|---|
| 423 | # is installed.
|
|---|
| 424 | lappend args "compiler=$GCJ_UNDER_TEST -B$specdir"
|
|---|
| 425 | }
|
|---|
| 426 |
|
|---|
| 427 | # Avoid libtool wrapper scripts when possible.
|
|---|
| 428 | # but not if libtool warnings results in FAILs
|
|---|
| 429 | if {$mode == "link"} {
|
|---|
| 430 | if {! [istarget "*-*-cygwin*"] && ! [istarget "*-*-mingw*"] } {
|
|---|
| 431 | lappend args "additional_flags=-no-install"
|
|---|
| 432 | }
|
|---|
| 433 | }
|
|---|
| 434 |
|
|---|
| 435 | return $args
|
|---|
| 436 | }
|
|---|
| 437 |
|
|---|
| 438 | # Link a bunch of objects into a program. MAIN is the name of the
|
|---|
| 439 | # class holding `main'. Return 0 on failure.
|
|---|
| 440 | proc gcj_link {program main files {options {}}} {
|
|---|
| 441 | set arguments [libjava_arguments link]
|
|---|
| 442 | if {[llength $options]} {
|
|---|
| 443 | eval lappend arguments $options
|
|---|
| 444 | }
|
|---|
| 445 | lappend arguments "additional_flags=--main=$main"
|
|---|
| 446 | set x [libjava_prune_warnings \
|
|---|
| 447 | [libjava_tcompile $files $program executable $arguments]]
|
|---|
| 448 | if {$x != ""} {
|
|---|
| 449 | verbose "link failure: $x" 2
|
|---|
| 450 | fail "linking $program"
|
|---|
| 451 | setup_xfail "*-*-*"
|
|---|
| 452 | fail "running $program"
|
|---|
| 453 | return 0
|
|---|
| 454 | }
|
|---|
| 455 |
|
|---|
| 456 | pass "linking $program"
|
|---|
| 457 | return 1
|
|---|
| 458 | }
|
|---|
| 459 |
|
|---|
| 460 | # Invoke a program and check its output. EXECUTABLE is the program;
|
|---|
| 461 | # ARGS are the arguments to the program. Returns 1 if tests passed
|
|---|
| 462 | # (or things were left untested), 0 otherwise.
|
|---|
| 463 | proc libjava_invoke {errname testName optName executable inpfile resultfile args} {
|
|---|
| 464 | upvar $optName opts
|
|---|
| 465 |
|
|---|
| 466 | if {[info exists opts(no-exec)]} {
|
|---|
| 467 | if {[info exists opts(need-threads)]} {
|
|---|
| 468 | # This means we wanted to try to run it but we couldn't
|
|---|
| 469 | # because threads aren't supported. So we have to
|
|---|
| 470 | # generate an `untested'.
|
|---|
| 471 | untested "$errname execution - $testName"
|
|---|
| 472 | untested "$errname output - $testName"
|
|---|
| 473 | }
|
|---|
| 474 | return 1
|
|---|
| 475 | }
|
|---|
| 476 |
|
|---|
| 477 | set result [libjava_load $executable $args "$inpfile"]
|
|---|
| 478 | set status [lindex $result 0]
|
|---|
| 479 | set output [lindex $result 1]
|
|---|
| 480 | if {[info exists opts(xfail-exec)]} then {
|
|---|
| 481 | setup_xfail *-*-*
|
|---|
| 482 | }
|
|---|
| 483 | $status "$errname execution - $testName"
|
|---|
| 484 | if { $status != "pass" } {
|
|---|
| 485 | untested "$errname output - $testName"
|
|---|
| 486 | return 0
|
|---|
| 487 | }
|
|---|
| 488 |
|
|---|
| 489 | verbose "resultfile is $resultfile"
|
|---|
| 490 | set id [open $resultfile r]
|
|---|
| 491 | set expected ""
|
|---|
| 492 | append expected [read $id]
|
|---|
| 493 | regsub -all "\r" "$output" "" output
|
|---|
| 494 | regsub "\n*$" $expected "" expected
|
|---|
| 495 | regsub "\n*$" $output "" output
|
|---|
| 496 | regsub "^\n*" $expected "" expected
|
|---|
| 497 | regsub "^\n*" $output "" output
|
|---|
| 498 | regsub -all "\[ \t\]\[ \t\]*" $expected " " expected
|
|---|
| 499 | regsub -all "\[ \t\]*\n\n*" $expected "\n" expected
|
|---|
| 500 | regsub -all "\[ \t\]\[ \t\]*" $output " " output
|
|---|
| 501 | regsub -all "\[ \t\]*\n\n*" $output "\n" output
|
|---|
| 502 | verbose "expected is $expected"
|
|---|
| 503 | verbose "actual is $output"
|
|---|
| 504 | set passed 0
|
|---|
| 505 | if {[info exists opts(regexp_match)]} {
|
|---|
| 506 | if [regexp $expected $output] {
|
|---|
| 507 | set passed 1
|
|---|
| 508 | }
|
|---|
| 509 | } else {
|
|---|
| 510 | if { $expected == $output } {
|
|---|
| 511 | set passed 1
|
|---|
| 512 | }
|
|---|
| 513 | }
|
|---|
| 514 | if {[info exists opts(xfail-output)]} {
|
|---|
| 515 | setup_xfail *-*-*
|
|---|
| 516 | }
|
|---|
| 517 | if { $passed == 1 } {
|
|---|
| 518 | pass "$errname output - $testName"
|
|---|
| 519 | } else {
|
|---|
| 520 | fail "$errname output - $testName"
|
|---|
| 521 | }
|
|---|
| 522 | close $id
|
|---|
| 523 |
|
|---|
| 524 | return $passed
|
|---|
| 525 | }
|
|---|
| 526 |
|
|---|
| 527 | #
|
|---|
| 528 | # Run the test specified by srcfile and resultfile. compile_args and
|
|---|
| 529 | # exec_args are options telling this proc how to work.
|
|---|
| 530 | #
|
|---|
| 531 | proc test_libjava_from_source { options srcfile compile_args inpfile resultfile exec_args } {
|
|---|
| 532 | global base_dir
|
|---|
| 533 | global LIBJAVA
|
|---|
| 534 | global LIBGC
|
|---|
| 535 | global srcdir subdir objdir
|
|---|
| 536 | global TOOL_OPTIONS
|
|---|
| 537 | global GCJ_UNDER_TEST
|
|---|
| 538 | global tmpdir
|
|---|
| 539 | global runtests
|
|---|
| 540 |
|
|---|
| 541 | # Make opts into an array.
|
|---|
| 542 | set opts(_) x
|
|---|
| 543 | unset opts(_)
|
|---|
| 544 | foreach item $exec_args {
|
|---|
| 545 | set opts($item) x
|
|---|
| 546 | }
|
|---|
| 547 |
|
|---|
| 548 | # If we need threads and we don't have them then set the `no-exec'
|
|---|
| 549 | # flag. This is case is also handled specially later.
|
|---|
| 550 | if {[info exists opts(need-threads)]} {
|
|---|
| 551 | global libjava_uses_threads
|
|---|
| 552 | if {! $libjava_uses_threads} {
|
|---|
| 553 | set opts(no-exec) x
|
|---|
| 554 | }
|
|---|
| 555 | }
|
|---|
| 556 |
|
|---|
| 557 | set errname [file rootname [file tail $srcfile]]
|
|---|
| 558 | if {! [runtest_file_p $runtests $errname]} {
|
|---|
| 559 | return
|
|---|
| 560 | }
|
|---|
| 561 |
|
|---|
| 562 | if {[info exists opts(no-link)]} {
|
|---|
| 563 | set mode compile
|
|---|
| 564 | } else {
|
|---|
| 565 | set mode link
|
|---|
| 566 | }
|
|---|
| 567 | set args [libjava_arguments $mode]
|
|---|
| 568 | if {! [info exists opts(no-link)]} {
|
|---|
| 569 | # Add the --main flag
|
|---|
| 570 | lappend args "additional_flags=--main=[file rootname [file tail $srcfile]]"
|
|---|
| 571 | if { $compile_args != "" } {
|
|---|
| 572 | lappend args "additional_flags=$compile_args"
|
|---|
| 573 | }
|
|---|
| 574 | }
|
|---|
| 575 |
|
|---|
| 576 | regsub "^.*/(\[^/.\]+)\[.\]\[^/]*$" "$srcfile" "\\1" out
|
|---|
| 577 | set executable "${objdir}/$out"
|
|---|
| 578 | if {[info exists opts(no-link)]} {
|
|---|
| 579 | append executable ".o"
|
|---|
| 580 | set target object
|
|---|
| 581 | } else {
|
|---|
| 582 | # DOS/win32 targets default to .exe if no suffix is given
|
|---|
| 583 | # We then try to delete a file that doesn't exist. It is
|
|---|
| 584 | # simpler to add the suffix everywhere.
|
|---|
| 585 | append executable ".exe"
|
|---|
| 586 | set target executable
|
|---|
| 587 | }
|
|---|
| 588 | if { $compile_args != "" } {
|
|---|
| 589 | set errname "$errname $compile_args"
|
|---|
| 590 | }
|
|---|
| 591 |
|
|---|
| 592 | set removeList [list $executable]
|
|---|
| 593 |
|
|---|
| 594 | set x [libjava_prune_warnings \
|
|---|
| 595 | [libjava_tcompile $srcfile "$executable" $target $args]]
|
|---|
| 596 | if {[info exists opts(xfail-gcj)]} {
|
|---|
| 597 | setup_xfail *-*-*
|
|---|
| 598 | }
|
|---|
| 599 | if { $x != "" } {
|
|---|
| 600 | verbose "target_compile failed: $x" 2
|
|---|
| 601 |
|
|---|
| 602 | if {[info exists opts(shouldfail)]} {
|
|---|
| 603 | pass "$errname compilation from source"
|
|---|
| 604 | eval gcj_cleanup $removeList
|
|---|
| 605 | return
|
|---|
| 606 | }
|
|---|
| 607 |
|
|---|
| 608 | fail "$errname compilation from source"
|
|---|
| 609 | if {[info exists opts(xfail-gcj)]
|
|---|
| 610 | || ! [info exists opts(no-exec)]
|
|---|
| 611 | || [info exists opts(need-threads)]} {
|
|---|
| 612 | untested "$errname execution from source compiled test"
|
|---|
| 613 | untested "$errname output from source compiled test"
|
|---|
| 614 | }
|
|---|
| 615 | return
|
|---|
| 616 | }
|
|---|
| 617 | if {[info exists opts(shouldfail)]} {
|
|---|
| 618 | fail "$errname compilation from source"
|
|---|
| 619 | return
|
|---|
| 620 | }
|
|---|
| 621 | pass "$errname compilation from source"
|
|---|
| 622 |
|
|---|
| 623 | # Set up the options the way they are expected by libjava_invoke.
|
|---|
| 624 | if {[info exists opts(xfail-source-output)]} {
|
|---|
| 625 | set opts(xfail-output) x
|
|---|
| 626 | }
|
|---|
| 627 | if {[libjava_invoke $errname "source compiled test" opts $executable \
|
|---|
| 628 | $inpfile $resultfile]} {
|
|---|
| 629 | # Everything ok, so clean up.
|
|---|
| 630 | eval gcj_cleanup $removeList
|
|---|
| 631 | }
|
|---|
| 632 | }
|
|---|
| 633 |
|
|---|
| 634 | #
|
|---|
| 635 | # Run the test specified by srcfile and resultfile. compile_args and
|
|---|
| 636 | # exec_args are options telling this proc how to work.
|
|---|
| 637 | #
|
|---|
| 638 | proc test_libjava_from_javac { options srcfile compile_args inpfile resultfile exec_args } {
|
|---|
| 639 | global base_dir
|
|---|
| 640 | global LIBJAVA
|
|---|
| 641 | global LIBGC
|
|---|
| 642 | global srcdir subdir objdir
|
|---|
| 643 | global TOOL_OPTIONS
|
|---|
| 644 | global GCJ_UNDER_TEST
|
|---|
| 645 | global tmpdir
|
|---|
| 646 | global runtests
|
|---|
| 647 | global INTERPRETER
|
|---|
| 648 |
|
|---|
| 649 | # Make opts into an array.
|
|---|
| 650 | set opts(_) x
|
|---|
| 651 | unset opts(_)
|
|---|
| 652 | foreach item $exec_args {
|
|---|
| 653 | set opts($item) x
|
|---|
| 654 | }
|
|---|
| 655 |
|
|---|
| 656 | # If we need threads and we don't have them then set the `no-exec'
|
|---|
| 657 | # flag. This is case is also handled specially later.
|
|---|
| 658 | if {[info exists opts(need-threads)]} {
|
|---|
| 659 | global libjava_uses_threads
|
|---|
| 660 | if {! $libjava_uses_threads} {
|
|---|
| 661 | set opts(no-exec) x
|
|---|
| 662 | }
|
|---|
| 663 | }
|
|---|
| 664 | set errname [file rootname [file tail $srcfile]]
|
|---|
| 665 | if {! [runtest_file_p $runtests $errname]} {
|
|---|
| 666 | return
|
|---|
| 667 | }
|
|---|
| 668 |
|
|---|
| 669 | # bytecompile files with Sun's compiler for now.
|
|---|
| 670 | set bc_ok [bytecompile_file $srcfile $objdir]
|
|---|
| 671 |
|
|---|
| 672 | set javac [find_javac]
|
|---|
| 673 | # This is an ugly heuristic but it will have to do.
|
|---|
| 674 | if {[string match *gcj* $javac]} {
|
|---|
| 675 | set tag gcjC
|
|---|
| 676 | } else {
|
|---|
| 677 | set tag javac
|
|---|
| 678 | }
|
|---|
| 679 | if {[info exists opts(xfail-$tag)]} {
|
|---|
| 680 | setup_xfail *-*-*
|
|---|
| 681 | }
|
|---|
| 682 | if {! $bc_ok} then {
|
|---|
| 683 | if {[info exists opts(shouldfail)]} {
|
|---|
| 684 | pass "$errname byte compilation"
|
|---|
| 685 | return
|
|---|
| 686 | }
|
|---|
| 687 | fail "$errname byte compilation"
|
|---|
| 688 | untested "$errname compilation from bytecode"
|
|---|
| 689 | if {! [info exists opts(no-exec)]
|
|---|
| 690 | || [info exists opts(need-threads)]} {
|
|---|
| 691 | untested "$errname execution from bytecode->native test"
|
|---|
| 692 | untested "$errname output from bytecode->native test"
|
|---|
| 693 | }
|
|---|
| 694 | return
|
|---|
| 695 | }
|
|---|
| 696 | if {[info exists opts(shouldfail)]} {
|
|---|
| 697 | fail "$errname byte compilation"
|
|---|
| 698 | return
|
|---|
| 699 | }
|
|---|
| 700 | pass "$errname byte compilation"
|
|---|
| 701 |
|
|---|
| 702 | set removeList {}
|
|---|
| 703 |
|
|---|
| 704 | # Find name to use for --main, and name of all class files.
|
|---|
| 705 | set jvscan [find_jvscan]
|
|---|
| 706 | verbose "jvscan is $jvscan"
|
|---|
| 707 | set main_name [string trim \
|
|---|
| 708 | [libjava_prune_warnings \
|
|---|
| 709 | [lindex [local_exec "$jvscan --encoding=UTF-8 $srcfile --print-main" "" "" 300] 1]]]
|
|---|
| 710 | verbose "main name is $main_name"
|
|---|
| 711 | set class_out [string trim \
|
|---|
| 712 | [libjava_prune_warnings \
|
|---|
| 713 | [lindex [local_exec "$jvscan --encoding=UTF-8 $srcfile --list-class" "" "" 300] 1]]]
|
|---|
| 714 | verbose "class list is $class_out"
|
|---|
| 715 |
|
|---|
| 716 | if {[string match "*parse error*" $main_name]
|
|---|
| 717 | || [string match "*parse error*" $class_out]} {
|
|---|
| 718 | untested "$errname compilation from bytecode"
|
|---|
| 719 | if {! [info exists opts(no-exec)]
|
|---|
| 720 | || [info exists opts(need-threads)]} {
|
|---|
| 721 | untested "$errname execution from bytecode->native test"
|
|---|
| 722 | untested "$errname output from bytecode->native test"
|
|---|
| 723 | }
|
|---|
| 724 | return
|
|---|
| 725 | }
|
|---|
| 726 |
|
|---|
| 727 | # Turn "a b" into "a.class b.class".
|
|---|
| 728 | # Also, turn "foo.bar" into "foo/bar.class".
|
|---|
| 729 | set class_files {}
|
|---|
| 730 | foreach file [split [string trim $class_out]] {
|
|---|
| 731 | set file [join [split $file .] /]
|
|---|
| 732 | lappend class_files $objdir/$file.class
|
|---|
| 733 | }
|
|---|
| 734 |
|
|---|
| 735 | eval lappend removeList $class_files
|
|---|
| 736 |
|
|---|
| 737 | # Usually it is an error for a test program not to have a `main'
|
|---|
| 738 | # method. However, for no-exec tests it is ok. Treat no-link
|
|---|
| 739 | # like no-exec here.
|
|---|
| 740 | if {[info exists opts(no-link)]} {
|
|---|
| 741 | set opts(no-exec) x
|
|---|
| 742 | }
|
|---|
| 743 | set largs {}
|
|---|
| 744 |
|
|---|
| 745 | if {[info exists opts(no-exec)]} {
|
|---|
| 746 | set type object
|
|---|
| 747 | set mode compile
|
|---|
| 748 | } elseif {$main_name == ""} {
|
|---|
| 749 | perror "No `main' given in program $errname"
|
|---|
| 750 | return
|
|---|
| 751 | } else {
|
|---|
| 752 | set type executable
|
|---|
| 753 | lappend largs "additional_flags=--main=$main_name"
|
|---|
| 754 | # DOS/win32 targets default to .exe if no suffix is given
|
|---|
| 755 | # We then try to delete a file that doesn't exist. It is
|
|---|
| 756 | # simpler to add the suffix everywhere.
|
|---|
| 757 | set executable "${objdir}/${main_name}.exe"
|
|---|
| 758 | set mode link
|
|---|
| 759 | }
|
|---|
| 760 |
|
|---|
| 761 | # We purposely ignore errors here; we still want to run the other
|
|---|
| 762 | # appropriate tests.
|
|---|
| 763 | set gij [libjava_find_gij]
|
|---|
| 764 | # libjava_find_gij will return `gij' if it couldn't find the
|
|---|
| 765 | # program; in this case we want to skip the test.
|
|---|
| 766 | if {$INTERPRETER == "yes" && $gij != "gij"} {
|
|---|
| 767 | libjava_invoke $errname "gij test" opts $gij \
|
|---|
| 768 | $inpfile $resultfile $main_name
|
|---|
| 769 | }
|
|---|
| 770 |
|
|---|
| 771 | # Initial arguments.
|
|---|
| 772 | set args [libjava_arguments $mode]
|
|---|
| 773 | eval lappend args $largs
|
|---|
| 774 |
|
|---|
| 775 | if { $compile_args != "" } {
|
|---|
| 776 | lappend args "additional_flags=$compile_args"
|
|---|
| 777 | }
|
|---|
| 778 |
|
|---|
| 779 | if { $compile_args != "" } {
|
|---|
| 780 | set errname "$errname $compile_args"
|
|---|
| 781 | }
|
|---|
| 782 |
|
|---|
| 783 | verbose "compilation command = $args" 2
|
|---|
| 784 | # When compiling and not linking, we have to build each .o
|
|---|
| 785 | # separately. We do this because DejaGNU's target_compile won't
|
|---|
| 786 | # accept an empty "destfile" argument when the mode is "compile".
|
|---|
| 787 | if {$mode == "compile"} {
|
|---|
| 788 | foreach c_file $class_files {
|
|---|
| 789 | set executable [file rootname [file tail $c_file]].o
|
|---|
| 790 | # Don't write files which contain $ chars.
|
|---|
| 791 | regsub -all "\\$" $executable "\^" executable
|
|---|
| 792 | set x [libjava_prune_warnings \
|
|---|
| 793 | [libjava_tcompile '$c_file' "$executable" $type $args]]
|
|---|
| 794 | lappend removeList $executable
|
|---|
| 795 | if {$x != ""} {
|
|---|
| 796 | break
|
|---|
| 797 | }
|
|---|
| 798 | }
|
|---|
| 799 | } else {
|
|---|
| 800 | # This is so evil: we de-listify CLASS_FILES so that we can
|
|---|
| 801 | # turn around and quote the `$' in it for the shell. I really
|
|---|
| 802 | # hate DejaGNU. It is so !@#$!@# unpredictable.
|
|---|
| 803 | set hack ""
|
|---|
| 804 | foreach stupid $class_files {
|
|---|
| 805 | set hack "$hack $stupid"
|
|---|
| 806 | }
|
|---|
| 807 | lappend removeList $executable
|
|---|
| 808 | set x [libjava_prune_warnings \
|
|---|
| 809 | [libjava_tcompile $hack "$executable" $type $args]]
|
|---|
| 810 | }
|
|---|
| 811 | if {[info exists opts(xfail-byte)]} {
|
|---|
| 812 | setup_xfail *-*-*
|
|---|
| 813 | }
|
|---|
| 814 | if { $x != "" } {
|
|---|
| 815 | verbose "target_compile failed: $x" 2
|
|---|
| 816 | fail "$errname compilation from bytecode"
|
|---|
| 817 | if {! [info exists opts(no-exec)]
|
|---|
| 818 | || [info exists opts(need-threads)]} {
|
|---|
| 819 | untested "$errname execution from bytecode->native test"
|
|---|
| 820 | untested "$errname output from bytecode->native test"
|
|---|
| 821 | }
|
|---|
| 822 | return;
|
|---|
| 823 | }
|
|---|
| 824 | pass "$errname compilation from bytecode"
|
|---|
| 825 |
|
|---|
| 826 | # Set up the options the way they are expected by libjava_invoke.
|
|---|
| 827 | if {[info exists opts(xfail-byte-output)]} {
|
|---|
| 828 | set opts(xfail-output) x
|
|---|
| 829 | }
|
|---|
| 830 | if {[libjava_invoke $errname "bytecode->native test" opts $executable \
|
|---|
| 831 | $inpfile $resultfile]} {
|
|---|
| 832 | # Everything ok, so clean up.
|
|---|
| 833 | eval gcj_cleanup $removeList
|
|---|
| 834 | }
|
|---|
| 835 | }
|
|---|
| 836 |
|
|---|
| 837 | #
|
|---|
| 838 | # Run the test specified by srcfile and resultfile. compile_args and
|
|---|
| 839 | # exec_args are options telling this proc how to work.
|
|---|
| 840 | # `no-link' don't try to link the program
|
|---|
| 841 | # `no-exec' don't try to run the test
|
|---|
| 842 | # `xfail-gcj' compilation from source will fail
|
|---|
| 843 | # `xfail-javac' compilation with javac will fail
|
|---|
| 844 | # `xfail-gcjC' compilation with gcj -C will fail
|
|---|
| 845 | # `shouldfail' compilation from source is supposed to fail
|
|---|
| 846 | # This is different from xfail, which marks a known
|
|---|
| 847 | # failure that we just haven't fixed.
|
|---|
| 848 | # A compilation marked this way should fail with any
|
|---|
| 849 | # front end.
|
|---|
| 850 | # `xfail-byte' compilation from bytecode will fail
|
|---|
| 851 | # `xfail-exec' exec will fail
|
|---|
| 852 | # `xfail-output'
|
|---|
| 853 | # output will be wrong
|
|---|
| 854 | # `xfail-byte-output'
|
|---|
| 855 | # output will be wrong when compiled from bytecode
|
|---|
| 856 | # `xfail-source-output'
|
|---|
| 857 | # output will be wrong when compiled from source code
|
|---|
| 858 | # `need-threads'
|
|---|
| 859 | # test relies on thread support
|
|---|
| 860 | #
|
|---|
| 861 | proc test_libjava { options srcfile compile_args inpfile resultfile exec_args } {
|
|---|
| 862 | test_libjava_from_source $options $srcfile $compile_args $inpfile $resultfile $exec_args
|
|---|
| 863 | test_libjava_from_javac $options $srcfile $compile_args $inpfile $resultfile $exec_args
|
|---|
| 864 | }
|
|---|
| 865 |
|
|---|
| 866 | #
|
|---|
| 867 | # libjava_version -- extract and print the version number of libjavap
|
|---|
| 868 | #
|
|---|
| 869 | proc default_libjava_version {} {
|
|---|
| 870 | }
|
|---|
| 871 |
|
|---|
| 872 | proc default_libjava_start { } {
|
|---|
| 873 | }
|
|---|
| 874 |
|
|---|
| 875 | # On IRIX 6, we have to set variables akin to LD_LIBRARY_PATH, but
|
|---|
| 876 | # called LD_LIBRARYN32_PATH (for the N32 ABI) and LD_LIBRARY64_PATH
|
|---|
| 877 | # (for the 64-bit ABI). The right way to do this would be to modify
|
|---|
| 878 | # unix.exp -- but that's not an option since it's part of DejaGNU
|
|---|
| 879 | # proper, so we do it here, by trickery. We really only need to do
|
|---|
| 880 | # this on IRIX, but it shouldn't hurt to do it anywhere else.
|
|---|
| 881 |
|
|---|
| 882 | proc ${tool}_set_ld_library_path { name element op } {
|
|---|
| 883 | setenv LD_LIBRARYN32_PATH [getenv LD_LIBRARY_PATH]
|
|---|
| 884 | setenv LD_LIBRARY64_PATH [getenv LD_LIBRARY_PATH]
|
|---|
| 885 | }
|
|---|
| 886 |
|
|---|
| 887 | trace variable env(LD_LIBRARY_PATH) w ${tool}_set_ld_library_path
|
|---|
| 888 |
|
|---|
| 889 | # Local Variables:
|
|---|
| 890 | # tcl-indent-level:4
|
|---|
| 891 | # End:
|
|---|