Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Can't build Pillow when using Xcode 12 (and its command line tools) #556

Closed
Cheaterman opened this issue Sep 30, 2020 · 59 comments · Fixed by #579
Closed

Can't build Pillow when using Xcode 12 (and its command line tools) #556

Cheaterman opened this issue Sep 30, 2020 · 59 comments · Fixed by #579

Comments

@Cheaterman
Copy link
Contributor

Cheaterman commented Sep 30, 2020

EDIT: Update 07-10-2020: As Xcode 12 seems to be the root cause, the title of the issue has been changed to better reflect this :-)

Hi, as the title suggests, Pillow seems to fail to build on a fresh OS X install.

The error is essentially "lipo can't open input file: libpillow.a (No such file or directory)", which is why Google pointed me to #527, but given #530 and #532 are closed, and @Zen-CODE asked, here I am on a fresh ticket - hopefully it'll help people 😄

Here are the build logs: https://gist.github.com/Cheaterman/6281d5d23923e88072220bc5f1786c1f

Thanks in advance!

@Zen-CODE
Copy link
Member

I think this line is the problem:

[DEBUG   ] Couldn't find library libwebpmux in ['/usr/local/Cellar/jpeg/9d/lib', '/usr/local/Cellar/libtiff/4.1.0/lib', '/Users/unity514/dev/chill-app/.buildozer/ios/platform/kivy-ios/build/pillow/x86_64/Pillow-6.1.0', '/usr/local/Cellar/freetype/2.10.2/lib', '/Users/unity514/dev/chill-app/.buildozer/ios/platform/kivy-ios/dist/lib', '/Applications/Xcode.app/Contents/Developer/Platforms/iPhoneSimulator.platform/Developer/SDKs/iPhoneSimulator.sdk/usr/lib', '/Users/unity514/dev/chill-app/.buildozer/ios/platform/kivy-ios/dist/hostpython3/lib', '/usr/local/lib', '/usr/lib']

So it seems like one of the dependencies is not building. Perhaps try again with a later version of pillow? You can change that in the recipes folder and try rebuilding.

@Cheaterman
Copy link
Contributor Author

Thanks @Zen-CODE, I'll give this a try and keep you in touch!

@Cheaterman
Copy link
Contributor Author

Unfortunately, it fails with exactly the same issue :-( including the "couldn't find library libwebpmux" part... I'll try to see if there's something I can install with brew to fix this issue?

@Cheaterman
Copy link
Contributor Author

Cheaterman commented Sep 30, 2020

AIUI the "biglink" thing is supposed to create the static library, and it's failing because it doesn't give arguments to ar, and it doesn't do that because it's looking for .so's and .so.o's in the same folder, when in fact they're not (build/temp.macosx-* vs build/lib.macosx-* - and it's not .so.o but just .o), so I changed the biglink tool as follows:

import os
import pathlib
import sys
import subprocess


def get_output_file(sofile):
    # dir/../../temp.*/src
    output_file_dir = next(pathlib.Path(sofile).parent.parent.parent.glob(
        'temp.*'
    )) / 'src'
    filename_radix = pathlib.Path(sofile).name.split('.', 1)[0]
    return output_file_dir / (filename_radix + '.o')


sofiles = []
for dir in sys.argv[2:]:
    for fn in os.listdir(dir):
        if fn.endswith(".so"):
            fn = os.path.join(dir, fn)
            output_file = get_output_file(fn)
            if output_file.exists() and os.path.exists(fn + ".libs"):
                sofiles.append(fn)

args = []  # The raw argument list.
for fn in sofiles:
    args.append(str(get_output_file(fn)))
    args.extend(open(fn + ".libs").read().split(" "))

unique_args = ' '.join(x for x in sorted(set(args)) if x.endswith('.o'))
print('Biglink create %s library' % sys.argv[1])
cmd = "ar -q %s %s" % (sys.argv[1], unique_args)
print('Binlinking: {}'.format(cmd))
subprocess.Popen(cmd, shell=True).communicate()

At least Pillow does seem to build now, but I'm hitting a (totally unrelated I think - probably has to do with Buildozer instead) other issue:

gcc -ObjC -g -o ios-deploy -framework Foundation -framework CoreFoundation -framework MobileDevice -F/System/Library/PrivateFrameworks ios-deploy.c
ld: framework not found MobileDevice

Thanks for your help, hope my little edit of biglink helps other people!

@Cheaterman
Copy link
Contributor Author

Cheaterman commented Oct 1, 2020

