Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

RFE: BuildRequires generator #104

Closed
ignatenkobrain opened this issue Dec 2, 2016 · 55 comments
Closed

RFE: BuildRequires generator #104

ignatenkobrain opened this issue Dec 2, 2016 · 55 comments
Labels

Comments

@ignatenkobrain
Copy link
Contributor

In many of languages (rust, python, golang) BuildRequires are normal Requires + Test deps. It's always (in many of cases) possible to get names of packages in advance, before building.

Since Requires are dynamic, BuildRequires also, but nowadays you still have to specify it manually and check those after each update of package. Would be nice to implement support for generating BuildRequires.

Usually such generator will require some additional package to be installed (cargo, python), so we will need to introduce someting like BuildRequires(pre) or BuildRequires(source) which should be installed for building SRPM. Having this is also beneficial for normal process since you don't need to modify buildroot all the time in order to have some macro.

@pmatilai
Copy link
Member

pmatilai commented Dec 2, 2016

For the record, there are a number of (other) build-requires that could be relatively easily collected automatically:

  • (de)compression utilities needed for processing sources + patches
  • utilities needed for patching (if any), for example %autosetup -S git would optimally pull in git as a build dependency
  • bash --rpm-requiresis likely to work fairly well with %prep / %build / %install / %check because unlike normal shell scripts, there are few conditionals to throw it off

@ignatenkobrain
Copy link
Contributor Author

ignatenkobrain commented Dec 2, 2016

utilities needed for patching (if any), for example %autosetup -S git would optimally pull in git as a build dependency

I submitted bug about this some time ago and it was closed as WONTFIX ;)

@mlschroe
Copy link
Contributor

mlschroe commented Dec 2, 2016

Build require generators will not work in the open build service...

@ffesti
Copy link
Contributor

ffesti commented Dec 2, 2016

There clearly is some chicken - egg problem here as one will likely need some tools to determine the dependencies for the build. So there needs to be a multi step process:

Getting the BuildRequires that are needed to determine the dynamic Buildrequires
Generating the SRPM with all the BuildRequires
Get all BuildRequires.
Building the Binary RPMs.

This is clearly not possible with most of the existing build systems. So changing this will require changes to basically all of them. We would probably need to add something like BuildRequires(srpm) and add a new section in the spec file that can be used to create the dynamic BuildRequires.

Another question is on what files this BuildDeps generator/section should operate. Obviously executing %prep before hand would be very helpful for many use cases.

The next question is whether the Dependencies should be generated automatically - by scripts provided by rpm and run in the background or if packagers would need to write their own section generating the dependencies - may be by executing some rpm provided scripts.

@cgwalters
Copy link
Contributor

I think the solution is to not try to improve RPM here, just do what everyone in the world that hit this has done: move to generating specs via a better build system.

Examples:

And there's the vast existing set of dynamic language -> spec tools, like the venerable cpan2rpm
and this gofed one for golang in fedora.

There are obviously challenges to this route too, like if you support multiple generators then they need to learn how to interact for dependencies. However, I think a lot of those issues can be solved by having everything use provides rather than package names for example. (And this would require generating provides for everything)

@nim-nim
Copy link

nim-nim commented Feb 11, 2018

@ffesti You're complicating things unecessary, rpm does not distinguish between manual and dynamic provides, there's no need to distinguish between manual and dynamic BuildRequires either

In a dynamic BuildRequires world, the spec still contains static BuildRequires (sufficient to pull in the build root whatever is necessary to compute the dynamic BuildRequires) and the packager executes at the end of %prep whatever command or commands are appropriate to compute those BuildRequires

That allows the packager to "fix" the project state that serves as a base to the computation, to massage the command output if needed, etc

All it needs is an rpm entry point that pipes a string or a string list into the BuildRequires list during %prep, for mock or whatever to read the final BuildRequires state at the end of %prep and complete the build root as needed

If you want maximum flexibility you can even forget about %prep or not %prep, and do it with two spec verbs:

  1. one verb that accepts piping new BuildRequires (one per line, without the BuildRequires prefix) or alternatively as arguments
  2. another verb that basically kicks the build system and tells it "add to the build root all the BuildRequires not already present"

and let packagers define the best dynamic BR strategy over time. Adding BRs just in time would simplify a lot of ifdefing in %build and %check for example: just request the BRs in the optional section instead of trying to sync several optional sections in different parts of the spec

@praiskup
Copy link
Member

If we had %build_requires -f <script> section (to be handled post %prep time),
-- piping out the additional build-requires line-by-line -- I don't see any reason
why RPM should feel blocked to implement this. Likely the SRPM won't be
parseable by older RPMs, likely old build-system won't know how to handle
them, but that's non problem.

So one thing is definition of this feature (done on RPM side), and the second thing
is implementing this feature in build-systems. From the build-system POV, there are
IMO two ways how to handle this (since the new action needs to be done
right after %prep section):

  • either split the build into two parts, which is not easily doable in RPM nowadays AFAIK
  • execute the %prep twice, first time solely for the purpose of BuildRequiresAction...

I don't think the former is needed at least at the beginning.

To me, I think we only need a volunteer to implement this in RPM (PoC pull request).

@nim-nim
Copy link

nim-nim commented Feb 12, 2018

@n3npq That's why not trying to force a specific strategy when there is so little previous art in rpm land to draw on, and providing a verb that the packager can use to tell the buildsys "I am finished computing new BRs, take those into account then continue from the next spec line" may be best

@praiskup
Copy link
Member

praiskup commented Feb 17, 2018 via email

@praiskup
Copy link
Member

praiskup commented Feb 17, 2018 via email

@praiskup
Copy link
Member

praiskup commented Feb 17, 2018 via email

@nim-nim
Copy link

nim-nim commented Feb 17, 2018

Contrarian examples are trivial to devise. Consider an autoconf based generated file that builds if (and only if) certain files are detected. None of those BuildRequires can be automated and generated during a spec file parse with a pipe/file redirection.

That's more or less the Go system right now, computing deps is just a special compiler mode where it dumps what it will need instead of building the project (it is slowly evolving as a separate command, but still, it will continue to call Go compiler innards behind). So that depends what you call "build" if "building" means calling the compiler yes that's building, my definition of building is producing files.

I don't think it needs more than one phase at present though.

Repopulating a buildroot with additional "dynamic" BuildRequires and restarting an rpm build either needs to teach rpm how to install additional packages as a side effect of parsing,

It only needs to teach rpm to:

  • pass dynamic BRs requests to the buildsystem,
  • bomb if the BuildSystem is unable to provide them (and in case of no build system, bomb if the dynamic BRs are not already present).
  • continue otherwise

There is not need to add BR provisioning logic to rpm itself, that has not been its role for quite a long time.

or needs to be handled by dep solvers that populate the build root (entirely out of scope for the current rpmbuild implementation) before rpmbuild is invoked.

I think everyone would prefer the current responsibility separation where rpm does the parsing and building and the build system does the provisioning

There is currently no known way other than "works" to verify that the BuildRequires passed to the depsolvers that populates the build system used.

You're over-engineering things. Builds can fail with static BR too, a requires system has never promised builds will succeed, only that the material they should need is present at build time.

Only looping to test that the BuildRequires are sufficient.

That's why I proposed a two-command compute-BR/populate-BR system, that makes incremental dynamic BR composition possible, and places the packager/language integrator in command of when dynamic BR population is needed, and whether it is needed once or several times

(everyone will understand that the populate-BR is expensive in build time, so the packager's interest will be to batch as much compute-BRs as possible to limit populate-BRs calls)

Of course you can make the looping implicit, force the packager to declare all the compute-BR engines
(a project can include code in several languages) before a specific step in the spec, and then at this step loop

  • execution of all compute-BR
  • populate-BR

till first step produces no dynamic BR not computed before.

That's a more brute-force approach. It will possibly be simpler to use by packagers, at the expense of increased build times (because the compute-BR logic will necessarily be simpler and more brutal too) and making some use-cases like declaring the BRs needed by unit tests in %check impossible.

Hence any attempt to automate BuilRequires MUST have a persistent incremental store from which the automagically generated BuildRequires can be retrieved on the final build.

"final" build is a murky concept when a project can include code in several languages, and %checks can include many tests which are all small build units. I'd rather have a system that either declares the end of %prep or %prep-br the final limit after which no BR resolving occurs, or no rpm-enforced limit with an explicit populate-BR command that can occur in all spec sections that need new BRs

Now as you astutely noted:

  1. adding BRs is necessarily incremental (dynamic BR removal is too horrid to contemplate and all the systems I know are additive, not substractive, at worst the build commands know how to ignore stuff it doesn't need or want)
  2. rpm needs to remember the result of the last compute-BR call to
  • abort the loop when no new BRs are produced in case of implicit looping
  • return a "you already asked this" error code from populate-BR if you go the explicit call route

@nim-nim
Copy link

nim-nim commented Feb 17, 2018

Theoretically yes, but I don't think we have to go that far. Btw. the set of build-requires wouldn't be "constant" for each build of particular package and that would be big -1 from me (at least if you consider bootstrapping scenario where everything isn't completed yet). Whatever the calculated build-requires set would be, I wish it was constant for each build, regardless of what's in buildroot at that time.

I'm pretty sure it will be constant, if only because once you go the dynamic BR route, the initial build root is likely to be sparse with few things that can influence the build.

But even if it weren't, is that's such a big deal? The set of BRs is already not constant – the only constant part is the first level explicitly declared BRs, but those can pull in different second level BRs depending on the repos state or depending on their own version. And a lot of the weird effects in Go stem from their attempt to remove second-level BRs from the picture (in a lala-lala dev world no rpm-style dependencies — no rpm dependency hell, when if fact it only moves the tricky effects to another point)

@nim-nim
Copy link

nim-nim commented Feb 17, 2018

Maybe I'm missing the point of the issue (OP to decide), but I think this has real and pretty trivial engineering solution for some languages: - distribution provides heuristic for language Foo in foo-build package - package Baz puts 'foo-build' into build requires - package Baz adds "%build_requires --script %foo_analyzer" to declare that the buildsystem should attempt to generate build requires after %prep with %foo_analyzer script - this brings new file/value in generated SRPM to let build-system know - mock finds %build_requires section in SRPM, so it - does installroot + and installs BuildRequires as usually - runs %prep - runs %foo_analyzer from %build_requires - runs the rest of the build

That would work too, as long as you take into account a package may declare several %build_requires s and you probably need to loop their execution with BR population till there are no new results. That's an analog of my "implicit looping".

Replace script with --command to make the people that reimplement everything as binaries happy

And make sure command can take arguments :).

So maybe just this ? Simpler is better

  1. Packager adds static BRs for everything needed to compute dynamic BRs and not included in the package sources

  2. Packager inserts the following calls in his spec header

%buildrequires <command1 with arguments> 
%buildrequires <command2 with arguments>

(commandX can be a macro, a script in the package archive, a system command, maybe even a %{sourceX}? Our should %{sourceX}s be deployed in %prep?)

  1. The buildsys populates static BRs as usual

  2. %prep is executed as usual

  3. The buildys executes automatically after %prep (forgive my atrocious pseudocode)

do
 DynamicBRs=nil
 for each BR_command do
   DynamicBRs += BR_command_output
 done
until install DynamicBRs returns "nothing to do"

Step one and 2 will probably be automated in language-specific macros such as %gometa for Go in Fedora

@nim-nim
Copy link

nim-nim commented Feb 17, 2018

Agreed. IMO rpm should just speficy "script" which prints build-requires to standard output. That can/could be: %build_requires # the script content /bin/awk ... do something or %build_requires -f or %build_requires -s . this way you don't have to adjust depsolver, only the build-system.

The main drawback being that if rpm is completely unaware of this, it can not abort local builds with a sensible error if the local system is missing one of the dynamic BRs

@praiskup
Copy link
Member

praiskup commented Feb 17, 2018 via email

@nim-nim
Copy link

nim-nim commented Feb 17, 2018

I'm not sure calculating "fixed point" for build requires dependency graph is required in the first place. Having BuildRequires and then single-step dynamic build requires would be powerful enough I think, and easier to implement from buildsystem pov.

To be honest, I don't think I need looping for Go, but I'm not sure I won't need it either (the Go dep situation is evolving fast those days as things have reached a "can't continue like before" point).

The "correct" future-proof way to do it is looping (for IT definitions of future-proof, that is). It is so hard to implement ? You know you've reached the end of the loop when the last dynamic BR install command does nothing.

do
 DynamicBRs=nil
 for each BR_command do
   DynamicBRs += BR_command_output
 done
until install DynamicBRs returns "nothing to do"

Slight benefit would be that packagers would be much less motivated to do very complicated magic in build-depsolving.

I'm not fearing packagers as much as upstream language ecosystems. Sure, some packagers will write their own custom BR logic but most major languages will just call upstream language tools in %buildrequires with a light translation layer to transform upstream component names and version constrains in rpm provides and constrains

(%buildrequires without _ please, so it's consistent with %{buildroot} and other historical rpm bits)

With git clone so easy nowadays I'm pretty sure some of the language upstreams will bake multi-phase BR solving in their tooling sooner or later (if not already done).

Asking them for a mode where the tooling does not download anything during BR computation and delegates to the package buildsystem is doable. And actually, just blocking downloads will usually result in a partial BR answer since the tooling can not compute on things not available yet. So it gets things done without annoying language people with rpm limitations.

Asking language people to rethink their BR logic so it's single phase is a lot more difficult. They are usually convinced their native tooling is better than Linux packages

I'd rather not have a brand-new dynamic BR system that lasts a month before they obsolete it.

@praiskup
Copy link
Member

With git clone so easy nowadays I'm pretty sure some of the language upstreams will bake multi-phase BR solving in their tooling sooner or later (if not already done).

Seeing an existing example would really help to justify the additional complexity.

Such problem smells like equivalent to bootstrapping distro from scratch problem. And what
I see from the recent movement out there (non-RPM world), bootstrapping is rather ignored
in language stacks since if you build something once, you don't have a reason to bootstrap
again. That said, I don't view automatic bulid-requires generator as something difficult to
hack on, maintain, or use; the "looping" would certainly go against simplicity. Anyways, no
strong disagreement here :-)

@nim-nim
Copy link

nim-nim commented Feb 17, 2018

Seeing an existing example would really help to justify the additional complexity.

As I said, I don't have such an example (and hope won't have for some time). It's just the kind of things I see upstreams do.

Such problem smells like equivalent to bootstrapping distro from scratch problem. And what
I see from the recent movement out there (non-RPM world), bootstrapping is rather ignored
in language stacks since if you build something once, you don't have a reason to bootstrap
again.

Since most Go projects do not use dynamic libraries, setting up the deps of a non-trivial project is similar to bootstraping, yes. They tried to ignore lots of things and it just moved the complexity at the project level. That's why the soonest it is all plugged in rpm where there is know-how to deal with software dep complexity, the better

the "looping" would certainly go against simplicity. Anyways, no strong disagreement here :-)

As long as you're ready to add it later, I don't care much (only that I'm quite sure that if it's required we'll manage to get EL stuck on the feature-free, and pay the price in "can not be packaged for EL" later). As I've shown you don't even need to maintain a dynamic BR state to loop, just to test in the install does something

@nim-nim
Copy link

nim-nim commented Oct 20, 2018

Anyway, to put things back into perspective. Since I spent a one more year trying to progress on the subject. When you remove all the fluff and optional feel-good additions, the basic raw need is very simple.

The constraints of a BuildRequires generator are the following:

  1. you need to unpack sources
  2. you need to fix those sources if they have problems so the generator gives accurate results (otherwise, GIGO)
  3. you need to run the generator
  4. you need to give the generator output to the rest of the toolchain

So concretely you can not run a generator before the end of some processing that does

  • unpack
  • patch
  • remove broken code
  • put files in the right place

Notice something? That's pretty much the definition of %prep. Anyone who thinks the contrary, is just lucky enough to have upstreams that release perfect sources, that need no fixing before the BuildRequires generator is run.

So to run any BuildRequires generator you need a %prep bis. And it better do the same thing as the current %prep, because computing BuildRequires on a code state, which is different from the code state fed to %build, is unlikely to produce happy results. (All this was not actually that obvious when I started this road, it took many refactorings and cleanups before I realized my BuildRequires computing logic was replaying %prep with BuildRequires computation at the end).

All the solutions that pretend computing BuildRequires without executing %prep in rpmbuild, just redefine a %prep, with its associated requirements, somewhere else. At best it just duplicates needlessly the specfile %prep. At worst it is slightly different (which will eventually result in bugs at %build or %check stage). And it's all hidden behind abstraction layers that obfuscate it's just a %prep stage, nothing more and nothing less.

So, with a year of hindsight, I've simplified the requirements to

  1. run classical %prep
  2. run the commands that compute BuildRequires (either as part of %prep or in a new %reqs section between %prep and %build). Those command can loop or do all the things discussed before in this ticket, rpm need not be aware of it.
  3. read the output and install the result in the build root before %build if you're running in one of those (ie mock).

So, it mainly needs to define how the BuildRequires compute engine must present the computed deps to the rest of the tooling. The simplest way is probably just to generate a file that contains standard BuildRequires: lines. And have a standard rpm tag or variable that gives the location of this file in the build root.

The moment when the rest of the tooling must parse the file is just before %build .

And optionally, as a further enhancement, because some people like to run rpm -qp on srpms

  1. either define a query mode that executes everything before %build
  2. or define an intermediary rpmbuild -bx stage that outputs something srpm-like, with the result of
    everything before %build:
  • either a pseudo-srpm that contains the generated BuildRequires file in addition to sources patches and spec file,
  • or the same that contains the output of the generated BuildRequires files in its headers.

Does not matter as long as you can run rpm -qp on the result.

You can even avoid the need of a define a separate rpmbuild -bx mode if you create a %reqs stage and make rpmbuild -bs progress to the %reqs stage by default when present in a spec. (That would seriously annoy people who do not have the deps needed by %prep+%reqs and just want to generate a classical srpm. But this is a change, and changes will always annoy someone, no matter what enhancements they bring).

But, the second part is an enhancement. Something some people feel strongly about, but is not necessary to produce working packages. The basic need one can not avoid, only hide behind abstraction layers is:

1. run classical %prep
2. run the commands that output BuildRequires in a file before %build
3. read the file and install the result before %build

So the most minimal changes required to integrate it all cleanly in rpm + mock are:
1 standardise the tag or rpm variable giving the BuildRequires file location
2. have mock process this file before %build

@ffesti
Copy link
Contributor

ffesti commented Oct 25, 2018

I agree that %prep is needed to do this. But there is another thing to think about:
Right now BuildRequires are the Requires of the SRPM. So the procedure is to build the SRPM and then use its Requires to set up the build root. So you do not have any Requires for building the SRPM. And indeed the SRPM can be build without any additional tools and libraries.
But for determining the dynamic BuildRequires (or even just running %prep) you will need additional tools. So the question is where do you get the Requires from for these.
So you probably need to do:

  • Build SRPM
  • See that it contains dynamic BuildRequieres
  • Rebuild SRPM with BuildRequires(pre) installed running %prep and the dynamic Buildrequires scripts
  • Setup the build root with the SRPM and build the binary rpms

@praiskup
Copy link
Member

But for determining the dynamic BuildRequires (or even just running %prep) you
will need additional tools. So the question is where do you get the Requires
from for these.

You have static BuildRrequires for this puprose. Those should be installed first, so
the dynamic build requires can be calculated. If I remember correctly, somebody
suggested to do "fix-point" calculation (install dynamic BR in loop, till
something gets installed - but I doubt this is needed in real world).

@praiskup
Copy link
Member

Of course, the SRPM format needs to be updated first; so we can store the dynamic build requires "unexpanded" there.

@ffesti
Copy link
Contributor

ffesti commented Oct 25, 2018

Well, the issue here is what is the procedure to build the package. There are two options:
The one I sketched above with a two stage SRPM build. You could use BuildRequires(pre) or something similar to setup the second stage SRPM build. (You probably can replace the first stage by a pure parsing pass.)
The other option is to spit out the additional requirements during the build of the binary packages by executing a %buildrequires script between %pre and %build and hope the build system is capable of installing those on the fly (or restarting the build afterwards). This seem much more fragile and dangerous as it requires root operations being triggered from a non root build.

Overall the static Buildrequires are not quite the same as the Requires needed to calculate the dynamic BuildRequires and they should be kept separate. Especially for the cases where there is no script for dynamic build requires.

@nim-nim
Copy link

nim-nim commented Oct 25, 2018

@ffesti

I thought the same thing as you at first but you don't absolutely need the separate BuildRequires syntax. You can perfectly limit static BuildRequires to the part needed to compute additional BuildRequires before %build and just add any static BuildRequires needed for %build or %check to the output of this computation.

(technically that's just putting those BuildRequires in an expand, and cat-ing >> the result to the dynamic BuildRequires file. Ugly for those that have to do it manually, if not hidden within a macro).

So, from a technical POW, sure the separate syntax would be nice to have, but it's not absolutely required.

@nim-nim
Copy link

nim-nim commented Oct 25, 2018

@praiskup

If I remember correctly, somebody
suggested to do "fix-point" calculation (install dynamic BR in loop, till
something gets installed - but I doubt this is needed in real world).

That was me and after playing with the concept for a year I agree you can live without it in the real world. A single install transaction before %build is sufficient.

@hroncok
Copy link
Contributor

hroncok commented Oct 25, 2018

One thing that concerns me is that now when srpms require certain packages, this information is visible from the source repo. I can run repoquery to check that nothing requires what I intent to retire etc. If we generate those, we should make sure the srpms we put in the source repo have the info in them available.

@praiskup
Copy link
Member

praiskup commented Oct 25, 2018

That's interesting thing from the policy POV, thanks. That would certainly be an issue for FESCO before allowing us to use that in Fedora. But I don't think it is necessarily a blocker for the actual implementation in mock/rpm.

@nim-nim
Copy link

nim-nim commented Oct 25, 2018

One thing that concerns me is that now when srpms require certain packages, this information is visible from the source repo. I can run repoquery to check that nothing requires what I intent to orphan etc. If we generate those, we should make sure the srpms we put in the source repo have the info in them available.

That's pretty much what I wrote in
#104 (comment)

if you want to use repoquery this way, you need either to redefine srpms as "current srpm + result of %buildrequires" or create some other intermediary file between current srpms and rpms which is "current srpm + result of %buildrequires" .

And then just output this file in mock/copr/koji, store it in repos the usual way, query it with repoquery, etc. Since the solution proposed by @ffesti does not require any special new rpm header, as long as you output this file, all the tooling that will index or query it need not be aware some of the BuildRequires in rpm headers have been generated dynamically.

Or, if I misunderstood @ffesti, and he intends to go the whole way with a new header, it does need slight adaptations in createrepo and dnf to index and query BuildDependencies. Slight because the processing is exactly the same as for BuildRequires.

But, as @praiskup wrote, that's all enhancement land, the repoquery part is not required to start creating clean packages that use BuildDependencies.

@xsuchy
Copy link
Member

xsuchy commented Oct 26, 2018

The rpmbuild side of things can probably be done quite easily. No idea about the build system stuff.

I actually like this idea and as maintainer of mock, I can promise implementation of this in Mock.

@xsuchy
Copy link
Member

xsuchy commented Oct 26, 2018

I can run repoquery to check that nothing requires what I intent to retire etc. If we generate those, we should make sure the srpms we put in the source repo have the info in them available.

I can imagine rpmbuild -bs --try-really-hard which would:

  1. generate src.rpm the classic way
  2. run %prep and %buildrequires
  3. generate new src.rpm with injected requires from %buildrequires

I can make support in mock for that and we can make this default in Koji, so all builds from Koji will have full set of buildrequires and you can still repoquery them.

I am not afraid about Koji/Mock, but what about OBS @mlschroe ?

@ffesti
Copy link
Contributor

ffesti commented Oct 26, 2018

Well, the result of %buildrequires could be added if the srpm is build side by side with the binary packages. We could add some marker if it is build stand alone. So you could know in advance that there are dynamic buildrequirements still missing.

@ffesti
Copy link
Contributor

ffesti commented Oct 29, 2018

Ok, I tried to sketch a POC patch and it turns out executing arbitrary scripts and breaking builds is something not too foreign to rpm. We still need a good name for the section. Unfortunately %buildrequires already is taken by the macro with the (static) buildrequires. It would be nice to have a naming scheme that would work for other types of dependencies, too. Just in case we'd like to add something like that in the future. Suggestions?

@nim-nim
Copy link

nim-nim commented Oct 29, 2018

How about a %buildreqs %checksreqs %prepreqs %installreqs scheme?

Warning: I suck at naming

@praiskup
Copy link
Member

I proposed somewhere above a %build_requires (with some options, too), but that would probably be too huge overlap, right? Can we operate with brackets or options? Like %dynamic_requires -t build?

@nim-nim
Copy link

nim-nim commented Oct 29, 2018

something not too long to type would be nice however

@ffesti
Copy link
Contributor

ffesti commented Oct 29, 2018

Oh, sorry I should have been more specific what I mean with "other dependencies". I don't think we need more different kind of build requires. But it may be interesting to add scripts for Provides, "normal" Requires, Conflicts, all the weak deps, well probably not obsoletes. This is currently totally speculative but I could imagine a future where we have build time scripts for those. Basically dependency generators on spec level.

@nim-nim
Copy link

nim-nim commented Oct 29, 2018

What a wonderful idea. You’re right. BuildRequires are the current pain point, but there's no reason the rest won’t want to be done after this problem is fixed.

However I think the way rpm syntax tries to pretend rpm and srpm are symetrical makes you miss the obvious. rpm and srpm are not symetrical. srpm-things are package-wide and need to be evaluated at specific points of the build process. rpm-things OTOH can all be evaluated at the end of the build process when rpm packages are assembled, but they are (sub-)package specific.

Therefore I don't feel the script model is the right one. Computing deps is a script, but declaring them is just declarative. Something like %files, with a static manual list of elements, and an optional file of computed elements, will probably work better than just a few script sections.

Of course you can also add the script sections to avoid overloading %prep, but if you want to do more than just “BuildRequires before %build”, you need real declarative sections.

So how about something like this? Provide containers for all the lists of dep things to allow moving them out of headers, where they can be generated, and where their scope is clear. During years of transition period, read both traditional headers and the new dep containers.

# Declarative section. For syntax symmetry
# Anything needed in %%prep or by the macros used before %%prep
# Existing BuildRequires could be migrated here over time, if they’re needed before %%build
# Alternatively, don’t implement it and make existing declarations an implicit %%sourcedeps
# Eventually make it accept a -f argument taken from sources
%sourcedeps
BuildRequires: x
BuildRequires: y

# Script section
%prep

# Another declarative section. With an optional computed list and static declarations
%builddeps -f <computed list>
BuildRequires: z

# Script section
%build

[…]

# Declarative sections for the built packages

%files -f <computed list>
%doc xxx

%deps -f <computed list>
Requires: moo
Obsoletes: foo < %{version}-%{release}

%files devel -f  <computed list>
%doc yyy

%deps devel -f <computed list>
Recommends: a_compiler
  • that makes it clear what is srpm-specific and what is (sub)-package specific
  • it allows splitting the srpm requirements per stage of the build process
  • it makes it clear when each part is evaluated
  • it allows mixing static and dynamic declarations freely
  • it's symetrical with %files and won`t feel alien to existing packagers.
  • it's extensible: you don’t need to invent new script names for every possible dep clause, you can add support for new clauses over time to the same section

In fact I just realized it could simplify some of the packaging macros I'm writing now. Having to inject dep things precisely after%package and before %description is highly inconvenient. A %files-like syntax would be so much easier to work with.

And that opens the way to more syntax cleanups in the future, like straightening up of the headers that apply to the srpm and those who apply to the rpm (once upon a time Build* applied to the srpm and the rest to the rpm, but that has changed since, and the limit between those is not obvious nowadays as long as they are not in separate sections). Or merging %files and %deps in a new section. Or cleaning up Sources/Patches via a %prepfiles that applies to the srpm. There are lots of things that could be done at some point of the future.

Short-term, we only need %builddeps implemented. It can be declined in %deps and %sourcedeps later.

@nim-nim
Copy link

nim-nim commented Oct 29, 2018

But if that’s too hard to do please just do the %buildrequires part as discussed before. We need it now. In fact we’ve been needing it for a decade at least.

Let’s not start chasing rainbows instead of doing the fixing we know we need and we know how to do now.

@nim-nim
Copy link

nim-nim commented Oct 29, 2018

The main problem I see is that current rpm does not like more than one -f flag, and complex packages that mix several kinds of things will probably want more than one of those. OTOH %files shows this is not a show-stopper. And whenever we find a solution to rpm argument processing it could be applied here.

Alternatively, (and probably simpler and more versatile), just accept an arbitrary number of %deps sections for the same (sub-)package, and merge them transparently.

The script approach, while it allows calling several commands easily, does not lend itself to splitting output by (sub-)package, which is what you want for non-srpm things. Many generators won’t be (sub-)package aware (the (sub-)package layout is a packager decision). So in all cases you will need to capture their output in a file or variable, and massage this file or variable to separate the (sub-)package components.

@xsuchy
Copy link
Member

xsuchy commented Oct 31, 2018

%generatedeps or %generatebuildrequires are my votes.

@Conan-Kudo
Copy link
Member

%generate_<dep_type> would be my vote

@ffesti ffesti mentioned this issue Nov 6, 2018
26 tasks
nim-nim pushed a commit to nim-nim/go-macros that referenced this issue Nov 30, 2018
@jnpkrn
Copy link
Contributor

jnpkrn commented Dec 21, 2018

Haven't read this all, but it seems to fit the bill wrt. use case
I tried to tackle at the mock side in the past:

rpm-software-management/mock#11

Nice to see it's becoming a popular request, finally :-)

@eclipseo
Copy link

Will it be possible to condition BR generator to output only main deps without tests deps? In some case it could be useful to break a cyclic deps to not have the tests deps included.

@nim-nim
Copy link

nim-nim commented Mar 23, 2019

@eclipseo My understanding of things is that you just need to have a BR generator that supports this distinction, no need for special rpm support

%if %{with check}
generate-foo-buildrequires --full
%else
generate-foo-buildrequires --without-tests
%endif

That's the nice thing of getting buildrequires generation integrated within rpmbuild, you get all the existing spec framework for free.

@pmatilai
Copy link
Member

Implemented as of commit 58dcfdd

rantala pushed a commit to rantala/go-rpm-macros that referenced this issue Oct 15, 2021
rantala pushed a commit to rantala/go-rpm-macros that referenced this issue Oct 15, 2021
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests