Managing transitive package dependencies declared via uses constraints - osgi

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?

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?

Related

Golang: multiple definition of CGO ported package

I have 2 project, the first, name as A, there is a submodule a imported sqlite3(github.com/mattn/go-sqlite3). Another B project import A's submodule a, and in another submodule b, it also import the same sqlite3.
Both A and B put there imports under vendor dir(managed by govendor). My Golang version is go version go1.12 linux/amd64.
While build B (go build main.go), throwing following errors(too many, part of them):
/usr/local/go/pkg/tool/linux_amd64/link: running gcc failed: exit status 1
/tmp/go-link-281256755/000029.o: In function `callbackTrampoline':
/tmp/go-build/_cgo_export.c:25: multiple definition of `callbackTrampoline'
/tmp/go-link-281256755/000005.o:/tmp/go-build/_cgo_export.c:25: first defined here
/tmp/go-link-281256755/000029.o: In function `stepTrampoline':
...
/home/xxx/go/src/gitlab.xxxxxxxxx.com/xxxxxxxxx-tools/A/vendor/github.com/mattn/go-sqlite3/sqlite3.go:129: multiple definition of `_sqlite3_result_text'
/tmp/go-link-281256755/000009.o:/home/xxx/go/src/gitlab.xxxxxxxxx.com/xxxxxxxxx-tools/A/vendor/github.com/mattn/go-sqlite3/sqlite3.go:129: first defined here
/tmp/go-link-281256755/000033.o: In function `_sqlite3_result_blob':
...
But building A works well. To testing the error, I started following demo, also with vendor inited by govendor, and build ok.
package main
import (
"database/sql"
"fmt"
"gitlab.xxxxxxxxx.com/xxxxxxxxxxxxxxx/A/a"
_ "github.com/mattn/go-sqlite3"
)
func main() {
fmt.Println(a.ModuleVariable) // use submodule `a` just like B is doing
_, _ = sql.Open(`sqlite3`, `test.db`) // use sqlite too
}
I think the compiler first compile A's sqlite3, objects are created under /tmp/go-link-281256755/000005.o (but no this dir after building), then compile B's importing of sqlite3 and also create a object contains the same-name function, then the compiler find 2 same-name symbols, the linking failed.
How to fix these situation? Is there any golang env settings to avoid these?
After I remove the sqlite3 package under vendor both of A and B, they both use the sqlite3 under ~/go/src/github.com/mattn/go-sqlite3/, they all build ok. But I can't do these, due to project A's deploy platform, I must put all dependencies under vendor, is there any another option to use multiple import with the same package?
For the cgo's issue of linking error "multiple definition of ...", the (work-around) solution is dependent on the nature of the linked C codes:
If two Go packages link to the same C codes (libraries), you should pass option --allow-multiple-definition to the linker (see ld man page), either via command options
go build --ldflags '-extldflags "-Wl,--allow-multiple-definition"',
or via #cgo directive in Go source of the packages linking to C codes:
//#cgo LDFLAGS: -Wl,--allow-multiple-definition
import "C"
If two Go packages link to different C codes containing some functions & variables with the same names, you should refactor those C codes:
Make sure to put keyword static to all declarations whose usage is within that C object only (not intended to be linked to Go nor to other C objects).
Find some way to do name mangling or put those duplicated identifiers into different namespaces (like in C++). It would be better if cgo supported some mechanism to do automatic namespacing using Go package name, but until now (2020) you must do it yourself. The C preprocessor's "token pasting" operator ## may help in this namespacing task. Eg.
//File: my_package1.h
#define NS(id) my_package1_ ## id
void NS(my_function1)(int);
void NS(my_function2)(float);
char NS(my_shared_var);
If you have any C function definition in the Go source, like in this question, you must move those definitions into a separate C source file under the same package folder, leaving only declarations in the Go source.

How to organize my python modules and packages

So I have written a module A and a dedicated test-file. This module can be used alone, but I wrote it to be used as a "base" for a second module I wrote. This second module absolutely needs the first one, and also has it's own test-file.
Finaly, I wrote a third module that is based on the first two modules. In other words :
module A, can be used without B or C.
module B needs module A, and can be used without C
module C needs module B (and so also A)
My question is how do treat all these modules ? For example, should I make each module a package, and then import A in B, and B in C ? Or should I put them all in a single package ? Also, what do I do of all the test files (put them next to the module, or all in a single test-folder) ?
As of today, I am treating each one as a package, but it seems a bit heavy to have to install A and B for using C:
+ moduleA
- moduleA.py
- test_moduleA.py
+ moduleB
- moduleB.py
- test_moduleB.py
+ moduleC
- moduleC.py
- test_moduleC.py
So I was thinking about merging all like this :
+ moduleC
- moduleA.py
- moduleB.py
- moduleC.py
+ tests
- test_moduleA.py
- test_moduleB.py
- test_moduleC.py
Is that the pythonic way to wrap my module C (and all its components) ? Or should I nest the modules in subpackages (moduleC.moduleB.moduleA) ?
The goal of all this is to export to github-like platform, and eventually pip.
The modules seem to be independent so they should be developed separately: separate development directories, separate git repositories.
For proper installation the modules should declare dependencies: B depends on A and C directly depends on B and indirectly (transitively via B) depends on A. Such dependencies should be declared in setup.py:
In B:
setup(
…
install_requires=[A]
…
)
In C:
setup(
…
install_requires=[B]
…
)
No need to declare dependency on A as B when being installed brings A with it.
This way when installing pip install A A will be installed alone;
when installing pip install B B will be installed with A;
when installing pip install C C will be installed with both A and B.

Is there a way to show the dependency graph of a Go package?

For example, given a package A that depends on package B and package C, where package C also depends on package D - is there a way to output this information? (Using a vendoring tool or otherwise)
The vendor.yaml output by govend doesn't include transitive dependency information - neither does the Gopkg.toml file
output by dep, from what I can see. The go.mod file produced by Golang 1.11's mod and does annotate some dependencies as // indirect - but it does not annotate dependencies with any information about which dependency they were pulled in via.
Did you try https://github.com/KyleBanks/depth?
It does provide a decent dependency tree at first look I tried.

class loading of OSGi on Required-Bundle and Imported-Package

For OSGi bundle, we can add dependencies by using Required-Bundle or Imported-Package. Now I have below case:
Both bundle A and bundle B export same packages, but bundle B with higher version, like:
bundle A:
Exported Packages:
xxx.a,
xxx.b,
xxx.c
bundle B:
Exported Packages:
xxx.a; version="5.0.0",
xxx.b; version="5.0.0",
xxx.c; version="5.0.0"
And bundle C has the dependency to package a, b, c, so it adds A in its Required-Bundle list, like
bundle C:
Required Bundles:
A
Let's assume both bundle A and B are resolved in the framework. So when resolving bundle C, which packages/classes are been loaded by C, the classes in A or classes B? I think is A. Am i right?
Yes, the packages from A are used because you require bundle A.
Please note that Require-Bundle is considered deprecated by most OSGi developers.

Access class of other OSGi bundle

My project has two bundles, lets say Bundle A and Bundle B.
Now Bundle A needs to access a class from Bundle B.
How can I do that?
There are two ways:
Add the dependency of bundle B to the Manifest of bundle A: Require-Bundle: bundle-id-of-bundle-A
Import the package of the wanted class in the Manifest of bundle A: Import-Package: package.of.your.class
In both situations, you need to export the package that contains your class in bundle B: Export-Package: package.of.your.class
Also, here's a good intro:
http://ctpjava.blogspot.com/2010/09/introduction-to-osgi.html
As #earcam wrote, it is strongly recommended to use Import-Package:.
Also, always add a version to the exported package in bundle B - this is good practice that you will appreciate later when you create the next version of bundles A and B.

Resources