I am creating a library with Rust. On library creation I type
cargo new name
According to the docs this should create a lib, because --bin is omitted.
However, the file is auto set to a binary.
Is there a setting I have to adjust to disable auto setting all projects to binary?
Cargo features
Cargo’s CLI has one really important change this release: cargo new will now default to generating a binary, rather than a library. We try to keep Cargo’s CLI quite stable, but this change is important, and is unlikely to cause breakage.
For some background, cargo new accepts two flags: --lib, for creating libraries, and --bin, for creating binaries, or executables. If you don’t pass one of these flags, in previous versions of Cargo, it would default to --lib. We made this decision because each binary (often) depends on many libraries, and so the library case is more common. However, this is incorrect; each library is depended upon by many binaries. Furthermore, when getting started, what you often want is a program you can run and play around with. It’s not just new Rustaceans though; even very long-time community members have said that they find this default surprising. As such, we’re changing it.
Source
Since Cargo 1.25 cargo new defaults to creating a binary crate, instead of a library crate.
cargo new accepts two flags: --lib, for creating libraries, and --bin, for creating binaries, or executables.
See the Changelog for 1.25.
Related
I come from a Java background and have recently started with Rust.
The official Rust doc is pretty self-explanatory except the chapter that explains Crates and Packages.
The official doc complicates it with so many ORs and ANDs while explaining the two.
This reddit post explains it a little better, but is not thorough.
What is the exact difference between a Crate and Package in Rust? Where/When do we use them?
Much thanks!
Crates
From the perspective of the Rust compiler, "crate" is the name of the compilation unit. A crate consists of an hierarchy of modules in one or multiple files. This is in contrast to most "traditional" compiled languages like Java, C or C++, where the compilation unit is a single file.
From the perspective of an user, this definition isn't really helpful. Indeed, in most cases, you will need to distinguish between two types of crates:
binary crates can be compiled to executables by the Rust compiler. For example, Cargo, the Rust package manager, is a binary crate translated by the Rust compiler to the executable that you use to manage your project.
library crates are what you'd simply call libraries in other languages. A binary crate can depend on library crates to use functionality supplied by the libraries.
Packages
The concept of packages does not originate in the Rust compiler, but in Cargo, the Rust package manager. At least for simple projects, a package is also what you will check into version control.
A package consists of one or multiple crates, but no more than one library crate.
Creating packages
to create a new package consisting of one binary crate, you can run cargo new
to create a new package consisting of one library crate, you can run cargo new --lib
to create a package consisting of a library as well as one or multiple binaries, you can run either cargo new or cargo new --lib and then modify the package directory structure to add the other crate
When should you use crates, and when should you use packages?
As you can see now, this question doesn't really make sense – you should and must always use both. A package can't exist without at least one crate, and a crate is (at least if you are using Cargo) always part of a package.
Therefore, a better question is this:
When should you put multiple crates into one package?
There are multiple reasons to have more than one crate in a package. For example:
If you have a binary crate, it is idiomatic to have the "business logic" in a library in the same package. This has multiple advantages:
Libraries can be integration tested while binaries can't
If you later decide that the business logic needs to also be used in another binary, it is trivial to add this second binary to the package and also use the library
If you have a library crate that generates some files (a database engine or something like that), you may want to have a helper binary to inspect those files
Note that if you have a very big project, you may instead want to use the workspace feature of Cargo in these cases.
I am new to Rust, so excuse me if im just doing things horribly wrong.
While larning the language i wanted to try out different bindings of libraries that i already used in other languages, amongst them SDL2, SFML2, Gtk3.
To my surprise, nothing seemed to work out of the box. They all depend on C libraries and those don't come with the cargo crate. I managed to get SFML2 to work after following the readme and manually copying .lib and .dll files to the right places. I tried to make the Rust linker to look into my vcpk directory for .lib files, sadly with no success.
The whole point of a package manager kind of is to automate these things for you. Other package managers like NuGet for C# dont require you to manually fiddle the dependencies for their packages together.
Getting rid of the thirdparty library management hell of C/C++ was one of the reasons why i took a closer look at Rust.
Am i doing something wrong, or is this just how things are with Rust/Cargo?
Cargo is a build management and source package management tool for Rust code - it is not a tool for managing binaries or compiling other languages such as C or C++.
Having said that, it is a very flexible tool so it is possible for crates that provide bindings to libraries written in other languages to "bundle" the libraries they depend on.
The Rust-SDL2 crate, for example, does offer such a feature - as it says in their README:
Since 0.31, this crate supports a feature named "bundled" which
downloads SDL2 from source, compiles it and links it automatically.
To use this, you would would add it to your Cargo.toml like this:
[dependancies]
sdl2 = { version = "0.34.0", features=["bundled"] }
Not all such binding crates support bundling, especially if the libraries they bind to are large, complex, have lots of their own dependencies and/or have lots of compile time configuration options.
In those cases you will either need to install a pre-compiled binary, or compile them from source yourself.
This question was asked before Rust officially supported incremental compilation. Rust 1.24.0 and later enable incremental compilation by default for development (debug) builds.
I'm an outsider trying to see if Rust is appropriate for my projects.
I've read that Rust lacks incremental compilation (beta features notwithstanding).
Is this similar to having everything be implemented in the headers in C++ (like in much of Boost)?
If the above is correct, does this limit Rust to rather small projects with small dependencies? (If, say, Qt or KDE were header-only libraries, then programs using them would be extremely painful to develop, since you'd effectively recompile Qt/KDE every time you want to compile your own code.)
In C and C++, a compilation unit is usually a source file and all the header files it transitively includes. An application or library is usually comprised of multiple compilation units that are linked together. An application or library can additionally be linked with other libraries. This means that changing a source file requires recompiling that source file only and then relinking, changing an external library only requires relinking, but changing a header file (whether it's part of the project or external; the compiler can't tell the difference) requires recompiling all source files that use it and then relinking.
In Rust, the crate is the compilation unit. (A crate can be an application or a library.) Rust doesn't use header files; instead, the equivalent information is stored as metadata in the compiled crates (which is faster to parse, and has the same effect as precompiled headers in C/C++). A crate can additionally be linked with other crates. This means that changing any of the source files for a crate requires recompiling the whole crate, and changing a crate requires recompiling all crates that depend on it (currently, this means recompiling from source, even if the API happens to not have changed).
To answer your questions, no, Rust doesn't recompile all dependencies every time you recompile your project; quite the opposite in fact.
Incremental compilation in Rust is about reusing the work done in previous compilations of a crate to speed up compilation times. For example, if you change a module and it doesn't affect the other modules, the compiler would be able to reuse the data that was generated when the other modules were compiled last time. The lack of incremental compilation is usually only a problem with large or complex crates (e.g. those who make heavy use of macros).
Background
I inherited and maintain a Linux shared library that is very closely coupled with specific hardware; let's call it libfoo.so.0.0.0. This library has been around for some time and "just worked". This library has now become a dependency for several higher-layer applications.
Now, unfortunately, new hardware designs have forced me to create symbols with wider types, thereby resulting in libfoo.so.0.1.0. There have been only additions; no deletions or other API changes. The original, narrow versions of the updated symbols still exist in their original form.
Additionally, I have an application (say, myapp) that depends on libfoo. It was originally written to support the 0.0.0 version of the library but has now been reworked to support the new 0.1.0 APIs.
For backwards compatibility reasons, I would like to be able to build myapp for either the old or new library via a compile flag. The kernel that a given build of myapp will be loaded on will always have exactly one version of the library, known at compile time.
The Question
It is very likely that libfoo will be updated again in the future.
When building myapp, is it possible to specify a minimum version of libfoo to link against based on a build flag?
I know it is possible to specify the library name directly on the build CLI. Will this cause myapp to require exactly that version or will later versions of the lib with the same major revision still be able to link against it (ex. libfoo.so.0.2.0)? I am really hoping to not have to update every dependent app's build each time a new minor version is released.
Is there a more intelligent way of accomplishing this in an application-agnostic way?
References
How do you link to a specific version of a shared library in GCC
You are describing external library versioning, where the app is built against libfoo.so.0, libfoo.so.1, etc. Documentation here.
Using external library versioning requires that exactly the same version of libfoo.so.x be present at runtime.
This is generally not the right technique on Linux, which, through the magic of symbol versioning, allows a single libfoo.so.Y to provide multiple incompatible definitions of the same symbol, and thus allows a single library serve both the old and the new applications simultaneously.
In addition, if you are simply always adding new symbols, and are not modifying existing symbols in incompatible way, then there is no reason to increment the external version. Keep libfoo.so at version 0, provide a int foo_version_X_Y; global variable in it (as well as all previous versions: foo_version_1_0, foo_version_1_1, etc.), and have an application binary read the variable that it requres. If an application requires a new symbol foo_version_1_2 and is run with an old library that only provides foo_version_1_1, then the application will fail to start with an obvious error.
When I run cabal build it uses some Haskell compiler to build the executables and/or test-suites in my .cabal file.
Can I control which compiler is used for the different targets? Ideally, I would like to have separate build targets that use ghc and ghcjs in the same .cabal file. It seems to me that someone might want to use ghc and hugs or two version of ghc in the same project. Is this currently possible?
Also, how does cabal decide what compiler to use when running cabal build? I saw there is a compiler option in my ~/.cabal/config file but changing it from ghc to ghcjs and uncommenting it, did not seem to change what cabal build does.
The compiler to use is determined during the configure step (or during an install step's implicit configure step, which does not share configuration options with a previous configure step). It is also determined by the entity building the package and cannot be influenced by the person writing the package. Probably what happened to you is that a previous cabal build implicitly invoked the configure step and chose a compiler; future builds will keep a previous choice of compiler over one stuck in your global configuration file. You can countermand that by simply manually running cabal configure again.
It is possible to cause a build to fail with the wrong implementation, e.g.
library
if impl(ghc)
buildable: False
will prevent cabal from trying to build the package using GHC. However, this isn't really useful for building separate parts of a package with separate compilers, as cabal will refuse to install a package unless it can build the whole thing with a single compiler.
Probably the best way forward is to make separate packages for things that should be built by separate compilers.