Publish crate without publishing local sub-crates?


#1

If I have a repository that contains multiple crates - let’s say A and B, where A has a dependency on B - is it possible to publish A without also requiring B to be published? In particular, the A -> B dependency is specified using local path traversal:

[dependencies.B]
path = "libs/B"

If the answer is yes, then how so? If the answer is no, then are there best practices for how to separate out logic that belongs in a separate crate, but that you don’t want published? Is there no other option than to use sub-modules inside the published crate?


#2

This isn’t possible. Why don’t you want to publish the other crate?


#3

It’s a crate for querying system configuration information (think Unix’s sysconf call, but cross-platform), but I’ve only bothered to implement the functionality that my main crate requires. I don’t want to dirty up the crates.io namespace with a crappy crate that won’t be helpful to other people, but I also don’t want to take responsibility for maintaining it as a fully-fledged public-facing crate.

Also, I realized that what I said in the original post about being able to make it a module isn’t actually true. I’m going to be adding another crate soon (that I do want to be public) that will depend on it. In other words, I’ve got crates A, B, and C, where I want A and C to be public - but not B - and A and C each have a dependency on B. Thus, the only way I can make B’s logic not in its own crate is to duplicate the code and keep a copy in A and a copy in C.


#4

Call it joshlf-hacky-sysconf-thing, note in the description it’s unsupported, and call it a day. You only have as much responsibility for maintenance as you fell you do.


#5

If A has unsupported dependencies I would consider A also unsupported.

For me you have two options:

  • Publish B but state in documentation that its scope is so far only this and that and it may be widened or replaced but help is needed
  • Get rid of dependency. Instead define in A and C traits that describe functionality they need. Make A and C generic over the traits. Implement the traits in B. Inject implementation from B into A and C in your main crate/application.

Which approach is better depends on your specifics, but with second one you can write unit tests for your high-level logic in A and C by mocking low-level B. With second approach users of A and C will be forced to provide their own implementation of querying system configuration.