diff mbox series

[09/14] Add D2 Testsuite Dejagnu files.

Message ID CABOHX+du+zw_hVgaPVAAOQ=KRriMRiBXQR_M+rWYs=F=DLkRAg@mail.gmail.com
State New
Headers show
Series None | expand

Commit Message

Iain Buclaw Sept. 18, 2018, 12:36 a.m. UTC

Comments

Iain Buclaw Sept. 19, 2018, 8:36 p.m. UTC | #1
On 18 September 2018 at 02:36, Iain Buclaw <ibuclaw@gdcproject.org> wrote:
>
> 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.

https://gcc.gnu.org/ml/gcc-patches/2017-08/msg00112.html

I take it from the comment in the last review, that I can self-approve
this, and the other testsuite related patches.

Correct me if I'm mistaken.

Iain.
Mike Stump Sept. 21, 2018, 7:59 p.m. UTC | #2
Ok.
Mike Stump Sept. 21, 2018, 8:04 p.m. UTC | #3
On Sep 19, 2018, at 1:36 PM, Iain Buclaw <ibuclaw@gdcproject.org> wrote:
> 
> On 18 September 2018 at 02:36, Iain Buclaw <ibuclaw@gdcproject.org> wrote:
>> 
>> 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.
> 
> https://gcc.gnu.org/ml/gcc-patches/2017-08/msg00112.html
> 
> I take it from the comment in the last review, that I can self-approve
> this, and the other testsuite related patches.

If you're a maintainer for D...  :-)  Presently, you're not listed as maintainer.  If appointed, then you will modify MAINTAINERS and move your entry up and put D front end on the line.  In the time span between the two events I'd punt to the SC.  If you have been appointed, yes, that remains until you step down or the SC changes their mind or some other big event.  You can also ask for advice or ask for a review, even if you can approve.
Iain Buclaw Sept. 21, 2018, 8:14 p.m. UTC | #4
On 21 September 2018 at 22:04, Mike Stump <mikestump@comcast.net> wrote:
> On Sep 19, 2018, at 1:36 PM, Iain Buclaw <ibuclaw@gdcproject.org> wrote:
>>
>> On 18 September 2018 at 02:36, Iain Buclaw <ibuclaw@gdcproject.org> wrote:
>>>
>>> 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.
>>
>> https://gcc.gnu.org/ml/gcc-patches/2017-08/msg00112.html
>>
>> I take it from the comment in the last review, that I can self-approve
>> this, and the other testsuite related patches.
>
> If you're a maintainer for D...  :-)  Presently, you're not listed as maintainer.  If appointed, then you will modify MAINTAINERS and move your entry up and put D front end on the line.  In the time span between the two events I'd punt to the SC.  If you have been appointed, yes, that remains until you step down or the SC changes their mind or some other big event.  You can also ask for advice or ask for a review, even if you can approve.

I have been appointed maintainer when the D language was accepted for
inclusion. I have been delaying adding myself to MAINTAINERS until all
this work is signed off.

Iain
Iain Buclaw Oct. 22, 2018, 1:13 a.m. UTC | #5
On Fri, 21 Sep 2018 at 21:59, Mike Stump <mikestump@comcast.net> wrote:
>
> Ok.

Richard requested that all tests use issue links rather than numbers
so as not to confuse with gcc's bugzilla tracker.

Posting just the patch overlay to original that applies just that.

Regards
--
Iain

---
diff mbox series

Patch

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