mbox series

[libgpiod,WIP,0/2] Convert the build from autotools to meson

Message ID 20221205132207.94775-1-andrew@aj.id.au
Headers show
Series Convert the build from autotools to meson | expand

Message

Andrew Jeffery Dec. 5, 2022, 1:22 p.m. UTC
Hello,

Based on a recent poke [1] and in-between meetings I've put together a
WIP series that converts libgpiod's build from autotools to meson. As
far as I'm aware the meson build supports all the significant options to
enable or disable features exposed by the autotools build:

* Tests
* Tools
  * Interactive gpioset
* Bindings
  * C++
  * Python
  * Rust
* Documentation
  * Manpages
  * Doxygen

[1] https://lore.kernel.org/all/CAMRc=Mda8UnyH+_GxeX_4MyKd+DPN0BVH5K+J+VWnMJNC1vwTQ@mail.gmail.com/

Meson has pretty good support for handling python and so the patch does
away with setup.py entirely. However, the rust case isn't quite so
simple. In order to handle the dependencies of the rust bindings I've
called out to cargo through a custom target. It's not great, but from
what I could see it seems to be the path of least resistance given
meson's support for rust.

There's no support for installing the rust bindings through meson, but
this is not worse than the support we appeared to have under autotools.

It's worth noting that you'll probably want to disable the rust bindings
if you need to run the install phase for libgpiod under e.g. sudo but
have used rustup to install cargo for your unpriviledged user.

Also, if you've used rustup to install the rust toolchain you may also
need to install clang in order to pick up C toolchain headers for
consumption by bindgen.

Anyway, feedback on the rust part is definitely appreciated. Maybe
there's a better approach?

Moving along, the following tests pass in their entirety in my test VM:

* gpiod-test
* gpiod-cxx-test
* python -m gpiod.test

I've also briefly compared the install trees for the autotools and meson
builds under some configurations. The differences are accounted for by
meson defaulting to multi-arch installation paths for shared objects and
picking the generic rather than interpreter-version-specific python3
dist-packages directory under $PREFIX. Let me know if those seem
problematic.

A complete meson setup invocation looks as follows:

```
$ meson setup -Dbindings=cxx,python,rust -Ddocumentation=man,inline -Dexamples=true -Dtests=true -Dtools=true build
```

Subsequently the build can be performed with:

```
$ meson compile -C build
```

Meson defaults to using ninja as its backend, and automatically exploits
ccache[2] when available to keep repeated builds speedy.

[2] https://ccache.dev/

We end up with a net reduction of 254 LOC for the build system, and,
IMO, a single and fairly readable language to express it. Along with
that comes easy integration as a dependency in other (meson) projects
and a straight-forward path for their cross-compilation.

Let me know what you think.

Andrew

Andrew Jeffery (2):
  Introduce meson as a build system
  Remove autotools in favour of meson

 Doxyfile.in                               |   2 +-
 Makefile.am                               |  43 ----
 autogen.sh                                |  17 --
 bindings/Makefile.am                      |  22 --
 bindings/cxx/Makefile.am                  |  48 ----
 bindings/cxx/examples/Makefile.am         |  26 ---
 bindings/cxx/examples/meson.build         |   9 +
 bindings/cxx/gpiodcxx/Makefile.am         |  20 --
 bindings/cxx/gpiodcxx/meson.build         |  19 ++
 bindings/cxx/meson.build                  |  49 ++++
 bindings/cxx/tests/Makefile.am            |  32 ---
 bindings/cxx/tests/meson.build            |  26 +++
 bindings/meson.build                      |  14 ++
 bindings/python/Makefile.am               |  35 ---
 bindings/python/examples/Makefile.am      |  10 -
 bindings/python/examples/meson.build      |  12 +
 bindings/python/gpiod/Makefile.am         |  17 --
 bindings/python/gpiod/ext/Makefile.am     |  11 -
 bindings/python/gpiod/ext/meson.build     |  14 ++
 bindings/python/gpiod/meson.build         |  17 ++
 bindings/python/meson.build               |  16 ++
 bindings/python/setup.py                  |  47 ----
 bindings/python/tests/Makefile.am         |  17 --
 bindings/python/tests/gpiosim/Makefile.am |   7 -
 bindings/python/tests/gpiosim/meson.build |  12 +
 bindings/python/tests/meson.build         |  17 ++
 bindings/rust/Makefile.am                 |  19 --
 bindings/rust/gpiosim-sys/build.rs        |   9 +-
 bindings/rust/libgpiod-sys/build.rs       |   9 +-
 bindings/rust/meson.build                 |  33 +++
 configure.ac                              | 272 ----------------------
 include/Makefile.am                       |   4 -
 include/meson.build                       |   7 +
 lib/Makefile.am                           |  27 ---
 lib/meson.build                           |  30 +++
 man/Makefile.am                           |  16 --
 man/meson.build                           |  21 ++
 meson.build                               |  91 ++++++++
 meson_options.txt                         |   9 +
 tests/Makefile.am                         |  34 ---
 tests/gpiosim/Makefile.am                 |  16 --
 tests/gpiosim/meson.build                 |  24 ++
 tests/meson.build                         |  30 +++
 tools/Makefile.am                         |  39 ----
 tools/meson.build                         |  69 ++++++
 45 files changed, 532 insertions(+), 786 deletions(-)
 delete mode 100644 Makefile.am
 delete mode 100755 autogen.sh
 delete mode 100644 bindings/Makefile.am
 delete mode 100644 bindings/cxx/Makefile.am
 delete mode 100644 bindings/cxx/examples/Makefile.am
 create mode 100644 bindings/cxx/examples/meson.build
 delete mode 100644 bindings/cxx/gpiodcxx/Makefile.am
 create mode 100644 bindings/cxx/gpiodcxx/meson.build
 create mode 100644 bindings/cxx/meson.build
 delete mode 100644 bindings/cxx/tests/Makefile.am
 create mode 100644 bindings/cxx/tests/meson.build
 create mode 100644 bindings/meson.build
 delete mode 100644 bindings/python/Makefile.am
 delete mode 100644 bindings/python/examples/Makefile.am
 create mode 100644 bindings/python/examples/meson.build
 delete mode 100644 bindings/python/gpiod/Makefile.am
 delete mode 100644 bindings/python/gpiod/ext/Makefile.am
 create mode 100644 bindings/python/gpiod/ext/meson.build
 create mode 100644 bindings/python/gpiod/meson.build
 create mode 100644 bindings/python/meson.build
 delete mode 100644 bindings/python/setup.py
 delete mode 100644 bindings/python/tests/Makefile.am
 delete mode 100644 bindings/python/tests/gpiosim/Makefile.am
 create mode 100644 bindings/python/tests/gpiosim/meson.build
 create mode 100644 bindings/python/tests/meson.build
 delete mode 100644 bindings/rust/Makefile.am
 create mode 100644 bindings/rust/meson.build
 delete mode 100644 configure.ac
 delete mode 100644 include/Makefile.am
 create mode 100644 include/meson.build
 delete mode 100644 lib/Makefile.am
 create mode 100644 lib/meson.build
 delete mode 100644 man/Makefile.am
 create mode 100644 man/meson.build
 create mode 100644 meson.build
 create mode 100644 meson_options.txt
 delete mode 100644 tests/Makefile.am
 delete mode 100644 tests/gpiosim/Makefile.am
 create mode 100644 tests/gpiosim/meson.build
 create mode 100644 tests/meson.build
 delete mode 100644 tools/Makefile.am
 create mode 100644 tools/meson.build

Comments

Bartosz Golaszewski Dec. 5, 2022, 6:55 p.m. UTC | #1
On Mon, Dec 5, 2022 at 2:22 PM Andrew Jeffery <andrew@aj.id.au> wrote:
>
> Hello,
>
> Based on a recent poke [1] and in-between meetings I've put together a
> WIP series that converts libgpiod's build from autotools to meson. As
> far as I'm aware the meson build supports all the significant options to
> enable or disable features exposed by the autotools build:
>
> * Tests
> * Tools
>   * Interactive gpioset
> * Bindings
>   * C++
>   * Python
>   * Rust
> * Documentation
>   * Manpages
>   * Doxygen
>
> [1] https://lore.kernel.org/all/CAMRc=Mda8UnyH+_GxeX_4MyKd+DPN0BVH5K+J+VWnMJNC1vwTQ@mail.gmail.com/
>
> Meson has pretty good support for handling python and so the patch does
> away with setup.py entirely.

Eek! No, please do keep setup.py. Autotools too is capable of building
python C extensions on its own and it's what we use in v1 but I want
the python code to be built the standard python way. I actually plan
to post libgpiod v2 on pypi and split out building python bindings
into a separate bitbake recipe in meta-openembedded using the
setuptools3 class.

So let's keep setup.py and just call it from meson.

> However, the rust case isn't quite so
> simple. In order to handle the dependencies of the rust bindings I've
> called out to cargo through a custom target. It's not great, but from
> what I could see it seems to be the path of least resistance given
> meson's support for rust.
>
> There's no support for installing the rust bindings through meson, but
> this is not worse than the support we appeared to have under autotools.
>

I think Viresh too wants to keep cargo as the building agent for the rust code.

> It's worth noting that you'll probably want to disable the rust bindings
> if you need to run the install phase for libgpiod under e.g. sudo but
> have used rustup to install cargo for your unpriviledged user.
>

Current autotools setup doesn't install rust bindings at all, can we
keep it this way?

> Also, if you've used rustup to install the rust toolchain you may also
> need to install clang in order to pick up C toolchain headers for
> consumption by bindgen.
>
> Anyway, feedback on the rust part is definitely appreciated. Maybe
> there's a better approach?
>

Cc'ed Viresh and Kent.

> Moving along, the following tests pass in their entirety in my test VM:
>
> * gpiod-test
> * gpiod-cxx-test
> * python -m gpiod.test
>
> I've also briefly compared the install trees for the autotools and meson
> builds under some configurations. The differences are accounted for by
> meson defaulting to multi-arch installation paths for shared objects and
> picking the generic rather than interpreter-version-specific python3
> dist-packages directory under $PREFIX. Let me know if those seem
> problematic.
>
> A complete meson setup invocation looks as follows:
>
> ```
> $ meson setup -Dbindings=cxx,python,rust -Ddocumentation=man,inline -Dexamples=true -Dtests=true -Dtools=true build
> ```
>
> Subsequently the build can be performed with:
>
> ```
> $ meson compile -C build
> ```
>
> Meson defaults to using ninja as its backend, and automatically exploits
> ccache[2] when available to keep repeated builds speedy.
>

It does show! Full rebuild with autotools:

real 0m43,902s
user 2m40,010s
sys 0m20,172s

Full rebuild with meson:

real 0m10,001s
user 1m1,334s
sys 0m12,205s

More than 4x faster now.

> [2] https://ccache.dev/
>
> We end up with a net reduction of 254 LOC for the build system, and,
> IMO, a single and fairly readable language to express it. Along with
> that comes easy integration as a dependency in other (meson) projects
> and a straight-forward path for their cross-compilation.
>
> Let me know what you think.

Meson has a steep learning curve but I really want to move over to it
now and will put in the time to learn it. Thanks for doing it. The
patches are functional from what I tested so far.

One thing I'd love to see changed is: put all API and ABI version
number next to each other in a single place so that there's less risk
of forgetting to update one of them when making a release. Is that
possible?

Bart

>
> Andrew
>
> Andrew Jeffery (2):
>   Introduce meson as a build system
>   Remove autotools in favour of meson
>
>  Doxyfile.in                               |   2 +-
>  Makefile.am                               |  43 ----
>  autogen.sh                                |  17 --
>  bindings/Makefile.am                      |  22 --
>  bindings/cxx/Makefile.am                  |  48 ----
>  bindings/cxx/examples/Makefile.am         |  26 ---
>  bindings/cxx/examples/meson.build         |   9 +
>  bindings/cxx/gpiodcxx/Makefile.am         |  20 --
>  bindings/cxx/gpiodcxx/meson.build         |  19 ++
>  bindings/cxx/meson.build                  |  49 ++++
>  bindings/cxx/tests/Makefile.am            |  32 ---
>  bindings/cxx/tests/meson.build            |  26 +++
>  bindings/meson.build                      |  14 ++
>  bindings/python/Makefile.am               |  35 ---
>  bindings/python/examples/Makefile.am      |  10 -
>  bindings/python/examples/meson.build      |  12 +
>  bindings/python/gpiod/Makefile.am         |  17 --
>  bindings/python/gpiod/ext/Makefile.am     |  11 -
>  bindings/python/gpiod/ext/meson.build     |  14 ++
>  bindings/python/gpiod/meson.build         |  17 ++
>  bindings/python/meson.build               |  16 ++
>  bindings/python/setup.py                  |  47 ----
>  bindings/python/tests/Makefile.am         |  17 --
>  bindings/python/tests/gpiosim/Makefile.am |   7 -
>  bindings/python/tests/gpiosim/meson.build |  12 +
>  bindings/python/tests/meson.build         |  17 ++
>  bindings/rust/Makefile.am                 |  19 --
>  bindings/rust/gpiosim-sys/build.rs        |   9 +-
>  bindings/rust/libgpiod-sys/build.rs       |   9 +-
>  bindings/rust/meson.build                 |  33 +++
>  configure.ac                              | 272 ----------------------
>  include/Makefile.am                       |   4 -
>  include/meson.build                       |   7 +
>  lib/Makefile.am                           |  27 ---
>  lib/meson.build                           |  30 +++
>  man/Makefile.am                           |  16 --
>  man/meson.build                           |  21 ++
>  meson.build                               |  91 ++++++++
>  meson_options.txt                         |   9 +
>  tests/Makefile.am                         |  34 ---
>  tests/gpiosim/Makefile.am                 |  16 --
>  tests/gpiosim/meson.build                 |  24 ++
>  tests/meson.build                         |  30 +++
>  tools/Makefile.am                         |  39 ----
>  tools/meson.build                         |  69 ++++++
>  45 files changed, 532 insertions(+), 786 deletions(-)
>  delete mode 100644 Makefile.am
>  delete mode 100755 autogen.sh
>  delete mode 100644 bindings/Makefile.am
>  delete mode 100644 bindings/cxx/Makefile.am
>  delete mode 100644 bindings/cxx/examples/Makefile.am
>  create mode 100644 bindings/cxx/examples/meson.build
>  delete mode 100644 bindings/cxx/gpiodcxx/Makefile.am
>  create mode 100644 bindings/cxx/gpiodcxx/meson.build
>  create mode 100644 bindings/cxx/meson.build
>  delete mode 100644 bindings/cxx/tests/Makefile.am
>  create mode 100644 bindings/cxx/tests/meson.build
>  create mode 100644 bindings/meson.build
>  delete mode 100644 bindings/python/Makefile.am
>  delete mode 100644 bindings/python/examples/Makefile.am
>  create mode 100644 bindings/python/examples/meson.build
>  delete mode 100644 bindings/python/gpiod/Makefile.am
>  delete mode 100644 bindings/python/gpiod/ext/Makefile.am
>  create mode 100644 bindings/python/gpiod/ext/meson.build
>  create mode 100644 bindings/python/gpiod/meson.build
>  create mode 100644 bindings/python/meson.build
>  delete mode 100644 bindings/python/setup.py
>  delete mode 100644 bindings/python/tests/Makefile.am
>  delete mode 100644 bindings/python/tests/gpiosim/Makefile.am
>  create mode 100644 bindings/python/tests/gpiosim/meson.build
>  create mode 100644 bindings/python/tests/meson.build
>  delete mode 100644 bindings/rust/Makefile.am
>  create mode 100644 bindings/rust/meson.build
>  delete mode 100644 configure.ac
>  delete mode 100644 include/Makefile.am
>  create mode 100644 include/meson.build
>  delete mode 100644 lib/Makefile.am
>  create mode 100644 lib/meson.build
>  delete mode 100644 man/Makefile.am
>  create mode 100644 man/meson.build
>  create mode 100644 meson.build
>  create mode 100644 meson_options.txt
>  delete mode 100644 tests/Makefile.am
>  delete mode 100644 tests/gpiosim/Makefile.am
>  create mode 100644 tests/gpiosim/meson.build
>  create mode 100644 tests/meson.build
>  delete mode 100644 tools/Makefile.am
>  create mode 100644 tools/meson.build
>
> --
> 2.37.2
>
Viresh Kumar Dec. 6, 2022, 12:06 a.m. UTC | #2
+ Miguel/Bjorn.

