You are incurring the wrath of the dependency monster.
The fact is, if you have code in one project that directly depends upon the API of any single object in another project, then you have a project dependency and they cannot be built separately. What you really want to do is get control over your dependencies, and here's how you do that.
I have a Person object in project A which wants to communicate with another Person object, and it uses a Phone object to do so, from project B. Since Person is using a Phone instance, it has to intimately know the Phone class' API. First, pick up the phone, then wait for a dial tone, then dial a number specifically formatted for input into the phone, loop talking into the microphone and listening at the speaker until the communication is done, then hang up the phone. A highly detailed sequence of interactions that's specific to this Phone object in project B and does not apply to other forms of communication (using IM, smoke signals, semaphore, etc). Furthermore, I cannot build project A unless project B is already built, even if Phone is the only object I use in all of project B. I've created a directional project-level dependency from A to B because of this usage of Phone's API.
Furthermore, it might turn out that to get Phone to compile, it has dependencies all throughout project B. It depends on all sorts of objects in project B, so what this boils down to is: if there's a single problem in any one part of the entire project B, and it doesn't build, I can't build A.
Here's how to fix it. Project A should define what it needs from a communication device API and define an interface. This interface belongs in project A and any two Persons in project A can use it. This API might look like this:
This is off-the-cuff as an example--in a real system it would probably make sense to build it out quite a bit more (for instance, instead of blocking to wait for a response from sendMessage(), it might make more sense to register a listener and receive the responses asynchronously). In any case, this API is defined based upon what the Person object needs from a communication device.
Then, Phone, in project B, can implement this interface. Now, project A doesn't depend on project B, but the other way round. Is this any better? Well...yes and no. Now you can compile project A without B, but not B without A...on the other hand, B is much easier to compile because it doesn't depend on any actual *code* from A, only an interface with no code (and therefore not likely to contain any bugs). Furthermore, project A could package up this interface (and all such interfaces implemented in B) into a jar file and build that jar separately and provide it to project B. This would be called an "SP" jar ("service provider"), so-called because it provides a set of APIs to a service provider (project B) to be implemented.
Or, you could allow the Communicator interface to be in project B, and have B package up all such interfaces separately in a jar. This kind of jar would be called a "client" jar, so-called because it is provided to all clients of B. You might say that in the previous case of an SP jar, A was providing a kind of client jar to B, so what's the difference? You'd be correct...but an SP jar is a specific kind of client jar. It simply denotes the roles of the two projects. In the former case, B is providing a service to A by implementing APIs controlled by A (specified in the SP jar). In the latter, B is in control of and owns the interfaces (specified in the client jar), so it's not implementing a service requested by A.
Or, you could make the interface a completely separate project altogether, project C. Now, both projects A and B depend upon project C, but project C consists of nothing but interfaces--it has no code whatsoever so it's nearly guaranteed to build. In this case, the only output of building project C is to generate a jar (or jars) with highly abstract APIs in it. With this approach, project C plays the role of a specification (or perhaps a "protocol", depending on whether it contains interfaces that define what each project does, or simply the communication between the two projects).
Regardless of what approach you use, you are very wise to recognize that dependencies between projects are something that must be carefully controlled.
For more information on these ideas, read the following articles in
this list: Stability and the Dependency Inversion Principle.