How do I pin indirect dependencies of a library? [duplicate] - rust

This question already has answers here:
How do I pin indirect dependencies of a crate?
(2 answers)
Can I force the use of my dependencies' Cargo.lock when resolving package versions?
(1 answer)
Closed 3 years ago.
I have a specific problem, but understanding the solution I think is going to be useful in a broader context.
I have a project that indirectly depends on pnet; I don't directly reference it anywhere.
It was building fine for a few weeks with pnet version 0.22. On Monday, something changed and the version of pnet incremented to 0.23 and our CI server started failing to build.
It seems that moving forward, especially once we start deploying builds, being able to definitively reproduce exact outputs is going to be pretty critical for us, so this isn't specific to this library. This could really happen at any time with any library.
Is there a way in Cargo to somehow "force" the dependency tree to use the older version short of us pulling the source of the older pnet (and maybe whatever is using it)?
I'd love to just be able to put an entry into Cargo.toml that pins the old version.
I tried adding the following, but it didn't help:
pnet = "=0.22.0"

Related

Is it possible to specify version for feature in dependency in Cargo.toml?

For example, I use barcoders crate:
barcoders = {version = "0.10.0", features = ["image",]}
Is it possible to specify which version of image this dependency should use?
Something like
barcoders = {version = "0.10.0", features = ["image=0.22.3",]}
Because it uses image crate version 0.18.0 and in my project I use latest 0.22.3.
Does it mean that there's only 2 ways to resolve that:
I downgrade version in my package
Barcoders dependency get updated
No, there is no way to specify the version for a dependency's (optional) dependency. This makes sense, as your dependency run their tests only against the version they specify in their Cargo.toml. In this case, as it appears everything you're doing uses open source, you could fork barcoders, update the dependency, run the test suite and if it passes, use your fork. It would also be polite to open an issue in that case.
If barcoders wasn't open-source, so you couldn't fork it, your best bet would be to switch to the version of image that barcoders uses. If your crate is a library, it may be annoying to expose a public interface that uses outdated libraries, but that's life. The "proper" solution to this problem is to wait until image has a 1.0 release, which is basically a forward compatibility promise, then barcoders can specify image = "^1" (i.e. >=1.0.0 <2.0.0). I mention this "solution" only because you appear to have commit privileges on barcoders, in fact you solved your own problem by updating the image dependency in barcoders.
As one of the comments points out, this version compatibility issue is less fragile that it at first seems. So long as types from different versions of some dependency crate don't cross api boundaries, your project can include any number of versions of that dependency simultaneously. Working with multiple versions of libraries took some work from the rust team on name mangling, which you can read about here
No, you can't, and shouldn't, and shouldn't worry.
Libraries were developed at a single point in time, used dependencies with a certain API. The dependency is likely to change some of that between major versions (changing the type a function returns, exposing different patterns, or whatever). This may make it unable to compile anymore. To really update something, you might need to change parts of the code that is using the dependency in the first place.
This is open source world, so you can do so and publish a pull request in the original crate to update. It might be appreciated, but don't underestimate the care that needs to be taken to not break other people's crates yourself when doing so.
Or make your own fork of the crate that updates it just for you.
But you are probably just worried seeing duplicates of the same crate with different versions during compilation. Cargo indeed compiles with different versions, so all calls to the dependended crate will receive what the developer expected when he/she wrote it. This is not a problem, in performance, or amount of instructions that end up in the binary. Just stop worrying.

Node JS addons - NAN vs N-API? [closed]

Closed. This question needs details or clarity. It is not currently accepting answers.
Want to improve this question? Add details and clarify the problem by editing this post.
Closed 2 years ago.
Improve this question
I am looking to working on a project using node js addons with C++. I came across two abstract library NAN and N-API that I can use. However I am unable to decide which one I should use. I was not able to find proper comparison between these two libraries.
What are the pros, cons and differences of both? How to choose between them?
So far I have found that NAN has more online tutorials/articles regarding async calls. But N-API is officially supported by Node (and was created after NAN as a better alternative, although not sure.)
My understanding is this:
The Node-API (formerly N-API) was added to the core node.js interface in v8.0.0. "It is intended to insulate Addons from changes in the underlying JavaScript engine…" to quote the documentation. It also provides some other wrappers around things like buffers and asynchronous work (which should help avoid some of the underlying non-stable APIs noted in their Implications of ABI stability section).
nan (Native Abstractions for Node) is indeed older and so also supports older versions of node.js — back to node.js 0.8! Now despite its author claiming back in 2017:
As I mentioned somewhere else, N-API is not meant to be directly used for anything. Where has this notion come from? It is an (effectively internal) low-level infrastructure layer meant to offer ABI stability. There will be another layer on top.
…I do not see much warning to that effect in the official Node.js add-on documentation. Perhaps this other comment is a bit more insightful:
Yes, you should still use NAN for production use. It covers every relevant version of Node.js. Also note that N-API is not intended for end users. You should eventually use https://github.com/nodejs/node-addon-api.
Again, that was in June of 2017 by the maintainer of nan at the time. It seems that node-addon-api has matured in the meantime and remains active. In fact, I found a comment in the -addon-api repo that is only a month old at present:
…part of the goal was to make it easy to transition from nan.
So I think the answer is:
use nan if you want something mature and very backwards-compatible
use node-addon-api if you want something forwards-looking in C++
use Node-API/N-API if you are comfortable working in C and dealing with possible lower-level concerns
You should use the node-addon-API module for new C++ code (or N-API for C code). All supported (non-EOL) versions of Node.js support it, and it makes maintaining and distributing native add-ons much easier: whereas addons using NAN require rebuilding the module for each NODE_MODULE_VERSION (major version of Node.js), modules using N-API/Node-Addon-API are forward-compatible:
A given version n of N-API will be available in the major version of Node.js in which it was published, and in all subsequent versions of Node.js, including subsequent major versions.
There's a somewhat confusing compatibility matrix here. N-API version 3 is compatible with Node.js v8.11.2+, v9.11.0+ and all later major versions (v10+), for example.
On top of that, node-addon-API fixes a lot of the annoying parts of NAN (like Buffers always being char* instead of, say uint8_t*).
NAN still works of course, and there are more learning resources online, but node-addon-API is the way forward.

Is it documented that Cargo can download and bundle multiple versions of the same crate?

By forking and playing with some code, I noticed that Cargo can download and bundle multiple versions of the same crate in the same project (native-tls 0.1.5 and 0.2.1, for example). I have wasted so much time by looking at the documentation of the wrong version.
I have looked for some information about this behaviour but I was not able to find anything. Is this documented somewhere?
Is there an easy way to determine/detect the version used by the code you're working on (current edited file)? Or can we tell Cargo to show some warnings/prevent the build if two versions the same crate are required?
It was a conscious decision when designing Rust to allow multiple versions of the same crate.
You have probably heard of Dependency Hell before, which occurs when 2 (or more) dependencies A and B have a common dependency C but each require a version which is incompatible with the other.
Rust was designed to ensure that this would not be an issue.
In general, cargo will attempt to find a common version which satisfies all requirements. As long as crate authors use SemVer correctly, and the requirements give enough leeway, a single version of the dependency can be computed and used successfully.
Sometimes, however, multiple versions of the same dependency are necessary, such as in your case since 0.1.x and 0.2.x are considered two different major versions. In this case, Rust has two features to allow the two versions to be used within the same binary:
a unique hash per version is appended to each symbol.
the type system considers the same type Foo from two versions of C to be different types.
There is a limitation, of course. If a function of A returns an instance of C::Foo and you attempt to pass it to a function of B, the compiler will refuse it (it considers the two types to be different). This is an intractable problem1.
Anytime the dependency on C is internal, or the use of C is isolated, it otherwise works automatically. As your experience shows, it is so seamless that the user may not even realize it is happening.
1 See the dtolnay trick that crate authors can use to allow some types to be interchangeable.
Cargo can indeed link multiple versions of some crate, but only one of those versions can be a direct dependency. The others are indirect references.
The direct reference is always the version referenced by Cargo.toml and on top-level of Cargo.lock (while the indirect references are in the dependencies subsections).
I am not sure how much it is documented, unfortunately.

Why do people store typescript's types as dependency in package.json (instead of devDep)? [duplicate]

This question already has answers here:
How do I decide whether #types/* goes into `dependencies` or `devDependencies`?
(4 answers)
Closed 4 years ago.
I noticed in almost all tutorials or blog posts about typescript, people just install packages via npm for types and/or typescript related modules as dependency.
This is compile-time related thing and end user will never have to load this, so for me logically this should all be impl. detail and thus go to devDependecies part of package.json.
I'm assuming that I'm missing something and would like the compact yet reasonable answer :)
While this was my standing back in '17 when this was written, I was shown evidence to the contrary. See the linked duplicate for more details.
Because they are lazy/ignorant of the difference.
#types should definitely be devDependencies, you don't want them installed when you npm i some-package, only when you clone the code and call npm i.
You are completely right.

How do I disable version parsing in cabal or stack?