On 05-12-22, 19:55, Bartosz Golaszewski wrote:
> On Mon, Dec 5, 2022 at 2:22 PM Andrew Jeffery <andrew@aj.id.au> wrote:
> >
> > Hello,
> >
> > Based on a recent poke [1] and in-between meetings I've put together a
> > WIP series that converts libgpiod's build from autotools to meson. As
> > far as I'm aware the meson build supports all the significant options to
> > enable or disable features exposed by the autotools build:
> >
> > * Tests
> > * Tools
> >   * Interactive gpioset
> > * Bindings
> >   * C++
> >   * Python
> >   * Rust
> > * Documentation
> >   * Manpages
> >   * Doxygen
> >
> > [1] https://lore.kernel.org/all/CAMRc=Mda8UnyH+_GxeX_4MyKd+DPN0BVH5K+J+VWnMJNC1vwTQ@mail.gmail.com/
> >
> > Meson has pretty good support for handling python and so the patch does
> > away with setup.py entirely.
> 
> Eek! No, please do keep setup.py. Autotools too is capable of building
> python C extensions on its own and it's what we use in v1 but I want
> the python code to be built the standard python way. I actually plan
> to post libgpiod v2 on pypi and split out building python bindings
> into a separate bitbake recipe in meta-openembedded using the
> setuptools3 class.
> 
> So let's keep setup.py and just call it from meson.
> 
> > However, the rust case isn't quite so
> > simple. In order to handle the dependencies of the rust bindings I've
> > called out to cargo through a custom target. It's not great, but from
> > what I could see it seems to be the path of least resistance given
> > meson's support for rust.
> >
> > There's no support for installing the rust bindings through meson, but
> > this is not worse than the support we appeared to have under autotools.
> >
> 
> I think Viresh too wants to keep cargo as the building agent for the rust code.

I am not the best guy to ask around Rust tooling in general and
probably Kent / Miguel can help here.

Sorry for the stupid question, but what does "installing the rust
bindings" mean here ? FWIW, for me the only thing that matters is that
we are able to build the rust bindings, along with Make, and run tests
somehow to make sure nothing broke. Since this is a library crate, the
user crate will mark its dependency and do the build itself too.

> > It's worth noting that you'll probably want to disable the rust bindings
> > if you need to run the install phase for libgpiod under e.g. sudo but
> > have used rustup to install cargo for your unpriviledged user.
> >
> 
> Current autotools setup doesn't install rust bindings at all, can we
> keep it this way?
> 
> > Also, if you've used rustup to install the rust toolchain you may also
> > need to install clang in order to pick up C toolchain headers for
> > consumption by bindgen.

Yeah, from what I remember, we do need clang support for bindgen.

> > Anyway, feedback on the rust part is definitely appreciated. Maybe
> > there's a better approach?
Kent Gibson Dec. 6, 2022, 3:54 a.m. UTC | #3
On Tue, Dec 06, 2022 at 09:10:34AM +0530, Viresh Kumar wrote:
> On 06-12-22, 10:56, Andrew Jeffery wrote:
> > My experience with rust is (unfortunately) superficial; the meson
> > conversion achieves the same outcome as the autotools integration (runs
> > `cargo build ...`). If that's enough then I don't think there are any
> > further issues.
> 
> That's all I care about at the moment. Lets see if Kent have something
> to add to this, else it looks okay.
> 

I've got nothing to add - calling cargo makes sense to me.

Cheers,
Kent.
Miguel Ojeda Dec. 6, 2022, 12:15 p.m. UTC | #4
On Tue, Dec 6, 2022 at 4:55 AM Kent Gibson <warthog618@gmail.com> wrote:
>
> I've got nothing to add - calling cargo makes sense to me.

We do that too in Kbuild in some cases (though not for building). I
think it is fine to delegate where it makes sense.

One concern may be handling `-j` properly between different build
systems. Not sure what Meson provides there. Cargo supports the GNU
Make jobserver as a client.

Cheers,
Miguel
Andy Shevchenko Dec. 6, 2022, 2:54 p.m. UTC | #5
On Mon, Dec 05, 2022 at 07:55:29PM +0100, Bartosz Golaszewski wrote:
> On Mon, Dec 5, 2022 at 2:22 PM Andrew Jeffery <andrew@aj.id.au> wrote:

...

> > Meson defaults to using ninja as its backend, and automatically exploits
> > ccache[2] when available to keep repeated builds speedy.

...which is a bad idea for a clean build.

> It does show! Full rebuild with autotools:
> 
> real 0m43,902s
> user 2m40,010s
> sys 0m20,172s
> 
> Full rebuild with meson:
> 
> real 0m10,001s
> user 1m1,334s
> sys 0m12,205s
> 
> More than 4x faster now.

And risk to have a badly formed binaries (yes, very little risk, but > 0).

> > [2] https://ccache.dev/

ccache has downside of its own use. If we have a common storage for ccache --
the collision is just matter of time (yes, have seen that in real life).

