aboutsummaryrefslogtreecommitdiff
path: root/lib/target.exp
diff options
context:
space:
mode:
Diffstat (limited to 'lib/target.exp')
-rw-r--r--lib/target.exp759
1 files changed, 759 insertions, 0 deletions
diff --git a/lib/target.exp b/lib/target.exp
new file mode 100644
index 0000000..f71c6f6
--- /dev/null
+++ b/lib/target.exp
@@ -0,0 +1,759 @@
+# Copyright (C) 92, 93, 94, 95, 96, 97, 98, 1999, 2000 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 2 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 this program; if not, write to the Free Software
+# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+# Please email any bugs, comments, and/or additions to this file to:
+# bug-dejagnu@prep.ai.mit.edu
+
+# This file was written by Rob Savoye. (rob@cygnus.com)
+# and extensively modified by Bob Manson. (manson@cygnus.com)
+
+# a hairy pattern to recognize text
+set text "\[- A-Za-z0-9\.\;\"\_\:\'\`\(\)\!\#\=\+\?\&\*]"
+
+#
+# this is a collection of support procs for the target data
+# structures. We use a named array, since Tcl has no real data
+# structures. Here's the special index words for the array:
+# Required fields are:
+# name - the name of the target. (mostly for error messages) This
+# should also be the string used for this target's array.
+# It should also be the same as the linker script so we
+# can find them dynamically.
+# Optional fields are:
+# ldflags - the flags required to produce a fully linked executable.
+# config - the target canonical for this target. This is a regexp
+# as passed to istarget or isnative.
+# cflags - the flags required to produce an object file from a
+# source file.
+# connect - the connectmode for this target. This is for both IP and
+# serial connections.
+# hostname - the hostname of the target. This is for TCP/IP based
+# connections, and is also used for versions of tip that
+# use /etc/remote.
+# serial - the serial port. This is typically /dev/tty? or com?:.
+# baud - the baud rate for a serial port connection.
+# netport - the IP port.
+# x10 - parameters for the x10 controller (used to reboot)
+# fileid - the fileid or spawn id of of the connection.
+# prompt - a regexp for matching the prompt.
+# ioport - the port for I/O on dual port systems.
+#
+# there are three main arrays, indexed in with "target", "build", and "host".
+# all other targets are indexed with a name usually based on the linker script
+# like "idp", or "ex93x.ld".
+#
+
+#
+# Set the target connection.
+#
+proc push_target { name } {
+ global target_abbrev
+
+ pop_config target
+ push_config target $name
+}
+
+#
+# Set the host connnection.
+#
+proc push_host { name } {
+ pop_config host
+ push_config host $name
+}
+
+#
+# Set the build connnection.
+#
+proc push_build { name } {
+ pop_config build
+ push_config build $name
+}
+
+#
+# Set the config for the current host or target connection.
+#
+proc push_config { type name } {
+ global target_info
+
+ verbose "pushing config for $type, name is $name"
+ if [info exists target_info($type,name)] {
+ if { $target_info($type,name) == $name } {
+ error "pushing config for $type, '$name' twice"
+ }
+ }
+ set target_info($type,name) $name
+}
+
+#
+# Set the current connection for target or host.
+#
+proc pop_config { type } {
+ global target_info
+
+ if [info exists target_info(${type},name)] {
+ unset target_info(${type},name)
+ }
+}
+
+#
+# Unset the target connection.
+#
+proc pop_target { } {
+ pop_config target
+}
+
+#
+# Unset the host connection.
+#
+proc pop_host { } {
+ pop_config host
+}
+
+#
+# Remove extraneous warnings we don't care about
+#
+proc prune_warnings { text } {
+ global host_triplet;
+
+ # remove the \r part of "\r\n" so we don't break all the patterns
+ # we want to match.
+ regsub -all -- "\r" $text "" text
+
+ # This is from sun4's. Do it for all machines for now.
+ # The "\\1" is to try to preserve a "\n" but only if necessary.
+ if [ishost "sparc-*-sunos*"] {
+ regsub -all "(^|\n)(ld.so: warning:\[^\n\]*\n?)+" $text "\\1" text
+ }
+
+ # See Brendan for the raison d'etre of this one.
+ if [ishost "alpha*-*-*"] {
+ regsub -all "(^|\n)(/usr/(ucb|bin)/ld.*without exceptions was\[^\n\]+\n?)" $text "\\1" text
+ }
+ if [ishost "hppa*-*-hpux*"] {
+ # Ignore the compiler's warnings about PA incompatibility.
+ regsub -all "(^|\n)\[^\n\]*PA 2.0 object file \[^\n\]* was detected. The linked output may not run on a PA 1.x system." $text "" text
+
+ regsub -all "(^|\n)\[^\n\]*PA 2.0 object file \[^\n\]* was detected. The linked output may not run on a PA 1.x system." $text "" text
+
+ # And the linker's +vcompatwarnings verbage.
+ regsub -all "(^|\n)\[^\n\]*Linker features were used that may not be supported\[^\n\]*.\[^\n\]*." $text "" text
+
+ # Ignore these warnings, which the HP aCC compiler seems to
+ # generate on HP-UX 10.30 and 11.0. (Something is probably
+ # wrong with some system headers, but still...)
+ #
+ # This particular warning always is given with a line of warning
+ # text, followed by a source line, followed by a line with "^^^"
+ # underlining an offending symbol name. Here we slurp up the
+ # warning text and the next two lines, assuming that they are
+ # the source line and underline chars.
+ #
+ regsub -all "Warning .*The linkage directive is ignored for an object or function declared static..\[^\n\]*.\[^\n\]*." $text "" text
+
+ # Ignore these warnings, which I often see from the ANSI C
+ # compiler installed on HP-UX 11.0 machines. (Something is
+ # probably wrong with an installation, or perhaps NLS isn't
+ # quite healthy yet on 11.0. In either case, it's easier to
+ # "fix" this nit here, than it is to track down & fix the
+ # root cause.)
+ #
+ # This particular warning always is given with a line of warning
+ # text, followed by line that says "Using internal messages".
+ #
+ regsub -all "Warning: Unable to open pxdb message catalog.*" $text "" text
+ regsub -all ".* Using internal messages.*" $text "" text
+
+ # Another form of the "unable to find message catalog" warning.
+ #
+ regsub -all "cpp: warning .*Possibly incorrect message catalog." $text "" text
+
+ # Another odd warning on 11.0.
+ #
+ regsub -all "aCC .assigner.: Warning .*Could not find library for -l.*" $text "" text
+
+ # Oh heck, just keep adding 'em here...
+ #
+ regsub -all "aCC .assigner.: Warning .*Could not satisfy instantiation request for \[^\n\]* contained in\[^\n\]*\n\t/lib/pa20_64/lib\[a-zA-Z0-9\]*.sl" $text "" text
+
+ # Remove the lines that are output by the HP F77 compiler to
+ # indicate the functions that are being compiled.
+ upvar compiler_type compiler_type
+ if { [info exists compiler_type] && $compiler_type == "f77" } {
+ regsub -all "\[ \ta-zA-Z_0-9\./\]*:\[\r\n\]+" $text "" text
+ }
+
+ # Ignore the warnings about unknown options
+ regsub -all ".*warning \[0-9\]+: Unknown option.*ignored.*" $text "" text
+
+ }
+
+ # Ignore these.
+ regsub -all "(^|\n)\[^\n\]*linker input file unused since linking not done" $text "" text
+ regsub -all "(^|\n)\[^\n\]*file path prefix \[^\n\]* never used" $text "" text
+
+ # This is from sun4's. Do it for all machines for now.
+ # The "\\1" is to try to preserve a "\n" but only if necessary.
+ regsub -all "(^|\n)(ld.so: warning:\[^\n\]*\n?)+" $text "\\1" text
+
+ # This happens when compiling on Alpha OSF/1 with cc -g -O.
+ regsub -all "(^|\n)(\n*uopt: Warning: file not optimized; use -g3 if both optimization and debug wanted\n?)+" $text "\\1" text
+
+ # This happens when compiling on Alpha OSF using gas.
+ regsub -all "(^|\n)(/usr/.*/ld:\nWarning: Linking some objects which contain exception information sections\n\tand some which do not. This may cause fatal runtime exception handling\n\tproblems\[^\n\]*\n?)+" $text "\\1" text
+
+ # This happens on SunOS with cc -g -O.
+ regsub -all "(^|\n)(cc: Warning: -O conflicts with -g. -O turned off.\n?)+" $text "\\1" text
+
+ # This happens when assembling code with the native HP assembler
+ regsub -all "(^|\n)(as:\[^\n\]*err#13.\n .warning.\[^\n\]*\n?)+" $text "\\1" text
+
+ # When using the HP assembler, -g isn't supported.
+ regsub -all "(^|\n)(cc1: warning: -g is only supported when using GAS on this processor\[^\n\]*\ncc1: warning:\[^\n\]*\n?)+" $text "\\1" text
+ regsub -all "(^|\n)(cc1plus: warning: -g is only supported when using GAS on this processor\[^\n\]*\ncc1plus: warning:\[^\n\]*\n?)+" $text "\\1" text
+
+ # This happens when testing across NFS.
+ regsub -all "(^|\n)(NFS server \[^\n\]* not responding still trying\[^\n\]*\n?)+" $text "\\1" text
+ regsub -all "(^|\n)(NFS server \[^\n\]* ok\[^\n\]*\n?)+" $text "\\1" text
+
+ # This happens when testing across NFS on osf4.
+ regsub -all "(^|\n)(NFS3 server \[^\n\]* not responding still trying\[^\n\]*\n?)+" $text "\\1" text
+ regsub -all "(^|\n)(NFS3 server \[^\n\]* ok\[^\n\]*\n?)+" $text "\\1" text
+
+ # When using the IRIX 6 o32 assembler, -g isn't supported
+ regsub -all "(^|\n)(cc1: warning: `-g' not supported by this configuration of GCC\[^\n\]*\n?)+" $text "\\1" text
+ regsub -all "(^|\n)(cc1plus: warning: `-g' not supported by this configuration of GCC\[^\n\]*\n?)+" $text "\\1" text
+
+ regsub -all "(^|\n)(cc1: warning: -mabi=32 does not support -g\[^\n\]*\n?)+" $text "\\1" text
+ regsub -all "(^|\n)(cc1plus: warning: -mabi=32 does not support -g\[^\n\]*\n?)+" $text "\\1" text
+
+ # This happens with the o32 assembler on IRIX 6.
+ regsub -all "(^|\n)(as: Warning: -O3 is not supported for assembly compiles for ucode compilers; changing to -O2.\n?)+" $text "\\1" text
+
+ # This happens when using g++ on a DWARF system.
+ regsub -all "(^|\n)(cc1plus: warning: -g option not supported for C\\+\\+ on systems using the DWARF debugging format\n?)+" $text "\\1" text
+
+ # This is from sun4's. Do it for all machines for now.
+ # The "\\1" is to try to preserve a "\n" but only if necessary.
+ regsub -all "(^|\n)(ld.so: warning:\[^\n\]*\n?)+" $text "\\1" text
+
+ # See Brendan for the raison d'etre of this one.
+ if [string match "alpha*-*-*" $host_triplet] {
+ regsub -all "(^|\n)(/usr/(ucb|bin)/ld.*without exceptions was\[^\n\]+\n?)" $text "\\1" text
+ }
+
+ # Don't pay attention to the AIX4 linker warnings.
+ regsub -all "(^|\n)(ld:.*WARNING: Duplicate.*ld:.*Use the -bload\[^\n\]*\n?)" $text "\\1" text
+
+ # Or the IRIX 6 ones.
+ regsub -all "(^|\n)(ld(|32|64): WARNING \[^\n\]*\n?)+" $text "\\1" text
+ regsub -all "(^|\n)(ld(|32|64): Giving up.*Use -wall\[^\n\]*\n?)+" $text "\\1" text
+
+ # Or the NetBSD ones.
+ regsub -all "(^|\n)(\[^\n\]*:\[0-9\]+: warning: \[^\n\]* possibly used unsafely, use \[^\n\]*\n?)" $text "\\1" text
+ regsub -all "(^|\n)(\[^\n\]*: warning: reference to compatibility glob\[^\n\]*\n?)" $text "\\1" text
+
+ # GNU ld warns about functions marked as dangerous in GNU libc.
+ regsub -all "(^|\n)\[^\n\]*: In function\[^\n\]*\n\[^\n\]\[^\n\]*function is dangerous\[^\n\]*" $text "" text
+
+ # Libgloss libnosys defines functions that warn when linked in
+ regsub -all "(^|\n)\[^\n\]*: In function\[^\n\]*\n\[^\n\]\[^\n\]*is not implemented and will always fail\[^\n\]*" $text "" text
+
+ # It might be tempting to get carried away and delete blank lines, etc.
+ # Just delete *exactly* what we're ask to, and that's it.
+ return $text
+}
+
+#
+# Invoke the compiler. This gets interesting cause the compiler may
+# not be on the same machine we're running DejaGnu on.
+#
+
+proc target_compile {source destfile type options} {
+ set target [target_info name];
+ if { [info proc ${target}_compile] != "" } {
+ return [${target}_compile $source $destfile $type $options];
+ } else {
+ return [default_target_compile $source $destfile $type $options];
+ }
+}
+
+proc default_target_compile {source destfile type options} {
+ global target_triplet
+ global tool_root_dir
+ global CFLAGS_FOR_TARGET
+ global compiler_flags
+
+ if { $destfile == "" && $type != "preprocess" && $type != "none" } {
+ error "Must supply an output filename for the compile to default_target_compile"
+ }
+
+ set add_flags ""
+ set libs ""
+ set compiler_type "c"
+ set compiler ""
+ set ldflags ""
+ set dest [target_info name]
+
+ if [info exists CFLAGS_FOR_TARGET] {
+ append add_flags " $CFLAGS_FOR_TARGET"
+ }
+
+ if [info exists target_info(host,name)] {
+ set host [host_info name];
+ } else {
+ set host "unix";
+ }
+
+ foreach i $options {
+ if { $i == "c++" } {
+ set compiler_type "c++"
+ if [board_info $dest exists cxxflags] {
+ append add_flags " [target_info cxxflags]"
+ }
+ append add_flags " [g++_include_flags]";
+ if [board_info $dest exists c++compiler] {
+ set compiler [target_info c++compiler];
+ } else {
+ set compiler [find_g++];
+ }
+ }
+
+ if { $i == "f77" } {
+ set compiler_type "f77"
+ if [board_info $dest exists f77flags] {
+ append add_flags " [target_info f77flags]"
+ }
+# append add_flags " [f77_include_flags]"
+ if [board_info $dest exists f77compiler] {
+ set compiler [target_info f77compiler]
+ } else {
+ set compiler [find_g77]
+ }
+ }
+
+ if [regexp "^dest=" $i] {
+ regsub "^dest=" $i "" tmp
+ if [board_info $tmp exists name] {
+ set dest [board_info $tmp name];
+ } else {
+ set dest $tmp;
+ }
+ }
+ if [regexp "^compiler=" $i] {
+ regsub "^compiler=" $i "" tmp
+ set compiler $tmp
+ }
+ if [regexp "^additional_flags=" $i] {
+ regsub "^additional_flags=" $i "" tmp
+ append add_flags " $tmp"
+ }
+ if [regexp "^ldflags=" $i] {
+ regsub "^ldflags=" $i "" tmp
+ append ldflags " $tmp"
+ }
+ if [regexp "^libs=" $i] {
+ regsub "^libs=" $i "" tmp
+ append libs " $tmp"
+ }
+ if [regexp "^incdir=" $i] {
+ regsub "^incdir=" $i "-I" tmp
+ append add_flags " $tmp"
+ }
+ if [regexp "^libdir=" $i] {
+ regsub "^libdir=" $i "-L" tmp
+ append add_flags " $tmp"
+ }
+ if [regexp "^ldscript=" $i] {
+ regsub "^ldscript=" $i "" ldscript
+ }
+ if [regexp "^redirect=" $i] {
+ regsub "^redirect=" $i "" redirect
+ }
+ if [regexp "^optimize=" $i] {
+ regsub "^optimize=" $i "" optimize
+ }
+ if [regexp "^timeout=" $i] {
+ regsub "^timeout=" $i "" timeout
+ }
+ }
+
+ if [board_info $host exists cflags_for_target] {
+ append add_flags " [board_info $host cflags_for_target]";
+ }
+
+ global CC_FOR_TARGET
+ global CXX_FOR_TARGET
+ global F77_FOR_TARGET
+
+ if [info exists CC_FOR_TARGET] {
+ if { $compiler == "" } {
+ set compiler $CC_FOR_TARGET
+ }
+ }
+
+ if [info exists CXX_FOR_TARGET] {
+ if { $compiler_type == "c++" } {
+ set compiler $CXX_FOR_TARGET
+ }
+ }
+
+ if [info exists F77_FOR_TARGET] {
+ if { $compiler_type == "f77" } {
+ set compiler $F77_FOR_TARGET
+ }
+ }
+
+ if { $compiler == "" } {
+ set compiler [board_info $dest compiler];
+ if { $compiler == "" } {
+ return "default_target_compile: No compiler to compile with";
+ }
+ }
+
+ if ![is_remote host] {
+ if { [which $compiler] == 0 } {
+ return "default_target_compile: Can't find $compiler."
+ }
+ }
+
+ if {$type == "object"} {
+ append add_flags " -c"
+ }
+
+ if { $type == "preprocess" } {
+ append add_flags " -E"
+ }
+
+ if { $type == "assembly" } {
+ append add_flags " -S"
+ }
+
+ if [board_info $dest exists cflags] {
+ append add_flags " [board_info $dest cflags]"
+ }
+
+ if { $type == "executable" } {
+ # This must be added here.
+ # if [board_info $dest exists ldscript] {
+ # append add_flags " [board_info $dest ldscript]"
+ # }
+
+ if [board_info $dest exists ldflags] {
+ append add_flags " [board_info $dest ldflags]"
+ }
+ if { $compiler_type == "c++" } {
+ append add_flags " [g++_link_flags]";
+ }
+ if [isnative] {
+ # This is a lose.
+ catch "glob -nocomplain $tool_root_dir/libstdc++/libstdc++.so* $tool_root_dir/libstdc++/libstdc++.sl" tmp
+ if { ${tmp} != "" } {
+ if [regexp ".*solaris2.*" $target_triplet] {
+ # Solaris 2
+ append add_flags " -R$tool_root_dir/libstdc++"
+ } elseif [regexp ".*(osf|irix5|linux).*" $target_triplet] {
+ # OSF/1 or Irix5
+ append add_flags " -Wl,-rpath,$tool_root_dir/libstdc++"
+ } elseif [regexp ".*hppa.*" $target_triplet] {
+ # HP/UX
+ append add_flags " -Wl,-a,shared_archive"
+ }
+ }
+ }
+ }
+
+ if ![info exists ldscript] {
+ set ldscript [board_info $dest ldscript]
+ }
+
+ foreach i $options {
+ if { $i == "debug" } {
+ if [board_info $dest exists debug_flags] {
+ append add_flags " [board_info $dest debug_flags]";
+ } else {
+ append add_flags " -g"
+ }
+ }
+ }
+
+ if [info exists optimize] {
+ append add_flags " $optimize";
+ }
+
+ if { $type == "executable" } {
+ foreach x $libs {
+ if [file exists $x] {
+ append source " $x"
+ } else {
+ append add_flags " $x";
+ }
+ }
+ append add_flags " $ldflags"
+
+ if [board_info $dest exists libs] {
+ append add_flags " [board_info $dest libs]"
+ }
+
+ # This probably isn't such a good idea, but it avoids nasty
+ # hackiness in the testsuites.
+ # The math library must be linked in before the C library. The C
+ # library is linked in by the linker script, so this must be before
+ # the linker script.
+ if [board_info $dest exists mathlib] {
+ append add_flags " [board_info $dest mathlib]"
+ } else {
+ append add_flags " -lm"
+ }
+
+ # This must be added here.
+ append add_flags " $ldscript";
+
+ if [board_info $dest exists remote_link] {
+ # Relink option.
+ append add_flags " -Wl,-r"
+ }
+ if [board_info $dest exists output_format] {
+ append add_flags " -Wl,-oformat,[board_info $dest output_format]";
+ }
+ }
+
+ if [board_info $dest exists multilib_flags] {
+ append add_flags " [board_info $dest multilib_flags]";
+ }
+
+ verbose "doing compile"
+
+ set sources ""
+ if [is_remote host] {
+ foreach x $source {
+ set file [remote_download host $x];
+ if { $file == "" } {
+ warning "Unable to download $x to host."
+ return "Unable to download $x to host."
+ } else {
+ append sources " $file";
+ }
+ }
+ } else {
+ set sources $source
+ }
+
+ if [is_remote host] {
+ append add_flags " -o a.out"
+ remote_file host delete a.out;
+ } else {
+ if { $destfile != "" } {
+ append add_flags " -o $destfile";
+ }
+ }
+
+ # This is obscure: we put SOURCES at the end when building an
+ # object, because otherwise, in some situations, libtool will
+ # become confused about the name of the actual source file.
+ if {$type == "object"} {
+ set opts "$add_flags $sources"
+ } else {
+ set opts "$sources $add_flags"
+ }
+
+ if [is_remote host] {
+ if [host_info exists use_at] {
+ set fid [open "atfile" "w"];
+ puts $fid "$opts";
+ close $fid;
+ set opts "@[remote_download host atfile]"
+ remote_file build delete atfile
+ }
+ }
+
+ verbose "Invoking the compiler as $compiler $opts" 2
+
+ if [info exists redirect] {
+ verbose "Redirecting output to $redirect" 2
+ set status [remote_exec host "$compiler $opts" "" "" $redirect];
+ } else {
+ if [info exists timeout] {
+ verbose "Setting timeout to $timeout" 2
+ set status [remote_exec host "$compiler $opts" "" "" "" $timeout];
+ } else {
+ set status [remote_exec host "$compiler $opts"];
+ }
+ }
+
+ set compiler_flags $opts
+ if [is_remote host] {
+ remote_upload host a.out $destfile;
+ remote_file host delete a.out;
+ }
+ set comp_output [prune_warnings [lindex $status 1]];
+ regsub "^\[\r\n\]+" $comp_output "" comp_output;
+ if { [lindex $status 0] != 0 } {
+ verbose -log "compiler exited with status [lindex $status 0]";
+ }
+ if { [lindex $status 1] != "" } {
+ verbose -log "output is:\n[lindex $status 1]" 2;
+ }
+ if { [lindex $status 0] != 0 && "${comp_output}" == "" } {
+ set comp_output "exit status is [lindex $status 0]";
+ }
+ return ${comp_output};
+}
+
+proc reboot_target { } {
+ set result [remote_reboot target]
+ puts "REBOOT_TARGET: \"$result\""
+ return ${result};
+}
+
+#
+# Invoke this if you really want as to be called directly, rather than
+# calling the compiler. FLAGS are any additional flags to pass to the
+# assembler.
+#
+proc target_assemble { source destfile flags } {
+ return [default_target_assemble $source $destfile $flags];
+}
+
+proc default_target_assemble { source destfile flags } {
+ global AS_FOR_TARGET
+ global ASFLAGS_FOR_TARGET
+
+ if [info exists AS_FOR_TARGET] {
+ set AS "$AS_FOR_TARGET";
+ } else {
+ if ![board_info target exists assembler] {
+ set AS [find_gas];
+ } else {
+ set AS [board_info target assembler];
+ }
+ }
+
+ if [info exists ASFLAGS_FOR_TARGET] {
+ append flags " $ASFLAGS_FOR_TARGET";
+ }
+
+ if [is_remote host] {
+ set source [remote_download host $source];
+ set dest "a.out"
+ } else {
+ set dest $destfile
+ }
+ set status [remote_exec host "$AS $source $flags -o $dest"]
+ if [is_remote host] {
+ remote_upload host $dest $destfile
+ }
+
+ set comp_output [prune_warnings [lindex $status 1]];
+ if { [lindex $status 0] != 0 } {
+ verbose -log "assembler exited with status [lindex $status 0]";
+ }
+ if { [lindex $status 1] != "" } {
+ verbose -log "assembler output is:\n[lindex $status 1]" 2;
+ }
+ return ${comp_output};
+}
+
+#
+# Invoke this if you really want ld to be called directly, rather than
+# calling the compiler. FLAGS are any additional flags to pass to the
+# linker.
+#
+proc target_link { objects destfile flags } {
+ return [default_link target "$objects" "$destfile" $flags];
+}
+
+proc default_link { board objects destfile flags } {
+ global LD_FOR_TARGET
+ global LDFLAGS_FOR_TARGET
+
+ # return -L's in ldflags
+ proc only--Ls { ldflags } {
+ set result ""
+ set ldflags [split $ldflags]
+ set len [llength $ldflags]
+ for { set i 0 } { $i < $len } { incr i } {
+ # ??? We ignore the situation where a -L is actually the argument
+ # to an option.
+ set arg [lindex $ldflags $i]
+ regsub "^-Wl," $arg "" arg
+ if [regexp "^-L" $arg] {
+ # Is the directory in the next arg, or part of this one?
+ if { "$arg" == "-L" } {
+ if { $i + 1 < $len } {
+ append result " -L [lindex $ldflags $i+1]"
+ incr i
+ }
+ } else {
+ append result " $arg"
+ }
+ }
+ }
+ return $result
+ }
+
+ if [info exists LD_FOR_TARGET] {
+ set LD "$LD_FOR_TARGET";
+ } else {
+ if ![board_info target exists linker] {
+ set LD [find_ld];
+ } else {
+ set LD [board_info target linker];
+ }
+ }
+
+ if [info exists LDFLAGS_FOR_TARGET] {
+ append flags " $LDFLAGS_FOR_TARGET";
+ }
+
+ # `ldflags' consists of arguments to gcc (that are then
+ # passed to ld), not arguments to ld directly.
+ # We need the -L's.
+ if [board_info $board exists ldflags] {
+ set ldflags [board_info $board ldflags]
+ set ldflags [only--Ls $ldflags]
+ append flags " $ldflags"
+ }
+
+ if [board_info $board exists ldscript] {
+ # strip leading -Wl, if present
+ set ldscript [board_info $board ldscript]
+ regsub "^-Wl," $ldscript "" ldscript
+ append flags " $ldscript"
+ }
+
+ if [is_remote host] {
+ foreach x $objects {
+ set nobjects "$nobjects [remote_download host $x]";
+ }
+ set objects "$nobjects";
+ set dest "a.out";
+ } else {
+ set dest $destfile;
+ }
+ set status [remote_exec host "$LD $objects $flags -o $dest"]
+ if [is_remote host] {
+ remote_upload host $dest $destfile;
+ }
+
+ set comp_output [prune_warnings [lindex $status 1]];
+ if { [lindex $status 0] != 0 } {
+ verbose -log "linker exited with status [lindex $status 0]";
+ }
+ if { [lindex $status 1] != "" } {
+ verbose -log "linker output is:\n[lindex $status 1]" 2;
+ }
+ return ${comp_output};
+}