diff --git a/build_config/MinGW.gfortran.default/build_rules.mk b/build_config/MinGW.gfortran.default/build_rules.mk index 3d06a67b5d..24f9fbfbbe 100644 --- a/build_config/MinGW.gfortran.default/build_rules.mk +++ b/build_config/MinGW.gfortran.default/build_rules.mk @@ -10,6 +10,20 @@ ESMF_F90DEFAULT = gfortran ESMF_CXXDEFAULT = g++ ESMF_CDEFAULT = gcc +############################################################ +# Use the GNU dialect (gnu++/gnu) instead of strict ISO (c++/c). On MinGW the +# strict -std=c++NN / -std=cNN flags define __STRICT_ANSI__, which makes the CRT +# headers (, ) hide their POSIX-named entry points (dup, dup2, +# close, open, read, write, ...). ESMF's VM code uses those names, so the strict +# dialect breaks the build. The GNU dialect keeps them visible. +# +ifneq ($(ESMF_CXXSTD),sysdefault) +ESMF_CXXSTDFLAG = -std=gnu++$(ESMF_CXXSTD) +endif +ifneq ($(ESMF_CSTD),sysdefault) +ESMF_CSTDFLAG = -std=gnu$(ESMF_CSTD) +endif + ############################################################ # Default MPI setting. # @@ -96,7 +110,20 @@ endif ifeq ($(ESMF_ABI),64) ESMF_ABISTRING := x86_64_small endif -else +endif +# 64-bit MSYS2/MinGW reports `uname -m` as x86_64; accept it alongside the legacy +# i686 label (mirrors the Linux.gfortran ABISTRING handling). ESMF_ABI still selects +# the 32- vs 64-bit memory model. +ifeq ($(ESMF_MACHINE),x86_64) +ESMF_ABISTRING := x86_64_small +ifeq ($(ESMF_ABI),32) +ESMF_ABISTRING := x86_64_32 +endif +ifeq ($(ESMF_ABI),64) +ESMF_ABISTRING := x86_64_small +endif +endif +ifeq ($(ESMF_ABISTRING),) $(error "ESMF_MACHINE = $(ESMF_MACHINE)" not recognized) endif @@ -149,8 +176,10 @@ ESMF_CXXCOMPILECPPFLAGS += -DESMF_NO_SYSTEMCALL ############################################################ # Windows does not have support for the times system call +# (also define it for C: vendored Zoltan timer.c is C and includes sys/times.h) # ESMF_CXXCOMPILECPPFLAGS += -DNO_TIMES +ESMF_CCOMPILECPPFLAGS += -DNO_TIMES ############################################################ # Windows does not have support for Pthreads @@ -212,7 +241,14 @@ ESMF_CXXLINKLIBS += -lgfortran -lWs2_32 ############################################################ # Shared library options # -ESMF_SL_LIBOPTS += -shared +# --export-all-symbols is required: parts of the tree (yaml-cpp, MOAB/mesquite, +# MOAB Factory.cpp, verdict, ESMCI_Trace, nlohmann/json) decorate symbols with +# __declspec(dllexport). As soon as ANY symbol is explicitly exported, MinGW ld +# stops auto-exporting the rest, so the undecorated extern "C" ESMC_* / ESMF C API +# (e.g. ESMC_Initialize) is absent from the DLL export table and ctypes can't find +# it. Forcing all globals to be exported restores the Unix-.so-like behavior ESMPy +# expects. +ESMF_SL_LIBOPTS += -shared -Wl,--export-all-symbols ESMF_SL_LIBLIBS += $(ESMF_CXXLINKPATHS) $(ESMF_CXXLINKLIBS) -lgfortran ############################################################ diff --git a/src/Infrastructure/Base/interface/ESMF_Info.F90 b/src/Infrastructure/Base/interface/ESMF_Info.F90 index 250ca4a7ba..fa6b190af6 100644 --- a/src/Infrastructure/Base/interface/ESMF_Info.F90 +++ b/src/Infrastructure/Base/interface/ESMF_Info.F90 @@ -893,7 +893,7 @@ subroutine ESMF_InfoGetI8(info, key, value, keywordEnforcer, default, idx, attne integer, intent(out), optional :: rc integer :: localrc - integer(C_LONG), target :: local_default + integer(ESMF_KIND_I8), target :: local_default integer(C_INT), target :: local_idx type(C_PTR) :: local_default_ptr, local_idx_ptr integer(C_INT) :: recursive, strlen_only diff --git a/src/Infrastructure/Base/interface/ESMF_InfoCDef.F90 b/src/Infrastructure/Base/interface/ESMF_InfoCDef.F90 index c09c884595..6d2c236f22 100644 --- a/src/Infrastructure/Base/interface/ESMF_InfoCDef.F90 +++ b/src/Infrastructure/Base/interface/ESMF_InfoCDef.F90 @@ -3,7 +3,7 @@ function c_info_base_get(base_address) bind(C, name="ESMC_BaseGetInfo") use iso_c_binding implicit none - integer(C_LONG), intent(in) :: base_address + integer(C_LONG_LONG), intent(in) :: base_address type(C_PTR) :: c_info_base_get end function c_info_base_get @@ -66,8 +66,8 @@ subroutine c_info_copyforattribute(isrc, idst, rc) bind(C, name="ESMC_InfoCopyFo subroutine c_info_copyforattribute_reference(src_base_address, dst_base_address, rc) bind(C, name="ESMC_InfoCopyForAttributeReference") use iso_c_binding implicit none - integer(C_LONG) :: src_base_address - integer(C_LONG) :: dst_base_address + integer(C_LONG_LONG) :: src_base_address + integer(C_LONG_LONG) :: dst_base_address integer(C_INT), intent(out) :: rc end subroutine @@ -205,7 +205,7 @@ subroutine c_info_base_sync(inqstate, rootPet, vmAddress, markClean, rc) bind(C, implicit none type(C_PTR), value :: inqstate integer(C_INT), intent(in) :: rootPet - integer(C_LONG), intent(in) :: vmAddress + integer(C_LONG_LONG), intent(in) :: vmAddress integer(C_INT), intent(in) :: markClean integer(C_INT), intent(out) :: rc end subroutine diff --git a/src/Infrastructure/Mesh/src/Moab/DiscreteGeometry/makefile b/src/Infrastructure/Mesh/src/Moab/DiscreteGeometry/makefile index 6b6ce974ed..a63d5ca543 100644 --- a/src/Infrastructure/Mesh/src/Moab/DiscreteGeometry/makefile +++ b/src/Infrastructure/Mesh/src/Moab/DiscreteGeometry/makefile @@ -3,7 +3,13 @@ # leave alone. ALL: build_here -ESMF_CXXCOMPILECPPFLAGS += -DIS_BUILDING_MB -DHAVE_VSNPRINTF -DLINUX -DUSE_MPI +ESMF_CXXCOMPILECPPFLAGS += -DIS_BUILDING_MB -DHAVE_VSNPRINTF -DUSE_MPI +# -DLINUX selects MOAB's Unix code paths (dlfcn.h, dirent.h in Core.cpp). +# Those headers do not exist on MinGW; leave LINUX undefined there so MOAB +# uses its POSIX/Windows-safe fallbacks. Kept for Linux and Darwin. +ifneq ($(ESMF_OS),MinGW) +ESMF_CXXCOMPILECPPFLAGS += -DLINUX +endif SOURCEC = \ DGMSolver.cpp HiReconstruction.cpp diff --git a/src/Infrastructure/Mesh/src/Moab/IntxMesh/makefile b/src/Infrastructure/Mesh/src/Moab/IntxMesh/makefile index 45627ee930..fcd148aa7a 100644 --- a/src/Infrastructure/Mesh/src/Moab/IntxMesh/makefile +++ b/src/Infrastructure/Mesh/src/Moab/IntxMesh/makefile @@ -3,7 +3,13 @@ # leave alone. ALL: build_here -ESMF_CXXCOMPILECPPFLAGS += -DIS_BUILDING_MB -DHAVE_VSNPRINTF -DLINUX -DUSE_MPI +ESMF_CXXCOMPILECPPFLAGS += -DIS_BUILDING_MB -DHAVE_VSNPRINTF -DUSE_MPI +# -DLINUX selects MOAB's Unix code paths (dlfcn.h, dirent.h in Core.cpp). +# Those headers do not exist on MinGW; leave LINUX undefined there so MOAB +# uses its POSIX/Windows-safe fallbacks. Kept for Linux and Darwin. +ifneq ($(ESMF_OS),MinGW) +ESMF_CXXCOMPILECPPFLAGS += -DLINUX +endif SOURCEC = \ Intx2Mesh.cpp Intx2MeshInPlane.cpp Intx2MeshOnSphere.cpp \ diff --git a/src/Infrastructure/Mesh/src/Moab/LocalDiscretization/makefile b/src/Infrastructure/Mesh/src/Moab/LocalDiscretization/makefile index 5d7cebcb4d..33001eb459 100644 --- a/src/Infrastructure/Mesh/src/Moab/LocalDiscretization/makefile +++ b/src/Infrastructure/Mesh/src/Moab/LocalDiscretization/makefile @@ -3,7 +3,13 @@ # leave alone. ALL: build_here -ESMF_CXXCOMPILECPPFLAGS += -DIS_BUILDING_MB -DHAVE_VSNPRINTF -DLINUX -DUSE_MPI +ESMF_CXXCOMPILECPPFLAGS += -DIS_BUILDING_MB -DHAVE_VSNPRINTF -DUSE_MPI +# -DLINUX selects MOAB's Unix code paths (dlfcn.h, dirent.h in Core.cpp). +# Those headers do not exist on MinGW; leave LINUX undefined there so MOAB +# uses its POSIX/Windows-safe fallbacks. Kept for Linux and Darwin. +ifneq ($(ESMF_OS),MinGW) +ESMF_CXXCOMPILECPPFLAGS += -DLINUX +endif SOURCEC = ElemEvaluator.cpp LinearHex.cpp LinearQuad.cpp \ LinearTet.cpp LinearTri.cpp QuadraticHex.cpp diff --git a/src/Infrastructure/Mesh/src/Moab/io/makefile b/src/Infrastructure/Mesh/src/Moab/io/makefile index 962a96b1cb..8117dcd381 100644 --- a/src/Infrastructure/Mesh/src/Moab/io/makefile +++ b/src/Infrastructure/Mesh/src/Moab/io/makefile @@ -3,7 +3,13 @@ # leave alone. ALL: build_here -ESMF_CXXCOMPILECPPFLAGS += -DIS_BUILDING_MB -DHAVE_VSNPRINTF -DLINUX -DUSE_MPI +ESMF_CXXCOMPILECPPFLAGS += -DIS_BUILDING_MB -DHAVE_VSNPRINTF -DUSE_MPI +# -DLINUX selects MOAB's Unix code paths (dlfcn.h, dirent.h in Core.cpp). +# Those headers do not exist on MinGW; leave LINUX undefined there so MOAB +# uses its POSIX/Windows-safe fallbacks. Kept for Linux and Darwin. +ifneq ($(ESMF_OS),MinGW) +ESMF_CXXCOMPILECPPFLAGS += -DLINUX +endif SOURCEC = \ ExoIIUtil.cpp FileTokenizer.cpp GmshUtil.cpp \ diff --git a/src/Infrastructure/Mesh/src/Moab/makefile b/src/Infrastructure/Mesh/src/Moab/makefile index 8a746698b9..ced29651cf 100644 --- a/src/Infrastructure/Mesh/src/Moab/makefile +++ b/src/Infrastructure/Mesh/src/Moab/makefile @@ -3,7 +3,13 @@ # leave alone. ALL: build_here -ESMF_CXXCOMPILECPPFLAGS += -DIS_BUILDING_MB -DHAVE_VSNPRINTF -DLINUX -DUSE_MPI +ESMF_CXXCOMPILECPPFLAGS += -DIS_BUILDING_MB -DHAVE_VSNPRINTF -DUSE_MPI +# -DLINUX selects MOAB's Unix code paths (dlfcn.h, dirent.h in Core.cpp). +# Those headers do not exist on MinGW; leave LINUX undefined there so MOAB +# uses its POSIX/Windows-safe fallbacks. Kept for Linux and Darwin. +ifneq ($(ESMF_OS),MinGW) +ESMF_CXXCOMPILECPPFLAGS += -DLINUX +endif SOURCEC = \ AdaptiveKDTree.cpp AEntityFactory.cpp AffineXform.cpp AxisBox.cpp \ diff --git a/src/Infrastructure/Mesh/src/Moab/moab/Matrix3.hpp b/src/Infrastructure/Mesh/src/Moab/moab/Matrix3.hpp index d620aa3dbd..e8071a4019 100644 --- a/src/Infrastructure/Mesh/src/Moab/moab/Matrix3.hpp +++ b/src/Infrastructure/Mesh/src/Moab/moab/Matrix3.hpp @@ -71,7 +71,18 @@ // We will rely on LAPACK directly -#ifdef WIN32 +// RLO: Only use ESMF-internal LAPACK subroutines with ESMF internal LAPACK. +// It seems like only dgeev and dsyevd are currently in use with MOAB. +// ESMF-internal LAPACK does not currently support dsyevr, dgetrf, dgetri. +// NOTE: this must be checked before the WIN32 case below. MinGW predefines +// WIN32, but the ESMF-internal LAPACK still exposes only the esmf_-prefixed +// names, so they must be used on Windows too -- otherwise the link fails +// with undefined references to dgeev_/dsyevd_. +#if defined ESMF_LAPACK_INTERNAL +#define MOAB_dgeev MOAB_FC_WRAPPER(esmf_dgeev, ESMF_DGEEV) +#define MOAB_dsyevd MOAB_FC_WRAPPER(esmf_dsyevd, ESMF_DSYEVD) + +#elif defined( WIN32 ) // Should use second form below for windows but // needed to do this to make it work. @@ -82,31 +93,11 @@ #define MOAB_dgetrf MOAB_FC_FUNC( dgetrf, DGETRF ) #define MOAB_dgetri MOAB_FC_FUNC( dgetri, DGETRI ) -#else - -// RLO: Only use ESMF-internal LAPACK subroutines with ESMF internal LAPACK. -// It seems like only dgeev and dsyevd are currently in use with MOAB. -// ESMF-internal LAPACK does not currently support dsyevr, dgetrf, dgetri. -#if defined ESMF_LAPACK_INTERNAL -#define MOAB_dgeev MOAB_FC_WRAPPER(esmf_dgeev, ESMF_DGEEV) -#define MOAB_dsyevd MOAB_FC_WRAPPER(esmf_dsyevd, ESMF_DSYEVD) #elif defined ESMF_LAPACK #define MOAB_dgeev MOAB_FC_WRAPPER(dgeev, DGEEV) #define MOAB_dsyevd MOAB_FC_WRAPPER(dsyevd, DSYEVD) #endif -// #define MOAB_dsyevr MOAB_FC_FUNC(dsyevr, DSYEVR) -// #define MOAB_dgetrf MOAB_FC_FUNC(dgetrf, DGETRF) -// #define MOAB_dgetri MOAB_FC_FUNC(dgetri, DGETRI) - -// #define MOAB_dsyevd MOAB_FC_WRAPPER( dsyevd, DSYEVD ) -// #define MOAB_dsyevr MOAB_FC_WRAPPER( dsyevr, DSYEVR ) -// #define MOAB_dgeev MOAB_FC_WRAPPER( dgeev, DGEEV ) -// #define MOAB_dgetrf MOAB_FC_WRAPPER( dgetrf, DGETRF ) -// #define MOAB_dgetri MOAB_FC_WRAPPER( dgetri, DGETRI ) - -#endif - extern "C" { // Computes all eigenvalues and, optionally, eigenvectors of a diff --git a/src/Infrastructure/Mesh/src/Moab/parallel/makefile b/src/Infrastructure/Mesh/src/Moab/parallel/makefile index f81e93a319..275c3e7a3e 100644 --- a/src/Infrastructure/Mesh/src/Moab/parallel/makefile +++ b/src/Infrastructure/Mesh/src/Moab/parallel/makefile @@ -3,7 +3,13 @@ # leave alone. ALL: build_here -ESMF_CXXCOMPILECPPFLAGS += -DIS_BUILDING_MB -DHAVE_VSNPRINTF -DLINUX -DUSE_MPI +ESMF_CXXCOMPILECPPFLAGS += -DIS_BUILDING_MB -DHAVE_VSNPRINTF -DUSE_MPI +# -DLINUX selects MOAB's Unix code paths (dlfcn.h, dirent.h in Core.cpp). +# Those headers do not exist on MinGW; leave LINUX undefined there so MOAB +# uses its POSIX/Windows-safe fallbacks. Kept for Linux and Darwin. +ifneq ($(ESMF_OS),MinGW) +ESMF_CXXCOMPILECPPFLAGS += -DLINUX +endif SOURCEC = \ gs.cpp ParallelComm.cpp ParallelData.cpp ParallelMergeMesh.cpp \ diff --git a/src/Infrastructure/Mesh/src/Moab/verdict/makefile b/src/Infrastructure/Mesh/src/Moab/verdict/makefile index 59c600dda1..cb7f7c1ea1 100644 --- a/src/Infrastructure/Mesh/src/Moab/verdict/makefile +++ b/src/Infrastructure/Mesh/src/Moab/verdict/makefile @@ -3,7 +3,13 @@ # leave alone. ALL: build_here -ESMF_CXXCOMPILECPPFLAGS += -DIS_BUILDING_MB -DHAVE_VSNPRINTF -DLINUX -DUSE_MPI +ESMF_CXXCOMPILECPPFLAGS += -DIS_BUILDING_MB -DHAVE_VSNPRINTF -DUSE_MPI +# -DLINUX selects MOAB's Unix code paths (dlfcn.h, dirent.h in Core.cpp). +# Those headers do not exist on MinGW; leave LINUX undefined there so MOAB +# uses its POSIX/Windows-safe fallbacks. Kept for Linux and Darwin. +ifneq ($(ESMF_OS),MinGW) +ESMF_CXXCOMPILECPPFLAGS += -DLINUX +endif SOURCEC = V_EdgeMetric.cpp VerdictVector.cpp VerdictWrapper.cpp \ V_GaussIntegration.cpp V_HexMetric.cpp V_KnifeMetric.cpp \ diff --git a/src/Infrastructure/Util/include/dmp_diff.hpp b/src/Infrastructure/Util/include/dmp_diff.hpp index 7d98ce6cf0..82da502acb 100644 --- a/src/Infrastructure/Util/include/dmp_diff.hpp +++ b/src/Infrastructure/Util/include/dmp_diff.hpp @@ -31,15 +31,20 @@ using namespace std; -enum Operation : int8_t { EQUAL=0, INSERT=1, DELETE=2 }; +// Enumerators are prefixed with OP_ to avoid collisions with preprocessor +// macros from system headers -- notably , which #defines DELETE +// (a Win32 access-right constant) on MinGW/Windows. A plain `DELETE` here would +// be macro-expanded before compilation, so the prefix is required for the +// MinGW build; renaming all three keeps the set consistent. +enum Operation : int8_t { OP_EQUAL=0, OP_INSERT=1, OP_DELETE=2 }; inline char op2chr(Operation op) { switch (op) { - case DELETE: + case OP_DELETE: return '-'; - case INSERT: + case OP_INSERT: return '+'; - case EQUAL: + case OP_EQUAL: return '='; default: return '?'; @@ -187,7 +192,7 @@ class MyersDiff { Diffs diffs{}; if (text1 == text2) { if (text1.size() != 0) { - diffs.push_back(Diff(EQUAL, text1)); + diffs.push_back(Diff(OP_EQUAL, text1)); } return diffs; } @@ -209,10 +214,10 @@ class MyersDiff { // Restore the prefix and suffix. if (commonprefix.size() != 0) { - diffs.insert(diffs.begin(), Diff(EQUAL, commonprefix)); + diffs.insert(diffs.begin(), Diff(OP_EQUAL, commonprefix)); } if (commonsuffix.size() != 0) { - diffs.push_back(Diff(EQUAL, commonsuffix)); + diffs.push_back(Diff(OP_EQUAL, commonsuffix)); } // TODO diff_cleanupMerge(diffs); @@ -235,13 +240,13 @@ class MyersDiff { if (text1.size() == 0) { // Just add some text (speedup). - diffs.push_back(Diff(INSERT, text2)); + diffs.push_back(Diff(OP_INSERT, text2)); return diffs; } if (text2.size() == 0) { // Just delete some text (speedup). - diffs.push_back(Diff(DELETE, text1)); + diffs.push_back(Diff(OP_DELETE, text1)); return diffs; } @@ -250,9 +255,9 @@ class MyersDiff { int i = longtext.find(shorttext); if (i != -1) { // Shorter text is inside the longer text (speedup). - Operation op = (text1.size() > text2.size()) ? DELETE : INSERT; + Operation op = (text1.size() > text2.size()) ? OP_DELETE : OP_INSERT; diffs.push_back(Diff(op, longtext.substr(0, i))); - diffs.push_back(Diff(EQUAL, shorttext)); + diffs.push_back(Diff(OP_EQUAL, shorttext)); diffs.push_back(Diff(op, longtext.substr(i + shorttext.size()))); return diffs; } @@ -260,8 +265,8 @@ class MyersDiff { if (shorttext.size() == 1) { // Single character string. // After the previous speedup, the character can't be an equality. - diffs.push_back(Diff(DELETE, text1)); - diffs.push_back(Diff(INSERT, text2)); + diffs.push_back(Diff(OP_DELETE, text1)); + diffs.push_back(Diff(OP_INSERT, text2)); return diffs; } @@ -281,7 +286,7 @@ class MyersDiff { checklines, deadline); // Merge the results. diffs = diffs_a; - diffs.push_back(Diff(EQUAL, mid_common)); + diffs.push_back(Diff(OP_EQUAL, mid_common)); diffs.addAll(diffs_b); return diffs; } @@ -417,8 +422,8 @@ class MyersDiff { // Diff took too long and hit the deadline or // number of diffs equals number of characters, no commonality at all. Diffs diffs{}; - diffs.push_back(Diff{DELETE, text1}); - diffs.push_back(Diff{INSERT, text2}); + diffs.push_back(Diff{OP_DELETE, text1}); + diffs.push_back(Diff{OP_INSERT, text2}); return diffs; } @@ -642,7 +647,7 @@ class MyersDiff { int length_deletions2 = 0; Diff thisDiff = pointer.next(); while (thisDiff != null) { - if (thisDiff.operation == EQUAL) { + if (thisDiff.operation == OP_EQUAL) { // Equality found. equalities.push(thisDiff); length_insertions1 = length_insertions2; @@ -652,7 +657,7 @@ class MyersDiff { lastEquality = thisDiff.text; } else { // An insertion or deletion. - if (thisDiff.operation == INSERT) { + if (thisDiff.operation == OP_INSERT) { length_insertions2 += thisDiff.text.size(); } else { length_deletions2 += thisDiff.text.size(); @@ -671,9 +676,9 @@ class MyersDiff { pointer.next(); // Replace equality with a delete. - pointer.set(Diff(DELETE, lastEquality)); + pointer.set(Diff(OP_DELETE, lastEquality)); // Insert a corresponding an insert. - pointer.push_back(Diff(INSERT, lastEquality)); + pointer.push_back(Diff(OP_INSERT, lastEquality)); equalities.pop(); // Throw away the equality we just deleted. if (!equalities.isEmpty()) { @@ -726,8 +731,8 @@ class MyersDiff { } } while (thisDiff != null) { - if (prevDiff.operation == DELETE && - thisDiff.operation == INSERT) { + if (prevDiff.operation == OP_DELETE && + thisDiff.operation == OP_INSERT) { String deletion = prevDiff.text; String insertion = thisDiff.text; int overlap_length1 = diff_commonOverlap(deletion, insertion); @@ -736,7 +741,7 @@ class MyersDiff { if (overlap_length1 >= deletion.size() / 2.0 || overlap_length1 >= insertion.size() / 2.0) { // Overlap found. Insert an equality and trim the surrounding - edits. pointer.previous(); pointer.push_back(Diff(EQUAL, + edits. pointer.previous(); pointer.push_back(Diff(OP_EQUAL, insertion.substring(0, overlap_length1))); prevDiff.text = deletion.substring(0, deletion.size() - overlap_length1); @@ -750,12 +755,12 @@ class MyersDiff { // Reverse overlap found. // Insert an equality and swap and trim the surrounding edits. pointer.previous(); - pointer.push_back(Diff(EQUAL, + pointer.push_back(Diff(OP_EQUAL, deletion.substring(0, overlap_length2))); - prevDiff.operation = INSERT; + prevDiff.operation = OP_INSERT; prevDiff.text = insertion.substring(0, insertion.size() - overlap_length2); - thisDiff.operation = DELETE; + thisDiff.operation = OP_DELETE; thisDiff.text = deletion.substring(overlap_length2); // pointer.add inserts the element before the cursor, so there is // no need to step past the new element. @@ -788,8 +793,8 @@ class MyersDiff { Diff nextDiff = pointer.hasNext() ? pointer.next() : null; // Intentionally ignore the first and last element (don't need checking). while (nextDiff != null) { - if (prevDiff.operation == EQUAL && - nextDiff.operation == EQUAL) { + if (prevDiff.operation == OP_EQUAL && + nextDiff.operation == OP_EQUAL) { // This is a single edit surrounded by equalities. equality1 = prevDiff.text; edit = thisDiff.text; @@ -933,7 +938,7 @@ class MyersDiff { bool post_del = false; Diff thisDiff = pointer.next(); Diff safeDiff = thisDiff; // The last Diff that is known to be - unsplittable. while (thisDiff != null) { if (thisDiff.operation == EQUAL) { + unsplittable. while (thisDiff != null) { if (thisDiff.operation == OP_EQUAL) { // Equality found. if (thisDiff.text.size() < Diff_EditCost && (post_ins || post_del)) { @@ -951,7 +956,7 @@ class MyersDiff { post_ins = post_del = false; } else { // An insertion or deletion. - if (thisDiff.operation == DELETE) { + if (thisDiff.operation == OP_DELETE) { post_del = true; } else { post_ins = true; @@ -977,9 +982,9 @@ class MyersDiff { pointer.next(); // Replace equality with a delete. - pointer.set(Diff(DELETE, lastEquality)); + pointer.set(Diff(OP_DELETE, lastEquality)); // Insert a corresponding an insert. - pointer.push_back(thisDiff = Diff(INSERT, lastEquality)); + pointer.push_back(thisDiff = Diff(OP_INSERT, lastEquality)); equalities.pop(); // Throw away the equality we just deleted. lastEquality = null; @@ -1025,7 +1030,7 @@ class MyersDiff { * @param diffs std::vector of Diff objects. * void diff_cleanupMerge(Diffs diffs) { - diffs.push_back(Diff(EQUAL, "")); // Add a dummy entry at the end. + diffs.push_back(Diff(OP_EQUAL, "")); // Add a dummy entry at the end. std::vectorIterator pointer = diffs.listIterator(); int count_delete = 0; int count_insert = 0; @@ -1036,17 +1041,17 @@ class MyersDiff { int commonlength; while (thisDiff != null) { switch (thisDiff.operation) { - case INSERT: + case OP_INSERT: count_insert++; text_insert += thisDiff.text; prevEqual = null; break; - case DELETE: + case OP_DELETE: count_delete++; text_delete += thisDiff.text; prevEqual = null; break; - case EQUAL: + case OP_EQUAL: if (count_delete + count_insert > 1) { bool both_types = count_delete != 0 && count_insert != 0; // Delete the offending records. @@ -1065,12 +1070,12 @@ class MyersDiff { if (commonlength != 0) { if (pointer.hasPrevious()) { thisDiff = pointer.previous(); - assert thisDiff.operation == EQUAL + assert thisDiff.operation == OP_EQUAL : "Previous diff should have been an equality."; thisDiff.text += text_insert.substring(0, commonlength); pointer.next(); } else { - pointer.push_back(Diff(EQUAL, + pointer.push_back(Diff(OP_EQUAL, text_insert.substring(0, commonlength))); } text_insert = text_insert.substring(commonlength); @@ -1091,10 +1096,10 @@ class MyersDiff { } // Insert the merged records. if (text_delete.size() != 0) { - pointer.push_back(Diff(DELETE, text_delete)); + pointer.push_back(Diff(OP_DELETE, text_delete)); } if (text_insert.size() != 0) { - pointer.push_back(Diff(INSERT, text_insert)); + pointer.push_back(Diff(OP_INSERT, text_insert)); } // Step forward to the equality. thisDiff = pointer.hasNext() ? pointer.next() : null; @@ -1133,8 +1138,8 @@ class MyersDiff { Diff nextDiff = pointer.hasNext() ? pointer.next() : null; // Intentionally ignore the first and last element (don't need checking). while (nextDiff != null) { - if (prevDiff.operation == EQUAL && - nextDiff.operation == EQUAL) { + if (prevDiff.operation == OP_EQUAL && + nextDiff.operation == OP_EQUAL) { // This is a single edit surrounded by equalities. if (thisDiff.text.endsWith(prevDiff.text)) { // Shift the edit over the previous equality. @@ -1179,7 +1184,7 @@ class MyersDiff { String diff_text1(Diffs diffs) { Range text{}; for (Diff aDiff : diffs) { - if (aDiff.operation != INSERT) { + if (aDiff.operation != OP_INSERT) { text.append(aDiff.text); } } @@ -1194,7 +1199,7 @@ class MyersDiff { String diff_text2(Diffs diffs) { Range text{}; for (Diff aDiff : diffs) { - if (aDiff.operation != DELETE) { + if (aDiff.operation != OP_DELETE) { text.append(aDiff.text); } } @@ -1210,9 +1215,9 @@ class MyersDiff { Stats ret; for (const auto &i : result) { switch (i.operation) { - case EQUAL: ret.equal += i.text.size(); break; - case INSERT: ret.inserted += i.text.size(); break; - case DELETE: ret.deleted += i.text.size(); break; + case OP_EQUAL: ret.equal += i.text.size(); break; + case OP_INSERT: ret.inserted += i.text.size(); break; + case OP_DELETE: ret.deleted += i.text.size(); break; } } return ret; diff --git a/src/Infrastructure/VM/include/ESMCI_VMKernel.h b/src/Infrastructure/VM/include/ESMCI_VMKernel.h index cde27db536..9881ae2cce 100644 --- a/src/Infrastructure/VM/include/ESMCI_VMKernel.h +++ b/src/Infrastructure/VM/include/ESMCI_VMKernel.h @@ -40,6 +40,21 @@ #include #else #include +// (via the COM headers) defines `interface` as a macro (== struct), +// which collides with identifiers named `interface` in headers included later -- +// notably MOAB's moab/Interface.hpp. ESMF/MOAB do not use COM, so drop it. +#undef interface +#include // Windows CRT: dup, dup2, close, open (used by Redirects) +// Windows has no unistd.h STD*_FILENO constants; define the POSIX values. +#ifndef STDIN_FILENO +#define STDIN_FILENO 0 +#endif +#ifndef STDOUT_FILENO +#define STDOUT_FILENO 1 +#endif +#ifndef STDERR_FILENO +#define STDERR_FILENO 2 +#endif #endif #ifndef ESMF_NO_OPENMP diff --git a/src/Infrastructure/VM/src/ESMCI_VMKernel.C b/src/Infrastructure/VM/src/ESMCI_VMKernel.C index 030e968128..c6b32f48a9 100644 --- a/src/Infrastructure/VM/src/ESMCI_VMKernel.C +++ b/src/Infrastructure/VM/src/ESMCI_VMKernel.C @@ -1015,7 +1015,7 @@ VMK::Redirects VMK::setRedirects(void *ssarg){ Redirects reds; // stdout and stderr redirect if (sarg->stdoutName.length()){ - reds.oldStdout = fcntl(STDOUT_FILENO, F_DUPFD, 0); // keep access to stdout + reds.oldStdout = dup(STDOUT_FILENO); // keep access to stdout (== fcntl F_DUPFD,0) if (reds.oldStdout == -1){ int localrc; ESMC_LogDefault.MsgFoundError(ESMC_RC_INTNRL_BAD, @@ -1036,7 +1036,7 @@ VMK::Redirects VMK::setRedirects(void *ssarg){ reds.oldStdout = -1; // indicate no redirect } if (sarg->stderrName.length()){ - reds.oldStderr = fcntl(STDERR_FILENO, F_DUPFD, 0); // keep access to stderr + reds.oldStderr = dup(STDERR_FILENO); // keep access to stderr (== fcntl F_DUPFD,0) if (reds.oldStderr == -1){ int localrc; ESMC_LogDefault.MsgFoundError(ESMC_RC_INTNRL_BAD, diff --git a/src/Infrastructure/stubs/mpiuni/mpi.h b/src/Infrastructure/stubs/mpiuni/mpi.h index ed74256466..07822c5943 100644 --- a/src/Infrastructure/stubs/mpiuni/mpi.h +++ b/src/Infrastructure/stubs/mpiuni/mpi.h @@ -59,6 +59,11 @@ #if !defined(__MPI_H) #define __MPI_H +/* intptr_t: a pointer-sized integer for the argument-swallowing casts below. + On Win64 (LLP64) `long` is 32-bit while pointers are 64-bit, so casting a + pointer through `(long)` truncates it; intptr_t is pointer-sized everywhere. */ +#include + #ifdef __cplusplus extern "C" { #endif @@ -246,240 +251,240 @@ extern double ESMC_MPI_Wtime(void); */ #define MPI_Init(argc,argv) \ - (MPIUNI_TMP = (void*)(long) (argc),\ - MPIUNI_TMP = (void*)(long) (argv),\ + (MPIUNI_TMP = (void*)(intptr_t) (argc),\ + MPIUNI_TMP = (void*)(intptr_t) (argv),\ MPI_SUCCESS) #define MPI_Init_thread(argc,argv,required,provided) \ - (MPIUNI_TMP = (void*)(long) (argc),\ - MPIUNI_TMP = (void*)(long) (argv),\ - MPIUNI_TMP = (void*)(long) (required),\ - MPIUNI_TMP = (void*)(long) (provided),\ + (MPIUNI_TMP = (void*)(intptr_t) (argc),\ + MPIUNI_TMP = (void*)(intptr_t) (argv),\ + MPIUNI_TMP = (void*)(intptr_t) (required),\ + MPIUNI_TMP = (void*)(intptr_t) (provided),\ MPI_SUCCESS) #define MPI_Send(buf,count,datatype,dest,tag,comm) \ - (MPIUNI_TMP = (void*)(long) (buf),\ - MPIUNI_TMP = (void*)(long) (count),\ - MPIUNI_TMP = (void*)(long) (datatype),\ - MPIUNI_TMP = (void*)(long) (dest),\ - MPIUNI_TMP = (void*)(long) (tag),\ - MPIUNI_TMP = (void*)(long) (comm),\ + (MPIUNI_TMP = (void*)(intptr_t) (buf),\ + MPIUNI_TMP = (void*)(intptr_t) (count),\ + MPIUNI_TMP = (void*)(intptr_t) (datatype),\ + MPIUNI_TMP = (void*)(intptr_t) (dest),\ + MPIUNI_TMP = (void*)(intptr_t) (tag),\ + MPIUNI_TMP = (void*)(intptr_t) (comm),\ MPI_SUCCESS) #define MPI_Recv(buf,count,datatype,source,tag,comm,status) \ - (MPIUNI_TMP = (void*)(long) (buf),\ - MPIUNI_TMP = (void*)(long) (count),\ - MPIUNI_TMP = (void*)(long) (datatype),\ - MPIUNI_TMP = (void*)(long) (source),\ - MPIUNI_TMP = (void*)(long) (tag),\ - MPIUNI_TMP = (void*)(long) (comm),\ - MPIUNI_TMP = (void*)(long) (status),\ + (MPIUNI_TMP = (void*)(intptr_t) (buf),\ + MPIUNI_TMP = (void*)(intptr_t) (count),\ + MPIUNI_TMP = (void*)(intptr_t) (datatype),\ + MPIUNI_TMP = (void*)(intptr_t) (source),\ + MPIUNI_TMP = (void*)(intptr_t) (tag),\ + MPIUNI_TMP = (void*)(intptr_t) (comm),\ + MPIUNI_TMP = (void*)(intptr_t) (status),\ MPI_Abort(MPI_COMM_WORLD,0)) #define MPI_Get_count(status, datatype,count) \ - (MPIUNI_TMP = (void*)(long) (status),\ - MPIUNI_TMP = (void*)(long) (datatype),\ - MPIUNI_TMP = (void*)(long) (count),\ + (MPIUNI_TMP = (void*)(intptr_t) (status),\ + MPIUNI_TMP = (void*)(intptr_t) (datatype),\ + MPIUNI_TMP = (void*)(intptr_t) (count),\ MPI_Abort(MPI_COMM_WORLD,0)) #define MPI_Bsend(buf,count,datatype,dest,tag,comm) \ - (MPIUNI_TMP = (void*)(long) (buf),\ - MPIUNI_TMP = (void*)(long) (count),\ - MPIUNI_TMP = (void*)(long) (datatype),\ - MPIUNI_TMP = (void*)(long) (dest),\ - MPIUNI_TMP = (void*)(long) (tag),\ - MPIUNI_TMP = (void*)(long) (comm),\ + (MPIUNI_TMP = (void*)(intptr_t) (buf),\ + MPIUNI_TMP = (void*)(intptr_t) (count),\ + MPIUNI_TMP = (void*)(intptr_t) (datatype),\ + MPIUNI_TMP = (void*)(intptr_t) (dest),\ + MPIUNI_TMP = (void*)(intptr_t) (tag),\ + MPIUNI_TMP = (void*)(intptr_t) (comm),\ MPI_SUCCESS) #define MPI_Ssend(buf,count, datatype,dest,tag,comm) \ - (MPIUNI_TMP = (void*)(long) (buf),\ - MPIUNI_TMP = (void*)(long) (count),\ - MPIUNI_TMP = (void*)(long) (datatype),\ - MPIUNI_TMP = (void*)(long) (dest),\ - MPIUNI_TMP = (void*)(long) (tag),\ - MPIUNI_TMP = (void*)(long) (comm),\ + (MPIUNI_TMP = (void*)(intptr_t) (buf),\ + MPIUNI_TMP = (void*)(intptr_t) (count),\ + MPIUNI_TMP = (void*)(intptr_t) (datatype),\ + MPIUNI_TMP = (void*)(intptr_t) (dest),\ + MPIUNI_TMP = (void*)(intptr_t) (tag),\ + MPIUNI_TMP = (void*)(intptr_t) (comm),\ MPI_SUCCESS) #define MPI_Rsend(buf,count, datatype,dest,tag,comm) \ - (MPIUNI_TMP = (void*)(long) (buf),\ - MPIUNI_TMP = (void*)(long) (count),\ - MPIUNI_TMP = (void*)(long) (datatype),\ - MPIUNI_TMP = (void*)(long) (dest),\ - MPIUNI_TMP = (void*)(long) (tag),\ - MPIUNI_TMP = (void*)(long) (comm),\ + (MPIUNI_TMP = (void*)(intptr_t) (buf),\ + MPIUNI_TMP = (void*)(intptr_t) (count),\ + MPIUNI_TMP = (void*)(intptr_t) (datatype),\ + MPIUNI_TMP = (void*)(intptr_t) (dest),\ + MPIUNI_TMP = (void*)(intptr_t) (tag),\ + MPIUNI_TMP = (void*)(intptr_t) (comm),\ MPI_SUCCESS) #define MPI_Buffer_attach(buffer,size) \ - (MPIUNI_TMP = (void*)(long) (buffer),\ - MPIUNI_TMP = (void*)(long) (size),\ + (MPIUNI_TMP = (void*)(intptr_t) (buffer),\ + MPIUNI_TMP = (void*)(intptr_t) (size),\ MPI_SUCCESS) #define MPI_Buffer_detach(buffer,size)\ - (MPIUNI_TMP = (void*)(long) (buffer),\ - MPIUNI_TMP = (void*)(long) (size),\ + (MPIUNI_TMP = (void*)(intptr_t) (buffer),\ + MPIUNI_TMP = (void*)(intptr_t) (size),\ MPI_SUCCESS) #define MPI_Ibsend(buf,count, datatype,dest,tag,comm,request) \ - (MPIUNI_TMP = (void*)(long) (buf),\ - MPIUNI_TMP = (void*)(long) (count),\ - MPIUNI_TMP = (void*)(long) (datatype),\ - MPIUNI_TMP = (void*)(long) (dest),\ - MPIUNI_TMP = (void*)(long) (tag),\ - MPIUNI_TMP = (void*)(long) (comm),\ - MPIUNI_TMP = (void*)(long) (request),\ + (MPIUNI_TMP = (void*)(intptr_t) (buf),\ + MPIUNI_TMP = (void*)(intptr_t) (count),\ + MPIUNI_TMP = (void*)(intptr_t) (datatype),\ + MPIUNI_TMP = (void*)(intptr_t) (dest),\ + MPIUNI_TMP = (void*)(intptr_t) (tag),\ + MPIUNI_TMP = (void*)(intptr_t) (comm),\ + MPIUNI_TMP = (void*)(intptr_t) (request),\ MPI_SUCCESS) #define MPI_Issend(buf,count, datatype,dest,tag,comm,request) \ - (MPIUNI_TMP = (void*)(long) (buf),\ - MPIUNI_TMP = (void*)(long) (count),\ - MPIUNI_TMP = (void*)(long) (datatype),\ - MPIUNI_TMP = (void*)(long) (dest),\ - MPIUNI_TMP = (void*)(long) (tag),\ - MPIUNI_TMP = (void*)(long) (comm),\ - MPIUNI_TMP = (void*)(long) (request),\ + (MPIUNI_TMP = (void*)(intptr_t) (buf),\ + MPIUNI_TMP = (void*)(intptr_t) (count),\ + MPIUNI_TMP = (void*)(intptr_t) (datatype),\ + MPIUNI_TMP = (void*)(intptr_t) (dest),\ + MPIUNI_TMP = (void*)(intptr_t) (tag),\ + MPIUNI_TMP = (void*)(intptr_t) (comm),\ + MPIUNI_TMP = (void*)(intptr_t) (request),\ MPI_SUCCESS) #define MPI_Irsend(buf,count, datatype,dest,tag,comm,request) \ - (MPIUNI_TMP = (void*)(long) (buf),\ - MPIUNI_TMP = (void*)(long) (count),\ - MPIUNI_TMP = (void*)(long) (datatype),\ - MPIUNI_TMP = (void*)(long) (dest),\ - MPIUNI_TMP = (void*)(long) (tag),\ - MPIUNI_TMP = (void*)(long) (comm),\ - MPIUNI_TMP = (void*)(long) (request),\ + (MPIUNI_TMP = (void*)(intptr_t) (buf),\ + MPIUNI_TMP = (void*)(intptr_t) (count),\ + MPIUNI_TMP = (void*)(intptr_t) (datatype),\ + MPIUNI_TMP = (void*)(intptr_t) (dest),\ + MPIUNI_TMP = (void*)(intptr_t) (tag),\ + MPIUNI_TMP = (void*)(intptr_t) (comm),\ + MPIUNI_TMP = (void*)(intptr_t) (request),\ MPI_SUCCESS) #define MPI_Irecv(buf,count, datatype,source,tag,comm,request) \ - (MPIUNI_TMP = (void*)(long) (buf),\ - MPIUNI_TMP = (void*)(long) (count),\ - MPIUNI_TMP = (void*)(long) (datatype),\ - MPIUNI_TMP = (void*)(long) (source),\ - MPIUNI_TMP = (void*)(long) (tag),\ - MPIUNI_TMP = (void*)(long) (comm),\ - MPIUNI_TMP = (void*)(long) (request),\ + (MPIUNI_TMP = (void*)(intptr_t) (buf),\ + MPIUNI_TMP = (void*)(intptr_t) (count),\ + MPIUNI_TMP = (void*)(intptr_t) (datatype),\ + MPIUNI_TMP = (void*)(intptr_t) (source),\ + MPIUNI_TMP = (void*)(intptr_t) (tag),\ + MPIUNI_TMP = (void*)(intptr_t) (comm),\ + MPIUNI_TMP = (void*)(intptr_t) (request),\ MPI_Abort(MPI_COMM_WORLD,0)) #define MPI_Isend(buf,count, datatype,dest,tag,comm,request) \ - (MPIUNI_TMP = (void*)(long) (buf),\ - MPIUNI_TMP = (void*)(long) (count),\ - MPIUNI_TMP = (void*)(long) (datatype),\ - MPIUNI_TMP = (void*)(long) (dest),\ - MPIUNI_TMP = (void*)(long) (tag),\ - MPIUNI_TMP = (void*)(long) (comm),\ - MPIUNI_TMP = (void*)(long) (request),\ + (MPIUNI_TMP = (void*)(intptr_t) (buf),\ + MPIUNI_TMP = (void*)(intptr_t) (count),\ + MPIUNI_TMP = (void*)(intptr_t) (datatype),\ + MPIUNI_TMP = (void*)(intptr_t) (dest),\ + MPIUNI_TMP = (void*)(intptr_t) (tag),\ + MPIUNI_TMP = (void*)(intptr_t) (comm),\ + MPIUNI_TMP = (void*)(intptr_t) (request),\ MPI_Abort(MPI_COMM_WORLD,0)) #define MPI_Wait(request,status) \ - (MPIUNI_TMP = (void*)(long) (request),\ - MPIUNI_TMP = (void*)(long) (status),\ + (MPIUNI_TMP = (void*)(intptr_t) (request),\ + MPIUNI_TMP = (void*)(intptr_t) (status),\ MPI_SUCCESS) #define MPI_Test(request,flag,status) \ - (MPIUNI_TMP = (void*)(long) (request),\ - MPIUNI_TMP = (void*)(long) (status),\ + (MPIUNI_TMP = (void*)(intptr_t) (request),\ + MPIUNI_TMP = (void*)(intptr_t) (status),\ *(flag) = 0, \ MPI_SUCCESS) #define MPI_Request_free(request) \ - (MPIUNI_TMP = (void*)(long) (request),\ + (MPIUNI_TMP = (void*)(intptr_t) (request),\ MPI_SUCCESS) #define MPI_Waitany(a,b,c,d) \ - (MPIUNI_TMP = (void*)(long) (a),\ - MPIUNI_TMP = (void*)(long) (b),\ - MPIUNI_TMP = (void*)(long) (c),\ - MPIUNI_TMP = (void*)(long) (d),\ + (MPIUNI_TMP = (void*)(intptr_t) (a),\ + MPIUNI_TMP = (void*)(intptr_t) (b),\ + MPIUNI_TMP = (void*)(intptr_t) (c),\ + MPIUNI_TMP = (void*)(intptr_t) (d),\ MPI_SUCCESS) #define MPI_Testany(a,b,c,d,e) \ - (MPIUNI_TMP = (void*)(long) (a),\ - MPIUNI_TMP = (void*)(long) (b),\ - MPIUNI_TMP = (void*)(long) (c),\ - MPIUNI_TMP = (void*)(long) (d),\ - MPIUNI_TMP = (void*)(long) (e),\ + (MPIUNI_TMP = (void*)(intptr_t) (a),\ + MPIUNI_TMP = (void*)(intptr_t) (b),\ + MPIUNI_TMP = (void*)(intptr_t) (c),\ + MPIUNI_TMP = (void*)(intptr_t) (d),\ + MPIUNI_TMP = (void*)(intptr_t) (e),\ MPI_SUCCESS) #define MPI_Waitall(count,array_of_requests,array_of_statuses) \ - (MPIUNI_TMP = (void*)(long) (count),\ - MPIUNI_TMP = (void*)(long) (array_of_requests),\ - MPIUNI_TMP = (void*)(long) (array_of_statuses),\ + (MPIUNI_TMP = (void*)(intptr_t) (count),\ + MPIUNI_TMP = (void*)(intptr_t) (array_of_requests),\ + MPIUNI_TMP = (void*)(intptr_t) (array_of_statuses),\ MPI_SUCCESS) #define MPI_Testall(count,array_of_requests,flag,array_of_statuses) \ - (MPIUNI_TMP = (void*)(long) (count),\ - MPIUNI_TMP = (void*)(long) (array_of_requests),\ - MPIUNI_TMP = (void*)(long) (flag),\ - MPIUNI_TMP = (void*)(long) (array_of_statuses),\ + (MPIUNI_TMP = (void*)(intptr_t) (count),\ + MPIUNI_TMP = (void*)(intptr_t) (array_of_requests),\ + MPIUNI_TMP = (void*)(intptr_t) (flag),\ + MPIUNI_TMP = (void*)(intptr_t) (array_of_statuses),\ MPI_SUCCESS) #define MPI_Waitsome(incount,array_of_requests,outcount,\ array_of_indices,array_of_statuses) \ - (MPIUNI_TMP = (void*)(long) (incount),\ - MPIUNI_TMP = (void*)(long) (array_of_requests),\ - MPIUNI_TMP = (void*)(long) (outcount),\ - MPIUNI_TMP = (void*)(long) (array_of_indices),\ - MPIUNI_TMP = (void*)(long) (array_of_statuses),\ + (MPIUNI_TMP = (void*)(intptr_t) (incount),\ + MPIUNI_TMP = (void*)(intptr_t) (array_of_requests),\ + MPIUNI_TMP = (void*)(intptr_t) (outcount),\ + MPIUNI_TMP = (void*)(intptr_t) (array_of_indices),\ + MPIUNI_TMP = (void*)(intptr_t) (array_of_statuses),\ MPI_SUCCESS) #define MPI_Comm_group(comm,group) \ - (MPIUNI_TMP = (void*)(long) (comm),\ - MPIUNI_TMP = (void*)(long) (group),\ + (MPIUNI_TMP = (void*)(intptr_t) (comm),\ + MPIUNI_TMP = (void*)(intptr_t) (group),\ MPI_SUCCESS) #define MPI_Group_incl(group,n,ranks,newgroup) \ - (MPIUNI_TMP = (void*)(long) (group),\ - MPIUNI_TMP = (void*)(long) (n),\ - MPIUNI_TMP = (void*)(long) (ranks),\ - MPIUNI_TMP = (void*)(long) (newgroup),\ + (MPIUNI_TMP = (void*)(intptr_t) (group),\ + MPIUNI_TMP = (void*)(intptr_t) (n),\ + MPIUNI_TMP = (void*)(intptr_t) (ranks),\ + MPIUNI_TMP = (void*)(intptr_t) (newgroup),\ MPI_SUCCESS) #define MPI_Testsome(incount,array_of_requests,outcount,\ array_of_indices,array_of_statuses) MPI_SUCCESS #define MPI_Iprobe(source,tag,comm,flag,status) (*(flag)=0, MPI_SUCCESS) #define MPI_Probe(source,tag,comm,status) MPI_SUCCESS -#define MPI_Cancel(request) (MPIUNI_TMP = (void*)(long) (request),MPI_SUCCESS) +#define MPI_Cancel(request) (MPIUNI_TMP = (void*)(intptr_t) (request),MPI_SUCCESS) #define MPI_Test_cancelled(status,flag) (*(flag)=0,MPI_SUCCESS) #define MPI_Send_init(buf,count, datatype,dest,tag,comm,request) \ - (MPIUNI_TMP = (void*)(long) (buf),\ - MPIUNI_TMP = (void*)(long) (count),\ - MPIUNI_TMP = (void*)(long) (datatype),\ - MPIUNI_TMP = (void*)(long) (dest),\ - MPIUNI_TMP = (void*)(long) (tag),\ - MPIUNI_TMP = (void*)(long) (comm),\ - MPIUNI_TMP = (void*)(long) (request),\ + (MPIUNI_TMP = (void*)(intptr_t) (buf),\ + MPIUNI_TMP = (void*)(intptr_t) (count),\ + MPIUNI_TMP = (void*)(intptr_t) (datatype),\ + MPIUNI_TMP = (void*)(intptr_t) (dest),\ + MPIUNI_TMP = (void*)(intptr_t) (tag),\ + MPIUNI_TMP = (void*)(intptr_t) (comm),\ + MPIUNI_TMP = (void*)(intptr_t) (request),\ MPI_SUCCESS) #define MPI_Bsend_init(buf,count, datatype,dest,tag,comm,request) \ - (MPIUNI_TMP = (void*)(long) (buf),\ - MPIUNI_TMP = (void*)(long) (count),\ - MPIUNI_TMP = (void*)(long) (datatype),\ - MPIUNI_TMP = (void*)(long) (dest),\ - MPIUNI_TMP = (void*)(long) (tag),\ - MPIUNI_TMP = (void*)(long) (comm),\ - MPIUNI_TMP = (void*)(long) (request),\ + (MPIUNI_TMP = (void*)(intptr_t) (buf),\ + MPIUNI_TMP = (void*)(intptr_t) (count),\ + MPIUNI_TMP = (void*)(intptr_t) (datatype),\ + MPIUNI_TMP = (void*)(intptr_t) (dest),\ + MPIUNI_TMP = (void*)(intptr_t) (tag),\ + MPIUNI_TMP = (void*)(intptr_t) (comm),\ + MPIUNI_TMP = (void*)(intptr_t) (request),\ MPI_SUCCESS) #define MPI_Ssend_init(buf,count, datatype,dest,tag,comm,request) \ - (MPIUNI_TMP = (void*)(long) (buf),\ - MPIUNI_TMP = (void*)(long) (count),\ - MPIUNI_TMP = (void*)(long) (datatype),\ - MPIUNI_TMP = (void*)(long) (dest),\ - MPIUNI_TMP = (void*)(long) (tag),\ - MPIUNI_TMP = (void*)(long) (comm),\ - MPIUNI_TMP = (void*)(long) (request),\ + (MPIUNI_TMP = (void*)(intptr_t) (buf),\ + MPIUNI_TMP = (void*)(intptr_t) (count),\ + MPIUNI_TMP = (void*)(intptr_t) (datatype),\ + MPIUNI_TMP = (void*)(intptr_t) (dest),\ + MPIUNI_TMP = (void*)(intptr_t) (tag),\ + MPIUNI_TMP = (void*)(intptr_t) (comm),\ + MPIUNI_TMP = (void*)(intptr_t) (request),\ MPI_SUCCESS) #define MPI_Bsend_init(buf,count, datatype,dest,tag,comm,request) \ - (MPIUNI_TMP = (void*)(long) (buf),\ - MPIUNI_TMP = (void*)(long) (count),\ - MPIUNI_TMP = (void*)(long) (datatype),\ - MPIUNI_TMP = (void*)(long) (dest),\ - MPIUNI_TMP = (void*)(long) (tag),\ - MPIUNI_TMP = (void*)(long) (comm),\ - MPIUNI_TMP = (void*)(long) (request),\ + (MPIUNI_TMP = (void*)(intptr_t) (buf),\ + MPIUNI_TMP = (void*)(intptr_t) (count),\ + MPIUNI_TMP = (void*)(intptr_t) (datatype),\ + MPIUNI_TMP = (void*)(intptr_t) (dest),\ + MPIUNI_TMP = (void*)(intptr_t) (tag),\ + MPIUNI_TMP = (void*)(intptr_t) (comm),\ + MPIUNI_TMP = (void*)(intptr_t) (request),\ MPI_SUCCESS) #define MPI_Rsend_init(buf,count, datatype,dest,tag,comm,request) \ - (MPIUNI_TMP = (void*)(long) (buf),\ - MPIUNI_TMP = (void*)(long) (count),\ - MPIUNI_TMP = (void*)(long) (datatype),\ - MPIUNI_TMP = (void*)(long) (dest),\ - MPIUNI_TMP = (void*)(long) (tag),\ - MPIUNI_TMP = (void*)(long) (comm),\ - MPIUNI_TMP = (void*)(long) (request),\ + (MPIUNI_TMP = (void*)(intptr_t) (buf),\ + MPIUNI_TMP = (void*)(intptr_t) (count),\ + MPIUNI_TMP = (void*)(intptr_t) (datatype),\ + MPIUNI_TMP = (void*)(intptr_t) (dest),\ + MPIUNI_TMP = (void*)(intptr_t) (tag),\ + MPIUNI_TMP = (void*)(intptr_t) (comm),\ + MPIUNI_TMP = (void*)(intptr_t) (request),\ MPI_SUCCESS) #define MPI_Recv_init(buf,count, datatype,source,tag,comm,request) \ - (MPIUNI_TMP = (void*)(long) (buf),\ - MPIUNI_TMP = (void*)(long) (count),\ - MPIUNI_TMP = (void*)(long) (datatype),\ - MPIUNI_TMP = (void*)(long) (source),\ - MPIUNI_TMP = (void*)(long) (tag),\ - MPIUNI_TMP = (void*)(long) (comm),\ - MPIUNI_TMP = (void*)(long) (request),\ + (MPIUNI_TMP = (void*)(intptr_t) (buf),\ + MPIUNI_TMP = (void*)(intptr_t) (count),\ + MPIUNI_TMP = (void*)(intptr_t) (datatype),\ + MPIUNI_TMP = (void*)(intptr_t) (source),\ + MPIUNI_TMP = (void*)(intptr_t) (tag),\ + MPIUNI_TMP = (void*)(intptr_t) (comm),\ + MPIUNI_TMP = (void*)(intptr_t) (request),\ MPI_SUCCESS) -#define MPI_Start(request) (MPIUNI_TMP = (void*)(long) (request),MPI_SUCCESS) +#define MPI_Start(request) (MPIUNI_TMP = (void*)(intptr_t) (request),MPI_SUCCESS) #define MPI_Startall(count,array_of_requests) \ - (MPIUNI_TMP = (void*)(long) (count),\ - MPIUNI_TMP = (void*)(long) (array_of_requests),\ + (MPIUNI_TMP = (void*)(intptr_t) (count),\ + MPIUNI_TMP = (void*)(intptr_t) (array_of_requests),\ MPI_SUCCESS) #define MPI_Op_create(function,commute,op) \ - (MPIUNI_TMP = (void*)(long) (function),\ - MPIUNI_TMP = (void*)(long) (commute),\ - MPIUNI_TMP = (void*)(long) (op),\ + (MPIUNI_TMP = (void*)(intptr_t) (function),\ + MPIUNI_TMP = (void*)(intptr_t) (commute),\ + MPIUNI_TMP = (void*)(intptr_t) (op),\ MPI_SUCCESS) #define MPI_Op_free(op) \ - (MPIUNI_TMP = (void*)(long) (op),\ + (MPIUNI_TMP = (void*)(intptr_t) (op),\ MPI_SUCCESS) /* Need to determine sizeof "sendtype" */ #define MPI_Sendrecv(sendbuf,sendcount, sendtype,\ @@ -509,7 +514,7 @@ extern double ESMC_MPI_Wtime(void); MPI_Abort(MPI_COMM_WORLD,0) #define MPI_Type_ub(datatype,displacement) \ MPI_Abort(MPI_COMM_WORLD,0) -#define MPI_Type_commit(datatype) (MPIUNI_TMP = (void*)(long) (datatype),\ +#define MPI_Type_commit(datatype) (MPIUNI_TMP = (void*)(intptr_t) (datatype),\ MPI_SUCCESS) #define MPI_Type_free(datatype) MPI_SUCCESS #define MPI_Get_elements(status, datatype,count) \ @@ -523,57 +528,57 @@ extern double ESMC_MPI_Wtime(void); #define MPI_Pack_size(incount, datatype,comm,size) \ MPI_Abort(MPI_COMM_WORLD,0) #define MPI_Barrier(comm) \ - (MPIUNI_TMP = (void*)(long) (comm),\ + (MPIUNI_TMP = (void*)(intptr_t) (comm),\ MPI_SUCCESS) #define MPI_Bcast(buffer,count,datatype,root,comm) \ - (MPIUNI_TMP = (void*)(long) (buffer),\ - MPIUNI_TMP = (void*)(long) (count),\ - MPIUNI_TMP = (void*)(long) (datatype),\ - MPIUNI_TMP = (void*)(long) (comm),\ + (MPIUNI_TMP = (void*)(intptr_t) (buffer),\ + MPIUNI_TMP = (void*)(intptr_t) (count),\ + MPIUNI_TMP = (void*)(intptr_t) (datatype),\ + MPIUNI_TMP = (void*)(intptr_t) (comm),\ MPI_SUCCESS) #define MPI_Gather(sendbuf,sendcount, sendtype,\ recvbuf,recvcount, recvtype,\ root,comm) \ - (MPIUNI_TMP = (void*)(long) (recvcount),\ - MPIUNI_TMP = (void*)(long) (root),\ - MPIUNI_TMP = (void*)(long) (recvtype),\ - MPIUNI_TMP = (void*)(long) (comm),\ + (MPIUNI_TMP = (void*)(intptr_t) (recvcount),\ + MPIUNI_TMP = (void*)(intptr_t) (root),\ + MPIUNI_TMP = (void*)(intptr_t) (recvtype),\ + MPIUNI_TMP = (void*)(intptr_t) (comm),\ MPIUNI_Memcpy(recvbuf,sendbuf,(sendcount)* (sendtype),CHECK_FOR_MPI_IN_PLACE_SOURCE), \ MPI_SUCCESS) #define MPI_Gatherv(sendbuf,sendcount, sendtype,\ recvbuf,recvcounts,displs,\ recvtype,root,comm) \ - (MPIUNI_TMP = (void*)(long) (recvcounts),\ - MPIUNI_TMP = (void*)(long) (displs),\ - MPIUNI_TMP = (void*)(long) (recvtype),\ - MPIUNI_TMP = (void*)(long) (root),\ - MPIUNI_TMP = (void*)(long) (comm),\ + (MPIUNI_TMP = (void*)(intptr_t) (recvcounts),\ + MPIUNI_TMP = (void*)(intptr_t) (displs),\ + MPIUNI_TMP = (void*)(intptr_t) (recvtype),\ + MPIUNI_TMP = (void*)(intptr_t) (root),\ + MPIUNI_TMP = (void*)(intptr_t) (comm),\ MPIUNI_Memcpy(recvbuf,sendbuf,(sendcount)* (sendtype),CHECK_FOR_MPI_IN_PLACE_SOURCE), \ MPI_SUCCESS) #define MPI_Scatter(sendbuf,sendcount, sendtype,\ recvbuf,recvcount, recvtype,\ root,comm) \ - (MPIUNI_TMP = (void*)(long) (sendbuf),\ - MPIUNI_TMP = (void*)(long) (sendcount),\ - MPIUNI_TMP = (void*)(long) (sendtype),\ - MPIUNI_TMP = (void*)(long) (recvbuf),\ - MPIUNI_TMP = (void*)(long) (recvcount),\ - MPIUNI_TMP = (void*)(long) (recvtype),\ - MPIUNI_TMP = (void*)(long) (root),\ - MPIUNI_TMP = (void*)(long) (comm),MPI_Abort(MPI_COMM_WORLD,0)) + (MPIUNI_TMP = (void*)(intptr_t) (sendbuf),\ + MPIUNI_TMP = (void*)(intptr_t) (sendcount),\ + MPIUNI_TMP = (void*)(intptr_t) (sendtype),\ + MPIUNI_TMP = (void*)(intptr_t) (recvbuf),\ + MPIUNI_TMP = (void*)(intptr_t) (recvcount),\ + MPIUNI_TMP = (void*)(intptr_t) (recvtype),\ + MPIUNI_TMP = (void*)(intptr_t) (root),\ + MPIUNI_TMP = (void*)(intptr_t) (comm),MPI_Abort(MPI_COMM_WORLD,0)) #define MPI_Allgather(sendbuf,sendcount, sendtype,\ recvbuf,recvcount, recvtype,comm) \ - (MPIUNI_TMP = (void*)(long) (recvcount),\ - MPIUNI_TMP = (void*)(long) (recvtype),\ - MPIUNI_TMP = (void*)(long) (comm),\ + (MPIUNI_TMP = (void*)(intptr_t) (recvcount),\ + MPIUNI_TMP = (void*)(intptr_t) (recvtype),\ + MPIUNI_TMP = (void*)(intptr_t) (comm),\ MPIUNI_Memcpy(recvbuf,sendbuf,(sendcount)* (sendtype),CHECK_FOR_MPI_IN_PLACE_SOURCE), \ MPI_SUCCESS) #define MPI_Allgatherv(sendbuf,sendcount, sendtype,\ recvbuf,recvcounts,displs,recvtype,comm) \ - (MPIUNI_TMP = (void*)(long) (recvcounts),\ - MPIUNI_TMP = (void*)(long) (displs),\ - MPIUNI_TMP = (void*)(long) (recvtype),\ - MPIUNI_TMP = (void*)(long) (comm),\ + (MPIUNI_TMP = (void*)(intptr_t) (recvcounts),\ + MPIUNI_TMP = (void*)(intptr_t) (displs),\ + MPIUNI_TMP = (void*)(intptr_t) (recvtype),\ + MPIUNI_TMP = (void*)(intptr_t) (comm),\ MPIUNI_Memcpy(recvbuf,sendbuf,(sendcount)* (sendtype),CHECK_FOR_MPI_IN_PLACE_SOURCE), \ MPI_SUCCESS) #define MPI_Alltoall(sendbuf,sendcount, sendtype,\ @@ -585,13 +590,13 @@ extern double ESMC_MPI_Wtime(void); #define MPI_Reduce(sendbuf, recvbuf,count,\ datatype,op,root,comm) \ (MPIUNI_Memcpy(recvbuf,sendbuf,(count)*(datatype),CHECK_FOR_MPI_IN_PLACE_SOURCE), \ - MPIUNI_TMP = (void*)(long) (comm),MPI_SUCCESS) + MPIUNI_TMP = (void*)(intptr_t) (comm),MPI_SUCCESS) #define MPI_Allreduce(sendbuf, recvbuf,count,datatype,op,comm) \ (MPIUNI_Memcpy(recvbuf,sendbuf,(count)*(datatype),CHECK_FOR_MPI_IN_PLACE_SOURCE), \ - MPIUNI_TMP = (void*)(long) (comm),MPI_SUCCESS) + MPIUNI_TMP = (void*)(intptr_t) (comm),MPI_SUCCESS) #define MPI_Scan(sendbuf, recvbuf,count,datatype,op,comm) \ (MPIUNI_Memcpy(recvbuf,sendbuf,(count)*(datatype),CHECK_FOR_MPI_IN_PLACE_SOURCE), \ - MPIUNI_TMP = (void*)(long) (comm),MPI_SUCCESS) + MPIUNI_TMP = (void*)(intptr_t) (comm),MPI_SUCCESS) #define MPI_Reduce_scatter(sendbuf, recvbuf,recvcounts,\ datatype,op,comm) \ MPI_Abort(MPI_COMM_WORLD,0) @@ -608,28 +613,28 @@ extern double ESMC_MPI_Wtime(void); #define MPI_Group_range_incl(group,n,ranges,newgroup) MPI_SUCCESS #define MPI_Group_range_excl(group,n,ranges,newgroup) MPI_SUCCESS #define MPI_Group_free(group) \ - (MPIUNI_TMP = (void*)(long) (group),\ + (MPIUNI_TMP = (void*)(intptr_t) (group),\ MPI_SUCCESS) #define MPI_Comm_size(comm,size) \ - (MPIUNI_TMP = (void*)(long) (comm),\ + (MPIUNI_TMP = (void*)(intptr_t) (comm),\ *(size)=1,\ MPI_SUCCESS) #define MPI_Comm_rank(comm,rank) \ - (MPIUNI_TMP = (void*)(long) (comm),\ + (MPIUNI_TMP = (void*)(intptr_t) (comm),\ *(rank)=0,\ MPI_SUCCESS) #define MPI_Comm_compare(comm1,comm2,result) \ - (MPIUNI_TMP = (void*)(long) (comm1),\ - MPIUNI_TMP = (void*)(long) (comm2),\ + (MPIUNI_TMP = (void*)(intptr_t) (comm1),\ + MPIUNI_TMP = (void*)(intptr_t) (comm2),\ *(result)=MPI_IDENT,\ MPI_SUCCESS) #define MPI_Comm_create(comm,group,newcomm) \ (*(newcomm) = (comm),\ - MPIUNI_TMP = (void*)(long) (group),\ + MPIUNI_TMP = (void*)(intptr_t) (group),\ MPI_SUCCESS) #define MPI_Comm_create_group(comm,group,tag,newcomm) \ (*(newcomm) = (comm),\ - MPIUNI_TMP = (void*)(long) (group),\ + MPIUNI_TMP = (void*)(intptr_t) (group),\ MPI_SUCCESS) #define MPI_Comm_split(comm,color,key,newcomm) MPI_SUCCESS #define MPI_Comm_test_inter(comm,flag) (*(flag)=1,MPI_SUCCESS) @@ -640,12 +645,12 @@ extern double ESMC_MPI_Wtime(void); #define MPI_Intercomm_merge(intercomm,high,newintracomm) MPI_SUCCESS #define MPI_Info_create(info) \ - (MPIUNI_TMP = (void*)(long) (info),\ + (MPIUNI_TMP = (void*)(intptr_t) (info),\ MPI_SUCCESS) #define MPI_Info_set(info,key,value) \ - (MPIUNI_TMP = (void*)(long) (info),\ - MPIUNI_TMP = (void*)(long) (key),\ - MPIUNI_TMP = (void*)(long) (value),\ + (MPIUNI_TMP = (void*)(intptr_t) (info),\ + MPIUNI_TMP = (void*)(intptr_t) (key),\ + MPIUNI_TMP = (void*)(intptr_t) (value),\ MPI_SUCCESS) #define MPI_Topo_test(comm,status) MPI_SUCCESS @@ -673,16 +678,16 @@ extern double ESMC_MPI_Wtime(void); #define MPI_Get_processor_name(name,result_len) \ (MPIUNI_Memcpy(name,"localhost",9*sizeof(char),CHECK_FOR_MPI_IN_PLACE_NONE),name[10] = 0,*(result_len) = 10) #define MPI_Errhandler_create(function,errhandler) \ - (MPIUNI_TMP = (void*)(long) (errhandler),\ + (MPIUNI_TMP = (void*)(intptr_t) (errhandler),\ MPI_SUCCESS) #define MPI_Errhandler_set(comm,errhandler) \ - (MPIUNI_TMP = (void*)(long) (comm),\ - MPIUNI_TMP = (void*)(long) (errhandler),\ + (MPIUNI_TMP = (void*)(intptr_t) (comm),\ + MPIUNI_TMP = (void*)(intptr_t) (errhandler),\ MPI_SUCCESS) #define MPI_Errhandler_get(comm,errhandler) MPI_SUCCESS #define MPI_Errhandler_free(errhandler) MPI_SUCCESS #define MPI_Error_string(errorcode,string,result_len) \ - (MPIUNI_TMP = (void*)(long) (errorcode),\ + (MPIUNI_TMP = (void*)(intptr_t) (errorcode),\ string[0]='\0', \ *result_len=0, \ MPI_SUCCESS) diff --git a/src/addon/esmpy/src/esmpy/__init__.py b/src/addon/esmpy/src/esmpy/__init__.py index 3845eac743..72ffb40f13 100644 --- a/src/addon/esmpy/src/esmpy/__init__.py +++ b/src/addon/esmpy/src/esmpy/__init__.py @@ -89,8 +89,30 @@ elif (sys.version_info >= (3,8)): # this requires Python 3.8 or higher import importlib.metadata as ilm - - msg = ilm.metadata("esmpy") + + try: + msg = ilm.metadata("esmpy") + except ilm.PackageNotFoundError: + # ESMPy may be installed under a variant distribution name that ships the + # same `esmpy` import package -- e.g. `esmpy-mpich` (an MPI-enabled build + # whose wheel depends on the `mpich` runtime). The distribution name is + # not the import name, so resolve whichever distribution provides this + # package rather than assuming "esmpy". + _dist_name = None + _pkg_to_dists = getattr(ilm, "packages_distributions", lambda: {})() + _dists = _pkg_to_dists.get("esmpy") + if _dists: + _dist_name = _dists[0] + else: + # Fallback (Python 3.8/3.9 lack packages_distributions): scan installed + # distributions for the one shipping the top-level `esmpy` package. + for _d in ilm.distributions(): + if "esmpy" in (_d.read_text("top_level.txt") or "").split(): + _dist_name = _d.metadata["Name"] + break + if _dist_name is None: + raise + msg = ilm.metadata(_dist_name) # set the private metadata __name__ = msg["Name"] diff --git a/src/addon/esmpy/src/esmpy/api/constants.py b/src/addon/esmpy/src/esmpy/api/constants.py index 489fdf3682..842ce11009 100644 --- a/src/addon/esmpy/src/esmpy/api/constants.py +++ b/src/addon/esmpy/src/esmpy/api/constants.py @@ -36,7 +36,8 @@ _ESMF_OS = None (_ESMF_OS_DARWIN, _ESMF_OS_LINUX, - _ESMF_OS_UNICOS) = (-5,-4,-3) + _ESMF_OS_UNICOS, + _ESMF_OS_WINDOWS) = (-5,-4,-3,-2) # ESMF_NETCDF _ESMF_NETCDF = False diff --git a/src/addon/esmpy/src/esmpy/interface/loadESMF.py b/src/addon/esmpy/src/esmpy/interface/loadESMF.py index 25dac450f9..16663cd1e1 100644 --- a/src/addon/esmpy/src/esmpy/interface/loadESMF.py +++ b/src/addon/esmpy/src/esmpy/interface/loadESMF.py @@ -6,7 +6,8 @@ import sys import traceback -from esmpy.interface.loadESMF_helpers import _check_version +from esmpy.interface.loadESMF_helpers import (_check_version, _find_esmf_mk, + _esmf_mk_is_bundled) import esmpy.api.constants as constants try: @@ -20,21 +21,11 @@ except: raise ImportError('The CTypes library cannot be found.') -esmfmk = None -try: - esmfmk = os.environ["ESMFMKFILE"] -except KeyError: - # Try to guess with very common paths in normal installs (especially conda) - guesses = [ - os.path.join(sys.prefix, 'lib', 'esmf.mk'), # conda build of esmf - os.path.join(sys.prefix, 'Library', 'lib', 'esmf.mk') - ] - for path in guesses: - if os.path.isfile(path): - esmfmk = path - break - else: - raise ImportError('The esmf.mk file cannot be found. Pass its path in the ESMFMKFILE environment variable.') +# The esmpy package directory (two levels up from this file: esmpy/interface/). +# Used both to find an esmf.mk bundled inside a pip wheel and to detect that case. +_PACKAGE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__))) + +esmfmk = _find_esmf_mk(os.environ, sys.prefix, _PACKAGE_DIR) #### INVESTIGATE esmf.mk ###################################################### @@ -92,6 +83,13 @@ libsdir = libsdir.rstrip() esmfos = esmfos.rstrip() +# For a pip wheel that bundles the ESMF library, the absolute ESMF_LIBSDIR baked +# into esmf.mk at build time is invalid once the package is relocated into +# site-packages. The bundled library sits next to esmf.mk, so resolve the library +# directory relative to it. This is a no-op for conda/source/HPC installs. +if _esmf_mk_is_bundled(esmfmk, _PACKAGE_DIR): + libsdir = os.path.dirname(os.path.abspath(esmfmk)) + # set _ESMF_OS if "Darwin" in esmfos: constants._ESMF_OS = constants._ESMF_OS_DARWIN @@ -99,6 +97,10 @@ constants._ESMF_OS = constants._ESMF_OS_LINUX elif "Unicos" in esmfos: constants._ESMF_OS = constants._ESMF_OS_UNICOS +elif os.name == "nt": + # Windows (e.g. a MinGW build); the esmf.mk ESMF_OS string varies, so key off + # the running interpreter, which for a wheel always matches the target OS. + constants._ESMF_OS = constants._ESMF_OS_WINDOWS else: raise ValueError("Unrecognized ESMF_OS setting!") @@ -128,12 +130,47 @@ # point. constants._ESMF_USE_INMEM_FACTORS = use_inmem_factors +#### MPI RUNTIME (real-MPI builds) ############################################ + +# A real-MPI build (ESMF_COMM != mpiuni) links libesmf_fullylinked against the C +# MPI runtime (libmpi). For a pip wheel we do NOT vendor libmpi: it is supplied by a +# separate runtime wheel (e.g. `mpich` for the esmpy-mpich distribution, or +# `openmpi` for esmpy-openmpi), which installs libmpi into /lib via the +# wheel "data" scheme -- a directory not on the default dynamic-loader search path. +# Preload it here with RTLD_GLOBAL, before libesmf is dlopened, so libesmf's MPI +# symbols bind to it. This stays comm-agnostic: try the known C libmpi sonames +# (MPICH's libmpi.so.12, Open MPI's libmpi.so.40) and the unversioned fallback, and +# load the first that is present. Best-effort: if none is there (a conda/HPC/system +# MPI already on the loader path, or a serial build), skip and let the normal loader +# search apply. +if esmfcomm is not None and "mpiuni" not in esmfcomm: + import sysconfig + _mpi_libdir = os.path.join(sysconfig.get_paths()["data"], "lib") + if constants._ESMF_OS == constants._ESMF_OS_DARWIN: + _mpi_names = ("libmpi.12.dylib", "libmpi.40.dylib", "libmpi.dylib") + else: + _mpi_names = ("libmpi.so.12", "libmpi.so.40", "libmpi.so") + for _mpi_name in _mpi_names: + _mpi_path = os.path.join(_mpi_libdir, _mpi_name) + if os.path.exists(_mpi_path): + try: + ct.CDLL(_mpi_path, mode=ct.RTLD_GLOBAL) + except OSError: + pass + break + #### SHARED LIBRARY ########################################################### # load the shared library for esmf try: if constants._ESMF_OS == constants._ESMF_OS_DARWIN: _ESMF = np.ctypeslib.load_library('libesmf_fullylinked',libsdir) + elif constants._ESMF_OS == constants._ESMF_OS_WINDOWS: + # Ensure the bundled dependency DLLs (also in libsdir) are on the search path. + if hasattr(os, "add_dll_directory"): + os.add_dll_directory(libsdir) + _ESMF = ct.CDLL(os.path.join(libsdir,'libesmf_fullylinked.dll'), + mode=ct.RTLD_GLOBAL) else: _ESMF = ct.CDLL(os.path.join(libsdir,'libesmf_fullylinked.so'), mode=ct.RTLD_GLOBAL) diff --git a/src/addon/esmpy/src/esmpy/interface/loadESMF_helpers.py b/src/addon/esmpy/src/esmpy/interface/loadESMF_helpers.py index 4f973c6fc6..32da8b040d 100644 --- a/src/addon/esmpy/src/esmpy/interface/loadESMF_helpers.py +++ b/src/addon/esmpy/src/esmpy/interface/loadESMF_helpers.py @@ -9,11 +9,55 @@ loadESMF.py. """ +import os import re import warnings from esmpy.util.exceptions import VersionWarning, VersionMismatch +def _find_esmf_mk(environ, sys_prefix, package_dir): + """ + Locate the esmf.mk makefile fragment that describes the ESMF installation. + + Resolution order: + 1. The ESMFMKFILE environment variable, if set (returned as-is, matching the + historical behavior where a missing file surfaces later as an open() error). + 2. A copy bundled inside the installed esmpy package (a pip wheel that ships + libesmf_fullylinked alongside esmf.mk); see _esmf_mk_is_bundled. + 3. Common conda layouts under sys.prefix. + + Raises ImportError if ESMFMKFILE is unset and no esmf.mk can be found. + """ + if "ESMFMKFILE" in environ: + return environ["ESMFMKFILE"] + + guesses = [ + os.path.join(package_dir, "_esmf", "lib", "esmf.mk"), # bundled in a wheel + os.path.join(sys_prefix, "lib", "esmf.mk"), # conda build of esmf + os.path.join(sys_prefix, "Library", "lib", "esmf.mk"), # conda on Windows + ] + for path in guesses: + if os.path.isfile(path): + return path + raise ImportError("The esmf.mk file cannot be found. Pass its path in the " + "ESMFMKFILE environment variable.") + + +def _esmf_mk_is_bundled(esmf_mk, package_dir): + """ + Return True if esmf_mk lives inside the installed esmpy package (i.e. a wheel + that bundles the ESMF library). + + In that case the absolute ESMF_LIBSDIR baked into esmf.mk at build time is + meaningless once pip relocates the package, so the caller resolves the library + directory relative to esmf.mk instead. Returns False for conda/source/HPC + installs, where the baked path is authoritative and behavior is unchanged. + """ + pkg = os.path.realpath(package_dir) + mk = os.path.realpath(esmf_mk) + return mk == pkg or mk.startswith(pkg + os.sep) + + def _check_version(esmfversion, esmpyversion): """ Check the ESMF version (from ESMF_VERSION_STRING in the esmf.mk file) against the diff --git a/src/addon/esmpy/src/esmpy/test/test_interface/test_loadESMF_helpers.py b/src/addon/esmpy/src/esmpy/test/test_interface/test_loadESMF_helpers.py index 6b9cf38b14..b574066cd4 100644 --- a/src/addon/esmpy/src/esmpy/test/test_interface/test_loadESMF_helpers.py +++ b/src/addon/esmpy/src/esmpy/test/test_interface/test_loadESMF_helpers.py @@ -2,10 +2,14 @@ Unit tests of loadESMF_helpers.py """ +import os +import tempfile + import pytest import warnings -from esmpy.interface.loadESMF_helpers import _check_version +from esmpy.interface.loadESMF_helpers import (_check_version, _find_esmf_mk, + _esmf_mk_is_bundled) from esmpy.test.base import TestBase from esmpy.util.exceptions import VersionWarning, VersionMismatch @@ -89,3 +93,112 @@ def test_check_version_release_vs_beta(self): with pytest.raises(VersionMismatch): _check_version("8.9.0", "8.9.0b0") + def test_find_esmf_mk_env_var_takes_precedence(self): + """ + Given ESMFMKFILE set in the environment, + when _find_esmf_mk is called, + then that value is returned verbatim (even if the file does not exist), + preserving the historical behavior. + """ + environ = {"ESMFMKFILE": "/some/explicit/esmf.mk"} + result = _find_esmf_mk(environ, sys_prefix="/unused", package_dir="/unused") + assert result == "/some/explicit/esmf.mk" + + def test_find_esmf_mk_bundled_in_package(self): + """ + Given no ESMFMKFILE and an esmf.mk bundled inside the esmpy package, + when _find_esmf_mk is called, + then the bundled esmf.mk path is returned. + """ + with tempfile.TemporaryDirectory() as tmp: + pkg = os.path.join(tmp, "esmpy") + bundled = os.path.join(pkg, "_esmf", "lib", "esmf.mk") + os.makedirs(os.path.dirname(bundled)) + open(bundled, "w").close() + result = _find_esmf_mk({}, sys_prefix=tmp, package_dir=pkg) + assert result == bundled + + def test_find_esmf_mk_bundled_preferred_over_conda(self): + """ + Given both a bundled esmf.mk and a conda-style sys.prefix/lib/esmf.mk, + when _find_esmf_mk is called, + then the bundled copy wins. + """ + with tempfile.TemporaryDirectory() as tmp: + pkg = os.path.join(tmp, "esmpy") + bundled = os.path.join(pkg, "_esmf", "lib", "esmf.mk") + conda = os.path.join(tmp, "lib", "esmf.mk") + for path in (bundled, conda): + os.makedirs(os.path.dirname(path)) + open(path, "w").close() + result = _find_esmf_mk({}, sys_prefix=tmp, package_dir=pkg) + assert result == bundled + + def test_find_esmf_mk_conda_prefix(self): + """ + Given no ESMFMKFILE and only a conda-style sys.prefix/lib/esmf.mk, + when _find_esmf_mk is called, + then that path is returned. + """ + with tempfile.TemporaryDirectory() as tmp: + conda = os.path.join(tmp, "lib", "esmf.mk") + os.makedirs(os.path.dirname(conda)) + open(conda, "w").close() + pkg = os.path.join(tmp, "esmpy") # no bundled esmf.mk here + result = _find_esmf_mk({}, sys_prefix=tmp, package_dir=pkg) + assert result == conda + + def test_find_esmf_mk_not_found_raises(self): + """ + Given no ESMFMKFILE and no esmf.mk in any known location, + when _find_esmf_mk is called, + then an ImportError is raised. + """ + with tempfile.TemporaryDirectory() as tmp: + with pytest.raises(ImportError): + _find_esmf_mk({}, sys_prefix=tmp, + package_dir=os.path.join(tmp, "esmpy")) + + def test_esmf_mk_is_bundled_true(self): + """ + Given an esmf.mk located inside the esmpy package directory, + when _esmf_mk_is_bundled is called, + then it returns True. + """ + with tempfile.TemporaryDirectory() as tmp: + pkg = os.path.join(tmp, "esmpy") + mk = os.path.join(pkg, "_esmf", "lib", "esmf.mk") + os.makedirs(os.path.dirname(mk)) + open(mk, "w").close() + assert _esmf_mk_is_bundled(mk, pkg) is True + + def test_esmf_mk_is_bundled_false_outside_package(self): + """ + Given an esmf.mk outside the esmpy package (conda/source install), + when _esmf_mk_is_bundled is called, + then it returns False. + """ + with tempfile.TemporaryDirectory() as tmp: + pkg = os.path.join(tmp, "esmpy") + os.makedirs(pkg) + mk = os.path.join(tmp, "lib", "esmf.mk") + os.makedirs(os.path.dirname(mk)) + open(mk, "w").close() + assert _esmf_mk_is_bundled(mk, pkg) is False + + def test_esmf_mk_is_bundled_false_for_sibling_prefix(self): + """ + Given a package dir and an esmf.mk under a sibling directory whose path + merely starts with the package dir's name (e.g. esmpy vs esmpy-data), + when _esmf_mk_is_bundled is called, + then it returns False (the separator guard prevents a false match). + """ + with tempfile.TemporaryDirectory() as tmp: + pkg = os.path.join(tmp, "esmpy") + sibling = os.path.join(tmp, "esmpy-data") + os.makedirs(pkg) + os.makedirs(sibling) + mk = os.path.join(sibling, "esmf.mk") + open(mk, "w").close() + assert _esmf_mk_is_bundled(mk, pkg) is False +