OTOH requiring per-project ccache storage makes a little sense for the end user
as they quite likely won't rebuild it many times.
Andrew Jeffery Dec. 6, 2022, 10:04 p.m. UTC | #6
Hi Andy,

On Wed, 7 Dec 2022, at 01:24, Andy Shevchenko wrote:
> On Mon, Dec 05, 2022 at 07:55:29PM +0100, Bartosz Golaszewski wrote:
>> On Mon, Dec 5, 2022 at 2:22 PM Andrew Jeffery <andrew@aj.id.au> wrote:
>
> ...
>
>> > Meson defaults to using ninja as its backend, and automatically exploits
>> > ccache[2] when available to keep repeated builds speedy.
>
> ...which is a bad idea for a clean build.
>
>> It does show! Full rebuild with autotools:
>> 
>> real 0m43,902s
>> user 2m40,010s
>> sys 0m20,172s
>> 
>> Full rebuild with meson:
>> 
>> real 0m10,001s
>> user 1m1,334s
>> sys 0m12,205s
>> 
>> More than 4x faster now.
>
> And risk to have a badly formed binaries (yes, very little risk, but > 0).
>
>> > [2] https://ccache.dev/
>
> ccache has downside of its own use. If we have a common storage for ccache --
> the collision is just matter of time (yes, have seen that in real life).
>
> OTOH requiring per-project ccache storage makes a little sense for the end user
> as they quite likely won't rebuild it many times.

Valid points. However I think they're addressed by:

1. Not installing ccache on the system, or
2. Overriding the auto-detection behaviour of `meson setup ...` 

Regarding 2, you can specify the CC and CXX environment variables to force its hand:

```
$ command -v ccache
/usr/bin/ccache
$ CC=cc CXX=c++ meson setup -Dbindings=cxx build
The Meson build system
Version: 0.63.0
...
C compiler for the host machine: cc (gcc 12.2.0 "cc (Ubuntu 12.2.0-3ubuntu1) 12.2.0")
...
C++ compiler for the host machine: c++ (gcc 12.2.0 "c++ (Ubuntu 12.2.0-3ubuntu1) 12.2.0")
...
```

Compared to the default behaviour:

```
$ meson setup -Dbindings=cxx build
The Meson build system
Version: 0.63.0
...
C compiler for the host machine: ccache cc (gcc 12.2.0 "cc (Ubuntu 12.2.0-3ubuntu1) 12.2.0")
...
C++ compiler for the host machine: ccache c++ (gcc 12.2.0 "c++ (Ubuntu 12.2.0-3ubuntu1) 12.2.0")
...
```

This use of the CC and CXX variables is covered in the documentation:

https://mesonbuild.com/Feature-autodetection.html#ccache

Andrew
Andy Shevchenko Dec. 6, 2022, 10:21 p.m. UTC | #7
On Wed, Dec 07, 2022 at 08:34:20AM +1030, Andrew Jeffery wrote:
> On Wed, 7 Dec 2022, at 01:24, Andy Shevchenko wrote:
> > On Mon, Dec 05, 2022 at 07:55:29PM +0100, Bartosz Golaszewski wrote:
> >> On Mon, Dec 5, 2022 at 2:22 PM Andrew Jeffery <andrew@aj.id.au> wrote:

...

> >> > Meson defaults to using ninja as its backend, and automatically exploits
> >> > ccache[2] when available to keep repeated builds speedy.
> >
> > ...which is a bad idea for a clean build.
> >
> >> It does show! Full rebuild with autotools:
> >> 
> >> real 0m43,902s
> >> user 2m40,010s
> >> sys 0m20,172s
> >> 
> >> Full rebuild with meson:
> >> 
> >> real 0m10,001s
> >> user 1m1,334s
> >> sys 0m12,205s
> >> 
> >> More than 4x faster now.
> >
> > And risk to have a badly formed binaries (yes, very little risk, but > 0).
> >
> >> > [2] https://ccache.dev/
> >
> > ccache has downside of its own use. If we have a common storage for ccache --
> > the collision is just matter of time (yes, have seen that in real life).
> >
> > OTOH requiring per-project ccache storage makes a little sense for the end user
> > as they quite likely won't rebuild it many times.
> 
> Valid points. However I think they're addressed by:
> 
> 1. Not installing ccache on the system, or
> 2. Overriding the auto-detection behaviour of `meson setup ...` 
> 
> Regarding 2, you can specify the CC and CXX environment variables to force its hand:
> 
> ```
> $ command -v ccache
> /usr/bin/ccache
> $ CC=cc CXX=c++ meson setup -Dbindings=cxx build
> The Meson build system
> Version: 0.63.0
> ...
> C compiler for the host machine: cc (gcc 12.2.0 "cc (Ubuntu 12.2.0-3ubuntu1) 12.2.0")
> ...
> C++ compiler for the host machine: c++ (gcc 12.2.0 "c++ (Ubuntu 12.2.0-3ubuntu1) 12.2.0")
> ...
> ```
> 
> Compared to the default behaviour:
> 
> ```
> $ meson setup -Dbindings=cxx build
> The Meson build system
> Version: 0.63.0
> ...
> C compiler for the host machine: ccache cc (gcc 12.2.0 "cc (Ubuntu 12.2.0-3ubuntu1) 12.2.0")
> ...
> C++ compiler for the host machine: ccache c++ (gcc 12.2.0 "c++ (Ubuntu 12.2.0-3ubuntu1) 12.2.0")
> ...
> ```
> 
> This use of the CC and CXX variables is covered in the documentation:
> 
> https://mesonbuild.com/Feature-autodetection.html#ccache

Right, my point that ccache should be opt-in and not opt-out.
For example, Buidroot project has ccache support (as opt-in).
Andrew Jeffery Dec. 8, 2022, 11:09 a.m. UTC | #8
On Thu, 8 Dec 2022, at 19:57, Bartosz Golaszewski wrote:
> On Thu, Dec 8, 2022 at 5:23 AM Andrew Jeffery <andrew@aj.id.au> wrote:
>>
>>
>>
>> On Tue, 6 Dec 2022, at 05:25, Bartosz Golaszewski wrote:
>> > On Mon, Dec 5, 2022 at 2:22 PM Andrew Jeffery <andrew@aj.id.au> wrote:
>> >>
>> >> Hello,
>> >>
>> >> Based on a recent poke [1] and in-between meetings I've put together a
>> >> WIP series that converts libgpiod's build from autotools to meson. As
>> >> far as I'm aware the meson build supports all the significant options to
>> >> enable or disable features exposed by the autotools build:
>> >>
>> >> * Tests
>> >> * Tools
>> >>   * Interactive gpioset
>> >> * Bindings
>> >>   * C++
>> >>   * Python
>> >>   * Rust
>> >> * Documentation
>> >>   * Manpages
>> >>   * Doxygen
>> >>
>> >> [1] https://lore.kernel.org/all/CAMRc=Mda8UnyH+_GxeX_4MyKd+DPN0BVH5K+J+VWnMJNC1vwTQ@mail.gmail.com/
>> >>
>> >> Meson has pretty good support for handling python and so the patch does
>> >> away with setup.py entirely.
>> >
>> > Eek! No, please do keep setup.py. Autotools too is capable of building
>> > python C extensions on its own and it's what we use in v1 but I want
>> > the python code to be built the standard python way. I actually plan
>> > to post libgpiod v2 on pypi and split out building python bindings
>> > into a separate bitbake recipe in meta-openembedded using the
>> > setuptools3 class.
>> >
>> > So let's keep setup.py and just call it from meson.
>>
>> I've poked at this for a little while and it's not a great experience.
>> Meson's design pushes back against calling out in this way, and I don't
>> really have the motivation to carry on fighting it to make it do what
>> you request. Unless someone else has that motivation, I think there are
>> two options if meson is still desired:
>>
>> 1. Use the meson python support as posted in this series
>> 2. Split out the python (and probably rust) bindings, keeping the
>>    dependency relationships pointing in one direction and using the
>>    language's own package management tooling.
>>
>> Given there's nothing to do in the install phase for rust we don't have
>> as big of an issue there, but it is problematic for python.
>>
>> Let me know which way you want to go, including if you want to abandon
>> meson :)
>>
>
> No, I don't want to abandon it. What is the problem exactly? Is meson
> unable to simply add external commands to its ninja output?

Not as far as I'm aware. I think it's best covered by this policy 
description:

https://mesonbuild.com/Mixing-build-systems.html

There are some things that might make it sound feasible but aren't 
actually appropriate:

1. run_command(): https://mesonbuild.com/Reference-manual_functions.html#run_command
2. run_target(): https://mesonbuild.com/Reference-manual_functions.html#run_target
3. custom_target(): https://mesonbuild.com/Reference-manual_functions.html#custom_target

run_command() isn't appropriate as it executes in the `meson setup`
phase. run_target() isn't appropriate as it disregards any output
artifacts and so has no impact in the `meson install` phase.

custom_target() is probably closest to what is required, but there's a
lot of pain in trying to get the artifacts to line up for correct
deployment in the `meson install` phase. This is exacerbated by the
requirement that setup.py be run from its containing directory in the
source tree. Further, I couldn't get all the options to line up such
that setuptools would relocate its output into meson's own build tree
(and out of the source tree). Here's a not entirely working attempt at
abusing custom_target() to that end:

```
diff --git a/bindings/python/meson.build b/bindings/python/meson.build
index 26f7ff13e0dd..136d10824345 100644
--- a/bindings/python/meson.build
+++ b/bindings/python/meson.build
@@ -3,14 +3,31 @@
 
 python = import('python')
 python3 = python.find_installation('python3')
-python3_dep = python3.dependency()
 
-subdir('gpiod')
+python_build_dir = 'python-build'
+python_install_dir = 'python-install'
+python_include_dirs = '../../include:../../tests/gpiosim'
+python_lib_dirs = '@0@/lib:@0@/tests/gpiosim'.format(meson.project_build_root())
+python_install_cmd = [ python3.full_path(), '@INPUT@', '--no-user-cfg',
+                      'build_ext', '--include-dirs', python_include_dirs, '--library-dirs', python_lib_dirs,
+                      'install', '--root', python_build_dir, '--prefix', get_option('prefix')]
 
-if get_option('examples')
-    subdir('examples')
-endif
+python_env = environment()
+python_env.set('GPIOD_WITH_TESTS', get_option('tests').to_string())
 
-if get_option('tests')
-    subdir('tests')
-endif
+python_setuptools = custom_target('python-setuptools',
+                                 input: 'setup.py',
+                                 output: python_build_dir,
+                                 depends: [gpiod, gpiosim],
+                                 env: python_env,
+                                 command: python_install_cmd)
+
+cp = find_program('cp')
+
+custom_target('python-install',
+             input: 'setup.py',
+             output: python_install_dir,
+             depends: python_setuptools,
+             command: [ cp, '-r', meson.current_source_dir() / python_build_dir, meson.current_build_dir() / python_install_dir ],
+             install: true,
+             install_dir: get_option('prefix'))
diff --git a/bindings/python/setup.py b/bindings/python/setup.py
index ec8f99d4013d..9eddae7466a1 100644
--- a/bindings/python/setup.py
+++ b/bindings/python/setup.py
@@ -1,9 +1,14 @@
 # SPDX-License-Identifier: GPL-2.0-or-later
 # SPDX-FileCopyrightText: 2022 Bartosz Golaszewski <brgl@bgdev.pl>
 
-from os import environ
+import os
+import sys
+
+from os import environ, path
 from setuptools import setup, Extension, find_packages
 
+os.chdir(path.dirname(sys.argv[0]) or '.')
+
 gpiod_ext = Extension(
     "gpiod._ext",
     sources=[
```

