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

WIP: Setup CI #79

Merged
merged 21 commits into from Apr 23, 2018
Merged

WIP: Setup CI #79

merged 21 commits into from Apr 23, 2018

Conversation

madig
Copy link
Collaborator

@madig madig commented Mar 2, 2018

We want a bundled shared FreeType library with a pinned version. If none comes bundled with the package, look for the system-wide one.

I copied and adapted what's done in ttfautohint-py, more testing needs to be done on macOS and Windows. Currently, no harfbuzz is built-in, not sure how to handle it yet (circular dependency freetype <-> harfbuzz).

Once the wheel build stuff works everywhere, I can experiment with Travis and Appveyor.

Copy link
Collaborator

@anthrotype anthrotype left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

thanks for working on this!

freetype/raw.py Outdated
filename = os.path.join(os.path.realpath('.'), 'freetype.dll')
else:
filename = 'libfreetype.so.6'
filename = pkg_resources.resource_filename('freetype', library_name)
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

using pkg_resources adds a runtime dependency on setuptools -- which nowadays is preinstalled on most python distributions alongside pip, but technically is not part of the python standard library.
The old-school approach to get a resource filename relative to __file__ works fine, unless you want to get a filename of a data file from a inside a zipped python package (like an .egg). But since we are including a precompiled native library, we have to set zip=False in setup.py in any case, otherwise we can't load it. So using pkg_resources has no concrete advantage IMO over os.path.dirname(__file__, library_name)

@anthrotype
Copy link
Collaborator

anthrotype commented Mar 2, 2018

no harfbuzz is built-in, not sure how to handle it yet (circular dependency freetype <-> harfbuzz)

I guess you'll have to build freetype --without-harfbuzz, then build harfbuzz --without-freetype, and finally freetype --with-harfbuzz

@anthrotype
Copy link
Collaborator

correction: of course, I meant harfbuzz --with-freetype

@anthrotype
Copy link
Collaborator

then we also need to figure out a way to make this optional, as there are some users that would like to simply pip install . or python setup.py install without building the embedded library, but using the system installed one (the current default behavior).
One way could be to add a command-line option or read from an environment variable that tells the setup.py to not add any ext_modules thus making the package "pure" python.

@anthrotype
Copy link
Collaborator

another thing with this setup borrowed from ttfautohint-py, is that the source distribution as generated with python setupt.py sdist will not include the freetype2 source. So, for example, running tox won't work, because tox by default creates the sdist, then installs it into the virtual environment, before running the tests inside it (ok, one can also do tox --develop or set usedevelop=True in tox.ini).

In any case, building the embedded library currently requires access to the freetype2 git submodule (thus one has to git clone --recursive ... or do git submodule update --init afterwards). And this submodule is not included in the python package sdist. I don't think it would be a good idea trying to add all the freetype2 sources from the git submodule to the python sdist package, because freetype's own build system probably detects whether it's running from a git repository or a released tarball.

One option instead of using git submodules would be to have the setup.py itself download the freetype2 released tarball from the official website, and do the build from there.
Using the released tarballs also has the advantage that you won't need to do ./autogen.sh but can do ./configure directly, so you don't need all the autotools but just make.

Actually, the only reason I used git submodules for ttfautohint-py was that at the time I wrote it, the stable ttfautohint release didn't have an option to build a shared library. If I were to redo it now, I would rather use the stable releases instead of the git repositories.

@anthrotype
Copy link
Collaborator

other than that, the current setup is already great, because it allows to build a wheel package that embeds a native library, works with both py2 and py3 (because it doesn't link with cpython like a regular extension module but is loaded via ctypes). And if you run this on Travis inside a manylinux1 docker container (like multibuild does), then you can have one universal wheel that works on almost every Linux distros (well, one for 64-bit, and another for 32 if you care about that), another one for Mac (a "fat" binary that works for both 64 and 32 architectures), and two others for Windows (32 and 64 bit) using Appveyor.

@madig
Copy link
Collaborator Author

madig commented Mar 2, 2018

Hm, running tox is actually on my want-list, so I guess I need to start looking into downloading a tarball... submodules seem to be quite a headache, anyway.

Thanks for your input on this :)

Will send a PR next to move freetype/ into src/python/.

@madig
Copy link
Collaborator Author

madig commented Mar 3, 2018

Alright, using a tarball works on Fedora 27. Now testing on macOS 10.13.

@madig
Copy link
Collaborator Author

madig commented Mar 3, 2018

It now builds and installs the module on Fedora 27 and macOS 10.13, running lsof | grep freetype confirms on both that the packaged library is used.

@madig
Copy link
Collaborator Author

madig commented Mar 3, 2018

