summaryrefslogtreecommitdiff
path: root/libstdc++-v3/mkcheck.in
blob: 9d676e8c85c514b073de79e25c3a8eba8e890f05 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
#!/usr/bin/env bash


# Script to do automated testing and data collection for various test
# files, so that we don't have to do this by hand on every test file.
# It attempts to collect some diagnostic info about size and speed that
# should be useful in the future as the library gets tuned for size
# and speed.  In addition, it tests static and shared linkage, iff each
# has been enabled.

# Invocation 
# mkcheck [012] (path to build) (path to src) (path to install)

### XXX There are a lot of tests in here for OS-specific stuff.  If we
###     move to a 'configure.target' method of determining those extra
###     flags and whatnot, we can take out all those things and source
###     that file from here.  (Write that file with this in mind...)

### XXX Note that breaking out of this with ^C will not work.  Dunno why.


#
# 1: variables
#
# WHICH determines if you are
# (0) testing the build binary and headers, or
# (1) testing the installed binary and headers, or
# (2) testing under dejagnu (just print the standard flags needed).
WHICH=$1
if [ "$WHICH"x = 0x ] && [ $# -eq 3 ]; then
  echo "running mkcheck"
  echo "$0: testing the build directory"
elif [ "$WHICH"x = 1x ] && [ $# -eq 4 ]; then
  echo "running mkcheck"
  echo "$0: testing the install directory $4"
elif [ "$WHICH"x = 2x ] && [ $# -eq 3 ]; then
  true
else
  echo 'Usage: mkcheck 0 (path to build) (path to src)'
  echo '       mkcheck 1 (path to build) (path to src) (path to install)'
  echo '       mkcheck 2 (path to build) (path to src)'
  exit 1;
fi
  
BUILD_DIR=$2
if [ ! -d "$BUILD_DIR" ]; then
  echo "build directory $BUILD_DIR not found, exiting."
  exit 1
fi

SRC_DIR=$3
if [ ! -d "$SRC_DIR" ]; then
  echo "source directory $SRC_DIR not found, exiting."
  exit 1
fi

if [ $WHICH -eq 1 ]; then 
    PREFIX_DIR=$4
    if [ ! -d "$PREFIX_DIR" ]; then
    echo "install directory $PREFIX_DIR not found, exiting."
    exit 1
    fi
fi

# This is LIBTOOL=@LIBTOOL@ piped through a bit of sanity that we can
# assume for this script (by the time we run this).
LIBTOOL="$BUILD_DIR/libtool"
chmod u+x $LIBTOOL

# INC_PATH == include path to new headers for use on gcc command-line
top_srcdir=@top_srcdir@
C_DIR="`basename @C_INCLUDE_DIR@`"
if [ $WHICH != "1" ]; then
  INC_PATH="-nostdinc++ @CSHADOW_FLAGS@ -I$BUILD_DIR/include \
    -I$SRC_DIR/include/std  -I$SRC_DIR/include/$C_DIR \
    -I$SRC_DIR/include -I$SRC_DIR/libsupc++ -I$SRC_DIR/libio \
    -I$SRC_DIR/testsuite"
elif [ $WHICH -eq 1 ]; then
  INC_PATH="-I$SRC_DIR/testsuite"
fi

if [ $WHICH -eq 2 ]; then
  echo $INC_PATH -I$SRC_DIR/include/backward -I$SRC_DIR/include/ext
  exit 0;
fi

# This has been true all along.  Found out about it the hard way...
case $BASH_VERSION in
    1*)  echo 'You need bash 2.x to run mkcheck.  Exiting.'; exit 1 ;;
    *)   ;;   # ??
esac

# It's not dejagnu; we need to do things ourselves.  Pick up any extra
# settings for this target.
. ${top_srcdir}/configure.target

# LIB_PATH == where to find the build libraries for libtool's use
# CXX == how to call the compiler
if [ $WHICH -eq 0 ]; then
  LIB_PATH="$BUILD_DIR/src"
  CXX="$BUILD_DIR/../../gcc/g++ -B$BUILD_DIR/../../gcc/"
elif [ $WHICH -eq 1 ]; then
  LIB_PATH="$PREFIX_DIR/lib"
  CXX="$PREFIX_DIR/bin/g++"
fi

# gcc compiler flags (maybe use glibcpp_cxxflags from configure.target,
# but thst's really meant for building the library itself, not using it)
CXX_FLAG="-ggdb3 -DDEBUG_ASSERT @SECTION_FLAGS@ @SECTION_LDFLAGS@"

# specific libtool flag(s) to force the use of shared libraries, if any
SH_FLAG=""

# specific libtool flag(s) to force the use of static libraries, if any
#ST_FLAG="-static"
ST_FLAG="-all-static"

# LTCXX == how to call libtool when creating an executable
# LTEXE == how to call libtool when running an executable
# LIBS == any extra needed -l switches, etc (may need more libs, lose lose)
if [ $WHICH -eq 0 ]; then
  LTCXX="$LIBTOOL --tag=CXX --mode=link \
          $CXX $CXX_FLAG $INC_PATH   \
          $LIB_PATH/../libsupc++/libsupc++.la  $LIB_PATH/libstdc++.la   \
          -no-install"
  LTEXE="$LIBTOOL --mode=execute"
  LIBS="-nodefaultlibs -lc -lgcc -lc"
elif [ $WHICH -eq 1 ]; then
  # For the installed version, we really only need to use libtool and
  # the .la file to get correct rpaths.
  LTCXX="$LIBTOOL --tag=CXX --mode=link \
          $CXX $CXX_FLAG $INC_PATH -L$LIB_PATH   \
          $LIB_PATH/libstdc++.la -no-install -rpath $LIB_PATH"
  LTEXE="$LIBTOOL --mode=execute"
  LIBS=
fi

# Set up the testing directory, which should be in a directory called
# "testsuite" in the root level of the build directory.
TEST_DIR="`pwd`/testsuite"
if [ ! -d "$TEST_DIR" ]; then
    echo "making directory $TEST_DIR"
    mkdir $TEST_DIR
    mkdir $TEST_DIR/.libs    # help libtool keep quiet
    chmod u+w $TEST_DIR
fi

# the name of the file that will collect and hold all this useful data:
RESULTS_FILE="$TEST_DIR/$(date +%Y%m%d)-mkcheck.txt"

# the name of the log file that will append compiler diagnostics:
LOG_FILE="$TEST_DIR/$(date +%Y%m%d)-mkchecklog.txt"

# the names of the specific test files to be run
TESTS_FILE="$TEST_DIR/$(date +%Y%m%d)-mkcheckfiles.txt"

# the heap size limit for testsuite binaries; start with a 2MB limit as per
# http://sources.redhat.com/ml/libstdc++/2000-10/msg00029.html
MAX_MEM_USAGE=3072

#
# 2: clean, make files, append general test info
#
if [ -f $RESULTS_FILE ]; then
    rm $RESULTS_FILE
fi
if [ -f $LOG_FILE ]; then
    rm $LOG_FILE
fi

# Make a list of the files we're going to run, or use an old one if it exists.
if [ ! -f "$TESTS_FILE" ]; then
    echo "making file $TESTS_FILE"
    for LONG_NAME in $SRC_DIR/testsuite/*/*.cc
    do
        DIR_NAME=$(dirname $LONG_NAME)
        SHORT_NAME="`basename $DIR_NAME`/`basename $LONG_NAME`"
        echo "$SHORT_NAME" >> $TESTS_FILE
    done
fi

# Nasty solution to replace GNU date(1)'s %s time_t output function.
if [ ! -x "$TEST_DIR/printnow" ]; then
    echo "making utility $TEST_DIR/printnow"
    gcc -o "$TEST_DIR/printnow" "$SRC_DIR/testsuite/printnow.c"
    strip "$TEST_DIR/printnow"
fi

# Remove old executables.
rm -rf "$TEST_DIR"/*exe

# Remove old core files (which now get left in cwd, not $TEST_DIR).
rm -rf ./*core*

# Copy over the data files for filebufs
cp $SRC_DIR/testsuite/27_io/*.txt $TEST_DIR
cp $SRC_DIR/testsuite/27_io/*.tst $TEST_DIR
chmod u+w $TEST_DIR/*.txt
chmod u+w $TEST_DIR/*.tst

# Emit useful info about compiler and platform
echo "host: $(uname -mrsv)" >> $RESULTS_FILE
echo "compiler: $($CXX -v 2>&1 | tail -1)" >> $RESULTS_FILE
echo "$($CXX -v 2>&1 | grep ^Configured)" >> $RESULTS_FILE
echo "compiler flags: $CXX_FLAG" >> $RESULTS_FILE
echo "date: $(date +%Y%m%d)" >> $RESULTS_FILE
echo "" >> $RESULTS_FILE

explanation='+: pass, -b: build failure, -r: run failure, x: disabled'
printf "%s\n     %s\n"  'p == pass/fail execution test'  "$explanation"  \
       >> $RESULTS_FILE
echo "ctime == time to compile and link" >> $RESULTS_FILE
echo "etime == time for executable to run" >> $RESULTS_FILE
echo "text == size of the executable text section" >> $RESULTS_FILE
echo "data == size of the executable data section" >> $RESULTS_FILE
echo "total == size of the executable" >> $RESULTS_FILE
echo "" >> $RESULTS_FILE
echo "(First static, then shared.)" >> $RESULTS_FILE

echo "p" | awk '{printf("%s ", $1)}' >> $RESULTS_FILE
echo "ctime" "etime" | awk '{printf("%s\t%s\t", $1, $2)}' >> $RESULTS_FILE
echo "text" "data" | awk '{printf("%s\t%s\t", $1, $2)}' >> $RESULTS_FILE
echo "total" "name" | awk '{printf("%s\t%s\t", $1, $2)}' >> $RESULTS_FILE
echo "" >> $RESULTS_FILE


#
# 2.5:  support functions
#

# Figure out how to extract size information from binaries.  We take
# the text of the value we want as an argument, and leave the size in
# the appropriate variable.
#
# We discover what kind of size(1) we are using *once* and build a shell
# function named 'size_command' to wrap it.  (The "function" keyword is
# redundant here, but helps me read it, so there.)  Previously we were
# re-discovering the size(1) arguments three times for each test; sloooow.
#
# It is VERY IMPORTANT not to compare these numbers across platforms.
# Different size(1)'s extract section information differently.  For
# example, using the native Sun size(1) and GNU size(1) built for Suns
# on the exact same binary will give very different numbers, due to all
# the variance in command-line options and arbitrary names of ELF sections.
#
# and suddenly we go to 2-space indentations...
setup_size_command()
{
  if size --version 2> /dev/null | grep -c GNU > /dev/null;
  then    # Then we're using a GNU size(1) built for this platform.
    # We lose .rodata and .data1 and who knows what else... kludge.
    function size_command()
    {
      case $1 in
        TEXT)  TEXT=$(size -A $EXENAME | grep ^.text | awk '{print $2}')  ;;
        DATA)  DATA=$(size -A $EXENAME | grep -w ^.data | awk '{print $2}')  ;;
        SIZE)  SIZE=$(size -A $EXENAME | grep otal | awk '{print $2}')  ;;
      esac
    }
  else
    # Not using GNU size; check for platform.  These numbers seem to match
    # up to text/data/total, although their meanings seem to be different.
    # THIS TABLE IS SORTED.  KEEP IT THAT WAY.
    case @host_os@ in
      *aix*)
        function size_command()
        {
          case $1 in
            TEXT)  TEXT=$(size -X32_64 $EXENAME | awk '{print $2}')  ;;
            DATA)  DATA=$(size -X32_64 $EXENAME | awk '{print $4}')  ;;
            SIZE)  SIZE=$(size -X32_64 $EXENAME | awk '{print $12}')  ;;
          esac
        }
        ;;
      *irix*)
        function size_command()
        {
          case $1 in
            TEXT)  TEXT=$(size -4 $EXENAME | awk '{print $1}')  ;;
            DATA)  DATA=$(size -4 $EXENAME | awk '{print $3}')  ;;
            SIZE)  SIZE=$(size -4 $EXENAME | awk '{print $7}')  ;;
          esac
        }
        ;;
      *solaris*)
        function size_command()
        {
          case $1 in
            TEXT)  TEXT=$(size $EXENAME | awk '{print $1}')  ;;
            DATA)  DATA=$(size $EXENAME | awk '{print $3}')  ;;
            SIZE)  SIZE=$(size $EXENAME | awk '{print $7}')  ;;
          esac
        }
        ;;
      *)
        echo ' * Warning!  Skipping section sizes!' 1>&2
        function size_command()
        {
        case $1 in
          TEXT)  TEXT=0 ;;
          DATA)  DATA=0 ;;
          SIZE)  SIZE=0 ;;
        esac
        }
        ;;
    esac
  fi
}

# Test for file output
test_for_output()
{
    # This checks for emitted output files, which is useful when
    # testing file-related output.  The rules for this working are as
    # follows: the emitted file must have the ".txt" extension, and be
    # based on the actual *.cc file's name.  For example, 27/filbuf.cc
    # currently outputs files named 27/filebuf-2.txt and 27/filebuf-3.txt.
    # Also, the first emitted file must be in the form $NAME-1.txt.
    # The control file must follow the same constraints, but have a
    # ".tst" extension.  Thus, you have 27/filebuf-2.tst, etc.

    # NAME contains the source name, like 27/filebuf.cc
    # From that NAME, we want to generate some possible names, using
    # ls on MATCH, a pattern description generated with sed.

    # this is the name of the resulting diff file, if any
    DIFF_FILE="`echo $TEST_NAME | sed 's/cc$/diff/'`"
    # construct wildcard names, ie for $NAME=filebuf.cc, makes "filebuf*.tst"
    DATA_FILES="`echo $NAME | sed 's/\.cc/\*\.tst/g'`"
    # make sure there is at least one, then go
    ST_E="`echo $NAME | sed 's/\.cc/\-1\.tst/g'`"
    if [ -f $ST_E ]; then
        # list of actual files that match the wildcard above, ie
        # "filebuf-1.tst"
        ST_MATCH_LIST="`ls $DATA_FILES`"
        for i in $ST_MATCH_LIST; do
            # ST_OUT_FILE is generated in the build directory.
            PRE_NAME2="$TEST_DIR/`basename $i`"
            ST_OUT_FILE="`echo $PRE_NAME2 | sed 's/tst$/txt/'`"
            diff $ST_OUT_FILE $i > $DIFF_FILE
            if [ -s $DIFF_FILE ]; then
                RESULT="-r"
                echo "$ST_OUT_FILE has some problems, dude"
            else
                RESULT="+"
            fi
            rm $DIFF_FILE
        done
    else
        # the file does no output, and didn't abnormally
        # terminate, so assume passed.
        RESULT="+"
    fi
}
    

#
# 3: compile, link, execute, time
#
# Abstract out the common code for compiling, linking, executing and printing.
test_file()
{
    # NB: S_FLAG has to be last argument because it may be null, and
    # error checking hasn't been invented yet.
    NAME=$1
    EXENAME=$2
    S_FLAG=$3

    SRC_NAME="$SRC_DIR/testsuite/$1"
    TEST_NAME="$TEST_DIR/`basename $NAME`"

    # This would be deliciously easy if GNU date's %s were always around.
    # There are three ways to do this:  1) use the builtin 'time' like we
    # do later; then getting compiler errors into LOG_FILE is a nightmare.
    # 2) Grab the output of a formatted date(1) and do the math; harder
    # and harder as we try compiling at, say, top of the hour; we would
    # eventually have to calculate time_t anyhow.  Or 3) just grab two
    # time_t's (no more overhead than grabbing two date(1)'s).
    compiler_invocation="$LTCXX $S_FLAG $SRC_NAME -o $EXENAME $LIBS"
    # Why the leading weird character, like a colon?  That way you can
    # 'grep -v ^: *mkchecklog.txt' and just see the errors.
    #printf "\n: " >> $LOG_FILE
    printf "\n" >> $LOG_FILE
    COMP_TIME_START=$($TEST_DIR/printnow)
    $compiler_invocation >> $LOG_FILE 2>&1
    COMP_TIME_END=$($TEST_DIR/printnow)

    if [ $COMP_TIME_START -lt $COMP_TIME_END ]; then
        C_TIME=$[ $COMP_TIME_END - $COMP_TIME_START ]
    else
        C_TIME="0"
    fi

    if [ -f $EXENAME ]; then
        size_command TEXT
        size_command DATA
        size_command SIZE

        # Actually run the executable and time it.  Note that output
        # printed by the executable will be lost and cannot be redirected,
        # because we need to capture the output of 'time'.  Bummer.
        TIMEFORMAT='timemark %R'
        E_TIME_TEXT="$(exec 2>&1; ulimit -d $MAX_MEM_USAGE; \
                     time $LTEXE $EXENAME)"
        E_ABNORMAL_TERMINATION=$?
        E_TIME="$(echo $E_TIME_TEXT | awk '{print $2}')"
        # joining those two commands does not work due to quoting problems:
        #E_TIME="$(exec 2>&1; time $EXENAME | awk '{print $2}')"
        # this will work as a fallback on certain systems...?
        #E_TIME=$(exec 2>&1; time $EXENAME | cut -d ' ' -f 2)
 
        if [ "$E_ABNORMAL_TERMINATION" -ne 0 ]; then
            RESULT='-r'
            rm -f ./*core
            # sometimes you want to save all core files for review:
            #mv ./core $EXENAME.core
            # sometimes the OS allows you to name core files yourself:
            #mv ./*core $EXENAME.core
            #mv ./core* $EXENAME.core
        else
            test_for_output
        fi

        # sometimes you want to save all failing exe files for review:
        if [ "$RESULT" = "+" ]; then
            rm "$EXENAME"
        fi
    else
        # the file did not compile/link.
        RESULT="-b"
        TEXT="0"
        DATA="0"
        SIZE="0"
    fi

    printf "%s\t" "$RESULT"
    printf "%-2s %d\t%.3f\t%s\t%s\t%s\t%s\n"   \
        "$RESULT" $C_TIME $E_TIME $TEXT $DATA $SIZE $NAME >> $RESULTS_FILE
}

setup_size_command
echo ""
echo "Detailed test results in .${RESULTS_FILE/$BUILD_DIR}"
echo $explanation
echo "------------------------------------------------------------------------"
printf "static\tshared\ttest\n"
echo "------------------------------------------------------------------------"

TEST_TIME_START=$($TEST_DIR/printnow)
for NAME in `cat $TESTS_FILE`
do
    PRE_NAME="$TEST_DIR/`basename $NAME`"
    ST_NAME="`echo $PRE_NAME | sed 's/cc$/st-exe/'`"
    SH_NAME="`echo $PRE_NAME | sed 's/cc$/sh-exe/'`"

    if test @enable_static@ = yes; then
        test_file $NAME $ST_NAME $ST_FLAG 
    else
        printf "x\t"
        printf "static skipped\n" >> $RESULTS_FILE
    fi
    if test @enable_shared@ = yes; then
        test_file $NAME $SH_NAME $SH_FLAG 
    else
        printf "x\t"
        printf "shared skipped\n" >> $RESULTS_FILE
    fi
    printf "%s\n" "$NAME"

    echo "" >> $RESULTS_FILE
done
TEST_TIME_END=$($TEST_DIR/printnow)


#
# 4: summary
#
# grep can count faster than we can...
total_failures=$(egrep -c "^\-" $RESULTS_FILE)
total_successes=$(egrep -c "^\+" $RESULTS_FILE)
resultstext="pass/fail results:  ${total_successes}/${total_failures}"
if [ $total_failures -eq 0 ]; then
    resultstext="${resultstext}, WIN WIN"
fi
sed -e "/^date:/a\\
$resultstext" $RESULTS_FILE > ${RESULTS_FILE}.tmp
mv ${RESULTS_FILE}.tmp $RESULTS_FILE

if [ $TEST_TIME_START -lt $TEST_TIME_END ]; then
    TEST_TIME=$[ $TEST_TIME_END - $TEST_TIME_START ]
    echo "testrun == $TEST_TIME seconds"
    echo "testrun == $TEST_TIME seconds" >> $RESULTS_FILE
fi

exit 0