@Zen-CODE On the other hand, could you please try a fully-fresh build on your end? I'm expecting yours to fail just as badly as mine did, it seems very unlikely the filenames would be so different on either end. Possibly having to do with Cython version...? I'm using the very latest release, simply installed with pip install --user -U cython.

Also FWIW, regarding the "3.8" thing - I don't know about hostpython3 (which seems to be 3.8 regardless) but using a freshly brew-installed 3.7 on OSX instead of 3.8 makes no difference (as one would expect). So as you noted in the other issue, it's not a 3.8 thing - at least not on the OSX side of things (but perhaps changing hostpython3 to 3.7 could help - I honestly very much doubt it).

@Zen-CODE Can you also please provide the filesystem layout of your successful build in both cases? It's probably a good idea that I make biglink work in both situations instead of only mine, at least as a transitional thing? (The relevant bit of the filesystem as mentioned above is kivy_ios/build/pillow/build or something along those lines - here it contains two folders, temp.macosx.* (x86_64 etc) and lib.macosx.*, but maybe in your case it only contains one, that has both the final .so 's and the intermediate .so.o 's ?)

@Zen-CODE
Copy link
Member

Zen-CODE commented Oct 1, 2020

Okay, perhaps that's the misunderstanding. I'm building using py3.7 in the venv, but py3.8 as hostpython using the latest checkout. Can't test right now, but try using Py3.7 in you venv?

@Cheaterman
Copy link
Contributor Author

Yes, as I mentioned that's what I did (the "freshly brew-installed 3.7 on OSX" bit), and it doesn't seem to make a difference - the only thing that seems to help is editing the "biglink" script to refer to the correct paths. Or maybe I'm misunderstanding what you expect me to do? I can certainly give it another go :-)

@Zen-CODE
Copy link
Member

Zen-CODE commented Oct 5, 2020

Puzzling. Fresh checkout. Below uses 3.7.7 in the venv.

git clean -dxf
python3 -m venv venv
source venv/bin/activate
pip install -r requirements.txt
python3 toolchain.py build kivy python3 openssl pillow

And all builds fine.

[DEBUG   ] Finished processing dependencies for Pillow==6.1.0
[DEBUG   ] New State: pillow.build_all at 2020-10-05 12:20:09.148236
(venv) richard@Richards-MacBook-Pro kivy-ios % ls build/pillow 
arm64	x86_64

Then finaly.

(venv) richard@Richards-MacBook-Pro kivy-ios % ls build/pillow/x86_64/Pillow-6.1.0/build/lib.macosx-10.15-x86_64-3.8/PIL/
BdfFontFile.py				JpegPresets.py
BlpImagePlugin.py			McIdasImagePlugin.py
BmpImagePlugin.py			MicImagePlugin.py
BufrStubImagePlugin.py			MpegImagePlugin.py
ContainerIO.py				MpoImagePlugin.py
CurImagePlugin.py			MspImagePlugin.py
DcxImagePlugin.py			PSDraw.py
DdsImagePlugin.py			PaletteFile.py
EpsImagePlugin.py			PalmImagePlugin.py
ExifTags.py				PcdImagePlugin.py
FitsStubImagePlugin.py			PcfFontFile.py
FliImagePlugin.py			PcxImagePlugin.py
FontFile.py				PdfImagePlugin.py
FpxImagePlugin.py			PdfParser.py
FtexImagePlugin.py			PixarImagePlugin.py
GbrImagePlugin.py			PngImagePlugin.py
GdImageFile.py				PpmImagePlugin.py
GifImagePlugin.py			PsdImagePlugin.py
GimpGradientFile.py			PyAccess.py
GimpPaletteFile.py			SgiImagePlugin.py
GribStubImagePlugin.py			SpiderImagePlugin.py
Hdf5StubImagePlugin.py			SunImagePlugin.py
IcnsImagePlugin.py			TarIO.py
IcoImagePlugin.py			TgaImagePlugin.py
ImImagePlugin.py			TiffImagePlugin.py
Image.py				TiffTags.py
ImageChops.py				WalImageFile.py
ImageCms.py				WebPImagePlugin.py
ImageColor.py				WmfImagePlugin.py
ImageDraw.py				XVThumbImagePlugin.py
ImageDraw2.py				XbmImagePlugin.py
ImageEnhance.py				XpmImagePlugin.py
ImageFile.py				__init__.py
ImageFilter.py				__main__.py
ImageFont.py				_binary.py
ImageGrab.py				_imaging.cpython-38-darwin.so
ImageMath.py				_imaging.cpython-38-darwin.so.libs
ImageMode.py				_imagingft.cpython-38-darwin.so
ImageMorph.py				_imagingft.cpython-38-darwin.so.libs
ImageOps.py				_imagingmath.cpython-38-darwin.so
ImagePalette.py				_imagingmath.cpython-38-darwin.so.libs
ImagePath.py				_imagingmorph.cpython-38-darwin.so
ImageQt.py				_imagingmorph.cpython-38-darwin.so.libs
ImageSequence.py			_imagingtk.cpython-38-darwin.so
ImageShow.py				_imagingtk.cpython-38-darwin.so.libs
ImageStat.py				_tkinter_finder.py
ImageTk.py				_util.py
ImageTransform.py			_version.py
ImageWin.py				_webp.cpython-38-darwin.so
ImtImagePlugin.py			_webp.cpython-38-darwin.so.libs
IptcImagePlugin.py			_webp.cpython-38-darwin.so.o
Jpeg2KImagePlugin.py			features.py
JpegImagePlugin.py

@Zen-CODE
Copy link
Member

Zen-CODE commented Oct 5, 2020

You --user would indicate you are not using a venv?

@Cheaterman
Copy link
Contributor Author

Now that's puzzling indeed! That is correct, I'm not actually doing a venv, so I'll literally try to copypaste your approach now and I'll keep you in touch. I'm sure we'll get to the bottom of this, however weird it currently seems! Thanks again for your patience @Zen-CODE, greatly appreciated!

@Cheaterman
Copy link
Contributor Author

Cheaterman commented Oct 5, 2020

Ah! By reproducing your approach, I might have found a candidate issue! You seem to (rightfully!) pin Cython to 0.29.17 in requirements.txt, while I just pip installed the latest one (resulting in 0.29.21) - that would likely explain a change in build paths, right?

Before closing this, I'll finish the venv build, then try a bare-metal build with 0.29.17 (not that it's a good idea to do bare-metal but at least that'll prove Cython version was the issue). Thanks again!

EDIT: @Zen-CODE - would it be possible that you attempt a build using latest Cython on your end, to confirm that it's also causing issues there? I suppose eventually we'll need to get it to work, so my biglink edit above might still be relevant? As-is it's not useful though, we need to support both naming conventions apparently (Kivy build failed if using only the biglink above).

@Cheaterman
Copy link
Contributor Author

Cheaterman commented Oct 5, 2020

