Dan Gravell
Dan Gravell

Reputation: 8275

Managing transitive package dependencies declared via uses constraints

I have bundles A, B and C. A contains a package 'a' that is depended on by code in packages b and c from bundles B and C respectively.

bundle A {
  package a

  export-package:a
}

bundle B {
  package b.a
  package b.b
  package b.c
  package b.d
  package b.e

  import-package: a
  export-package:b.a;uses:=a,
    b.b;uses:=b.a,
    b.c;uses:=b.b,
    b.d;uses:=b.c,
    b.e;uses:=b.d
}

bundle C {
  package c

  import-package: b.e,
    a
}

When I update all of these bundles together, I often get uses constraint violations (Felix reporting style):

Chain 1:
  C [47.1]
    import: (&(osgi.wiring.package=a)(version>=1.1.0))
     |
    export: osgi.wiring.package=a
  A [9.1]

Chain 2:
  C [47.1]
    import: (&(osgi.wiring.package=b.e)(version>=1.0.0))
     |
    export: osgi.wiring.package=b.e; uses:=a
  B [33.0]
    import: (&(osgi.wiring.package=a)(version>=1.0.0))
     |
    export: osgi.wiring.package=a
  C [9.0]

I was initially surprised that b.e generates a uses clause for 'a'. This is not declared in the Manifest nor the OBR repository.xml through which these bundles are provisioned. However, types in b.e expose types in a through their API, so I guess this is where it comes from.

The only way I find to resolve these is to increase the version number of the export and import of intermediate packages, e.g. b.e in this example. However, there are a lot of packages that ultimately use 'a', transitively.

This means every time I update 'a' I also need to update all transitive dependencies on a with new versions. Is it the correct thing to be doing to increase the version number of these packages? Is refactoring my code to be less interdependent the only other way?

Upvotes: 1

Views: 342

Answers (1)

BJ Hargrave
BJ Hargrave

Reputation: 9384

The uses constraints are not handled transitively by the resolver.

If bundle C imports b.e and b.e used b.d, then bundle C also needs to import b.d. That is, the public signature of b.e includes a reference to something in b.d. This is why we say b.e uses b.d. Therefore, any bundle which imports b.e must also import b.d. Otherwise the bundle cannot properly use b.e since some type referenced in b.e is not visible to the bundle.

For the export of b.e, it should state it uses b.d, b.c, b.b, b.a and a since using b.d means you also use b.c and so on...

Did you hand generate your uses clauses? Or was this example derived from something bnd generated?

Upvotes: 3

Related Questions