Apple Clang bug: headers in /usr/local/include may cause build isolation failures on macOS (for any package)
Nobody has claimed this yet.
- Dominant language
- CMake
- Stars
- 27.5k
- Forks
- 7.7k
- Avg merge
- 2d 19h
- Merged PRs (30d)
- 321
Description
## Summary
Apple Clang has a bug where `/usr/local/include` is searched before `-isystem` paths, breaking vcpkg's build isolation on macOS when system headers exist in `/usr/local/include`.
For example, a preexisting `zlib.h` 1.2.12 in `/usr/local/include` can shadow vcpkg's zlib 1.3.1 during the build of dependent packages like libpng.
This can cause version conflicts and build failures in dependent packages.
See for example the libpng issue https://github.com/microsoft/vcpkg/issues/48330 (where zlib version mismatch causes build failure).
> Note: files inside /usr/local/include are never installed by default on macOS. They are also not installed by homebrew. Their presence often indicates legacy or manual development setups (where developers manually built and installed libraries from source, and likely forgot to clean up).
**Related stack overflow discussion**: https://stackoverflow.com/questions/66325376/clang-does-not-respect-isystem-flag-different-behavior-from-g
## Environment
- **Host OS**: macOS 15.5 (arm64)
- **Compiler**: Apple clang version 17.0.0 (clang-1700.0.13.5) (from Xcode)
- **vcpkg version**: commit 7824193852 (2025-11-20)
- **Affected packages**: libpng (confirmed), potentially many others
## Root Cause Analysis
### Apple Clang Include Path Bug
Apple's version of Clang has a known bug where `/usr/local/include` is placed at the beginning of the system include search path, **before** any `-isystem` directories specified on the command line.
**Demonstration:**
```bash
echo '#include ' | clang++ -isystem /tmp -E -v - 2>&1 | grep -A 10 "#include <...> search starts here:"
```
**Apple Clang Result (BROKEN):**
```
#include <...> search starts here:
/usr/local/include <- /usr/local/include system path comes FIRST
/tmp <- user selected -isystem comes AFTER
/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/lib/clang/17/include
... <- Other system paths come later
```
**Comparison with GCC/upstream Clang (CORRECT):**
```bash
echo '#include ' | gcc -isystem /tmp -E -v - 2>&1 | grep -A 10 "#include <...> search starts here:"
```
```
#include <...> search starts here:
/tmp <- -user selected -isystem comes FIRST
/usr/local/include <- All System path comes AFTER
/usr/lib/gcc/aarch64-linux-gnu/11/include
...
```
### Impact on vcpkg
vcpkg uses `-isystem` flags to provide package headers, expecting them to take precedence over system paths. Due to this Apple Clang bug, it is not the case on macOS when `/usr/local/include` contains conflicting headers.
## Reproduction Case
### Setup System Conflict
Create a fake older `zlib.h` in /usr/local/include to simulate the conflict.
This should not affect the build, since vcpkg should use its own zlib. However, this header file will take precedence.
```bash
sudo mkdir -p /usr/local/include
sudo tee /usr/local/include/zlib.h > /dev/null << 'EOF'
#ifndef ZLIB_H
#define ZLIB_H
#define ZLIB_VERSION "1.2.12"
#define ZLIB_VERNUM 0x12c0
// Minimal zlib.h content for demonstration
#endif
EOF
```
### Attempt vcpkg Installation of libpng (depends on zlib)
```bash
./vcpkg remove libpng --triplet arm64-osx
./vcpkg install libpng --triplet arm64-osx --no-binarycaching
```
### Expected vs Actual Results
**Expected**: libpng builds successfully using vcpkg's zlib 1.3.1
**Actual**: Build fails with:
```
error: The include path of is incorrect
```
**Root cause**: libpng finds system zlib 1.2.12 instead of vcpkg zlib 1.3.1 due to include path ordering.
## Scope of Impact
This issue potentially affects **any vcpkg package** when:
1. A system version of a header exists in `/usr/local/include` (may originate from a manual build)
2. The build runs on macOS with Apple Clang
**Common sources of `/usr/local/include` pollution:**
- Manual `./configure && make install` builds (default prefix)
- Legacy development setups
- Third-party installer scripts?
## Potential Solutions
### 1. Per-Package Workaround (example: libpng)
A possible solution is to modify all potentially affected package portfiles to explicitly use `-I` instead of `-isystem` when building on macOS if a conflict is detected.
For example, a potential fix for https://github.com/microsoft/vcpkg/issues/48330, is in libpng's portfile.cmake:
```cmake
if(VCPKG_TARGET_IS_OSX AND EXISTS "/usr/local/include/zlib.h")
set(VCPKG_INCLUDE_OVERRIDE "-DCMAKE_C_FLAGS=-I${CURRENT_INSTALLED_DIR}/include")
endif()
vcpkg_cmake_configure(
SOURCE_PATH "${SOURCE_PATH}"
OPTIONS
${VCPKG_INCLUDE_OVERRIDE}
...
```
**Pros**: Surgical, maintains warning suppression for other headers
**Cons**: Requires individual fixes for each affected package (i.e. any package depending on zlib, etc.)
### 2. Conflict Detection in Root Packages
Add detection in foundational packages (zlib, openssl, etc.) that fail with clear error messages when conflicts exist.
**Pros**: Forces users to clean up system pollution
**Cons**: Disruptive to existing workflows
For example, in zlib's portfile.cmake:
```cmake
if(VCPKG_TARGET_IS_OSX AND EXISTS "/usr/local/include/zlib.h")
message(FATAL_ERROR # or a warning
"System zlib detected. This may causes build failures due to Apple Clang include path bugs.\n"
"You are advised to remove this file:
rm /usr/local/include/zlib.h
"
endif()
```
### 3. vcpkg Diagnostic Command
Diagnose this issue when users run the `vcpkg` command on macOS, warning them of potential conflicting headers in `/usr/local/include`.
This requires to change the main vcpkg command logic to check for known conflicting headers and print warnings. I don't know if this is feasible or recommendable, but it could be a low-impact way to inform users.
### 4. vcpkg-wide macOS Fix (change all -isystem to -I)
Modify vcpkg's CMake integration to use `-I` instead of `-isystem` on macOS with Apple Clang.
This is probably a very bad idea as it loses the warning suppression benefits of `-isystem`.
## Test Environment Cleanup
```bash
# Remove test conflict file
sudo rm /usr/local/include/zlib.h
```
Contributor guide
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
Research direction
Start by reproducing the Apple Clang include-ordering command and the libpng installation with a conflicting /usr/local/include/zlib.h. Inspect the vcpkg CMake integration, the example libpng portfile.cmake workaround, and the main command logic mentioned in the issue. Done means an agreed macOS mitigation prevents the conflicting header from shadowing vcpkg's header, with coverage for the reported scenario.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- cmake, cpp, macos
- Domain
- build-system, devtools, operating-systems
- Issue type
- Bug
- Difficulty
- 4/5
- Estimated time
- 3-5 days
- Activity status
- Quiet
- Clarity
- Needs clarification
- Newbie friendliness
- 38/100