Some news! Unfortunately, it doesn't seem to be "only" a Cython version thing - I tried buildozer again in bare metal after downgrading it, but I still get the exact same issue (libpillow.a isn't archived because of biglink failing). Nonetheless, I clearly do not get it when using kivy-ios directly (at least from the venv, maybe I'll try in bare-metal as well), so I think most of this issue can be attributed to buildozer. Sorry for the waste of time!

@Cheaterman
Copy link
Contributor Author

Cheaterman commented Oct 5, 2020

... Never mind. I somehow didn't try pillow itself and I get the exact same issue in the venv. Logs here: https://gist.github.com/Cheaterman/95625d6d17ab12e579061a148b391ab9

Pip freeze:

(venv) MacBook-Pro-de-Unity514:dev unity514$ pip freeze
arrow==0.16.0
binaryornot==0.4.4
certifi==2020.6.20
chardet==3.0.4
click==7.1.2
cookiecutter==1.7.2
Cython==0.29.17
docopt==0.6.2
future==0.18.2
idna==2.10
Jinja2==2.11.2
jinja2-time==0.2.0
kivy-ios==1.1.2
MarkupSafe==1.1.1
openstep-parser==1.5.3
pbxproj==2.5.1
Pillow==7.2.0
poyo==0.5.0
python-dateutil==2.8.1
python-slugify==4.0.1
requests==2.24.0
sh==1.12.14
six==1.15.0
text-unidecode==1.3
urllib3==1.25.10

Filesystem state:

(venv) MacBook-Pro-de-Unity514:dev unity514$ ls build/pillow/x86_64/Pillow-6.1.0/build/lib.macosx-10.15-x86_64-3.8/PIL/
_imaging.cpython-38-darwin.so		_imagingft.cpython-38-darwin.so		_imagingmath.cpython-38-darwin.so	_imagingmorph.cpython-38-darwin.so	_imagingtk.cpython-38-darwin.so
_imaging.cpython-38-darwin.so.libs	_imagingft.cpython-38-darwin.so.libs	_imagingmath.cpython-38-darwin.so.libs	_imagingmorph.cpython-38-darwin.so.libs	_imagingtk.cpython-38-darwin.so.libs

@Cheaterman
Copy link
Contributor Author

Can't help but notice the only actual .so.o you have in your folder is for webp, and mine does not build webp as you pointed out earlier ; so in the end it's very much like what you said in the first place? Although it seems weird that the other dynamic libs such as _imaging.*.so wouldn't be included in the final libpillow.a, no?

In any case, getting the webp thing to work on my machine should indeed help, but that might be highlighting a bigger issue in general with PIL and kivy-ios AIUI?

@Zen-CODE
Copy link
Member

Zen-CODE commented Oct 5, 2020

It seems you are trying too much at once here. Go back to basics. Forget buildozer for now. Do exactly the steps I posted above (and the ones on the kivy-ios site). Does that not build pillow successfully?

@Cheaterman
Copy link
Contributor Author

Cheaterman commented Oct 5, 2020

Yeah, I just tried from scratch, and I can confirm it doesn't build pillow successfully - same output :-(

The full build log is half a million lines, Github gists is having a bit of an issue processing it, hehe. And pastebin freezes when I paste it. >__<

@Zen-CODE
Copy link
Member

Zen-CODE commented Oct 5, 2020

Then please paste:

  1. Your exact XCode version number i.e. output of /usr/bin/xcodebuild -version
  2. The output of which python from your venv.
  3. The output of python -V from your venv
  4. The output of pip freeze from your venv
  5. The exact commands you are using to install kivy-ios.

Thanks

@Cheaterman
Copy link
Contributor Author

So, here is all of this info:

(venv) MacBook-Pro-de-Unity514:dev unity514$ xcodebuild -version
Xcode 12.0.1
Build version 12A7300
(venv) MacBook-Pro-de-Unity514:dev unity514$ which xcodebuild
/usr/bin/xcodebuild
(venv) MacBook-Pro-de-Unity514:dev unity514$ which python
/Users/unity514/dev/venv/bin/python
(venv) MacBook-Pro-de-Unity514:dev unity514$ python -V
Python 3.7.9
(venv) MacBook-Pro-de-Unity514:dev unity514$ pip freeze
arrow==0.16.0
binaryornot==0.4.4
certifi==2020.6.20
chardet==3.0.4
click==7.1.2
cookiecutter==1.7.2
docopt==0.6.2
idna==2.10
Jinja2==2.11.2
jinja2-time==0.2.0
kivy-ios==1.1.2
MarkupSafe==1.1.1
openstep-parser==1.5.3
pbxproj==2.11.0
Pillow==7.2.0
poyo==0.5.0
python-dateutil==2.8.1
python-slugify==4.0.1
requests==2.24.0
sh==1.14.0
six==1.15.0
text-unidecode==1.3
urllib3==1.25.10

Full build log from scratch in venv: https://gist.github.com/Cheaterman/da46650d6239be223ade0ddc9f325832

As you can see there, I merely did:

python -m venv venv
. venv/bin/activate
pip install kivy-ios
venv/bin/toolchain build pillow

@Cheaterman
Copy link
Contributor Author

For completion:

(venv) MacBook-Pro-de-Unity514:dev unity514$ which pip
/Users/unity514/dev/venv/bin/pip

Thanks again for your help @Zen-CODE, really appreciated! :-)

@Zen-CODE
Copy link
Member

Zen-CODE commented Oct 5, 2020

Have you tried building python, kivy and openssl first?

venv/bin/toolchain build kivy python3 openssl pillow

@Cheaterman
Copy link
Contributor Author

Cheaterman commented Oct 5, 2020

Alrighty, let me give it a try - cleaning pillow first of course I suppose!

EDIT: I might also need to install Cython in the venv for Kivy, so I'm doing that as well. I'll paste the full build log when it's complete. :-)

EDIT2: It's using Cython from the system instead, I suppose that's fine too. I'm letting it build. :-)

@Cheaterman
Copy link
Contributor Author

https://gist.github.com/Cheaterman/2f05e256a07219e0b4a89087787b113e Here is the build log (still unsuccessful :-( )

@Cheaterman
Copy link
Contributor Author

@Zen-CODE
Copy link
Member

Zen-CODE commented Oct 5, 2020

Try venv/bin/toolchain build pyobjus then try again?

@Cheaterman
Copy link
Contributor Author

I think it won't change the result, given the output:

(venv) MacBook-Pro-de-Unity514:dev unity514$ venv/bin/toolchain build pyobjus
[INFO    ] Building with 8 processes, where supported
[INFO    ] Want to build ['pyobjus']
[INFO    ] Loaded recipe pyobjus (depends of ['python'], optional are [])
[INFO    ] Loaded recipe python (depends of ['python3'], optional are [])
[INFO    ] Loaded recipe python3 (depends of ['hostpython3', 'libffi', 'openssl'], optional are [])
[INFO    ] Loaded recipe hostpython3 (depends of ['hostlibffi', 'hostopenssl'], optional are [])
[INFO    ] Loaded recipe libffi (depends of [], optional are [])
[INFO    ] Loaded recipe openssl (depends of [], optional are [])
[INFO    ] Loaded recipe hostlibffi (depends of [], optional are [])
[INFO    ] Loaded recipe hostopenssl (depends of [], optional are [])
[INFO    ] Build order is ['hostlibffi', 'hostopenssl', 'libffi', 'openssl', 'hostpython3', 'python3', 'python', 'pyobjus']
[INFO    ] Recipe order is ['hostlibffi', 'hostopenssl', 'libffi', 'openssl', 'hostpython3', 'python3', 'pyobjus']
[INFO    ] Include dir added: {arch.arch}/hostlibffi
[INFO    ] Include dir added: {arch.arch}/ffi
[INFO    ] Include dir added: {arch.arch}/openssl
[INFO    ] Global: hostpython located at /Users/unity514/dev/dist/hostpython3/bin/python
[INFO    ] Global: hostpgen located at /Users/unity514/dev/dist/hostpython3/bin/pgen
[DEBUG   ] Cached result: Download hostlibffi. Ignoring
[DEBUG   ] Cached result: Extract hostlibffi. Ignoring
[INFO    ] Build hostlibffi for x86_64 (filtered)
[DEBUG   ] Cached result: Build hostlibffi. Ignoring
[DEBUG   ] New State: hostlibffi.build_all at 2020-10-05 20:00:42.816777
[DEBUG   ] Cached result: Download hostopenssl. Ignoring
[DEBUG   ] Cached result: Extract hostopenssl. Ignoring
[DEBUG   ] Cached result: Build_all hostopenssl. Ignoring
[DEBUG   ] Cached result: Download libffi. Ignoring
[DEBUG   ] Cached result: Extract libffi. Ignoring
[DEBUG   ] Cached result: Build_all libffi. Ignoring
[DEBUG   ] Cached result: Download openssl. Ignoring
[DEBUG   ] Cached result: Extract openssl. Ignoring
[DEBUG   ] Cached result: Build_all openssl. Ignoring
[DEBUG   ] Cached result: Download hostpython3. Ignoring
[DEBUG   ] Cached result: Extract hostpython3. Ignoring
[DEBUG   ] Cached result: Build_all hostpython3. Ignoring
[DEBUG   ] Cached result: Download python3. Ignoring
[DEBUG   ] Cached result: Extract python3. Ignoring
[DEBUG   ] Cached result: Build_all python3. Ignoring
[DEBUG   ] Cached result: Download pyobjus. Ignoring
[DEBUG   ] Cached result: Extract pyobjus. Ignoring
[DEBUG   ] Cached result: Build_all pyobjus. Ignoring

@Cheaterman
Copy link
Contributor Author

I still rebuilt pillow and can confirm it doesn't change the result :-(

@Zen-CODE
Copy link
Member

Zen-CODE commented Oct 5, 2020

I see this in your logs:
FutureWarning: Cython directive 'language_level' not set, using 2 for now (Py2)

And I notice cython does not appear in your pip freeze. Try installing that and try again? Las

pip install Cython==0.29.17

If still not, please wipe, clone the repo and enter these instructions exactly.

git clone https://www.github.com/kivy/kivy-ios
cd kivy-ios
python3 -m venv venv
source venv/bin/activate
pip install -r requirements.txt
python3 toolchain.py build kivy python3 openssl pillow

@Cheaterman
Copy link
Contributor Author

Thanks again for your help @Zen-CODE, really appreciated - I'll do exactly as you said and post back the results!

@Cheaterman
Copy link
Contributor Author

So first things first, installing Cython inside the venv didn't help. Lemme clone the repo and apply your instructions to the letter, I'll keep you in touch!

@Zen-CODE
Copy link
Member

Zen-CODE commented Oct 6, 2020

Well, the argument that it's inevitable we will have to upgrade is a strong one :-). So it makes most sense if I upgrade. Just not sure when I will be able to do this. Probably not until next week to be honest....

@Cheaterman
Copy link
Contributor Author

I think I did a magic in the meantime, PR might be coming soon if it happens to work on all recipes I'm trying (python3 kivy openssl pillow as earlier)!

@Cheaterman
Copy link
Contributor Author

Cheaterman commented Oct 6, 2020

It does build!!! I'll be doing a PR, but in the meantime, if you guys could review this:

#!/usr/bin/env python3

import fnmatch
import pathlib
import subprocess
import sys


def list_library_names(libs_dirs):
    lib_names = set()

    for libs_dir in libs_dirs:
        libs_path = pathlib.Path(libs_dir)

        for lib_file in libs_path.glob('*.so.libs'):
            # Example: pyobjus.cpython-38-darwin.so.libs
            lib_name, target, so, libs = lib_file.name.rsplit('.', 4)
            lib_names.add(lib_name)

    return lib_names


def get_current_build_root(libs_dir):
    current_path = pathlib.Path(libs_dir)

    while(
        not fnmatch.fnmatch(current_path.name, 'lib.*')
        and current_path.name != ''  # Emergency exit
    ):
        current_path = current_path.parent

    build_dir = current_path.parent
    assert build_dir.name == 'build'  # Sanity check
    return build_dir


def main():
    target_library, lib_dirs = sys.argv[1], sys.argv[2:]
    print(
        f'Biglink will create library "{target_library}" '
        'from dirs:\n{}'.format("\n".join(lib_dirs))
    )

    lib_names = list_library_names(lib_dirs)
    build_root = get_current_build_root(lib_dirs[0])
    temp_dir = next(build_root.glob('temp.*'))
    target_object_files = set()

    for object_file in temp_dir.rglob('*.o'):
        if object_file.stem in lib_names:
            target_object_files.add(str(object_file))
            lib_names.remove(object_file.stem)

            if not lib_names:
                # We found everything we need
                break

    # ... or maybe we didn't
    assert not lib_names

    command = ['ar', '-q', target_library, *target_object_files]
    print(f'Biglink: running "{" ".join(command)}"')
    subprocess.run(command)


if __name__ == '__main__':
    main()

In particular, if you could check that everything still builds (and works!) properly for you afterwards @Zen-CODE ? I myself want to actually build my app against this environment and test it on a live device before claiming victory, hehe.

Thanks a lot in advance, and thanks again for all your help @Zen-CODE !

@Zen-CODE
Copy link
Member

Zen-CODE commented Oct 6, 2020

@Cheaterman Nice work and well done! +1 Look forward to testing it :-)

@Cheaterman
Copy link
Contributor Author

Cheaterman commented Oct 6, 2020

Okay, so some more news: I created the xcode project and tried to run it, got an error about libpillow.a being built for macOS, and looking up the error brought me to this: https://stackoverflow.com/questions/63607158/xcode-12-building-for-ios-simulator-but-linking-in-object-file-built-for-ios

First, that would seem to generally confirm Xcode 12 is indeed breaking builds for people (not just us!), so that's probably indeed why I am having issues in the first place. Secondly, I need to fix something in the recipe to make it properly build for iOS ; I'm not quite sure what yet, but I'll investigate the various env vars that are mentioned on the SO post and see if something clicks. :-)

EDIT: Also FWIW, libpillow.a seems to be the only one with this issue, so there's gotta be something different in the recipe that I can pin down. I'll keep you guys in touch :-)

@tshirtman
Copy link
Member

as a temporary mesure, seems this should still be possible? https://stackoverflow.com/a/14756127/1209937 (you could check if the older version you want is still available before deleting Xcode from the applications).

@Cheaterman
Copy link
Contributor Author

Thanks a bunch for that Gab'! That's actually a good workaround to keep under the elbow in case crap starts hitting the fan for some other users :-) fortunately (and you know how rare it is in real scenarios...) I can afford to "do things right" for once instead of having to "do things quick", so I'll keep investigating the linking issues - I'm fairly sure we're very close to a solution, possibly just a few env vars (or Xcode GUI tweaks) away! I'll spend more time investigating the subject this afternoon and evening, I'll keep you guys informed :-) as I said I expect it to be no more than just a little recipe tweak away from completion!

@Cheaterman Cheaterman changed the title Can't build Pillow on a fresh OSX Catalina install Can't build Pillow when using Xcode 12 (and its command line tools) Oct 7, 2020
@Cheaterman
Copy link
Contributor Author

Cheaterman commented Oct 26, 2020

So. After a disastrous waste of time trying to fix the recipe, I finally downgraded as per Gab's suggestion, and interestingly got the same "libpillow.a was build for macOS" error message. This led me to think Xcode tools version might not be the only issue, so I stashed everything and reverted back to kivy-ios master... Which sorta works (I'm now hitting this thing which seems easy enough to fix).

There's not that many differences between master and my branch either, mostly the biglink rewrite, also I removed debugging symbols from the pillow recipe (-g argument to setup.py). In the biglink rewrite itself, there doesn't seem to be that much different either - ar is called with shell=True, I tried that, it doesn't help on its own. I'll further inspect the difference between the two ar calls (pre- and post- biglink rewrite) to try and understand what's going on here.

FWIW, I'm doing rm -rf build/ dist/ myapp-ios/ between attempts, I suppose that's more than sufficient to clean out everything? (Note from later: apparently it's not?)

EDIT: From all the above, and if I manage to make my biglink rewrite work, I suspect it'll be fine for Xcode 12 as well? Given I'm probably going to spend the day on this again, might as well make it right :-)

EDIT2: Apparently not - the most likely issue with my version of biglink is that it doesn't use the .so.o's (which was the root of this issue in the first place), so I changed it accordingly, I'll keep you guys in touch. Unfortunately that probably also means it'll break again on Xcode 12... But I'll try and see.

@Cheaterman
Copy link
Contributor Author

Cheaterman commented Oct 26, 2020

So. For now, my new biglink essentially does the same as the old one, but that seems to work for Xcode 11. I got stuck on another pretty big issue: kivy-garden/zbarcam#7 (to be precise, the fact that pyzbar uses cdll.find_library and ctypes.util.LoadLibrary, these functions obviously won't work on iOS) - so for now I'll give another go to Xcode 12, if I can at least get stuck at the exact same point, means I can PR my changes.

Some people seem to have switched to native means for QR code decoding, which might indeed be ideal ; the thing is, I want to avoid platform-specific code (especially written/maintained by myself) given this is a cross-platform app I'm distributing (Android/iOS).

I'm going to reinstall Xcode 12 and its command line tools and retry, I'll keep you guys in touch.

EDIT: The current state of biglink:

#!/usr/bin/env python3

import fnmatch
import pathlib
import subprocess
import sys


def lib_name(path):
    return path.name.split('.', 1)[0]


def list_library_names(libs_dirs):
    lib_names = set()

    for libs_dir in libs_dirs:
        libs_path = pathlib.Path(libs_dir)

        for lib_file in libs_path.glob('*.so.libs'):
            # Example: pyobjus.cpython-38-darwin.so.libs
            lib_names.add(lib_name(lib_file))

    return lib_names


def get_current_build_root(libs_dir):
    current_path = pathlib.Path(libs_dir)

    while(
        not fnmatch.fnmatch(current_path.name, 'lib.*')
        and current_path.name != ''  # Emergency exit
    ):
        current_path = current_path.parent

    build_dir = current_path.parent
    assert build_dir.name == 'build'  # Sanity check
    return build_dir


def main():
    target_library, lib_dirs = sys.argv[1], sys.argv[2:]
    print(
        f'Biglink will create library "{target_library}" '
        'from dirs:\n{}'.format("\n".join(lib_dirs))
    )

    lib_names = list_library_names(lib_dirs)
    build_root = get_current_build_root(lib_dirs[0])
    lib_dir = next(build_root.glob('lib.*'))
    target_object_files = set()

    for object_file in lib_dir.rglob('*.so.o'):
        if not object_file.with_suffix('.libs').exists():
            continue

        object_lib = lib_name(object_file)

        if object_lib in lib_names:
            target_object_files.add(str(object_file))
            lib_names.remove(object_lib)

            if not lib_names:
                # We found everything we need
                break

    # ... or maybe we didn't
    assert not lib_names

    command = ['ar', '-q', target_library, *target_object_files]
    print(f'Biglink: running "{" ".join(command)}"')
    subprocess.run(command)


if __name__ == '__main__':
    main()

@Cheaterman
Copy link
Contributor Author

Cheaterman commented Oct 26, 2020

Okay, so I installed Xcode 12 and tried to run my project in the simulator as-is, and I'm getting this:
ld: in /Users/unity514/dev/kivy-ios/dist/lib/libsdl2_image.a(IMG_bmp.o), building for iOS Simulator, but linking in object file built for iOS, file '/Users/unity514/dev/kivy-ios/dist/lib/libsdl2_image.a' for architecture arm64
As I understand it, it's normal that we're bundling object files for both architectures, right? Given we use the same files for the simulator and actual devices? We simply need to tell Xcode to just let us do it? That's probably where the previous StackOverflow links might come in handy...

EDIT: Setting "Build active architecture only" to "yes" in "Build Settings" of my target seems to fix this.

@Zen-CODE
Copy link
Member

So, there is a lot to process here :-) Thanks for all the effort and feedback. So, you seemed to have got it working? Are there any changes we need to make?

@Cheaterman
Copy link
Contributor Author

