From f25ca078a81dcd3c2accdb756ce9e6ee1cf536df Mon Sep 17 00:00:00 2001 From: "Oleg A. Khlybov" Date: Mon, 4 Nov 2024 22:27:26 -0800 Subject: [PATCH] mumps: new test suite --- mingw-w64-mumps/PKGBUILD | 18 +- mingw-w64-mumps/all.tcl | 7 - mingw-w64-mumps/buildme-0.tm | 70 +++ mingw-w64-mumps/mumps.tcl | 48 ++ mingw-w64-mumps/mumps.test | 21 - mingw-w64-mumps/tclbuildtest.tcl | 751 ------------------------------- mingw-w64-mumps/testme-0.tm | 640 ++++++++++++++++++++++++++ mingw-w64-mumps/xyz-0.tm | 54 +++ 8 files changed, 822 insertions(+), 787 deletions(-) delete mode 100644 mingw-w64-mumps/all.tcl create mode 100644 mingw-w64-mumps/buildme-0.tm create mode 100644 mingw-w64-mumps/mumps.tcl delete mode 100644 mingw-w64-mumps/mumps.test delete mode 100644 mingw-w64-mumps/tclbuildtest.tcl create mode 100644 mingw-w64-mumps/testme-0.tm create mode 100644 mingw-w64-mumps/xyz-0.tm diff --git a/mingw-w64-mumps/PKGBUILD b/mingw-w64-mumps/PKGBUILD index 2856baa3f9..445983d2fd 100644 --- a/mingw-w64-mumps/PKGBUILD +++ b/mingw-w64-mumps/PKGBUILD @@ -30,7 +30,7 @@ _realname=mumps pkgbase=mingw-w64-${_realname} pkgname="${MINGW_PACKAGE_PREFIX}-${_realname}" pkgver=5.7.3 -pkgrel=1 +pkgrel=2 pkgdesc="Sparse direct SLAE solver (mingw-w64)" arch=('any') mingw_arch=('mingw64' 'ucrt64') @@ -52,16 +52,18 @@ source=("https://mumps-solver.org/MUMPS_${pkgver}.tar.gz" "0001-makefile.inc.patch" "0002-skip-examples.patch" "0003-fix-setenv.patch" - "all.tcl" - "tclbuildtest.tcl" - "mumps.test") + "mumps.tcl" + "testme-0.tm" + "buildme-0.tm" + "xyz-0.tm") sha256sums=('84a47f7c4231b9efdf4d4f631a2cae2bdd9adeaabc088261d15af040143ed112' 'd4e3d06c316544304ac6fefd595f20fd5865e791c9377e031fbad49b6238406c' 'bbefd4a5f841536132f32c1ffc684a58b778901cd777445ca817dbb34d983450' '11609d173fc0df7b1d7269c19d5d81b2fd05a3abc57eff8ba12de1597242236c' - 'ec5072630e1c0309fe383669e9187790cd135a393c67bc4bc35cf60b0ba396ff' - '277a71049b2d4cde76ca21253b253ccd7ea9e8bcfb654868c05c6bfb137d2690' - '58bc4cc4820cc91dc8cc67c2c95774b00c628fa56cc9c627894a5da08900b11b') + 'aa8cc50e447eebb14492744c8be6bd8f731e0140c339a76cc31e54ea2f11813d' + '8d8f5670ffdf34a10b0d027bff976131824e2e6b053f8a13d207ecddd4663d6d' + 'd0db2aa573c9aaf57b30cb3c2bd7c66e1677f3f468002f467da98b75943076b1' + 'd52709e3663d50ed793bfe991c571ec4ea5e6eaf72fcc920e1f8ba43d0ed7050') apply_patch_with_msg() { for _patch in "$@" @@ -131,7 +133,7 @@ package() { install -m644 *.h "${pkgdir}${MINGW_PREFIX}/include" ) ( - cp ${srcdir}/{all.tcl,tclbuildtest.tcl,mumps.test} ${pkgdir}${MINGW_PREFIX}/share/test/mumps + cp ${srcdir}/{*.tcl,*.tm} ${pkgdir}${MINGW_PREFIX}/share/test/mumps cd "$srcdir/${_realname}_${pkgver}/examples" cp c_example.c ?simpletest.F input_simpletest_* ${pkgdir}${MINGW_PREFIX}/share/test/mumps ) diff --git a/mingw-w64-mumps/all.tcl b/mingw-w64-mumps/all.tcl deleted file mode 100644 index b9ea41a400..0000000000 --- a/mingw-w64-mumps/all.tcl +++ /dev/null @@ -1,7 +0,0 @@ -# Template {all.tcl} file which is to be put into each test module's directory. -# Either [source] the bundled {tclbuildtest.tcl} to force load the specific code or -# alter the $auto_path list to add location of {pkgIndex.tcl,tclbuildtest.tcl}. -# The same scheme is to be applied to all .test files. -source [file join [file dirname [file normalize [info script]]] tclbuildtest.tcl] -package require tclbuildtest -::tclbuildtest::suite {*}$::argv \ No newline at end of file diff --git a/mingw-w64-mumps/buildme-0.tm b/mingw-w64-mumps/buildme-0.tm new file mode 100644 index 0000000000..11123aa808 --- /dev/null +++ b/mingw-w64-mumps/buildme-0.tm @@ -0,0 +1,70 @@ +# https://github.com/okhlybov/testme + + +package require Tcl + + +namespace eval ::buildme { + + + namespace export sandbox shell + + + proc MakeTempDir {args} { + upvar 1 unit unit + set roots $args + foreach t {TMPDIR TMP} { + if {![catch {set t [set ::env($t)]}]} { + lappend roots $t + } + } + lappend roots /tmp + foreach r $roots { + if {![catch { + set prefix [file rootname [file tail [dict get $unit -source]]] + set t [file join $r $prefix.[expr {int(rand()*999999)}]] + file mkdir $t + }]} {return $t} + } + error "failed to create temporary directory $t" + } + + + proc sandbox {code} { + upvar 1 unit unit + set dir [MakeTempDir] + try { + foreach p [glob -nocomplain -directory [dict get $unit -stage] * .*] { + set last [lindex [file split $p] end] + if {$last != "." && $last != ".."} { + file copy -force -- $p $dir + } + } + # Can't cd into stage dir in multithreaded environment where all threads have the same current directory + dict set unit -stage $dir + eval $code + } finally { + if {[dict get $unit -cleanup]} { + if {[catch {file delete -force -- $dir}]} { + puts stderr "failed to delete temporary directory $dir + } + } + } + } + + + proc shell {cmd} { + upvar 1 unit unit + set stage [dict get $unit -stage] + set cd "cd \"$stage\"" + puts stdout "$cd && \\\n$cmd" + if {[catch {exec -ignorestderr $::env(SHELL) -c "$cd && $cmd" 2>@1} result opts]} { + puts stderr $result + } else { + puts stdout $result + } + return {*}$opts $result + } + + +} \ No newline at end of file diff --git a/mingw-w64-mumps/mumps.tcl b/mingw-w64-mumps/mumps.tcl new file mode 100644 index 0000000000..aec836b9aa --- /dev/null +++ b/mingw-w64-mumps/mumps.tcl @@ -0,0 +1,48 @@ +tcl::tm::add [file normalize [file join [file dirname [info script]] .]] + + +package require xyz + + +foreach static {{} static} { + foreach executor {{} omp} { + xyz::unit MUMPS [concat $executor $static c double] { + package require buildme + buildme::sandbox { + buildme::shell "cc -o a c_example.c `pkgconf mumps-[dict get $unit -xyz] --cflags --libs [dict get $unit -static]` [dict get $unit -static] && ./a" + } + } + } + foreach executor {mpi} { + xyz::unit MUMPS [concat $executor $static c double] { + package require buildme + buildme::sandbox { + buildme::shell "mpicc -o a c_example.c `pkgconf mumps-[dict get $unit -xyz] --cflags --libs [dict get $unit -static]` [dict get $unit -static] && mpiexec -n 1 ./a" + } + } + } +} + +foreach precision {double single} { + foreach scalar {real complex} { + if {$scalar == "complex"} {set input input_simpletest_cmplx} else {set input input_simpletest_real} + foreach static {{} static} { + foreach executor {{} omp} { + xyz::unit MUMPS [list $executor $static $precision $scalar fortran] -input $input { + package require buildme + buildme::sandbox { + buildme::shell "gfortran -o a [string index [dict get $unit -xyz] 0]simpletest.F -I/ucrt64/include `pkgconf mumps-[dict get $unit -xyz] --cflags --libs [dict get $unit -static]` [dict get $unit -static] && ./a < [dict get $unit -input]" + } + } + } + foreach executor {mpi} { + xyz::unit MUMPS [list $executor $static $precision $scalar fortran] -input $input { + package require buildme + buildme::sandbox { + buildme::shell "mpifort -o a [string index [dict get $unit -xyz] 0]simpletest.F -I/usrt64/include `pkgconf mumps-[dict get $unit -xyz] --cflags --libs [dict get $unit -static]` [dict get $unit -static] && mpiexec -n 1 ./a < [dict get $unit -input]" + } + } + } + } + } +} \ No newline at end of file diff --git a/mingw-w64-mumps/mumps.test b/mingw-w64-mumps/mumps.test deleted file mode 100644 index 3ffc5e46c0..0000000000 --- a/mingw-w64-mumps/mumps.test +++ /dev/null @@ -1,21 +0,0 @@ -source [file join [file dirname [file normalize [info script]]] tclbuildtest.tcl] - -package require tclbuildtest - -::tclbuildtest::sandbox { - foreach t {{} openmp mpi} { - foreach b {{} static} { - test [list c $t real double $b] { - run [build [require mumps-[xyz]] c_example.c] - } - foreach s {real complex} { - foreach p {single double} { - test [list fortran $t $p $s $b] { - if {[constraint? complex]} {set input input_simpletest_cmplx} else {set input input_simpletest_real} - run [build [require mumps-[xyz]] -fallow-invalid-boz [x]simpletest.F] < $input - } - } - } - } - } -} \ No newline at end of file diff --git a/mingw-w64-mumps/tclbuildtest.tcl b/mingw-w64-mumps/tclbuildtest.tcl deleted file mode 100644 index 25787fcf55..0000000000 --- a/mingw-w64-mumps/tclbuildtest.tcl +++ /dev/null @@ -1,751 +0,0 @@ -# -# TclTest extenstion to test source code compilation & running -# -# https://github.com/okhlybov/tclbuildtest -# - -package provide tclbuildtest 0.1.0 - -package require Tcl 8.6 -package require tcltest 2.5.1 - -namespace eval ::tcltest {}; # Make pkg_mkIndex happy - -# https://github.com/tcl2020/named-parameters - -namespace eval ::np { - # - # proc_args_to_dict - given a proc name and declared - # proc arguments (variable names with optional - # default values and a -- and possible some more - # stuff, create and return a dict containing that - # info in a way that's convenient and quicker - # for us at runtime: - # * we store a list of positional parameters - # * we store a list of named parameters - # * we store a list of var-value defaults - # * we get a tricked-out error message in errmsg - # - ::proc proc_args_to_dict {name procArgs} { - set seenDashes 0 - dict set d defaults [list] - dict set d positional [list] - dict set d named [list] - set errmsg "wrong # args: should be \"$name " - - foreach arg $procArgs { - if {$arg eq "--"} { - set seenDashes 1 - append errmsg "?--? " - continue - } - - set var [lindex $arg 0] - dict lappend d [expr {$seenDashes ? "positional" : "named"}] $var - - if {[llength $arg] == 2} { - dict lappend d defaults $var [lindex $arg 1] - if {$seenDashes} { - append errmsg "?$var? " - } else { - append errmsg "?-$var val? " - } - } elseif {$var eq "args"} { - dict lappend d defaults $var [list] - append errmsg "?arg ...? " - } else { - if {$seenDashes} { - append errmsg "$var " - } else { - append errmsg "-$var val " - } - } - } - dict set d errmsg "[string range $errmsg 0 end-1]\"" - return $d - } - - # - # np_handler - look at an argument dict created by proc_args_to_dict - # and look at the real arguments to a function (args), and sort - # out the named and positional parameters to behave in the - # expected way. - # - ::proc np_handler {argd realArgs} { - set named [dict get $argd named] - set positional [dict get $argd positional] - - # process named parameters - while {[llength $realArgs] > 0} { - set arg [lindex $realArgs 0] - - # if arg is --, flip to positional - if {$arg eq "--"} { - set realArgs [lrange $realArgs 1 end] - break - } - - # if "var" doesn't start with a dash, flip to positional - if {[string index $arg 0] ne "-"} { - #puts "possible var '$arg' doesn't start with a dash, flip to positional" - break - } - - # if "var" isn't known to us as a named parameter, flip to positional - set var [string range $arg 1 end] - if {[lsearch $named $var] < 0} { - #puts "'var' '$arg' not recognized, flip to positional" - break - } - - # if there isn't at least one more element in the arg list, - # we are missing a value for one of our named parameters - if {[llength $realArgs] == 0} { - #puts "realArgs is empty but i expect something for $var" - error [dict get $argd errmsg] "" [list TCL WRONGARGS] - } - - # we're good, set the named parameter into the variable sets - #puts [list set vsets($var) [lindex $realArgs 1]] - - # but don't allow the same variable to be set twice - if {[info exists vsets($var)]} { - error [dict get $argd errmsg] "" [list TCL WRONGARGS] - } - - set vsets($var) [lindex $realArgs 1] - set realArgs [lrange $realArgs 2 end] - } - - # fill in defaults for all the vars with defaults that - # didn't get set to a value - foreach "var value" [dict get $argd defaults] { - if {![info exists vsets($var)]} { - set vsets($var) $value - } - } - - foreach var $positional { - if {$var eq "args"} { - set vsets($var) $realArgs - set realArgs [list] - break - } - - if {[llength $realArgs] > 0} { - set vsets($var) [lindex $realArgs 0] - set realArgs [lrange $realArgs 1 end] - } - - # no arguments left. if this var doesn't - # have a default value, it's a wrong args error - if {![info exists vsets($var)]} { - error [dict get $argd errmsg] "" [list TCL WRONGARGS] - } - } - - # make sure all the named parameters have been set, either - # by defaults or explicitly, any not set is an error - foreach var $named { - if {![info exists vsets($var)]} { - #puts "required named parameter '-$var' is not set" - error [dict get $argd errmsg] "" [list TCL WRONGARGS] - } - } - - # are there too many arguments? - if {[llength $realArgs] > 0} { - #puts "leftover arguments (too many) '$realArgs'" - error [dict get $argd errmsg] "" [list TCL WRONGARGS] - } - - # now iterate through the var-value pairs and set them into - # the caller's frame - foreach "var value" [array get vsets] { - #puts "set '$var' '$value'" - upvar $var myvar - set myvar $value - } - return - } - - # - # np::proc - same as proc except if -- is in the argv - # then it will generate a proc that has extra code - # at the beginning to wrangle the named parameters - # - proc proc {name argv body} { - # handle the case where there are no named parameters - if {[lsearch $argv --] < 0} { - uplevel [list ::proc $name $argv $body] - return - } - - if {[lsearch $argv --] == 0} { - return -code error "-- cannot be the first argument for named parameters. Use positional parameters." - } - - set d [proc_args_to_dict $name $argv] - set newbody "::proc $name args {\n" - append newbody " ::np::np_handler [list $d] \$args\n" - append newbody $body - append newbody "\n}" - #puts $newbody - uplevel $newbody - } -} - -namespace eval ::tclbuildtest { - - variable system-count 0 - variable build-count 0 - - # Standard predefined constraints - foreach ct { - c cxx fortran - single double - real complex - openmp thread hybrid mpi - static - debug - } {::tcltest::testConstraint $ct 1} - - # Return a value of the environment variable or {} if no such variable is set - proc env {var} { - try {return [set ::env($var)]} on error {} {return {}} - } - - # MpiExec detection - proc mpiexec {} { - variable mpiexec - try {set mpiexec} on error {} { - set mpiexec {} - foreach x [collect [env MPIEXEC] mpiexec mpirun] { - if {![catch {exec {*}$x}]} { - set mpiexec $x - break - } - } - } - if {$mpiexec == {}} {error {failed to detect MpiExec or equivalent}} - return $mpiexec - } - - # PkgConfig detection - proc pkg-config {} { - variable pc - try {set pc} on error {} { - set pc {} - foreach x [collect [env PKG_CONFIG] pkg-config pkgconf] { - if {![catch {exec {*}$x --version}]} { - set pc $x - break - } - } - } - if {$pc == {}} {error {failed to detect PkgConfig or equivalent}} - return $pc - } - - # C compiler detection - proc cc {} { - variable cc - try {set cc} on error {} { - set cc {} - foreach x [collect [env CC] gcc] { - if {![catch {exec {*}$x --version}]} { - set cc $x - break - } - } - } - if {$cc == {}} {error {failed to detect C compiler}} - return $cc - } - - # C++ compiler detection - proc cxx {} { - variable cxx - try {set cxx} on error {} { - set cxx {} - foreach x [collect [env CXX] g++] { - if {![catch {exec {*}$x --version}]} { - set cxx $x - break - } - } - } - if {$cxx == {}} {error {failed to detect C++ compiler}} - return $cxx - } - - # FORTRAN compiler detection - proc fc {} { - variable fc - try {set fc} on error {} { - set fc {} - foreach x [collect [env FC] gfortran] { - if {![catch {exec {*}$x --version}]} { - set fc $x - break - } - } - } - if {$fc == {}} {error {failed to detect FORTRAN compiler}} - return $fc - } - - # MPI C compiler detection - proc mpicc {} { - variable mpicc - try {set mpicc} on error {} { - set mpicc {} - foreach x [collect [env MPICC] mpicc] { - if {![catch {exec {*}$x --version}]} { - set mpicc $x - break - } - } - } - if {$mpicc == {}} {error {failed to detect MPI C compiler}} - return $mpicc - } - - # MPI C++ compiler detection - proc mpicxx {} { - variable mpicxx - try {set mpicxx} on error {} { - set mpicxx {} - foreach x [collect [env MPICXX] mpicxx mpic++] { - if {![catch {exec {*}$x --version}]} { - set mpicxx $x - break - } - } - } - if {$mpicxx == {}} {error {failed to detect MPI C++ compiler}} - return $mpicxx - } - - # MPI FORTRAN compiler detection - proc mpifc {} { - variable mpifc - try {set mpifc} on error {} { - set mpifc {} - foreach x [collect [env MPIFC] [env MPIFORT] mpifort mpif90 mpif77] { - if {![catch {exec {*}$x --version}]} { - set mpifc $x - break - } - } - } - if {$mpifc == {}} {error {failed to detect MPI FORTRAN compiler}} - return $mpifc - } - - # Create temporary directory - proc mktempdir {} { - set t [file join $::env(TEMP) [file rootname [file tail [info script]]][expr {int(rand()*9999)}]] - file mkdir $t - return $t - } - - # Delete directory tree - proc rmdir {dir} { - try { - file delete -force $dir - } on error {} { - # This command fires up a background sanitizing process which does its best to delete - # staging directory in spite of executable locks or what's not which can happend on Windows - # This code should work in real UNIX environments or UNIX-like Windows environments - # such as Cygwin or MSYS(2). - exec -ignorestderr sh -c "nohup \${SHELL} -c \" while \[ -d '$dir' \]; do rm -rf '$dir' || sleep 3; done\" > /dev/null 2>&1 &" - } - } - - # Execute script from a temporary location - # Script file is copied to the location along with all residing files - # The location gets deleted afterwards - proc sandbox {script} { - variable stagedir [mktempdir] - try { - ::tcltest::configure {*}$::argv - ::tcltest::workingDirectory $stagedir - file copy -force {*}[glob -directory [file dirname [file normalize [info script]]] -nocomplain *] $stagedir - eval $script - } finally { - ::tcltest::cleanupTests - rmdir $stagedir - } - } - - # Obtain compilation and linking flags for the specified packages via PkgConfig - proc require {args} { - if {[constraint? static]} {set flags --static} else {set flags {}} - xflags {*}[lindex [dict get [system [pkg-config] {*}$args --keep-system-cflags --cflags {*}$flags] stdout] 0] - ldflags {*}[lindex [dict get [system [pkg-config] {*}$args --libs {*}$flags] stdout] 0] - return - } - - # Deduce source code language from command line arguments - proc deduce-language {opts} { - switch -regexp -nocase [lindex $opts [lsearch -glob -not $opts {-*}]] { - {\.c$} {return c} - {\.(cxx|cpp|cc)$} {return cxx} - {\.(f|for|f\d+)$} {return fortran} - default {error {failed to deduce source language from the command line agruments}} - } - } - - # Deduce compilation command from command line arguments - proc deduce-compiler-proc {opts} { - set lang [deduce-language $opts] - if {[constraint? mpi]} { - switch $lang { - c {return mpicc} - cxx {return mpicxx} - fortran {return mpifc} - } - } else { - switch $lang { - c {return cc} - cxx {return cxx} - fortran {return fc} - } - } - } - - # Deduce compilation flags command from command line arguments - proc deduce-compile-flags-proc {opts} { - switch [deduce-language $opts] { - c {return cflags} - cxx {return cxxflags} - fortran {return fflags} - } - } - - # C preprocessor command line arguments - proc cppflags {args} { - variable cppflags - try {set cppflags} on error {} { - set cppflags [lsqueeze [env CPPFLAGS]] - if {![constraint? debug]} {lappend cppflags -DNDEBUG} - } - lappend cppflags {*}$args - } - - # Language-agnostic compilation command line arguments - proc xflags {args} { - variable xflags - try {set xflags} on error {} { - set xflags {} - if {[constraint? openmp]} {lappend xflags -fopenmp} - if {[constraint? thread]} {lappend xflags -pthread} - if {[constraint? debug]} {lappend xflags -Og} else {lappend xflags -O2} - } - lappend xflags {*}$args - } - - # C-specific compilation command line arguments - proc cflags {args} { - variable cflags - try {set cflags} on error {} { - set cflags [lsqueeze [env CFLAGS]] - } - lappend cflags {*}$args - } - - - # C++-specific compilation command line arguments - proc cxxflags {args} { - variable cxxflags - try {set cxxflags} on error {} { - set cxxflags [lsqueeze [env CXXFLAGS]] - } - lappend cxxflags {*}$args - } - - # FORTRAN-specific compilation command line arguments - proc fflags {args} { - variable fflags - try {set fflags} on error {} { - set fflags [lsqueeze [env FFLAGS]] - } - lappend fflags {*}$args - } - - # Linker command line arguments - proc ldflags {args} { - variable ldflags - try {set ldflags} on error {} { - set ldflags [lsqueeze [env LDFLAGS]] - if {[constraint? static]} {lappend ldflags -static} - if {[constraint? openmp]} {lappend ldflags -fopenmp} - if {[constraint? thread]} {lappend ldflags -pthread} - } - lappend ldflags {*}$args - } - - # Linked libraries command line arguments - proc libs {args} { - variable libs - try {set libs} on error {} { - set libs [lsqueeze [env LIBS]] - if {[constraint? cxx]} {lappend libs -lstdc++} - if {[constraint? fortran]} {lappend libs -lgfortran -lquadmath} - } - lappend libs {*}$args - } - - # Perform source code compilation into executable - # Returns the executable name - proc build {args} { - set args [lsqueeze $args] - set exe [executable] - system {*}[concat \ - [[deduce-compiler-proc $args]] \ - -o $exe \ - [cppflags] \ - [xflags] \ - [[deduce-compile-flags-proc $args]] \ - $args \ - [ldflags] \ - [libs] \ - ] - return $exe - } - - # Perform running of the specified executable with supplied command line arguments - proc run {args} { - if {[constraint? mpi]} {set runner [mpiexec]} else {set runner {}} - system {*}[list $runner {*}$args] - } - - # Execute command line built from command line arguments - proc system {args} { - variable system-count - incr system-count - set stdout stdout${system-count} - set stderr stderr${system-count} - set args [lsqueeze $args] - set command [join $args] - if {[lsearch [::tcltest::verbose] exec] < 0} {set verbose 0} else {set verbose 1} - if {$verbose} {::puts [::tcltest::outputChannel] "> $command"} - try { - exec -ignorestderr -- {*}$args > $stdout 2> $stderr - set options {} - set status 0 - set code ok - } trap CHILDSTATUS {results options} { - set status [lindex [dict get $options -errorcode] 2] - set code error - } finally { - try { - set out [read-file $stdout] - set err [read-file $stderr] - } finally { - file delete -force $stdout $stderr - } - } - if {$verbose} { - foreach x $out {::puts [::tcltest::outputChannel] $x} - if {[llength $out] > 0 && [llength $err] > 0} {::puts [::tcltest::outputChannel] ----} - foreach x $err {::puts [::tcltest::outputChannel] $x} - } - return -code $code [dict create command $command status $status stdout $out stderr $err options $options] - } - - # Construct a scalar type ID from the constraints - proc x {} { - if {[constraint? complex]} { - if {[constraint? double]} {return z} - if {[constraint? single]} {return c} - } else { - if {[constraint? double]} {return d} - if {[constraint? single]} {return s} - } - error {failed to contstruct the scalar type} - } - - # Construct an execution model ID from the constraints - proc y {} { - if {[constraint? mpi]} {return m} - if {[constraint-any? openmp thread]} {return t} - if {[constraint? hybrid]} {return h} - return s - } - - # Construct an build type ID from the constraints - proc z {} { - if {[constraint? debug]} {return g} - return o - } - - # Construct a 3-letter XYZ build code from the constraints - proc xyz {} { - return [x][y][z] - } - - # Construct the test name based on the constraints set - proc name {} { - join [list [file rootname [file tail [info script]]] {*}[constraints]] - - } - - # Construct new unique executable name - proc executable {} { - variable build-count - variable executable - return [set executable [name]-[incr build-count].exe] - } - - # Construct human-readable description of the test according to the contraints set - proc description {} { - set t {} - switch [intersection {c cxx fortran} [constraints]] { - c {lappend t C} - cxx {lappend t C++} - fortran {lappend t FORTRAN} - } - try { - switch [y] { - s {lappend t sequential} - m {lappend t MPI} - t {lappend t multithreaded} - h {lappend t heterogeneous} - } - } on error {} {} - try { - switch [x] { - s {lappend t "single precision"} - d {lappend t "double precision"} - c {lappend t "single precision complex"} - z {lappend t "double precision complex"} - } - } on error {} {} - switch [z] { - o {lappend t optimized} - g {lappend t debugging} - } - if {[constraint? static]} {lappend t static} - join $t - } - - # Set constraints - proc constraints {args} { - variable constraints - try {set constraints} on error {} { - set constraints {} - } - lappend constraints {*}[lsqueeze $args] - } - - # Return true if any of specified contraints is set - proc constraint-any? {args} { - foreach ct $args { - if {[constraint? $ct]} {return 1} - } - return 0 - } - - # Return true if all scpecified constraints are set - proc constraint-all? {args} { - foreach ct $args { - if {![constraint? $ct]} {return 0} - } - return 1 - } - - # Return true if specified constraint is set - proc constraint? {ct} { - variable constraints - expr {[lsearch $constraints $ct] >= 0} - } - - # Test failure is triggered by throwing an exception - ::tcltest::customMatch exception {return 1; #} - - # Main test command - ::np::proc test {{name {}} {description {}} {match {exception}} -- cts script} { - foreach v {executable constraints cppflags xflags cflags cxxflags fflags ldflags libs} {variable $v; catch {unset $v}} - set cts [constraints {*}$cts] - if {$name == {}} {set name [name]} - if {$description == {}} {set description "[description] build"} - ::tcltest::test $name $description -constraints $cts -body $script -match $match - # Attempt to delete the created executable if any to conserve space in the stage dir - # It's OK for the operation to fail at this point as the executable may still be locked - variable executable; try {file delete -force $executable} on error {} {} - } - - # To be used in {all.tcl} - proc suite {args} { - ::tcltest::configure -testdir [file dirname [file normalize [info script]]] {*}$args - ::tcltest::runAllTests - ::tcltest::cleanupTests - } - - # Quick & dirty hack to introduce extra verbosity option(s) - # Override the proc from in tcltest-*.tm - # Original code corresponds to version 2.5.1 - proc ::tcltest::AcceptVerbose { level } { - set level [AcceptList $level] - set levelMap { - x exec - l list - p pass - b body - s skip - t start - e error - l line - m msec - u usec - } - set levelRegexp "^([join [dict values $levelMap] |])\$" - if {[llength $level] == 1} { - if {![regexp $levelRegexp $level]} { - # translate single characters abbreviations to expanded list - set level [string map $levelMap [split $level {}]] - } - } - set valid [list] - foreach v $level { - if {[regexp $levelRegexp $v]} { - lappend valid $v - } - } - return $valid - } - - # Read text file and return list of lines - proc read-file {file} { - set f [open $file r] - try { - return [split [read -nonewline $f] \n] - } finally { - close $f - } - } - - # Return a new list from the specified list entries squashing {} values - proc lsqueeze {list} { - set out [list] - foreach x $list { - if {$x != {}} {lappend out $x} - } - return $out - } - - # Return a new list from the specified arguments squashing {} values - proc collect {args} { - lsqueeze $args - } - - # Return intersection of two lists - proc intersection {a b} { - set x {} - foreach i $a { - if {[lsearch -exact $b $i] != -1} {lappend x $i} - } - return $x - } -} \ No newline at end of file diff --git a/mingw-w64-mumps/testme-0.tm b/mingw-w64-mumps/testme-0.tm new file mode 100644 index 0000000000..f6c6eb69e7 --- /dev/null +++ b/mingw-w64-mumps/testme-0.tm @@ -0,0 +1,640 @@ +# https://github.com/okhlybov/testme + + +package require Tcl + + +package require Thread + + +namespace eval ::testme { + + + namespace export unit + + + proc Import {source} { + variable executor + interp create box + try { + interp alias box ::testme::unit {} ::testme::unit + box eval set ::argv0 [file normalize $source] + box eval set ::nesting [incr $::nesting -1] + box eval { + cd [file dirname $::argv0] + source [file tail $::argv0] + } + } finally { + interp delete box + } + } + + + ### Toplevel code + + + try {set ::nesting} on error {} { + + + package require platform + + + try { + + + ### CLIP code + + + # package require Tcl 8.6 + + + namespace eval ::clip { + + + # defs: { { opt(s) } -slot opt -default value -info "text" -section {common} -apply {script} } + proc parse {argv defs} { + set x [lsearch $argv --] + if {$x < 0} { + set opts $argv + set args {} + } else { + set opts [lrange $argv 0 [expr {$x-1}]] + set args [lrange $argv [expr {$x+1}] end] + } + set xargs {} + lassign [NormalizeDefs $defs] short_flags short_opts long_flags long_opts + set flagset [dict create] + foreach f $short_flags { + dict set flagset [dict get $f bare] $f + } + while {[llength $opts]} { + set x [Next opts] + # long option with inline value, ex. --abc=123 + if {[regexp {^-+([[:alnum:]][[:alnum:]\-\_]*)=(.*)$} $x ~ tag value]} { + set found 0 + foreach d $long_opts { + dict with d { + if {$tag == $bare} { + set found 1 + break + } + } + } + if {$found} { + apply $apply $slot $value + continue + } else { + error "unrecognized option in $x" + } + } + # long/short option expecting separate value, ex. --abc 123 + if {[regexp {^-+([[:alnum:]][[:alnum:]\-\_]*)} $x ~ tag]} { + set found 0 + foreach d [concat $long_opts $short_opts] { + dict with d { + if {$tag == $bare} { + set value [Next opts] + set found 1 + break + } + } + } + if {$found} { + apply $apply $slot $value + continue + } + } + # long/short separate flag, ex. -C, --create + if {[regexp {^-+([[:alnum:]][[:alnum:]\-\_]*)} $x ~ tag]} { + set found 0 + foreach d [concat $long_flags $short_flags] { + dict with d { + if {$tag == $bare} { + set value $default + set found 1 + break + } + } + } + if {$found} { + apply $apply $slot $value + continue + } + } + # short flag within the coalesced flag set, ex. -Sxy + if {[regexp {^-([[:alnum:]]+)$} $x ~ flags]} { + foreach flag [split $flags {}] { + try { + set d [dict get $flagset $flag] + dict with d { + apply $apply $slot $default + } + } on error {} { + error "unrecognized short flag -$flag" + } + } + continue + } + # stray -flag + if {[regexp {^-.*} $x]} { + error "unrecognized argument $x" + } + # the rest arguments are passed through + lappend xargs $x + } + concat $xargs $args + } + + + # + proc usage {defs {sections {}} {chan stdout}} { + set padding [ComputePadding $defs] + dict for {section info} $sections { + PrintSection [ExtractSectionDefs defs $section] $info $chan $padding + } + PrintSection $defs "Generic options" $chan $padding + } + + + proc ComputePadding {defs} { + set pad 0 + foreach def $defs { + set x [string length [FormatOpts [Opts $def]]] + if {$x > $pad} { set pad $x } + } + return $pad + } + + + proc ExtractSectionDefs {defsVar section} { + upvar $defsVar defs + set rest [list] + set filtered [list] + foreach def $defs { + if {[Section $def] == $section} { + lappend filtered $def + } else { + lappend rest $def + } + } + set defs $rest + return $filtered + } + + + proc FormatOpts {opts} { + set arg 0 + set x [lmap opt $opts { + regexp {(.*?)(=*)$} $opt ~ bare flag + if {!$arg && $flag != {}} { set arg 1 } + subst $bare + }] + set x [join $x {, }] + if {$arg} { set x "$x " } + return $x + } + + + proc PrintSection {defs info chan padding} { + if {[llength $defs]} { + incr padding 2 + if {$info != {}} { puts $chan "\n* $info:\n" } + foreach def $defs { + set opts [format %${padding}s [FormatOpts [Opts $def]]] + puts $chan "$opts [Info $def]" + } + } + } + + + proc Opts {def} { lindex $def 0 } + + + proc Dict {def} { lrange $def 1 end } + + + proc Default {def} { + try { return [dict get [Dict $def] -default] } on error {} { return 1 } + } + + + proc Section {def} { + try { return [dict get [Dict $def] -section] } on error {} { return {} } + } + + + proc Info {def} { + try { return [dict get [Dict $def] -info] } on error {} { return {} } + } + + + proc Slot {def} { + try { return [dict get [Dict $def] -slot] } on error {} { return {} } + } + + + proc Apply {def} { + try { return [list {slot value} [dict get [Dict $def] -apply]] } on error {} { return {{slot value} { upvar 2 $slot x; set x $value }} } + } + + + proc Next {listVar} { + upvar $listVar list + if {![llength $list]} { error "not enough arguments" } + set v [lindex $list 0] + set list [lrange $list 1 end] + return $v + } + + + # Flags are the parameterless options which receive 1 value when set, ex. -S + # Single letter flags may be coalesced, ex. -Sxyz + # Multi letter flags must come on their own, ex. -foo + proc NormalizeDefs {defs} { + set short_flags {} + set short_opts {} + set long_flags {} + set long_opts {} + foreach def $defs { + set slot [Slot $def] + foreach opt [Opts $def] { + regexp -- {-+(.*?)=?} $opt ~ bare + if {$slot == {}} { set slot $bare } + switch -regexp $opt { + {^-[[:alnum:]]$} { set kind short_flags } + {^-+[[:alnum:]][[:alnum:]\-\_]*$} { set kind long_flags } + {^-[[:alnum:]]=$} { set kind short_opts } + {^-+[[:alnum:]][[:alnum:]\-\_]*=$} { set kind long_opts } + default { error "failed to decode option descriptor $opt" } + } + lappend $kind [dict create bare $bare slot $slot default [Default $def] apply [Apply $def] info [Info $def] section [Section $def]] + } + } + return [list $short_flags $short_opts $long_flags $long_opts] + } + + + } + + + variable verbose false + + + variable quiet false + + + variable staging false + + + variable premature false + + + variable cleanup true + + + variable jobs 0 + + + set opts { + {{--jobs= -j=} -info "set maximum number of allowed threads" -default 0 -slot jobs} + {{-v --verbose} -info "dump unit output to standard error channel" -default true -slot verbose} + {{-T --staging} -info "manage staging directory in \$TMPDIR" -default true -slot staging} + {{-K --keep} -info "keep temporary directories & files" -default false -slot cleanup} + {{-e --bailout} -info "bail out on first failure" -default true -slot premature} + {{-q --quiet} -info "suppress TAP output to standard output channel" -default true -slot quiet} + {{-h --help} -info "print help" -apply { + puts stderr "usage: $::argv0 {-f --flag --opt=arg --opt arg -opt arg ...} {--} {tag +tag -tag ...}" + puts stderr {} + puts stderr " +tag | tag instruct to execute only units with specified tag(s)" + puts stderr " -tag instruct to skip units with specified tag(s)" + clip::usage $testme::opts {} stderr + exit 0 + }} + {{--version} -info "print package version" -apply { + puts stderr [package require testme] + exit 0 + }} + } + + + if {[catch { + if {[llength $::argv]} {set ::argv [clip::parse $::argv $opts]} + } return]} { + puts stderr $return + exit 1 + } + + + # TODO + if {$jobs == 0} { + set jobs 4 + switch -glob [platform::identify] { + linux-* {catch {set jobs [exec nproc --all]}} + win32-* {catch {set jobs $env(NUMBER_OF_PROCESSORS)}} + } + } + + + set +tags [list] + set -tags [list] + + + foreach arg $::argv { + switch -glob $arg { + +* {lappend +tags [string trimleft $arg +]} + -* {lappend -tags [string trimleft $arg -]} + default {lappend +tags $arg} + } + } + + + set ::nesting -1 + + + set paths "eval tcl::tm::path add [tcl::tm::path list]" + + + set static { + + + ### Execution thread code + + + proc lshift {var} { + upvar 1 $var x + set r [lindex $x 0] + set x [lrange $x 1 end] + return $r + } + + + proc lfront {list} { + return [lindex $list 0] + } + + + rename puts ::tcl::puts + + + proc puts {args} { + variable stdout + variable stderr + set xargs $args + if {[llength $args] > 1 && [lfront $args] == "-nonewline"} { + lshift args + set newline 0 + } else { + set newline 1 + } + switch [llength $args] { + 1 {set chan stdout} + default {set chan [lshift args]} + } + if {$chan == "stdout" || $chan == "stderr"} { + if {$newline} { + foreach arg $args {lappend $chan $arg} + } else { + set $chan [concat [lrange [set $chan] 0 end-1] "[lindex [set $chan] end]$args"] + } + } else { + tcl::puts {*}$xargs + } + } + + + proc skip {{reason {}}} {return -code 1073741823 -level 0 $reason} + + + proc process-unit {unit} { + variable stdout [list] + variable stderr [list] + interp create unit + try { + interp alias unit puts {} puts + interp alias unit skip {} skip + unit eval tcl::tm::path add {*}[tcl::tm::path list] + catch {unit eval "apply {{unit} {[dict get $unit -code]}} {$unit}"} return opts + return [dict merge $opts [dict create -return $return -stdout $stdout -stderr $stderr -id [dict get $unit -id]]] + } finally { + interp delete unit + } + } + + + } + + + variable executor [tpool::create -maxworkers $jobs -initcmd "$paths; $static;"] + + + variable pending [list] + + + variable skipped [list] + + + variable units [dict create] + + + variable id 1 + + + proc union {as bs} { + set result $as + foreach elem $bs { + if {[lsearch -exact $as $elem] == -1} { + lappend result $elem + } + } + return $result + } + + + proc intersection {as bs} { + set result {} + foreach elem $bs { + if {[lsearch -exact $as $elem] >= 0} { + lappend result $elem + } + } + return $result + } + + + proc unit {args} { + variable executor + variable pending + variable skipped + variable units + variable +tags + variable -tags + variable cleanup + variable id + set s [llength $args] + if {$s < 1 || $s % 2 == 0} {error "usage: testme::unit ?-name ...? ?-tags ...? {...}"} + set opts [lrange $args 0 end-1] + set code [lindex [lrange $args end end] 0] + set name unit[llength $pending] + set tags [list] + catch {set name [dict get $opts -name]} + catch {set tags [dict get $opts -tags]} + set tags [lsearch -inline -all -not -exact $tags {}]; # Squeeze out empty {} tags + set unit [dict create {*}$opts -stage [pwd] -name $name -tags $tags -code $code -id $id -source $::argv0 -cleanup $cleanup] + dict set units $id $unit + if {([llength ${+tags}] == 0 || [llength [intersection ${+tags} $tags]] > 0) && [llength [intersection ${-tags} $tags]] == 0} { + lappend pending [tpool::post $executor "process-unit {$unit}"] + } else { + lappend skipped $id + } + incr id + } + + + if {$staging} { + + + proc MakeTempDir {args} { + set roots $args + foreach t {TMPDIR TMP} { + if {![catch {set t [set ::env($t)]}]} { + lappend roots $t + } + } + lappend roots /tmp + foreach r $roots { + if {![catch { + set t [file join $r [expr {int(rand()*999999)}]] + file mkdir $t + }]} { + return $t + } + } + error "failed to create temporary directory $t" + } + + + set staging [set ::env(TMPDIR) [MakeTempDir]] + + + if {$verbose} {puts stderr "created temporary directory $staging"} + + } + + + try { + + + Import $::argv0 + + + if {!$quiet} { + puts "TAP version 14" + puts "1..[dict size $units]" + foreach s $skipped { + set u [dict get $units $s] + puts "ok [dict get $u -id] - [dict get $u -name] # SKIP due to tagging" + } + } + + + while {[llength $pending]} { + foreach f [tpool::wait $executor $pending pending] { + set pending [lsearch -inline -all -not -exact $pending $f] + set return [tpool::get $executor $f] + set u [dict get $units [dict get $return -id]] + set name [dict get $u -name] + set id [dict get $u -id] + if {!$quiet} { + switch [dict get $return -code] { + 0 {puts "ok $id - $name"} + 1073741823 {puts "ok $id - $name # SKIP [dict get $return -return]"} + default { + puts "not ok $id - $name" + puts " ---" + set lines [split [dict get $return -return] "\n"] + set r [lindex $lines 0] + if {[llength $lines] > 1} {set r "$r >>>"} + puts " tags: [dict get $u -tags]" + puts " source: [dict get $u -source]" + puts " return: $r" + puts " ..." + } + } + } + if {$verbose} { + set stdout [dict get $return -stdout] + set stderr [dict get $return -stderr] + if {[llength $stdout] + [llength $stderr] > 0} { + puts stderr {} + puts stderr "- $name" + if {[llength $stdout] > 0} { + puts stderr "-- stdout:" + foreach line $stdout {puts stderr $line} + } + if {[llength $stderr] > 0} { + puts stderr "-- stderr:" + foreach line $stderr {puts stderr $line} + } + } + } + flush stdout + flush stderr + if {$premature && [dict get $return -code] != 0} {error "bailing out on failure"} + } + } + + + } finally { + + + if {$cleanup && $staging != {false}} { + if {[catch {file delete -force -- $staging}]} { + if {$verbose} {puts stderr "failed to remove temporary directory $staging"} + } else { + if {$verbose} {puts stderr "removed temporary directory $staging"} + } + } + + + } + + + exit 0 + + + } on error {return opts} { + if {$verbose} { + puts stderr $return + puts stderr [dict get $opts -errorinfo] + } + if {!$quiet} {puts "Bail out!"} + exit 1 + } + + + } + + + ### Nested code + + + if {$::nesting != 0} { + set wd [pwd] + foreach source [glob -nocomplain [file join * [file tail $::argv0]]] { + try {Import $source} finally {cd $wd} + } + } + + + ### Custom code which slurped the testme package's code + + + proc with {var list code} { + upvar 1 $var v + if {[catch {set v}]} {set v [list]} + set list [concat $v $list] + apply [list $var $code] $list + } + + +} \ No newline at end of file diff --git a/mingw-w64-mumps/xyz-0.tm b/mingw-w64-mumps/xyz-0.tm new file mode 100644 index 0000000000..cf6710770a --- /dev/null +++ b/mingw-w64-mumps/xyz-0.tm @@ -0,0 +1,54 @@ +package require testme + + +namespace eval ::xyz { + + + proc unit {prefix tags args} { + testme::unit -tags $tags -name [DescribeXYZ $prefix $tags] -xyz [DeduceXYZ $tags] -static [DeduceStatic $tags] {*}$args + } + + + proc any? {tag tags} { + foreach t $tag { + if {[lsearch -exact $tags $t] >= 0} {return 1} + } + return 0 + } + + + proc DeduceXYZ {tags} { + if {[any? debug $tags]} {set z g} else {set z o} + if {[any? mpi $tags]} {set y m} { + if {[any? {omp openmp} $tags]} {set y t} else {set y s} + } + if {[any? complex $tags]} { + if {[any? single $tags]} {set x c} else {set x z} + } else { + if {[any? single $tags]} {set x s} else {set x d} + } + return $x$y$z + } + + + proc DescribeXYZ {prefix tags} { + set prefix "$prefix:" + if {[any? single $tags]} {set prefix "$prefix single-precision"} + if {[any? double $tags]} {set prefix "$prefix double-precision"} + if {[any? complex $tags]} {set prefix "$prefix complex"} + if {[any? mpi $tags]} {set prefix "$prefix MPI"} else {if {[any? {omp openmp} $tags]} {set prefix "$prefix OpenMP"}} + if {[any? debug $tags]} {set prefix "$prefix debug"} + if {[any? c $tags]} {set prefix "$prefix C"} + if {[any? fortran $tags]} {set prefix "$prefix FORTRAN"} + if {[any? static $tags]} {set prefix "$prefix static"} + set prefix "$prefix build" + return $prefix + } + + + proc DeduceStatic {tags} { + if {[any? static $tags]} {return {-static}} else {return {}} + } + + +} \ No newline at end of file