[RFC] Add git sha information to the gdb version string

classic Classic list List threaded Threaded
15 messages Options
Reply | Threaded
Open this post in threaded view
|

[RFC] Add git sha information to the gdb version string

Andrew Burgess
I don't know if there is any interest in adding git sha information to
the GDB version string.  I seem to recall this was discussed briefly
at 2019's GNU cauldron, but I don't recall if there was interest in
the idea or not.

Personally I think having the git information in the binary can be
helpful, so below is an initial proposal.  I'm happy to change this as
needed if people have feedback on how to improve it.

Let me know what you think,

Thanks,
Andrew

---

Adds information about the precise git version from which gdb was
built.  The new version string will look like this:

  GNU gdb (GDB) 10.0.50.20200307-git (137acc6fbd6-72fbdf834da-2-dirty)

The first half (up to the '-git' string) is as before, and taken from
the version.in file within the gdb source tree, with the date text
taken from the bfd source tree.

The second part is new, and is built from the current git version.
This is broken down like this:

  137acc6fbd6-72fbdf834da-2-dirty
  |         | |         | | |   |
  '---A-----' '-----B---' C '-D-'

Where:
 A - This is the last git commit sha.  This represents the HEAD of the
     branch that was built.
 B - This is the merge base between the current branch and the
     upstream master branch.
 C - The number of commits from the merge base to the current sha.
     This gives an impression of how diverged the branch is.
 D - Is the current git tree fully committed? If not then it is dirty.

Parts B, C, and D are optional, though B and C will almost always
appear together (see below for details).  The following are all valid:

  137acc6fbd6-72fbdf834da-2-dirty

Current HEAD is 137acc6fbd6, which is 2 commits from the merge-base
72fbdf834da (which is in sourceware's master branch), however, the
repository that built this GDB was not fully committed, so 137acc6fbd6
will not accurately represent the source code that built this GDB.

  137acc6fbd6-72fbdf834da-2

Like the above, but the repository was fully committed, so 137acc6fbd6
does exactly match the source code that built this version of GDB.

  72fbdf834da-dirty

This version of GDB was built directly from sourceware's master
branch (commit 72fbdf834da), however the repository had local changes
at the time of build, so 72fbdf834da does not exactly match the source
code that built this version of GDB.

  72fbdf834da

Like the above, but the repository was clean at the time of build, so
72fbdf834da exactly matches that source code that built this version
of GDB.

  137acc6fbd6-unknown-dirty
  137acc6fbd6-unknown

These occur when the version script can't find the remote sourceware
repository, and so is unable to figure out a suitable merge-base, nor
can the script figure out if the current HEAD is in sourceware's
master branch.  In this case parts B and C are replaced with the
string 'unknown'.

I have tried to ensure that if the source code is not a git repository
then the git version token will not be added, so folks building from
tar files should get exactly what they had before.

The file gdbsupport/remote-repository contains the pattern used to
identify the remote repository, and the name of the upstream branch
from that repository which we care about.  For us this will be
sourceware and master, but by moving these strings into a separate
file anyone maintaining an out of tree GDB can easily update these to
point to their repository and branch, and get project specific version
strings.

gdbsupport/ChangeLog:

        * create-version.sh: Add git sha information.
        * remote-repository: New file.

gdbserver/ChangeLog:

        * Makefile.in (version-generated.cc): Add remote-repository file
        as a dependency.

gdb/ChangeLog:

        * Makefile.in (stamp-version): Add remote-repository file as a
        dependency.
---
 gdb/ChangeLog                |  5 +++++
 gdb/Makefile.in              |  2 +-
 gdbserver/ChangeLog          |  5 +++++
 gdbserver/Makefile.in        |  2 +-
 gdbsupport/ChangeLog         |  5 +++++
 gdbsupport/create-version.sh | 45 ++++++++++++++++++++++++++++++++++++++++++++
 gdbsupport/remote-repository |  2 ++
 7 files changed, 64 insertions(+), 2 deletions(-)
 create mode 100644 gdbsupport/remote-repository

diff --git a/gdb/Makefile.in b/gdb/Makefile.in
index 0c331af4bff..9b5ad1ea176 100644
--- a/gdb/Makefile.in
+++ b/gdb/Makefile.in
@@ -2068,7 +2068,7 @@ $(srcdir)/copying.c: @MAINTAINER_MODE_TRUE@ $(srcdir)/../COPYING3 $(srcdir)/copy
 version.c: stamp-version; @true
 # Note that the obvious names for the temp file are taken by
 # create-version.sh.
-stamp-version: Makefile version.in $(srcdir)/../bfd/version.h $(srcdir)/../gdbsupport/create-version.sh
+stamp-version: Makefile version.in $(srcdir)/../bfd/version.h $(srcdir)/../gdbsupport/create-version.sh $(srcdir)/../gdbsupport/remote-repository
  $(ECHO_GEN) $(SHELL) $(srcdir)/../gdbsupport/create-version.sh $(srcdir) \
     $(host_alias) $(target_alias) version-t.t
  @$(SHELL) $(srcdir)/../move-if-change version-t.t version.c
diff --git a/gdbserver/Makefile.in b/gdbserver/Makefile.in
index 8c35c169d62..0c67d64b02e 100644
--- a/gdbserver/Makefile.in
+++ b/gdbserver/Makefile.in
@@ -445,7 +445,7 @@ am--refresh:
 
 force:
 
-version-generated.cc: Makefile $(srcdir)/../gdb/version.in $(srcdir)/../bfd/version.h $(srcdir)/../gdbsupport/create-version.sh
+version-generated.cc: Makefile $(srcdir)/../gdb/version.in $(srcdir)/../bfd/version.h $(srcdir)/../gdbsupport/create-version.sh $(srcdir)/../gdbsupport/remote-repository
  $(ECHO_GEN) $(SHELL) $(srcdir)/../gdbsupport/create-version.sh $(srcdir)/../gdb \
  $(host_alias) $(target_alias) $@
 
diff --git a/gdbsupport/create-version.sh b/gdbsupport/create-version.sh
index 81d6dbf8c1f..2f8e5a3e283 100755
--- a/gdbsupport/create-version.sh
+++ b/gdbsupport/create-version.sh
@@ -27,9 +27,54 @@ host_alias="$2"
 target_alias="$3"
 output="$4"
 
+GIT_TAG=""
+if $(cd $srcdir && git rev-parse --show-toplevel >/dev/null 2>/dev/null); then
+    short_head_sha=$(cd $srcdir && git rev-parse --short HEAD)
+
+    dirty_mark=""
+    (cd $srcdir && git update-index -q --refresh)
+    test -z "$(cd $srcdir && git diff-index --name-only HEAD --)" ||
+ dirty_mark="-dirty"
+
+    remote_repo_pattern=`grep ^pattern: \
+ $srcdir/../gdbsupport/remote-repository \
+ | cut -d: -f2-`
+    remote_repo_branch=`grep ^branch: \
+ $srcdir/../gdbsupport/remote-repository \
+ | cut -d: -f2-`
+    branch_info=""
+    remote_name=`(cd $srcdir && git remote -v) \
+ | grep ${remote_repo_pattern} | grep \(fetch\) \
+ | awk -F '\t' '{print $1}'`
+    if [ -n "${remote_name}" ]; then
+ remote_branch="${remote_name}/${remote_repo_branch}"
+ # If the remote branch contains our commit, then we're good.
+ if ! $(cd $srcdir  && git merge-base \
+  --is-ancestor ${short_head_sha} \
+  ${remote_branch}); then
+    # SHA is not on the remote tracking branch.  We need to figure out
+    # the merge base, and the distance from that merge base.
+    merge_base_sha=$(cd $srcdir && git merge-base ${short_head_sha} \
+       ${remote_branch})
+    short_merge_base_sha=$(cd $srcdir \
+       && git rev-parse \
+      --short ${merge_base_sha})
+    commit_count=$(cd $srcdir \
+       && git rev-list --count ${merge_base_sha}..HEAD)
+    branch_info="-${short_merge_base_sha}-${commit_count}"
+ fi
+    else
+ branch_info="-unknown"
+    fi
+    GIT_TAG="${short_head_sha}${branch_info}${dirty_mark}"
+fi
+
 rm -f version.c-tmp $output version.tmp
 date=`sed -n -e 's/^.* BFD_VERSION_DATE \(.*\)$/\1/p' $srcdir/../bfd/version.h`
 sed -e "s/DATE/$date/" < $srcdir/version.in > version.tmp
+if [ -n "$GIT_TAG" ]; then
+    echo " ($GIT_TAG)" >> version.tmp
+fi
 echo '#include "gdbsupport/version.h"' >> version.c-tmp
 echo 'const char version[] = "'"`sed q version.tmp`"'";' >> version.c-tmp
 echo 'const char host_name[] = "'"$host_alias"'";' >> version.c-tmp
diff --git a/gdbsupport/remote-repository b/gdbsupport/remote-repository
new file mode 100644
index 00000000000..c05f3163e81
--- /dev/null
+++ b/gdbsupport/remote-repository
@@ -0,0 +1,2 @@
+pattern:sourceware.org/git/binutils-gdb.git
+branch:master
--
2.14.5

Reply | Threaded
Open this post in threaded view
|

Re: [RFC] Add git sha information to the gdb version string

Simon Marchi-4
Hi Andrew,

On 2020-03-25 7:48 a.m., Andrew Burgess wrote:

> I don't know if there is any interest in adding git sha information to
> the GDB version string.  I seem to recall this was discussed briefly
> at 2019's GNU cauldron, but I don't recall if there was interest in
> the idea or not.
>
> Personally I think having the git information in the binary can be
> helpful, so below is an initial proposal.  I'm happy to change this as
> needed if people have feedback on how to improve it.
>
> Let me know what you think,
>
> Thanks,
> Andrew

I am in favor of this, and I have no comments on the user-visible result, I like the
way it looks.

When we discussed this, we had the "build date" and the "git sha1" camps.  I think
they both have their use, so keeping both in the version string is good.

For the shell script, I'd suggest to first make a patch (probably obvious) to make it
shellcheck-clean [1], and then ensure that your patch keeps it clean.  shellcheck finds
so many little gotchas of shell scripting.

[1] https://github.com/koalaman/shellcheck

> The file gdbsupport/remote-repository contains the pattern used to
> identify the remote repository, and the name of the upstream branch
> from that repository which we care about.  For us this will be
> sourceware and master, but by moving these strings into a separate
> file anyone maintaining an out of tree GDB can easily update these to
> point to their repository and branch, and get project specific version
> strings.

What is the advantage of doing this, versus just doing

  git-merge-base master HEAD

... which would just use the local master branch?

I presume that this file will need to be updated to change the branch name
in the stable branches (CCing Joel for that).

> diff --git a/gdbsupport/create-version.sh b/gdbsupport/create-version.sh
> index 81d6dbf8c1f..2f8e5a3e283 100755
> --- a/gdbsupport/create-version.sh
> +++ b/gdbsupport/create-version.sh
> @@ -27,9 +27,54 @@ host_alias="$2"
>  target_alias="$3"
>  output="$4"
>  
> +GIT_TAG=""
> +if $(cd $srcdir && git rev-parse --show-toplevel >/dev/null 2>/dev/null); then
> +    short_head_sha=$(cd $srcdir && git rev-parse --short HEAD)
> +
> +    dirty_mark=""
> +    (cd $srcdir && git update-index -q --refresh)
>
> +    test -z "$(cd $srcdir && git diff-index --name-only HEAD --)" ||
> + dirty_mark="-dirty"
> +
> +    remote_repo_pattern=`grep ^pattern: \
> + $srcdir/../gdbsupport/remote-repository \
> + | cut -d: -f2-`
> +    remote_repo_branch=`grep ^branch: \
> + $srcdir/../gdbsupport/remote-repository \
> + | cut -d: -f2-`
> +    branch_info=""
> +    remote_name=`(cd $srcdir && git remote -v) \
> + | grep ${remote_repo_pattern} | grep \(fetch\) \
> + | awk -F '\t' '{print $1}'`
> +    if [ -n "${remote_name}" ]; then
> + remote_branch="${remote_name}/${remote_repo_branch}"
> + # If the remote branch contains our commit, then we're good.
> + if ! $(cd $srcdir  && git merge-base \
> +  --is-ancestor ${short_head_sha} \
> +  ${remote_branch}); then
> +    # SHA is not on the remote tracking branch.  We need to figure out
> +    # the merge base, and the distance from that merge base.
> +    merge_base_sha=$(cd $srcdir && git merge-base ${short_head_sha} \
> +       ${remote_branch})
> +    short_merge_base_sha=$(cd $srcdir \
> +       && git rev-parse \
> +      --short ${merge_base_sha})
> +    commit_count=$(cd $srcdir \
> +       && git rev-list --count ${merge_base_sha}..HEAD)
> +    branch_info="-${short_merge_base_sha}-${commit_count}"
> + fi
> +    else
> + branch_info="-unknown"
> +    fi
> +    GIT_TAG="${short_head_sha}${branch_info}${dirty_mark}"
> +fi

Could you please comment the code a bit more, to say what each line does?  It will
make it easier to read in the future, if we want to fix/modify it.

Simon
Reply | Threaded
Open this post in threaded view
|

Re: [RFC] Add git sha information to the gdb version string

Andrew Burgess
* Simon Marchi <[hidden email]> [2020-03-26 10:55:59 -0400]:

> Hi Andrew,
>
> On 2020-03-25 7:48 a.m., Andrew Burgess wrote:
> > I don't know if there is any interest in adding git sha information to
> > the GDB version string.  I seem to recall this was discussed briefly
> > at 2019's GNU cauldron, but I don't recall if there was interest in
> > the idea or not.
> >
> > Personally I think having the git information in the binary can be
> > helpful, so below is an initial proposal.  I'm happy to change this as
> > needed if people have feedback on how to improve it.
> >
> > Let me know what you think,
> >
> > Thanks,
> > Andrew
>
> I am in favor of this, and I have no comments on the user-visible result, I like the
> way it looks.
>
> When we discussed this, we had the "build date" and the "git sha1" camps.  I think
> they both have their use, so keeping both in the version string is good.
>
> For the shell script, I'd suggest to first make a patch (probably obvious) to make it
> shellcheck-clean [1], and then ensure that your patch keeps it clean.  shellcheck finds
> so many little gotchas of shell scripting.
>
> [1] https://github.com/koalaman/shellcheck

Good idea, I'll take a look at doing this.

>
> > The file gdbsupport/remote-repository contains the pattern used to
> > identify the remote repository, and the name of the upstream branch
> > from that repository which we care about.  For us this will be
> > sourceware and master, but by moving these strings into a separate
> > file anyone maintaining an out of tree GDB can easily update these to
> > point to their repository and branch, and get project specific version
> > strings.
>
> What is the advantage of doing this, versus just doing
>
>   git-merge-base master HEAD
>
> ... which would just use the local master branch?

I'd very much like to not make assumptions about what people have
chosen to name branches in their local repository.

>
> I presume that this file will need to be updated to change the branch name
> in the stable branches (CCing Joel for that).

Yes, if we wanted the merge-base part to show anything better than the
SHA where the release branch forked from the master branch then this
file would need to be changed when the release branch was created.

>
> > diff --git a/gdbsupport/create-version.sh b/gdbsupport/create-version.sh
> > index 81d6dbf8c1f..2f8e5a3e283 100755
> > --- a/gdbsupport/create-version.sh
> > +++ b/gdbsupport/create-version.sh
> > @@ -27,9 +27,54 @@ host_alias="$2"
> >  target_alias="$3"
> >  output="$4"
> >  
> > +GIT_TAG=""
> > +if $(cd $srcdir && git rev-parse --show-toplevel >/dev/null 2>/dev/null); then
> > +    short_head_sha=$(cd $srcdir && git rev-parse --short HEAD)
> > +
> > +    dirty_mark=""
> > +    (cd $srcdir && git update-index -q --refresh)
> >
> > +    test -z "$(cd $srcdir && git diff-index --name-only HEAD --)" ||
> > + dirty_mark="-dirty"
> > +
> > +    remote_repo_pattern=`grep ^pattern: \
> > + $srcdir/../gdbsupport/remote-repository \
> > + | cut -d: -f2-`
> > +    remote_repo_branch=`grep ^branch: \
> > + $srcdir/../gdbsupport/remote-repository \
> > + | cut -d: -f2-`
> > +    branch_info=""
> > +    remote_name=`(cd $srcdir && git remote -v) \
> > + | grep ${remote_repo_pattern} | grep \(fetch\) \
> > + | awk -F '\t' '{print $1}'`
> > +    if [ -n "${remote_name}" ]; then
> > + remote_branch="${remote_name}/${remote_repo_branch}"
> > + # If the remote branch contains our commit, then we're good.
> > + if ! $(cd $srcdir  && git merge-base \
> > +  --is-ancestor ${short_head_sha} \
> > +  ${remote_branch}); then
> > +    # SHA is not on the remote tracking branch.  We need to figure out
> > +    # the merge base, and the distance from that merge base.
> > +    merge_base_sha=$(cd $srcdir && git merge-base ${short_head_sha} \
> > +       ${remote_branch})
> > +    short_merge_base_sha=$(cd $srcdir \
> > +       && git rev-parse \
> > +      --short ${merge_base_sha})
> > +    commit_count=$(cd $srcdir \
> > +       && git rev-list --count ${merge_base_sha}..HEAD)
> > +    branch_info="-${short_merge_base_sha}-${commit_count}"
> > + fi
> > +    else
> > + branch_info="-unknown"
> > +    fi
> > +    GIT_TAG="${short_head_sha}${branch_info}${dirty_mark}"
> > +fi
>
> Could you please comment the code a bit more, to say what each line does?  It will
> make it easier to read in the future, if we want to fix/modify it.

Will do.

Thanks,
Andrew
Reply | Threaded
Open this post in threaded view
|

[PATCH 0/2] Adding git sha information to the version string

Andrew Burgess
In reply to this post by Simon Marchi-4
Following up to Simon's feedback:

 1. Patch #1 now make create-version.sh shellcheck clean.

 2. Patch #2 keeps create-version.sh shellcheck clean, and adds more
    comments throughout.

Thanks
Andrew

---

Andrew Burgess (2):
  gdbsupport: Resolve shellcheck issues in create-version.sh script
  Add git sha information to the gdb version string

 gdb/ChangeLog                |   5 ++
 gdb/Makefile.in              |   2 +-
 gdbserver/ChangeLog          |   5 ++
 gdbserver/Makefile.in        |   2 +-
 gdbsupport/ChangeLog         |   9 ++++
 gdbsupport/create-version.sh | 108 +++++++++++++++++++++++++++++++++++++++----
 gdbsupport/remote-repository |   2 +
 7 files changed, 123 insertions(+), 10 deletions(-)
 create mode 100644 gdbsupport/remote-repository

--
2.14.5

Reply | Threaded
Open this post in threaded view
|

[PATCH 1/2] gdbsupport: Resolve shellcheck issues in create-version.sh script

Andrew Burgess
Run shellcheck (version 0.4.7) on the create-version.sh script, and
resolve the issues it highlighter - they all seemed reasonable.

gdbsupport/ChangeLog:

        * create-version.sh: Resolve issues highlighted by shellcheck.
---
 gdbsupport/ChangeLog         |  4 ++++
 gdbsupport/create-version.sh | 18 ++++++++++--------
 2 files changed, 14 insertions(+), 8 deletions(-)

diff --git a/gdbsupport/create-version.sh b/gdbsupport/create-version.sh
index 81d6dbf8c1f..6135d219d94 100755
--- a/gdbsupport/create-version.sh
+++ b/gdbsupport/create-version.sh
@@ -27,12 +27,14 @@ host_alias="$2"
 target_alias="$3"
 output="$4"
 
-rm -f version.c-tmp $output version.tmp
-date=`sed -n -e 's/^.* BFD_VERSION_DATE \(.*\)$/\1/p' $srcdir/../bfd/version.h`
-sed -e "s/DATE/$date/" < $srcdir/version.in > version.tmp
-echo '#include "gdbsupport/version.h"' >> version.c-tmp
-echo 'const char version[] = "'"`sed q version.tmp`"'";' >> version.c-tmp
-echo 'const char host_name[] = "'"$host_alias"'";' >> version.c-tmp
-echo 'const char target_name[] = "'"$target_alias"'";' >> version.c-tmp
-mv version.c-tmp $output
+rm -f version.c-tmp "$output" version.tmp
+date=$(sed -n -e 's/^.* BFD_VERSION_DATE \(.*\)$/\1/p' "$srcdir/../bfd/version.h")
+sed -e "s/DATE/$date/" < "$srcdir/version.in" > version.tmp
+{
+    echo '#include "gdbsupport/version.h"'
+    echo 'const char version[] = "'"$(sed q version.tmp)"'";'
+    echo 'const char host_name[] = "'"$host_alias"'";'
+    echo 'const char target_name[] = "'"$target_alias"'";'
+} >> version.c-tmp
+mv version.c-tmp "$output"
 rm -f version.tmp
--
2.14.5

Reply | Threaded
Open this post in threaded view
|

[PATCH 2/2] Add git sha information to the gdb version string

Andrew Burgess
In reply to this post by Andrew Burgess
Adds information about the precise git version from which gdb was
built.  The new version string will look like this:

  GNU gdb (GDB) 10.0.50.20200307-git (137acc6fbd6-72fbdf834da-2-dirty)

The first half (up to the '-git' string) is as before, and taken from
the version.in file within the gdb source tree, with the date text
taken from the bfd source tree.

The second part is new, and is built from the current git version.
This is broken down like this:

  137acc6fbd6-72fbdf834da-2-dirty
  |         | |         | | |   |
  '---A-----' '-----B---' C '-D-'

Where:
 A - This is the last git commit sha.  This represents the HEAD of the
     branch that was built.
 B - This is the merge base between the current branch and the
     upstream master branch.
 C - The number of commits from the merge base to the current sha.
     This gives an impression of how diverged the branch is.
 D - Is the current git tree fully committed? If not then it is dirty.

Parts B, C, and D are optional, though B and C will almost always
appear together (see below for details).  The following are all valid:

  137acc6fbd6-72fbdf834da-2-dirty

Current HEAD is 137acc6fbd6, which is 2 commits from the merge-base
72fbdf834da (which is in sourceware's master branch), however, the
repository that built this GDB was not fully committed, so 137acc6fbd6
will not accurately represent the source code that built this GDB.

  137acc6fbd6-72fbdf834da-2

Like the above, but the repository was fully committed, so 137acc6fbd6
does exactly match the source code that built this version of GDB.

  72fbdf834da-dirty

This version of GDB was built directly from sourceware's master
branch (commit 72fbdf834da), however the repository had local changes
at the time of build, so 72fbdf834da does not exactly match the source
code that built this version of GDB.

  72fbdf834da

Like the above, but the repository was clean at the time of build, so
72fbdf834da exactly matches that source code that built this version
of GDB.

  137acc6fbd6-unknown-dirty
  137acc6fbd6-unknown

These occur when the version script can't find the remote sourceware
repository, and so is unable to figure out a suitable merge-base, nor
can the script figure out if the current HEAD is in sourceware's
master branch.  In this case parts B and C are replaced with the
string 'unknown'.

I have tried to ensure that if the source code is not a git repository
then the git version token will not be added, so folks building from
tar files should get exactly what they had before.

The file gdbsupport/remote-repository contains the pattern used to
identify the remote repository, and the name of the upstream branch
from that repository which we care about.  For us this will be
sourceware and master, but by moving these strings into a separate
file anyone maintaining an out of tree GDB can easily update these to
point to their repository and branch, and get project specific version
strings.

gdbsupport/ChangeLog:

        * create-version.sh: Add git sha information.
        * remote-repository: New file.

gdbserver/ChangeLog:

        * Makefile.in (version-generated.cc): Add remote-repository file
        as a dependency.

gdb/ChangeLog:

        * Makefile.in (stamp-version): Add remote-repository file as a
        dependency.
---
 gdb/ChangeLog                |  5 +++
 gdb/Makefile.in              |  2 +-
 gdbserver/ChangeLog          |  5 +++
 gdbserver/Makefile.in        |  2 +-
 gdbsupport/ChangeLog         |  5 +++
 gdbsupport/create-version.sh | 90 ++++++++++++++++++++++++++++++++++++++++++++
 gdbsupport/remote-repository |  2 +
 7 files changed, 109 insertions(+), 2 deletions(-)
 create mode 100644 gdbsupport/remote-repository

diff --git a/gdb/Makefile.in b/gdb/Makefile.in
index 0c331af4bff..9b5ad1ea176 100644
--- a/gdb/Makefile.in
+++ b/gdb/Makefile.in
@@ -2068,7 +2068,7 @@ $(srcdir)/copying.c: @MAINTAINER_MODE_TRUE@ $(srcdir)/../COPYING3 $(srcdir)/copy
 version.c: stamp-version; @true
 # Note that the obvious names for the temp file are taken by
 # create-version.sh.
-stamp-version: Makefile version.in $(srcdir)/../bfd/version.h $(srcdir)/../gdbsupport/create-version.sh
+stamp-version: Makefile version.in $(srcdir)/../bfd/version.h $(srcdir)/../gdbsupport/create-version.sh $(srcdir)/../gdbsupport/remote-repository
  $(ECHO_GEN) $(SHELL) $(srcdir)/../gdbsupport/create-version.sh $(srcdir) \
     $(host_alias) $(target_alias) version-t.t
  @$(SHELL) $(srcdir)/../move-if-change version-t.t version.c
diff --git a/gdbserver/Makefile.in b/gdbserver/Makefile.in
index 8c35c169d62..0c67d64b02e 100644
--- a/gdbserver/Makefile.in
+++ b/gdbserver/Makefile.in
@@ -445,7 +445,7 @@ am--refresh:
 
 force:
 
-version-generated.cc: Makefile $(srcdir)/../gdb/version.in $(srcdir)/../bfd/version.h $(srcdir)/../gdbsupport/create-version.sh
+version-generated.cc: Makefile $(srcdir)/../gdb/version.in $(srcdir)/../bfd/version.h $(srcdir)/../gdbsupport/create-version.sh $(srcdir)/../gdbsupport/remote-repository
  $(ECHO_GEN) $(SHELL) $(srcdir)/../gdbsupport/create-version.sh $(srcdir)/../gdb \
  $(host_alias) $(target_alias) $@
 
diff --git a/gdbsupport/create-version.sh b/gdbsupport/create-version.sh
index 6135d219d94..68c6518615f 100755
--- a/gdbsupport/create-version.sh
+++ b/gdbsupport/create-version.sh
@@ -27,9 +27,99 @@ host_alias="$2"
 target_alias="$3"
 output="$4"
 
+GIT_TAG=""
+if (cd "$srcdir" && git rev-parse --show-toplevel >/dev/null 2>/dev/null); then
+
+    # The git version string looks something like this:
+    #
+    #     137acc6fbd6-72fbdf834da-2-dirty
+    #     |         | |         | | |   |
+    #     '---A-----' '-----B---' C '-D-'
+    #
+    # Where:
+    #   A - This is the last git commit sha.  This represents the HEAD of the
+    #       branch that was built.
+    #   B - This is the merge base between the current branch and the
+    #       upstream master branch.
+    #   C - The number of commits from the merge base to the current sha.
+    #       This gives an impression of how diverged the branch is.
+    #   D - Is the current git tree fully committed? If not then it is dirty.
+    #
+    # First figure out part A, the short sha for the current head:
+    short_head_sha=$(cd "$srcdir" && git rev-parse --short HEAD)
+
+    # Now figure out part D, the dirty tag.  This might be left as the
+    # empty string if the repository has no local changes.
+    dirty_mark=""
+    (cd "$srcdir" && git update-index -q --refresh)
+    test -z "$(cd "$srcdir" && git diff-index --name-only HEAD --)" ||
+ dirty_mark="-dirty"
+
+    # To calculate parts B and C we need to calculate the merge-base
+    # between the current branch and a specific remote branch.  The
+    # local file 'remote-repository' contains the remote repository
+    # url, and the branch name we are comparing against.  Here we
+    # extract that information.
+    remote_repo_pattern=$(grep ^pattern: \
+       "$srcdir/../gdbsupport/remote-repository" \
+      | cut -d: -f2-)
+    remote_repo_branch=$(grep ^branch: \
+      "$srcdir/../gdbsupport/remote-repository" \
+     | cut -d: -f2-)
+
+    # Use the remote url pattern from the remote-repository file to
+    # find the local name for the remote git repository.
+    remote_name=$( (cd "$srcdir" && git remote -v) \
+ | grep "${remote_repo_pattern}" | grep \(fetch\) \
+ | awk -F '\t' '{print $1}')
+    branch_info=""
+    if [ -n "${remote_name}" ]; then
+ # We found the local name for the remote repository, we can
+ # now go ahead and figure out parts B and C of the version
+ # string.
+ remote_branch="${remote_name}/${remote_repo_branch}"
+ # Check to see if the remote branch contains the current HEAD.
+ # If it does then the user is building directly from (their
+ # checkout of) the upstream branch.
+ if ! (cd "$srcdir"  && git merge-base \
+   --is-ancestor "${short_head_sha}" \
+   "${remote_branch}"); then
+    # The current head sha is not on the remote tracking
+    # branch.  We need to figure out the merge base, and the
+    # distance from that merge base.
+    merge_base_sha=$(cd "$srcdir" && git merge-base "${short_head_sha}" \
+       "${remote_branch}")
+    short_merge_base_sha=$(cd "$srcdir" \
+       && git rev-parse \
+      --short "${merge_base_sha}")
+
+    # Count the commits between the merge base and current head.
+    commit_count=$(cd "$srcdir" \
+       && git rev-list --count "${merge_base_sha}"..HEAD)
+
+    # Now format the parts B and C of the git version string.
+    branch_info="-${short_merge_base_sha}-${commit_count}"
+ else
+    # The user is building from a commit on the upstream
+    # branch.  There's no need to include parts B and C of the
+    # git version string.
+    branch_info=""
+ fi
+    else
+ # We couldn't find the local name for the remote repository.
+ # Maybe this user has cloned from some other remote, or has
+ # deleted their remotes.
+ branch_info="-unknown"
+    fi
+    GIT_TAG="${short_head_sha}${branch_info}${dirty_mark}"
+fi
+
 rm -f version.c-tmp "$output" version.tmp
 date=$(sed -n -e 's/^.* BFD_VERSION_DATE \(.*\)$/\1/p' "$srcdir/../bfd/version.h")
 sed -e "s/DATE/$date/" < "$srcdir/version.in" > version.tmp
+if [ -n "$GIT_TAG" ]; then
+    echo " ($GIT_TAG)" >> version.tmp
+fi
 {
     echo '#include "gdbsupport/version.h"'
     echo 'const char version[] = "'"$(sed q version.tmp)"'";'
diff --git a/gdbsupport/remote-repository b/gdbsupport/remote-repository
new file mode 100644
index 00000000000..c05f3163e81
--- /dev/null
+++ b/gdbsupport/remote-repository
@@ -0,0 +1,2 @@
+pattern:sourceware.org/git/binutils-gdb.git
+branch:master
--
2.14.5

Reply | Threaded
Open this post in threaded view
|

Re: [PATCH 1/2] gdbsupport: Resolve shellcheck issues in create-version.sh script

Simon Marchi-4
In reply to this post by Andrew Burgess
On 2020-03-27 8:27 a.m., Andrew Burgess wrote:

> Run shellcheck (version 0.4.7) on the create-version.sh script, and
> resolve the issues it highlighter - they all seemed reasonable.
>
> gdbsupport/ChangeLog:
>
> * create-version.sh: Resolve issues highlighted by shellcheck.
> ---
>  gdbsupport/ChangeLog         |  4 ++++
>  gdbsupport/create-version.sh | 18 ++++++++++--------
>  2 files changed, 14 insertions(+), 8 deletions(-)
>
> diff --git a/gdbsupport/create-version.sh b/gdbsupport/create-version.sh
> index 81d6dbf8c1f..6135d219d94 100755
> --- a/gdbsupport/create-version.sh
> +++ b/gdbsupport/create-version.sh
> @@ -27,12 +27,14 @@ host_alias="$2"
>  target_alias="$3"
>  output="$4"
>  
> -rm -f version.c-tmp $output version.tmp
> -date=`sed -n -e 's/^.* BFD_VERSION_DATE \(.*\)$/\1/p' $srcdir/../bfd/version.h`
> -sed -e "s/DATE/$date/" < $srcdir/version.in > version.tmp
> -echo '#include "gdbsupport/version.h"' >> version.c-tmp
> -echo 'const char version[] = "'"`sed q version.tmp`"'";' >> version.c-tmp
> -echo 'const char host_name[] = "'"$host_alias"'";' >> version.c-tmp
> -echo 'const char target_name[] = "'"$target_alias"'";' >> version.c-tmp
> -mv version.c-tmp $output
> +rm -f version.c-tmp "$output" version.tmp
> +date=$(sed -n -e 's/^.* BFD_VERSION_DATE \(.*\)$/\1/p' "$srcdir/../bfd/version.h")
> +sed -e "s/DATE/$date/" < "$srcdir/version.in" > version.tmp
> +{
> +    echo '#include "gdbsupport/version.h"'
> +    echo 'const char version[] = "'"$(sed q version.tmp)"'";'
> +    echo 'const char host_name[] = "'"$host_alias"'";'
> +    echo 'const char target_name[] = "'"$target_alias"'";'
> +} >> version.c-tmp
> +mv version.c-tmp "$output"
>  rm -f version.tmp
> --
> 2.14.5
>

Thanks, I think it's probably worth pushing this patch right away, it's an improvement
in its own right.

Simno
Reply | Threaded
Open this post in threaded view
|

Re: [PATCH 2/2] Add git sha information to the gdb version string

Simon Marchi-4
In reply to this post by Andrew Burgess
On 2020-03-27 8:27 a.m., Andrew Burgess wrote:
> +
> +    # Use the remote url pattern from the remote-repository file to
> +    # find the local name for the remote git repository.
> +    remote_name=$( (cd "$srcdir" && git remote -v) \
> + | grep "${remote_repo_pattern}" | grep \(fetch\) \
> + | awk -F '\t' '{print $1}')

I just tried it locally, this is what I get:

  GNU gdb (GDB) 10.0.50.20200327-git (c13ff238f921--0)

I identifier the problem to the fact that I have two remotes that match the given
URL:

$ git remote -v | grep 'sourceware.org/git/binutils-gdb.git'
origin  git://sourceware.org/git/binutils-gdb.git (fetch)
origin  git://sourceware.org/git/binutils-gdb.git (push)
upstream        ssh://sourceware.org/git/binutils-gdb.git (fetch)
upstream        ssh://sourceware.org/git/binutils-gdb.git (push)

I just prefer to use two remotes to reduce the changes of pushing to
`upstream` by mistake.  So the command above prints:

origin
upstream

And that confuses the following commands.  It works better if I put a
`head -n 1` command in there:

-       | grep "${remote_repo_pattern}" | grep \(fetch\) \
+       | grep "${remote_repo_pattern}" | grep \(fetch\) | head -n 1 \

That happens to work well for me, because origin/master is always the one I
keep up to date (I fetch new changes from origin).  upstream/master dates
from the last time I pushed, so is outdated.  Since `origin` alphabetically
comes before `upstream`, it's the one that's going to be used as the
reference point.  But if my "push" remote came before `origin`, it would be
the one used as a reference point, so the version string would always show
that I am at ${some_old_commit} plus many commits on top.  Not really a big
deal for me though, I can live with it.


Otherwise, it looks good to me.  Thanks a lot for the extensive comments, that
makes the script much easier to follow.

Simon

Reply | Threaded
Open this post in threaded view
|

Re: [PATCH 1/2] gdbsupport: Resolve shellcheck issues in create-version.sh script

Andrew Burgess
In reply to this post by Simon Marchi-4
* Simon Marchi <[hidden email]> [2020-03-27 09:11:33 -0400]:

> On 2020-03-27 8:27 a.m., Andrew Burgess wrote:
> > Run shellcheck (version 0.4.7) on the create-version.sh script, and
> > resolve the issues it highlighter - they all seemed reasonable.
> >
> > gdbsupport/ChangeLog:
> >
> > * create-version.sh: Resolve issues highlighted by shellcheck.
> > ---
> >  gdbsupport/ChangeLog         |  4 ++++
> >  gdbsupport/create-version.sh | 18 ++++++++++--------
> >  2 files changed, 14 insertions(+), 8 deletions(-)
> >
> > diff --git a/gdbsupport/create-version.sh b/gdbsupport/create-version.sh
> > index 81d6dbf8c1f..6135d219d94 100755
> > --- a/gdbsupport/create-version.sh
> > +++ b/gdbsupport/create-version.sh
> > @@ -27,12 +27,14 @@ host_alias="$2"
> >  target_alias="$3"
> >  output="$4"
> >  
> > -rm -f version.c-tmp $output version.tmp
> > -date=`sed -n -e 's/^.* BFD_VERSION_DATE \(.*\)$/\1/p' $srcdir/../bfd/version.h`
> > -sed -e "s/DATE/$date/" < $srcdir/version.in > version.tmp
> > -echo '#include "gdbsupport/version.h"' >> version.c-tmp
> > -echo 'const char version[] = "'"`sed q version.tmp`"'";' >> version.c-tmp
> > -echo 'const char host_name[] = "'"$host_alias"'";' >> version.c-tmp
> > -echo 'const char target_name[] = "'"$target_alias"'";' >> version.c-tmp
> > -mv version.c-tmp $output
> > +rm -f version.c-tmp "$output" version.tmp
> > +date=$(sed -n -e 's/^.* BFD_VERSION_DATE \(.*\)$/\1/p' "$srcdir/../bfd/version.h")
> > +sed -e "s/DATE/$date/" < "$srcdir/version.in" > version.tmp
> > +{
> > +    echo '#include "gdbsupport/version.h"'
> > +    echo 'const char version[] = "'"$(sed q version.tmp)"'";'
> > +    echo 'const char host_name[] = "'"$host_alias"'";'
> > +    echo 'const char target_name[] = "'"$target_alias"'";'
> > +} >> version.c-tmp
> > +mv version.c-tmp "$output"
> >  rm -f version.tmp
> > --
> > 2.14.5
> >
>
> Thanks, I think it's probably worth pushing this patch right away, it's an improvement
> in its own right.

Thanks.  I went ahead and pushed this.

Andrew
Reply | Threaded
Open this post in threaded view
|

Re: [PATCH 2/2] Add git sha information to the gdb version string

Andrew Burgess
In reply to this post by Simon Marchi-4
* Simon Marchi <[hidden email]> [2020-03-27 09:56:35 -0400]:

> On 2020-03-27 8:27 a.m., Andrew Burgess wrote:
> > +
> > +    # Use the remote url pattern from the remote-repository file to
> > +    # find the local name for the remote git repository.
> > +    remote_name=$( (cd "$srcdir" && git remote -v) \
> > + | grep "${remote_repo_pattern}" | grep \(fetch\) \
> > + | awk -F '\t' '{print $1}')
>
> I just tried it locally, this is what I get:
>
>   GNU gdb (GDB) 10.0.50.20200327-git (c13ff238f921--0)
>
> I identifier the problem to the fact that I have two remotes that match the given
> URL:
>
> $ git remote -v | grep 'sourceware.org/git/binutils-gdb.git'
> origin  git://sourceware.org/git/binutils-gdb.git (fetch)
> origin  git://sourceware.org/git/binutils-gdb.git (push)
> upstream        ssh://sourceware.org/git/binutils-gdb.git (fetch)
> upstream        ssh://sourceware.org/git/binutils-gdb.git (push)

OK.  I hadn't considered that.  But challenge accepted :)

The new version should handle multiple remotes and identify the most
up to date and use that one.

If try the version below and do 'git remote rename origin zzzzz', then
we should still find and use the zzzzz remote.  I've done a bit of
basic testing but more exposure would be great.

Thanks,
Andrew

---

commit f5f1136f1549720f38d904016ded68e0b70bc99b
Author: Andrew Burgess <[hidden email]>
Date:   Mon Mar 9 10:17:46 2020 +0000

    Add git sha information to the gdb version string
   
    Adds information about the precise git version from which gdb was
    built.  The new version string will look like this:
   
      GNU gdb (GDB) 10.0.50.20200307-git (137acc6fbd6-72fbdf834da-2-dirty)
   
    The first half (up to the '-git' string) is as before, and taken from
    the version.in file within the gdb source tree, with the date text
    taken from the bfd source tree.
   
    The second part is new, and is built from the current git version.
    This is broken down like this:
   
      137acc6fbd6-72fbdf834da-2-dirty
      |         | |         | | |   |
      '---A-----' '-----B---' C '-D-'
   
    Where:
     A - This is the last git commit sha.  This represents the HEAD of the
         branch that was built.
     B - This is the merge base between the current branch and the
         upstream master branch.
     C - The number of commits from the merge base to the current sha.
         This gives an impression of how diverged the branch is.
     D - Is the current git tree fully committed? If not then it is dirty.
   
    Parts B, C, and D are optional, though B and C will almost always
    appear together (see below for details).  The following are all valid:
   
      137acc6fbd6-72fbdf834da-2-dirty
   
    Current HEAD is 137acc6fbd6, which is 2 commits from the merge-base
    72fbdf834da (which is in sourceware's master branch), however, the
    repository that built this GDB was not fully committed, so 137acc6fbd6
    will not accurately represent the source code that built this GDB.
   
      137acc6fbd6-72fbdf834da-2
   
    Like the above, but the repository was fully committed, so 137acc6fbd6
    does exactly match the source code that built this version of GDB.
   
      72fbdf834da-dirty
   
    This version of GDB was built directly from sourceware's master
    branch (commit 72fbdf834da), however the repository had local changes
    at the time of build, so 72fbdf834da does not exactly match the source
    code that built this version of GDB.
   
      72fbdf834da
   
    Like the above, but the repository was clean at the time of build, so
    72fbdf834da exactly matches that source code that built this version
    of GDB.
   
      137acc6fbd6-unknown-dirty
      137acc6fbd6-unknown
   
    These occur when the version script can't find the remote sourceware
    repository, and so is unable to figure out a suitable merge-base, nor
    can the script figure out if the current HEAD is in sourceware's
    master branch.  In this case parts B and C are replaced with the
    string 'unknown'.
   
    I have tried to ensure that if the source code is not a git repository
    then the git version token will not be added, so folks building from
    tar files should get exactly what they had before.
   
    The file gdbsupport/remote-repository contains the pattern used to
    identify the remote repository, and the name of the upstream branch
    from that repository which we care about.  For us this will be
    sourceware and master, but by moving these strings into a separate
    file anyone maintaining an out of tree GDB can easily update these to
    point to their repository and branch, and get project specific version
    strings.
   
    gdbsupport/ChangeLog:
   
            * create-version.sh: Add git sha information.
            * remote-repository: New file.
   
    gdbserver/ChangeLog:
   
            * Makefile.in (version-generated.cc): Add remote-repository file
            as a dependency.
   
    gdb/ChangeLog:
   
            * Makefile.in (stamp-version): Add remote-repository file as a
            dependency.

diff --git a/gdb/Makefile.in b/gdb/Makefile.in
index bc3ef695bbd..92a88f6d7e7 100644
--- a/gdb/Makefile.in
+++ b/gdb/Makefile.in
@@ -2071,7 +2071,7 @@ $(srcdir)/copying.c: @MAINTAINER_MODE_TRUE@ $(srcdir)/../COPYING3 $(srcdir)/copy
 version.c: stamp-version; @true
 # Note that the obvious names for the temp file are taken by
 # create-version.sh.
-stamp-version: Makefile version.in $(srcdir)/../bfd/version.h $(srcdir)/../gdbsupport/create-version.sh
+stamp-version: Makefile version.in $(srcdir)/../bfd/version.h $(srcdir)/../gdbsupport/create-version.sh $(srcdir)/../gdbsupport/remote-repository
  $(ECHO_GEN) $(SHELL) $(srcdir)/../gdbsupport/create-version.sh $(srcdir) \
     $(host_alias) $(target_alias) version-t.t
  @$(SHELL) $(srcdir)/../move-if-change version-t.t version.c
diff --git a/gdbserver/ChangeLog b/gdbserver/ChangeLog
index 37e38611d5d..b52d6bccf95 100644
--- a/gdbserver/ChangeLog
+++ b/gdbserver/ChangeLog
@@ -1,3 +1,8 @@
+2020-03-27  Andrew Burgess  <[hidden email]>
+
+ * Makefile.in (version-generated.cc): Add remote-repository file
+ as a dependency.
+
 2020-03-20  Simon Marchi  <[hidden email]>
 
  * config.in: Re-generate.
diff --git a/gdbserver/Makefile.in b/gdbserver/Makefile.in
index 8c35c169d62..0c67d64b02e 100644
--- a/gdbserver/Makefile.in
+++ b/gdbserver/Makefile.in
@@ -445,7 +445,7 @@ am--refresh:
 
 force:
 
-version-generated.cc: Makefile $(srcdir)/../gdb/version.in $(srcdir)/../bfd/version.h $(srcdir)/../gdbsupport/create-version.sh
+version-generated.cc: Makefile $(srcdir)/../gdb/version.in $(srcdir)/../bfd/version.h $(srcdir)/../gdbsupport/create-version.sh $(srcdir)/../gdbsupport/remote-repository
  $(ECHO_GEN) $(SHELL) $(srcdir)/../gdbsupport/create-version.sh $(srcdir)/../gdb \
  $(host_alias) $(target_alias) $@
 
diff --git a/gdbsupport/ChangeLog b/gdbsupport/ChangeLog
index 1d27971f5cc..1323894b407 100644
--- a/gdbsupport/ChangeLog
+++ b/gdbsupport/ChangeLog
@@ -1,3 +1,8 @@
+2020-03-27  Andrew Burgess  <[hidden email]>
+
+ * create-version.sh: Add git sha information.
+ * remote-repository: New file.
+
 2020-03-27  Andrew Burgess  <[hidden email]>
 
  * create-version.sh: Resolve issues highlighted by shellcheck.
diff --git a/gdbsupport/create-version.sh b/gdbsupport/create-version.sh
index 6135d219d94..52c8dc959d5 100755
--- a/gdbsupport/create-version.sh
+++ b/gdbsupport/create-version.sh
@@ -27,9 +27,182 @@ host_alias="$2"
 target_alias="$3"
 output="$4"
 
+# Takes two parameters extracted from the remote-repository file.  The first
+# is the pattern for the remote repository, and the second is the name of
+# the remote branch to use.
+find_remote_name ()
+{
+    remote_repo_pattern=$1
+    remote_repo_branch=$2
+
+    # Use the remote url pattern from the remote-repository file to
+    # find the local name for the remote git repository.  It might be
+    # that the user has multiple remotes all pointing at the same
+    # remote repository.
+    remote_names=$( (cd "$srcdir" && git remote -v) \
+ | grep "${remote_repo_pattern}" | grep \(fetch\) \
+ | awk -F '\t' '{print $1}')
+
+    # How many remotes did we find?
+    remote_count=$(echo "$remote_names" | wc -l)
+
+    # If we only found 0 or 1 remotes then we know what to do.
+    if [ "$remote_count" = 0 ]; then
+ echo ""
+ return
+    elif [ "$remote_count" = 1 ]; then
+ echo "$remote_names"
+ return
+    fi
+
+    # This user has multiple remotes all pointing at the upstream
+    # repository.  We want to find the most up to date remote, and return
+    # its name.  We don't worry about efficiency here, we assume that there
+    # will only be a couple of remote names pointing at the same remote url.
+    while IFS= read -r remote1; do
+ is_best=yes
+ branch1="$remote1/$remote_repo_branch"
+
+ # Check that this remote can give us a head sha.  No point trying to
+ # use a remote that's just broken.
+ if ! (cd "$srcdir" && git rev-parse --short "$branch1" \
+  >/dev/null 2>/dev/null ); then
+    continue
+ fi
+
+ # Compare REMOTE1 agaist every other remote.
+ while IFS= read -r remote2; do
+    if [ "$remote1" != "$remote2" ]; then
+ branch2="$remote2/$remote_repo_branch"
+
+ # Again, check that REMOTE2 isn't just broken.
+ if ! (cd "$srcdir" && git rev-parse --short "$branch2" \
+  >/dev/null 2>/dev/null ); then
+    continue
+ fi
+
+ # If REMOTE2 is not an ancestor of REMOTE1 then REMOTE2 must
+ # have more recent commits than REMOTE1, so REMOTE1 is not
+ # the best choice.  Two remotes pointing at the same commit
+ # are both ancestors of each other.
+ if ! (cd "$srcdir"  && git merge-base \
+   --is-ancestor "$branch2" \
+   "$branch1"); then
+    is_best=no
+ fi
+    fi
+ done <<EOF
+$remote_names
+EOF
+
+ # If REMOTE1 still looks like the best choice then all other remotes
+ # are its ancestors.  Worst case all other remotes point to the same
+ # commit as REMOTE1, best case, REMOTE1 has the newest commit.
+ if [ "$is_best" = "yes" ]; then
+    echo "${remote1}"
+    return
+ fi
+    done <<EOF
+$remote_names
+EOF
+
+    # None of the remotes appeared to be the "best".  This is weird, but
+    # lets just take the first remote and assume that will give us something
+    # we can work with.
+    echo "$remote_names" | head -n1
+}
+
+GIT_TAG=""
+if (cd "$srcdir" && git rev-parse --show-toplevel >/dev/null 2>/dev/null); then
+
+    # The git version string looks something like this:
+    #
+    #     137acc6fbd6-72fbdf834da-2-dirty
+    #     |         | |         | | |   |
+    #     '---A-----' '-----B---' C '-D-'
+    #
+    # Where:
+    #   A - This is the last git commit sha.  This represents the HEAD of the
+    #       branch that was built.
+    #   B - This is the merge base between the current branch and the
+    #       upstream master branch.
+    #   C - The number of commits from the merge base to the current sha.
+    #       This gives an impression of how diverged the branch is.
+    #   D - Is the current git tree fully committed? If not then it is dirty.
+    #
+    # First figure out part A, the short sha for the current head:
+    short_head_sha=$(cd "$srcdir" && git rev-parse --short HEAD)
+
+    # Now figure out part D, the dirty tag.  This might be left as the
+    # empty string if the repository has no local changes.
+    dirty_mark=""
+    (cd "$srcdir" && git update-index -q --refresh)
+    test -z "$(cd "$srcdir" && git diff-index --name-only HEAD --)" ||
+ dirty_mark="-dirty"
+
+    # To calculate parts B and C we need to calculate the merge-base
+    # between the current branch and a specific remote branch.  The
+    # local file 'remote-repository' contains the remote repository
+    # url, and the branch name we are comparing against.  Here we
+    # extract that information.
+    remote_repo_pattern=$(grep ^pattern: \
+       "$srcdir/../gdbsupport/remote-repository" \
+      | cut -d: -f2-)
+    remote_repo_branch=$(grep ^branch: \
+      "$srcdir/../gdbsupport/remote-repository" \
+     | cut -d: -f2-)
+
+    # Use the remote url pattern from the remote-repository file to
+    # find the local name for the remote git repository.
+    remote_name=$( find_remote_name "${remote_repo_pattern}" "${remote_repo_branch}" )
+    branch_info=""
+    if [ -n "${remote_name}" ]; then
+ # We found the local name for the remote repository, we can
+ # now go ahead and figure out parts B and C of the version
+ # string.
+ remote_branch="${remote_name}/${remote_repo_branch}"
+ # Check to see if the remote branch contains the current HEAD.
+ # If it does then the user is building directly from (their
+ # checkout of) the upstream branch.
+ if ! (cd "$srcdir"  && git merge-base \
+   --is-ancestor "${short_head_sha}" \
+   "${remote_branch}"); then
+    # The current head sha is not on the remote tracking
+    # branch.  We need to figure out the merge base, and the
+    # distance from that merge base.
+    merge_base_sha=$(cd "$srcdir" && git merge-base "${short_head_sha}" \
+       "${remote_branch}")
+    short_merge_base_sha=$(cd "$srcdir" \
+       && git rev-parse \
+      --short "${merge_base_sha}")
+
+    # Count the commits between the merge base and current head.
+    commit_count=$(cd "$srcdir" \
+       && git rev-list --count "${merge_base_sha}"..HEAD)
+
+    # Now format the parts B and C of the git version string.
+    branch_info="-${short_merge_base_sha}-${commit_count}"
+ else
+    # The user is building from a commit on the upstream
+    # branch.  There's no need to include parts B and C of the
+    # git version string.
+    branch_info=""
+ fi
+    else
+ # We couldn't find the local name for the remote repository.
+ # Maybe this user has cloned from some other remote, or has
+ # deleted their remotes.
+ branch_info="-unknown"
+    fi
+    GIT_TAG="${short_head_sha}${branch_info}${dirty_mark}"
+fi
+
 rm -f version.c-tmp "$output" version.tmp
 date=$(sed -n -e 's/^.* BFD_VERSION_DATE \(.*\)$/\1/p' "$srcdir/../bfd/version.h")
 sed -e "s/DATE/$date/" < "$srcdir/version.in" > version.tmp
+if [ -n "$GIT_TAG" ]; then
+    echo " ($GIT_TAG)" >> version.tmp
+fi
 {
     echo '#include "gdbsupport/version.h"'
     echo 'const char version[] = "'"$(sed q version.tmp)"'";'
diff --git a/gdbsupport/remote-repository b/gdbsupport/remote-repository
new file mode 100644
index 00000000000..c05f3163e81
--- /dev/null
+++ b/gdbsupport/remote-repository
@@ -0,0 +1,2 @@
+pattern:sourceware.org/git/binutils-gdb.git
+branch:master
Reply | Threaded
Open this post in threaded view
|

Re: [PATCH 2/2] Add git sha information to the gdb version string

Andreas Schwab-2
On Mär 27 2020, Andrew Burgess wrote:

> diff --git a/gdbsupport/remote-repository b/gdbsupport/remote-repository
> new file mode 100644
> index 00000000000..c05f3163e81
> --- /dev/null
> +++ b/gdbsupport/remote-repository
> @@ -0,0 +1,2 @@
> +pattern:sourceware.org/git/binutils-gdb.git
> +branch:master

That doesn't match.

$ git remote -v
origin  git://sourceware.org/git/binutils-gdb (fetch)
origin  ssh://sourceware.org/git/binutils-gdb (push)

Andreas.

--
Andreas Schwab, [hidden email]
GPG Key fingerprint = 7578 EB47 D4E5 4D69 2510  2552 DF73 E780 A9DA AEC1
"And now for something completely different."
Reply | Threaded
Open this post in threaded view
|

Re: [PATCH 2/2] Add git sha information to the gdb version string

Simon Marchi-4
In reply to this post by Andrew Burgess
On 2020-03-27 11:28 a.m., Andrew Burgess wrote:

> * Simon Marchi <[hidden email]> [2020-03-27 09:56:35 -0400]:
>
>> On 2020-03-27 8:27 a.m., Andrew Burgess wrote:
>>> +
>>> +    # Use the remote url pattern from the remote-repository file to
>>> +    # find the local name for the remote git repository.
>>> +    remote_name=$( (cd "$srcdir" && git remote -v) \
>>> + | grep "${remote_repo_pattern}" | grep \(fetch\) \
>>> + | awk -F '\t' '{print $1}')
>>
>> I just tried it locally, this is what I get:
>>
>>   GNU gdb (GDB) 10.0.50.20200327-git (c13ff238f921--0)
>>
>> I identifier the problem to the fact that I have two remotes that match the given
>> URL:
>>
>> $ git remote -v | grep 'sourceware.org/git/binutils-gdb.git'
>> origin  git://sourceware.org/git/binutils-gdb.git (fetch)
>> origin  git://sourceware.org/git/binutils-gdb.git (push)
>> upstream        ssh://sourceware.org/git/binutils-gdb.git (fetch)
>> upstream        ssh://sourceware.org/git/binutils-gdb.git (push)
>
> OK.  I hadn't considered that.  But challenge accepted :)
>
> The new version should handle multiple remotes and identify the most
> up to date and use that one.
>
> If try the version below and do 'git remote rename origin zzzzz', then
> we should still find and use the zzzzz remote.  I've done a bit of
> basic testing but more exposure would be great.
>
> Thanks,
> Andrew


It works here, if you think this is worth the extra complexity, I am fine with it.

Simon

Reply | Threaded
Open this post in threaded view
|

Re: [PATCH 2/2] Add git sha information to the gdb version string

Andrew Burgess
In reply to this post by Andreas Schwab-2
* Andreas Schwab <[hidden email]> [2020-03-27 16:42:40 +0100]:

> On Mär 27 2020, Andrew Burgess wrote:
>
> > diff --git a/gdbsupport/remote-repository b/gdbsupport/remote-repository
> > new file mode 100644
> > index 00000000000..c05f3163e81
> > --- /dev/null
> > +++ b/gdbsupport/remote-repository
> > @@ -0,0 +1,2 @@
> > +pattern:sourceware.org/git/binutils-gdb.git
> > +branch:master
>
> That doesn't match.
>
> $ git remote -v
> origin  git://sourceware.org/git/binutils-gdb (fetch)
> origin  ssh://sourceware.org/git/binutils-gdb (push)

OK, thanks for highlighting this.  I'll drop the '.git' extension.

Thanks,
Andrew


>
> Andreas.
>
> --
> Andreas Schwab, [hidden email]
> GPG Key fingerprint = 7578 EB47 D4E5 4D69 2510  2552 DF73 E780 A9DA AEC1
> "And now for something completely different."
Reply | Threaded
Open this post in threaded view
|

Re: [PATCH 2/2] Add git sha information to the gdb version string

Joel Brobecker
In reply to this post by Andrew Burgess
Hi Andrew,

Thanks for doing this. I finally had a chance to look at the changes
you are proposing.

First, a point of clarification regarding the discussions that occurred
during last year's GNU Cauldron, since it's actually not the same as
what is proposed here: What was discussed was the reasons people needed
the version date to be updated and checked in every day.  The idea was
to explore alternate options to achieve the same goal without having to
make a commit every single day. Unfortunately, I don't have a solution
for that, right now.

The two ideas aren't mutually exclusive. We may have to adjust
the format of the version ID at some point, but since I don't have
a good solution to the daily checkins problem, that's really
not a consideration at the moment.

I'd like to propose we add a bit more flexibility to this, so vendors
can plug their own way of calculating the ID. Without budening you
with the details, it wouldn't work well in our production environment,
and the only thing that we are really after is the SHA1 of the commit
used during the source packaging and the counter.

What do you guys think of adding a configure option to pass a "git-tag",
for instance, which, when passed, would use that instead of trying
to calculate it on the fly?

One additional question: As far as I can tell, this create-version.sh
creates the version.c files during the build. If so, users building
from source tarballs uploaded to ftp each day (using the src-release.sh
script) would be building versions of GDB without any git information
in them...  What do we think we should have for...
  - official releases;
  - daily snapshots?
Seems like we would want to be consistent regardless of whether
it's a snapshot or a release?

On Fri, Mar 27, 2020 at 12:27:12PM +0000, Andrew Burgess wrote:

> Adds information about the precise git version from which gdb was
> built.  The new version string will look like this:
>
>   GNU gdb (GDB) 10.0.50.20200307-git (137acc6fbd6-72fbdf834da-2-dirty)
>
> The first half (up to the '-git' string) is as before, and taken from
> the version.in file within the gdb source tree, with the date text
> taken from the bfd source tree.
>
> The second part is new, and is built from the current git version.
> This is broken down like this:
>
>   137acc6fbd6-72fbdf834da-2-dirty
>   |         | |         | | |   |
>   '---A-----' '-----B---' C '-D-'
>
> Where:
>  A - This is the last git commit sha.  This represents the HEAD of the
>      branch that was built.
>  B - This is the merge base between the current branch and the
>      upstream master branch.
>  C - The number of commits from the merge base to the current sha.
>      This gives an impression of how diverged the branch is.
>  D - Is the current git tree fully committed? If not then it is dirty.
>
> Parts B, C, and D are optional, though B and C will almost always
> appear together (see below for details).  The following are all valid:
>
>   137acc6fbd6-72fbdf834da-2-dirty
>
> Current HEAD is 137acc6fbd6, which is 2 commits from the merge-base
> 72fbdf834da (which is in sourceware's master branch), however, the
> repository that built this GDB was not fully committed, so 137acc6fbd6
> will not accurately represent the source code that built this GDB.
>
>   137acc6fbd6-72fbdf834da-2
>
> Like the above, but the repository was fully committed, so 137acc6fbd6
> does exactly match the source code that built this version of GDB.
>
>   72fbdf834da-dirty
>
> This version of GDB was built directly from sourceware's master
> branch (commit 72fbdf834da), however the repository had local changes
> at the time of build, so 72fbdf834da does not exactly match the source
> code that built this version of GDB.
>
>   72fbdf834da
>
> Like the above, but the repository was clean at the time of build, so
> 72fbdf834da exactly matches that source code that built this version
> of GDB.
>
>   137acc6fbd6-unknown-dirty
>   137acc6fbd6-unknown
>
> These occur when the version script can't find the remote sourceware
> repository, and so is unable to figure out a suitable merge-base, nor
> can the script figure out if the current HEAD is in sourceware's
> master branch.  In this case parts B and C are replaced with the
> string 'unknown'.
>
> I have tried to ensure that if the source code is not a git repository
> then the git version token will not be added, so folks building from
> tar files should get exactly what they had before.
>
> The file gdbsupport/remote-repository contains the pattern used to
> identify the remote repository, and the name of the upstream branch
> from that repository which we care about.  For us this will be
> sourceware and master, but by moving these strings into a separate
> file anyone maintaining an out of tree GDB can easily update these to
> point to their repository and branch, and get project specific version
> strings.
>
> gdbsupport/ChangeLog:
>
> * create-version.sh: Add git sha information.
> * remote-repository: New file.
>
> gdbserver/ChangeLog:
>
> * Makefile.in (version-generated.cc): Add remote-repository file
> as a dependency.
>
> gdb/ChangeLog:
>
> * Makefile.in (stamp-version): Add remote-repository file as a
> dependency.
> ---
>  gdb/ChangeLog                |  5 +++
>  gdb/Makefile.in              |  2 +-
>  gdbserver/ChangeLog          |  5 +++
>  gdbserver/Makefile.in        |  2 +-
>  gdbsupport/ChangeLog         |  5 +++
>  gdbsupport/create-version.sh | 90 ++++++++++++++++++++++++++++++++++++++++++++
>  gdbsupport/remote-repository |  2 +
>  7 files changed, 109 insertions(+), 2 deletions(-)
>  create mode 100644 gdbsupport/remote-repository
>
> diff --git a/gdb/Makefile.in b/gdb/Makefile.in
> index 0c331af4bff..9b5ad1ea176 100644
> --- a/gdb/Makefile.in
> +++ b/gdb/Makefile.in
> @@ -2068,7 +2068,7 @@ $(srcdir)/copying.c: @MAINTAINER_MODE_TRUE@ $(srcdir)/../COPYING3 $(srcdir)/copy
>  version.c: stamp-version; @true
>  # Note that the obvious names for the temp file are taken by
>  # create-version.sh.
> -stamp-version: Makefile version.in $(srcdir)/../bfd/version.h $(srcdir)/../gdbsupport/create-version.sh
> +stamp-version: Makefile version.in $(srcdir)/../bfd/version.h $(srcdir)/../gdbsupport/create-version.sh $(srcdir)/../gdbsupport/remote-repository
>   $(ECHO_GEN) $(SHELL) $(srcdir)/../gdbsupport/create-version.sh $(srcdir) \
>      $(host_alias) $(target_alias) version-t.t
>   @$(SHELL) $(srcdir)/../move-if-change version-t.t version.c
> diff --git a/gdbserver/Makefile.in b/gdbserver/Makefile.in
> index 8c35c169d62..0c67d64b02e 100644
> --- a/gdbserver/Makefile.in
> +++ b/gdbserver/Makefile.in
> @@ -445,7 +445,7 @@ am--refresh:
>  
>  force:
>  
> -version-generated.cc: Makefile $(srcdir)/../gdb/version.in $(srcdir)/../bfd/version.h $(srcdir)/../gdbsupport/create-version.sh
> +version-generated.cc: Makefile $(srcdir)/../gdb/version.in $(srcdir)/../bfd/version.h $(srcdir)/../gdbsupport/create-version.sh $(srcdir)/../gdbsupport/remote-repository
>   $(ECHO_GEN) $(SHELL) $(srcdir)/../gdbsupport/create-version.sh $(srcdir)/../gdb \
>   $(host_alias) $(target_alias) $@
>  
> diff --git a/gdbsupport/create-version.sh b/gdbsupport/create-version.sh
> index 6135d219d94..68c6518615f 100755
> --- a/gdbsupport/create-version.sh
> +++ b/gdbsupport/create-version.sh
> @@ -27,9 +27,99 @@ host_alias="$2"
>  target_alias="$3"
>  output="$4"
>  
> +GIT_TAG=""
> +if (cd "$srcdir" && git rev-parse --show-toplevel >/dev/null 2>/dev/null); then
> +
> +    # The git version string looks something like this:
> +    #
> +    #     137acc6fbd6-72fbdf834da-2-dirty
> +    #     |         | |         | | |   |
> +    #     '---A-----' '-----B---' C '-D-'
> +    #
> +    # Where:
> +    #   A - This is the last git commit sha.  This represents the HEAD of the
> +    #       branch that was built.
> +    #   B - This is the merge base between the current branch and the
> +    #       upstream master branch.
> +    #   C - The number of commits from the merge base to the current sha.
> +    #       This gives an impression of how diverged the branch is.
> +    #   D - Is the current git tree fully committed? If not then it is dirty.
> +    #
> +    # First figure out part A, the short sha for the current head:
> +    short_head_sha=$(cd "$srcdir" && git rev-parse --short HEAD)
> +
> +    # Now figure out part D, the dirty tag.  This might be left as the
> +    # empty string if the repository has no local changes.
> +    dirty_mark=""
> +    (cd "$srcdir" && git update-index -q --refresh)
> +    test -z "$(cd "$srcdir" && git diff-index --name-only HEAD --)" ||
> + dirty_mark="-dirty"
> +
> +    # To calculate parts B and C we need to calculate the merge-base
> +    # between the current branch and a specific remote branch.  The
> +    # local file 'remote-repository' contains the remote repository
> +    # url, and the branch name we are comparing against.  Here we
> +    # extract that information.
> +    remote_repo_pattern=$(grep ^pattern: \
> +       "$srcdir/../gdbsupport/remote-repository" \
> +      | cut -d: -f2-)
> +    remote_repo_branch=$(grep ^branch: \
> +      "$srcdir/../gdbsupport/remote-repository" \
> +     | cut -d: -f2-)
> +
> +    # Use the remote url pattern from the remote-repository file to
> +    # find the local name for the remote git repository.
> +    remote_name=$( (cd "$srcdir" && git remote -v) \
> + | grep "${remote_repo_pattern}" | grep \(fetch\) \
> + | awk -F '\t' '{print $1}')
> +    branch_info=""
> +    if [ -n "${remote_name}" ]; then
> + # We found the local name for the remote repository, we can
> + # now go ahead and figure out parts B and C of the version
> + # string.
> + remote_branch="${remote_name}/${remote_repo_branch}"
> + # Check to see if the remote branch contains the current HEAD.
> + # If it does then the user is building directly from (their
> + # checkout of) the upstream branch.
> + if ! (cd "$srcdir"  && git merge-base \
> +   --is-ancestor "${short_head_sha}" \
> +   "${remote_branch}"); then
> +    # The current head sha is not on the remote tracking
> +    # branch.  We need to figure out the merge base, and the
> +    # distance from that merge base.
> +    merge_base_sha=$(cd "$srcdir" && git merge-base "${short_head_sha}" \
> +       "${remote_branch}")
> +    short_merge_base_sha=$(cd "$srcdir" \
> +       && git rev-parse \
> +      --short "${merge_base_sha}")
> +
> +    # Count the commits between the merge base and current head.
> +    commit_count=$(cd "$srcdir" \
> +       && git rev-list --count "${merge_base_sha}"..HEAD)
> +
> +    # Now format the parts B and C of the git version string.
> +    branch_info="-${short_merge_base_sha}-${commit_count}"
> + else
> +    # The user is building from a commit on the upstream
> +    # branch.  There's no need to include parts B and C of the
> +    # git version string.
> +    branch_info=""
> + fi
> +    else
> + # We couldn't find the local name for the remote repository.
> + # Maybe this user has cloned from some other remote, or has
> + # deleted their remotes.
> + branch_info="-unknown"
> +    fi
> +    GIT_TAG="${short_head_sha}${branch_info}${dirty_mark}"
> +fi
> +
>  rm -f version.c-tmp "$output" version.tmp
>  date=$(sed -n -e 's/^.* BFD_VERSION_DATE \(.*\)$/\1/p' "$srcdir/../bfd/version.h")
>  sed -e "s/DATE/$date/" < "$srcdir/version.in" > version.tmp
> +if [ -n "$GIT_TAG" ]; then
> +    echo " ($GIT_TAG)" >> version.tmp
> +fi
>  {
>      echo '#include "gdbsupport/version.h"'
>      echo 'const char version[] = "'"$(sed q version.tmp)"'";'
> diff --git a/gdbsupport/remote-repository b/gdbsupport/remote-repository
> new file mode 100644
> index 00000000000..c05f3163e81
> --- /dev/null
> +++ b/gdbsupport/remote-repository
> @@ -0,0 +1,2 @@
> +pattern:sourceware.org/git/binutils-gdb.git
> +branch:master
> --
> 2.14.5

--
Joel
Reply | Threaded
Open this post in threaded view
|

Re: [PATCH 2/2] Add git sha information to the gdb version string

Joel Brobecker
> What do you guys think of adding a configure option to pass a "git-tag",
> for instance, which, when passed, would use that instead of trying
> to calculate it on the fly?

Other ideas (brainstorming): Look for a file in the source which,
if present, would either:
  - Be executed as a script; or
  - Just contain the ID we want to add.

These might be easier to implement, and could also integrate well
the creation of source packages that don't have the .git metadata...

--
Joel