Structuring a project that generates two similarly-named executables

I'm in the process of converting an existing project from C to Rust. The actual conversion is straightforward, and has resulted in code that's 10% of the size of the C version, more robust and easier to understand. So that's absolutely awesome :slightly_smiling_face: But one thing I'm having trouble deciding how to handle is the project structure.

My initial Rust implementation is a simple main.rs containing all the code, that builds project.exe. But my C code generates two executables, project.exe and projectw.exe, which are essentially the same but the -w version is a Windows GUI executable.

I can make this happen by writing a bin/projectw.rs containing a copy of the code from main.rs, plus an attribute setting to make it a GUI subsystem build. So far, so good. There's a lot of shared code, but I should be able to move that into a private module (I need to read up on modules, I've not used them yet, but they seem like what I want here).

But I'm a little concerned about the lack of symmetry between the two versions - if I want to change the name of project.exe, I do that in Cargo.toml, but if I want to change the name of the -w version, I rename the source file. In my C version, I just built the source file twice, with different compiler flags.

Is there a better way of doing this? I thought about having both bin/project.rs and bin/projectw.rs, with no main.rs at all. Is that allowed? It makes the project name in Cargo.toml irrelevant, which seems odd. Or is there a way to derive the filename for the bin/projectw.rs build from the name of the project (by adding a "w") rather than from the source filename? Or can I do like I do in C, and have all the source in main.rs with the differences handled by features (which seem to cover what I use C defines for - another thing I need to read up on!) and have the executable filename calculated based on what features I enable?

I'm probably over-thinking all of this, but I'd like to start my first non-trivial Rust project with a reasonably "best practice" project structure, and learn how to do things right from the start :slight_smile:

I would put them both in bin. Then instead of a main.rs, use lib.rs as the root of your module tree, and refer to shared code in lib.rs as, for example, crate_name::f().

Edit to add: with this structure, you wouldn't put any mod declarations in your bin/ files.

1 Like

Cool. If I do that, am I allowed to call the crate the same as one of the files in bin? I tried that but I got some weird complaints from VS Code (that I can't reproduce right now) which suggested that this was invalid. The project built OK, though.

You may get a warning about .pdb files colliding if you build both dynamic library and exe of the same name on Windows.

But apart from that it's fine to have a binary and a Rust library with the same name, even in the same package.

That shouldn't be an issue, as I'm not building a DLL (if I were, I'd probably rename the project so the DLL had a different name anyway). The warning was from the VS Code rust extension - I've reported it there on the assumption that it's an extension bug, as the build seems OK.

Thanks for the help.