[Qbs] Qbs and debian packaging

Christian Kandeler christian.kandeler at qt.io
Wed Dec 20 11:09:01 CET 2017

On Wed, 20 Dec 2017 04:54:44 +0000
Wookey <wookey at wookware.org> wrote:

> I have a few things to package for Debian which use QBS.
> So I've had to work out how to make QBS fit into debian's build
> concepts and packaging mechanisms. (e.g separate build and install steps)
> That has gone reasonably well (although some queries about best
> practice remain), and I have
> a) a package in debian (which so far as I can tell is the first one using QBS):
> https://tracker.debian.org/pkg/dewalls

I'm having trouble locating the actual project sources. Can you point me to them?

> b) a wiki page on packaging qbs-using packages for debian-style distros:
> https://wiki.debian.org/QBS
> Do please tell me what's incorrect on that page (some probably is - I
> claim no particular expertise). Or just fix the page.

Here are my comments on the wiki page.
- Regarding the separation of build and install steps:
    1) Even when not installing during the build, the install root should
       still be passed: qbs build --no-install modules.qbs.installRoot:<dir>.
    2) I suggest passing the --no-build flag to the install command, for
       extra safety.
- From (I think) qbs 1.9 on the profile no longer determines the name of the
  build directory. Instead, there is now the concept of a "configuration".
  Until (and including) qbs 1.10, this name is (unfortunately) given as
  a simple context-less parameter, like this:
     $ qbs build default // Same as "qbs build", dir is named "default"
     $ qbs build myConfig // dir is named "myConfig"
  From qbs 1.11 onwards, there will be a more sensible syntax:
     $ qbs build config:myConfig
- Regarding the setup: As you have noticed, the current approach to
  storing/reading settings does not really consider anything but a
  "normal user". It'd be great if you could create a task at
  bugreports.qt.io and tell us more about your requirements.
- I find this sentence a bit misleading: "qbs is usually used with
  Qt although in principle it could work for other projects." It might
  be statistically true at this point, but the wording seems to imply
  that using it for non-Qt projects is purely a theoretical thing,
  which is really not the case. I'd prefer something like "qbs is often
  used for Qt projects, in which case the path to qmake [...]"
- Regarding the lib paths: I suppose something along the lines of what
  you show there is the correct approach, though I would not necessarily
  expect project authors to provide debian-specific hooks, but rather
  generic ones. For instance:
      Project {  // Or in some project-specific module
          property string libDir: "lib"
          // ...
      DynamicLibrary {
          Group {
              fileTagsFilter: ["dynamiclibrary", "dynamiclibrary_symlink"]
              qbs.install: true
              qbs.installDir: project.libDir
      $ qbs build project.libDir:lib/$DEB_HOST_MULTIARCH
  Note that "usr" should probably not be part of qbs.installDir, but
  rather is a possible value of qbs.installPrefix.
- Environment variables can be read with Environment.getEnv(). 
  See https://doc.qt.io/qbs/jsextension-environment.html.
- Setting cpp.cxxFlags on the command line should work. Note that your 
  example has a typo (cxxflags with a lower-case f). If that's how
  you entered it, that would explain why it didn't work (though you
  should have gotten a warning).

> It might be nice to have a debian support module in QBS to make stuff
> 'just work'.

You might want to add suggestions there.

> Supporting multiarch

I think I have addressed most of these above. If anything is still unclear, does not work or you simply disagree, please tell me.

> There is also the issue for upstream to detect that this is a
> 'debian-style' build and thus should use multiarch paths. There is
> provision for detecting the OS, but not the distro. So perhaps it
> should be enabled by some kind of flag? cpp.multiarchPaths perhaps?
> Although I expect users would prefer it if the build system just DTRT
> automagically. (Similarly debian almost never wants rpath set (except
> plugins), and does want soVersions and dynamiclibray_symlinks so those
> would be good defaults too)

I would have thought that this sort of package-specific configuration was the job of the debian rules file. Am I wrong?

> Honouring buildflags
> --------------------
> Debian has standard buildflags, e.g. for security settings, like
> hardening flags, and default optimisation. It also has a mechanism for
> enabling debug builds or disabling checks (e.g. for crossbuilding or
> when they are slow), or disabling optimisation. See 
> https://www.debian.org/doc/debian-policy/#debian-rules-and-deb-build-options
> There are various ways to do this in the build process: typically
> some env vars are set to be used in the build, but cammands can be run instead:
> e.g.: CPPFLAGS:=$(shell dpkg-buildflags --get CPPFLAGS)
> https://wiki.debian.org/HardeningWalkthrough gives quite a lot of
> examples for different build systems. 
> I have not managed to make these work as I don't know if there is a
> machanism to use env vars in qbs files. Is there? If not, how should
> such info be passed in? Would we need to make equivalent qbs strings/lists?

I have mentioned above how to get at environment variables, but unless we are talking about a specific debian module in qbs (see the linked task above), this looks like it's the wrong way around. Why not just pass the flags on the command line or put them in some sort of "packaging profile", e.g. via the qbs config command?

> Also I haven't worked out the 'precedence rules' for QBS. i.e if
> cpp.cxxFlags is set in the qbs file, and passed in via a qbs command,
> does the latter take precedence? Is there a syntax for += (i.e. add
> these options to the existing list) ?

The precendence for module properties in decreasing order:
    - command line
    - project files
    - profiles
    - module prototype (i.e. the default values from the module file)
Regarding the list semantics: Command-line overrides wipe out everything else (we might want to think about making that configurable), but in all other contexts lists are merged. In particular, profile contents simply replace the default values from the module prototype and thus get merged with what's in the project files. The latter is probably what you want.

> qbs tried to avoid this sticky area of setting flags, because they are
> toolchain specific, which makes sense, but we need a way of setting a specific set of things. The current dpkg-buildflags is:
> CFLAGS=-g -O2 -fdebug-prefix-map=/home/wookey/packages/cavewhere/dewalls/debian/dewalls-1.0.0=. -fstack-protector-strong -Wformat -Werror=format-security

"-g" -> cpp.debugInformation:true
"-O2" -> cpp.optimization:fast
The rest would go into cpp.cFlags.


"-D" -> cpp.defines
The rest would go into cpp.commonCompilerFlags.

> CXXFLAGS=-g -O2 -fdebug-prefix-map=/home/wookey/packages/cavewhere/dewalls/debian/dewalls-1.0.0=. -fstack-protector-strong -Wformat -Werror=format-security

cpp.cxxFlags for the "rest".

> FCFLAGS=-g -O2 -fdebug-prefix-map=/home/wookey/packages/cavewhere/dewalls/debian/dewalls-1.0.0=. -fstack-protector-strong
> FFLAGS=-g -O2 -fdebug-prefix-map=/home/wookey/packages/cavewhere/dewalls/debian/dewalls-1.0.0=. -fstack-protector-strong

This is for Fortran? We have no fortran module yet.

> GCJFLAGS=-g -O2 -fdebug-prefix-map=/home/wookey/packages/cavewhere/dewalls/debian/dewalls-1.0.0=. -fstack-protector-strong

Is gcj of any relevance these days?

> LDFLAGS=-Wl,-z,relro

cpp.linkerFlags, but without the "-Wl," escape.

> OBJCFLAGS=-g -O2 -fdebug-prefix-map=/home/wookey/packages/cavewhere/dewalls/debian/dewalls-1.0.0=. -fstack-protector-strong -Wformat -Werror=format-security

cpp.objcFlags for the "rest".

> OBJCXXFLAGS=-g -O2 -fdebug-prefix-map=/home/wookey/packages/cavewhere/dewalls/debian/dewalls-1.0.0=. -fstack-protector-strong -Wformat -Werror=format-security

cpp.objcxxFlags for the "rest".

> Does it make sense to add generic qbs names for all those things? 

No, I don't think so (in general; I have not evaluated all of the flags). We introduce convenience properties whenever there is a sensible abstraction that maps to different options on different compilers/linkers.

> What happens when debian changes to a different set of options? 

Again, I was under the impression that it would be the packaging process' job to provide the correct set of flags to the build tool.

> If not, how do we let qbs set what the package asks for (e.g. via
> cpp.cLanguageVersion) whilst also honouring the required debian build
> options?

Not sure what you mean here. There should not be any conflicts.

> Avoiding $HOME use

Also commented on above.

> Crossbuilding
> -------------
> Does QBS support this, or is it intended to support this? I've not
> tried yet. Setting the right toolchain commands: <triplet>-gcc,
> <triplet>-binutils, <triplet>-strip, etc is a good start.

There is nothing special about crossbuilding. Historically, the target architecture has been determined by the setup-toolchain command, but recently qbs has shifted more and more to being self-contained in this regard. Setting cpp.toolchainInstallPath, cpp.toolchainPrefix and qbs.sysroot should generally be enough.


More information about the Qbs mailing list