Skip to content

crate-type = ["rlib", "dylib"] fails to build with test profile #15890

@Firestar99

Description

@Firestar99

Problem

Likely related: #6313

I am a maintainer of rust-gpu (https://github.com/Rust-GPU/rust-gpu/) and currently working on adding rust-gpu support for Graphite (https://github.com/GraphiteEditor/Graphite), with the first integration in GraphiteEditor/Graphite#3097. Though this bug has nothing to do with rust-gpu itself, I'm having issues compiling tests on the CPU with dylib as an additional crate type.

rust-gpu requires that the crate compiled to "spirv shaders" is a dylib, otherwise the shaders won't link (since we have to hijack dylib linking a little). As cargo does not have a cmdline option to pass the crate type, only rustc has, we've told all our users to just add the config below to every "shader bin crate". Only the final "shader binary crate" requires this to perform linking, the shader crate may depend on any other crates without this (as long as all crates are no-std). We also recommend keeping lib for CPU linking, though lib and rlib seem to be interchangeable (at the moment).

[lib]
crate-type = ["lib", "dylib"]

While integrating it in graphite, I've noticed that compiling tests for the entire workspace (cargo test --workspace) started to fail and traced it to adding dylib as a crate-type to a specific crate. This has nothing to do with rust-gpu, since at this point it has not been integrated, and we're just working with tests compiled on the CPU. This is the first instance we have seen fail this way.

See Steps on how to get the following warnings and errors.

Warning

This warning is printed immediately after executing cargo test --workspace and appears 5 times, with the following paths:

  • target/debug/deps/libgraphene_raster_nodes.rlib
  • target/debug/deps/libgraphene_raster_nodes.so
  • target/debug/libgraphene_raster_nodes.so
  • target/debug/deps/libgraphene_raster_nodes.so.dwp
  • target/debug/libgraphene_raster_nodes.so.dwp
warning: output filename collision.
The lib target `graphene_raster_nodes` in package `graphene-raster-nodes v0.1.0 (/home/firestar99/workspace/graphite/node-graph/graster-nodes)` has the same output filename as the lib target `graphene_raster_nodes` in package `graphene-raster-nodes v0.1.0 (/home/firestar99/workspace/graphite/node-graph/graster-nodes)`.
Colliding filename is: /home/firestar99/workspace/graphite/target/debug/deps/libgraphene_raster_nodes.rlib
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>.

Error 1

error: extern location for graphene_raster_nodes does not exist: /home/firestar99/workspace/graphite/target/debug/deps/libgraphene_raster_nodes.so
  --> node-graph/gbrush/src/brush.rs:17:5
   |
17 | use graphene_raster_nodes::blending_nodes::blend_colors;
   |     ^^^^^^^^^^^^^^^^^^^^^

error: extern location for graphene_raster_nodes does not exist: /home/firestar99/workspace/graphite/target/debug/deps/libgraphene_raster_nodes.so
  --> node-graph/gbrush/src/brush.rs:18:5
   |
18 | use graphene_raster_nodes::std_nodes::{empty_image, extend_image_to_bounds};
   |     ^^^^^^^^^^^^^^^^^^^^^

error: could not compile `graphene-brush` (lib) due to 2 previous errors
warning: build failed, waiting for other jobs to finish...
error: could not compile `graphene-brush` (lib test) due to 2 previous errors

Error 2

The "multiple candidates" error does not always show. There is only a single glam dependency, according to cargo tree.

[...]

   Compiling graphene-raster-nodes v0.1.0 (/home/firestar99/workspace/graphite/node-graph/graster-nodes)
   Compiling graphene-brush v0.1.0 (/home/firestar99/workspace/graphite/node-graph/gbrush)
error[E0464]: multiple candidates for `dylib` dependency `graphene_raster_nodes` found
  --> node-graph/gbrush/src/brush.rs:17:5
   |
17 | use graphene_raster_nodes::blending_nodes::blend_colors;
   |     ^^^^^^^^^^^^^^^^^^^^^
   |
   = note: candidate #1: /home/firestar99/workspace/graphite/target/debug/deps/libgraphene_raster_nodes.rlib
   = note: candidate #2: /home/firestar99/workspace/graphite/target/debug/deps/libgraphene_raster_nodes.so

error[E0464]: multiple candidates for `dylib` dependency `graphene_raster_nodes` found
  --> node-graph/gbrush/src/brush.rs:18:5
   |
18 | use graphene_raster_nodes::std_nodes::{empty_image, extend_image_to_bounds};
   |     ^^^^^^^^^^^^^^^^^^^^^
   |
   = note: candidate #1: /home/firestar99/workspace/graphite/target/debug/deps/libgraphene_raster_nodes.rlib
   = note: candidate #2: /home/firestar99/workspace/graphite/target/debug/deps/libgraphene_raster_nodes.so

For more information about this error, try `rustc --explain E0464`.
error: could not compile `graphene-brush` (lib test) due to 2 previous errors
warning: build failed, waiting for other jobs to finish...
error[E0308]: arguments to this function are incorrect
   --> node-graph/gbrush/src/brush.rs:133:22
    |
133 |     let blank_texture = empty_image((), transform, Table::new_from_element(Color::TRANSPARENT)).into_iter().next().unwrap_or_default();
    |                         ^^^^^^^^^^^     --------- expected `glam::f64::daffine2::DAffine2`, found `DAffine2`
    |
note: two different versions of crate `glam` are being used; two types coming from two different versions of the same crate are different types even if they look the same
   --> /home/firestar99/.cargo/registry/src/index.crates.io-1949cf8c6b5b557f/glam-0.29.3/src/f64/daffine2.rs:9:1
    |
9   | pub struct DAffine2 {
    | ^^^^^^^^^^^^^^^^^^^
    | |
    | this is the expected type `glam::f64::daffine2::DAffine2`
    | this is the found type `DAffine2`
    |
   ::: node-graph/gbrush/src/brush.rs:3:5
    |
3   | use glam::{DAffine2, DVec2};
    |     ---- one version of crate `glam` used here, as a direct dependency of the current crate
...
17  | use graphene_raster_nodes::blending_nodes::blend_colors;
    |     --------------------- one version of crate `glam` used here, as a dependency of crate `graphene_core_shaders`
    = help: you can use `cargo tree` to explore your dependency tree
note: expected `Table<Color>`, found a different `Table<Color>`
   --> node-graph/gbrush/src/brush.rs:133:49
    |
133 |     let blank_texture = empty_image((), transform, Table::new_from_element(Color::TRANSPARENT)).into_iter().next().unwrap_or_default();
    |                                                    ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
note: two different versions of crate `graphene_core` are being used; two types coming from two different versions of the same crate are different types even if they look the same
   --> /home/firestar99/workspace/graphite/node-graph/gcore/src/table.rs:10:1
    |
10  | pub struct Table<T> {
    | ^^^^^^^^^^^^^^^^^^^
    | |
    | this is the expected type `graphene_core::table::Table`
    | this is the found type `graphene_core::table::Table`
    |
   ::: node-graph/gbrush/src/brush.rs:4:5
    |
4   | use graphene_core::blending::BlendMode;
    |     ------------- one version of crate `graphene_core` used here, as a direct dependency of the current crate
...
17  | use graphene_raster_nodes::blending_nodes::blend_colors;
    |     --------------------- one version of crate `graphene_core` used here, as a dependency of crate `graphene_raster_nodes`
    = help: you can use `cargo tree` to explore your dependency tree
note: function defined here
   --> /home/firestar99/workspace/graphite/node-graph/graster-nodes/src/std_nodes.rs:283:8
    |
283 | pub fn empty_image(_: impl Ctx, transform: DAffine2, color: Table<Color>) -> Table<Raster<CPU>> {
    |        ^^^^^^^^^^^

// a bunch of "two different versions of crate" errors follow
[...]

Steps

Tested on graphite rev a744499f4f6a9966f853a0ae6a1d1cb8a555bd97, x86_64-unknown-linux-gnu native target with rustup on latest stable toolchain (1.89.0).

  1. git clone https://github.com/GraphiteEditor/Graphite
  2. git checkout a744499f4f6a9966f853a0ae6a1d1cb8a555bd97 (latest master as of me writing this)
  3. cargo test --workspace (takes ~10min), observe successful building and tests passing
  4. (ignore the Cargo.toml changing by one line, to be fixed)
  5. add the following to /node-graph/graster-nodes/Cargo.toml:
[lib]
crate-type = ["rlib", "dylib"]

Option 1

  1. cargo test --workspace again
  2. small chance of a rustc ICE (need to record that one again)
  3. observe Warning and Error 2

Option 2

  1. cargo clean
  2. cargo test --workspace again
  3. observe Warning and Error 1
  4. cargo test --workspace again
  5. observe Warning and Error 2

Possible Solution(s)

No response

Notes

  • I have been unable to minify it further than a full build of everything
  • initial build can take 10min or more on an 8/16 core machine
    • We may be hitting some very bad rustc performance, will investigate more later
  • --workspace is required, everything works when it is not passed
  • it seems like some dependencies are build three times, instead of just twice. Could just be a feature difference issue, or potentially hint at something going wrong.
>     Building [====================>  ] 1075/1141: graphene-core, graphene-core, graphene_core(test)

Thanks for your time ❤️

Version

cargo 1.89.0 (c24e10642 2025-06-23)
rustc 1.89.0 (29483883e 2025-08-04)

Metadata

Metadata

Assignees

No one assigned

    Labels

    C-bugCategory: bugS-triageStatus: This issue is waiting on initial triage.

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions