Commit 7cd8a0a0a47 for php.net
commit 7cd8a0a0a471b12bd2940fbb3b1406d9d77ec911
Author: Marc <m@pyc.ac>
Date: Mon Apr 20 21:20:59 2026 +0700
[Windows] Improve clang-cl support (#21618)
* fix compiling (intl) C++ extensions --with-toolset=clang
* guard the double extern "C" { ... } for clang-only
* don't error on warnings with clang
* enable compiler intrinsics for clang too
* make --enable-compiler-intrinsics=no same as disabled
* add clang windows x64 ZTS test
* remove check if it's clang
* debloat logs from common warning
* @shivammathur feedback
* remove CI changes
* rebase on https://github.com/php/php-src/pull/21630
* fix default to asan => false
* bring back explicit error
* fix typo
diff --git a/.github/matrix.php b/.github/matrix.php
index dec8c7d249c..18c2ef1269b 100644
--- a/.github/matrix.php
+++ b/.github/matrix.php
@@ -144,12 +144,15 @@ function select_jobs($repository, $trigger, $nightly, $labels, $php_version, $re
$jobs['SOLARIS'] = true;
}
if ($all_jobs || !$no_jobs || $test_windows) {
- $jobs['WINDOWS']['matrix'] = $all_variations
- ? ['include' => [
- ['asan' => true, 'opcache' => true, 'x64' => true, 'zts' => true],
- ['asan' => false, 'opcache' => false, 'x64' => false, 'zts' => false],
- ]]
- : ['include' => [['asan' => false, 'opcache' => true, 'x64' => true, 'zts' => true]]];
+ $matrix = [['asan' => false, 'opcache' => true, 'x64' => true, 'zts' => true]];
+ if ($all_variations) {
+ $matrix[] = ['asan' => true, 'opcache' => true, 'x64' => true, 'zts' => true];
+ $matrix[] = ['asan' => false, 'opcache' => false, 'x64' => false, 'zts' => false];
+ if (version_compare($php_version, '8.5', '>=')) {
+ $matrix[] = ['asan' => false, 'opcache' => true, 'x64' => true, 'zts' => true, 'clang' => true];
+ }
+ }
+ $jobs['WINDOWS']['matrix'] = ['include' => $matrix];
$jobs['WINDOWS']['config'] = version_compare($php_version, '8.4', '>=')
? ['vs_crt_version' => 'vs17']
: ['vs_crt_version' => 'vs16'];
diff --git a/.github/scripts/windows/build_task.bat b/.github/scripts/windows/build_task.bat
index b6547945184..1177cef3be4 100644
--- a/.github/scripts/windows/build_task.bat
+++ b/.github/scripts/windows/build_task.bat
@@ -26,12 +26,18 @@ if %errorlevel% neq 0 exit /b 3
if "%THREAD_SAFE%" equ "0" set ADD_CONF=%ADD_CONF% --disable-zts
if "%INTRINSICS%" neq "" set ADD_CONF=%ADD_CONF% --enable-native-intrinsics=%INTRINSICS%
if "%ASAN%" equ "1" set ADD_CONF=%ADD_CONF% --enable-sanitizer --enable-debug-pack
+if "%CLANG_TOOLSET%" equ "1" set ADD_CONF=%ADD_CONF% --with-toolset=clang
rem C4018: comparison: signed/unsigned mismatch
rem C4146: unary minus operator applied to unsigned type
rem C4244: type conversion, possible loss of data
rem C4267: 'size_t' type conversion, possible loss of data
-set CFLAGS=/W3 /WX /wd4018 /wd4146 /wd4244 /wd4267
+if "%CLANG_TOOLSET%" equ "1" (
+ rem Clang is much stricter than MSVC, produces too many warnings that would fail the build with /WX
+ set CFLAGS=/W3 /wd4018 /wd4146 /wd4244 /wd4267
+) else (
+ set CFLAGS=/W3 /WX /wd4018 /wd4146 /wd4244 /wd4267
+)
cmd /c configure.bat ^
--enable-snapshot-build ^
diff --git a/.github/workflows/test-suite.yml b/.github/workflows/test-suite.yml
index 90bcafd1630..4905dcb9ccb 100644
--- a/.github/workflows/test-suite.yml
+++ b/.github/workflows/test-suite.yml
@@ -940,7 +940,7 @@ jobs:
strategy:
fail-fast: false
matrix: ${{ fromJson(inputs.branch).jobs.WINDOWS.matrix }}
- name: "WINDOWS_${{ matrix.x64 && 'X64' || 'X86' }}_${{ matrix.zts && 'ZTS' || 'NTS' }}${{ matrix.asan && '_ASAN' || ''}}"
+ name: "WINDOWS_${{ matrix.x64 && 'X64' || 'X86' }}_${{ matrix.zts && 'ZTS' || 'NTS' }}${{ matrix.asan && '_ASAN' || ''}}${{ matrix.clang && '_CLANG' || ''}}"
runs-on: windows-2022
env:
PHP_BUILD_CACHE_BASE_DIR: C:\build-cache
@@ -954,6 +954,7 @@ jobs:
PARALLEL: -j2
OPCACHE: "${{ matrix.opcache && '1' || '0' }}"
ASAN: "${{ matrix.asan && '1' || '0' }}"
+ CLANG_TOOLSET: "${{ matrix.clang && '1' || '0' }}"
steps:
- name: git config
run: git config --global core.autocrlf false && git config --global core.eol lf
diff --git a/TSRM/TSRM.h b/TSRM/TSRM.h
index 80d6cbad044..ea13552c837 100644
--- a/TSRM/TSRM.h
+++ b/TSRM/TSRM.h
@@ -175,9 +175,14 @@ TSRM_API bool tsrm_is_managed_thread(void);
#define TSRMG_BULK_STATIC(id, type) ((type) (*((void ***) TSRMLS_CACHE))[TSRM_UNSHUFFLE_RSRC_ID(id)])
#define TSRMG_FAST_STATIC(offset, type, element) (TSRMG_FAST_BULK_STATIC(offset, type)->element)
#define TSRMG_FAST_BULK_STATIC(offset, type) ((type) (((char*) TSRMLS_CACHE)+(offset)))
+#ifdef __cplusplus
+#define TSRMLS_MAIN_CACHE_EXTERN() extern "C" { extern TSRM_TLS void *TSRMLS_CACHE TSRM_TLS_MODEL_ATTR; }
+#define TSRMLS_CACHE_EXTERN() extern "C" { extern TSRM_TLS void *TSRMLS_CACHE; }
+#else
#define TSRMLS_MAIN_CACHE_EXTERN() extern TSRM_TLS void *TSRMLS_CACHE TSRM_TLS_MODEL_ATTR;
-#define TSRMLS_MAIN_CACHE_DEFINE() TSRM_TLS void *TSRMLS_CACHE TSRM_TLS_MODEL_ATTR = NULL;
#define TSRMLS_CACHE_EXTERN() extern TSRM_TLS void *TSRMLS_CACHE;
+#endif
+#define TSRMLS_MAIN_CACHE_DEFINE() TSRM_TLS void *TSRMLS_CACHE TSRM_TLS_MODEL_ATTR = NULL;
#define TSRMLS_CACHE_DEFINE() TSRM_TLS void *TSRMLS_CACHE = NULL;
#define TSRMLS_CACHE_UPDATE() TSRMLS_CACHE = tsrm_get_ls_cache()
#define TSRMLS_CACHE _tsrm_ls_cache
diff --git a/win32/build/confutils.js b/win32/build/confutils.js
index 36484e71f8f..fd1e9ce0be1 100644
--- a/win32/build/confutils.js
+++ b/win32/build/confutils.js
@@ -3361,7 +3361,7 @@ function toolset_setup_common_cflags()
ADD_FLAG("CFLAGS", "/Zc:wchar_t");
} else if (CLANG_TOOLSET) {
- ADD_FLAG("CFLAGS", "-Wno-deprecated-declarations");
+ ADD_FLAG("CFLAGS", "-Wno-deprecated-declarations -Wno-microsoft-enum-forward-reference");
if (TARGET_ARCH == 'x86') {
ADD_FLAG('CFLAGS', '-m32');
} else {
@@ -3395,24 +3395,25 @@ function toolset_setup_intrinsic_cflags()
/* From oldest to newest. */
var scale = new Array("sse", "sse2", "sse3", "ssse3", "sse4.1", "sse4.2", "avx", "avx2", "avx512");
- if (VS_TOOLSET) {
- if ("disabled" == PHP_NATIVE_INTRINSICS) {
- ERROR("Can't enable intrinsics, --with-codegen-arch passed with an incompatible option. ")
- }
+ if ("disabled" == PHP_NATIVE_INTRINSICS) {
+ ERROR("Can't enable intrinsics, --with-codegen-arch passed with an incompatible option. ")
+ }
- if (TARGET_ARCH == 'arm64') {
- /* arm64 supports neon */
- configure_subst.Add("PHP_SIMD_SCALE", 'NEON');
- /* all officially supported arm64 cpu supports crc32 (TODO: to be confirmed) */
- AC_DEFINE('HAVE_ARCH64_CRC32', 1);
- return;
- }
+ if (TARGET_ARCH == 'arm64') {
+ /* arm64 supports neon */
+ configure_subst.Add("PHP_SIMD_SCALE", 'NEON');
+ /* all officially supported arm64 cpu supports crc32 (TODO: to be confirmed) */
+ AC_DEFINE('HAVE_ARCH64_CRC32', 1);
+ return;
+ }
- if ("no" == PHP_NATIVE_INTRINSICS || "yes" == PHP_NATIVE_INTRINSICS) {
- PHP_NATIVE_INTRINSICS = default_enabled;
- }
+ // if --enable-native-intrisics is not specified, it's "no" - enable default
+ if ("no" == PHP_NATIVE_INTRINSICS || "yes" == PHP_NATIVE_INTRINSICS) {
+ PHP_NATIVE_INTRINSICS = default_enabled;
+ }
- if ("all" == PHP_NATIVE_INTRINSICS) {
+ if ("all" == PHP_NATIVE_INTRINSICS) {
+ if (VS_TOOLSET) {
var list = (new VBArray(avail.Keys())).toArray();
for (var i in list) {
@@ -3421,46 +3422,61 @@ function toolset_setup_intrinsic_cflags()
/* All means all. __AVX__, __AVX2__, and __AVX512*__ are defined by compiler. */
ADD_FLAG("CFLAGS","/arch:AVX512");
- configure_subst.Add("PHP_SIMD_SCALE", "AVX512");
- } else {
- var list = PHP_NATIVE_INTRINSICS.split(",");
- var j = 0;
- for (var k = 0; k < scale.length; k++) {
- for (var i = 0; i < list.length; i++) {
- var it = list[i].toLowerCase();
- if (scale[k] == it) {
- j = k > j ? k : j;
- } else if (!avail.Exists(it) && "avx512" != it && "avx2" != it && "avx" != it) {
- WARNING("Unknown intrinsic name '" + it + "' ignored");
- }
- }
- }
- if (TARGET_ARCH == 'x86') {
- /* SSE2 is currently the default on 32-bit. It could change later,
- for now no need to pass it. But, if SSE only was chosen,
- /arch:SSE is required. */
- if ("sse" == scale[j]) {
- ADD_FLAG("CFLAGS","/arch:SSE");
+ } else if (CLANG_TOOLSET) {
+ ADD_FLAG("CFLAGS","-mavx512f -mavx512cd -mavx512bw -mavx512dq -mavx512vl");
+ }
+ configure_subst.Add("PHP_SIMD_SCALE", "AVX512");
+ } else {
+ var list = PHP_NATIVE_INTRINSICS.split(",");
+ var j = 0;
+ for (var k = 0; k < scale.length; k++) {
+ for (var i = 0; i < list.length; i++) {
+ var it = list[i].toLowerCase();
+ if (scale[k] == it) {
+ j = k > j ? k : j;
+ } else if (!avail.Exists(it) && "avx512" != it && "avx2" != it && "avx" != it) {
+ WARNING("Unknown intrinsic name '" + it + "' ignored");
}
}
- configure_subst.Add("PHP_SIMD_SCALE", scale[j].toUpperCase());
- /* There is no explicit way to enable intrinsics between SSE3 and SSE4.2.
- The declared macros therefore won't affect the code generation,
- but will enable the guarded code parts. */
- if ("avx512" == scale[j]) {
- ADD_FLAG("CFLAGS","/arch:AVX512");
- j -= 3;
- } else if ("avx2" == scale[j]) {
- ADD_FLAG("CFLAGS","/arch:AVX2");
- j -= 2;
- } else if ("avx" == scale[j]) {
- ADD_FLAG("CFLAGS","/arch:AVX");
- j -= 1;
- }
+ }
+ if (TARGET_ARCH == 'x86') {
+ /* SSE2 is currently the default on 32-bit. It could change later,
+ for now no need to pass it. But, if SSE only was chosen,
+ /arch:SSE is required. */
+ if ("sse" == scale[j]) {
+ ADD_FLAG("CFLAGS", VS_TOOLSET ? "/arch:SSE" : "-msse");
+ }
+ }
+ configure_subst.Add("PHP_SIMD_SCALE", scale[j].toUpperCase());
+ if ("avx512" == scale[j]) {
+ ADD_FLAG("CFLAGS", VS_TOOLSET ? "/arch:AVX512" : "-mavx512f -mavx512cd -mavx512bw -mavx512dq -mavx512vl");
+ j -= 3;
+ } else if ("avx2" == scale[j]) {
+ ADD_FLAG("CFLAGS", VS_TOOLSET ? "/arch:AVX2" : "-mavx2");
+ j -= 2;
+ } else if ("avx" == scale[j]) {
+ ADD_FLAG("CFLAGS", VS_TOOLSET ? "/arch:AVX" : "-mavx");
+ j -= 1;
+ }
+ if (VS_TOOLSET) {
+ /* MSVC has no explicit way to enable intrinsics between SSE3 and SSE4.2.
+ The declared macros won't affect code generation, but will enable
+ the guarded code parts. */
for (var i = 0; i <= j; i++) {
var it = scale[i];
AC_DEFINE(avail.Item(it), 1);
}
+ } else if (CLANG_TOOLSET) {
+ /* clang supports -m flags for each SSE level and auto-defines
+ the corresponding __SSE*__ macros. Pass the highest requested
+ level; clang implicitly enables all lower levels. */
+ var clang_flag_map = {
+ "sse": "-msse", "sse2": "-msse2", "sse3": "-msse3",
+ "ssse3": "-mssse3", "sse4.1": "-msse4.1", "sse4.2": "-msse4.2"
+ };
+ if (clang_flag_map[scale[j]]) {
+ ADD_FLAG("CFLAGS", clang_flag_map[scale[j]]);
+ }
}
}
}