[libcamera-devel,v4,2/6] libcamera: Auto generate version information

Message ID 20190704145942.17879-3-kieran.bingham@ideasonboard.com
State Accepted
Headers show
Series
  • Automatic Version Generation ++
Related show

Commit Message

Kieran Bingham July 4, 2019, 2:59 p.m. UTC
Generate a version string, and provide a global singleton object which
allows applications to interrogate the current libcamera version
information.

The version header is automatically updated by meson on each build.
The string roughly follows the semver [0] conventions of
major.minor.patch-label as a value.

[0] https://semver.org/

A script (utils/gen-version.sh) is provided which is modelled upon the
processing from autoconf's git-version-gen. The gen-version.sh script
will look for tags in the form vX.Y as starting points for the version
string. While the repository does not have any matching tags, v0.0 will
be assumed, resulting in versions with both major and minor being set to
'0', and the patch count resulting from the number of patches in the
history to that point.

Finally, a uniquely identifying shortened hash is provided from git:

	v0.0.509+0ec0edf7

Signed-off-by: Kieran Bingham <kieran.bingham@ideasonboard.com>

---
v2:
  - Store VCS_Tag return reference for dependancy linking
  - Fix indentation on meson.build
  - fix shell usage and shellcheck warnings in version-gen
  - Make LibcameraVersion version global
  - Sphinx version now explicit as to it's source from
    Documentation/meson.build
  - Pass project_version() through api_version
  - Use Camera object to report version rather than global constructor.

v3:
 - Add dependency to the vcs tag to ensure libcamera builds the header
 - Fix up commit title
 - Rename version-gen to gen-version.sh
 - Append git sha and any -dirty flag with a '+' separator
 - Move version generation to single libcamera/version.h file.
 - Remove version.cpp and store the const std::string version in
   camera_manager.cpp

v4:
 - Fix commit message
 - Use path_join() to reference gen-version.sh
 - change Docuementation/conf.py comment
 - trivial fixups.
---
 Documentation/conf.py            |  7 ++----
 Documentation/meson.build        |  7 ++++--
 include/libcamera/meson.build    |  7 ++++++
 include/libcamera/version.h.in   | 22 +++++++++++++++++++
 meson.build                      |  9 +++-----
 src/libcamera/camera_manager.cpp |  8 +++++++
 src/libcamera/meson.build        |  1 +
 utils/gen-version.sh             | 37 ++++++++++++++++++++++++++++++++
 8 files changed, 85 insertions(+), 13 deletions(-)
 create mode 100644 include/libcamera/version.h.in
 create mode 100755 utils/gen-version.sh

Comments

Laurent Pinchart July 4, 2019, 8:58 p.m. UTC | #1
Hi Kieran,

Thank you for the patch.

On Thu, Jul 04, 2019 at 03:59:38PM +0100, Kieran Bingham wrote:
> Generate a version string, and provide a global singleton object which
> allows applications to interrogate the current libcamera version
> information.
> 
> The version header is automatically updated by meson on each build.
> The string roughly follows the semver [0] conventions of
> major.minor.patch-label as a value.
> 
> [0] https://semver.org/
> 
> A script (utils/gen-version.sh) is provided which is modelled upon the
> processing from autoconf's git-version-gen. The gen-version.sh script
> will look for tags in the form vX.Y as starting points for the version
> string. While the repository does not have any matching tags, v0.0 will
> be assumed, resulting in versions with both major and minor being set to
> '0', and the patch count resulting from the number of patches in the
> history to that point.
> 
> Finally, a uniquely identifying shortened hash is provided from git:
> 
> 	v0.0.509+0ec0edf7
> 
> Signed-off-by: Kieran Bingham <kieran.bingham@ideasonboard.com>
> 
> ---
> v2:
>   - Store VCS_Tag return reference for dependancy linking
>   - Fix indentation on meson.build
>   - fix shell usage and shellcheck warnings in version-gen
>   - Make LibcameraVersion version global
>   - Sphinx version now explicit as to it's source from
>     Documentation/meson.build
>   - Pass project_version() through api_version
>   - Use Camera object to report version rather than global constructor.
> 
> v3:
>  - Add dependency to the vcs tag to ensure libcamera builds the header
>  - Fix up commit title
>  - Rename version-gen to gen-version.sh
>  - Append git sha and any -dirty flag with a '+' separator
>  - Move version generation to single libcamera/version.h file.
>  - Remove version.cpp and store the const std::string version in
>    camera_manager.cpp
> 
> v4:
>  - Fix commit message
>  - Use path_join() to reference gen-version.sh
>  - change Docuementation/conf.py comment
>  - trivial fixups.
> ---
>  Documentation/conf.py            |  7 ++----
>  Documentation/meson.build        |  7 ++++--
>  include/libcamera/meson.build    |  7 ++++++
>  include/libcamera/version.h.in   | 22 +++++++++++++++++++
>  meson.build                      |  9 +++-----
>  src/libcamera/camera_manager.cpp |  8 +++++++
>  src/libcamera/meson.build        |  1 +
>  utils/gen-version.sh             | 37 ++++++++++++++++++++++++++++++++
>  8 files changed, 85 insertions(+), 13 deletions(-)
>  create mode 100644 include/libcamera/version.h.in
>  create mode 100755 utils/gen-version.sh
> 
> diff --git a/Documentation/conf.py b/Documentation/conf.py
> index 970edf3d7298..bffd1d8f1e5d 100644
> --- a/Documentation/conf.py
> +++ b/Documentation/conf.py
> @@ -23,11 +23,8 @@ project = 'libcamera'
>  copyright = '2018-2019, The libcamera documentation authors'
>  author = u'Kieran Bingham, Jacopo Mondi, Laurent Pinchart, Niklas Söderlund'
>  
> -# The short X.Y version
> -version = ''
> -# The full version, including alpha/beta/rc tags
> -release = '0.1'
> -
> +# Version information is provided by the build environment, through the
> +# sphinx command line.
>  
>  # -- General configuration ---------------------------------------------------
>  
> diff --git a/Documentation/meson.build b/Documentation/meson.build
> index 629e853120cb..2db80b39989b 100644
> --- a/Documentation/meson.build
> +++ b/Documentation/meson.build
> @@ -1,4 +1,4 @@
> -doc_install_dir = join_paths(get_option('datadir'), 'doc', 'libcamera-@0@'.format(api_version))
> +doc_install_dir = join_paths(get_option('datadir'), 'doc', 'libcamera-@0@'.format(meson.project_version()))
>  
>  #
>  # Doxygen
> @@ -47,8 +47,11 @@ if sphinx.found()
>          'index.rst',
>      ]
>  
> +    release = 'release=' + meson.project_version()
> +
>      custom_target('documentation',
> -                  command : [sphinx, '-q', '-W', '-b', 'html', meson.current_source_dir(), '@OUTPUT@'],
> +                  command : [sphinx, '-D', release, '-q', '-W', '-b', 'html',
> +                             meson.current_source_dir(), '@OUTPUT@'],
>                    input : docs_sources,
>                    output : 'html',
>                    build_by_default : true,
> diff --git a/include/libcamera/meson.build b/include/libcamera/meson.build
> index 3067120a1598..6f81f1117318 100644
> --- a/include/libcamera/meson.build
> +++ b/include/libcamera/meson.build
> @@ -16,6 +16,13 @@ libcamera_api = files([
>      'timer.h',
>  ])
>  
> +gen_version = join_paths(meson.source_root(), 'utils', 'gen-version.sh')
> +
> +version_h = vcs_tag(command : [gen_version, meson.current_source_dir()],
> +                    input : 'version.h.in',
> +                    output : 'version.h',
> +                    fallback : 'v0.0')
> +
>  gen_header = files('gen-header.sh')
>  
>  libcamera_h = custom_target('gen-header',
> diff --git a/include/libcamera/version.h.in b/include/libcamera/version.h.in
> new file mode 100644
> index 000000000000..e49b36962aed
> --- /dev/null
> +++ b/include/libcamera/version.h.in
> @@ -0,0 +1,22 @@
> +/* SPDX-License-Identifier: LGPL-2.1-or-later */
> +/*
> + * Copyright (C) 2019, Google Inc.
> + *
> + * version.h - Library version information
> + *
> + * This file is auto-generated. Do not edit.
> + */
> +#ifndef __LIBCAMERA_VERSION_H__
> +#define __LIBCAMERA_VERSION_H__
> +
> +#include <string>
> +
> +#define LIBCAMERA_VERSION "@VCS_TAG@"
> +
> +namespace libcamera {
> +
> +extern const std::string version;
> +
> +} /* namespace libcamera */
> +
> +#endif /* __LIBCAMERA_VERSION_H__ */
> diff --git a/meson.build b/meson.build
> index a3b0bc820072..342b3cc76a93 100644
> --- a/meson.build
> +++ b/meson.build
> @@ -1,6 +1,8 @@
>  project('libcamera', 'c', 'cpp',
>      meson_version : '>= 0.40',
> -    version : '0.1',
> +    version : run_command('utils/gen-version.sh',
> +                          '@0@'.format(meson.source_root()),
> +                          check : true).stdout().strip(),
>      default_options : [
>          'werror=true',
>          'warning_level=2',
> @@ -8,11 +10,6 @@ project('libcamera', 'c', 'cpp',
>      ],
>      license : 'LGPL 2.1+')
>  
> -# TODO: Extract this from project.version.
> -#       Ideally the version at Documentation/conf.py should be
> -#       generated from this too.
> -api_version = '0.1'
> -
>  cc = meson.get_compiler('c')
>  config_h = configuration_data()
>  
> diff --git a/src/libcamera/camera_manager.cpp b/src/libcamera/camera_manager.cpp
> index cf881ce2e641..2df24d44e284 100644
> --- a/src/libcamera/camera_manager.cpp
> +++ b/src/libcamera/camera_manager.cpp
> @@ -9,6 +9,7 @@
>  
>  #include <libcamera/camera.h>
>  #include <libcamera/event_dispatcher.h>
> +#include <libcamera/version.h>
>  
>  #include "device_enumerator.h"
>  #include "event_dispatcher_poll.h"
> @@ -64,6 +65,11 @@ CameraManager::~CameraManager()
>  {
>  }
>  
> +/**
> + * \brief Declare the library global version string

s/Declare the/The/

> + */
> +const std::string version(LIBCAMERA_VERSION);
> +

I would move this above the CameraManager class definition, not put it
in the middle.

With these small issues addressed,

Reviewed-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>

There are however multiple strategies to handle version information, and
I think we should discuss them, but that's not a reason to delay this
series.

>  /**
>   * \brief Start the camera manager
>   *
> @@ -79,6 +85,8 @@ int CameraManager::start()
>  	if (enumerator_)
>  		return -EBUSY;
>  
> +	LOG(Camera, Info) << "libcamera " << version;
> +
>  	enumerator_ = DeviceEnumerator::create();
>  	if (!enumerator_ || enumerator_->enumerate())
>  		return -ENODEV;
> diff --git a/src/libcamera/meson.build b/src/libcamera/meson.build
> index 8075b1f696f5..336f4f066fac 100644
> --- a/src/libcamera/meson.build
> +++ b/src/libcamera/meson.build
> @@ -80,6 +80,7 @@ control_types_cpp = custom_target('control_types_cpp',
>  libcamera_sources += control_types_cpp
>  
>  libcamera_deps = [
> +    declare_dependency(sources : version_h),
>      cc.find_library('dl'),
>      libudev,
>  ]
> diff --git a/utils/gen-version.sh b/utils/gen-version.sh
> new file mode 100755
> index 000000000000..b3003d7a80d3
> --- /dev/null
> +++ b/utils/gen-version.sh
> @@ -0,0 +1,37 @@
> +#!/bin/sh
> +
> +# SPDX-License-Identifier: GPL-2.0-or-later
> +# Generate a version string using git describe
> +
> +if [ -n "$1" ]
> +then
> +	cd "$1" 2>/dev/null || exit 1
> +fi
> +
> +# Get a short description from the tree.
> +version=$(git describe --abbrev=8 --match "v[0-9]*" 2>/dev/null)
> +
> +if [ -z "$version" ]
> +then
> +	# Handle an un-tagged repository
> +	sha=$(git describe --abbrev=8 --always 2>/dev/null)
> +	commits=$(git log --oneline | wc -l 2>/dev/null)
> +	version=v0.0.$commits.$sha
> +fi
> +
> +# Prevent changed timestamps causing -dirty labels
> +git update-index --refresh > /dev/null 2>&1
> +dirty=$(git diff-index --name-only HEAD 2>/dev/null) || dirty=
> +
> +# Strip the 'g', and replace the preceeding '-' with a '+' to denote a label
> +version=$(echo "$version" | sed -e 's/-g/+/g')
> +
> +# Fix the '-' (the patch count) to a '.' as a version increment.
> +version=$(echo "$version" | sed -e 's/-/./g')
> +
> +if [ -n "$dirty" ]
> +then
> +	version=$version-dirty
> +fi
> +
> +echo "$version"

Patch

diff --git a/Documentation/conf.py b/Documentation/conf.py
index 970edf3d7298..bffd1d8f1e5d 100644
--- a/Documentation/conf.py
+++ b/Documentation/conf.py
@@ -23,11 +23,8 @@  project = 'libcamera'
 copyright = '2018-2019, The libcamera documentation authors'
 author = u'Kieran Bingham, Jacopo Mondi, Laurent Pinchart, Niklas Söderlund'
 
-# The short X.Y version
-version = ''
-# The full version, including alpha/beta/rc tags
-release = '0.1'
-
+# Version information is provided by the build environment, through the
+# sphinx command line.
 
 # -- General configuration ---------------------------------------------------
 
diff --git a/Documentation/meson.build b/Documentation/meson.build
index 629e853120cb..2db80b39989b 100644
--- a/Documentation/meson.build
+++ b/Documentation/meson.build
@@ -1,4 +1,4 @@ 
-doc_install_dir = join_paths(get_option('datadir'), 'doc', 'libcamera-@0@'.format(api_version))
+doc_install_dir = join_paths(get_option('datadir'), 'doc', 'libcamera-@0@'.format(meson.project_version()))
 
 #
 # Doxygen
@@ -47,8 +47,11 @@  if sphinx.found()
         'index.rst',
     ]
 
+    release = 'release=' + meson.project_version()
+
     custom_target('documentation',
-                  command : [sphinx, '-q', '-W', '-b', 'html', meson.current_source_dir(), '@OUTPUT@'],
+                  command : [sphinx, '-D', release, '-q', '-W', '-b', 'html',
+                             meson.current_source_dir(), '@OUTPUT@'],
                   input : docs_sources,
                   output : 'html',
                   build_by_default : true,
diff --git a/include/libcamera/meson.build b/include/libcamera/meson.build
index 3067120a1598..6f81f1117318 100644
--- a/include/libcamera/meson.build
+++ b/include/libcamera/meson.build
@@ -16,6 +16,13 @@  libcamera_api = files([
     'timer.h',
 ])
 
+gen_version = join_paths(meson.source_root(), 'utils', 'gen-version.sh')
+
+version_h = vcs_tag(command : [gen_version, meson.current_source_dir()],
+                    input : 'version.h.in',
+                    output : 'version.h',
+                    fallback : 'v0.0')
+
 gen_header = files('gen-header.sh')
 
 libcamera_h = custom_target('gen-header',
diff --git a/include/libcamera/version.h.in b/include/libcamera/version.h.in
new file mode 100644
index 000000000000..e49b36962aed
--- /dev/null
+++ b/include/libcamera/version.h.in
@@ -0,0 +1,22 @@ 
+/* SPDX-License-Identifier: LGPL-2.1-or-later */
+/*
+ * Copyright (C) 2019, Google Inc.
+ *
+ * version.h - Library version information
+ *
+ * This file is auto-generated. Do not edit.
+ */
+#ifndef __LIBCAMERA_VERSION_H__
+#define __LIBCAMERA_VERSION_H__
+
+#include <string>
+
+#define LIBCAMERA_VERSION "@VCS_TAG@"
+
+namespace libcamera {
+
+extern const std::string version;
+
+} /* namespace libcamera */
+
+#endif /* __LIBCAMERA_VERSION_H__ */
diff --git a/meson.build b/meson.build
index a3b0bc820072..342b3cc76a93 100644
--- a/meson.build
+++ b/meson.build
@@ -1,6 +1,8 @@ 
 project('libcamera', 'c', 'cpp',
     meson_version : '>= 0.40',
-    version : '0.1',
+    version : run_command('utils/gen-version.sh',
+                          '@0@'.format(meson.source_root()),
+                          check : true).stdout().strip(),
     default_options : [
         'werror=true',
         'warning_level=2',
@@ -8,11 +10,6 @@  project('libcamera', 'c', 'cpp',
     ],
     license : 'LGPL 2.1+')
 
-# TODO: Extract this from project.version.
-#       Ideally the version at Documentation/conf.py should be
-#       generated from this too.
-api_version = '0.1'
-
 cc = meson.get_compiler('c')
 config_h = configuration_data()
 
diff --git a/src/libcamera/camera_manager.cpp b/src/libcamera/camera_manager.cpp
index cf881ce2e641..2df24d44e284 100644
--- a/src/libcamera/camera_manager.cpp
+++ b/src/libcamera/camera_manager.cpp
@@ -9,6 +9,7 @@ 
 
 #include <libcamera/camera.h>
 #include <libcamera/event_dispatcher.h>
+#include <libcamera/version.h>
 
 #include "device_enumerator.h"
 #include "event_dispatcher_poll.h"
@@ -64,6 +65,11 @@  CameraManager::~CameraManager()
 {
 }
 
+/**
+ * \brief Declare the library global version string
+ */
+const std::string version(LIBCAMERA_VERSION);
+
 /**
  * \brief Start the camera manager
  *
@@ -79,6 +85,8 @@  int CameraManager::start()
 	if (enumerator_)
 		return -EBUSY;
 
+	LOG(Camera, Info) << "libcamera " << version;
+
 	enumerator_ = DeviceEnumerator::create();
 	if (!enumerator_ || enumerator_->enumerate())
 		return -ENODEV;
diff --git a/src/libcamera/meson.build b/src/libcamera/meson.build
index 8075b1f696f5..336f4f066fac 100644
--- a/src/libcamera/meson.build
+++ b/src/libcamera/meson.build
@@ -80,6 +80,7 @@  control_types_cpp = custom_target('control_types_cpp',
 libcamera_sources += control_types_cpp
 
 libcamera_deps = [
+    declare_dependency(sources : version_h),
     cc.find_library('dl'),
     libudev,
 ]
diff --git a/utils/gen-version.sh b/utils/gen-version.sh
new file mode 100755
index 000000000000..b3003d7a80d3
--- /dev/null
+++ b/utils/gen-version.sh
@@ -0,0 +1,37 @@ 
+#!/bin/sh
+
+# SPDX-License-Identifier: GPL-2.0-or-later
+# Generate a version string using git describe
+
+if [ -n "$1" ]
+then
+	cd "$1" 2>/dev/null || exit 1
+fi
+
+# Get a short description from the tree.
+version=$(git describe --abbrev=8 --match "v[0-9]*" 2>/dev/null)
+
+if [ -z "$version" ]
+then
+	# Handle an un-tagged repository
+	sha=$(git describe --abbrev=8 --always 2>/dev/null)
+	commits=$(git log --oneline | wc -l 2>/dev/null)
+	version=v0.0.$commits.$sha
+fi
+
+# Prevent changed timestamps causing -dirty labels
+git update-index --refresh > /dev/null 2>&1
+dirty=$(git diff-index --name-only HEAD 2>/dev/null) || dirty=
+
+# Strip the 'g', and replace the preceeding '-' with a '+' to denote a label
+version=$(echo "$version" | sed -e 's/-g/+/g')
+
+# Fix the '-' (the patch count) to a '.' as a version increment.
+version=$(echo "$version" | sed -e 's/-/./g')
+
+if [ -n "$dirty" ]
+then
+	version=$version-dirty
+fi
+
+echo "$version"