For dynamic libraries usually the hard part is finding them on the system (using pkg-config, searching dirs, building from source, etc.) and configuring them, so the simple #[link] directive is not enough (the #[link] directive just adds -l flags to the linker invocation).
So the usual solution is the first one. Do it in a separate $libraryname-sys crate, so that you won't have to duplicate the search-and-link code each time you use the library, and you'll just reuse the Rust sys crate for it.
So If I understand correctly, the only way to link is to use #[link] and the build.rs allows to find the library.
When using only build.rs and links in Cargo.toml, there is no link done.
Moreover, when I add links in my Cargo.toml, I can't link with two libraries to a common other library whereas with #[link], this limitation is gone.
links in Cargo.toml is just for preventing two crates linking the same library by accident.
#[link] and link directives printed by build.rs script are equivalent. The difference is build.rs can run code to build the link information dynamically rather than hardcoding it.