Repository: python-pillow/Pillow

Issue:
Building with Homebrew llvm/clang fails with error: 'TARGET_OS_IPHONE' is not defined
<!--
Thank you for reporting an issue.

Follow these guidelines to ensure your issue is handled properly.

If you have a ...

1.  General question: consider asking the question on Stack Overflow
    with the python-imaging-library tag:

    * https://stackoverflow.com/questions/tagged/python-imaging-library

    Do not ask a question in both places.

    If you think you have found a bug or have an unexplained exception
    then file a bug report here.

2.  Bug report: include a self-contained, copy-pastable example that
    generates the issue if possible. Be concise with code posted.
    Guidelines on how to provide a good bug report:

    * https://stackoverflow.com/help/mcve

    Bug reports which follow these guidelines are easier to diagnose,
    and are often handled much more quickly.

3.  Feature request: do a quick search of existing issues
    to make sure this has not been asked before.

We know asking good questions takes effort, and we appreciate your time.
Thank you.
-->

### What did you do?

On latest Homebrew on macOS 11.4 (x86_64) installed llvm package, and tried to build Pillow with
clang/clang++ it provides.

### What did you expect to happen?

that it just works (many Python packages build just fine in such a setup)


### What actually happened?

`error: 'TARGET_OS_IPHONE' is not defined` quite early in the build, compiling `_imaging.c`
In more detail, 
```
clang -Wno-unused-result -Wsign-compare -Wunreachable-code -fno-common -dynamic -DNDEBUG -g -fwrapv -O3 -Wall -arch x86_64 -g -DHAVE_LIBJPEG -DHAVE_OPENJPEG -DHAVE_LIBZ -DHAVE_LIBTIFF -DHAVE_XCB -DPILLOW_
VERSION="8.4.0.dev0" -I/usr/local/Cellar/openjpeg/2.4.0/include/openjpeg-2.4 -I/usr/local/Cellar/jpeg/9d/include -I/usr/local/Cellar/libtiff/4.3.0/include -I/Users/dima/software/Pillow -I/usr/local/Cellar
/freetype/2.10.4/include/freetype2 -I/usr/local/Cellar/fribidi/1.0.10/include/fribidi -I/usr/local/Cellar/little-cms2/2.12/include -I/usr/local/Cellar/ntl/11.5.1/include -I/usr/local/Cellar/readline/8.1/i
nclude -I/usr/local/include -I/Library/Frameworks/Python.framework/Versions/3.9/include -I/usr/local/Cellar/freetype/2.10.4/include -I/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/D
eveloper/SDKs/MacOSX.sdk/usr/include -I/Library/Frameworks/Python.framework/Versions/3.9/include/python3.9 -c src/_imaging.c -o build/temp.macosx-10.9-x86_64-3.9/src/_imaging.o
In file included from src/_imagingft.c:22:
In file included from /Library/Frameworks/Python.framework/Versions/3.9/include/python3.9/Python.h:25:
In file included from /Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX.sdk/usr/include/stdio.h:64:
/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX.sdk/usr/include/_stdio.h:93:16: warning: pointer is missing a nullability type specifier (_Nonnull, _Nullable, or
 _Null_unspecified) [-Wnullability-completeness]
        unsigned char   *_base;
                        ^
... [many similar warning]

/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX.sdk/usr/include/_stdio.h:144:18: warning: pointer is missing a nullability type specifier (_Nonnull, _Nullable, o
r _Null_unspecified) [-Wnullability-completeness]
        struct __sFILEX *_extra; /* additions to FILE to not break ABI */
In file included from src/_webp.c:2:
In file included from /Library/Frameworks/Python.framework/Versions/3.9/include/python3.9/Python.h:25:
In file included from /Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX.sdk/usr/include/stdio.h:64:
/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX.sdk/usr/include/_stdio.hIn file included from src/_imagingft.c:22:
In file included from /Library/Frameworks/Python.framework/Versions/3.9/include/python3.9/Python.h:25:
/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX.sdk/usr/include/stdio.h:220::5: error: 'TARGET_OS_IPHONE' is not defined, evaluates to 0 [-Werror,-Wundef-prefix=TARGET_OS_]
                        ^
93:16: warning: #if TARGET_OS_IPHONE
    ^

... [more similar warnings and errorrs]
... 
```

### What are your OS, Python and Pillow versions?

* OS: macOS 11.4
* Python: python3: 3.9.6 , python2 2.7.16
* Pillow: current master 426b730d3b0810fca59d4e0bcbc670916b890398, and also with 8.1.2

<!--
Please include **code** that reproduces the issue and whenever possible, an **image** that demonstrates the issue. Please upload images to GitHub, not to third-party file hosting sites. If necessary, add the image to a zip or tar archive.

The best reproductions are self-contained scripts with minimal dependencies. If you are using a framework such as Plone, Django, or Buildout, try to replicate the issue just using Pillow.
-->

```bash
brew install llvm
export PATH=/usr/local/opt/llvm/bin:$PATH
CC=clang CXX=clang++ make install
```



Discussion:
The way I read that log, the problem comes from `_imagingft.c`, not `_imaging.c`.
https://github.com/python-pillow/Pillow/blob/426b730d3b0810fca59d4e0bcbc670916b890398/src/_imagingft.c#L22

The problem is not caused by our code directly, rather it is stdio.h being called from Python.h.

Could we get a full copy of the log? What version of Xcode are you using?
indeed, it's `_imagingft.c`, sorry.
```
% xcodebuild -version
Xcode 12.4
Build version 12D4e
```

Apparently pillow is too aggressive in appending all sorts of include directories for the compiler to search, and manages to break `stdio.h` inclusion in this case:
```
% clang -v
Homebrew clang version 12.0.1
Target: x86_64-apple-darwin20.5.0
Thread model: posix
InstalledDir: /usr/local/opt/llvm/bin
```

macOS defines TARGET_OS_IPHONE in `TargetConditionals.h` which is normally included 1st thing (no need to explicitly doing it).


Please see the full log at  https://users.ox.ac.uk/~coml0531/tmp/pillow-8.1.2.log
If you open your setup.py, and remove the code added at https://github.com/python-pillow/Pillow/pull/4974/files, does that fix the error?
this leads to a problem finding zlib



On Tue, 20 Jul 2021, 13:59 Andrew Murray, ***@***.***> wrote:

> If you open your setup.py, and remove the code added at
> https://github.com/python-pillow/Pillow/pull/4974/files, does that fix
> the error?
>
> —
> You are receiving this because you authored the thread.
> Reply to this email directly, view it on GitHub
> <https://github.com/python-pillow/Pillow/issues/5622#issuecomment-883371704>,
> or unsubscribe
> <https://github.com/notifications/unsubscribe-auth/AAJXYHAOYNTEUGPODI3YWILTYVXJTANCNFSM5AT6U6KA>
> .
>

So the goal here is to detect zlib.h, but not stdio.h.

Ok, so what if we avoid `/usr/` in favour of `System/Library/Frameworks/Kernel.framework/Versions/A/Headers/libkern`. Does https://github.com/radarhere/Pillow/tree/zlib / https://github.com/radarhere/Pillow/commit/d5146861459bd1f1133daa99b66007f141cb0eb2 work for you?
With this patch as is, zlib library cannot be found. If I leave the line 
```python
_add_directory(library_dirs, os.path.join(sdk_path, "usr", "lib"))
```
in, then I get basically the same errors as before.
hmm, no, wait, it works (at least `CC=clang make inplace` completes).

OK, indeed, your patch works, unamended (`CC=clang make install` builds and passes tests).

What's the essential difference between these two `include` locations? It's quite weird... 
`xcrun --show-sdk-path` is `/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX.sdk` (on my machine).

Your problem is happening because stdio.h, from
`/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX.sdk/usr/include/stdio.h`
is being included.

But, as we've found, if we ignore that directory, then we're not including zlib.h from
`/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX.sdk/usr/include/zlib.h`

So I wondered if zlib.h was anywhere else inside `/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX.sdk`.

```
$ pwd
/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX.sdk
$ find . -iname zlib.h
./usr/include/zlib.h
./System/Library/Frameworks/Kernel.framework/Versions/A/Headers/libkern/zlib.h
$ ls ./System/Library/Frameworks/Kernel.framework/Versions/A/Headers/libkern/
Block.h		OSByteOrder.h	OSMalloc.h	_OSByteOrder.h	copyio.h	i386		machine		version.h
OSAtomic.h	OSDebug.h	OSReturn.h	arm		crc.h		libkern.h	sysctl.h	zconf.h
OSBase.h	OSKextLib.h	OSTypes.h	c++		crypto		locks.h		tree.h		zlib.h
```
So at that location, we have zlib.h, but no stdio.h
By the way, `libkern/zlib.h` corresponds to an older version of zlib. (1.2.3), while the other, "bad" one, corresponds to 1.2.11.


Resolving patch:
diff --git a/setup.py b/setup.py
--- a/setup.py
+++ b/setup.py
@@ -533,14 +533,16 @@ def build_extensions(self):
                 _add_directory(include_dirs, "/usr/X11/include")
 
             # SDK install path
-            try:
-                sdk_path = (
-                    subprocess.check_output(["xcrun", "--show-sdk-path"])
-                    .strip()
-                    .decode("latin1")
-                )
-            except Exception:
-                sdk_path = None
+            sdk_path = "/Library/Developer/CommandLineTools/SDKs/MacOSX.sdk"
+            if not os.path.exists(sdk_path):
+                try:
+                    sdk_path = (
+                        subprocess.check_output(["xcrun", "--show-sdk-path"])
+                        .strip()
+                        .decode("latin1")
+                    )
+                except Exception:
+                    sdk_path = None
             if sdk_path:
                 _add_directory(library_dirs, os.path.join(sdk_path, "usr", "lib"))
                 _add_directory(include_dirs, os.path.join(sdk_path, "usr", "include"))


Test patch: