libsass icon indicating copy to clipboard operation
libsass copied to clipboard

[WIP] Build with Meson

Open SolarLiner opened this issue 4 years ago • 19 comments

Admin edit: Needs https://github.com/sass/sass-spec/pull/1529 to pass CI.

The Meson build system is a build system designed as a Ninja front-end. It is significantly faster than Autotools and (IMHO) much easier to work with.

Meson also natively supports dependencies either as system dependencies (using pkg-config) or subprojects (where Meson will build another Meson-based (or more recently CMake-based) project to use with the current project). This I use in https://github.com/sass/sassc/pull/269 to conditionally build libsass if it hasn't been found on the system.

Usage:

$ meson _build
$ ninja -C _build
$ ninja -C _build install

The conversion hasn't been done by transcribing the Automake script - furthermore not all "build features" have been translated yet:

  • [x] Base sources
    • [x] Contrib plugin
    • [x] SASS_CUSTOM_ALLOCATOR configuration variable
  • [x] Installation (90% Meson, 10% specifying what headers to install)
  • [x] Windows resources
  • [x] ~~Changes to CI to use Meson~~ (Meson will not become primary, no need to change CI)
  • [x] Add a few CI configurations that utilize the Meson build

SolarLiner avatar Mar 08 '20 21:03 SolarLiner

Are you aware of https://github.com/lazka/libsass/commit/f6fe57396b4d7fecd364defe14ea0ab76c107e80?

eyelash avatar Apr 16 '20 11:04 eyelash

I was not, thanks for the pointer. It seems their version is older and differs from mine; I'll merge his work with mine.

SolarLiner avatar Apr 16 '20 16:04 SolarLiner

I manually merged his work with my branch here, keeping what I think is the most "meson-idiomatic" way (i.e. keeping the library dependency as library instead of shared_library to let dependent projects the choice of building a static or shared library).

SolarLiner avatar Apr 16 '20 16:04 SolarLiner

libsass build is so simple that probably we could get rid of autoconf and generate ninja file easily :)

saper avatar Apr 18 '20 12:04 saper

Well, that's what Meson does, generating Ninja files ;) Given how Ninja files are so barebones, I think Meson still adds value (i.e. wrt to conditional generation based on target system, etc.). Furthermore it allows using the repo as subproject in other Meson-based projects (like sassc).

SolarLiner avatar Apr 18 '20 13:04 SolarLiner

Hey @SolarLiner

Thanks for the contribution. I personally have nothing against supporting more build chains, but they tend to add additional maintenance burden. I already have this issue with the MSVC build files. Most other build systems I use (e.g. perl-libsass) already consume https://github.com/sass/libsass/blob/master/Makefile.conf, which I consider the master. I plan to also add all headers and includes to it in the future (see https://github.com/mgreter/libsass/blob/libsass-refactor-snapshot/Makefile.conf).

For my upcoming refactoring I currently have a hackish perl script to generate the MSVC files from a template and the Makefile.conf settings, as it was just to tedious to keep them manually in sync. I can try to backport this to current LibSass so you/we could generate the necessary inputs for such a meson build? I doubt meson can directly consume Makefile.conf?

Without such an automated generation method I would honestly be very reluctant to merge another build system into LibSass, since I know we would miss to update it at some point.

mgreter avatar May 01 '20 11:05 mgreter

Given that the current build system is Autotools the possible end goal here would be to make Meson the primary build system of the project. It supports generating Visual Studio and XCode projects on top of Ninja files (which solves the issue of keeping the MSVC projects in sync), and has an API to query the build project itself (with meson introspect or by reading the files at [build dir]/meson-info/intro-*.json, cf. documentation).

Meson is also built to bridge (supported) languages together, meaning that integrating this with the python bindings would be as simple as adding this project as a subproject in python-libsass and using it as a PEP 517 build system to handle everything.
In the case of Perl, while there is no direct support one can get away either by having Meson as a build system anyway and have it call Perl scripts to take care of the different parts of the building and packaging, or by having Meson introspect this project to get the proper targets for inclusion with Perl (I do not know how Perl handles FFI so I can't offer more help here).

And, as I said before, By having Meson in here mean we can directly plug this project with sassc without any glue.

Of course, this requires making Meson the primary build system of the project, which means learning and working with a new build system for those who don't know about the project, so I do understand not wanting to make the change. However I do think the value Meson adds is well worth the effort of switching to it.

SolarLiner avatar May 01 '20 12:05 SolarLiner

I'm sorry, but I'm not willing to switch the main build system! The Makefiles work OOTB on windows and linux for me for multiple chains without any additional dependency. I don't mind to support another build system, but the main setup will stay as it is until somebody else takes on the full burden to support and develop LibSass.

mgreter avatar May 01 '20 12:05 mgreter

Sorry if that might was a bit rude, but until a build system has proven to be very well and stable, I'm reluctant to even consider switching the main build system, that has been tweaked and tested for years now. We had similar approaches with CMAKE (https://github.com/sass/libsass/pull/292). So please, if you want to get LibSass to build with meson, first try to derive from said Makefile.conf. If meson turns out to be superior to all other approaches, I'm happy to consider a switch.

What I meant by "deriving" from Makefile.conf via the mentioned perl script would be to generate the file you have at https://github.com/sass/libsass/pull/3073/files#diff-9fbb37ad64805c2da3889d419806cd51. If you checkout https://github.com/sass/libsass/blob/master/win/libsass.targets you see what the perl-script is actually generating that from https://github.com/sass/libsass/blob/master/Makefile.conf => https://github.com/mgreter/libsass/blob/libsass-refactor-snapshot/utils/build-skeletons/libsass.targets. This script only needs to be run once whenever we add new compilation units, headers etc. Autotools can directly consume this Makefile.conf, so it doesn't need any "fancy translation" done by the perl script. I know that a lot of build tools are out there to solve this, but I want to keep this as dependency free as possible, but I don't mind adding more options ;)

mgreter avatar May 01 '20 12:05 mgreter

It's okay, I completely understand, I just wanted to state the goal with this PR and my vision. In the meantime Meson can sit with other build systems, but I am confident that it will prove itself worthy of switching. :)

I guess src/meson.build can indeed be generated by the Perl script, in fact since Meson will come as a secondary build system, it only makes sense. I do not know any Perl however, but I think the structure of the file is easy enough for you to write the necessary Perl code to generate it.

As for dependencies, I'm not so sure I agree with "minimal dependencies". Autotools a few of them, so it's just a matter of opinion. With Meson, you just have to pip install meson ninja and you're ready to go, as far as the build system is concerned. See also this entry from the Meson docs about this very issue.

In any case, this probably means also not touching any CI files. I'll remove that from the PR and complete the SASS_ALLOCATOR option and undraft the PR.

SolarLiner avatar May 01 '20 14:05 SolarLiner

I have made the PR ready for review, however the Perl script to generate src/meson.build isn't there yet, perhaps @mgreter can make it as I have no Perl experience.

SolarLiner avatar May 02 '20 18:05 SolarLiner

Thanks @SolarLiner, I made a PR for the generator script at https://github.com/sass/libsass/pull/3093. Amended your initial post so CI will pickup the PR pending at sass-spec to make CI pass.

mgreter avatar May 02 '20 19:05 mgreter

@SolarLiner can you add a few additional CI jobs that utilize the meson build? Ideally at least one for each OS. We probably will disable most of them again once this is merged to keep regular CI fast, but for this PR I would like to see at least a few combinations with green light on CI using meson :)

mgreter avatar May 02 '20 20:05 mgreter

I just tested this shortly locally, and so far it seems to work. Just saw that the dll produced is 32MB, one by mingw is only 3MB?

Please also incorporate some documentation into docs/build.md. Here are some of the main points of interest (at least for me).

  • How to create release vs debug builds (optimization flags).
  • How to create a static vs shared library for libsass.
  • How to use clang instead of gcc (or any other compiler)
  • Can we generate MSVC project files via meson?
  • Can we run the spec test suite via meson?
  • How do you determine libsass version via git?
  • How can we trigger "gprof" or other profiling?
  • How can we trigger "asan" or other memory checks?
  • System-wide installs (pkg-config)?

I understand that probably not all of these can be answered for a first version. Some are also not supported via autotools-build. But these are some of the use-cases I have for the main build chain 😄

mgreter avatar May 04 '20 01:05 mgreter

All of this points, bar the "getting version from git" are supported natively by Meson. I'll write about those in the docs, but I believe the Meson docs are a very good centralized source of documentation.

