-
Notifications
You must be signed in to change notification settings - Fork 427
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
Reopen the discussion on stdlib
jinja function
#5053
Comments
cc @isuruf |
I think the idea definitely has merit (usability, migration, etc.). Though I'm not a big fan of the second line here:
If we can pull it off, I'd like to specify the stdlib implementation and version only in the CBC (not in the meta.yaml), such that
would be zipped and generate two builds on linux, e.g.
|
I think we might be conflating stdlib('c') with the standard lib for the c compiler versus glibc. I think we meant this to be glibc so that we'd also have stdlib('musl'). |
So basically we can keep the Theoretically this could also be solved with more compiler packages, such as |
The compilers are independent of the stdlib. Coupling them is not needed. |
Expanding to two lines is going to be problematic. Jinja does string substitution. If there are selectors applied to the line, what happens to those? Also we'd need to ensure that jinja has given us enough information to get the right indent. Finally we'd need to ensure that we know what kind of yaml structure we're in. We cannot always assume a list as a set of dashes on a new line versus an actually list with brackets. |
That was not what was discussed in #4981 (or what was implemented). The argument to stdlib is - like for the compiler jinja - a programming language like "c" / "cxx" / "fortran" etc. We do mean it to include more than just the c stdlib (i.e. all the other bits that make up the sysroot), but the c library is arguably the driver there. It's true that we don't strictly need to zip the compiler into two different stdlib builds, but as Wolf points out, each combination will be a unique target, so we might as well make it easy to, say, use a newer GCC when you're targeting musl.
Even though it's not pretty, this can be worked around by introducing new metapackages that do the job. We already have to introduce them anyway - like It would be a mess naming wise, and we'd have a matrix of compiler_version X stdlib_version to build, so I'd hope we could could find a way to teach jinja to create two lines. Speaking of which, a technically possible but thoroughly unappealing approach for that would be to have yet another idiosyncrasy in conda-build, of preprocessing the file to duplicate all lines that contain
into
and then run Jinja. I guess it's a bit late to claim that such horrors are just to scare people a bit for Halloween, but in any case while we're brainstorming... 🎃😜 |
This would probably get easier in the new recipe format, as there we don't have semantically relevant comments anymore (plus some merge logic if the indents don't align, IIUC), so we might get away with substituting in a |
Ahhhh I misremembered how we did the stdlibs then @h-vetinari. Sorry! Looking at the ideas above, all of them are worse IMHO than simply have people carry an extra line for the stdlib. Also, recipes are a mystery to the vast majority of conda users anyways IMHO. I personally do not like having to maintain a manual set of pairs of compilers and stdlibs together. The whole point of the conda build config is to provide a structured way to mix and match things. |
Yeah, I'm not a fan of the ideas I spelled out either 😅 Just thought I'd write down my thoughts about how one might shove this square peg into that round hole. I mean, I see the issues with migration, and user confusion, but OTOH, the original design has some substantial benefits as well, especially through being more explicit & less magic:
|
@wolfv can you comment on the points brought up here? The currently available options all seem unpalatable:
In general, I tend to agree with @beckermr's point that it's better to make the stdlib explicitly declared. So far the stdlib was a silent assumption in our infrastructure, and surfacing that is going to lead to some churn, but IMO I think it's the better choice than a silent default, especially as there doesn't seem to be a good way to implement it. |
I made a little implementation of the idea of expanding a single jinja function into multiple values. This is done by flattening a list-of-lists for the requirements. The most breaking change is that selectors without hash don't work anymore, e.g. this was actually legal:
I've tested this so far on a single-output recipe and seems to work (including with your configuration of stdlib's in the conda_build_config.yaml). I agree that it's modestly hacky, but it doesn't really make things worse as they are already pretty dire. |
Also there is a bug in your implementation – I don't think it's currently added to the "used_variables" and doesn't appear in the hash computation. I need to reiterate how crazy the conda-build code base is ... :headexplode: |
Let me reiterate my points:
To me, this still seems like a fix that is mainly done because of some technical limitation that we can solve more elegantly. I don't think many users will understand the With my proposal, selectors are absolutely not a problem at all, they work exactly the same way as they used to (remove the line with the The indentation stuff is also not a concern at all, because we use the alternate syntax for lists The stdlib remains "as configurable" as it is with your current implementation. The users who care about it will figure it out wether it's written in the recipe or not (because we would write some docs about it and it would surface in the conda-forge pinnings. |
Nice work @wolfv! This implementation will break any usage of the compiler jinja2 function that is not embedded in a list. IDK if that ever happens of course. |
Everything will be better with I don't think anybody uses the |
Awesome! I am looking forward to the new format and tooling! IDK how to add to the variables used list in conda build. @h-vetinari @isuruf do you happen to know how to do this or can provide me with some guidance? BTW @wolfv, can you cut a release of boa (mamba-org/boa#381)? |
Introducing new features in recipe yaml (lists of lists for requirements) like this for a simple function like this is the definition of technical debt and as you noticed in conda-build code base, it is full of technical debt. I'm not sure why you would want to do this given all your work to reduce technical debt. |
While most C programs depend on the C standard library, I'm not sure it is also true that most programs using the C++ compilers use the C++ standard libraries. I often see warnings from conda-build from recipes which use the C++ compiler about overdepending on the C++ standard library. I think if we defocus from the C language and consider the other compilers, the benefit of requiring explicit dependence on standard libraries becomes clearer: less packages will be depending on unused standard libraries. The current method for avoiding unused dependencies requires declaring I would also like to echo Matt's comment about how compilers and standard libraries are separate entities, so it makes sense to list them as separate dependencies. |
Also this
may be a spot where the list expansion becomes an issue? |
My 2¢. My main focus is user experience. I understand (and firmly believe in) the argument to always be explicit but I believe we can take it a step further by incorporating sensible defaults and providing clear error messages that guide users on when and how to be explicit. Even though recipes can be a bit mysterious, I think we should take the user by the hand rather than adding more magic to the process. In that light, I'm wondering what happens if you do not specify I'm in favor of keeping the recipe straightforward, using sensible defaults, and minimizing unnecessary details. Therefore, I suggest not requiring the specification of the |
If we assume this approach, how would this work (or how would the recipe need to be adapted) - as an eminently possible future use - to build linux against both glibc and musl? In the
Not that this isn't the be-all use case, but my goal here is to figure out that going with the "sensible defaults" approach does not close the door to reasonable future use cases, which would be a sign that it's not the right long-term design (and worst case we'd have to change it again in a few years). |
I might have misunderstood, it was my understanding that we would have to add I'm not entirely sure about the technical details but what I am advocating for is that ideally one would only have to add |
Actually, in terms of technical details, my approach would also add That actually currently does not work for your implementation if I read it right (becasue you missed that part with the jinja regexes). |
Sure, that's a bug in the implementation, but not a fundamental stumbling block for anything.
What would happen in that setup if just the compiler without the stdlib is requested? And user-friendliness aside1, would it work to use Footnotes
|
Ping @wolfv |
#4999 has been released in conda-build 3.28 ~two weeks ago - the window for large overhauls here is starting to close I think. Aside from the open points about injecting two dependencies (and how to deal with ignore_run_exports), I think my apprehension boils down to how turning For example, in requirements:
build:
- {{ compiler("c") }} there'd then be an implicit magic host dep under "build" (which then has to be corrected with a strong run-export). We don't really have an option to make it explicit under the kwarg-proposal, as then we'd lose the abstraction between platforms and end up with something like: requirements:
build:
- {{ compiler("c", stdlib="sysroot") }} # [linux]
- {{ compiler("c", stdlib="macosx_deployment_target") }} # [osx] This layering confusion between build and host is also problematic for cross-compilation, obviously. On top of that, the question arises how stdlib versions are specified in a case when non-standard library implementation are used. For example, how would I pass the correct version to Aside from picking up unrelated (by name) keys from CBC, it would then also appear to be a consistent choice2 to use c_stdlib:
- False for indicating Finally, if we do something like removing requirements:
build:
- - {{ compiler("cxx") }}
+ - {{ compiler("cxx", stdlib=False) }}
host:
- libfoo for all the feedstocks that don't actually need requirements:
build:
- {{ compiler("cxx") }}
host:
+ - {{ stdlib("cxx") }}
- libfoo for those that do. We also cannot solve this by defaulting to In summary, I understand the desire to avoid such an amount of churn for this, but it seems to me that the alternative is more of a churn-avoidance bandaid rather than a coherent design, and long term, that seems like a trade-off we'll come to regret. Footnotes |
We can avoid package churn by not forcing a migration. We could add a lint that warns any recipe using the compiler template, and let the packages transition as they are rebuilt naturally. |
The way I understood @wolfv's concern was about avoiding "recipe churn" first and foremost. Package churn is kinda unavoidable, but I agree it can be stretched out over time a bit. |
Hey @wolfv and happy new year! Can we move this topic forward? |
Sorry for being slow! I don't want to block this any further. I do think that for the future (ie. rattler-build) we'll have an upcoming CEP to define this feature better. It won't be an issue to move the existing recipes to the new standard, though, so all is fine from my side. |
For those interested, some more thoughts on this are being shared in prefix-dev/rattler-build#239 |
What is the idea?
We had a discussion at todays
conda-forge
meeting about the recently mergedstdlib
jinja function.#4981
The current state is that we would write a migrator that would add this function to all recipes that have a
{{ compiler('c') }}
in their text, as most (maybe not all) packages would want that.However, this seems a little "noisy" from a user perspective as all of a sudden they need to add another odd jinja function, and they need to add it almost unconditionally to all recipes that use the compiler.
For that reason I would like to propose a modification that extends the functionality of the
compiler
jinja function to add more than one dependency (this might need some hackery in conda-build, admittedly).The idea would be that the
compiler
function would also read the additional variant config keys and have a extra keyword argument to control the behavior.For example
We also make this backwards compatible by ignoring any non-existent stdlib. E.g. if the
conda_build_config.yaml
doesn't define ac_stdlib
we do not add anything.The main problem is that we need to figure out if we can add two packages from a single Jinja function.
The text was updated successfully, but these errors were encountered: