From 7d8cafa8e0ae228f94c615a8bb9043aa7a751114 Mon Sep 17 00:00:00 2001
From: Iain Buclaw <ibuclaw@gdcproject.org>
Date: Fri, 26 May 2017 23:35:09 +0200
Subject: [PATCH 09/14] Add D2 Testsuite Dejagnu files.

This patch adds D language support to the GCC testsuite.

As well as generating the DejaGNU options for compile and link tests, handles the conversion from DMD-style compiler options to GDC.

---
 gcc/testsuite/gdc.test/d_do_test.exp | 404 +++++++++++++++++++++++++++
 gcc/testsuite/lib/gdc-dg.exp         |  88 ++++++
 gcc/testsuite/lib/gdc.exp            | 277 ++++++++++++++++++
 3 files changed, 769 insertions(+)
 create mode 100644 gcc/testsuite/gdc.test/d_do_test.exp
 create mode 100644 gcc/testsuite/lib/gdc-dg.exp
 create mode 100644 gcc/testsuite/lib/gdc.exp

diff --git a/gcc/testsuite/gdc.test/d_do_test.exp b/gcc/testsuite/gdc.test/d_do_test.exp
new file mode 100644
index 00000000000..a3c49165bbd
--- /dev/null
+++ b/gcc/testsuite/gdc.test/d_do_test.exp
@@ -0,0 +1,404 @@
+# Copyright (C) 2012-2018 Free Software Foundation, Inc.
+
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with GCC; see the file COPYING3.  If not see
+# <http://www.gnu.org/licenses/>.
+
+# Test using the DMD testsuite.
+# Load support procs.
+load_lib gdc-dg.exp
+
+#
+# Convert DMD arguments to GDC equivalent
+#
+
+proc gdc-convert-args { base args } {
+    set out ""
+
+    foreach arg [split [lindex $args 0] " "] {
+        # List of switches kept in ASCII collated order.
+        if { [regexp -- {^-I([\w+/-]+)} $arg pattern path] } {
+            lappend out "-I$base/$path"
+
+        } elseif { [regexp -- {^-J([\w+/-]+)} $arg pattern path] } {
+            lappend out "-J$base/$path"
+
+        } elseif [string match "-allinst" $arg] {
+            lappend out "-fall-instantiations"
+
+        } elseif { [string match "-boundscheck" $arg]
+                 || [string match "-boundscheck=on" $arg] } {
+            lappend out "-fbounds-check"
+
+        } elseif { [string match "-boundscheck=off" $arg]
+                   || [string match "-noboundscheck" $arg] } {
+            lappend out "-fno-bounds-check"
+
+        } elseif [string match "-boundscheck=safeonly" $arg] {
+            lappend out "-fbounds-check=safeonly"
+
+        } elseif [string match "-c" $arg] {
+            lappend out "-c"
+
+        } elseif [string match "-d" $arg] {
+            lappend out "-Wno-deprecated"
+
+        } elseif [string match "-de" $arg] {
+            lappend out "-Wdeprecated"
+            lappend out "-Werror"
+
+        } elseif [string match "-debug" $arg] {
+            lappend out "-fdebug"
+
+        } elseif [regexp -- {^-debug=(\w+)} $arg pattern value] {
+            lappend out "-fdebug=$value"
+
+        } elseif [string match "-dip1000" $arg] {
+            lappend out "-ftransition=dip1000"
+
+        } elseif [string match "-dip25" $arg] {
+            lappend out "-ftransition=dip25"
+
+        } elseif [string match "-dw" $arg] {
+            lappend out "-Wdeprecated"
+            lappend out "-Wno-error"
+
+        } elseif [string match "-fPIC" $arg] {
+            lappend out "-fPIC"
+
+        } elseif { [string match "-g" $arg]
+                   || [string match "-gc" $arg] } {
+            lappend out "-g"
+
+        } elseif [string match "-inline" $arg] {
+            lappend out "-finline-functions"
+
+        } elseif [string match "-main" $arg] {
+            lappend out "-fmain"
+
+        } elseif [regexp -- {^-mv=([\w+=./-]+)} $arg pattern value] {
+            lappend out "-fmodule-file=$value"
+
+        } elseif [string match "-O" $arg] {
+            lappend out "-O2"
+
+        } elseif [string match "-release" $arg] {
+            lappend out "-frelease"
+
+        } elseif [regexp -- {^-transition=(\w+)} $arg pattern value] {
+            lappend out "-ftransition=$value"
+
+        } elseif [string match "-unittest" $arg] {
+            lappend out "-funittest"
+
+        } elseif [string match "-verrors=spec" $arg] {
+            lappend out "-Wspeculative"
+
+        } elseif [regexp -- {^-verrors=(\d+)} $arg pattern num] {
+            lappend out "-fmax-errors=$num"
+
+        } elseif [regexp -- {^-version=(\w+)} $arg pattern value] {
+            lappend out "-fversion=$value"
+
+        } elseif [string match "-vtls" $arg] {
+            lappend out "-ftransition=tls"
+
+        } elseif [string match "-w" $arg] {
+            lappend out "-Wall"
+            lappend out "-Werror"
+
+        } elseif [string match "-wi" $arg] {
+            lappend out "-Wall"
+            lappend out "-Wno-error"
+
+        } else {
+            # print "Unhandled Argument: $arg"
+        }
+    }
+
+    return $out
+}
+
+proc gdc-copy-extra { base extra } {
+    # Split base, folder/file.
+    set type [file dirname $extra]
+
+    # print "Filename: $base - $extra"
+
+    set fdin [open $base/$extra r]
+    fconfigure $fdin -encoding binary
+
+    file mkdir $type
+    set fdout [open $extra w]
+    fconfigure $fdout -encoding binary
+
+    while { [gets $fdin copy_line] >= 0 } {
+        set out_line $copy_line
+        puts $fdout $out_line
+    }
+
+    close $fdin
+    close $fdout
+
+    return $extra
+}
+
+#
+# Translate DMD test directives to dejagnu equivalent.
+#
+#   COMPILE_SEPARATELY: Not handled.
+#   EXECUTE_ARGS:       Parameters to add to the execution of the test.
+#   EXTRA_SOURCES:      List of extra sources to build and link along with
+#                       the test.
+#   EXTRA_FILES:        List of extra files to copy for the test runs.
+#   PERMUTE_ARGS:       The set of arguments to permute in multiple compiler
+#                       invocations.  An empty set means only one permutation
+#                       with no arguments.
+#   TEST_OUTPUT:        The output expected from the compilation.
+#   POST_SCRIPT:        Not handled.
+#   REQUIRED_ARGS:      Arguments to add to the compiler command line.
+#   DISABLED:           Not handled.
+#
+
+proc dmd2dg { base test } {
+    global DEFAULT_DFLAGS
+    global PERMUTE_ARGS
+    global GDC_EXECUTE_ARGS
+
+    set PERMUTE_ARGS $DEFAULT_DFLAGS
+    set GDC_EXECUTE_ARGS ""
+
+    # Split base, folder/file.
+    set type [file dirname $test]
+
+    # print "Filename: $base - $test"
+
+    set fdin [open $base/$test r]
+    #fconfigure $fdin -encoding binary
+
+    file mkdir $type
+    set fdout [open $test w]
+    #fconfigure $fdout -encoding binary
+
+    while { [gets $fdin copy_line] >= 0 } {
+        set out_line $copy_line
+
+        if [regexp -- {COMPILE_SEPARATELY} $copy_line] {
+            # COMPILE_SEPARATELY is not handled.
+            regsub -- {COMPILE_SEPARATELY.*$} $copy_line "" out_line
+
+        } elseif [regexp -- {DISABLED} $copy_line] {
+            # DISABLED is not handled.
+            regsub -- {DISABLED.*$} $copy_line "" out_line
+
+        } elseif [regexp -- {POST_SCRIPT} $copy_line] {
+            # POST_SCRIPT is not handled
+            regsub -- {POST_SCRIPT.*$} $copy_line "" out_line
+
+        } elseif [regexp -- {PERMUTE_ARGS\s*:\s*(.*)} $copy_line match args] {
+            # PERMUTE_ARGS is handled by gdc-do-test.
+            set PERMUTE_ARGS [gdc-convert-args $base $args]
+            regsub -- {PERMUTE_ARGS.*$} $copy_line "" out_line
+
+        } elseif [regexp -- {EXECUTE_ARGS\s*:\s*(.*)} $copy_line match args] {
+            # EXECUTE_ARGS is handled by gdc_load.
+            foreach arg $args {
+                lappend GDC_EXECUTE_ARGS $arg
+            }
+            regsub -- {EXECUTE_ARGS.*$} $copy_line "" out_line
+
+        } elseif [regexp -- {REQUIRED_ARGS\s*:\s*(.*)} $copy_line match args] {
+            # Convert all listed arguments to from dmd to gdc-style.
+            set new_option "{ dg-additional-options \"[gdc-convert-args $base $args]\" }"
+            regsub -- {REQUIRED_ARGS.*$} $copy_line $new_option out_line
+
+        } elseif [regexp -- {EXTRA_SOURCES\s*:\s*(.*)} $copy_line match sources] {
+            # Copy all sources to the testsuite build directory.
+            foreach import $sources {
+                # print "Import: $base $type/$import"
+                gdc-copy-extra $base "$type/$import"
+            }
+            set new_option "{ dg-additional-sources \"$sources\" }"
+            regsub -- {EXTRA_SOURCES.*$} $copy_line $new_option out_line
+
+        } elseif [regexp -- {EXTRA_CPP_SOURCES\s*:\s*(.*)} $copy_line match sources] {
+            # Copy all sources to the testsuite build directory.
+            foreach import $sources {
+                # print "Import: $base $type/$import"
+                gdc-copy-extra $base "$type/$import"
+            }
+            set new_option "{ dg-additional-sources \"$sources\" }"
+            regsub -- {EXTRA_CPP_SOURCES.*$} $copy_line $new_option out_line
+
+        } elseif [regexp -- {EXTRA_FILES\s*:\s*(.*)} $copy_line match files] {
+            # Copy all sources to the testsuite build directory.
+            foreach import $files {
+                # print "Import: $base $type/$import"
+                gdc-copy-extra $base "$type/$import"
+            }
+            set new_option "{ dg-additional-files \"$files\" }"
+            regsub -- {EXTRA_FILES.*$} $copy_line $new_option out_line
+
+        }
+
+        puts $fdout $out_line
+    }
+
+    # Add specific options for test type
+
+    # DMD's testsuite is extremely verbose, compiler messages from constructs
+    # such as pragma(msg, ...) would otherwise cause tests to fail.
+    set out_line "// { dg-prune-output .* }"
+    puts $fdout $out_line
+
+    # Since GCC 6-20160131 blank lines are not allowed in the output by default.
+    dg-allow-blank-lines-in-output { 1 }
+
+    # Compilable files are successful if an output is generated.
+    # Fail compilable are successful if an output is not generated.
+    # Runnable must compile, link, and return 0 to be successful by default.
+    switch [file dirname $test] {
+        runnable {
+            if ![isnative] {
+                set out_line "// { dg-final { output-exists } }"
+                puts $fdout $out_line
+            }
+        }
+
+        compilable {
+            set out_line "// { dg-final { output-exists } }"
+            puts $fdout $out_line
+        }
+
+        fail_compilation {
+            set out_line "// { dg-final { output-exists-not } }"
+            puts $fdout $out_line
+        }
+    }
+
+    close $fdin
+    close $fdout
+
+    return $test
+}
+
+proc gdc-permute-options { options } {
+    set result { }
+    set n [expr 1<<[llength $options]]
+    for { set i 0 } { $i<$n } { incr i } {
+        set option ""
+        for { set j 0 } { $j<[llength $options] } { incr j } {
+            if [expr $i & 1 << $j] {
+                append option [lindex $options $j]
+                append option " "
+            }
+        }
+        lappend result $option
+
+    }
+    return $result
+}
+
+
+proc gdc-do-test { } {
+    global srcdir subdir
+    global dg-do-what-default
+    global verbose
+
+    # If a testcase doesn't have special options, use these.
+    global DEFAULT_DFLAGS
+    if ![info exists DEFAULT_DFLAGS] then {
+        set DEFAULT_DFLAGS "-g -O2 -frelease"
+        #set DEFAULT_DFLAGS "-O2"
+    }
+
+    # These are special options to use on testcase, and override DEFAULT_DFLAGS
+    global PERMUTE_ARGS
+
+    # Set if an extra option should be passed to link to shared druntime.
+    global SHARED_OPTION
+
+    # Additional arguments for gdc_load
+    global GDC_EXECUTE_ARGS
+
+    # Initialize `dg'.
+    dg-init
+
+    # Main loop.
+
+    # set verbose 1
+    # set dg-final-code ""
+    # Find all tests and pass to routine.
+    foreach test [lsort [find $srcdir/$subdir *]] {
+        regexp -- "(.*)/(.+)/(.+)\.(.+)$" $test match base dir name ext
+
+        # Skip invalid test directory
+        if { [lsearch "runnable compilable fail_compilation" $dir] == -1 } {
+            continue
+        }
+
+        # Skip invalid test extensions
+        if { [lsearch "d" $ext] == -1 } {
+            continue
+        }
+
+        # Convert to DG test.
+        set imports [format "-I%s/%s" $base $dir]
+        set filename [dmd2dg $base $dir/$name.$ext]
+
+        if { $dir == "runnable" } {
+            append PERMUTE_ARGS " $SHARED_OPTION"
+        }
+        set options [gdc-permute-options $PERMUTE_ARGS]
+
+        switch $dir {
+            runnable {
+                for { set i 0 } { $i<[llength $options] } { incr i } {
+                    set flags [lindex $options $i]
+                    if [isnative] {
+                        set dg-do-what-default "run"
+                    } else {
+                        set dg-do-what-default "link"
+                    }
+                    gdc-dg-runtest $filename $flags $imports
+                }
+            }
+
+            compilable {
+                for { set i 0 } { $i<[llength $options] } { incr i } {
+                    set flags [lindex $options $i]
+                    #set dg-do-what-default "compile"
+                    set dg-do-what-default "assemble"
+                    gdc-dg-runtest $filename $flags $imports
+                }
+            }
+
+            fail_compilation {
+                for { set i 0 } { $i<[llength $options] } { incr i } {
+                    set flags [lindex $options $i]
+                    set dg-do-what-default "assemble"
+                    gdc-dg-runtest $filename $flags $imports
+                }
+            }
+        }
+
+        # Cleanup
+        #file delete $filename
+    }
+
+    # All done.
+    dg-finish
+}
+
+gdc-do-test
+
diff --git a/gcc/testsuite/lib/gdc-dg.exp b/gcc/testsuite/lib/gdc-dg.exp
new file mode 100644
index 00000000000..e5d9f1d9cb7
--- /dev/null
+++ b/gcc/testsuite/lib/gdc-dg.exp
@@ -0,0 +1,88 @@
+# Copyright (C) 2012-2018 Free Software Foundation, Inc.
+
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with GCC; see the file COPYING3.  If not see
+# <http://www.gnu.org/licenses/>.
+
+load_lib gcc-dg.exp
+
+# Define gdc callbacks for dg.exp.
+
+proc gdc-dg-test { prog do_what extra_tool_flags } {
+    set result \
+        [gcc-dg-test-1 gdc_target_compile $prog $do_what $extra_tool_flags]
+
+    set comp_output [lindex $result 0]
+    set output_file [lindex $result 1]
+
+    return [list $comp_output $output_file]
+}
+
+proc gdc-dg-prune { system text } {
+    return [gcc-dg-prune $system $text]
+}
+
+# Utility routines.
+
+#
+# Modified dg-runtest that can cycle through a list of optimization options
+# as c-torture does.
+#
+
+proc gdc-dg-runtest { testcases flags default-extra-flags } {
+    global runtests
+
+    foreach test $testcases {
+        # If we're only testing specific files and this isn't one of
+        # them, skip it.
+        if ![runtest_file_p $runtests $test] {
+            continue
+        }
+
+        # Use TORTURE_OPTIONS to cycle through an option list.
+        if [torture-options-exist] then {
+            global torture_with_loops
+            set option_list $torture_with_loops
+        } else {
+            set option_list { "" }
+        }
+
+        set nshort [file tail [file dirname $test]]/[file tail $test]
+
+        foreach flags_t $option_list {
+            verbose "Testing $nshort, $flags $flags_t" 1
+            dg-test $test "$flags $flags_t" ${default-extra-flags}
+        }
+    }
+}
+
+#
+# gdc_load -- wrapper around default gdc_load to handle tests that
+# require program arguments passed to them.
+#
+
+if { [info procs gdc_load] != [list] \
+      && [info procs prev_gdc_load] == [list] } {
+    rename gdc_load prev_gdc_load
+
+    proc gdc_load { program args } {
+        global GDC_EXECUTE_ARGS
+        if [info exists GDC_EXECUTE_ARGS] then {
+            set args [concat "{$GDC_EXECUTE_ARGS}"]
+        }
+        #print "Running: $program [lindex $args 0]"
+        set result [eval [list prev_gdc_load $program] $args ]
+        return $result
+    }
+}
+
diff --git a/gcc/testsuite/lib/gdc.exp b/gcc/testsuite/lib/gdc.exp
new file mode 100644
index 00000000000..425cb4a61e3
--- /dev/null
+++ b/gcc/testsuite/lib/gdc.exp
@@ -0,0 +1,277 @@
+# Copyright (C) 2012-2018 Free Software Foundation, Inc.
+
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with GCC; see the file COPYING3.  If not see
+# <http://www.gnu.org/licenses/>.
+
+#
+# gdc support library routines
+#
+
+load_lib prune.exp
+load_lib gcc-defs.exp
+load_lib timeout.exp
+load_lib target-libpath.exp
+
+#
+# GDC_UNDER_TEST is the compiler under test.
+#
+
+set gdc_compile_options ""
+
+
+#
+# gdc_version -- extract and print the version number of the compiler
+#
+
+proc gdc_version { } {
+    global GDC_UNDER_TEST
+
+    gdc_init
+
+    # ignore any arguments after the command
+    set compiler [lindex $GDC_UNDER_TEST 0]
+
+    # verify that the compiler exists
+    if { [is_remote host] || [which $compiler] != 0 } then {
+        set tmp [remote_exec host "$compiler -v"]
+        set status [lindex $tmp 0]
+        set output [lindex $tmp 1]
+        regexp " version \[^\n\r\]*" $output version
+        if { $status == 0 && [info exists version] } then {
+            if [is_remote host] {
+                clone_output "$compiler $version\n"
+            } else {
+                clone_output "[which $compiler] $version\n"
+            }
+        } else {
+            clone_output "Couldn't determine version of [which $compiler]\n"
+        }
+    } else {
+        # compiler does not exist (this should have already been detected)
+        warning "$compiler does not exist"
+    }
+}
+
+#
+# gdc_include_flags -- include flags for the gcc tree structure
+#
+
+proc gdc_include_flags { paths } {
+    global srcdir
+    global TESTING_IN_BUILD_TREE
+
+    set flags ""
+
+    if { [is_remote host] || ![info exists TESTING_IN_BUILD_TREE] } {
+        return "${flags}"
+    }
+
+    set gccpath ${paths}
+    set target [file tail [file normalize ${paths}]]
+
+    if { $gccpath != "" } {
+        if [file exists "${gccpath}/libphobos/libdruntime"] {
+            append flags "-I${gccpath}/libphobos/libdruntime "
+        }
+    }
+    append flags "-I${srcdir}/../../libphobos/libdruntime "
+    append flags "-I${srcdir}/../../libphobos/src "
+
+    # For the tests that mix C++ and D, we should try and handle this better.
+    if { $gccpath != "" } {
+        if [file exists "${gccpath}/libstdc++-v3/include"] {
+            append flags "-I${gccpath}/libstdc++-v3/include "
+            append flags "-I${gccpath}/libstdc++-v3/include/$target "
+        }
+    }
+    append flags "-I${srcdir}/../../libstdc++-v3/libsupc++"
+}
+
+#
+# gdc_link_flags -- linker flags for the gcc tree structure
+#
+
+proc gdc_link_flags { paths } {
+    global srcdir
+    global ld_library_path
+    global GDC_UNDER_TEST
+    global shlib_ext
+    global SHARED_OPTION
+
+    set gccpath ${paths}
+    set libio_dir ""
+    set flags ""
+    set ld_library_path "."
+    set shlib_ext [get_shlib_extension]
+    set SHARED_OPTION ""
+    verbose "shared lib extension: $shlib_ext"
+
+    if { $gccpath != "" } {
+        # Path to libgphobos.spec.
+        append flags "-B${gccpath}/libphobos/src "
+
+        if { [file exists "${gccpath}/libphobos/src/.libs/libgphobos.a"] \
+             || [file exists "${gccpath}/libphobos/src/.libs/libgphobos.${shlib_ext}"] } {
+            append flags "-L${gccpath}/libphobos/src/.libs "
+            append ld_library_path ":${gccpath}/libphobos/src/.libs"
+        }
+        if { [file exists "${gccpath}/libphobos/libdruntime/.libs/libgdruntime.a"] \
+             || [file exists "${gccpath}/libphobos/libdruntime/.libs/libgdruntime.${shlib_ext}"] } {
+            append flags "-L${gccpath}/libphobos/libdruntime/.libs "
+            append ld_library_path ":${gccpath}/libphobos/libdruntime/.libs"
+        }
+        # Static linking is default. If only the shared lib is available adjust
+        # flags to always use it. If both are available, set SHARED_OPTION which
+        # will be added to PERMUTE_ARGS
+        if { [file exists "${gccpath}/libphobos/libdruntime/.libs/libgdruntime.${shlib_ext}"] } {
+            if { [file exists "${gccpath}/libphobos/libdruntime/.libs/libgdruntime.a"] } {
+                set SHARED_OPTION "-shared-libphobos"
+            } else {
+                append flags "-shared-libphobos "
+            }
+        }
+        if [file exists "${gccpath}/libiberty/libiberty.a"] {
+            append flags "-L${gccpath}/libiberty "
+        }
+        # For the tests that mix C++ and D, we should try and handle this better.
+        if { [file exists "${gccpath}/libstdc++-v3/src/.libs/libstdc++.a"] \
+             || [file exists "${gccpath}/libstdc++-v3/src/.libs/libstdc++.${shlib_ext}"] } {
+            append flags "-L${gccpath}/libstdc++-v3/src/.libs "
+            append ld_library_path ":${gccpath}/libstdc++-v3/src/.libs"
+        }
+        append ld_library_path [gcc-set-multilib-library-path $GDC_UNDER_TEST]
+    } else {
+        global tool_root_dir
+
+        set libphobos [lookfor_file ${tool_root_dir} libgphobos]
+        if { $libphobos != "" } {
+            append flags "-B${libphobos} -L${libphobos} "
+            append ld_library_path ":${libphobos}"
+        }
+        set libdruntime [lookfor_file ${tool_root_dir} libgdruntime]
+        if { $libdruntime != "" } {
+            append flags "-L${libdruntime} "
+            append ld_library_path ":${libdruntime}"
+        }
+        set libiberty [lookfor_file ${tool_root_dir} libiberty]
+        if { $libiberty != "" } {
+            append flags "-L${libiberty} "
+        }
+    }
+
+    set_ld_library_path_env_vars
+
+    return "$flags"
+}
+
+#
+# gdc_init -- called at the start of each subdir of tests
+#
+
+proc gdc_init { args } {
+    global subdir
+    global gdc_initialized
+    global base_dir
+    global tmpdir
+    global libdir
+    global gluefile wrap_flags
+    global objdir srcdir
+    global ALWAYS_DFLAGS
+    global TOOL_EXECUTABLE TOOL_OPTIONS
+    global GDC_UNDER_TEST
+    global TESTING_IN_BUILD_TREE
+    global TEST_ALWAYS_FLAGS
+
+    # We set LC_ALL and LANG to C so that we get the same error messages as expected.
+    setenv LC_ALL C
+    setenv LANG C
+
+    if ![info exists GDC_UNDER_TEST] then {
+        if [info exists TOOL_EXECUTABLE] {
+            set GDC_UNDER_TEST $TOOL_EXECUTABLE
+        } else {
+            if { [is_remote host] || ! [info exists TESTING_IN_BUILD_TREE] } {
+                set GDC_UNDER_TEST [transform gdc]
+            } else {
+                set GDC_UNDER_TEST [findfile $base_dir/../../gdc "$base_dir/../../gdc -B$base_dir/../../" [findfile $base_dir/gdc "$base_dir/gdc -B$base_dir/" [transform gdc]]]
+            }
+        }
+    }
+
+    if ![is_remote host] {
+        if { [which $GDC_UNDER_TEST] == 0 } then {
+            perror "GDC_UNDER_TEST ($GDC_UNDER_TEST) does not exist"
+            exit 1
+        }
+    }
+    if ![info exists tmpdir] {
+        set tmpdir "/tmp"
+    }
+
+    if [info exists gluefile] {
+        unset gluefile
+    }
+
+    gdc_maybe_build_wrapper "${tmpdir}/d-testglue.o"
+
+    set ALWAYS_DFLAGS ""
+
+    # TEST_ALWAYS_FLAGS are flags that should be passed to every
+    # compilation.  They are passed first to allow individual
+    # tests to override them.
+    if [info exists TEST_ALWAYS_FLAGS] {
+        lappend ALWAYS_DFLAGS "additional_flags=$TEST_ALWAYS_FLAGS"
+    }
+
+    if ![is_remote host] {
+        if [info exists TOOL_OPTIONS] {
+            lappend ALWAYS_DFLAGS "additional_flags=[gdc_include_flags [get_multilibs ${TOOL_OPTIONS}] ]"
+            lappend ALWAYS_DFLAGS "ldflags=[gdc_link_flags [get_multilibs ${TOOL_OPTIONS}] ]"
+        } else {
+            lappend ALWAYS_DFLAGS "additional_flags=[gdc_include_flags [get_multilibs] ]"
+            lappend ALWAYS_DFLAGS "ldflags=[gdc_link_flags [get_multilibs] ]"
+        }
+    }
+
+    if [info exists TOOL_OPTIONS] {
+        lappend ALWAYS_DFLAGS "additional_flags=$TOOL_OPTIONS"
+    }
+
+    verbose -log "ALWAYS_DFLAGS set to $ALWAYS_DFLAGS"
+
+    verbose "gdc is initialized" 3
+}
+
+#
+# gdc_target_compile -- compile a source file
+#
+
+proc gdc_target_compile { source dest type options } {
+    global tmpdir
+    global gluefile wrap_flags
+    global ALWAYS_DFLAGS
+    global GDC_UNDER_TEST
+
+    if { [target_info needs_status_wrapper] != "" && [info exists gluefile] } {
+        lappend options "libs=${gluefile}"
+        lappend options "ldflags=${wrap_flags}"
+    }
+
+    lappend options "timeout=[timeout_value]"
+    lappend options "compiler=$GDC_UNDER_TEST"
+
+    set options [concat "$ALWAYS_DFLAGS" $options]
+    set options [dg-additional-files-options $options $source]
+    return [target_compile $source $dest $type $options]
+}
-- 
2.17.1

