Depending on older crate version in test

I want the test code of my binary to depend on older version of itself. Let's say, that it is not semver compatible. However, I occur a problem - the naming collision of library artifacts:

warning: output filename collision.
The lib target `counting-contract` in package `counting-contract v0.3.0 (...)` has the same output filename as the lib target `counting-contract` in package `counting-contract v0.1.0 (...)`.
Colliding filename is: .../target/debug/deps/libcounting_contract.so
The targets should have unique names.
Consider changing their names to be unique or compiling them separately.
This may become a hard error in the future; see <https://github.com/rust-lang/cargo/issues/6313>.

It is not a hard error yet, but it actually did some harm to me - for example, if I have binary in this project, then tests for this binary are using the old library version, not the one I am building. I get why all this happens, there is a problem, however - I really need to have two distinct versions of my library in a single project. It can be an additional project containing only tests, but still, there has to be one. And now there is a question - is there any way to work around this? For example, telling cargo to change the output filename of dependency to be called differently?

The reason why I need this (as I am sure there would be questions about that) - is the crates I am working on are smart contracts - basically wasm binaries executed by some runtime. A smart contract can have a migration function on it - it is basically the same as what you expect by migration in some database service, it is a one-shot function called by the environment when updating the smart contract version, so it can transform runtime state so it is correct from new contract POV. Now, to test our smart contracts we have the crate which simulates the runtime, but instead of loading built WASM binaries, it interfaces with the contract calling its entry points directly - this way we have way better error reporting, and even the possibility to debug tests as they are run as native binaries. But for testing these migration functions I need to first interface with an older version of the contract, so I can create it on a fake chain, and then I can call the migration entry point on my crate under test.

Are you using the package syntax to import the library under a different name?

[dev-dependencies]
my_library_in_old_ver = { package = "my_library_real_name", version = "old" }

The problem is that your crate is a dylib. Rlibs get a unique hash in their name to avoid this kind of conflicts. Unfortunately this is not possible for dylibs as they have to be renamed in the end when copying from target/<profile>/deps to target/<profile>. Renaming dylibs can break among other things debuginfo. See

@kornel obviously this is how I include a dependency
@bjorn3 ok, so I assume there is no way around that? My crate has to be dylib - this is the only way I am aware of to compile it for the wasm target. The only solution I see at this point is to always run tests with --lib arg as my crates do not typically test on binaries (only binary is a utility to generate schema), so this is not a problem I guess... The only "problem" here is that anyone who would run tests has to remember to add --lib which is not terrible, but a bit problematic (using it on CI is not a problem).

Would it be possible to extract the wasm interface to a separate crate? That way the crate to be tested can remain a regular rlib. In addition you don't run the risk of symbol name conflicts caused by #[no_mangle] in both crates. Finally for wasm you should use the cdylib instead of dylib crate type. The difference is that the former omits the crate metadata and only exports #[no_mangle] symbols. This makes it much smaller, but prevents linking as regular rust dependency, which isn't supported on non-emscripten wasm anyway.