-
So, I need to run old toolchains, and and found old binutils respond differently when queried about the version
bu_v="`$ld --version 2> /dev/null | head -n1 | cut -d" " -f4`"
(new)
bu_v="`$ld --version 2> /dev/null | head -n1 | cut -d" " -f5`"
(old)
is there a way to always get the same answer? :-//
(is there a better way to do it?)
this stuff has to be used from a bash script
# mytc_version_get tc mipsel-unknown-linux-gnu
2.21.1/4.5.3
(binutils/gcc (crosscompiler))
# mytc_version_get bu mipsel-unknown-linux-gnu
2.21.1
(binutils (crosscompiler))
# mytc_version_get cc mipsel-unknown-linux-gnu
4.5.3
(gcc (crosscompiler))
# mytc_version_get tc
2.33.1/9.3.0
(binutils/gcc (host))
-
Post as many as possible xxxx-ld --version of your toolchains, so we can determine a logic to extract the version. I expect that in the true and tested tradition of "real-programmers" the host OS packaging system is totally ignored and these are installed from archives in different places as it seems fit and eventually added to the path :palm:.
On my development machines I always pack these myself if not provided, so I can always query dpkg, but out of curiosity I've run the command on few of the toolchains installed:
ld --version
GNU ld (GNU Binutils for Ubuntu) 2.30
arm-v5te-linux-gnueabi-ld --version
GNU ld (GNU Binutils) 2.31.1
arm-ppc-linux-uclibcgnueabi-ld --version
GNU ld (crosstool-NG crosstool-ng-1.23.0) 2.28
aarch64-v8a-linux-gnu-ld --version
GNU ld (GNU Binutils) 2.35
So here the parsing is elementary, but I'm curious to see the variations for your toolchains. My really old toolchains are installed on a virtual Ubuntu 16.04 that is not started now.
Cheers,
DC1MC
-
is there a way to always get the same answer? :-//
(is there a better way to do it?)
If you can't force the same version output format string from different tools versions, then you could try to first parse/match some known version format. If that fails, then try to parse/match some other format etc. until the parser is able to return a valid version string.
-
mipsel-unknown-linux-gnu-ld --version
GNU ld (GNU Binutils 2.35.1 p2) 2.35.1
Copyright (C) 2020 Free Software Foundation, Inc.
This program is free software; you may redistribute it under the terms of
the GNU General Public License version 3 or (at your option) a later version.
This program has absolutely no warranty.
GNU ld (GNU Binutils) 2.21.1
Copyright 2011 Free Software Foundation, Inc.
This program is free software; you may redistribute it under the terms of
the GNU General Public License version 3 or (at your option) a later version.
This program has absolutely no warranty.
-
OK, then pipe your --version results like this, to see if we have some outliers:
<your toolchain component> --version | head -n 1 | tr -d ' '| cut -f 2 -d\)
-
The version is the last number at the end of the first line? That is pretty simple to parse with grep.
For example in my system:
$ ld --version
GNU ld (GNU Binutils for Ubuntu) 2.38
Copyright (C) 2022 Free Software Foundation, Inc.
This program is free software; you may redistribute it under the terms of
the GNU General Public License version 3 or (at your option) a later version.
This program has absolutely no warranty.
This oneliner will produce version number 2.38:
$ ld --version | head -n 1 | grep -o "[^[:blank:]]*$"
2.38
-
The version is the last number at the end of the first line? That is pretty simple to parse with grep.
For example in my system:
$ ld --version
GNU ld (GNU Binutils for Ubuntu) 2.38
Copyright (C) 2022 Free Software Foundation, Inc.
This program is free software; you may redistribute it under the terms of
the GNU General Public License version 3 or (at your option) a later version.
This program has absolutely no warranty.
This oneliner will produce version number 2.38:
$ ld --version | head -n 1 | grep -o "[^[:blank:]]*$"
2.38
this as well, now we need to see if we have some strange versions like 4.22.3/20060821 or, worse 3.35.2 20110222
-
The version is the last number at the end of the first line? That is pretty simple to parse with grep.
For example in my system:
$ ld --version
GNU ld (GNU Binutils for Ubuntu) 2.38
Copyright (C) 2022 Free Software Foundation, Inc.
This program is free software; you may redistribute it under the terms of
the GNU General Public License version 3 or (at your option) a later version.
This program has absolutely no warranty.
This oneliner will produce version number 2.38:
$ ld --version | head -n 1 | grep -o "[^[:blank:]]*$"
2.38
this as well, now we need to see if we have some strange versions like 4.22.3/20060821 or, worse 3.35.2 20110222
Grep is able to perform alternative matching using | operator, so it may be still possible to parse different version string formats with a single oneliner.
-
@DC1MC
it works!!!
perfect job :-+ :-+ :-+
-
@DC1MC
it works!!!
perfect job :-+ :-+ :-+
Most welcome ^-^
-
# ./mybuild-2023
kernel-2.6.37.1(mips.32/le)
tc) show toolchain version
up) script_update
0) clean
1) configure
2) compile app
3) app module
4) tftp kernel@192.168.1.21:
5) tools
app_name = kernel-2.6.37.1-32bit
machine_note = revB
qualified_host = { macmini-intel } ... accepted
toolchain = mipsel-unknown-linux-gnu:2.21.1/4.5.3
checking toolchain ... failed
[!] panic
module=profile/do/utils_ver
reason=found gcc-v4.5.3, needed gcc-v{ 4.6.0 .. 4.7.0 }
This is a practical application when you want to share a kernel/firmware repo among different machines with different ecosystems, or among different ecosystems on the same machine.
That check remembers me I have to select the proper toolchain version.
[1] aarch64-unknown-linux-gnu-6.5.0
[2] aarch64-unknown-linux-gnu-9.3.0 *
[3] armv5tel-softfloat-linux-gnueabi-6.5.0 *
[4] armv5tel-softfloat-linux-gnueabi-9.3.0
[5] armv7a-unknown-linux-gnueabihf-6.5.0
[6] armv7a-unknown-linux-gnueabihf-8.4.0
[7] armv7a-unknown-linux-gnueabihf-9.3.0 *
[8] hppa-unknown-linux-gnu-6.5.0
[9] hppa-unknown-linux-gnu-9.3.0 *
[10] hppa64-unknown-linux-gnu-6.5.0
[11] hppa64-unknown-linux-gnu-9.3.0 *
[12] i686-pc-linux-gnu-4.9.4-gnat2016
[13] i686-pc-linux-gnu-6.5.0
[14] i686-pc-linux-gnu-7.3.1-gnat2018
[15] i686-pc-linux-gnu-7.5.0
[16] i686-pc-linux-gnu-8.3.1-gnat2019
[17] i686-pc-linux-gnu-8.4.0
[18] i686-pc-linux-gnu-9.3.0 *
[19] i686-pc-linux-gnu-10.2.0
[20] mips-unknown-linux-gnu-4.1.2-legacy
[21] mips-unknown-linux-gnu-4.5.3-legacy
[22] mips-unknown-linux-gnu-6.5.0
[23] mips-unknown-linux-gnu-9.3.0 *
[24] mips64-unknown-linux-gnu-6.5.0 *
[25] mips64-unknown-linux-gnu-9.3.0
[26] mipsel-unknown-linux-gnu-4.5.3-legacy *
[27] mipsel-unknown-linux-gnu-6.5.0
[28] mipsel-unknown-linux-gnu-9.3.0
[29] powerpc-unknown-linux-gnu-6.5.0
[30] powerpc-unknown-linux-gnu-9.3.0 *
[31] powerpc64-unknown-linux-gnu-9.3.0 *
[32] sparc64-unknown-linux-gnu-6.5.0 *
[33] sparc64-unknown-linux-gnu-9.3.0
[34] x86_64-pc-linux-gnu-10.2.0 *
Or ... that I have to compile the correct version of the cross-compiler :o :o :o
-
In case you are still interested, here are some more strings:
GNU ld (2.34-4ubuntu1+13ubuntu1) 2.3
GNU ld (GNU Arm Embedded Toolchain 9-2020-q2-update) 2.34.0.20200428
GNU ld (GNU Arm Embedded Toolchain 10.3-2021.10) 2.36.1.20210621
GNU ld (GNU Toolchain for the Arm Architecture 11.2-2022.02 (arm-11.14)) 2.37.20220122
GNU ld (Arm GNU Toolchain 12.2.MPACBTI-Bet1 (Build arm-12-mpacbti.16)) 2.39.50.20220821
GNU ld (Zephyr SDK 0.15.2) 2.38
The pattern seems to be "GNU ld (some text) some.number.and.more"
-
I'd use GNU sed and
ld --version 2>/dev/null | sed -ne 's|^.* \([0-9][^ ]*\) *$|\1|p ; q'
to print the final token on the first line that is preceded by a space and starts with a digit, and nothing else. The q is a GNU extension, so if you use some other sed, check that it supports q first.
If you prefer awk,
ld --version 2>/dev/null | awk 'NR > 1 { exit } NF > 1 { print $NF }'
which does not require GNU awk, and works fine with other awk variants like mawk.
-
function toolchain_cc_get_ver()
{
local test
local cc="$1"
test="`$cc 1> /dev/null 2> /dev/null`"
test="$?"
if [ "$test" == "0" ]
then
#not installed"
ans="?"
else
ans="`$cc -dumpversion 2> /dev/null`"
fi
#return ans
}
function toolchain_bu_get_ver()
{
local test
local ld="$1"
test="`$ld 1> /dev/null 2> /dev/null`"
test="$?"
if [ "$test" == "0" ]
then
#not installed"
ans="?"
else
ans="`$ld --version 2> /dev/null | head -n1 | tr -d ' ' | cut -f 2 -d\)`"
fi
#return ans
}
function get_fixed()
{
local name=$1
local value=$3
local myarch=$4
local content=$2
if [ "*$myarch" != "*" ]
then
value="$myarch-$value"
fi
# if name is not defined by ENV
# then define it
#echo "[$1][$2][$3][$4]"
if [ "*$content" == "*" ]
then
eval $name=$value
fi
}
function get_info()
{
local myarch="$1"
#global cc
#global cc_v
#global ld
#global bu_v
#global tc_v
# echo "myarch=[$myarch]"
get_fixed "cc" "$cc" "gcc" "$myarch"
get_fixed "ld" "$ld" "ld" "$myarch"
toolchain_cc_get_ver "$cc"
cc_v="$ans"
toolchain_bu_get_ver "$ld"
bu_v="$ans"
tc_v="$bu_v/$cc_v"
}
function app()
{
local option="$1"
local myarch="$2"
#global cc
#global cc_v
#global ld
#global bu_v
#global tc_v
get_info "$myarch"
case $option in
"cc") echo "$cc_v" ;;
"bu") echo "$bu_v" ;;
"as") echo "$bu_v" ;;
"ld") echo "$bu_v" ;;
*) echo "$tc_v" ;;
esac
}
app "$1" "$2"
This is the final bash-script.
needs to run it on
- GNU/Linux
- BSD/NetBSD
g-sed is supported :-+
-
function fooo()
{
local argc="$#" # how many args line ?
local args=("$@") # args[]={arg0..argC}
i=$(($argc-1))
item="${args[$i]}"
echo "[$item]"
}
test="`ld --version | head -n1`"
fooo $test
test="`mips-unknown-linux-gnu-ld --version | head -n1`"
fooo $test
test="`mipsel-unknown-linux-gnu-ld --version | head -n1`"
fooo $test
test="`mipsle-unknown-linux-gnu-ld --version | head -n1`"
fooo $test
[2.33.1]
[2.34.0]
[2.35.1]
[2.21.1]
Maybe too silly (sorry), but this trick seems to work too :o :o :o
-
Hint: It is also possible to use Bash's here-document feature to embed a Perl/Python script straight into the Bash command file. This way it is possible to use more suitable tool for a job without external script file dependencies.
For example, if parsing the version number information seems to get too complicated using basic grep and cut, it is possible to use Perl or Python do the parsing instead, and use the full potential and expressiveness of those programming languages.
-
This is the final bash-script.
Bash?
# LastToken VARNAME COMMAND...
function LastTokenOf() {
declare -n thevar=$1
shift 1
local tokens=($(LANG=C LC_ALL=C "$@" 2>/dev/null | head -n 1))
if [ ${#tokens[@]} -gt 1 ]; then
thevar="${tokens[-1]}"
elif [ -z "${tokens[*]}" ]; then
thevar="none"
else
thevar="unknown"
fi
}
LastTokenOf LD_VERSION ${LD:-ld} --version
LastTokenOf GCC_VERSION $(CC:-gcc} --version
using traditional test ([) instead of Bash-specific [[, so that it'll run even on ancient Bashes.
The variable will be set to the last token on the first line, to "none" if the command is not found or it produces no output or an empty first line, or to "unknown" if the command prints a single token on its first line.
-
Just one small note for the sake of completeness, about -v versus --version. The former produces just one line with the version information, while the latter adds copyright and stuff:
> arm-none-eabi-ld -v
GNU ld (GNU Toolchain for the Arm Architecture 11.2-2022.02 (arm-11.14)) 2.37.20220122
> arm-none-eabi-ld --version
GNU ld (GNU Toolchain for the Arm Architecture 11.2-2022.02 (arm-11.14)) 2.37.20220122
Copyright (C) 2021 Free Software Foundation, Inc.
This program is free software; you may redistribute it under the terms of
the GNU General Public License version 3 or (at your option) a later version.
This program has absolutely no warranty.
-
Here is an example of a Bash-script which is using a here-document embedding a Python script which will parse a version number.
Bash script file parse_version.sh:
#!/bin/bash
#
# parse_version.sh
#
PYTHON="python3"
function parse_version() {
local VERSIONSTR="$@"
VER=$(${PYTHON} - <<EOF
import re
s = '$VERSIONSTR'
PATTERNS = [
r'\s([\d\.]+)\/[\d]+$', # 4.22.3/20060821 => 4.22.3
r'\s([\d\.]+)\s[\d\.]+$', # 3.35.2 20110222 => 3.35.2
r'\s([\d\.]+)\.\d{8}$', # 2.39.50.20220821 => 2.39.50
r'\s([\d\.]+)$' # 2.38 => 2.38
]
for p in PATTERNS:
m = re.search(p, s)
if m is not None:
# Found valid version string
v = m.group(1)
print(v)
exit(0)
# Did not find valid version string
print('None')
exit(1)
EOF
)
}
#
# Run tests for the given test version strings
#
VERSIONS=( \
"1 GNU ld (GNU Binutils for Ubuntu) 2.38" \
"2 GNU ld (GNU Binutils for Ubuntu) 4.22.3/20060821" \
"3 GNU ld (GNU Binutils for Ubuntu) 3.35.2 20110222" \
"4 GNU ld (2.34-4ubuntu1+13ubuntu1) 2.3" \
"5 GNU ld (GNU Arm Embedded Toolchain 9-2020-q2-update) 2.34.0.20200428" \
"6 GNU ld (GNU Arm Embedded Toolchain 10.3-2021.10) 2.36.1.20210621" \
"7 GNU ld (GNU Toolchain for the Arm Architecture 11.2-2022.02 (arm-11.14)) 2.37.20220122" \
"8 GNU ld (Arm GNU Toolchain 12.2.MPACBTI-Bet1 (Build arm-12-mpacbti.16)) 2.39.50.20220821" \
"9 GNU ld (Zephyr SDK 0.15.2) 2.38" \
"10 GNU ld (Zephyr SDK 0.15.2)" \
"11 GNU ld (Zephyr SDK 0.15.2) 1.2.H")
for v in "${VERSIONS[@]}"; do
parse_version $v
echo "Exit code=$?, Version='$VER'"
done
Produced output:
$ ./parse_version.sh
Exit code=0, Version='2.38'
Exit code=0, Version='4.22.3'
Exit code=0, Version='3.35.2'
Exit code=0, Version='2.3'
Exit code=0, Version='2.34.0'
Exit code=0, Version='2.36.1'
Exit code=0, Version='2.37'
Exit code=0, Version='2.39.50'
Exit code=0, Version='2.38'
Exit code=1, Version='None'
Exit code=1, Version='None'
-
WOW, impressed!
Thanks you :D