So, I'm not quite clear just yet about everything - I at least believe we should change the template to have the "Build active architecture only" setting set to "yes" in the xcode project by default, and it's possible (I'll be doing more tests) that my whole biglink rewrite is mostly useless (might still PR it if you think it looks good). It has become a bit more urgent for me to get things working quickly, so my current situation is that my dist was built with Xcode 11 tools but I'm making the final package with Xcode 12 - I'll need to rebuild my dist from scratch with Xcode 12 to make sure it actually works :-)
In the meantime it might be a good idea to get some extra feedback from other people on Xcode 12, maybe you can try to upgrade and rebuild a dist? It won't be too long until I can do more tests but there are some other issues I'm working on hehe.

@Cheaterman
Copy link
Contributor Author

Cheaterman commented Oct 28, 2020

More investigation, more knowledge... The liblink tool fails silently, that's why the .so.o's don't get generated. As I understand it, the "ld: building for iOS Simulator, but linking in object file built for macOS" thing used to be a warning and is now an error. I believe we need to use a "-platform" argument to ld or something like that... But I'm not quite sure. So as it is, Xcode 12 fails to build a dist from scratch :-/

EDIT: A small recommendation regarding liblink:

diff --git a/kivy_ios/tools/liblink b/kivy_ios/tools/liblink
index 05d59d0..a21a427 100755
--- a/kivy_ios/tools/liblink
+++ b/kivy_ios/tools/liblink
@@ -1,4 +1,4 @@
-#!/usr/bin/env python
+#!/usr/bin/env python3
 
 import sys
 import subprocess
@@ -85,4 +85,5 @@ else:
     min_version_flag = '-ios_simulator_version_min'
 call = [ld, '-r', '-o', output + '.o', min_version_flag, '8.0', '-arch', arch] + objects
 print("Linking: {}".format(" ".join(call)))
-subprocess.call(call)
+if subprocess.call(call):  # Non-zero exit code
+    raise RuntimeError(f'An error occured while biglinking {output} into {output}.o')

@Zen-CODE
Copy link
Member

Pity. Unfortunately, I really cannot help here are this time. The solution for the moment is just to use a compatible XCode. Good luck :-)

@Cheaterman
Copy link
Contributor Author

I agree with you - I have mostly given up at this point. At the very least I might PR these few changes to make the failure more obvious and ease future issue triage, but I think we'll have to wait until we get a clearer idea of how to fix our command invocations for newer toolchains, and ask people to use Xcode 11 for now.

Let's leave this issue open, people might come up with ideas :-)

@misl6
Copy link
Member

misl6 commented Dec 8, 2020

After some research it could be linked on how Xcode 12.x handles the available platforms. Let's pin that, I'm keeping it on my list after some cleanup of the warnings and errors Xcode 12 is throwing.

@Cheaterman
Copy link
Contributor Author

Cheaterman commented Dec 8, 2020 via email

@misl6
Copy link
Member

misl6 commented Dec 26, 2020

I just did a PR (#579) that should fix the issue.

After a long research I found out that a simple +was missing. 😡 😡 😡 .

I don't have an use case, so I can't test it on runtime. Can someone give it a try?

P.S: We should be able to update Pillow to 7.2.0 but let's consider this one later.

@Zen-CODE
Copy link
Member

@misl6 I'm afraid I'm leaving and won't be able to help until a weeks time. Will retry as soon as I can.

@Cheaterman
Copy link
Contributor Author

I'm not sure this is entirely fixed, as I'm hitting #540 (comment) - which seems to be Pillow-related? 🙂 thanks in advance!

@n-march
Copy link

n-march commented Feb 3, 2021

Probably not a recommended course of action but wanted to share what worked for me. I was trying to toolchain pip3 install kivymd and realised that the build was failing because Pillow wasn't building.

After a lot of research for over a week and trying to make the Pillow build work for a few days I simply copied and pasted the Pillow folders ("PIL" and "Pillow-8.1.0.dist-info")

from:
/opt/anaconda3/envs/EVMap/lib/python3.6/site-packages/

to:
[MyAppname/dist/root/python3/lib/python3.8/site-packages

This will probably come to bite me back in the *** at some point in the future but the build worked and doesn't seem to be creating any issues...

While not directly relevant, I'll comment #585, as it seems to be the only related open comment on Pillow not building.

macOS Big Sur 11.1
Xcode 12.3
Python 3.6

@Zen-CODE
Copy link
Member

Zen-CODE commented Feb 4, 2021

@n-march Thanks for that. But I think anyone experiencing issues should create a new tickets with fresh logs. This conversation is getting too long to make sense of. And I'm suffering from the classic problem of "it works for me"...:-)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging a pull request may close this issue.

5 participants