This commits a bunch of crimes:

1. Assumes the structure of the meson build directory via the paths in
   python_lib_dirs
2. Adds a chdir() in setup.py to relocate the process out of the meson
   build directory back into the source tree
3. Assumes the chdir() operation in the setup of python_include_dirs
   rather than relying on meson's built-in dependency tracking as the
   inc objects are opaque[1]
4. Hacks the setuptools output back into the meson build directory using
   a crufty target invoking `cp` so meson can locate the artifacts in the
   `meson install` phase 
5. Still doesn't correctly install the artifacts in the end due to
   restrictions on path mangling (can't strip off the parent directory)
   and the fact that we're trying to install an entire tree rather than
   specific files.

[1] https://mesonbuild.com/Reference-manual_returned_inc.html

It might feel like install_data() or install_subdir() could be used
here, but from experiment their behaviour also seems unfit to be used
in this context.

At least, that's what I've experimented with. Maybe others can see the 
way through here, but it really is fighting against the policy linked 
earlier.

Andrew
Bartosz Golaszewski Dec. 8, 2022, 6:48 p.m. UTC | #9
On Thu, Dec 8, 2022 at 12:11 PM Andrew Jeffery <andrew@aj.id.au> wrote:
>
>
>
> On Thu, 8 Dec 2022, at 19:57, Bartosz Golaszewski wrote:
> > On Thu, Dec 8, 2022 at 5:23 AM Andrew Jeffery <andrew@aj.id.au> wrote:
> >>
> >>
> >>
> >> On Tue, 6 Dec 2022, at 05:25, Bartosz Golaszewski wrote:
> >> > On Mon, Dec 5, 2022 at 2:22 PM Andrew Jeffery <andrew@aj.id.au> wrote:
> >> >>
> >> >> Hello,
> >> >>
> >> >> Based on a recent poke [1] and in-between meetings I've put together a
> >> >> WIP series that converts libgpiod's build from autotools to meson. As
> >> >> far as I'm aware the meson build supports all the significant options to
> >> >> enable or disable features exposed by the autotools build:
> >> >>
> >> >> * Tests
> >> >> * Tools
> >> >>   * Interactive gpioset
> >> >> * Bindings
> >> >>   * C++
> >> >>   * Python
> >> >>   * Rust
> >> >> * Documentation
> >> >>   * Manpages
> >> >>   * Doxygen
> >> >>
> >> >> [1] https://lore.kernel.org/all/CAMRc=Mda8UnyH+_GxeX_4MyKd+DPN0BVH5K+J+VWnMJNC1vwTQ@mail.gmail.com/
> >> >>
> >> >> Meson has pretty good support for handling python and so the patch does
> >> >> away with setup.py entirely.
> >> >
> >> > Eek! No, please do keep setup.py. Autotools too is capable of building
> >> > python C extensions on its own and it's what we use in v1 but I want
> >> > the python code to be built the standard python way. I actually plan
> >> > to post libgpiod v2 on pypi and split out building python bindings
> >> > into a separate bitbake recipe in meta-openembedded using the
> >> > setuptools3 class.
> >> >
> >> > So let's keep setup.py and just call it from meson.
> >>
> >> I've poked at this for a little while and it's not a great experience.
> >> Meson's design pushes back against calling out in this way, and I don't
> >> really have the motivation to carry on fighting it to make it do what
> >> you request. Unless someone else has that motivation, I think there are
> >> two options if meson is still desired:
> >>
> >> 1. Use the meson python support as posted in this series
> >> 2. Split out the python (and probably rust) bindings, keeping the
> >>    dependency relationships pointing in one direction and using the
> >>    language's own package management tooling.
> >>
> >> Given there's nothing to do in the install phase for rust we don't have
> >> as big of an issue there, but it is problematic for python.
> >>
> >> Let me know which way you want to go, including if you want to abandon
> >> meson :)
> >>
> >
> > No, I don't want to abandon it. What is the problem exactly? Is meson
> > unable to simply add external commands to its ninja output?
>
> Not as far as I'm aware. I think it's best covered by this policy
> description:
>
> https://mesonbuild.com/Mixing-build-systems.html
>
> There are some things that might make it sound feasible but aren't
> actually appropriate:
>
> 1. run_command(): https://mesonbuild.com/Reference-manual_functions.html#run_command
> 2. run_target(): https://mesonbuild.com/Reference-manual_functions.html#run_target
> 3. custom_target(): https://mesonbuild.com/Reference-manual_functions.html#custom_target
>
> run_command() isn't appropriate as it executes in the `meson setup`
> phase. run_target() isn't appropriate as it disregards any output
> artifacts and so has no impact in the `meson install` phase.
>
> custom_target() is probably closest to what is required, but there's a
> lot of pain in trying to get the artifacts to line up for correct
> deployment in the `meson install` phase. This is exacerbated by the
> requirement that setup.py be run from its containing directory in the
> source tree. Further, I couldn't get all the options to line up such
> that setuptools would relocate its output into meson's own build tree
> (and out of the source tree). Here's a not entirely working attempt at
> abusing custom_target() to that end:
>
> ```
> diff --git a/bindings/python/meson.build b/bindings/python/meson.build
> index 26f7ff13e0dd..136d10824345 100644
> --- a/bindings/python/meson.build
> +++ b/bindings/python/meson.build
> @@ -3,14 +3,31 @@
>
>  python = import('python')
>  python3 = python.find_installation('python3')
> -python3_dep = python3.dependency()
>
> -subdir('gpiod')
> +python_build_dir = 'python-build'
> +python_install_dir = 'python-install'
> +python_include_dirs = '../../include:../../tests/gpiosim'
> +python_lib_dirs = '@0@/lib:@0@/tests/gpiosim'.format(meson.project_build_root())
> +python_install_cmd = [ python3.full_path(), '@INPUT@', '--no-user-cfg',
> +                      'build_ext', '--include-dirs', python_include_dirs, '--library-dirs', python_lib_dirs,
> +                      'install', '--root', python_build_dir, '--prefix', get_option('prefix')]
>
> -if get_option('examples')
> -    subdir('examples')
> -endif
> +python_env = environment()
> +python_env.set('GPIOD_WITH_TESTS', get_option('tests').to_string())
>
> -if get_option('tests')
> -    subdir('tests')
> -endif
> +python_setuptools = custom_target('python-setuptools',
> +                                 input: 'setup.py',
> +                                 output: python_build_dir,
> +                                 depends: [gpiod, gpiosim],
> +                                 env: python_env,
> +                                 command: python_install_cmd)
> +
> +cp = find_program('cp')
> +
> +custom_target('python-install',
> +             input: 'setup.py',
> +             output: python_install_dir,
> +             depends: python_setuptools,
> +             command: [ cp, '-r', meson.current_source_dir() / python_build_dir, meson.current_build_dir() / python_install_dir ],
> +             install: true,
> +             install_dir: get_option('prefix'))
> diff --git a/bindings/python/setup.py b/bindings/python/setup.py
> index ec8f99d4013d..9eddae7466a1 100644
> --- a/bindings/python/setup.py
> +++ b/bindings/python/setup.py
> @@ -1,9 +1,14 @@
>  # SPDX-License-Identifier: GPL-2.0-or-later
>  # SPDX-FileCopyrightText: 2022 Bartosz Golaszewski <brgl@bgdev.pl>
>
> -from os import environ
> +import os
> +import sys
> +
> +from os import environ, path
>  from setuptools import setup, Extension, find_packages
>
> +os.chdir(path.dirname(sys.argv[0]) or '.')
> +
>  gpiod_ext = Extension(
>      "gpiod._ext",
>      sources=[
> ```
>
> This commits a bunch of crimes:
>
> 1. Assumes the structure of the meson build directory via the paths in
>    python_lib_dirs
> 2. Adds a chdir() in setup.py to relocate the process out of the meson
>    build directory back into the source tree
> 3. Assumes the chdir() operation in the setup of python_include_dirs
>    rather than relying on meson's built-in dependency tracking as the
>    inc objects are opaque[1]
> 4. Hacks the setuptools output back into the meson build directory using
>    a crufty target invoking `cp` so meson can locate the artifacts in the
>    `meson install` phase
> 5. Still doesn't correctly install the artifacts in the end due to
>    restrictions on path mangling (can't strip off the parent directory)
>    and the fact that we're trying to install an entire tree rather than
>    specific files.
>
> [1] https://mesonbuild.com/Reference-manual_returned_inc.html
>
> It might feel like install_data() or install_subdir() could be used
> here, but from experiment their behaviour also seems unfit to be used
> in this context.
>
> At least, that's what I've experimented with. Maybe others can see the
> way through here, but it really is fighting against the policy linked
> earlier.
>
> Andrew

I see. I understand that meson doesn't like dealing with other build-systems.

The thing I like about the current autotools setup is that with the
following one-liner:

./autogen.sh --prefix=/tmp/gpio/inst --enable-bindings-cxx
--enable-examples --enable-tests --enable-tools
--enable-gpioset-interactive --enable-bindings-python
--enable-bindings-rust && make -j16 && sudo ./tests/gpiod-test && sudo
./bindings/cxx/tests/gpiod-cxx-test && sudo
PYTHONPATH=./bindings/python
LD_LIBRARY_PATH=./lib/.libs/:./tests/gpiosim/.libs/:bindings/python/
python -B -m tests && cd bindings/rust/; sudo
CARGO_TARGET_DIR=/tmp/libgpiod-rust PATH=/home/brgl/.cargo/bin/:$PATH
/home/brgl/.cargo/bin/cargo test; cd ../.. && sudo
./tools/gpio-tools-test

I can configure, build and test the entire code base while also using
the language specific build tools for python and rust.

I will try to play with your patches and maybe figure it out or even a
close approximation of the current functionality but then again: I'm
not well versed with meson yet. Between it and rust and dayjob my cup
runneth over...

Bartosz