23.2. Cross-Platform Dependencies

Ordinarily, when A depends on B, abuild requires that B be buildable on every platform that A is being built on. In this case, the instance of A being built on platform p depends specifically on the instance of B being built on platform p. Under these rules, it would be impossible for A to depend on B if B couldn't be built on all of A's platforms. This would make it impossible for a platform-independent item to depend on any object-code or Java build items or for object-code and Java build items to depend on each other. (There is a special case that any item can depend on a platform-independent build item.) To make these other cases possible, abuild allows a dependency to declare a specific platform using the -platform flag. Rather than declaring a platform by name, the argument to the -platform argument is either a platform type or a platform-type-qualified platform selector. In this case, the instance of A on each of its platforms depends on the specifically selected instance of B.

To choose which of B's platforms will be used, abuild picks the first platform in the given type that matches the platform selector. Matches are performed using the same technique as when platform selectors are specified on the command line with two exceptions: the criteria field may be omitted, and the selector only ever matches a single platform even if * appears as one of the fields. Abuild versions prior to 1.1 ignored any platform specifiers given on the command line or in the environment when resolving cross-platform dependencies, but the abuild does take them into consideration. If you want to specify a platform-specific dependency on the default platform for a given platform type regardless of any platform selectors, you can specify platform-type:default as the -platform option to your dependency.

The other situation in which a build item may depend on another item with different platforms occurs with pass-through build items. In this case, if A1 and A2 depend on pass-through item P which in turn depends on B1 and B2, abuild will create effective dependencies between the As and the Bs based on platform type (see Figure 23.1, “Multiplatform Pass-through Build Item”).

Figure 23.1. Multiplatform Pass-through Build Item

Multiplatform Pass-through Build Item

Pass-through item P effectively connects A1 to B1 and A2 to B2 based on their platform types.


The documentation doesn't provide a specific example that illustrates that case because this type of usage would be fairly unusual. [49] Instead, we will provide a description of how it would work. Suppose you had a plugin to support VxWorks, an embedded operating system, that added a platform type vxworks, and you wanted to provide a custom threading library that worked for your native platform and for VxWorks. Suppose also that your native library implementation used boost threads but that you wanted to create a VxWorks implementation that used VxWorks native threads. You could create a pass-through build item called threads that depends on threads.native and threads.vxworks, and you could set up threads.native to have platform-types native and threads.vxworks to have platform-types vxworks. The threads build item would not declare any platform types. It would just depend on threads.vxworks and threads.native. If you now had a program that supported both native and vxworks that depended on threads, your application would use the threads.native implementation when it built on the native platforms and the threads.vxworks implementation when it built on vxworks platforms. This would happen transparently because of the pass-through build item. To fully understand why this works, please see Section 32.6, “Construction of the Build Graph”. Note that you could also put conditionals in your Abuild.interface and/or Abuild.mk to avoid having to split this into multiple build items, so this is not the only solution. The same trick would work if you wanted to create a facade for a library that was implemented in multiple languages, though it's unlikely that there would be any reason to do that: although you can have one build item that builds for multiple platform types, you can't have a single build item that builds for multiple languages.

23.2.1. Interface Errors

Under a very specific set of circumstances, it is possible to have a subtle and hard-to-understand error condition involving interface variables with cross-platform dependencies. You should feel free to skip this section unless you are either determined to understand the deepest subtleties of how abuild works or you have been directed here by an error message issued by abuild. To understand the material in this section, it will help to understand Section 32.6, “Construction of the Build Graph” and Section 32.7, “Implementation of the Abuild Interface System”.

Internally, when abuild builds a build item, it loads the interfaces of all the other build items that the item depends on. If item A depends on item B in two different ways (say directly and indirectly or indirectly through two different dependency paths), abuild will effectively still load B's interface file only one time because of the way the interface system keeps track of things. At least this is what happens under normal circumstances. If, however, the two different instances of B in A's dependency chain are from different platforms, problems can arise.

We should note that this can happen only under the following conditions:

  • Build item A depends (directly or indirectly) on two items, which we'll call X1 and X2.

  • Both X1 and X2 depend on B.

  • At least one of X1 and X2 depends on B with a platform-specific dependency. If both do, they do so with different platform specifications.

When all of the above conditions have been met, A will have two different instances of B in its dependency chain.

Once this situation has occurred, it becomes possible for there two be conflicting assignments to a variable, both of which originate from the same line of the same interface file. For example, if B's Abuild.interface file assigns the value of $(ABUILD_OUTPUT_DIR) to a scalar interface variable, the effect of that assignment will differ across the two different instances of B. Abuild will detect this case and issue an error message. (That error message will direct you here to this section of the manual!) If B assigns this to a list variable, there's no problem—abuild will honor both assignments. It's also no problem if the assignment doesn't have different meanings on the different platforms. It's only when the same assignment causes a conflict that abuild will complain.

If you should run into this situation, there are several possible remedies you should consider.

  • Rethink why you are using cross-platform dependencies in this way. If you're just trying to make sure that some other build item gets built, consider whether you can use build-also instead of platform-specific dependencies to meet your needs.

  • If you want both values and doing this won't hurt other build items, use a list variable instead of a non-list variable. In this case, abuild will give you both (all) values.

  • If you don't care which value you get, and doing so doesn't cause other problems for other build items, use a fallback or override assignment instead of a regular assignment. Then you'll get the first (in the case of fallback) or last (in the case of override) assignment that is processed.

  • If you can't change B's interface and A doesn't care about the value of the value, you can do a reset on the offending variable from the one or more of the items that A depends on and that depend on different instances of B. For example, X1 could have an after-build file that resets the offending variable. Then when A imports X1's interface, it will no longer include the conflicting assignment from B's interface.



[49] Okay, we don't provide an example because it's tricky to make one that would be more illustrative than confusing without an actual embedded platform to work with. If we did create an example, we'd have to make up some kind of simulated embedded platform with a plugin, and that would probably create more confusion than it would be worth.