CMake: `-fPIC` and other Unix flags injected for Clang on Windows
envgap__google__sentencepiece-1239
01 / FAILURE SIGNATURE
As reported upstream
The MSVC ABI is position-independent by definition, so `-fPIC` is a no-op (or hard error) there even for MSVC; on Clang-on-Windows it is rejected outright.
Not a benchmark task.
- The project already builds and runs before the fix, so there is nothing to repair.
02 / ENVIRONMENT RECIPE
- Base commit
6cc43b55016f17486291033e8da4a6cd1614ecec- Manifest
CMakeLists.txt- Reproduce
Awaiting issue-specific recipe- Run under trace
Awaiting a meaningful runtime command
03 / ORIGINAL ISSUE TEXT
google/sentencepiece #1239 · read the original issue
**Describe the bug**
On Windows, several Unix-toolchain compiler flags are injected unconditionally for any compiler that is not MSVC's `cl.exe`. The gates use `if (NOT MSVC)`, but `MSVC` is `FALSE` for `clang.exe` (whether it is invoked as `clang-cl` on x64 Windows or as `clang` driven by a toolchain file targeting the MSVC ABI). As a result, building sentencepiece with native Clang on Windows fails because Clang rejects flags such as `-fPIC` and `-pthread` on the MSVC ABI.
There are three injection sites, all driven by the same root cause:
1. `CMakeLists.txt:47–49` — sets `CMAKE_POSITION_INDEPENDENT_CODE ON` whenever `SPM_ENABLE_SHARED` is on. CMake translates this to `-fPIC` for non-MSVC compilers. The block at `CMakeLists.txt:60–62` (`if(WIN32) set(SPM_ENABLE_SHARED OFF)`) runs *after* this, so on Windows the global is set first and only later does `SPM_ENABLE_SHARED` get forced off.
2. `src/CMakeLists.txt:254` — `if (NOT MSVC) set(CMAKE_CXX_FLAGS "-O3 -Wall -fPIC ${CMAKE_CXX_FLAGS}")` plus a few `-Wno-*` sets. Fires for Clang-on-Windows.
3. `src/CMakeLists.txt:56–60` — in the internal-protobuf branch, `if (MSVC) /DHAVE_PTHREAD ... else() -pthread -DHAVE_PTHREAD=1 -Wno-sign-compare -Wno-deprecated-declarations`. Same gate, same problem.
The MSVC ABI is position-independent by definition, so `-fPIC` is a no-op (or hard error) there even for MSVC; on Clang-on-Windows it is rejected outright.
**To Reproduce**
- OS: Windows 10/11 (any Windows host with native Clang reproduces).
- Compiler: any of the following triggers it:
- `clang-cl` from a recent LLVM release (e.g. 17+).
- `clang.exe` driven by a CMake toolchain file that targets the MSVC ABI (for example a Windows-on-arm64 toolchain that sets `CMAKE_CXX_COMPILER_TARGET=arm64-pc-windows-msvc`).
- CMake: 3.27+, Ninja or NMake generator (Visual Studio + ClangCL toolset also reproduces).
- Commands (toolchain-file form):
```
cmake -S . -B build ^
-G Ninja ^
-DCMAKE_TOOLCHAIN_FILE=<path/to/clang-windows.cmake> ^
-DCMAKE_BUILD_TYPE=Release
cmake --build build
```
- Observed: configure succeeds, build fails with Clang errors on `-fPIC` (and warnings → errors on `-pthread` / GCC-style `-Wno-*` depending on `-Werror` policy).
A minimal reproducer of the gate logic, without sentencepiece-specific knobs:
```cmake
# CMAKE_CXX_COMPILER_ID == "Clang", MSVC == FALSE, WIN32 == TRUE
if (NOT MSVC)
set(CMAKE_CXX_FLAGS "-fPIC ${CMAKE_CXX_FLAGS}") # injected on Clang-Windows
endif()
```
**Expected behavior**
On Windows, regardless of which compiler is in use, the build should not inject `-fPIC`, `-pthread`, `-O3 -Wall`, or other Unix-toolchain flags. The check should be against the *platform* (Windows vs. Unix), not against `MSVC` (the compiler frontend), since these flags are defined by the platform/ABI rather than by the compiler.
**Proposed fix**
Switch the three gates from `NOT MSVC` to `NOT WIN32` (and the corresponding `if (MSVC)` to `if (WIN32)` in site #3), and additionally gate the `CMAKE_POSITION_INDEPENDENT_CODE` global on `NOT WIN32`:
- `CMakeLists.txt`: `if (SPM_ENABLE_SHARED AND NOT WIN32)` around the PIC global.
- `src/CMakeLists.txt:254`: `if (NOT MSVC)` → `if (NOT WIN32)`.
- `src/CMakeLists.txt:56–60`: `if (MSVC) ... else() ...` → `if (WIN32) ... else() ...`.
No behavior change on Linux/macOS or under MSVC `cl.exe`.04 / LABELS
Labels from the report text only; not yet run
No supported category has been assigned.
Label rules and the text that matched
[]