Skip to content
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

Ability to specify the output name for a bin target different from the crate name #1706

Closed
crumblingstatue opened this issue Jun 11, 2015 · 40 comments
Assignees
Labels
A-cargo-targets Area: selection and definition of targets (lib, bins, examples, tests, benches) A-manifest Area: Cargo.toml issues E-medium Experience: Medium

Comments

@crumblingstatue
Copy link

crumblingstatue commented Jun 11, 2015

As far as I know, the only way to name the output of a bin target is through the name attribute of a bin section.

This, however, sets both the crate name and the output name.

It seems too restricting that the output name of an executable should be a valid crate name.
For example, it cannot contain spaces. Cargo also warns if it's uppercase, because crate names are lowercase by convention.

Rustc with the -o FILENAME option allows to set any arbitrary filename for the output.

If there is already a way to do this with cargo, it should be better documented, as I couldn't find it.

@alexcrichton
Copy link
Member

I think this can be solved with cargo rustc (a relatively new subcommand), so I'm going to classify this as a docs bug.

@alexcrichton alexcrichton added the A-documenting-cargo-itself Area: Cargo's documentation label Jun 11, 2015
@crumblingstatue
Copy link
Author

How does cargo rustc solve this problem?

What I'm thinking of is the ability to specify the output name of the executable in Cargo.toml, so everyone who compiles it gets that executable name.

@alexcrichton
Copy link
Member

Yes cargo rustc would not allow you to encode the value in Cargo.toml, cargo does not currently allow that level of configuration.

@alexcrichton alexcrichton added A-configuration Area: cargo config files and env vars and removed A-documenting-cargo-itself Area: Cargo's documentation labels Jun 11, 2015
@ebkalderon
Copy link

I would like to express interest in this feature as well.

@cutewalker
Copy link

yes, +1 for this feature

@VelocityRa
Copy link

One whole year and still nothing...

@iddm
Copy link

iddm commented Nov 14, 2016

+1 for this feature.

@Lakier15
Copy link

Lakier15 commented Feb 1, 2017

+1 for this feature

@Boscop
Copy link

Boscop commented Apr 9, 2018

Yes, please :)

@matklad
Copy link
Member

matklad commented May 6, 2018

@brettcannon binary can have a name different from the name of he package, you can see it in Cargo toml in a [[bin]] section with the name key

@brettcannon
Copy link

@matklad yep, and I deleted my comment as it was incorrect; sorry about the noise; misunderstanding on my part when looking for a solution for my problem. (And feel free to hide this comment.)

@tzaeru
Copy link

tzaeru commented May 16, 2018

+1.

I wouldn't want to change my pretty

[[bin]]
name = "server"
path = "src/server/main.rs"

to

[[bin]]
name = "SoundAnalyzerServer.exe"
path = "src/server/main.rs"

@manhnt9
Copy link

manhnt9 commented Sep 25, 2018

+1 for this too

@alexcrichton
Copy link
Member

This should in theory be a pretty easy issue to knock out if anyone's interested in implementing it! I'll try to leave some instructions here and if anyone has any questions please feel free to just let me know!

I think a basic design for this will probably look like a new key in the [[bin]] section:

[[bin]]
name = "some-valid-crate-name"
filestem = "invalid.crate.name but valid-ish file $name" 

Basically the filestem key (or something similarly named) would control the file that rustc actually literally emits, but is probably orthogonal from the crate name. As mentioned in the OP we'd implement this with the -o flag passed to rustc.

Some things to note for the implementation here:

  • Deserialization happens via this struct, which would need to grow a new optional field for this key.
  • Cargo's internal data structure is here. The TOML configuration would need to make its way to this internal data structure.
  • This will want to start off as an unstable feature. There's some documentation about adding features here to Cargo, and the call to require would happen wherever the internal Target is configured if the TOML key is Some
  • The actual -o flag would go somewhere around here where unit.target is the Target structure for Cargo, and cx.files().out_dir(unit) is the folder where the output file should go.
  • We'll probably want to only allow this on [[bin]] and [[example]] targets to start off. Configuring the file stem of a [lib] target should likely be an error
  • After that, a few simple tests for this new feature should suffice!

@m-ou-se
Copy link
Member

m-ou-se commented Nov 29, 2018

We'll probably want to only allow this on [[bin]] and [[example]] targets to start off. Configuring the file stem of a [lib] target should likely be an error

I need this feature for a [lib]. My use case: I write plugins for other software in Rust, which are technically shared libraries (crate-type = ["dylib"]: .so files, as I'm workig on Linux), but should be named something.plugin instead of libsomething.so.

@Coding-Badly
Copy link

Hello @alexcrichton. I want to make certain I understand what you have in mind. Your suggestion, filestem, would not change the target's extension. Which means @m-ou-se would not be helped. Correct?

@m-ou-se
Copy link
Member

m-ou-se commented Oct 7, 2019

I need this feature for a [lib]. My use case: I write plugins for other software in Rust, which are technically shared libraries (crate-type = ["dylib"]: .so files, as I'm workig on Linux), but should be named something.plugin instead of libsomething.so.

One could argue that these plugins should not be [lib]s, but [[bin]]s instead, as there's no need to restrict them to one per package. Just like normal binaries, it'd be fine if one package produces multiple different plugins (possibly all using the same [lib] crate of the package). Even though they are technically 'libraries', they will not be used as libraries by other Rust crates. Maybe [[bin]] just needs to allow crate-type = "dylib" or something like that?

@alexcrichton
Copy link
Member

Note that I was also just spitballing, we could also switch it to using filename = "..." which include the extension to cover @m-ou-se's use case as well

@adenine-dev
Copy link

I would also like to +1 this with the possibility of allowing feature based filenames. So something like cargo build --feature foo would produce appname-foo.exe, based on a defined pattern in cargo.toml.

@aliu
Copy link

aliu commented Nov 15, 2019

I spent some time working on @alexcrichton's suggestions and implemented most of the data plumbing, but I ran into some issues. Basically, the -o flag doesn't combine very well with rest of the arguments supplied to rustc. For example, if the output directory doesn't exist, --out-dir will create it, but passing the output directory as part of -o panics with an internal compiler error. I'm not sure if this is a bug with rustc and should be fixed there, or if we should work around it in cargo by creating the directory first (however this doesn't seem ideal).

@alexcrichton
Copy link
Member

Nowadays it's probably best to use the --emit flag, so I think instead of -o you can use:

rustc --emit link=path/to/output foo.rs

I think that'll work better in conjunction with all the other outputs we're getting from rustc right now.

@Guang1234567
Copy link

Guang1234567 commented Dec 10, 2019

@crumblingstatue

Maybe it can work, but not under test.

RUSTFLAGS="-C link-arg=-o -C link-arg=libabc.so"   cargo build

# or specify the path

RUSTFLAGS="-C link-arg=-o -C link-arg=<your_pc_path>/libabc.so"   cargo build

# or

RUSTFLAGS="-C link-arg=-o -C link-arg=libabc.so"   cargo build —target=aarch64-linux-android





In additional, it also works on android gradle script:

build.gradle

           
            // …..

            // Build with cargo
            tasks.create(name: "cargo-build-${arch}-${buildType}", type: Exec, description: "Building core for ${arch}", dependsOn: "cargo-output-dir-${arch}-${buildType}") {

                doFirst { println("\n============================== Start Compile Native Lib ==============================\n") }

                workingDir rustBasePath

                environment("RUSTFLAGS", "-C link-arg=-o -C link-arg=${project.ext.cargo_target_directory}/${target}/${buildType}/libabc.so")

                if (buildType.equalsIgnoreCase("release")) {
                    commandLine 'cargo', 'build', "--color=always", "--target=${target}", '--release'
                } else {
                    commandLine 'cargo', 'build', "--color=always", "--target=${target}"
                }

                doLast { println("\n============================== Finish Compile Native Lib ==============================\n") }
            }

              // …..





And you can just change libName to xyz for test.

build.gradle#L45

@dherman
Copy link

dherman commented Dec 17, 2020

@alexcrichton Maybe filestem (bikeshed: basename?) and filename could both be supported options. The former allows you to write an OS-neutral filename and let Cargo do the work of determining the OS-conventional extension, and the latter allows you to override the OS-conventional extension.

@alexcrichton
Copy link
Member

Sounds like a great idea to me!

@dherman
Copy link

dherman commented Dec 18, 2020

@matklad I noticed in #5203 you explained that --out-dir only allows specifying a directory because a single target may produce multiple artifacts. Can you explain how that can happen? Does that complicate the goal of this issue, if "the output name" may not be a unique thing?

@matklad
Copy link
Member

matklad commented Dec 18, 2020

@dherman the most common case for that is that debuginfo on mac and windows is in a separate file. So you get foo and foo.dSYM. IIRC, there's split-dwarf for linux as well, at least in theory: rust-lang/rust#34651

I also have vague recollections that emscripting used to spit out .wasm and .js files together.

I don't have exact details about how that works? Ie, how rustc's -o flag interracts with multi-file outputs.

@dherman
Copy link

dherman commented Dec 19, 2020

This makes me wonder if letting users override the full filename might be a bad idea, since there may not be a single file. It might be that @alexcrichton's idea of filestem is as far as the extensibility should go, so the target backend can determine the full set of files it needs to create, and what extensions they need.

(For my use case, it's got me leaning towards doing the final copying for myself, and just wrapping cargo build with --message-format=json to find out where the generated DLL is so I can copy into the final destination.)

@alexcrichton
Copy link
Member

I personally feel that both make sense. I think that if you asked for a specific filename on Emscripten and rustc doesn't support that then it should error, but naming a shared library on Linux something arbitrary I don't think should be blocked because Windows has PDB files that need to be named something (for example). Basically I still fill that both are probably warranted.

@Wafelack
Copy link

Wafelack commented Feb 2, 2021

Sounds like a good idea, it would be very convenient when the crate name is quite long.

@dcow
Copy link

dcow commented Feb 2, 2021

Would love to see the ability to specify the name of the inferred main.rs binary target. Just a note, you can:

mkdir src/bin
mv src/main.rs src/bin/foo.rs

and the main bin will not longer be auto-discovered and cargo run will run the sole foo bin target without any other config. Would be nice to be able to do something like:

[bin.main]
name = "foo"

for aesthetics.

@dragonmaus
Copy link

While I agree that it would be nice for aesthetics and/or convenience, personally I want this feature so that I can produce executables that have names not allowed by the current scheme (e.g. en% and de%).

@dcow
Copy link

dcow commented Feb 2, 2021

Just tested and you can also:

[[bin]]
name = "foo"
path = "src/main.rs"

The name applies to the auto-discovered main target (no duplicate binary target is created).

@kotx
Copy link

kotx commented Feb 14, 2021

Just tested and you can also:

[[bin]]
name = "foo"
path = "src/main.rs"

The name applies to the auto-discovered main target (no duplicate binary target is created).

Unfortunately if the name isn't in snake case (or kebab case) you'll get a warning (crate `X` should have a snake case name), but I want to name my executable file in pascal case. Hoping for a workaround other than disabling the warning or changing the name.

@SoniEx2
Copy link

SoniEx2 commented Feb 21, 2021

We used to have application binaries called foo.cli and foo.gui and unfortunately we can't switch to rust because this issue breaks backwards compatibility. All in all it's kinda silly that applications have a crate name tho, it's not like that's ever gonna be exposed anywhere, and it's not like there are macros to get the crate name at compile-time or anything.

Why not just set the crate name the same for all applications, and/or remove the concept of crate name from rust applications?

@Wafelack
Copy link

Wafelack commented Feb 23, 2021

You can actually get the crate name at compile time. And crate names for application aren't « silly » as you say, they are necessary for crates.io (for both installation and searching.).

@mainrs
Copy link

mainrs commented Mar 7, 2021

Unfortunately if the name isn't in snake case you'll get a warning (crate `X` should have a snake case name), but I want to name my executable file in pascal case. Hoping for a workaround other than disabling the warning or changing the name.

This isn't true (entirely), I have the following and I do not get any errors when calling cargo run:

[package]
name = "krate_name"

[[bin]]
name = "krate-name"
path = "src/bin/krate_name.rs"

It seems to also support kebab-case.

@kotx
Copy link

kotx commented Mar 7, 2021

Unfortunately if the name isn't in snake case you'll get a warning (crate `X` should have a snake case name), but I want to name my executable file in pascal case. Hoping for a workaround other than disabling the warning or changing the name.

This isn't true (entirely), I have the following and I do not get any errors when calling cargo run:

[package]
name = "krate_name"

[[bin]]
name = "krate-name"
path = "src/bin/krate_name.rs"

It seems to also support kebab-case.

Yeah I forgot about that, edited. The warning explicitly says snake case, so I guess that's an oversight. Snake case is preferred over kebab case IIRC.

@ehuss ehuss added the E-medium Experience: Medium label Jun 21, 2021
@whereistejas
Copy link
Contributor

whereistejas commented Jun 26, 2021

Hi everyone,
If possible I would like to take up this issue. Based on the discussion above, we can summarise the requirements as follows:

  1. output name of the binary should not have the restrictions of a crate name.
  2. add a second key in [[bin]] section along with name called filename.
    1. name will allow us to set the name of the crate.
    2. filename will allow us to set the name of the binary.
  3. only allow this config options in [[bin]] and [[example]].

@alexcrichton @ehuss please correct me if I'm wrong about the above requirements.

@rustbot claim

bors added a commit that referenced this issue Aug 11, 2021
Ability to specify the output name for a bin target different from the crate name

Hi,

I have opened this to close the following issue #1706 .

I have decided to start by writing a test to outline what behavior is expected from `Cargo`.
As of now, this test fails (for obvious reasons). I will now start writing the code needed to pass this test.

This is my first time contributing to cargo. Please, feel free to let me know if there are any protocols/processes that need to be followed. I'm a newbie at this.

Closes issue #1706
@ehuss
Copy link
Contributor

ehuss commented Aug 11, 2021

Closing as this is now implemented via #9627, and stabilization tracked in #9778.

@eureka-cpu
Copy link

We'll probably want to only allow this on [[bin]] and [[example]] targets to start off. Configuring the file stem of a [lib] target should likely be an error

I need this feature for a [lib]. My use case: I write plugins for other software in Rust, which are technically shared libraries (crate-type = ["dylib"]: .so files, as I'm workig on Linux), but should be named something.plugin instead of libsomething.so.

Such a good suggestion. I'm writing a plugin atm and I have a post-install script that renames the resulting "lib", since it's prefixed with lib and there doesn't seem to be a direct way of telling cargo to just use the name field. Strange that it does this by default.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
A-cargo-targets Area: selection and definition of targets (lib, bins, examples, tests, benches) A-manifest Area: Cargo.toml issues E-medium Experience: Medium
Projects
None yet
Development

No branches or pull requests