Skip to content

CMake: check that the POSIX regex functions link, not just regex.h - #67

Open
pjknowles wants to merge 1 commit into
KarypisLab:masterfrom
pjknowles:cmake-regex-link-check
Open

pjknowles wants to merge 1 commit into
KarypisLab:masterfrom
pjknowles:cmake-regex-link-check

Conversation

@pjknowles

Copy link
Copy Markdown

Problem

CMakeLists.txt takes finding regex.h to mean that regcomp() and friends can be linked. That is true where they are in libc (glibc, macOS, the BSDs), but not where regex.h belongs to a separate library. On MSYS2 (MinGW-w64, e.g. UCRT64) regex.h comes from libsystre (built on TRE). GKlib builds, but anything linked with it fails:

ld.exe: .../lib/libGKlib.a(string.c.obj):string.c:(.text+0x151): undefined reference to `regcomp'
ld.exe: .../lib/libGKlib.a(string.c.obj):string.c:(.text+0x1d4): undefined reference to `regexec'
ld.exe: .../lib/libGKlib.a(string.c.obj):string.c:(.text+0x35c): undefined reference to `regfree'

Fix

  • Compile and link a small program that calls regcomp(), regexec(), regerror() and regfree().
  • If that fails with the C library alone, try systre, tre, gnurx and regex in turn. Add the first one that works to GKlib's PUBLIC link libraries, so it is exported to find_package(GKlib) users. This is the same approach already used for libexecinfo.
  • If none works, use GKlib's own implementation (gkregex) rather than producing a library that cannot be linked.
  • check_symbol_exists() is deliberately not used: it accepts a macro, and TRE's regex.h defines regcomp etc. as macros for tre_regcomp etc., so it would wrongly report success.
  • The GKREGEX option (make config gkregex=set) was declared but had no effect. It now selects gkregex unconditionally, which gives users a way to avoid the system regex.

Testing

MSYS2 UCRT64, GCC 16.2.0, CMake 4.4.4, libsystre 1.0.2. Each case builds and installs GKlib (GKLIB_BUILD_APPS=OFF unless stated), then builds a small find_package(GKlib) program that calls gk_strstr_replace() and runs it:

Case Before After
default GKlib builds; test program fails to link (above) systre detected and exported; program runs correctly
default, GKLIB_BUILD_APPS=ON – builds; program runs correctly
no usable regex library (library checks forced off), CMAKE_C_STANDARD=17 – falls back to gkregex; program runs correctly
same, default C standard (C23) – gkregex.c fails to compile, as fixed by #66; with #66 applied, program runs correctly
GKREGEX=ON, CMAKE_C_STANDARD=17 – uses gkregex; program runs correctly

macOS (Apple clang). The library check passes against libc, nothing extra is linked and the program runs correctly. I also ran GKREGEX=ON, plus a TRE-style regex.h that maps regcomp to tre_regcomp. With no library providing tre_regcomp, GKlib falls back to gkregex. When a libtre is available, tre is detected, exported and linked. In both cases the test program runs correctly. Without this change, that setup fails to link (_tre_regcomp undefined).

Not tested: Linux (the libc check should pass exactly as on macOS) and native MSVC (no regex.h, so behaviour is unchanged).

Known limitation: a fully static link (-static) on MSYS2 still needs -ltre -lintl -liconv added by the user. libsystre.a depends on these, and the check only sees the shared import library. Setting GKREGEX=ON avoids this.

Reported by Claude Code on behalf of @pjknowles, following a request from @ajmay81.

🤖 Generated with Claude Code

https://claude.ai/code/session_01HhHuoyV4eedKKTaFRt9Wfi

Finding regex.h was taken to mean that regcomp() etc. are available.
On some systems the header belongs to a separate library that is not
linked by default: on MSYS2 (MinGW-w64) regex.h comes from libsystre
(TRE), whose regex.h defines regcomp etc. as macros for tre_regcomp
etc., so GKlib compiles but fails to link (undefined tre_regcomp).

Now compile and link a small program that calls regcomp(), regexec(),
regerror() and regfree(). If that fails with the C library alone, try
systre, tre, gnurx and regex, and add the first that works to GKlib's
public link interface (as for libexecinfo). If none works, fall back to
GKlib's own implementation (gkregex) instead of building a library
that cannot be linked. check_symbol_exists() is not used, because it
accepts a macro and so cannot detect the TRE case.

The GKREGEX option (make config gkregex=set) was declared but had no
effect; it now selects gkregex unconditionally.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01HhHuoyV4eedKKTaFRt9Wfi
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant