Skip to content

Fix Windows ZTS shared-build LNK2001 on _tsrm_ls_cache#1674

Merged
jahnvi480 merged 1 commit into
devfrom
fix/windows-ts-tsrmls-cache-linkage
Jul 9, 2026
Merged

Fix Windows ZTS shared-build LNK2001 on _tsrm_ls_cache#1674
jahnvi480 merged 1 commit into
devfrom
fix/windows-ts-tsrmls-cache-linkage

Conversation

@jahnvi480

Copy link
Copy Markdown
Contributor

Problem

Windows thread-safe (ZTS) shared builds fail to link:

core_stmt.obj : error LNK2001: unresolved external symbol
"void * _tsrm_ls_cache" (?_tsrm_ls_cache@@3PEAXEA)
fatal error LNK1120: 1 unresolved externals

NTS builds and all Linux/macOS builds are unaffected.

Root cause

A C vs C++ language-linkage mismatch on _tsrm_ls_cache, exposed only when
ZEND_ENABLE_STATIC_TSRMLS_CACHE is defined (config.w32 defines it; config.m4 does not):

  • init.cpp / pdo_init.cpp include php_*sqlsrv.h (-> php.h -> zend.h) inside
    an extern "C" block, so zend.h's file-scope ZEND_TSRMLS_CACHE_EXTERN() gives
    _tsrm_ls_cache C linkage, and ZEND_TSRMLS_CACHE_DEFINE() defines the unmangled symbol.
  • shared/core_sqlsrv.h includes php.h outside extern "C", so core_stmt.cpp
    (via SQLSRV_G -> ZEND_MODULE_GLOBALS_ACCESSOR -> TSRMG_STATIC -> _tsrm_ls_cache)
    references the C++-mangled ?_tsrm_ls_cache@@3PEAXEA.
  • Definition (C, unmangled) != reference (C++, mangled) -> LNK2001.

The define is applied consistently to every sqlsrv/pdo_sqlsrv translation unit, so the
failure is a linkage mismatch rather than a missing define. Merely relocating the define
within config.w32 is a no-op; removing it is what changes the outcome.

Fix

Remove /DZEND_ENABLE_STATIC_TSRMLS_CACHE=1 from both EXTENSION() calls. The Windows
shared build then resolves the TSRM cache through the engine (tsrm_get_ls_cache()),
matching the Linux/macOS config.m4 builds and the Windows static build.

Drop /DZEND_ENABLE_STATIC_TSRMLS_CACHE=1 from the sqlsrv and pdo_sqlsrv
EXTENSION() calls in config.w32.

On thread-safe (ZTS) shared builds this define made init.cpp / pdo_init.cpp
define _tsrm_ls_cache with C linkage (php_sqlsrv.h / php_pdo_sqlsrv.h are
included inside an extern "C" block), while the shared core_*.cpp translation
units reference it with C++ linkage (core_sqlsrv.h includes php.h outside
extern "C"). The linkage mismatch produced:

  core_stmt.obj : error LNK2001: unresolved external symbol
  "void * _tsrm_ls_cache" (?_tsrm_ls_cache@@3PEAXEA)
  fatal error LNK1120: 1 unresolved externals

Removing the define makes the Windows shared build resolve the TSRM cache
through the engine (tsrm_get_ls_cache()), matching the Linux/macOS config.m4
builds and the Windows static build. NTS builds are unaffected.
@codecov

codecov Bot commented Jul 9, 2026

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 85.80%. Comparing base (c0edf0c) to head (39317c0).

Additional details and impacted files

Impacted file tree graph

@@           Coverage Diff           @@
##              dev    #1674   +/-   ##
=======================================
  Coverage   85.80%   85.80%           
=======================================
  Files          23       23           
  Lines        7247     7247           
=======================================
  Hits         6218     6218           
  Misses       1029     1029           
🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

@jahnvi480 jahnvi480 merged commit 5fe2823 into dev Jul 9, 2026
15 checks passed
@jahnvi480 jahnvi480 deleted the fix/windows-ts-tsrmls-cache-linkage branch July 9, 2026 09:13
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.

2 participants