I just did the move from freetype/ to src/freetype and added the Makefile to the manifest, running tox now passes :)

.travis.yml Outdated

install:
# Maybe get and clean and patch source
- clean_code $REPO_DIR $BUILD_COMMIT
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You don’t need this line

# Test for OSX with [ -n "$IS_OSX" ]

function run_tests {
tox
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is going to build the shared library from source again, whereas you actually want to test the precompiled wheel (the one compiled inside the manylinux1 docker).
Use tox with —installpkg option, or just skip tox and run the tests directly. Multibuild already makes sure you are running the run_tests function from inside a fresh venv with the built wheel installed.
You can also lists tests requirements with an env variable

@@ -2,5 +2,5 @@
# Test for OSX with [ -n "$IS_OSX" ]

function run_tests {
tox
pytest
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Forgot to mention (though it’s in multibuild docs) that this function runs from within a new temporary subfolder, so if you want to run pytest from the root of th repo, you need to cd ..

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@anthrotype
Copy link
Collaborator

It’s working! 👍

@madig
Copy link
Collaborator Author

madig commented Mar 3, 2018

Okay, more work some other day. Get things to deploy on PyPI or get Appveyor up first?

@anthrotype
Copy link
Collaborator

Appveyor first. PyPI deployment is more complicated

@madig
Copy link
Collaborator Author

madig commented Mar 3, 2018

Kay :)

Oh, well, still need to give the option to not bundle FT. Maybe look for an env var and bundle FT only then? The var can be set in the build files. The default would be not to bundle.

@anthrotype
Copy link
Collaborator

@rougier needs to enable the repository with his Appveyor account for this to work, just like he did for Travis.

Yes, default should be not bundle

@madig
Copy link
Collaborator Author

madig commented Mar 5, 2018

Is it possible to cache the FT tarball somewhere? I feel uncomfortable downloading 2 Mb off the internet multiple times for every commit :(

@madig
Copy link
Collaborator Author

madig commented Mar 5, 2018

I'll be using https://ci.appveyor.com/project/madig/freetype-py until @rougier enables Appveyor on his repo :)

@anthrotype
Copy link
Collaborator

Is it possible to cache the FT tarball somewhere?

You could make a separate make target that just curls the tarball and make the other target depend on it

@anthrotype
Copy link
Collaborator

Oh you mean for every commit.. hm yes Travis has a cache feature, check the docs

@madig
Copy link
Collaborator Author

madig commented Mar 5, 2018

Will do.

The Windows MSYS2 build produces a libfreetype.dll.a, file says it is a "current ar" -- is this related to the dllwrap magic you did?

@anthrotype
Copy link
Collaborator

That’s just the import library (equivalent of *.lib when building with MSVC) for use when linking, you don’t need that.
You don’t get any DLL? Try configuring with —enable-shared, maybe it’s not enabled by default on MSYS2 builds.

@anthrotype
Copy link
Collaborator

I suggest you do your experiments on a real Windows machine or a local VM first, it’s easier.

Also use Dependency Walker to check that the built dll doesn’t depend on anything else but system libraries, we want to bundle a single freetype DLL.

http://www.dependencywalker.com

If you see it still depends on msys2 specific dlls, then try to create the DLL using the dllwrap tool and see if that makes it a standalone library.

(I’m at the airport typing from my phone)

@anthrotype
Copy link
Collaborator

Maybe also try passing -static-libgcc
https://stackoverflow.com/a/18138926

@anthrotype
Copy link
Collaborator

Also, technically we don’t have to use kings-w64 gcc to build the freetype DLL on windows, we could also build it with MSVC (there should be an nmake makefile in win32 folder). The reason I had to use msys2 for ttfautohint-py was because ttfautohint depends on gnulib and that can only be built with the autotools in a Unix-like environment.

@anthrotype
Copy link
Collaborator

mingw, not kings

@HinTak
Copy link
Collaborator

HinTak commented Mar 5, 2018 via email

@madig
Copy link
Collaborator Author

madig commented Mar 5, 2018

The .dll.a gets produced even when I do --enable-shared --disable-static. When I produce a static .a and use dllwrap (with --export-all-symbols), I get a proper .dll that only depends on kernel32.dll and msvcrt.dll.

Hm, I guess I'd have to make a separate (N)Makefile for Windows maybe. Although I guess that won't get us far if we want HarfBuzz, too... Oh, the build instructions mention vcpkg. More investigation needed I guess.

@HinTak: I'm cross-compiling to Windows.. on Windows 😀

@AppVeyorBot
Copy link

Build freetype-py 1.0.18 completed (commit a4aed6f965 by @madig)

Copy link
Collaborator

@anthrotype anthrotype left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM

@AppVeyorBot
Copy link

Build freetype-py 1.0.19 completed (commit ddcb2211d1 by @madig)

@madig
Copy link
Collaborator Author

madig commented Apr 10, 2018

I don't have a PyPI account. @rougier do you want to fill in the deployment stuff yourself or hand that off to someone?

@anthrotype Why are you using "skip_cleanup: true", "distributions: check" and "on: repo: ..." in ttfautohint? Shouldn't 'distributions: "sdist bdist_wheel"' suffice?

@anthrotype
Copy link
Collaborator

Why are you using "skip_cleanup: true", "distributions: check" and "on: repo: ..." in ttfautohint? Shouldn't 'distributions: "sdist bdist_wheel"' suffice?

because we have already built the wheels inside the multibuild environment, we don't want Travis dpl tool to try rebuiding them again outside of it, which it will attempt to do.
The default distributions value is sdist bdist_wheel; these are simply forwarded by Travis to the setup.py script. I set it to check so that it doesn't actually do anything. The check setuptools command just checks the package metadata is correct. In other projects, I defined a pass custom command that does nothing, for the same reasons.
The skip_cleanup is to prevent Travis from deleting the wheels we just built.
I know, it sounds complicated, but it works.
The alternative would be to pip install twine and call twine ourselves in a custom deploy script, avoiding the use of Travis built-in PyPI intergration.

@madig
Copy link
Collaborator Author

madig commented Apr 10, 2018

And what about the "on: repo: ..." thing?

@anthrotype
Copy link
Collaborator

it's to prevent the deploy stage to trigger from forks.

Username and password need to be filled in still.
@AppVeyorBot
Copy link

Build freetype-py 1.0.20 failed (commit f0b6329154 by @madig)

@AppVeyorBot
Copy link

Build freetype-py 1.0.21 failed (commit f7f43e0c70 by @madig)

@AppVeyorBot
Copy link

Build freetype-py 1.0.22 completed (commit 239e794eca by @madig)

@madig
Copy link
Collaborator Author

madig commented Apr 20, 2018

@rougier ping :)

@rougier
Copy link
Owner

rougier commented Apr 23, 2018

Yes, sorry. I've not been reactive lately (lot of work). Is this ready to be merged ?

@madig
Copy link
Collaborator Author

madig commented Apr 23, 2018

Yes, the only thing left to do is filling in the PyPI upload credentials. You can do that yourself or follow Cosimo's suggestion (#79 (comment)).

@rougier
Copy link
Owner

rougier commented Apr 23, 2018

Ok, I will add them later then. Found how to do it on with Travis but not with apppveyor.

@rougier rougier merged commit 76e13a7 into rougier:master Apr 23, 2018
@anthrotype
Copy link
Collaborator

For Appveyor, you need to encrypt your PyPI password by going to Account → Encrypt data. Store the secure value as TWINE_PASSWORD in appveyor.yml

@rougier
Copy link
Owner

rougier commented Apr 23, 2018

Just dit it. Travis still failing. We need to add a travis/appveyor status in the README byt the way.

@rougier
Copy link
Owner

rougier commented Apr 23, 2018

Traceback (most recent call last):
  File "ci/multibuild/supported_wheels.py", line 9, in <module>
    from pip.pep425tags import get_supported
ModuleNotFoundError: No module named 'pip.pep425tags'
ERROR: You must give at least one requirement to install (see "pip help install")

@anthrotype
Copy link
Collaborator

Try update the multibuild submodule ti latest master, or even try the dev branch if it still fails

@rougier
Copy link
Owner

rougier commented Apr 23, 2018

It seems to be up to date and the PR was ok when not merged.

@madig madig deleted the setup-ci branch April 23, 2018 13:55
@madig
Copy link
Collaborator Author

madig commented Apr 23, 2018

https://github.com/matthew-brett/multibuild/issues/159 -- seems to be this?

@rougier
Copy link
Owner

rougier commented Apr 23, 2018

Yes. Note sure how to switch to the devel branch on the module though. Maybe it's not worth the trouble.

@madig
Copy link
Collaborator Author

madig commented Apr 23, 2018

You can do follow https://stackoverflow.com/questions/5828324/update-git-submodule-to-latest-commit-on-origin and use the commit hash of the latest devel branch.

@rougier
Copy link
Owner

rougier commented Apr 23, 2018

This seems to work. 🎉

@madig @anthrotype By the way, I forgot to say a huge thanks to for this huge PR that hopefully will make things easier for a lot of people! Again, many many thanks for your contribution.

@madig madig mentioned this pull request May 9, 2018
@bgermann bgermann mentioned this pull request Jun 11, 2018
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

6 participants