Join GitHub today
GitHub is home to over 31 million developers working together to host and review code, manage projects, and build software together.
Sign upthoughts on the `src/main.rs` and `src/lib.rs` pattern #167
Comments
This comment has been minimized.
This comment has been minimized.
nabijaczleweli
commented
May 1, 2018
|
As a user (or, should I say, proponent, even) of crates containing both a library and binaries, I'd be severely in favour of formalising that pattern as explicitly supported (since, as my ground-ear @Enet4 reports, it's If the pattern is not mentioned within the guide (whichever one is official nowadays) and "decidedly baffling", it'd probably be a good idea to mention it there. TL;DR: pattern good, formalise and promote pl0x. |
This comment has been minimized.
This comment has been minimized.
|
I definitely like the concept of a lib + bin crate, but I prefer the structure of |
This comment has been minimized.
This comment has been minimized.
|
And throwing in a third option, I really prefer to use a workspace for this case. Doing so allows me to have binary-specific dependencies (e.g. all the fancy command line parsing you want for these utility programs). |
This comment has been minimized.
This comment has been minimized.
|
This convention is written down, though perhaps not in the most discoverable location... https://doc.rust-lang.org/stable/book/second-edition/ch12-03-improving-error-handling-and-modularity.html#separation-of-concerns-for-binary-projects |
This comment has been minimized.
This comment has been minimized.
|
I also tend to look at these as a continuum as I'm coding along:
Which restrictions are we talking about here? You can put tests in a |
This comment has been minimized.
This comment has been minimized.
|
loving the convo so far ya'll, please keep it going!
i really like my tests separate. i am not saying this is right or good, it's just the case and expectation for a lot of folks. as a result, everytime i write a binary i make a lib.rs that has basically everything and the binary is a weird shell, e.g. https://github.com/ashleygwilliams/wasm-pack/blob/master/src/main.rs. again, not saying i'm correct or amazing, just that this way of testing makes more sense to a lot of people, particularly those coming from ecosystems where this (tests in tests dir) is the norm. |
This comment has been minimized.
This comment has been minimized.
|
Note that there are references to both |
This comment has been minimized.
This comment has been minimized.
|
I basically never use this pattern and probably wouldn't choose to recommend it on my own either. My reasons are basically what @shepmaster already stated: the dependencies for a library may be quite different than the dependencies for a command line application. A command line application typically requires an argv parser as an example of something that the library would generally not need. In practice, I've found the disparity quite a bit larger. Recently, a CLI program I wrote required an HTTP client where as the library doesn't. This one thing alone makes the dependency tree for the CLI program roughly an order of magnitude larger than the dependency tree for the library. This matters to me. One exception here where I think this pattern might be useful is if there is a use case for others making use of your command line application directly via argv (whether because it's easier or you want to avoid process creation overhead or what not), but I haven't felt compelled to do that for any CLI program I've written. I admit, this sounds useful for tests, but my tests for CLI programs are always written to invoke the executable itself, because that is invariably how the end user uses the program. To be clear, I generally agree with the high level goal of trying to make programs relatively thin by trying to push more code into libraries, and I do think workspaces are a good way to accomplish that. Workspaces "scale" too and have other benefits. That is, a |
This comment has been minimized.
This comment has been minimized.
Ixrec
commented
May 2, 2018
|
If cargo supported "lib-only deps" and/or "bin-only deps", would that significantly change the tradeoffs? |
This comment has been minimized.
This comment has been minimized.
withoutboats
commented
May 2, 2018
•
|
I don't have a strong opinion about a separate workspace vs just a binary in the same project, but I do prefer not having them rooted in the same directory. For this reason, I prefer to see (I've also seen people who have two overlapping crates, where Overall, I'd be glad to see us formulate more guidelines around multi-crate projects, even beyond 1 lib and 1 binary, to recommendations for how to organize multiple binaries, how to organize a workspace with different packages in it, etc.
Seems like a solution to this particular problem would be to adjust |
matklad
referenced this issue
May 2, 2018
Closed
Support both --bin and --lib together in cargo new #5433
This comment has been minimized.
This comment has been minimized.
kornelski
commented
May 2, 2018
•
|
I love the pattern and use it for all my CLI applications.
So the way I see it projects that are primarily a library could be better served by having separate satellite CLI crates, but projects that are primarily CLI tools are best served by having a private low-maintenance library. A bin+lib project can always be separated if it outgrows that setup, so I don't see harm in starting out that way. |
This comment has been minimized.
This comment has been minimized.
i would really really like this. |
This comment has been minimized.
This comment has been minimized.
kornelski
commented
May 4, 2018
|
I've noticed |
This comment has been minimized.
This comment has been minimized.
kornelski
commented
May 4, 2018
|
Another argument in favor of combined bin+lib: it's surprising that doccomment tests don't work in |
This comment has been minimized.
This comment has been minimized.
WiSaGaN
commented
May 28, 2018
|
I think the original idea is to make creating crates really easy, so that you can create separate crates for binaries and libraries except some really small binaries inside a crate. And we also have established pattern of multiple crates inside a single repo. Like mentioned above, the dependencies can be quite different. And one of my use cases also needs |
This comment has been minimized.
This comment has been minimized.
nrxus
commented
Jul 18, 2018
|
I am unsure if this a lot to the conversation but it is possible to have test files separate without having a I am personally a fan of having my tests in a separate file that the code they are testing (even for unit tests) so I recently moved one of my tests in a I am unsure how much I like this strategy when compared against moving Con: I have to specify every top test module in |
This comment has been minimized.
This comment has been minimized.
cfsamson
commented
Aug 28, 2018
•
|
I'm new to Rust but the exact pattern above has confused me a lot! Really, after borrowing and a few more concepts, it's the one that I have messed around with the most. Why have so many options here instead of just having one pattern unless you choose actively to change it in the .toml file. This would be easier to grasp in my eyes: cargo create --lib cargo create --bin The files inside "bin" could use the same pattern of accessing the library through "extern crate myproject" (like it does now when you want to create a second executable) when you have submodules. If you have no submodules you just put the code in main and compile. Does this make sense only to me? |
This comment has been minimized.
This comment has been minimized.
mre
commented
Oct 25, 2018
|
Your suggestion makes a lot of sense to me @cfsamson. I'm just a bit concerned about onboarding beginners though. Creating a |
This comment has been minimized.
This comment has been minimized.
cfsamson
commented
Oct 25, 2018
•
|
Hmm, I guess after using it regularely for a while I see your point here. Also, the changes in 2018 edition will certainly make modules in general less confusing in the start. When you're new, the logical way of thinking about it would be that in Rust you basically put all modules and divide your code up in a library as a default way of organizing a project. A library can either be a stand alone library "project", called a crate, or an "internal" library where you structure your code for your executable - and you call your own internal library like any other crate. If you're only writing some short code you'll just delete or ignore the lib.rs file and code in bin/main.rs as you do now. Problem for me in the start was that you could not necessarily build understanding of A onto understanding of B to get to C. I.e. what happens when you add a lib.rs to a --bin project, why do you need to reorganize and suddenly use "extern crate" and add a lib.rs file if you want two executables in the same --bin project. And what happened with the submodules you used in your main.rs when you did that change? Why is there no testing setup by default in --bin project? Are there other changes than file/folder structure in --bin vs --lib that I haven't gotten to yet (I guess few start to learn by getting a full understanding of the configuration options in the .toml file)? IMHO those situations create a bit of unneccesary uncertainty and headache in the start. |
ashleygwilliams commentedMay 1, 2018
in yesterday's cargo team meeting we got into some interesting discussions around this PR:
rust-lang/cargo#5433
the gist of this PR is that
cargo new --lib --binshould work.in discussing this we got into a convo about the
src/main.rsandsrc/lib.rscohabiting pattern that is pretty prevalent in the rust ecosystem, but also decidedly baffling to many people. before we pave a road to that pattern, we want to make sure this pattern is deliberate and something that we want to continue.speaking for myself, i am a user of the pattern, largely due to the restrictions of
cargo test. i'm curious to hear others' opinions on this, particularly the libs team, and other people focused on API guidelines. looking forward to hearing ya'lls thoughts!@rust-lang-nursery/libs @rust-lang-nursery/cargo