Open mammo0 opened 2 years ago
I'm no sure to fully understand this PR but if @anthrotype approve, it's fine for me. @HinTak Can you have a quick look?
@rougier: I ran into the problem which is described in #123. I wanted to use an emoji font with freetype. But to get this working libpng and zlib is required. So I extended the setup-build-freetype.py
to build and embed those libraries.
@mammo0 Hmm, I think building with Jam has been dropped years ago. For unix and mingw builds, the export symbol list is generated by this sub-makefile (if you build via ./configure , etc).
./builds/exports.mk
As for your problem /motivation for this pull - I actually do understand why you want to do this. Some emoji (I think you are talking about Apple Emoji specifically, actually!) fonts use png as the embedded bitmap format, so freetype needs to be linked with libpng to support that. As for libz, it is one of the specific compression schemes that libpng uses, so it comes as an indirect dependency at least because of needing libpng.
There are 4 kinds of emoji fonts, I think - one with png embedded (Apple's), svg (Adobe/Mozilla folks), CPAL (Microsoft), CBDT (Google...).
I think providing an option to statically build libpng/libz info freetype is a good idea. Hopefully it is done correctly.
I am not familar with cmake enough to tell - but it is probably simple enough to just analyse the outcome - if it loads the apple emoji fonts, and does not show the png/zlib symbols under nm (on linux/mac) PE export table (for windows) , that would be fine.
@mammo0 Hmm, I think building with Jam has been dropped years ago. For unix and mingw builds, the export symbol list is generated by this sub-makefile (if you build via ./configure , etc).
./builds/exports.mk
Ok, back in 2020, when I made the original PR, you used freetype version 2.10.2. That version still used the Jamfile. Now you've switched to version 2.11.0 (current master). That version uses the exports.mk
file. I will update this PR to the current master and post the output of nm
here.
As for your problem /motivation for this pull - I actually do understand why you want to do this. Some emoji (I think you are talking about Apple Emoji specifically, actually!) fonts use png as the embedded bitmap format, so freetype needs to be linked with libpng to support that. As for libz, it is one of the specific compression schemes that libpng uses, so it comes as an indirect dependency at least because of needing libpng.
Yes, you're absolutely right about this.
I think providing an option to statically build libpng/libz info freetype is a good idea. Hopefully it is done correctly.
Thanks for supporting my idea. As I mentioned above, I will rework my PR and post a list of the exported symbols.
Ok, now I've rebased this PR to the current master branch.
@HinTak regarding the problem with the re-export of symbols from included libraries:
I found out that this problem was already there with the Harfbuzz library.
If I execute nm -g libfreetype.so
on the library that was built from the current master (without any changes of this PR), then all Harfbuzz symbols were re-exported.
But I think I found a solution to not re-export the symbols of the embedded libraries. On Linux and Windows the linker flag --exclude-libs
and on OSX -hidden-lx
can be used. Please have a look at the last commit in this PR that uses those linker flags.
Afterwards the output of nm -g libfreetype.so
is:
There are no references to harfbuzz, libpng or zlib.
adler32, deflate and zlib* are zlib (libz) symbols. I just remember zlib is treated slightly differently - freetype bundles its sources under src/gzip/ .
I think I used this before -Wl,--exclude-libs,ALL
on a different project.I am wondering about the syntax - I think you only need harfbuzz, z,png (the part without lib
and .a
), just like what you do with -lharfbuzz -lpng -lz
in linking.
Oh, you're right. Zlib is still there... Sorry about that, but it was a long debugging session yesterday.
At first I globally used -Wl,--exclude-libs,ALL
, but that flat is not available on Mac OS. So I splitted it up to only exclude the bundled libraries.
I will try your suggested syntax tomorrow and report back.
Thanks for your patience.
Ok, I already found some time today.
I tested your suggested syntax with e.g. -Wl,--exclude-libs,png
. But this does not work. Afterwards the libpng symbols are re-exported. Only if I use -Wl,--exclude-libs,libpng
it's working. I think for Linux and Windows they have to be named like the files of the corresponding library. Only without the .a
or .so
suffix.
The problem with the exported zlib symbols was because of a typo. The resulting library file was libz.a
, but I excluded zlib
. Sorry, my mistake. I corrected it and now it works:
maybe the ci should be set up to run this (at least on Linux), otherwise even if we merge this the code will get rotten pretty soon. A test loading a subset of an emoji font would also be nice to confirm it works at runtime as well. Potentially we could even include zlib and libpng by default in the distributed wheel packages.
I agree, some tests are never a mistake. I can add a test. But before the CI integration should be done by a maintainer.
There are some conflicts but I'm not sure I can fix them.
@rougier merged it ;)
Just a historical note: the jam build mechanism is perhaps 20+ years old; ./configure && make slightly younger but not much. Yes, it looks like jam support was removed recently; and building with cmake and meson were added. And visual studio support perhaps 10 years old.
I suppose this is ready to merge after someone added a test? I think we can just ship with zlib and png deps built into the bundle by default.
just ship with zlib and png deps built into the bundle by default
+1
I just tried to run this on my local macOS machine (M1 Pro MBP) and I got an error while it tries to build libpng, not sure what this is. In any case, it would be good to hook this up to the CI.
# Next, build libpng.
-- The C compiler identification is AppleClang 14.0.3.14030022
-- The ASM compiler identification is Clang with GNU-like command-line
-- Found assembler: /Library/Developer/CommandLineTools/usr/bin/cc
-- Detecting C compiler ABI info
-- Detecting C compiler ABI info - done
-- Check for working C compiler: /Library/Developer/CommandLineTools/usr/bin/cc - skipped
-- Detecting C compile features
-- Detecting C compile features - done
-- Found ZLIB: /Users/clupo/oss/freetype-py/build/local/lib/libz.a (found version "1.2.11")
-- Symbol prefix:
-- Configuring done
-- Generating done
CMake Warning:
Manually-specified variables were not used by the project:
CMAKE_COLOR_MAKEFILE
CMAKE_CXX_FLAGS
-- Build files have been written to: /Users/clupo/oss/freetype-py/build/libpng-1.6.37/build
[2/34] Generating scripts/symbols.out
FAILED: scripts/symbols.out /Users/clupo/oss/freetype-py/build/libpng-1.6.37/build/scripts/symbols.out
cd /Users/clupo/oss/freetype-py/build/libpng-1.6.37/build && /opt/homebrew/Cellar/cmake/3.22.2/bin/cmake -DINPUT=/Users/clupo/oss/freetype-py/build/libpng-1.6.37/scripts/symbols.c -DOUTPUT=/Users/clupo/oss/freetype-py/build/libpng-1.6.37/build/scripts/symbols.out -P /Users/clupo/oss/freetype-py/build/libpng-1.6.37/build/scripts/genout.cmake
clang: error: no such file or directory: 'arm64'
CMake Error at scripts/genout.cmake:78 (message):
Failed to generate
/Users/clupo/oss/freetype-py/build/libpng-1.6.37/build/scripts/symbols.out.tf1
[4/34] Generating scripts/pnglibconf.c
ninja: build stopped: subcommand failed.
Traceback (most recent call last):
File "/Users/clupo/oss/freetype-py/setup-build-freetype.py", line 255, in <module>
shell("cmake --build . --config Release --target install --parallel", cwd=build_dir_lp)
File "/Users/clupo/oss/freetype-py/setup-build-freetype.py", line 150, in shell
subprocess.run(cmd, shell=True, check=True, cwd=cwd)
File "/opt/homebrew/Cellar/python@3.10/3.10.8/Frameworks/Python.framework/Versions/3.10/lib/python3.10/subprocess.py", line 526, in run
raise CalledProcessError(retcode, process.args,
subprocess.CalledProcessError: Command 'cmake --build . --config Release --target install --parallel' returned non-zero exit status 1.
@anthrotype I had a quick look at your build error. It seems to be a problem with the CMAKE variables that are set for the macOS platform:
if sys.platform == "darwin":
print("# Making a 64 bit build.")
CMAKE_GLOBAL_SWITCHES += (
'-DCMAKE_OSX_ARCHITECTURES="x86_64;arm64" '
'-DCMAKE_OSX_DEPLOYMENT_TARGET="10.9" '
'-DCMAKE_C_FLAGS="-O2" '
'-DCMAKE_CXX_FLAGS="-O2" '
)
bitness = 64
# the library path is needed for the '-hidden-lx' option to work
CMAKE_PREVENT_REEXPORT += "-Wl,-L{} ".format(lib_dir)
CMAKE_PREVENT_REEXPORT += "-Wl,-hidden-lharfbuzz "
if BUILD_ZLIB or BUILD_LIBPNG:
CMAKE_PREVENT_REEXPORT += "-Wl,-hidden-lz "
if BUILD_LIBPNG:
CMAKE_PREVENT_REEXPORT += "-Wl,-hidden-lpng "
I have only an old Intel Mac, there these variables work and libpng compiles successfully. I'm sorry, but I can't find out which variables must be set for cmake to work on an M1/2 Mac.
It is probably both of these:
'-DCMAKE_OSX_ARCHITECTURES="x86_64;arm64" '
'-DCMAKE_OSX_DEPLOYMENT_TARGET="10.9" '
AFAIK, arm64 needs 11.x . 10.9 definitely does not support arm64; You need a much later 10.x (10.14/10.15?) for arm64 at least. 11.x is a safer bet.
AFAIK, arm64 needs 11.x . 10.9 definitely does not support arm64
I thought also about this. But then why do the global variables
CMAKE_OSX_ARCHITECTURES="x86_64;arm64"
CMAKE_OSX_DEPLOYMENT_TARGET="10.9"
work for building the freetype and harfbuzz library on an M1 Mac? At least @anthrotype didn't report a build error of these libraries. And both get definitely built before libpng with the above variables set on MacOS (see lines 207 and 220 of the setup-build-freetype.py
file).
Targeting old os is less of a problem than building for a "future" arch. I suspect newer libpng (1.6.37) maybe dropping support for old mac os (10+ years old, 10.9?) too.
If you build arm64 (stand-alone or fused to x64), I think you have to target macOS 11.0 anyway.
I just tried to run this on my local macOS machine (M1 Pro MBP) and I got an error while it tries to build libpng
Today I hit the same error as @anthrotype. After some research I found the following issue: https://github.com/glennrp/libpng/issues/372
So, it's a problem on the side of libpng. As a temporary work around I use the following workaround: https://github.com/mammo0/freetype-py/commit/990de1e77d1e45a825dafabd914f13626bd50f04
I can make another PR with this change, but I don't know if a universal binary is desired?
That depends - python (shipped by Apple or homebrew?) itself is a universal binary, right?
itself is a universal binary, right?
On my Intel Mac the Python binary from Homebrew is only x86_64. Don't know what is it on a Silicon Mac... But I reworked my workaround from yesterday: https://github.com/mammo0/freetype-py/commit/14e29c4a50a4a9327aedbdabed99bd024b62f6e7 This time a universal library gets built. Like the others.
@mammo0 what's the status of this?
I just tried to build from this branch from my M1 Pro macbook (arm64 architecture) and it seems to have worked this time, unlike the last time I tried. Maybe it's just a matter of rebasing or master and perhaps adding a small test?
I also propose that, instead of building zlib and libpng only when FREETYPEPY_WITH_ZLIB
and FREETYPEPY_WITH_LIBPNG
are set, we do the opposite and build them always by default, unless one requests to build it without for whatever reason. This way the prebuilt wheels that we publish on PyPI will support loading color fonts out of the box.
zlib is shipped with both Windows and Mac os x as standard as far as I know. (Besides Linux). It is really libpng which is not.
There is also the opposite issue, where somebody installed a bundled build, which gradually getting out dated and buggy compared to the system zlib/libpng/freetype.
That's the case with skia-python until a couple of months ago - it was bundling a copy of freetype about 5 years old, and still is a problem for a few libraries inherited from the wheel-building.
See https://github.com/kyamagu/skia-python/issues/175 for example.
we can take care of keeping everything up to date just like we do for the embedded freetype and harbuzz, it's no big deal
Until you no longer work for Google, you mean?
There is the option of somebody else, such as you @anthrotype , maintaining such additional functionality elsewhere, for those who needs/wants this.
In Sharpfont (the C# binding to freetype), https://github.com/Robmaister/SharpFont , the bundled libraries are maintained in a separate repo: https://github.com/Robmaister/SharpFont.Dependencies
@mammo0 what's the status of this?
Currently, I use my forked version of freetype-py to build with libpng support. I tested this on my linux PC and on my Intel MacBook.
There is also the opposite issue, where somebody installed a bundled build, which gradually getting out dated and buggy compared to the system zlib/libpng/freetype.
Good point. But this is a strategic decision that should be discussed among the maintainers. I think, I can not help here.
@HinTak sorry, the "additional functionality" you are suggesting to maintain elsewhere, is it the bitmap color font support enabled by zlib+libpng that this PR adds, or is it the ability to pip install a precompiled freetype-py from PyPI with a bundled library that doesn't rely on system installed libraries?
Because in my view the latter has had great value in enabling more users, especially on non-linux, who might not know how to compile C/C++ from source, to use freetype-py in various Python applications. I understand that you are not interested in maintaining that piece of code, but there are others like me or @madig who can take care of occasionally making sure that the published freetype-py binary wheels are up to date.
And just like we keep freetype itself or harfbuzz updated, we can do the same for zlib or libpng, it's mostly a matter of changing the version number and the SHA256 hash (see #186), and from time to time updating cibuildwheel to fix various packaging bugs or support newer python versions.
As I commented elsewhere, a line has to be drawn somewhere. Adding skia-python as a dependency to support OT-SVG color fonts (and COLRv1) is such a suggestion, for example.
skia is not a direct dependency of freetype, zlib and libpng are. If one wants to render OT-SVG or COLRv1 one would need more than just freetype. freetype-py only exposes a Python interface to the freetype API, anything more is out of scope here.
Skia-python builds everything (including skia) bundled.
I would probably suggest that when you no longer work for Google and @madig no longer contracts for Google, some of this stuff needs to be removed . Probably should file an issue to keep track of your employment status :-(
Just FYI, I think there is an understanding between me and skia-python's owner, that if I stop having an interest in skia-python and the COLRv1-related code starts to bit-rot, it will be removed.
And dependency on libpng is optional because there is only one common font that needs it: Apple's Color Emoji. So it is arguable whether libpng should be bundled for windows build.
@HinTak
there is only one common font that needs it: Apple's Color Emoji.
That is not quite true. I'm using an unofficial ttf build of twemoji (https://git.sr.ht/~whynothugo/twemoji.ttf) which also uses png files.
@anthrotype
If one wants to render OT-SVG or COLRv1 one would need more than just freetype. freetype-py only exposes a Python interface to the freetype API, anything more is out of scope here.
This means, that freetype is generally not capable of rendering svg fonts?
It just parses the table and provides hooks for an external SVG library to actually parse and render the glyphs
There are two examples in the example directory, one uses pycairo and the other uses skia-python, to enhance freetype-py to use OT-SVG fonts.
Twomoji.ttf also have a OT-SVG table. That's an argument to add skia-python as a dependency, actually. 😀
This is the official place for twemoji: https://github.com/twitter/twemoji
There are two examples in the example directory, one uses pycairo and the other uses skia-python, to enhance freetype-py to use OT-SVG fonts.
Thank you for the hint :)
This is the official place for twemoji:
The work is currently continued here: https://github.com/jdecked/twemoji (see https://github.com/jdecked/twemoji/issues/10 for more information)
Because I renamed some branches my old PR #133 was closed by GitHub. So I reopen it here with the correct branch names.
To continue the discussion with @HinTak from christmas 2020:
I checked again the sources to find out what symbols get exported. If I get it right the only file that creates the
ftexport.sym
file with the symbols is theJamfile
in the root directory of the freetype library: https://github.com/freetype/freetype/blob/132f19b779828b194b3fede187cee719785db4d8/Jamfile#L161-L193And there you can see it only exports symbols from the header files in the
include
directory of the freetype library itself (https://github.com/freetype/freetype/tree/132f19b779828b194b3fede187cee719785db4d8/include). And this directory does not contain any external header files. So I think that wrongly exported symbols are not a problem here.But you can put me right if I'm wrong here :)