MPI.jl icon indicating copy to clipboard operation
MPI.jl copied to clipboard

Intended way to generate MPI.jl compatible C bindings

Open termi-official opened this issue 3 years ago • 13 comments

I am currently trying to generate MPI.jl compatible bindings of the C library HYPRE with the help Clang.jl . The current generator (found here https://github.com/termi-official/HYPRE.jl/blob/master/gen/generator.jl) creates files that have incompatible data types (see e.g. https://github.com/termi-official/HYPRE.jl/blob/master/lib/LibHYPRE.jl#L6), so I was wondering what the intended way to grab the correct MPI headers and data type definitions is?

cc @fredrikekre @Gnimuc

termi-official avatar Oct 04 '22 16:10 termi-official

Can gen/src/MPIgenerator.jl be of inspiration? That script is used to generate the new low-level API.

giordano avatar Oct 04 '22 16:10 giordano

(Slightly tangential, I am curious why there is a mismatch between https://github.com/JuliaParallel/MPI.jl/blob/3f21294863a55fbbefa8376bd489bceec84dc478/src/api/mpich.jl#L35 and https://github.com/fredrikekre/HYPRE.jl/blob/50c06161e9b654c5095dffd6a6b6e0978f1ae851/lib/LibHYPRE.jl#L6 since they are both (apparently) generated based on MPICH headers)

fredrikekre avatar Oct 04 '22 16:10 fredrikekre

Thanks for the quick answer and your suggestion. I already tried to use this one as a template.

diff --git a/gen/generator.jl b/gen/generator.jl
index d6880cb..3df8f19 100644
--- a/gen/generator.jl
+++ b/gen/generator.jl
@@ -1,10 +1,18 @@
 using Clang.Generators
-using HYPRE_jll, MPICH_jll
+using HYPRE_jll, MPIPreferences
 
 cd(@__DIR__)
 
+if MPIPreferences.binary == "MPICH_jll"
+    import MPICH_jll: artifact_dir
+elseif MPIPreferences.binary == "OpenMPI_jll"
+    import OpenMPI_jll: artifact_dir
+else
+    error("Unknown MPI binary: $(MPIPreferences.binary)")
+end
+
 hypre_include_dir = normpath(HYPRE_jll.artifact_dir, "include")
-mpi_include_dir = normpath(MPICH_jll.artifact_dir, "include")
+mpi_include_dir = normpath(artifact_dir, "include")
 
 options = load_options(joinpath(@__DIR__, "generator.toml"))

but the types are still not matching - and we generate quite a bit of redundant code which is readily available in MPI.jl.

termi-official avatar Oct 04 '22 16:10 termi-official

(Slightly tangential, I am curious why there is a mismatch between https://github.com/JuliaParallel/MPI.jl/blob/3f21294863a55fbbefa8376bd489bceec84dc478/src/api/mpich.jl#L35 and https://github.com/fredrikekre/HYPRE.jl/blob/50c06161e9b654c5095dffd6a6b6e0978f1ae851/lib/LibHYPRE.jl#L6 since they are both (apparently) generated based on MPICH headers)

I'm not entirely sure that file was automatically generated from header files,

giordano avatar Oct 04 '22 16:10 giordano

This could maybe be of inspiration https://github.com/cesmix-mit/LAMMPS.jl/tree/main/res

vchuravy avatar Oct 04 '22 17:10 vchuravy

I'm not entirely sure that file was automatically generated from header files,

It wasn't, that was manually translated.

I don't think it matters which one we use. I'm not sure why I changed them to unsigned? Perhaps changing them back to Cint would make things easier.

simonbyrne avatar Oct 04 '22 17:10 simonbyrne

This could maybe be of inspiration https://github.com/cesmix-mit/LAMMPS.jl/tree/main/res

Sorry to ask again, but how exactly is the variable mpi_header_dir (https://github.com/cesmix-mit/LAMMPS.jl/blob/main/res/wrap.jl#L13) resolved? I could not find it in MPI.jl, LAMMPS_jll or Clang.jl .

termi-official avatar Oct 04 '22 17:10 termi-official

I don't think it matters which one we use. I'm not sure why I changed them to unsigned? Perhaps changing them back to Cint would make things easier.

Okay, I ran into MethodError: Cannot convert an object of type MPI.Comm to an object of type Int32 when ccalling a function generated with Clang (based on the MPICH header) which then had Cint for the argument, and cconvert(::Type, ::MPI.Comm) fails. Perhaps https://github.com/JuliaParallel/MPI.jl/blob/61947d925f0b5dee1c62ed1f668a77be19ee9947/src/comm.jl#L10 could be relaxed a bit? Probably that could be

Base.cconvert(::Type{T}, comm::Comm) where {T <: Integer} = convert(T, comm.val)

?

fredrikekre avatar Oct 04 '22 21:10 fredrikekre

Lets just change them to signed: that's what they are in the headers.

simonbyrne avatar Oct 04 '22 22:10 simonbyrne

Basically, we can reuse symbols from MPI by treating MPI headers as system headers.

Change this line:

push!(args, "-I$(mpi_include_dir)")

to

push!(args, "-isystem$(mpi_include_dir)")

Gnimuc avatar Oct 05 '22 01:10 Gnimuc

In this way, all useless symbols under mpi_include_dir will be ignored, so symbols from MPI.jl can be added on demand and you get no conflicts.

Gnimuc avatar Oct 05 '22 01:10 Gnimuc

Basically, we can reuse symbols from MPI by treating MPI headers as system headers.

Change this line:

push!(args, "-I$(mpi_include_dir)")

to

push!(args, "-isystem$(mpi_include_dir)")

Exactly what I was looking for - thanks!

Now, if I am understanding correctly, then Binary Builder ensures that an artifact matching the MPI backend selected in MPIPreferences is selected, right?

termi-official avatar Oct 05 '22 12:10 termi-official

I've changed the MPICH and Microsoft MPI handles to now be signed ints (#668), I'll tag a new patch release.

It would be great to turn this discussion into some docs.

simonbyrne avatar Oct 05 '22 17:10 simonbyrne