Wrt. the git versinoning issue, it's because Meson wants to be the ground truth about the project's metadata. As such, you specify the version in the project() call, and can't modify it later, and the call to project() must be the first statement of the root file. There is [vcs_tag()](https://mesonbuild.com/Reference-manual.html#vcs_tag) but it doesn't replace the version available at meson.project_version(), it only configures a template file to be replaced with the git hash (or tag).
There are workarounds but nothing explicitely supported.

Anyway, should I write extensively about Meson in the docs or do links to the relevant parts of the Meson docs suffice? I think the latter would help reduce maintenance as the links would always point to the updated docs. On the other hands it feels like redirecting the user around...

SolarLiner avatar May 04 '20 09:05 SolarLiner

I havent't tested this yet, but is there a possibility for Meson to build a static (.a) library but with PIC symbols included? I have a quick and dirty workaround for this in my BSD makefiles:

https://github.com/saper/ports-exp/blob/932e7be6c2e5f3e23817a6657e8e5d71abb665e7/textproc/libsass35/Makefile#L32-L36

I think it is possible with autotools somehow.... it would be nice to have it out of the box.

The reason for this is to slurp libsass statically into another shared module (node-sass binding).

saper avatar May 04 '20 20:05 saper

I have changed the build script a little to more easily select from the 3 build systems supported by the project now, I'm testing only on Linux now, and will expand to OSX next, and then dive into the AppVeyor docs to do the same on that platform...

SolarLiner avatar May 08 '20 14:05 SolarLiner

I havent't tested this yet, but is there a possibility for Meson to build a static (.a) library but with PIC symbols included?

According to the docs, simply configure the build with -Db_staticpic=true and all static libraries will be built as position independent.
Since the libsass target is generated as a library, this allows you to choose whether you want that as a static or as a shared library (or both); therefore you need to specify --default-library=static to build libsass as a static library.

Tl;DR: meson _build --default-library=static -Db_staticpic=true && ninja -C _build should do the trick.

SolarLiner avatar May 08 '20 14:05 SolarLiner

I'll answer those questions from @mgreter here as a placeholder for when I'll write the docs fully (though I need directions on whether to write docs self-contained at the risk of them becoming outdated, or if links to the Meson docs are allowed (which would require the user to navigate back and forth)).

How to create release vs debug builds (optimization flags).

By default Meson generates debug builds. There's the --buildtype option which will enable different presets of optimization and debug symbol generation. You can set --buildtype=debug explicitely, or use --buildtype=release to enable optimizations. There's also --buildtype=debugoptimized which leaves debug symbols but also enables optimizations.

You can also explicitely pass the --optimization option to tune the compiler to the desired level (0..1, g and s) (source).

How to create a static vs shared library for libsass.

Libraries declared with library() in the build file can be compiled as either static or shared libraries (or even both). For this project this is all libraries except memory, which is declared to always be a static library.

The switch is --default-library=<static/shared/both> (source).

How to use clang instead of gcc (or any other compiler)

You can choose the compiler with the CC and CXX environment variables, and linkers with the CC_LD and CXX_LD environment variables (source).

Can we generate MSVC project files via meson?

Meson has a Visual Studio backend (as well as an XCode backend), selectable with --backend=<ninja,vs,vs2010,vs2015,vs2017,vs2019,xcode> (source).

Can we run the spec test suite via meson?

I have not included any tests to be run by meson yet, but it is definitely possible. Meson even has TAP support for more granular reporting of errors (source).

How do you determine libsass version via git?

Meson has the vcs_tag() function in build files that allow generating or configuring a source file with VCS information. However, it does not support setting the VCS tag as the project version, as Meson's philosophy is to be the ground truth over metadata and to be usable without a VCS enabled (i.e. repo downloads).

How can we trigger "gprof" or other profiling?

There doesn't seem to be an implemented feature of Meson, but we can pass the -pg flag either through CFLAGS/CXXFLAGS or by creating an option in the build file that adds the flag to the compiler (source, example).

How can we trigger "asan" or other memory checks?

Configure the build with -Db_sanitize=address (source, source (possibles values of b_sanitize)).

System-wide installs (pkg-config)?

The build file generates and installs a .pc file for the library. You can set the installation prefix at configure with --prefix=<path> and a destination folder (i.e. for packaging purposes) with the DESTDIR environment variable when running ninja install.

SolarLiner avatar Jul 16 '20 16:07 SolarLiner