Repository navigation
Build the Cython extensions under GCC 14: declare the functions charm.h lacks - #313
Conversation
…n extensions GCC 14 turns incompatible-pointer-types and implicit-function-declaration into errors by default; the generated Cython code and charm4py's calls to functions charm's exported headers do not declare trigger them, so the extension build fails on Linux with GCC 14 (e.g. NCSA Delta). The darwin branch already sets -Wno-error=implicit-function-declaration via CPPFLAGS; this passes both flags to the two extensions on every non-Windows build. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
ritvikrao
left a comment
There was a problem hiding this comment.
I reproduced the failure and checked the fix on macOS with Homebrew GCC 15, which turns on the same two errors by default as GCC 14. I compiled the generated charmlib_cython.c with -fsyntax-only against the headers of a classic Charm++ build (charm main, netlrts-darwin-arm8):
| Extra compile flags | Compiler errors (count) |
|---|---|
| none | 11 |
| this PR's two flags | 0 |
The 11 errors:
- 6 ×
implicit-function-declaration:LBTurnInstrumentOn,LBTurnInstrumentOff,CkExtContributeToChare,CkExtContributeToGroup,CkExtContributeToArray,CkExtContributeToSection.ccharm.pxdlists them undercdef extern from "charm.h", butcharm.hdoesn't declare them (they are defined with C linkage inckreduction.CandLBManager.C), so Cython emits the calls with no prototype in scope. - 5 ×
incompatible-pointer-types: argument 2 ofCkRegisterMainChareExt,CkRegisterGroupExt,CkRegisterSectionManagerExt,CkRegisterArrayExtandCkRegisterArrayMapExt. The pyx passeschar **wherecharm.hexpectsconst char **.
Against a Reconverse build older than reconverse 599798b (Oct 15) there is a 12th, CcsRegisterHandlerExt. Reconverse has declared it in conv-ccs.h since then.
The flags are safe for today's code. All six undeclared functions return void and take only int and pointer arguments, so the implicit int f() declaration calls them correctly on x86-64 and arm64. The five pointer errors differ only in const. Fine to merge as it is once it builds on Delta.
Suggestion, non-blocking (here or in a follow-up): fix the two causes instead of turning the errors off. With the flags on, the next function charm4py calls without a declaration also compiles without complaint. If that function returns a pointer, the implicit int return truncates it to 32 bits on 64-bit machines, which is the main reason GCC 14 made this an error. The fix is two small edits:
diff --git a/charm4py/charmlib/ccharm.pxd b/charm4py/charmlib/ccharm.pxd
index da873e1..2759265 100644
--- a/charm4py/charmlib/ccharm.pxd
+++ b/charm4py/charmlib/ccharm.pxd
@@ -10,8 +10,6 @@ cdef extern from "charm.h":
void realCkExit(int exitcode);
void CmiAbort(const char *, ...);
void CmiPrintf(const char *, ...);
- void LBTurnInstrumentOn();
- void LBTurnInstrumentOff();
int CmiPeOnSamePhysicalNode(int pe1, int pe2);
int CmiNumPhysicalNodes();
@@ -60,10 +58,6 @@ cdef extern from "charm.h":
void registerPyReductionExtCallback(int (*cb)(char**, int*, int, char**));
void registerArrayMapProcNumExtCallback(int (*cb)(int, int, const int *));
- void CkExtContributeToChare(void* contribute_params, int onPE, void* objPtr);
- void CkExtContributeToGroup(void* contribute_params, int gid, int pe);
- void CkExtContributeToArray(void* contribute_params, int aid, int* idx, int ndims);
- void CkExtContributeToSection(void* contribute_params, int sid_pe, int sid_cnt, int rootPE);
void CkStartQDExt_ChareCallback(int onPE, void* objPtr, int epIdx, int fid);
void CkStartQDExt_GroupCallback(int gid, int pe, int epIdx, int fid);
void CkStartQDExt_ArrayCallback(int aid, int* idx, int ndims, int epIdx, int fid);
@@ -76,6 +70,24 @@ cdef extern from "charm.h":
void CkTraceBeginUserBracketEvent(int eventID);
void CkTraceEndUserBracketEvent(int eventID);
+# Defined in libcharm with C linkage but not declared in charm.h (C compilers
+# from GCC 14 on reject the implicit declarations), so declare them here.
+cdef extern from *:
+ """
+ void LBTurnInstrumentOn(void);
+ void LBTurnInstrumentOff(void);
+ void CkExtContributeToChare(void *contribute_params, int onPE, void *objPtr);
+ void CkExtContributeToGroup(void *contribute_params, int gid, int pe);
+ void CkExtContributeToArray(void *contribute_params, int aid, int *idx, int ndims);
+ void CkExtContributeToSection(void *contribute_params, int sid_pe, int sid_cnt, int rootPE);
+ """
+ void LBTurnInstrumentOn();
+ void LBTurnInstrumentOff();
+ void CkExtContributeToChare(void* contribute_params, int onPE, void* objPtr);
+ void CkExtContributeToGroup(void* contribute_params, int gid, int pe);
+ void CkExtContributeToArray(void* contribute_params, int aid, int* idx, int ndims);
+ void CkExtContributeToSection(void* contribute_params, int sid_pe, int sid_cnt, int rootPE);
+
cdef extern from "converse.h":
ctypedef void (*CmiHandler)(void* )
cdef const int CmiReservedHeaderSize
diff --git a/charm4py/charmlib/charmlib_cython.pyx b/charm4py/charmlib/charmlib_cython.pyx
index 8b2f37d..7d7a23b 100644
--- a/charm4py/charmlib/charmlib_cython.pyx
+++ b/charm4py/charmlib/charmlib_cython.pyx
@@ -525,7 +525,7 @@ class CharmLib(object):
cdef int chareIdx, startEpIdx
self.emNames += [name.encode() for name in entryMethodNames]
# TODO: do we want to track/free these pointers?
- cdef char** c1 = to_cstring_array(self.emNames)
+ cdef const char** c1 = <const char**>to_cstring_array(self.emNames)
CkRegisterMainChareExt(self.chareNames[-1], c1, self.emStart, numEntryMethods, &chareIdx, &startEpIdx)
self.emStart = len(self.emNames)
return chareIdx, startEpIdx
@@ -534,7 +534,7 @@ class CharmLib(object):
self.chareNames.append(name.encode())
cdef int chareIdx, startEpIdx
self.emNames += [name.encode() for name in entryMethodNames]
- cdef char** c1 = to_cstring_array(self.emNames)
+ cdef const char** c1 = <const char**>to_cstring_array(self.emNames)
CkRegisterGroupExt(self.chareNames[-1], c1, self.emStart, numEntryMethods, &chareIdx, &startEpIdx)
self.emStart = len(self.emNames)
return chareIdx, startEpIdx
@@ -543,7 +543,7 @@ class CharmLib(object):
self.chareNames.append(name.encode())
cdef int chareIdx, startEpIdx
self.emNames += [name.encode() for name in entryMethodNames]
- cdef char** c1 = to_cstring_array(self.emNames)
+ cdef const char** c1 = <const char**>to_cstring_array(self.emNames)
CkRegisterSectionManagerExt(self.chareNames[-1], c1, self.emStart, numEntryMethods, &chareIdx, &startEpIdx)
self.emStart = len(self.emNames)
@@ -553,7 +553,7 @@ class CharmLib(object):
self.chareNames.append(name.encode())
cdef int chareIdx, startEpIdx
self.emNames += [name.encode() for name in entryMethodNames]
- cdef char** c1 = to_cstring_array(self.emNames)
+ cdef const char** c1 = <const char**>to_cstring_array(self.emNames)
CkRegisterArrayMapExt(self.chareNames[-1], c1, self.emStart, numEntryMethods, &chareIdx, &startEpIdx)
self.emStart = len(self.emNames)
return chareIdx, startEpIdx
@@ -562,7 +562,7 @@ class CharmLib(object):
self.chareNames.append(name.encode())
cdef int chareIdx, startEpIdx
self.emNames += [name.encode() for name in entryMethodNames]
- cdef char** c1 = to_cstring_array(self.emNames)
+ cdef const char** c1 = <const char**>to_cstring_array(self.emNames)
CkRegisterArrayExt(self.chareNames[-1], c1, self.emStart, numEntryMethods, &chareIdx, &startEpIdx)
self.emStart = len(self.emNames)
return chareIdx, startEpIdxWith these edits, GCC 15 compiles the generated C with no extra flags (0 errors). Clang with -Werror=implicit-function-declaration builds and links it, and libcharm4py exports all six symbols. I only compile- and link-checked it; I didn't run the test suite with it, because my local libcharm is older than these headers. It works with any charm version because charm.h doesn't have to change. If charm.h ever declares these functions, its declarations need the same void * first argument, or C will report conflicting types. With this in, the -Wno-error=implicit-function-declaration that setup.py adds to CPPFLAGS on macOS (line 86) could go too.
Minor: c_object_store is C++ (# distutils: language=c++), and both options are C-only in GCC, so they have no effect on that extension. g++ 15 compiles it without them and accepts them silently, so this is harmless.
…ut flags
GCC 14 makes implicit-function-declaration and incompatible-pointer-types
errors by default. Compiling charmlib_cython.c hit 11 of them:
- Six functions charm4py calls (LBTurnInstrumentOn/Off and
CkExtContributeTo{Chare,Group,Array,Section}) are defined in libcharm
with C linkage but not declared in charm.h, so the generated C called
them with no prototype. ccharm.pxd now declares them in a C block.
- The entry-method name arrays passed to the five CkRegister*Ext
functions were char ** where charm.h takes const char **.
This replaces the -Wno-error flags of the previous commit, which would
also hide the next call made without a declaration, including one that
returns a pointer (the implicit int return truncates it to 32 bits).
setup.py is back to main.
Checked with GCC 15 (same defaults as 14) and clang with
-Werror=implicit-function-declaration, -fsyntax-only on the generated C:
0 errors against classic Charm++ headers and against recharm's
Reconverse headers configured for charm4py; main gives 11 with GCC 15.
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
|
I pushed c1d22ca to this branch. It applies the fix from my review: the six missing prototypes are declared in |
|
Built c1d22ca on NCSA Delta: GCC 14.2.1, Python 3.13.5, with
So it's good to leave draft from my side. (Reply written by Claude in Advait's session and posted at his request.) |
lvkale
left a comment
There was a problem hiding this comment.
Ritvik's rewrite (c1d22ca) fixes the causes rather than silencing the errors, and Advait built and ran the reduction, QD and section tests on Delta with GCC 14.2 and no CFLAGS workaround. Rebuilt and ran here too (macOS arm64, Python 3.13, Charm++ classic 917de4953): array/group/section/future/custom reductions, qd and sections/simple all pass on 4 PEs. Compiling the generated charmlib_cython.c directly with clang and -Werror=implicit-function-declaration placed last: main fails with the same 6 undeclared functions, this branch compiles clean.
One more thing found on the way, which this PR could take since it is in the same file: arrayMapProcNum(int gid, int ndims, const int *arrayIndex) (charmlib_cython.pyx line 1003) passes a const int * to cdef inline object array_index_to_tuple(int ndims, int *arrayIndex) (line 293). clang reports it under -Wincompatible-pointer-types (discards qualifiers), so a clang build with that warning as an error still fails; GCC files it under -Wdiscarded-qualifiers, which GCC 14 keeps as a warning. Adding const to the array_index_to_tuple parameter fixes it. Main has the same code, so it is not blocking.
Note for the darwin branch of setup.py: it appends -Wno-error=implicit-function-declaration through CPPFLAGS, after CFLAGS, so a user's CFLAGS=-Werror=... is cancelled on macOS. With this PR in, that flag can go in a follow-up.
Follow-up for the charm repository: declare LBTurnInstrumentOn/Off and the four CkExtContributeTo* functions in charm.h with the same void * first argument, so the private prototypes in ccharm.pxd can go.
(Review written by Claude in Kale's session and posted at his request.)
lvkale
left a comment
There was a problem hiding this comment.
Approved (local build, tests and review in the comment above).
Merge queue for PRs #310-#313, stale PR and issue triage, release 1.2, the live-tools and runtime lines, a survey of what charm4py can use of Charm++'s GPU support (device-resident data, device-to-device messaging, the GPU-aware load balancer), docs and ownership. Co-authored-by: Claude Fable 5.1 <noreply@anthropic.com> Co-authored-by: Ritvik Rao <rsrao2@illinois.edu>
Problem
On Linux with GCC 14, the default compiler on NCSA Delta,
pip installof charm4py fails while compiling the Cython extensions. GCC 14 turns two warnings into errors by default:incompatible-pointer-types, from the generated Cython code;implicit-function-declaration, because charm4py calls functions that charm's exported headers don't declare.The darwin branch of
setup.pyalready sets-Wno-error=implicit-function-declaration, but Linux gets nothing.Change
Instead of turning the two errors into warnings, this fixes what triggers them (commit c1d22ca, which replaces the first commit's
setup.pyflags, sosetup.pyis unchanged from main):LBTurnInstrumentOn,LBTurnInstrumentOffandCkExtContributeTo{Chare,Group,Array,Section}are defined in libcharm with C linkage but not declared incharm.h, so the generated C called them with no prototype.ccharm.pxdnow declares them in a C block of its own.CkRegister*Extfunctions werechar **wherecharm.htakesconst char **; they are nowconst char **.Keeping the errors as warnings would also hide the next call made without a declaration, including one that returns a pointer, which the implicit
intreturn truncates to 32 bits.Testing
-fsyntax-onlyon the generatedcharmlib_cython.c, with no extra flags, on macOS:-Werror=implicit-function-declaration(errors)GCC 15 has the same two errors on by default as GCC 14.
c_object_store(C++) compiles with g++ 15 without any flags. CI runs the test suite on this branch.Still to do before this leaves draft: build on Delta (GCC 14.2) without the
CFLAGSworkaround.🤖 Generated with Claude Code