grasph/wrapit

LoadError: Double registration for method

peremato opened this issue · 14 comments

With this configuration I am getting following the error at module loading time:

ulia> using Geant4
[ Info: Precompiling Geant4 [559df036-b7a0-42fd-85df-7d5dd9d70f44]
Warning: Type 8G4String already had a mapped type set as G4StringAllocated using hash 5238750270 and const-ref indicator 0
ERROR: LoadError: Double registration for method (:function, :copy, :Base, 0x9df832de6d2b232b)

Somehow CxxWrap thinks the method or type is defined twice, but I do not see it in the generated code.

Any idea of this this could be? When I tried yesterday it was somehow working.

Hello Pere,

I cannot reproduce the issue, because it fails before with the following error:

/home/opt/lib/libG4geometry.so: cannot allocate memory in static TLS block

Philippe.

I guess the problem is a missing compilation/linking flag such as

  CXXFLAGS += -ftls-model=initial-exec -pthread

But the easiest is to use CMake to build the wrapper library instead of a hand-made Makefile. This is what I am using currently CMakeLists.txt

More info. The problem appears when I add G4Box.hh and G4UBox.hh to the list of headers. This explains why I was not getting this error yesterday.

input               = [ "Geant4Wrap.h",
                        "G4RunManager.hh",
                        "G4NistManager.hh",
                        "G4LogicalVolume.hh",
                        "G4PVPlacement.hh",
                        "G4Box.hh",
                        "G4UBox.hh" ]

Hello Pere,

Neither adding the compilation flag or using cmake to build fixed the issue I had. Nevertheless, I've managed to circumvent it by setting the environment variable LD_PRELOAD as:

LD_PRELOAD=/home/opt/lib/libG4geometry.so:/home/opt/lib/libG4digits_hits.so:/home/opt/lib/libG4processes.so 

Back to your issue, the problem comes from a typedef/alias in G4VSolid.hh:

using G4GeometryType = G4String;

Typedefs are not handled properly by wrapit. We still need to define how to do it. Current code makes a wrapper for the typedefs, but CxxWrap does not accept to have more than one wrapper for a type or one of its aliases. So it works only if the type is used uniformly with the same alias.

Two options to solve your issue, until I implement a clean handling of typedefs:

  1. Disabling typedef wrapping by commenting out the line #define WRAP_TYPEDEFS in src/CodeTree.cpp;
  2. or adding G4GeometryType in your veto file.

After fixing this, I have an error message about a CLHEP class. I expect this can be solved by adding a CLHEP header in the extra_headers but I've not investigated it more.

Philippe.

Thanks for looking into it. I did check the diff of the generated wrapper code between working and not working I didn't realize that the culprit was the wrapper for G4GeometryType.
What is the logic of generating the wrapper for the typesdefs if at the end is replaced by the actual type. Put it in another way, if a have a method/function returning a G4GeometryType, it will actually return a G4String for which we have the wrapper and CxxWrap knows about it. So, the typedef should be complete invisible, isn't it?

The function wrapper will actually return a G4GeometryType .

One solution would indeed be to resolve all typedefs to the underlying type. The drawbacks are that, first, the underlying type can be complex, in particular for templated types (take as example std::string), second, the function signature of the Julia binding will differ from the original one.

I do not think is true. In my case it returns a G4String or subclass of it.

box = G4Box("Box1", 1,2,3)

@test typeof(GetEntityType(box)) == Geant4.G4StringAllocated
@test typeof(GetEntityType(box)) <: G4String # Test Passed

@grasph What is needed for typedefs (at least in my use case) is the following:

  • Do not generate the wrapper for the typedef since it does not make sense because is an empty type with no methods. I have achieved this by adding the type to the veto file
  • Make sure that the real types are selected by adding their header files as input to wrapit
  • Add in the Julia module the following lines:
      const G4RotationMatrix = CLHEP!HepRotation
      const G4ThreeVector = CLHEP!Hep3Vector
      
      export G4ThreeVector, G4RotationMatrix
    
    I have done this step by hand, but it could be done with wrapit I guess.

With these changes I am able to create G4ThreeVectors and operate on them.

julia> box = G4Box("Box1", 1,2,3)
Geant4.G4BoxAllocated(Ptr{Nothing} @0x00007f9d136199f0)
julia> m1, m2 = G4ThreeVector(), G4ThreeVector()
(Geant4.CLHEP!Hep3VectorAllocated(Ptr{Nothing} @0x00007f9d0d4f6ca0), Geant4.CLHEP!Hep3VectorAllocated(Ptr{Nothing} @0x00007f9d10d27ea0))
julia> BoundingLimits(box, m1, m2)
julia> @test m1 == G4ThreeVector(-1,-2,-3)
Test Passed
julia> @test m2 == G4ThreeVector(1,2,3)
Test Passed
julia> @test m1 + m2 == G4ThreeVector()
Test Passed  

OK. Thanks for the feedback. The typedef is useful for the ex002-ROOT example. It's a special case. It's for FILE which is a typedef to a struct which is declared in the system header, but not defined

I agree with you that wrapper to typedef should not be produced and another approach should be taken for the FILE use case (or it should be produced only in absence of wrapper for the underlying type).

The Julia aliases are needed for convenience only. You could also use Geant4.CLHEP!Hep3Vector. Am I correct?

Philippe.

The Julia aliases are needed for convenience only. You could also use Geant4.CLHEP!Hep3Vector. Am I correct?

Yes, you can use Geant4.CLHEP!Hep3Vector but will diverge from the C++ way of naming and showing the implementation choices.

Workaround is working fine

Some followup:

  • This commit removes the typedef wrapper generation while solving use cases that depended on it.
  • Automatic generation of julia type aliases to reflect c++ typedef/using statements is put on the TODO list. The list contains items with higher priority, like proper support of templates and splitting the generated code in smaller source files.

@grasph With these changes I get runtime problems on static variables. For example I get the error:

ERROR: LoadError: UndefVarError: CLHEP!HepRotation!IDENTITY not defined
Stacktrace:
  [1] getproperty(x::Module, f::Symbol)

The generated wrapper being:

  // defined in /Users/Shared/cvmfs/sft.cern.ch/lcg/views/LCG_102/x86_64-centos7-gcc11-opt/include/CLHEP/Vector/Rotation.h:368:28
  types.method("CLHEP!HepRotation!IDENTITY", []()-> const CLHEP::HepRotation& { return CLHEP::HepRotation::IDENTITY; });

end the definition in C++ is:

   368    static const HepRotation IDENTITY;

@peremato above commit should fix the issue with CLHEP!HepRotation!IIDENTITY.