diff --git a/examples/ex19.jl b/examples/ex19.jl index 11539c5b..7539eb8c 100644 --- a/examples/ex19.jl +++ b/examples/ex19.jl @@ -258,7 +258,13 @@ end opts = isinteractive() ? NamedTuple() : PETSc.parse_options(filter(a -> a != "-log_view", ARGS)) log_view = "-log_view" in ARGS -petsclib = PETSc.getlib(; PetscScalar = Float64, PetscInt = Int32) +petsclib = try + PETSc.getlib(; PetscScalar = Float64, PetscInt = Int32) +catch + # Fall back to any available Float64 library (e.g. when only the + # Int64 variants are built, or with a set_library! custom library) + first(filter(l -> PETSc.scalartype(l) == Float64, collect(PETSc.petsclibs))) +end PETSc.initialize(petsclib; log_view) _T = Float64 diff --git a/src/LibPETSc_startup.jl b/src/LibPETSc_startup.jl index a6078304..42dc6038 100644 --- a/src/LibPETSc_startup.jl +++ b/src/LibPETSc_startup.jl @@ -16,18 +16,29 @@ using Preferences # @load_preference is evaluated at compile time; changing a preference via # set_library!() triggers automatic recompilation (standard Preferences.jl behaviour). +# +# Only ONE PetscInt width is registered per process (default Int64, +# switchable with the "PetscInt" preference / `set_petscint!`). The Int64 +# and Int32 libpetsc variants link external packages that export identical +# symbols with different integer ABIs (hypre, SuperLU_DIST), so loading +# both widths into one flat ELF namespace cross-binds those symbols. const libs = @static if @load_preference("library_path", nothing) === nothing using PETSc_jll - ( - ((PETSc_jll.libpetsc_Float64_Real_Int64,), Float64, Int64), - ((PETSc_jll.libpetsc_Float32_Real_Int64,), Float32, Int64), - ((PETSc_jll.libpetsc_Float64_Complex_Int64,), Complex{Float64}, Int64), - ((PETSc_jll.libpetsc_Float32_Complex_Int64,), Complex{Float32}, Int64), - ((PETSc_jll.libpetsc_Float64_Real_Int32,), Float64, Int32), - ((PETSc_jll.libpetsc_Float32_Real_Int32,), Float32, Int32), - ((PETSc_jll.libpetsc_Float64_Complex_Int32,), Complex{Float64}, Int32), - ((PETSc_jll.libpetsc_Float32_Complex_Int32,), Complex{Float32}, Int32), - ) + @static if @load_preference("PetscInt", "Int64") == "Int32" + ( + ((PETSc_jll.libpetsc_Float64_Real_Int32,), Float64, Int32), + ((PETSc_jll.libpetsc_Float32_Real_Int32,), Float32, Int32), + ((PETSc_jll.libpetsc_Float64_Complex_Int32,), Complex{Float64}, Int32), + ((PETSc_jll.libpetsc_Float32_Complex_Int32,), Complex{Float32}, Int32), + ) + else + ( + ((PETSc_jll.libpetsc_Float64_Real_Int64,), Float64, Int64), + ((PETSc_jll.libpetsc_Float32_Real_Int64,), Float32, Int64), + ((PETSc_jll.libpetsc_Float64_Complex_Int64,), Complex{Float64}, Int64), + ((PETSc_jll.libpetsc_Float32_Complex_Int64,), Complex{Float32}, Int64), + ) + end else let _path = @load_preference("library_path"), _scalar = @load_preference("PetscScalar", "Float64"), diff --git a/src/PETSc.jl b/src/PETSc.jl index 49d109f3..4c051aa2 100644 --- a/src/PETSc.jl +++ b/src/PETSc.jl @@ -23,7 +23,7 @@ using .LibPETSc export LibPETSc export audit_petsc_file export set_petsclib -export set_library!, unset_library!, library_info +export set_library!, unset_library!, set_petscint!, library_info export AbstractPETScMemBackend, HostBackend export determine_memtype export get_petsc_arrays, restore_petsc_arrays diff --git a/src/init.jl b/src/init.jl index b68e0bf2..e24f4763 100644 --- a/src/init.jl +++ b/src/init.jl @@ -337,6 +337,25 @@ function unset_library!() @info "PETSc library preference removed — restart Julia to revert to PETSc_jll." end +""" + set_petscint!(::Type{T}) where {T<:Union{Int32,Int64}} + +Persistently select which `PetscInt` width of the `PETSc_jll` libraries is +loaded (default: `Int64`). Only one width is registered per process: the +Int64 and Int32 library variants link external packages (hypre, +SuperLU_DIST) that export identical symbols with different integer ABIs, +so mixing both widths in one process is unsafe on platforms with a flat +dynamic-linker namespace. + +Takes effect on the next Julia session (standard Preferences.jl +recompilation). Has no effect when a custom library is configured via +[`set_library!`](@ref). +""" +function set_petscint!(::Type{T}) where {T<:Union{Int32,Int64}} + @set_preferences!("PetscInt" => string(T)) + @info "PETSc_jll PetscInt width set — restart Julia to use it." PetscInt = T +end + """ check_petsc_wrappers_version(petsclib=nothing) diff --git a/test/dmda.jl b/test/dmda.jl index c39a9587..e2731057 100644 --- a/test/dmda.jl +++ b/test/dmda.jl @@ -345,7 +345,7 @@ end mpirank = MPI.Comm_rank(comm) mpisize = MPI.Comm_size(comm) # Just check a couple libraries - for petsclib in PETSc.petsclibs[1:2] + for petsclib in PETSc.petsclibs[1:min(2, length(PETSc.petsclibs))] #petsclib = PETSc.petsclibs[1] PETSc.initialize(petsclib) PetscScalar = petsclib.PetscScalar diff --git a/test/init.jl b/test/init.jl index f331f6d3..a88ff648 100644 --- a/test/init.jl +++ b/test/init.jl @@ -185,12 +185,15 @@ using PETSc PETSc.finalize(custom_lib) @test !PETSc.initialized(custom_lib) - # Test with different scalar/int types - lib_path_f32 = PETSc.petsclibs[2].petsc_library # Float32 library - custom_lib_f32 = PETSc.set_petsclib(lib_path_f32; PetscScalar=Float32, PetscInt=Int64) - @test custom_lib_f32 isa PETSc.LibPETSc.PetscLibType{Float32, Int64, String} - @test PETSc.scalartype(custom_lib_f32) == Float32 - @test PETSc.inttype(custom_lib_f32) == Int64 + # Test with different scalar/int types (only when more than one + # library is configured; with set_library! there is just one) + if length(PETSc.petsclibs) >= 2 + lib_path_f32 = PETSc.petsclibs[2].petsc_library # Float32 library + custom_lib_f32 = PETSc.set_petsclib(lib_path_f32; PetscScalar=Float32, PetscInt=Int64) + @test custom_lib_f32 isa PETSc.LibPETSc.PetscLibType{Float32, Int64, String} + @test PETSc.scalartype(custom_lib_f32) == Float32 + @test PETSc.inttype(custom_lib_f32) == Int64 + end end end diff --git a/test/test_dmstag.jl b/test/test_dmstag.jl index 2b14cabc..a290803f 100644 --- a/test/test_dmstag.jl +++ b/test/test_dmstag.jl @@ -11,7 +11,7 @@ end comm = Sys.iswindows() ? LibPETSc.PETSC_COMM_SELF : MPI.COMM_WORLD mpirank = MPI.Comm_rank(comm) mpisize = MPI.Comm_size(comm) - for petsclib in PETSc.petsclibs[1:4] + for petsclib in PETSc.petsclibs[1:min(4, length(PETSc.petsclibs))] #petsclib = PETSc.petsclibs[1] PETSc.initialize(petsclib) PetscScalar = PETSc.scalartype(petsclib) @@ -471,7 +471,7 @@ end comm = Sys.iswindows() ? LibPETSc.PETSC_COMM_SELF : MPI.COMM_WORLD mpirank = MPI.Comm_rank(comm) mpisize = MPI.Comm_size(comm) - for petsclib in PETSc.petsclibs[1:4] + for petsclib in PETSc.petsclibs[1:min(4, length(PETSc.petsclibs))] #@show petsclib #petsclib = PETSc.petsclibs[1] @@ -606,7 +606,7 @@ end comm = Sys.iswindows() ? LibPETSc.PETSC_COMM_SELF : MPI.COMM_WORLD mpirank = MPI.Comm_rank(comm) mpisize = MPI.Comm_size(comm) - for petsclib in PETSc.petsclibs[1:2] + for petsclib in PETSc.petsclibs[1:min(2, length(PETSc.petsclibs))] #petsclib = PETSc.petsclibs[1] PETSc.initialize(petsclib, log_view=false) PetscScalar = PETSc.scalartype(petsclib) @@ -736,7 +736,7 @@ end @testset "DMStagVecGetArray/RestoreArray" begin comm = Sys.iswindows() ? LibPETSc.PETSC_COMM_SELF : MPI.COMM_WORLD - for petsclib in PETSc.petsclibs[1:4] + for petsclib in PETSc.petsclibs[1:min(4, length(PETSc.petsclibs))] PETSc.initialize(petsclib) PetscScalar = PETSc.scalartype(petsclib) PetscInt = PETSc.inttype(petsclib) diff --git a/test/vec.jl b/test/vec.jl index a5a9add2..de8e66f2 100644 --- a/test/vec.jl +++ b/test/vec.jl @@ -89,7 +89,7 @@ end @testset "VecCreateSeqWithArray" begin N = 10 - for petsclib in PETSc.petsclibs[1:2] + for petsclib in PETSc.petsclibs[1:min(2, length(PETSc.petsclibs))] #petsclib = PETSc.petsclibs[5] PETSc.initialize(petsclib) PetscScalar = petsclib.PetscScalar