# Copyright (C) 1992-2019, 2020 Free Software Foundation, Inc. # # This file is part of DejaGnu. # # DejaGnu 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. # # DejaGnu 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 DejaGnu; if not, write to the Free Software Foundation, # Inc., 51 Franklin Street - Fifth Floor, Boston, MA 02110-1301, USA. # This file was written by Rob Savoye . # this contains a list of gcc options and their respective directories. # Find the pieces of libgloss for testing the GNU development tools # needed to link a set of object files into an executable. # This usually means setting the -L and -B paths correctly. # proc libgloss_link_flags { args } { global target_cpu global srcdir # libgloss doesn't work native if {[isnative]} { return "" } # if we're on a remote host, we can't search for the file, so we can only # use an installed compiler, so we don't add any paths here. if {[isremote host]} { return "" } set gccpath "[get_multilibs]" # map the target_cpu to the proper libgloss directory. unfortunately, these # directory names are hardcoded into libgloss. switch -glob -- $target_cpu { "sparc86x" { set cpu sparc } "sparclite" { set cpu sparc } "sparclet" { set cpu sparc } "sparc64*" { set cpu sparc } "hppa*" { set cpu pa } "mips*" { set cpu mips } "powerpc*" { set cpu rs6000 } "d10v*" { set cpu libnosys } "xscale*" { set cpu arm } "aarch64*" { set cpu aarch64 } default { set cpu $target_cpu } } set gloss_srcdir "" # look for the libgloss srcdir sp we can find the linker scripts set gloss_srcdir [lookfor_file $srcdir libgloss/$cpu] # set the proper paths for gcc if the target subdir exists, else assume we # have no libgloss support for this target. if { $gloss_srcdir eq "" } { return "" } if {[file exists [file join $gccpath libgloss $cpu]]} { verbose "Libgloss path is $gccpath/libgloss/$cpu" 2 return "-B$gccpath/libgloss/$cpu/ -L$gccpath/libgloss/$cpu -L$gloss_srcdir" } else { verbose -log "No libgloss support for this target." 2 return "" } } # There aren't any, but we'll be orthogonal here. # proc libgloss_include_flags { args } { return "" } # Find the newlib libraries in the current source tree. # proc newlib_link_flags { args } { global tool_root_dir # libgloss doesn't work native if {[isnative]} { return "" } # if we're on a remote host, we can't search for the file, so we can only # use an installed compiler, so we don't add any paths here. if {[isremote host]} { return "" } set ld_script_path [lookfor_file $tool_root_dir "ld/ldscripts"] if { $ld_script_path ne "" } { set result "-L[file dirname $ld_script_path]" } else { set result "" } set gccpath "[get_multilibs]" verbose "Looking for $gccpath/newlib" if {[file exists [file join $gccpath newlib]]} { verbose "Newlib path is $gccpath/newlib" return "$result -B$gccpath/newlib/ -L$gccpath/newlib" } else { verbose "No newlib support for this target" return $result } } proc newlib_include_flags { args } { global srcdir if {[isnative]} { return "" } if {[isremote host]} { return "" } set gccpath "[get_multilibs]" if {[file exists [file join $gccpath newlib]]} { verbose "Newlib path is $gccpath/newlib" set newlib_dir [lookfor_file $srcdir newlib/libc/include/assert.h] if { $newlib_dir ne "" } { set newlib_dir [file dirname $newlib_dir] } # Note - we use -isystem rather than -I because newlib contains # system header files. This is especially important for the # limits.h header which makes use of the #include_next directive. # #include_next will generate error messages from GCC if compiling # in strict ANSI mode or if another limits.h header cannot be found. # When it is included via -isystem these things do not happen. return " -isystem $gccpath/newlib/targ-include -isystem $newlib_dir" } else { verbose "No newlib support for this target" } } proc libio_include_flags { args } { global srcdir global tool_root_dir if {[isremote host]} { return "" } set gccpath "[get_multilibs]" if { $gccpath eq "" } { set gccpath $tool_root_dir } set libio_bin_dir [lookfor_file $gccpath libio/_G_config.h] # linux doesn't build _G_config.h and the test above fails, so # we search for iostream.list too. if { $libio_bin_dir eq "" } { set libio_bin_dir [lookfor_file $gccpath libio/iostream.list] } set libio_src_dir [lookfor_file $srcdir libio/Makefile.in] if { $libio_bin_dir ne "" && $libio_src_dir ne "" } { set libio_src_dir [file dirname $libio_src_dir] set libio_bin_dir [file dirname $libio_bin_dir] # Note - unlike the newlib_include_flags proc above we use the -I # switch to specify the include paths. This is because these headers # are not system headers, and if -isystem were to be used GCC would # generate an implicit extern "C" { ... } surrounding them. This # will break targets which do not define NO_IMPLICIT_EXTERN_C. return " -I$libio_src_dir -I$libio_bin_dir" } else { return "" } } proc libio_link_flags { args } { if {[isremote host]} { return "" } set gccpath "[get_multilibs]" set libio_dir [lookfor_file $gccpath libio/libio.a] if { $libio_dir ne "" } { return "-L[file dirname $libio_dir]" } else { return "" } } proc g++_include_flags { args } { global srcdir global target_alias if {[isremote host]} { return "" } set gccpath [get_multilibs] set libio_dir "" set flags "" set dir [lookfor_file $srcdir libg++] if { $dir ne "" } { # See comment in libio_include_flags about using -I. append flags " -I$dir -I$dir/src" } set dir [lookfor_file $srcdir libstdc++-v3] if { $dir ne "" } { append flags " -I$dir/include -I$dir/include/std -I$dir/include/c_std -I$dir/libsupc++" } set dir [lookfor_file $gccpath libstdc++-v3] if { $dir ne "" } { append flags " -I$dir/include -I$dir/include/$target_alias" } set dir [lookfor_file $srcdir libstdc++] if { $dir ne "" } { append flags " -I$dir -I$dir/stl" } return $flags } proc g++_link_flags { args } { global srcdir global ld_library_path set gccpath [get_multilibs] set libio_dir "" set flags "" set ld_library_path "." if { $gccpath ne "" } { if {[file exists [file join $gccpath lib libstdc++.a]]} { append ld_library_path ":$gccpath/lib" } if {[file exists [file join $gccpath libg++ libg++.a]]} { append flags "-L$gccpath/libg++ " append ld_library_path ":$gccpath/libg++" } if {[file exists [file join $gccpath libstdc++ libstdc++.a]]} { append flags "-L$gccpath/libstdc++ " append ld_library_path ":$gccpath/libstdc++" } if {[file exists [file join $gccpath libstdc++-v3 src .libs libstdc++.a]]} { append flags "-L$gccpath/libstdc++-v3/src/.libs " append ld_library_path ":$gccpath/libstdc++-v3/src/.libs" } if {[file exists [file join $gccpath libiberty libiberty.a]]} { append flags "-L$gccpath/libiberty " } if {[file exists [file join $gccpath librx librx.a]]} { append flags "-L$gccpath/librx " } } else { global tool_root_dir set libgpp [lookfor_file $tool_root_dir libg++] if { $libgpp ne "" } { append flags "-L$libgpp " append ld_library_path ":$libgpp" } set libstdcpp [lookfor_file $tool_root_dir libstdc++] if { $libstdcpp ne "" } { append flags "-L$libstdcpp " append ld_library_path ":$libstdcpp" } set libiberty [lookfor_file $tool_root_dir libiberty] if { $libiberty ne "" } { append flags "-L$libiberty " } set librx [lookfor_file $tool_root_dir librx] if { $librx ne "" } { append flags "-L$librx " } } return $flags } proc libstdc++_include_flags { args } { global srcdir global target_alias if {[isremote host]} { return "" } set gccpath [get_multilibs] set libio_dir "" set flags "" set dir [lookfor_file $srcdir libstdc++-v3] if { $dir ne "" } { # See comment in libio_include_flags about using -I. append flags " -I$dir/include -I$dir/include/std -I$dir/include/c_std -I$dir/libsupc++" } set gccpath [get_multilibs] set dir [lookfor_file $gccpath libstdc++-v3] if { $dir ne "" } { append flags " -I$dir/include -I$dir/include/$target_alias" } set dir [lookfor_file $srcdir libstdc++] if { $dir ne "" } { append flags " -I$dir -I$dir/stl" } return $flags } proc libstdc++_link_flags { args } { global srcdir global ld_library_path set gccpath [get_multilibs] set libio_dir "" set flags "" if { $gccpath ne "" } { if {[file exists [file join $gccpath libstdc++ libstdc++.a]]} { append flags "-L$gccpath/libstdc++ " append ld_library_path ":$gccpath/libstdc++" } if {[file exists [file join $gccpath libiberty libiberty.a]]} { append flags "-L$gccpath/libiberty " } if {[file exists [file join $gccpath librx librx.a]]} { append flags "-L$gccpath/librx " } } else { global tool_root_dir set libstdcpp [lookfor_file $tool_root_dir libstdc++] if { $libstdcpp ne "" } { append flags "-L$libstdcpp " append ld_library_path ":$libstdcpp" } set libiberty [lookfor_file $tool_root_dir libiberty] if { $libiberty ne "" } { append flags "-L$libiberty " } set librx [lookfor_file $tool_root_dir librx] if { $librx ne "" } { append flags "-L$librx " } } return $flags } # Get the list of directories and -m options for gcc. This is kinda bogus that # generic testing software needs support for gcc hardwired in, but to make # testing the GNU tools work right, there didn't seem to be any other way. # proc get_multilibs { args } { global target_alias global board global board_info # if we're on a remote host, we can't search for the file, so we can only # use an installed compiler, so we don't add any paths here. if {[isremote host]} { return "" } if {[info exists board]} { set target_board $board } else { set target_board [target_info name] } if { [llength $args] == 0 } { if {[board_info $target_board exists multitop]} { return "[board_info $target_board multitop]" } set board_info($target_board,multitop) "" } if { [board_info $target_board exists compiler] } { set compiler [board_info $target_board compiler] } else { set compiler [find_gcc] } if { $compiler eq "" } { return "" } foreach x $compiler { if {[regexp "^-B" $x]} { regsub "^-B" $x "" comp_base_dir set comp_base_dir [file dirname $comp_base_dir] break } } regexp "/.* " $compiler compiler set compiler [string trimright $compiler " "] verbose "compiler is $compiler" if { [which $compiler] == 0 } { return "" } if { [llength $args] > 0 } { set mopts [lindex $args 0] } else { if { [board_info $target_board exists multilib_flags] } { set mopts [board_info $target_board multilib_flags] } else { set mopts "" } } set default_multilib [exec $compiler --print-multi-lib] set default_multilib [lindex $default_multilib 0] set extra [string trimleft $default_multilib ".;@@"] # extract the options and their directory names as know by gcc foreach i "[exec $compiler --print-multi-lib]" { if {$extra ne ""} { # string trimright would do the wrong thing if we included # the leading @@ in $extra set i [string trimright $i $extra] set i [string trimright $i "@@"] } set opts "" set dir "" regexp -- "\[a-z0-9=/\.-\]*;" $i dir set dir [string trimright $dir "\;@"] regexp -- "\;@*\[\@a-zA-Z0-9=/\.-\]*" $i opts set opts [split [string trimleft $opts "\;@@"] "@@"] lappend multilibs "$dir {$opts }" # If args contains arguments don't use the first one as # multilib option unless it qualifies as a multilib option. if { [llength $args] > 0 } { set override_opt [lindex $args 0] foreach j $opts { if {$j == $override_opt} { set mopts $override_opt } } } } regsub "^-" $mopts "" moptions regsub -all " -" $moptions " " dirty_moptions set moptions "" foreach x [split $dirty_moptions " "] { if { $x ne "" && [lsearch -exact $moptions $x] < 0 } { lappend moptions $x } } if {![info exists comp_base_dir]} { set comp_base_dir [file dirname [file dirname [file dirname [file dirname [file dirname [exec $compiler --print-prog-name=cc1]]]]]] } # search for the top level multilib directory set multitop [lookfor_file $comp_base_dir $target_alias] if { $multitop eq "" } { set multitop [lookfor_file $comp_base_dir "libraries"] if { $multitop eq "" } { set multitop "[lookfor_file $comp_base_dir gcc/xgcc]" if { $multitop ne "" } { set multitop [file dirname [file dirname $multitop]] } else { return "" } } } set gccpath [eval exec $compiler --print-multi-directory $mopts] set gccpath [lindex $gccpath 0] if { $gccpath ne "" } { verbose "GCC path is $gccpath" if { [llength $args] == 0 } { set board_info($target_board,multitop) $multitop/$gccpath } return $multitop/$gccpath } # extract the MULTILIB_MATCHES from dumpspecs set multimatches "" set lines [split [exec $compiler -dumpspecs] "\n"] for {set i 0} {$i <= [llength $lines] - 1} {incr i 1} { if {"*multilib_matches:" eq "[lindex $lines $i]"} { set multimatches [lindex $lines [expr {$i + 1}]] break } } # if we find some if {$multimatches ne ""} { # Split it into a list of pairs. If an moptions are the first # of a pair, then replace it with the second. If an moption # is not in multimatches, we assume it's not a multilib option set splitmatches [split $multimatches ";"] set multimatches "" foreach i $splitmatches { lappend multimatches [split $i " "] } verbose "multimatches: $multimatches" 3 verbose "options before multimatches: $moptions" 3 set toptions $moptions set moptions "" foreach i $toptions { foreach j $multimatches { verbose "comparing [lindex $j 0] == $i" 3 if {[lindex $j 0] == $i} { lappend moptions [lindex $j 1] } } } verbose "options after multimatches: $moptions" 3 } # make a list of -m options from the various compiler config variables set gccpath "" # compare the lists of gcc options with the list of support multilibs verbose "Supported multilibs are: $multilibs" 3 set best 0 foreach i $multilibs { set hits 0 set opts [lindex $i 1] if { [llength $opts] <= [llength $moptions] } { foreach j $moptions { # see if all the -m options match any of the multilibs verbose "Looking in $i for $j" 3 if { [lsearch -exact $opts $j] >= 0 } { incr hits } } if { $hits > $best } { verbose "[lindex $i 0] is better, using as gcc path" 2 set gccpath "[lindex $i 0]" set best $hits } } } if {![info exists multitop]} { return "" } verbose "gccpath is $gccpath" 3 if {[file exists [file join $multitop $gccpath]]} { verbose "GCC path is $multitop/$gccpath" 3 if { [llength $args] == 0 } { set board_info($target_board,multitop) $multitop/$gccpath } return $multitop/$gccpath } else { verbose "GCC path is $multitop" 3 if { [llength $args] == 0 } { set board_info($target_board,multitop) $multitop } return $multitop } } proc find_binutils_prog { name } { global tool_root_dir if {![isremote host]} { set file [lookfor_file $tool_root_dir $name] if { $file eq "" } { set file [lookfor_file $tool_root_dir $name-new] } if { $file eq "" } { set file [lookfor_file $tool_root_dir binutils/$name] } if { $file eq "" } { set file [lookfor_file $tool_root_dir binutils/$name-new] } if { $file ne "" } { set NAME $file } else { set NAME [transform $name] } } else { set NAME [transform $name] } return $NAME } proc find_gcc {} { global tool_root_dir if {![isremote host]} { set file [lookfor_file $tool_root_dir xgcc] if { $file eq "" } { set file [lookfor_file $tool_root_dir gcc/xgcc] } if { $file ne "" } { set CC "$file -B[file dirname $file]/" } else { set CC [transform gcc] } } else { set CC [transform gcc] } return $CC } proc find_gcj {} { global tool_root_dir if {![isremote host]} { set file [lookfor_file $tool_root_dir gcj] if { $file eq "" } { set file [lookfor_file $tool_root_dir gcc/gcj] } if { $file ne "" } { set CC "$file -B[file dirname $file]/" } else { set CC [transform gcj] } } else { set CC [transform gcj] } return $CC } proc find_g++ {} { global tool_root_dir if {![isremote host]} { set file [lookfor_file $tool_root_dir xg++] if { $file eq "" } { set file [lookfor_file $tool_root_dir gcc/xg++] } if { $file eq "" } { set file [lookfor_file $tool_root_dir g++] } if { $file ne "" } { set CC "$file -B[file dirname $file]/" } else { set CC [transform g++] } } else { set CC [transform g++] } return $CC } proc find_gdc {} { global tool_root_dir if {![isremote host]} { set file [lookfor_file $tool_root_dir gdc] if { $file eq "" } { set file [lookfor_file $tool_root_dir gcc/gdc] } if { $file ne "" } { set CC "$file -B[file dirname $file]/" } else { set CC [transform gdc] } } else { set CC [transform gdc] } return $CC } proc find_g77 {} { global tool_root_dir if {![isremote host]} { set file [lookfor_file $tool_root_dir g77] if { $file eq "" } { set file [lookfor_file $tool_root_dir gcc/g77] } if { $file ne "" } { set CC "$file -B[file dirname $file]/" } else { set CC [transform g77] } } else { set CC [transform g77] } return $CC } proc find_gfortran {} { global tool_root_dir if {![isremote host]} { set file [lookfor_file $tool_root_dir gfortran] if { $file eq "" } { set file [lookfor_file $tool_root_dir gcc/gfortran] } if { $file ne "" } { set CC "$file -B[file dirname $file]/" } else { set CC [transform gfortran] } } else { set CC [transform gfortran] } return $CC } proc find_gnatmake {} { global tool_root_dir if {![isremote host]} { set file [lookfor_file $tool_root_dir gnatmake] if { $file eq "" } { set file [lookfor_file $tool_root_dir gcc/gnatmake] } if { $file ne "" } { set root [file dirname $file] set CC "$file -I$root/ada/rts --GCC=$root/xgcc --GNATBIND=$root/gnatbind --GNATLINK=$root/gnatlink -cargs -B$root -largs --GCC=$root/xgcc -B$root -margs" } else { set CC [transform gnatmake] } } else { set CC [transform gnatmake] } return $CC } proc find_go {} { global tool_root_dir set GO "" if {![is_remote host]} { set file [lookfor_file $tool_root_dir gccgo] if { $file ne "" } { set root [file dirname $file] set GO "$file -B$root/gcc/" } } if { $GO eq "" } { set GO [transform gccgo] } return $GO } proc find_go_linker {} { return [find_go] } proc find_rustc {} { global tool_root_dir if {![is_remote host]} { set rustc [lookfor_file $tool_root_dir rustc] if {$rustc eq ""} { set rustc rustc } } else { set rustc "" } if {$rustc ne ""} { append rustc " --color never" } return $rustc } proc find_nm {} { global tool_root_dir set NM "" if {![isremote host]} { set NM [lookfor_file $tool_root_dir nm-new] if {$NM eq ""} { set NM [lookfor_file $tool_root_dir binutils/nm-new] } } if { $NM eq ""} { set NM [transform nm] } return $NM } proc process_multilib_options { args } { global board global board_variant_list global is_gdb_remote set is_gdb_remote 0 if {[board_info $board exists multilib_flags]} { return } eval add_multilib_option $args set multilib_flags "" foreach x $board_variant_list { regsub -all "^\[ \t\]*" $x "" x regsub -all "\[ \t\]*$" $x "" x if { $x eq "" } { continue } switch -glob -- $x { "aout" { set_board_info obj_format "a.out" } "elf" { set_board_info obj_format "elf" } "pe" { set_board_info obj_format "pe" } "ecoff" { set_board_info obj_format "ecoff" } "stabs" { set_board_info debug_flags "-gstabs" } "dwarf2" { set_board_info debug_flags "-gdwarf2" } "gdb:*=*" { regsub "^gdb:\[^=\]*=(.*)$" $x "\\1" value regsub "^gdb:(\[^=\]*)=.*$" $x "\\1" variable set_board_info $variable $value } "gdb*remote" { set is_gdb_remote 1 } "little*endian" - "el" - "EL" { append multilib_flags " -EL" } "big*endian" - "eb" - "EB" { append multilib_flags " -EB" } "soft*float" { append multilib_flags " -msoft-float" } "-*" { append multilib_flags " $x" } default { append multilib_flags " -m$x" } } } set_board_info multilib_flags $multilib_flags } proc add_multilib_option { args } { global board_variant_list if {![info exists board_variant_list]} { set board_variant_list "" } set board_variant_list [concat $args $board_variant_list] } proc find_gas { } { global tool_root_dir set AS "" if {![isremote host]} { set AS [lookfor_file $tool_root_dir as-new] if { $AS eq "" } { set AS [lookfor_file $tool_root_dir gas/as-new] } } if { $AS eq "" } { set AS [transform as] } return $AS } proc find_ld { } { global tool_root_dir set LD "" if {![isremote host]} { set LD [lookfor_file $tool_root_dir ld-new] if { $LD eq "" } { set LD [lookfor_file $tool_root_dir ld/ld-new] } } if { $LD eq "" } { set LD [transform ld] } return $LD } proc build_wrapper { gluefile } { global libdir global tool if {[target_info exists wrap_m68k_aout]} { set flags "additional_flags=-DWRAP_M68K_AOUT" set result "" } elseif {[target_info exists uses_underscores]} { set flags "additional_flags=-DUNDERSCORES" set result "-Wl,-wrap,_exit -Wl,-wrap,__exit -Wl,-wrap,_main -Wl,-wrap,_abort" } else { set flags "" if {[target_info exists is_vxworks]} { set flags "additional_flags=-DVXWORKS" set result "-Wl,-wrap,exit -Wl,-wrap,_exit -Wl,-wrap,main -Wl,-wrap,abort" } else { set result "-Wl,-wrap,exit -Wl,-wrap,_exit -Wl,-wrap,main -Wl,-wrap,abort" } } if {[target_info exists wrap_compile_flags]} { lappend flags "additional_flags=[target_info wrap_compile_flags]" } if { [target_compile $libdir/testglue.c $gluefile object $flags] eq "" } { set gluefile [remote_download host $gluefile ${tool}_tg.o] return [list $gluefile $result] } else { return "" } } proc winsup_include_flags { args } { global srcdir if {[isnative]} { return "" } if {[isremote host]} { return "" } set gccpath "[get_multilibs]" if {[file exists [file join $gccpath winsup]]} { verbose "Winsup path is $gccpath/winsup" set winsup_dir [lookfor_file $srcdir winsup/include/windows.h] if { $winsup_dir ne "" } { set winsup_dir [file dirname $winsup_dir] # See comment in libio_include_flags about using -I. return " -I$winsup_dir" } } verbose "No winsup support for this target" } # Find the winsup libraries in the current source tree. # proc winsup_link_flags { args } { # libgloss doesn't work native if {[isnative]} { return "" } # if we're on a remote host, we can't search for the file, so we can only # use an installed compiler, so we don't add any paths here. if {[isremote host]} { return "" } set gccpath "[get_multilibs]" verbose "Looking for $gccpath/winsup" if {[file exists [file join $gccpath winsup]]} { verbose "Winsup path is $gccpath/newlib" return "-B$gccpath/winsup/ -L$gccpath/winsup" } else { verbose "No winsup support for this target" return "" } }