I am using alternative version numbering approach for my projects. I have encountered strange behavior by cabal and stack that does not allow me to fully enjoy benefits of this approach. Both cabal and stack enforce version to be of format Int.Int.Int, which does not cover the case of another version format I use for branches (0.x.x, 1.x.x, 1.0.x, etc).
If I have line version: 0.x.x in my .cabal file, I am getting Parse of field 'version' failed. error when running cabal build or Unable to parse cabal file {PROJECT_NAME}.cabal: NoParse "version" 5 when running stack init.
Is there a way to disable version parsing on cabal and stack commands? Is there a flag for it? Or do I have to request this kind of change (adding flags, disabling version parsing) from the developers of cabal and stack?
Why is there any parsing at all? How does it help with building a package? Does cabal or stack automatically increment build numbers on some event? If yes, where could I read more about this? How could I influence the way version numbering incrementation gets implemented in cabal and stack? I want developers of haskell packages take into account the possibility of alternative version numbering approaches.
PS. For all interested folks, I want to quickly summarize the idea behind "weird" version numbers, such as 0.x.x, 1.x.x, 1.0.x. I use the version numbers with x's to describe streamlines of development that allow code changes while such version numbers as 1.0.0, 1.1.0, 2.35.46 are used to describe frozen states of development (to be precise, they are used for released versions of software). Note that such version numbers as 0.x.0, 1.x.15, 2.x.23 are also possible (used for snapshots/builds of software) and they mean that codebase has been inherited from branches with version numbers 0.x.x, 1.x.x and 2.x.x correspondingly.
Why do I need such version numbers as 0.x.x, 1.x.x and 2.x.x at all? In brief, different number of x's mean branches of different types. For example, version number pattern N.x.x is used for support branches, while pattern N.M.x is used for release branches. Idea behind support branches is that they get created due to incompatibility of the corresponding codebases. Release branches get created due to feature freeze in corresponding codebase. For example, branches 1.0.x, 1.1.x, 1.2.x, ... get created as a result of feature freezes (or releases) in branch 1.x.x.
I know this is all confusing, but I worked hard to establish this version numbering approach and I continue working on awareness about the inconsistencies of version numbering through my presentations and other projects. This all makes sense once you think more about the pitfalls of semver approach (you can find detailed slideshare presentation on the matter following the link). But I do not want to defend it for now. For the time being, I just want cabal and stack to stop enforcing their, as I perceive them, unjustified rules to my project. Hope you can help me with that.
You can't. The version will be parsed to Version, which is:
data Version = PV0 {-# UNPACK #-} !Word64
| PV1 !Int [Int]
Stack uses Cabal as a library but has its own Version type:
newtype Version =
Version {unVersion :: Vector Word}
deriving (Eq,Ord,Typeable,Data,Generic,Store,NFData)
Neither cabal nor stack have a way to customize the parsing. You have to write your own variant of those programs if you want to use another version type. But then again, you're not winning anything at that point: neither Hackage nor Stackage will recognize your package's version.
So the 1.x.x isn't possible at the moment. You could exchange x with 99999999 or something similar to mitigate the problem. That being said, it's not clear what cabal install should then install. The 99999999 version? Or the latest stable variant?
If you can express the semantics, a discussion on the mailing list as well as a feature request might change the behaviour in the (far away) future, but for now, you either have to patch the programs yourself or use another numbering scheme.
Is there a way to disable version parsing on cabal and stack commands? Is there a flag for it?
No.
Or do I have to request this kind of change (adding flags, disabling version parsing) from the developers of cabal and stack?
You can of course ask, but there are so many outstanding issues that you are unlikely to get any traction. You will have to be very convincing -- convincing enough to overturn more than 20 years of experience that says the current versioning scheme is basically workable. Realistically, if you want this to happen you'll probably have to maintain a fork of these tools yourself, and provide an alternative place to host packages using this scheme.
Why is there any parsing at all? How does it help with building a package?
Packages specify dependencies, and for each dependency, specify what version ranges they work with. The build tools then use a constraint solver to choose a coherent set of package/version pairs to satisfy all the (transitive) dependencies. To do this, they must at a minimum be able to check whether a given version is in a given range -- which requires parsing the version number at least a little bit.
Does cabal or stack automatically increment build numbers on some event? If yes, where could I read more about this?
There is nothing automatic. But you should take a look at the Package Version Policy, which serves as a social contract between package maintainers. It lets one package maintainer say, "I am using bytestring version 0.10.0.1 and it seems to work. I'm being careful about qualifying all my bytestring imports; therefore I can specify a range like >=0.10 && <0.11 and be sure that things will just work, while giving the bytestring maintainer the ability to push security and efficiency updates to my users." without having to pore through the full documentation of bytestring and hope its maintainer had written about what his version numbers mean.
How could I influence the way version numbering incrementation gets implemented in cabal and stack?
As with your previous question about changing the way the community does things, I think modifications to the Package Versioning Policy are going to be quite difficult, especially changes as radical as you seem to be proposing here. The more radical the change, the more carefully motivated it will have to be to gain traction.
I honestly don't know what a reasonable place to take such motivation and discussion would be; perhaps the haskell-cafe mailing list or similar.

Resources