[Development] Build system for Qt 6

Matthew Woehlke mwoehlke.floss at gmail.com
Wed Oct 31 20:41:49 CET 2018


On 31/10/2018 14.26, Oswald Buddenhagen wrote:
> On Wed, Oct 31, 2018 at 01:09:13PM -0400, Matthew Woehlke wrote:
>> Again, how then does the consuming tool know which qt.core and which
>> qt.gui are compatible with each other? How does it handle the case of
>> finding a qt.core with no matching qt.gui?
>
> as i said below, by the sub-packages constraining their transitive
> dependencies.

That is insufficient.

A.X can be used by itself. A.Y also can be used by itself. However,
mixing different versions of A.X and A.Y is an error.

Even if you propose to solve this by having both A.X and A.Y depend on a
"virtual" A.base target of the same version, you still haven't explained
how to make it so a consumer can find the correct version of A in the
pathological scenario I outlined without a global dependency solver.

Please explain this, not with platitudes, but with a *concrete example*,
i.e. show what the components specifications would look like and what
steps the build tool will take to find the correct versions of the
components.

>> Having a top-level spec provides a well-defined answer to these sorts of
>> problems; if the top-level spec doesn't meet the user's requirements,
>> you ignore the entire thing and keep looking.
>
> that answer might be unnecessarily strict, though. if i build a
> 3rd-party qt module and install it into /opt/myqt, it might be
> compatible with the system qt in /usr. i want to be able to use that
> additional qt module by depending on {qt.{core,gui,3rdpartymodule}}.

Well, then, don't make it part of the "Qt" package. I don't think you
can have it both ways. (If it's a third-party module, why is it a first
party component of the "Qt" package?)

>> I think you are suggesting that finding build requirements has to be
>> done as a single, monolithic pass; i.e. a project must specify ALL of
>> its requirements before ANY attempt is made to satisfy those
>> requirements.
>
> but that's exactly what you do anyway with the syntax above, within the
> scope of a single package. whether the interfaces are explicitly
> aggregated by some top-level file or implicitly by some shared
> properties and mutual constraints is completely inconsequential for the
> user.

Not quite. CPS as currently specified does need bookkeeping, but it does
*not* need global dependency solving. (Although this does, admittedly,
have the disadvantage that it may fail in cases where global solving
might succeed, and thus require more user hand-holding to arrive at an
overall acceptable "answer".)

As there is no global solving, each request to find a package is
considered on its own:

- First, look for a candidate package.
- For each candidate:
  - If that package's arch is incompatible, TTA¹.
  - If that package has a dependency for which an incompatible version
is already "being used", TTA.
  - For each of the package's dependencies, recursively invoke this process.
  - If dependencies could not be found, TTA.
  - If the candidate does not provide the components required by the
consumer, TTA.

(¹ "Try, Try Again"... IOW, make a note of why this package is not
acceptable and continue with the next candidate. If no suitable
candidate is found, these notes may be used to tell the user why a
candidate was rejected.)

The difference is that, once a package is found, it is found, and cannot
be "un-found". The tool does not have to try all possible candidates in
all possible combinations. Also, this process can be dropped into
existing build tools that also look for one package (or component) at a
time. It is not implausible, for example, that I could write a
CLI-compatible pkg-config implementation that uses CPS, or that I could
extend CMake's find_package to look for CPS's and turn them into
imported targets. This means that CPS has the potential to "just work"
with existing build tools, and even existing software using those build
tools. In fact, this is explicitly one of the goals of CPS. A system
relying on global dependency solving can't do that.

(The bookkeeping is that the system can't "commit" to adding
dependencies into the global space until a candidate is accepted, so it
needs a separate "holding space" that it can throw out again if it turns
out a candidate is not viable.)

-- 
Matthew



More information about the Development mailing list