I'd suggest that it's your approach to these libraries which is causing your problems. You can change this if you start to think about libraries as separate projects in their own right. Think of them as having their own reasons for being, their own design and their own release cycles, just like the 3rd party libraries you may use for unit testing, xml readers, db access, etc.
Of course you will regularly have times where a feature in a project requires a new feature in a library. Implementing the library feature and making use of the library function are two independent tasks - they may be one business task but they're two development tasks. There's no need to tightly link the two activities together just because that's how the job came in. Checkout the library, change it, release it, then checkout your project and use the new release of the library in your project.
I feel strongly that having libraries separated out into their own trunks is a good thing - I can't stand it when I see multiple independently releasable projects under a single trunk. It smacks of poor design and having been backed into a corner by development cruft. But to separate them out you have to be able to release each project independently - to me, that's what having multiple projects means. But it's not a hard thing to do:
First a project uses externals to reference a specific released version of a library. That's the only way a project references a library. Doing this means that developers can make a new version of the library without breaking any of the projects using it, because all projects will be referencing the previous version. Projects get to control when they want to bring in new versions of libraries - the developers get to choose when they want to put in the effort of testing their code with the new version and when to take the pain of fixing any build issues the new library introduces.
When you explicitly change versions of a library like this, you also get an entry in your project that says "I'm now using this version of library X", which gives you a good sense of history in your project as to when things were working and exactly when things changed.
Now of course, this is all nice in theory, but in practice developers will sometimes have to reference unstable and unfinished versions of a library. That's fine - a developer can always switch their working copy to point to library trunk instead of a tag, or some development branch, and use the code from there (even work on it through there if they must, brrr). A switch is just a local edit, so will have no effect on the committed code. If the project development is on an unstable branch, then you can decide to make the switch more permanent by changing the externals reference until the branch is ready to be reintegrated, but this isn't something that would normally be done without an explicit reason.
And, finally, branching and tagging your project becomes a simple case of making a branch or tag of your main project - that's all. There's no need to worry about branching libraries - they take care of themselves. The process of making a change to a library doesn't change whether the project is in trunk, a development branch, or a maintenance release. And your libraries can themselves have development branches entirely independent of the main projects, as well as multiple supported versions, etc, down to whatever level of complexity you need and can support.
By using externals on your trunk or development branch, you can have a single checkout that builds your workspace in whatever structure you need. Because all libraries are under the main root, you can have multiple checkouts of multiple versions without getting clashes in the build.
I've found this system works pretty well, and after moving jobs to a place that doesn't work this way, I find myself pining for the previous way of working. There are issues, mainly to do with libraries depending on libraries and whether to have recursive externals or not. My take on that is to go recursive unless it causes a problem (or excessive pain), then move to a 'degenerate' model where the project has to know about certain 'deep' dependencies even if it doesn't use them directly. Also, decide where you're going to put your externals definitions and stick to it, nothing's more annoying than hunting for those svn:externals properties on random folders in different projects. Putting them on the root of trunk is fine.