RazrFalcon / resvg

An SVG rendering library.
Mozilla Public License 2.0
2.71k stars 219 forks source link

Investigate cargo-c? #198

Closed ferdnyc closed 4 years ago

ferdnyc commented 4 years ago

The cargo-c project has the laudable goal of making life easier for the consumers (and developers!) of C-API libraries written in Rust, by wrapping a Rust library project's output in the more traditional forms of metadata and packaging familiar to C/C++ developers and system administrators. Specifically, its goal is to take library objects, headers, and etc. produced from Rust code, and publish them as first-class pkg-config citizens.

For those of us downstream of resvg, especially if we're integrating libresvg.so into more traditional C/C++ project structures, this could potentially be a real boon. Most of our dependencies are already being imported using pkg-config, which is natively well-supported in build-configuration systems like CMake.

Having the option of building a pkg-config-defined package for system install sounds like a win, assuming there aren't any downsides or major headaches involved. Worth taking a look-see, perhaps?

RazrFalcon commented 4 years ago

For now, I prefer keeping c-api as a separate crate. Also, resvg depends on C/C++ libraries, so autogenerated pkg-config would not be enough.

We should write 4 confings for each backend, but I'm not familiar with pkg-config.

ferdnyc commented 4 years ago

@RazrFalcon The idea is that the pkg-config metadata gets generated with the details of a specific individual installation of the library — it contains details like the CFLAGS / CXXFLAGS needed to include the headers, and the LDFLAGS to link with the package library(ies) itself/themselves and any shared dependencies necessary, plus any pertinent details on the installed configuration.

For instance, here's everything defined in the librsvg-2.0.pc file:

$ cat /usr/lib64/pkgconfig/librsvg-2.0.pc
prefix=/usr
exec_prefix=/usr
libdir=/usr/lib64
includedir=/usr/include

svgz_supported=true
css_supported=true

Name: librsvg
Description: library that renders svg files
Version: 2.46.4
Requires: glib-2.0 gio-2.0 gdk-pixbuf-2.0 cairo
Requires.private:
Libs: -L${libdir} -lrsvg-2 -lm
Cflags: -I${includedir}/librsvg-2.0

With that info, a build system has all of the information it needs to integrate the /usr/lib64/librsvg-2.so.2.46.0 installed on my system into a build — without even needing to know that the library's path is /usr/lib64/librsvg-2.so.2.46.0. (That's what the linker is for!)

With resvg, a libresvg.so built with cargo build --release --features="qt-backend" and installed in /usr/lib64/ (on my Fedora system, for example) might write a /usr/lib64/pkgconfig/libresvg.pc file containing:

prefix=/usr
exec_prefix=/usr # (presuming rendersvg and viewsvg are installed in /usr/bin)
libdir=/usr/lib64
includedir=/usr/include

release_build=true
qt_backend=true

Name: resvg
Description: ...
Version: 0.8.0
Libs: -L${libdir} -lresvg
Requires: Qt5Core >= 5.6 Qt5Gui >= 5.6 fontconfig
Requires.private: harfbuzz
CFlags: -I${includedir}/resvg  # (Subdir to hold both header files)

(As a quick off-the-top-of-my head start, I'm sure there's wrong info there, and missing info besides.)

A library built on Ubuntu with the raqote or cairo backend(s) would have completely different info. It'd be libdir=/usr/lib/x86_64-linux-gnu instead, there. And perhaps a different include path, certainly different private libs and requires...

As far as the different backends go... I never checked, but I assume multiple backends can't be built into the same library, correct?

If that's the case, there are two choices really:

  1. As you say, write separate configs for each backend, but that's not enough all by itself. They'd need to be named uniquely, too. If you can have qt-resvg and cairo-resvg installed on the same system (theoretically), then they can't both be built as libresvg.so. They'd need to build as libresvg_qt.so and libresvg_cairo.so (or better yet, versioned with an SONAME), so they can be installed alongside each other. Then, yeah, resvg-qt.pc and resvg-cairo.pc could live together in /usr/lib64/pkgconfig/ and point to the proper files for each.
  2. Or, if the user doesn't necessarily care which backend is in use, then a generic resvg.pc that simply documents which backends are available in the installed libresvg.so (like the svgz_supported/css_supported flags for librsvg-2.0) would be more convenient, as they could simply pick up the library under the common name and not need to care about details of backends.

The above two also aren't mutually exclusive. Especially — speaking in a purely hypothetical sense here, just as a way of exploring possibilities — if libresvg.so were to adopt a modular structure where the backends are built as plugin libraries (/usr/lib64/resvg/backend_qt.so, /usr/lib64/resvg/backend_cairo.so), with /usr/lib64/libresvg.so providing the common interface to all of them. All of that can be consolidated into one or more pkg-config files, stored in a well-known standard location, so that any library consumer can pick up all of the necessary specifics for the local installation.

There are other ways to achieve this, of course. CMake projects often export their build config directly into cmake-format Config modules, convenient as they can be imported directly into other dependent CMake projects. But pkg-config is simple and universal, enough so that even many CMake projects will generate .pc files in addition to their FooConfig.cmake exports.

RazrFalcon commented 4 years ago

In case of librsvg, you should look into librsvg.pc.in. The problem is that someone should edit it before install. Basically, it should be preprocessed by the system package manager first.

As for config-per-backend problem, I plan to ditch all backends except raqote anyway, so we can probably ignore this for now.

Also, note that pkg-config should be different for different OS-es too. For example, on Linux the system harfbuzz will be linked, but on macos/Win it will be built from sources.

In the end, there are too many questions and not too many answers. I understand the necessity in pkg-config, but I'm not sure how it should be done. I think we should revisit this issue later, when only one backend will be left.