[libcamera-devel] test: CameraManager: Add start/stop tests
diff mbox series

Message ID 20210727120754.998501-1-kieran.bingham@ideasonboard.com
State New
Delegated to: Kieran Bingham
Headers show
Series
  • [libcamera-devel] test: CameraManager: Add start/stop tests
Related show

Commit Message

Kieran Bingham July 27, 2021, 12:07 p.m. UTC
Validate the CameraManager can start, stop, and restart successfully, as
well as highlight that we can not construct a second CameraManager
without hitting assertions.

Signed-off-by: Kieran Bingham <kieran.bingham@ideasonboard.com>
---
This introduces some basic tests on the lifetime of the CameraManager.

Integration is optional, but I'm posting to higlight the investigations
I did on this yesterday.

 - We can successfully construct, use and destroy a CameraManager
   and then reconstruct a new one and use that too.

 - Construction of a CameraManager, with a start()/stop() cycle will
   not function using the same CameraManager if we try to re-start()
   the same instance.

 - Construction of two CameraManager instances causes a FATAL assertion
   though somewhat confusingly, it will face a FATAL assertion on the
   second IPAManager construction, before the second CameraManager gets
   to execute its constructor.


 test/camera-manager.cpp | 106 ++++++++++++++++++++++++++++++++++++++++
 test/meson.build        |   1 +
 2 files changed, 107 insertions(+)
 create mode 100644 test/camera-manager.cpp

Comments

Laurent Pinchart July 27, 2021, 5:58 p.m. UTC | #1
Hi Kieran,

Thank you for the patch.

On Tue, Jul 27, 2021 at 01:07:54PM +0100, Kieran Bingham wrote:
> Validate the CameraManager can start, stop, and restart successfully, as
> well as highlight that we can not construct a second CameraManager
> without hitting assertions.
> 
> Signed-off-by: Kieran Bingham <kieran.bingham@ideasonboard.com>
> ---
> This introduces some basic tests on the lifetime of the CameraManager.
> 
> Integration is optional, but I'm posting to higlight the investigations
> I did on this yesterday.
> 
>  - We can successfully construct, use and destroy a CameraManager
>    and then reconstruct a new one and use that too.
> 
>  - Construction of a CameraManager, with a start()/stop() cycle will
>    not function using the same CameraManager if we try to re-start()
>    the same instance.

That's not expected, and should be fixed.

>  - Construction of two CameraManager instances causes a FATAL assertion
>    though somewhat confusingly, it will face a FATAL assertion on the
>    second IPAManager construction, before the second CameraManager gets
>    to execute its constructor.

This part I'd keep out of the test, as it's an API limitation.

>  test/camera-manager.cpp | 106 ++++++++++++++++++++++++++++++++++++++++
>  test/meson.build        |   1 +
>  2 files changed, 107 insertions(+)
>  create mode 100644 test/camera-manager.cpp
> 
> diff --git a/test/camera-manager.cpp b/test/camera-manager.cpp
> new file mode 100644
> index 000000000000..9e9c494af21c
> --- /dev/null
> +++ b/test/camera-manager.cpp
> @@ -0,0 +1,106 @@
> +/* SPDX-License-Identifier: GPL-2.0-or-later */
> +/*
> + * Copyright (C) 2021, Google Inc.
> + *
> + * libcamera Camera Manager API tests
> + */
> +
> +#include <iostream>
> +#include <memory>
> +
> +#include <libcamera/camera.h>
> +#include <libcamera/camera_manager.h>
> +
> +#include "test.h"
> +
> +using namespace libcamera;
> +using namespace std;
> +
> +class CameraManagerTest : public Test
> +{
> +protected:
> +	int validate()
> +	{
> +		std::shared_ptr<Camera> camera;
> +
> +		if (cm_->start()) {
> +			cerr << "Failed to start camera manager" << endl;
> +			return TestFail;
> +		}
> +
> +		if (cm_->cameras().size() <= 0) {
> +			cerr << "No cameras available" << endl;
> +			return TestFail;
> +		}
> +
> +		camera = cm_->cameras()[0];
> +		if (!camera) {
> +			cerr << "Can not obtain a camera at index 0" << endl;
> +			return TestFail;
> +		}
> +
> +		/* Store the camera id that we get */
> +		cameraId_ = camera->id();
> +
> +		return TestPass;
> +	}
> +
> +	int run()
> +	{
> +		std::string firstCamera;
> +
> +		/* Construct and validate the CameraManager */
> +		cm_ = new CameraManager();
> +		if (validate()) {
> +			cerr << "Failed first construction" << endl;
> +			return TestFail;
> +		}
> +
> +		/* Get camera ID stored by validate */
> +		firstCamera = cameraId_;
> +
> +		/* Now stop everything and reconstruct the CameraManager */
> +		cm_->stop();
> +		delete cm_;
> +
> +		/* Restart and assert we can still get a camera */
> +		cm_ = new CameraManager();
> +		if (validate()) {
> +			cerr << "Failed after re-construction" << endl;
> +			return TestFail;
> +		}
> +
> +		if (firstCamera != cameraId_) {
> +			cerr << "Expected to get the same camera after re-construction" << endl;
> +			return TestFail;
> +		}

There's no guarantee that cameras will be presented in the same order,
we only guarantee camera ID stability. Assuming no camera is plugged or
unplugged while the test is running, which I think is a fair assumption,
but should be documeted in a comment here, you could store all the
camera IDs in a std::set and compare the two sets.

> +
> +		/* Test stop and start (without re-create) */
> +		cm_->stop();
> +
> +		/* validate will call start() */
> +		if (validate()) {
> +			cerr << "Failed after re-starting CameraManager" << endl;
> +			return TestFail;
> +		}
> +
> +		/*
> +		 * Creating a second camera manager is not permitted
> +		 *
> +		 * This will fail with a FATAL in constructing a second IPA
> +		 * Manager, even though we also have a FATAL in the
> +		 * CameraManager construction, but the CameraManager tries
> +		 * to construct an IPA manager, which fails before the
> +		 * CameraManager executes any of it's constructor.
> +		 */
> +		//CameraManager *cm2 = new CameraManager();

Ah, you keep it out :-) We could keep it commented out, but I'm not sure
what value it brings. As an out-of-tree patch, to support work on
addressing the assertion in the IPA manager constructor, it's useful,
but I'm not sure I'd merge it.

You're leaking cm_ here. I'd store it in a std::unique_ptr<>.

> +
> +		return TestPass;
> +	}
> +
> +private:
> +	CameraManager *cm_;
> +	std::string cameraId_;
> +};
> +
> +TEST_REGISTER(CameraManagerTest)
> diff --git a/test/meson.build b/test/meson.build
> index 2c3e76546fbc..cd23c07e1f16 100644
> --- a/test/meson.build
> +++ b/test/meson.build
> @@ -24,6 +24,7 @@ subdir('v4l2_subdevice')
>  subdir('v4l2_videodevice')
>  
>  public_tests = [
> +    ['camera-manager',                  'camera-manager.cpp'],

I would have put this in test/camera/

>      ['geometry',                        'geometry.cpp'],
>      ['public-api',                      'public-api.cpp'],
>      ['signal',                          'signal.cpp'],
Kieran Bingham July 28, 2021, 11:17 a.m. UTC | #2
Hi Laurent,

On 27/07/2021 18:58, Laurent Pinchart wrote:
> Hi Kieran,
> 
> Thank you for the patch.
> 
> On Tue, Jul 27, 2021 at 01:07:54PM +0100, Kieran Bingham wrote:
>> Validate the CameraManager can start, stop, and restart successfully, as
>> well as highlight that we can not construct a second CameraManager
>> without hitting assertions.
>>
>> Signed-off-by: Kieran Bingham <kieran.bingham@ideasonboard.com>
>> ---
>> This introduces some basic tests on the lifetime of the CameraManager.
>>
>> Integration is optional, but I'm posting to higlight the investigations
>> I did on this yesterday.
>>
>>  - We can successfully construct, use and destroy a CameraManager
>>    and then reconstruct a new one and use that too.
>>
>>  - Construction of a CameraManager, with a start()/stop() cycle will
>>    not function using the same CameraManager if we try to re-start()
>>    the same instance.
> 
> That's not expected, and should be fixed.
> 
>>  - Construction of two CameraManager instances causes a FATAL assertion
>>    though somewhat confusingly, it will face a FATAL assertion on the
>>    second IPAManager construction, before the second CameraManager gets
>>    to execute its constructor.
> 
> This part I'd keep out of the test, as it's an API limitation.
> 
>>  test/camera-manager.cpp | 106 ++++++++++++++++++++++++++++++++++++++++
>>  test/meson.build        |   1 +
>>  2 files changed, 107 insertions(+)
>>  create mode 100644 test/camera-manager.cpp
>>
>> diff --git a/test/camera-manager.cpp b/test/camera-manager.cpp
>> new file mode 100644
>> index 000000000000..9e9c494af21c
>> --- /dev/null
>> +++ b/test/camera-manager.cpp
>> @@ -0,0 +1,106 @@
>> +/* SPDX-License-Identifier: GPL-2.0-or-later */
>> +/*
>> + * Copyright (C) 2021, Google Inc.
>> + *
>> + * libcamera Camera Manager API tests
>> + */
>> +
>> +#include <iostream>
>> +#include <memory>
>> +
>> +#include <libcamera/camera.h>
>> +#include <libcamera/camera_manager.h>
>> +
>> +#include "test.h"
>> +
>> +using namespace libcamera;
>> +using namespace std;
>> +
>> +class CameraManagerTest : public Test
>> +{
>> +protected:
>> +	int validate()
>> +	{
>> +		std::shared_ptr<Camera> camera;
>> +
>> +		if (cm_->start()) {
>> +			cerr << "Failed to start camera manager" << endl;
>> +			return TestFail;
>> +		}
>> +
>> +		if (cm_->cameras().size() <= 0) {
>> +			cerr << "No cameras available" << endl;
>> +			return TestFail;
>> +		}
>> +
>> +		camera = cm_->cameras()[0];
>> +		if (!camera) {
>> +			cerr << "Can not obtain a camera at index 0" << endl;
>> +			return TestFail;
>> +		}
>> +
>> +		/* Store the camera id that we get */
>> +		cameraId_ = camera->id();
>> +
>> +		return TestPass;
>> +	}
>> +
>> +	int run()
>> +	{
>> +		std::string firstCamera;
>> +
>> +		/* Construct and validate the CameraManager */
>> +		cm_ = new CameraManager();
>> +		if (validate()) {
>> +			cerr << "Failed first construction" << endl;
>> +			return TestFail;
>> +		}
>> +
>> +		/* Get camera ID stored by validate */
>> +		firstCamera = cameraId_;
>> +
>> +		/* Now stop everything and reconstruct the CameraManager */
>> +		cm_->stop();
>> +		delete cm_;
>> +
>> +		/* Restart and assert we can still get a camera */
>> +		cm_ = new CameraManager();
>> +		if (validate()) {
>> +			cerr << "Failed after re-construction" << endl;
>> +			return TestFail;
>> +		}
>> +
>> +		if (firstCamera != cameraId_) {
>> +			cerr << "Expected to get the same camera after re-construction" << endl;
>> +			return TestFail;
>> +		}
> 
> There's no guarantee that cameras will be presented in the same order,
> we only guarantee camera ID stability. Assuming no camera is plugged or
> unplugged while the test is running, which I think is a fair assumption,
> but should be documeted in a comment here, you could store all the
> camera IDs in a std::set and compare the two sets.

The aim was mostly to be sure I interacted with the CameraManager and
could see that it was working - which was what highlighted the
start/stop/start issue.

If we assume the cameras shouldn't change, a set does make sense, so I
can look at that ... if ...


> 
>> +
>> +		/* Test stop and start (without re-create) */
>> +		cm_->stop();
>> +
>> +		/* validate will call start() */
>> +		if (validate()) {
>> +			cerr << "Failed after re-starting CameraManager" << endl;
>> +			return TestFail;
>> +		}
>> +
>> +		/*
>> +		 * Creating a second camera manager is not permitted
>> +		 *
>> +		 * This will fail with a FATAL in constructing a second IPA
>> +		 * Manager, even though we also have a FATAL in the
>> +		 * CameraManager construction, but the CameraManager tries
>> +		 * to construct an IPA manager, which fails before the
>> +		 * CameraManager executes any of it's constructor.
>> +		 */
>> +		//CameraManager *cm2 = new CameraManager();
> 
> Ah, you keep it out :-) We could keep it commented out, but I'm not sure
> what value it brings. As an out-of-tree patch, to support work on

Certainly helpful to easily highlight the IPA manager issue.

But I quite like that it shows in the tests what is and isn't
possible/expected, much like you have other tests that show expected
compilation failure, though I guess this shows an expected runtime failure.

It's a shame we can't test that something is expected to fire an assert?


> addressing the assertion in the IPA manager constructor, it's useful,
> but I'm not sure I'd merge it.
> 
> You're leaking cm_ here. I'd store it in a std::unique_ptr<>.

Yes, that's worth doing.

I wonder if we should recommend that in the other usages.

For example the application developer guide just stores the pointer.
(I now have a local patch to submit later to fix this)


>> +
>> +		return TestPass;
>> +	}
>> +
>> +private:
>> +	CameraManager *cm_;
>> +	std::string cameraId_;
>> +};
>> +
>> +TEST_REGISTER(CameraManagerTest)
>> diff --git a/test/meson.build b/test/meson.build
>> index 2c3e76546fbc..cd23c07e1f16 100644
>> --- a/test/meson.build
>> +++ b/test/meson.build
>> @@ -24,6 +24,7 @@ subdir('v4l2_subdevice')
>>  subdir('v4l2_videodevice')
>>  
>>  public_tests = [
>> +    ['camera-manager',                  'camera-manager.cpp'],
> 
> I would have put this in test/camera/

Ok.

> 
>>      ['geometry',                        'geometry.cpp'],
>>      ['public-api',                      'public-api.cpp'],
>>      ['signal',                          'signal.cpp'],
>
Laurent Pinchart July 28, 2021, 11:33 a.m. UTC | #3
Hi Kieran,

On Wed, Jul 28, 2021 at 12:17:14PM +0100, Kieran Bingham wrote:
> On 27/07/2021 18:58, Laurent Pinchart wrote:
> > On Tue, Jul 27, 2021 at 01:07:54PM +0100, Kieran Bingham wrote:
> >> Validate the CameraManager can start, stop, and restart successfully, as
> >> well as highlight that we can not construct a second CameraManager
> >> without hitting assertions.
> >>
> >> Signed-off-by: Kieran Bingham <kieran.bingham@ideasonboard.com>
> >> ---
> >> This introduces some basic tests on the lifetime of the CameraManager.
> >>
> >> Integration is optional, but I'm posting to higlight the investigations
> >> I did on this yesterday.
> >>
> >>  - We can successfully construct, use and destroy a CameraManager
> >>    and then reconstruct a new one and use that too.
> >>
> >>  - Construction of a CameraManager, with a start()/stop() cycle will
> >>    not function using the same CameraManager if we try to re-start()
> >>    the same instance.
> > 
> > That's not expected, and should be fixed.
> > 
> >>  - Construction of two CameraManager instances causes a FATAL assertion
> >>    though somewhat confusingly, it will face a FATAL assertion on the
> >>    second IPAManager construction, before the second CameraManager gets
> >>    to execute its constructor.
> > 
> > This part I'd keep out of the test, as it's an API limitation.
> > 
> >>  test/camera-manager.cpp | 106 ++++++++++++++++++++++++++++++++++++++++
> >>  test/meson.build        |   1 +
> >>  2 files changed, 107 insertions(+)
> >>  create mode 100644 test/camera-manager.cpp
> >>
> >> diff --git a/test/camera-manager.cpp b/test/camera-manager.cpp
> >> new file mode 100644
> >> index 000000000000..9e9c494af21c
> >> --- /dev/null
> >> +++ b/test/camera-manager.cpp
> >> @@ -0,0 +1,106 @@
> >> +/* SPDX-License-Identifier: GPL-2.0-or-later */
> >> +/*
> >> + * Copyright (C) 2021, Google Inc.
> >> + *
> >> + * libcamera Camera Manager API tests
> >> + */
> >> +
> >> +#include <iostream>
> >> +#include <memory>
> >> +
> >> +#include <libcamera/camera.h>
> >> +#include <libcamera/camera_manager.h>
> >> +
> >> +#include "test.h"
> >> +
> >> +using namespace libcamera;
> >> +using namespace std;
> >> +
> >> +class CameraManagerTest : public Test
> >> +{
> >> +protected:
> >> +	int validate()
> >> +	{
> >> +		std::shared_ptr<Camera> camera;
> >> +
> >> +		if (cm_->start()) {
> >> +			cerr << "Failed to start camera manager" << endl;
> >> +			return TestFail;
> >> +		}
> >> +
> >> +		if (cm_->cameras().size() <= 0) {
> >> +			cerr << "No cameras available" << endl;
> >> +			return TestFail;
> >> +		}
> >> +
> >> +		camera = cm_->cameras()[0];
> >> +		if (!camera) {
> >> +			cerr << "Can not obtain a camera at index 0" << endl;
> >> +			return TestFail;
> >> +		}
> >> +
> >> +		/* Store the camera id that we get */
> >> +		cameraId_ = camera->id();
> >> +
> >> +		return TestPass;
> >> +	}
> >> +
> >> +	int run()
> >> +	{
> >> +		std::string firstCamera;
> >> +
> >> +		/* Construct and validate the CameraManager */
> >> +		cm_ = new CameraManager();
> >> +		if (validate()) {
> >> +			cerr << "Failed first construction" << endl;
> >> +			return TestFail;
> >> +		}
> >> +
> >> +		/* Get camera ID stored by validate */
> >> +		firstCamera = cameraId_;
> >> +
> >> +		/* Now stop everything and reconstruct the CameraManager */
> >> +		cm_->stop();
> >> +		delete cm_;
> >> +
> >> +		/* Restart and assert we can still get a camera */
> >> +		cm_ = new CameraManager();
> >> +		if (validate()) {
> >> +			cerr << "Failed after re-construction" << endl;
> >> +			return TestFail;
> >> +		}
> >> +
> >> +		if (firstCamera != cameraId_) {
> >> +			cerr << "Expected to get the same camera after re-construction" << endl;
> >> +			return TestFail;
> >> +		}
> > 
> > There's no guarantee that cameras will be presented in the same order,
> > we only guarantee camera ID stability. Assuming no camera is plugged or
> > unplugged while the test is running, which I think is a fair assumption,
> > but should be documeted in a comment here, you could store all the
> > camera IDs in a std::set and compare the two sets.
> 
> The aim was mostly to be sure I interacted with the CameraManager and
> could see that it was working - which was what highlighted the
> start/stop/start issue.

Sure, but the test as done today may fail as there's no guarantee on the
ordering, that part needs to be fixed to avoid false positives.

> If we assume the cameras shouldn't change, a set does make sense, so I
> can look at that ... if ...
> 
> >> +
> >> +		/* Test stop and start (without re-create) */
> >> +		cm_->stop();
> >> +
> >> +		/* validate will call start() */
> >> +		if (validate()) {
> >> +			cerr << "Failed after re-starting CameraManager" << endl;
> >> +			return TestFail;
> >> +		}
> >> +
> >> +		/*
> >> +		 * Creating a second camera manager is not permitted
> >> +		 *
> >> +		 * This will fail with a FATAL in constructing a second IPA
> >> +		 * Manager, even though we also have a FATAL in the
> >> +		 * CameraManager construction, but the CameraManager tries
> >> +		 * to construct an IPA manager, which fails before the
> >> +		 * CameraManager executes any of it's constructor.
> >> +		 */
> >> +		//CameraManager *cm2 = new CameraManager();
> > 
> > Ah, you keep it out :-) We could keep it commented out, but I'm not sure
> > what value it brings. As an out-of-tree patch, to support work on
> 
> Certainly helpful to easily highlight the IPA manager issue.
> 
> But I quite like that it shows in the tests what is and isn't
> possible/expected, much like you have other tests that show expected
> compilation failure, though I guess this shows an expected runtime failure.
> 
> It's a shame we can't test that something is expected to fire an assert?

If we really wanted to I think we could, by wrapping the test in another
process, but it will be quite a bit of work.

If you want to keep the above, let's just fix the comment style with
/* ... */ instead of //.

> > addressing the assertion in the IPA manager constructor, it's useful,
> > but I'm not sure I'd merge it.
> > 
> > You're leaking cm_ here. I'd store it in a std::unique_ptr<>.
> 
> Yes, that's worth doing.
> 
> I wonder if we should recommend that in the other usages.
> 
> For example the application developer guide just stores the pointer.
> (I now have a local patch to submit later to fix this)

Yes I think that's good practice.

> >> +
> >> +		return TestPass;
> >> +	}
> >> +
> >> +private:
> >> +	CameraManager *cm_;
> >> +	std::string cameraId_;
> >> +};
> >> +
> >> +TEST_REGISTER(CameraManagerTest)
> >> diff --git a/test/meson.build b/test/meson.build
> >> index 2c3e76546fbc..cd23c07e1f16 100644
> >> --- a/test/meson.build
> >> +++ b/test/meson.build
> >> @@ -24,6 +24,7 @@ subdir('v4l2_subdevice')
> >>  subdir('v4l2_videodevice')
> >>  
> >>  public_tests = [
> >> +    ['camera-manager',                  'camera-manager.cpp'],
> > 
> > I would have put this in test/camera/
> 
> Ok.
> 
> > 
> >>      ['geometry',                        'geometry.cpp'],
> >>      ['public-api',                      'public-api.cpp'],
> >>      ['signal',                          'signal.cpp'],

Patch
diff mbox series

diff --git a/test/camera-manager.cpp b/test/camera-manager.cpp
new file mode 100644
index 000000000000..9e9c494af21c
--- /dev/null
+++ b/test/camera-manager.cpp
@@ -0,0 +1,106 @@ 
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+/*
+ * Copyright (C) 2021, Google Inc.
+ *
+ * libcamera Camera Manager API tests
+ */
+
+#include <iostream>
+#include <memory>
+
+#include <libcamera/camera.h>
+#include <libcamera/camera_manager.h>
+
+#include "test.h"
+
+using namespace libcamera;
+using namespace std;
+
+class CameraManagerTest : public Test
+{
+protected:
+	int validate()
+	{
+		std::shared_ptr<Camera> camera;
+
+		if (cm_->start()) {
+			cerr << "Failed to start camera manager" << endl;
+			return TestFail;
+		}
+
+		if (cm_->cameras().size() <= 0) {
+			cerr << "No cameras available" << endl;
+			return TestFail;
+		}
+
+		camera = cm_->cameras()[0];
+		if (!camera) {
+			cerr << "Can not obtain a camera at index 0" << endl;
+			return TestFail;
+		}
+
+		/* Store the camera id that we get */
+		cameraId_ = camera->id();
+
+		return TestPass;
+	}
+
+	int run()
+	{
+		std::string firstCamera;
+
+		/* Construct and validate the CameraManager */
+		cm_ = new CameraManager();
+		if (validate()) {
+			cerr << "Failed first construction" << endl;
+			return TestFail;
+		}
+
+		/* Get camera ID stored by validate */
+		firstCamera = cameraId_;
+
+		/* Now stop everything and reconstruct the CameraManager */
+		cm_->stop();
+		delete cm_;
+
+		/* Restart and assert we can still get a camera */
+		cm_ = new CameraManager();
+		if (validate()) {
+			cerr << "Failed after re-construction" << endl;
+			return TestFail;
+		}
+
+		if (firstCamera != cameraId_) {
+			cerr << "Expected to get the same camera after re-construction" << endl;
+			return TestFail;
+		}
+
+		/* Test stop and start (without re-create) */
+		cm_->stop();
+
+		/* validate will call start() */
+		if (validate()) {
+			cerr << "Failed after re-starting CameraManager" << endl;
+			return TestFail;
+		}
+
+		/*
+		 * Creating a second camera manager is not permitted
+		 *
+		 * This will fail with a FATAL in constructing a second IPA
+		 * Manager, even though we also have a FATAL in the
+		 * CameraManager construction, but the CameraManager tries
+		 * to construct an IPA manager, which fails before the
+		 * CameraManager executes any of it's constructor.
+		 */
+		//CameraManager *cm2 = new CameraManager();
+
+		return TestPass;
+	}
+
+private:
+	CameraManager *cm_;
+	std::string cameraId_;
+};
+
+TEST_REGISTER(CameraManagerTest)
diff --git a/test/meson.build b/test/meson.build
index 2c3e76546fbc..cd23c07e1f16 100644
--- a/test/meson.build
+++ b/test/meson.build
@@ -24,6 +24,7 @@  subdir('v4l2_subdevice')
 subdir('v4l2_videodevice')
 
 public_tests = [
+    ['camera-manager',                  'camera-manager.cpp'],
     ['geometry',                        'geometry.cpp'],
     ['public-api',                      'public-api.cpp'],
     ['signal',                          'signal.cpp'],