[libcamera-devel,v2,2/5] libcamera: Auto generate version information

Message ID 20190704130347.9372-7-kieran.bingham@ideasonboard.com
State Accepted
Headers show
Series
  • Untitled series #403
Related show

Commit Message

Kieran Bingham July 4, 2019, 1:03 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-versin-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+c544

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
---
 Documentation/conf.py            |  7 ++----
 Documentation/meson.build        |  6 ++++--
 include/libcamera/meson.build    |  5 +++++
 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, 82 insertions(+), 13 deletions(-)
 create mode 100644 include/libcamera/version.h.in
 create mode 100755 utils/gen-version.sh

Comments

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

Thank you for the patch.

On Thu, Jul 04, 2019 at 02:03:44PM +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-versin-gen. The gen-version.sh script

s/versin/version/

> 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+c544

The script now uses 8 characters by default for the abbreviated SHA1.
> 
> 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
> ---
>  Documentation/conf.py            |  7 ++----
>  Documentation/meson.build        |  6 ++++--
>  include/libcamera/meson.build    |  5 +++++
>  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, 82 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..3ac61a208145 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
> +# configuration_data (cdata) in Documentation/meson.build

"through the sphinx command line" ? configuration_data() is an internal
meson concept.

>  
>  # -- General configuration ---------------------------------------------------
>  
> diff --git a/Documentation/meson.build b/Documentation/meson.build
> index 629e853120cb..ea7db4eaeab0 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,10 @@ 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@'],

Time to split this on multiple lines ? :-)

>                    input : docs_sources,
>                    output : 'html',
>                    build_by_default : true,
> diff --git a/include/libcamera/meson.build b/include/libcamera/meson.build
> index 3067120a1598..69823dd1da63 100644
> --- a/include/libcamera/meson.build
> +++ b/include/libcamera/meson.build
> @@ -18,6 +18,11 @@ libcamera_api = files([
>  
>  gen_header = files('gen-header.sh')
>  
> +version_h = vcs_tag(command: ['../../utils/gen-version.sh', meson.current_source_dir()],

Maybe join_paths(meson.source_root(), 'utils', 'gen-version.sh') ?

> +                    input: 'version.h.in',
> +                    output: 'version.h',
> +                    fallback: 'v0.0')

s/:/ :/ in all the lines above.

> +
>  libcamera_h = custom_target('gen-header',
>                              input : 'meson.build',
>                              output : 'libcamera.h',
> 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(),

I don't think we should run the script here. This value becomes
accessible in meson.project_version(), which is the default fallback for
the vcs_tag() function, and should be used when no version control is
available (for instance in the case of release tarballs). Here what I
propose doing instead:

- In this file:

libcamera_version = run_command('utils/gen-version.sh',
                                '@0@'.format(meson.source_root()),
				check : true).stdout().strip()
if libcamera_version == ''
    libcamera_version = 'v0.0'
endif

project(
    ...
    version : libcamera_version,
    ...
)

- In include/libcamera/meson.build:

version_h = vcs_tag(command : ['echo', libcamera_version],
                    input: 'version.h.in',
                    output: 'version.h')

That we we only run the script once, and have a canonical location for
the tarball release version in the root meson.build. What do you think ?

>      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..5ced4ad76ba0 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/\.//

> + */
> +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
> +

If you can exit here when the tree isn't under git control then we'll be
ready for tarball releases.

> +# 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"
Kieran Bingham July 4, 2019, 2:12 p.m. UTC | #2
Hi Laurent,

On 04/07/2019 14:40, Laurent Pinchart wrote:
> Hi Kieran,
> 
> Thank you for the patch.
> 
> On Thu, Jul 04, 2019 at 02:03:44PM +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-versin-gen. The gen-version.sh script
> 
> s/versin/version/

Fixed,

> 
>> 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+c544
> 
> The script now uses 8 characters by default for the abbreviated SHA1.

I'll update.

>>
>> 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
>> ---
>>  Documentation/conf.py            |  7 ++----
>>  Documentation/meson.build        |  6 ++++--
>>  include/libcamera/meson.build    |  5 +++++
>>  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, 82 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..3ac61a208145 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
>> +# configuration_data (cdata) in Documentation/meson.build
> 
> "through the sphinx command line" ? configuration_data() is an internal
> meson concept.

Also - that's how the Doxygen version information is passed, not the
sphinx...

Changed,

> 
>>  
>>  # -- General configuration ---------------------------------------------------
>>  
>> diff --git a/Documentation/meson.build b/Documentation/meson.build
>> index 629e853120cb..ea7db4eaeab0 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,10 @@ 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@'],
> 
> Time to split this on multiple lines ? :-)

Wrapped,

The doc_install_dir at the top of this file is also long, which is the
precedent I followed for not wrapping this.

Additional patch wrapping that line added to this series.


> 
>>                    input : docs_sources,
>>                    output : 'html',
>>                    build_by_default : true,
>> diff --git a/include/libcamera/meson.build b/include/libcamera/meson.build
>> index 3067120a1598..69823dd1da63 100644
>> --- a/include/libcamera/meson.build
>> +++ b/include/libcamera/meson.build
>> @@ -18,6 +18,11 @@ libcamera_api = files([
>>  
>>  gen_header = files('gen-header.sh')
>>  
>> +version_h = vcs_tag(command: ['../../utils/gen-version.sh', meson.current_source_dir()],
> 
> Maybe join_paths(meson.source_root(), 'utils', 'gen-version.sh') ?

Yes. I had been trying to use files() - but vcs_tag() does not support
it, because it generates a list...

The join_paths is better than hardcoding the ../../ though.


> 
>> +                    input: 'version.h.in',
>> +                    output: 'version.h',
>> +                    fallback: 'v0.0')
> 
> s/:/ :/ in all the lines above.

Updated.

> 
>> +
>>  libcamera_h = custom_target('gen-header',
>>                              input : 'meson.build',
>>                              output : 'libcamera.h',
>> 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(),
> 
> I don't think we should run the script here. This value becomes
> accessible in meson.project_version(), which is the default fallback for
> the vcs_tag() function, and should be used when no version control is

I override the vcs_tag fallback through the fallback parameter to v0.0.


> available (for instance in the case of release tarballs). Here what I
> propose doing instead:

In the case of release tarballs, the script should be updated to return
that.

And meson should create a release version file on dist/install. But
that's for another patch series, as it's tough enough to get this part
in first :)



> - In this file:
> 
> libcamera_version = run_command('utils/gen-version.sh',
>                                 '@0@'.format(meson.source_root()),
> 				check : true).stdout().strip()
> if libcamera_version == ''
>     libcamera_version = 'v0.0'
> endif
> 
> project(
>     ...
>     version : libcamera_version,
>     ...
> )

You can't do that - I've tried before. (And I've just retried)

ERROR: First statement must be a call to project



> - In include/libcamera/meson.build:
> 
> version_h = vcs_tag(command : ['echo', libcamera_version],
>                     input: 'version.h.in',
>                     output: 'version.h')


And that would not run the vcs command on every build... which is the
purpose of the vcs_tag.



> That we we only run the script once, and have a canonical location for
> the tarball release version in the root meson.build. What do you think ?


See above.


> 
>>      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..5ced4ad76ba0 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/\.//

Removed.

> 
>> + */
>> +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
>> +
> 
> If you can exit here when the tree isn't under git control then we'll be
> ready for tarball releases.


No, I think it will be up to this script to return the tarball release
version.

That's currently unimplemented and can be built on top.

It will also need hooks adding into meson as a dist rule or such.



>> +# 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"
>
Laurent Pinchart July 4, 2019, 7:52 p.m. UTC | #3
Hi Kieran,

On Thu, Jul 04, 2019 at 03:12:10PM +0100, Kieran Bingham wrote:
> On 04/07/2019 14:40, Laurent Pinchart wrote:
> > On Thu, Jul 04, 2019 at 02:03:44PM +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-versin-gen. The gen-version.sh script
> > 
> > s/versin/version/
> 
> Fixed,
> 
> >> 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+c544
> > 
> > The script now uses 8 characters by default for the abbreviated SHA1.
> 
> I'll update.
> 
> >> 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
> >> ---
> >>  Documentation/conf.py            |  7 ++----
> >>  Documentation/meson.build        |  6 ++++--
> >>  include/libcamera/meson.build    |  5 +++++
> >>  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, 82 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..3ac61a208145 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
> >> +# configuration_data (cdata) in Documentation/meson.build
> > 
> > "through the sphinx command line" ? configuration_data() is an internal
> > meson concept.
> 
> Also - that's how the Doxygen version information is passed, not the
> sphinx...

Is it ? conf.py is for sphinx, for doxygen we generate Doxyfile from
Doxyfile.in and put the version there.

> Changed,
> 
> >>  
> >>  # -- General configuration ---------------------------------------------------
> >>  
> >> diff --git a/Documentation/meson.build b/Documentation/meson.build
> >> index 629e853120cb..ea7db4eaeab0 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,10 @@ 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@'],
> > 
> > Time to split this on multiple lines ? :-)
> 
> Wrapped,
> 
> The doc_install_dir at the top of this file is also long, which is the
> precedent I followed for not wrapping this.
> 
> Additional patch wrapping that line added to this series.
> 
> >>                    input : docs_sources,
> >>                    output : 'html',
> >>                    build_by_default : true,
> >> diff --git a/include/libcamera/meson.build b/include/libcamera/meson.build
> >> index 3067120a1598..69823dd1da63 100644
> >> --- a/include/libcamera/meson.build
> >> +++ b/include/libcamera/meson.build
> >> @@ -18,6 +18,11 @@ libcamera_api = files([
> >>  
> >>  gen_header = files('gen-header.sh')
> >>  
> >> +version_h = vcs_tag(command: ['../../utils/gen-version.sh', meson.current_source_dir()],
> > 
> > Maybe join_paths(meson.source_root(), 'utils', 'gen-version.sh') ?
> 
> Yes. I had been trying to use files() - but vcs_tag() does not support
> it, because it generates a list...
> 
> The join_paths is better than hardcoding the ../../ though.
> 
> >> +                    input: 'version.h.in',
> >> +                    output: 'version.h',
> >> +                    fallback: 'v0.0')
> > 
> > s/:/ :/ in all the lines above.
> 
> Updated.
> 
> >> +
> >>  libcamera_h = custom_target('gen-header',
> >>                              input : 'meson.build',
> >>                              output : 'libcamera.h',
> >> 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(),
> > 
> > I don't think we should run the script here. This value becomes
> > accessible in meson.project_version(), which is the default fallback for
> > the vcs_tag() function, and should be used when no version control is
> 
> I override the vcs_tag fallback through the fallback parameter to v0.0.

But you don't override version here, so it's not very consistent. I
think we should have version here set to the release version when doing
a release, and use vcs_tag to override that when git is available. As
the project() call has to be first it's not that easy so we could do it
as a second step. I do however want when we'll address that to store the
release version number in the root meson.build and not hide it in
src/libcamera/meson.build.

> > available (for instance in the case of release tarballs). Here what I
> > propose doing instead:
> 
> In the case of release tarballs, the script should be updated to return
> that.
> 
> And meson should create a release version file on dist/install. But
> that's for another patch series, as it's tough enough to get this part
> in first :)
> 
> > - In this file:
> > 
> > libcamera_version = run_command('utils/gen-version.sh',
> >                                 '@0@'.format(meson.source_root()),
> > 				check : true).stdout().strip()
> > if libcamera_version == ''
> >     libcamera_version = 'v0.0'
> > endif
> > 
> > project(
> >     ...
> >     version : libcamera_version,
> >     ...
> > )
> 
> You can't do that - I've tried before. (And I've just retried)
> 
> ERROR: First statement must be a call to project

Oh :-(

> > - In include/libcamera/meson.build:
> > 
> > version_h = vcs_tag(command : ['echo', libcamera_version],
> >                     input: 'version.h.in',
> >                     output: 'version.h')
> 
> And that would not run the vcs command on every build... which is the
> purpose of the vcs_tag.

You're right.

> > That we we only run the script once, and have a canonical location for
> > the tarball release version in the root meson.build. What do you think ?
> 
> See above.

I'll try to think about a better option :-)

> >>      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..5ced4ad76ba0 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/\.//
> 
> Removed.
> 
> >> + */
> >> +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
> >> +
> > 
> > If you can exit here when the tree isn't under git control then we'll be
> > ready for tarball releases.
> 
> No, I think it will be up to this script to return the tarball release
> version.

I don't agree. I think the script should focus on extracting the version
from git. When making releases the version number should be in the main
meson.build.

> That's currently unimplemented and can be built on top.
> 
> It will also need hooks adding into meson as a dist rule or such.
> 
> >> +# 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"
Kieran Bingham July 4, 2019, 8:44 p.m. UTC | #4
Hi Laurent,

On 04/07/2019 20:52, Laurent Pinchart wrote:
> Hi Kieran,
> 
> On Thu, Jul 04, 2019 at 03:12:10PM +0100, Kieran Bingham wrote:
>> On 04/07/2019 14:40, Laurent Pinchart wrote:
>>> On Thu, Jul 04, 2019 at 02:03:44PM +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-versin-gen. The gen-version.sh script
>>>
>>> s/versin/version/
>>
>> Fixed,
>>
>>>> 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+c544
>>>
>>> The script now uses 8 characters by default for the abbreviated SHA1.
>>
>> I'll update.
>>
>>>> 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
>>>> ---
>>>>  Documentation/conf.py            |  7 ++----
>>>>  Documentation/meson.build        |  6 ++++--
>>>>  include/libcamera/meson.build    |  5 +++++
>>>>  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, 82 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..3ac61a208145 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
>>>> +# configuration_data (cdata) in Documentation/meson.build
>>>
>>> "through the sphinx command line" ? configuration_data() is an internal
>>> meson concept.
>>
>> Also - that's how the Doxygen version information is passed, not the
>> sphinx...
> 
> Is it ? conf.py is for sphinx, for doxygen we generate Doxyfile from
> Doxyfile.in and put the version there.

*That's precisely my point*. I was stating that I had got it wrong.

See:
https://git.linuxtv.org/libcamera.git/tree/Documentation/meson.build#n10

The configuration_data() that I was referring to in this superseded
patch updates the Doxyfile.in to create the Doxyfile, so referring to
the cdata in conf.py is wrong.

This was already changed for the recent posting.


>> Changed,
>>
>>>>  
>>>>  # -- General configuration ---------------------------------------------------
>>>>  
>>>> diff --git a/Documentation/meson.build b/Documentation/meson.build
>>>> index 629e853120cb..ea7db4eaeab0 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,10 @@ 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@'],
>>>
>>> Time to split this on multiple lines ? :-)
>>
>> Wrapped,
>>
>> The doc_install_dir at the top of this file is also long, which is the
>> precedent I followed for not wrapping this.
>>
>> Additional patch wrapping that line added to this series.
>>
>>>>                    input : docs_sources,
>>>>                    output : 'html',
>>>>                    build_by_default : true,
>>>> diff --git a/include/libcamera/meson.build b/include/libcamera/meson.build
>>>> index 3067120a1598..69823dd1da63 100644
>>>> --- a/include/libcamera/meson.build
>>>> +++ b/include/libcamera/meson.build
>>>> @@ -18,6 +18,11 @@ libcamera_api = files([
>>>>  
>>>>  gen_header = files('gen-header.sh')
>>>>  
>>>> +version_h = vcs_tag(command: ['../../utils/gen-version.sh', meson.current_source_dir()],
>>>
>>> Maybe join_paths(meson.source_root(), 'utils', 'gen-version.sh') ?
>>
>> Yes. I had been trying to use files() - but vcs_tag() does not support
>> it, because it generates a list...
>>
>> The join_paths is better than hardcoding the ../../ though.
>>
>>>> +                    input: 'version.h.in',
>>>> +                    output: 'version.h',
>>>> +                    fallback: 'v0.0')
>>>
>>> s/:/ :/ in all the lines above.
>>
>> Updated.
>>
>>>> +
>>>>  libcamera_h = custom_target('gen-header',
>>>>                              input : 'meson.build',
>>>>                              output : 'libcamera.h',
>>>> 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(),
>>>
>>> I don't think we should run the script here. This value becomes
>>> accessible in meson.project_version(), which is the default fallback for
>>> the vcs_tag() function, and should be used when no version control is
>>
>> I override the vcs_tag fallback through the fallback parameter to v0.0.
> 
> But you don't override version here, so it's not very consistent. I


It's not possible to provide a fallback here, so the solution should be
to handle it in utils/gen-version.sh.

It's trivial to handle this in the script, and painful to handle it in
meson.

The script is called 'gen-version.sh' so I think it's very reasonable
for that script to do whatever it needs to generate a version, be it
reading a '.tarball_release' version file, or detecting if the sources
are controlled by git.

It can then handle the fallback appropriately.

The meson.project_version is only parsed at project configuration time,
where as the vcs_tag() call runs on every build.

Yes, it's a pain, but that's what meson gives us currently.


> think we should have version here set to the release version when doing
> a release, and use vcs_tag to override that when git is available. As
> the project() call has to be first it's not that easy so we could do it
> as a second step. I do however want when we'll address that to store the
> release version number in the root meson.build and not hide it in
> src/libcamera/meson.build.


I could not get vcs_tag to generate files anywhere except the directory
the meson.build is located, which is why the version.h was in the root
initially.

You asked for the version.h to be generated at include/libcamera/ hence
it's here ...



>>> available (for instance in the case of release tarballs). Here what I
>>> propose doing instead:
>>
>> In the case of release tarballs, the script should be updated to return
>> that.
>>
>> And meson should create a release version file on dist/install. But
>> that's for another patch series, as it's tough enough to get this part
>> in first :)
>>
>>> - In this file:
>>>
>>> libcamera_version = run_command('utils/gen-version.sh',
>>>                                 '@0@'.format(meson.source_root()),
>>> 				check : true).stdout().strip()
>>> if libcamera_version == ''
>>>     libcamera_version = 'v0.0'
>>> endif
>>>
>>> project(
>>>     ...
>>>     version : libcamera_version,
>>>     ...
>>> )
>>
>> You can't do that - I've tried before. (And I've just retried)
>>
>> ERROR: First statement must be a call to project
> 
> Oh :-(
> 
>>> - In include/libcamera/meson.build:
>>>
>>> version_h = vcs_tag(command : ['echo', libcamera_version],
>>>                     input: 'version.h.in',
>>>                     output: 'version.h')
>>
>> And that would not run the vcs command on every build... which is the
>> purpose of the vcs_tag.
> 
> You're right.
> 
>>> That we we only run the script once, and have a canonical location for
>>> the tarball release version in the root meson.build. What do you think ?
>>
>> See above.
> 
> I'll try to think about a better option :-)

Can we get this in, in some form, in the meantime at least?

You're welcome to apply patches on top :-D


>>>>      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..5ced4ad76ba0 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/\.//
>>
>> Removed.
>>
>>>> + */
>>>> +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
>>>> +
>>>
>>> If you can exit here when the tree isn't under git control then we'll be
>>> ready for tarball releases.
>>
>> No, I think it will be up to this script to return the tarball release
>> version.
> 
> I don't agree. I think the script should focus on extracting the version
> from git. When making releases the version number should be in the main
> meson.build.

I'm not sure if you're saying you want to edit the meson.build and
update a number, in which case:

Tags. Tags tags tags.

To create a release, create a signed tag. The script makes the version
based on the tag. 'ninja dist' shall then create a .tarball_release file
based on that so that a release tarball is created from that tag version.

All that should then be handled via automated jobs creating the tarballs
accordingly.


Or, if you're disagreeing about the version script reading a version
from a tarball_release file:


http://git.savannah.gnu.org/gitweb/?p=autoconf.git;a=blob;f=build-aux/git-version-gen;
takes a parameter to point to the '.tarball-version'. And in that event
uses that.

I would happily just drop utils/gen-version.sh and use the
git-version-gen from autoconf which is used in many other open source
project, but it's GPLv3 so I don't know how that complicates things, and
having our own gives us some more control and a simpler script anyway.



>> That's currently unimplemented and can be built on top.
>>
>> It will also need hooks adding into meson as a dist rule or such.
>>
>>>> +# 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..3ac61a208145 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
+# configuration_data (cdata) in Documentation/meson.build
 
 # -- General configuration ---------------------------------------------------
 
diff --git a/Documentation/meson.build b/Documentation/meson.build
index 629e853120cb..ea7db4eaeab0 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,10 @@  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..69823dd1da63 100644
--- a/include/libcamera/meson.build
+++ b/include/libcamera/meson.build
@@ -18,6 +18,11 @@  libcamera_api = files([
 
 gen_header = files('gen-header.sh')
 
+version_h = vcs_tag(command: ['../../utils/gen-version.sh', meson.current_source_dir()],
+                    input: 'version.h.in',
+                    output: 'version.h',
+                    fallback: 'v0.0')
+
 libcamera_h = custom_target('gen-header',
                             input : 'meson.build',
                             output : 'libcamera.h',
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..5ced4ad76ba0 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"