diff mbox

[9/13] D: D2 Testsuite Dejagnu files.

Message ID CABOHX+fOsuDAxHAcuUebc6HbQy4zQX-k6+VOZoO7DyOgYxhfyg@mail.gmail.com
State New
Headers show

Commit Message

Iain Buclaw May 28, 2017, 9:16 p.m. UTC
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.

---

Comments

Mike Stump May 30, 2017, 11:32 p.m. UTC | #1
On May 28, 2017, at 2:16 PM, Iain Buclaw <ibuclaw@gdcproject.org> wrote:
> 
> This patch adds D language support to the GCC test suite.

Ok.  If you could ensure that gcc without D retains all it's goodness and that gcc with D works on 2 different systems, that will help ensure integration smoothness.

Something this large can be integration tested on a svn/git branch, if you need others to help out.
Matthias Klose May 31, 2017, 9:11 a.m. UTC | #2
On 30.05.2017 16:32, Mike Stump wrote:
> On May 28, 2017, at 2:16 PM, Iain Buclaw <ibuclaw@gdcproject.org> wrote:
>>
>> This patch adds D language support to the GCC test suite.
> 
> Ok.  If you could ensure that gcc without D retains all it's goodness and that gcc with D works on 2 different systems, that will help ensure integration smoothness.
> 
> Something this large can be integration tested on a svn/git branch, if you need others to help out.

I built the library (x86 and ARM32) and the D frontend on several Debian
architectures and OSes (Linux, KFreeBSD, Hurd) in the past, but can do that with
the proposed patches again. A svn/git branch would be helpful for that, if a
recent test is required.

Matthias
Iain Buclaw June 6, 2017, 2:15 p.m. UTC | #3
On 31 May 2017 at 11:11, Matthias Klose <doko@ubuntu.com> wrote:
> On 30.05.2017 16:32, Mike Stump wrote:
>> On May 28, 2017, at 2:16 PM, Iain Buclaw <ibuclaw@gdcproject.org> wrote:
>>>
>>> This patch adds D language support to the GCC test suite.
>>
>> Ok.  If you could ensure that gcc without D retains all it's goodness and that gcc with D works on 2 different systems, that will help ensure integration smoothness.
>>
>> Something this large can be integration tested on a svn/git branch, if you need others to help out.
>
> I built the library (x86 and ARM32) and the D frontend on several Debian
> architectures and OSes (Linux, KFreeBSD, Hurd) in the past, but can do that with
> the proposed patches again. A svn/git branch would be helpful for that, if a
> recent test is required.
>
> Matthias

Indeed, I have all cross-compilers running on explore.dgnu.org at
least.  A little hello world program should give a rough idea of which
targets are supported by libphobos - x86/64, ARM/64, MIPS/64 and
PPC/64 should be either supported or partial.  And if partial, then I
suspect that it's only because there's a missing 'CRuntime_xxx'
version define in the gcc/config patches.  Although I only use gdc on
Linux myself, the reference D compiler is tested on x86/Linux, OSX,
Solaris, and FreeBSD.  I'll optimistically say we should work on these
as well, although off the top of my head, the module dso support may
need looking at in the library.

Iain.
Iain Buclaw June 6, 2017, 5:48 p.m. UTC | #4
On 31 May 2017 at 01:32, Mike Stump <mikestump@comcast.net> wrote:
> On May 28, 2017, at 2:16 PM, Iain Buclaw <ibuclaw@gdcproject.org> wrote:
>>
>> This patch adds D language support to the GCC test suite.
>
> Ok.  If you could ensure that gcc without D retains all it's goodness and that gcc with D works on 2 different systems, that will help ensure integration smoothness.
>
> Something this large can be integration tested on a svn/git branch, if you need others to help out.
>

It would probably be easier for me to maintain also, rather than
continuously regenerating patches each time I make an update to
reflect something that changed in GCC.

Iain.
Mike Stump June 6, 2017, 6:07 p.m. UTC | #5
On Jun 6, 2017, at 10:48 AM, Iain Buclaw <ibuclaw@gdcproject.org> wrote:
>> Something this large can be integration tested on a svn/git branch, if you need others to help out.
>> 
> 
> It would probably be easier for me to maintain also, rather than
> continuously regenerating patches each time I make an update to
> reflect something that changed in GCC.

A branch doesn't remove the need to post patches for review; only eases the burden of working with external people before it hits trunk.
diff mbox

Patch

[PATCH 9/13] D: 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.

---

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..94ea92cf94e
--- /dev/null
+++ b/gcc/testsuite/gdc.test/d_do_test.exp
@@ -0,0 +1,376 @@ 
+#   Copyright (C) 2012-2017 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 { 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$path"
+
+        } elseif { [regexp -- {^-J([\w+/-]+)} $arg pattern path] } {
+            lappend out "-J$path"
+
+        } elseif [string match "-allinst" $arg] {
+            lappend out "-femit-templates"
+
+        } 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 [string match "-dip1000" $arg] {
+            lappend out "-ftransition=safe"
+
+        } 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 [regexp -- {^-mv=([\w+=./-]+)} $arg pattern value] {
+            lappend out "-fmodule-filepath=$value"
+
+        } elseif [string match "-O" $arg] {
+            lappend out "-O2"
+
+        } elseif [string match "-property" $arg] {
+            lappend out "-fproperty"
+
+        } 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 "-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 [file dirname $extra ]
+    set fdout [ open $extra w]
+    fconfigure $fdout -encoding binary
+
+    # print "[file dirname $test ]"
+    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.
+proc dmd2dg { base test } {
+    global DEFAULT_DFLAGS
+    global PERMUTE_ARGS
+    global EXECUTE_ARGS
+
+    set PERMUTE_ARGS $DEFAULT_DFLAGS
+    set 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 [file dirname $test]
+    set fdout [ open $test w]
+    #fconfigure $fdout -encoding binary
+
+    # print "[file dirname $test ]"
+
+    # Add specific options for test type
+
+    # DMD's testsuite is exteremly verbose.
+    #  dg-prune-ouput generates pass.
+    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 ] {
+        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
+        }
+
+    }
+
+    while { [gets $fdin copy_line] >= 0 } {
+        set out_line $copy_line
+
+        # PERMUTE_ARGS.  Must be handled separately
+        if [regexp -- {PERMUTE_ARGS\s*:\s*(.*)} $copy_line match args] {
+            set PERMUTE_ARGS [gdc-convert-args $args]
+            continue
+        }
+
+        # COMPILE_SEPARATELY. Not handled.
+        if [regexp -- {COMPILE_SEPARATELY} $copy_line] {
+            continue
+        }
+
+        # POST_SCRIPT. not handled
+        if [regexp -- {POST_SCRIPT} $copy_line] {
+            continue
+        }
+
+        # Can be handled with dg directives.
+
+        # Handle EXECUTE_ARGS option.
+        if [regexp -- {EXECUTE_ARGS\s*:\s*(.*)} $copy_line match args] {
+            foreach arg $args {
+                lappend EXECUTE_ARGS $arg
+            }
+            continue
+        }
+
+        # Handle EXTRA_SOURCES option
+        if [regexp -- {EXTRA_SOURCES\s*:\s*(.*)} $copy_line match sources] {
+            # Iterate imports and convert
+            foreach import $sources {
+                # print "Import: $base $type/$import"
+                gdc-copy-extra $base "$type/$import"
+            }
+            set out_line "// { dg-additional-sources \"$sources\" }"
+        }
+
+        # Handle EXTRA_CPP_SOURCES option
+        if [regexp -- {EXTRA_CPP_SOURCES\s*:\s*(.*)} $copy_line match sources] {
+            # Iterate imports and convert
+            foreach import $sources {
+                # print "Import: $base $type/$import"
+                gdc-copy-extra $base "$type/$import"
+            }
+            set out_line "// { dg-additional-sources \"$sources\" }"
+        }
+
+        # Handle EXTRA_FILES option
+        if [regexp -- {EXTRA_FILES\s*:\s*(.*)} $copy_line match files] {
+            # Iterate imports and convert
+            foreach import $files {
+                # print "Import: $base $type/$import"
+                gdc-copy-extra $base "$type/$import"
+            }
+            set out_line "// { dg-additional-files \"$files\" }"
+        }
+
+        # REQUIRED_ARGS.
+        if [regexp -- {REQUIRED_ARGS\s*:\s*(.*)} $copy_line match args] {
+            set out_line "// { dg-additional-options \"[gdc-convert-args $args]\" }"
+        }
+        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 TORTURE_OPTIONS
+    global SHARED_OPTION
+    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
+
+    # Additional arguments for gdc_load
+    global 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 [file dirname $test]
+        set imports [format "-I%s -I%s/imports" $imports $imports]
+        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 TORTURE_OPTIONS [lindex $options $i]
+                    set dg-do-what-default "run"
+                    gdc-dg-runtest $filename $imports
+                }
+            }
+
+            compilable {
+                for { set i 0 } { $i<[llength $options] } { incr i } {
+                    set TORTURE_OPTIONS [lindex $options $i]
+                    set dg-do-what-default "assemble"
+                    gdc-dg-runtest $filename "$imports"
+                }
+            }
+
+            fail_compilation {
+                for { set i 0 } { $i<[llength $options] } { incr i } {
+                    set TORTURE_OPTIONS [lindex $options $i]
+                    set dg-do-what-default "assemble"
+                    #set dg-do-what-default "compile"
+                    gdc-dg-runtest $filename $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..a8003f4ad01
--- /dev/null
+++ b/gcc/testsuite/lib/gdc-dg.exp
@@ -0,0 +1,82 @@ 
+#   Copyright (C) 2012-2017 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 go 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 default-extra-flags } {
+    global runtests
+    global TORTURE_OPTIONS
+
+    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
+        }
+
+        if [expr [search_for $test "dg-do run"]] {
+            set flags ""
+        } else {
+            set flags $TORTURE_OPTIONS
+        }
+
+        # Use dg-options if specified
+        #dg-options
+
+        set nshort [file tail [file dirname $test]]/[file tail $test]
+        verbose "Testing $nshort, $TORTURE_OPTIONS" 1
+        dg-test $test $TORTURE_OPTIONS ${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 EXECUTE_ARGS
+        set args [concat "{$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..8035d4eacdf
--- /dev/null
+++ b/gcc/testsuite/lib/gdc.exp
@@ -0,0 +1,274 @@ 
+# Copyright (C) 2012-2017 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 != "" } {
+      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 -B${gccpath}/libphobos/src "
+          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 "-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]
+}