diff --git a/pythonforandroid/recipe.py b/pythonforandroid/recipe.py index 44469aef2..9b2299dee 100644 --- a/pythonforandroid/recipe.py +++ b/pythonforandroid/recipe.py @@ -1290,6 +1290,7 @@ class MesonRecipe(PyProjectRecipe): meson_version = "1.4.0" ninja_version = "1.11.1.1" + skip_python = False def sanitize_flags(self, *flag_strings): return " ".join(flag_strings).strip().split(" ") @@ -1372,7 +1373,8 @@ def build_arch(self, arch): ]: if dep not in self.hostpython_prerequisites: self.hostpython_prerequisites.append(dep) - super().build_arch(arch) + if not self.skip_python: + super().build_arch(arch) class RustCompiledComponentsRecipe(PyProjectRecipe): diff --git a/pythonforandroid/recipes/libcairo/__init__.py b/pythonforandroid/recipes/libcairo/__init__.py new file mode 100644 index 000000000..f969d4038 --- /dev/null +++ b/pythonforandroid/recipes/libcairo/__init__.py @@ -0,0 +1,57 @@ +from pythonforandroid.recipe import Recipe, MesonRecipe +from os.path import join +from pythonforandroid.util import ensure_dir, current_directory +from pythonforandroid.logger import shprint +from multiprocessing import cpu_count +import sh + + +class LibCairoRecipe(MesonRecipe): + name = 'libcairo' + version = '1.18.4' + url = 'https://gitlab.freedesktop.org/cairo/cairo/-/archive/{version}/cairo-{version}.tar.bz2' + skip_python = True + depends = ["png", "freetype"] + patches = ["meson.patch"] + built_libraries = { + 'libcairo.so': 'install/lib', + 'libpixman-1.so': 'install/lib', + 'libcairo-script-interpreter.so': 'install/lib' + } + + def should_build(self, arch): + return Recipe.should_build(self, arch) + + def build_arch(self, arch): + super().build_arch(arch) + build_dir = self.get_build_dir(arch.arch) + install_dir = join(build_dir, 'install') + ensure_dir(install_dir) + env = self.get_recipe_env(arch) + + lib_dir = self.ctx.get_libs_dir(arch.arch) + png_include = self.get_recipe('png', self.ctx).get_build_dir(arch.arch) + freetype_inc = join(self.get_recipe('freetype', self.ctx).get_build_dir(arch), "include") + + with current_directory(build_dir): + shprint(sh.meson, 'setup', 'builddir', + '--cross-file', join("/tmp", "android.meson.cross"), + f'--prefix={install_dir}', + '-Dpng=enabled', + '-Dzlib=enabled', + '-Dglib=disabled', + '-Dgtk_doc=false', + '-Dsymbol-lookup=disabled', + + # deps + f'-Dpng_include_dir={png_include}', + f'-Dpng_lib_dir={lib_dir}', + f'-Dfreetype_include_dir={freetype_inc}', + f'-Dfreetype_lib_dir={lib_dir}', + _env=env) + + shprint(sh.ninja, '-C', 'builddir', '-j', str(cpu_count()), _env=env) + shprint(sh.ninja, '-C', 'builddir', 'install', _env=env) + + +recipe = LibCairoRecipe() diff --git a/pythonforandroid/recipes/libcairo/meson.patch b/pythonforandroid/recipes/libcairo/meson.patch new file mode 100644 index 000000000..0e119c5cc --- /dev/null +++ b/pythonforandroid/recipes/libcairo/meson.patch @@ -0,0 +1,64 @@ +diff '--color=auto' -uNr cairo-1.18.4/meson.build cairo-1.18.4.mod/meson.build +--- cairo-1.18.4/meson.build 2025-03-08 18:53:25.000000000 +0530 ++++ cairo-1.18.4.mod/meson.build 2025-07-14 20:42:56.226164648 +0530 +@@ -235,11 +235,13 @@ + conf.set('HAVE_ZLIB', 1) + endif + +-png_dep = dependency('libpng', +- required: get_option('png'), +- version: libpng_required_version, +- fallback: ['libpng', 'libpng_dep'] ++png_inc = include_directories(get_option('png_include_dir')) ++png_lib = cc.find_library('png16', dirs: [get_option('png_lib_dir')], required: true) ++png_dep = declare_dependency( ++ include_directories: png_inc, ++ dependencies: [png_lib] + ) ++ + if png_dep.found() + feature_conf.set('CAIRO_HAS_SVG_SURFACE', 1) + feature_conf.set('CAIRO_HAS_PNG_FUNCTIONS', 1) +@@ -265,7 +267,7 @@ + + # Disable fontconfig by default on platforms where it is optional + fontconfig_option = get_option('fontconfig') +-fontconfig_required = host_machine.system() not in ['windows', 'darwin'] ++fontconfig_required = false + fontconfig_option = fontconfig_option.disable_auto_if(not fontconfig_required) + + fontconfig_dep = dependency('fontconfig', +@@ -304,11 +306,14 @@ + freetype_required = host_machine.system() not in ['windows', 'darwin'] + freetype_option = freetype_option.disable_auto_if(not freetype_required) + +-freetype_dep = dependency('freetype2', +- required: freetype_option, +- version: freetype_required_version, +- fallback: ['freetype2', 'freetype_dep'], ++freetype_inc = include_directories(get_option('freetype_include_dir')) ++freetype_lib = cc.find_library('freetype', dirs: [get_option('freetype_lib_dir')], required: true) ++ ++freetype_dep = declare_dependency( ++ include_directories: freetype_inc, ++ dependencies: [freetype_lib] + ) ++ + if freetype_dep.found() + feature_conf.set('CAIRO_HAS_FT_FONT', 1) + built_features += [{ +diff '--color=auto' -uNr cairo-1.18.4/meson.options cairo-1.18.4.mod/meson.options +--- cairo-1.18.4/meson.options 2025-03-08 18:53:25.000000000 +0530 ++++ cairo-1.18.4.mod/meson.options 2025-07-14 20:43:00.473191452 +0530 +@@ -28,3 +28,11 @@ + # Documentation + option('gtk_doc', type : 'boolean', value : false, + description: 'Build the Cairo API reference (depends on gtk-doc)') ++ ++# Deps ++ ++option('png_include_dir', type: 'string', value: '', description: 'Path to PNG headers') ++option('png_lib_dir', type: 'string', value: '', description: 'Path to PNG library') ++option('freetype_include_dir', type: 'string', value: '', description: 'Path to FreeType headers') ++option('freetype_lib_dir', type: 'string', value: '', description: 'Path to FreeType library') ++ diff --git a/pythonforandroid/recipes/pycairo/__init__.py b/pythonforandroid/recipes/pycairo/__init__.py new file mode 100644 index 000000000..2e9474568 --- /dev/null +++ b/pythonforandroid/recipes/pycairo/__init__.py @@ -0,0 +1,26 @@ +from pythonforandroid.recipe import MesonRecipe +from os.path import join + + +class PyCairoRecipe(MesonRecipe): + version = '1.28.0' + url = 'https://github.com/pygobject/pycairo/releases/download/v{version}/pycairo-{version}.tar.gz' + name = 'pycairo' + site_packages_name = 'cairo' + depends = ['libcairo'] + patches = ["meson.patch"] + + def build_arch(self, arch): + + include_path = join(self.get_recipe('libcairo', self.ctx).get_build_dir(arch), "install", "include", "cairo") + lib_path = self.ctx.get_libs_dir(arch.arch) + + self.extra_build_args += [ + f'-Csetup-args=-Dcairo_include={include_path}', + f'-Csetup-args=-Dcairo_lib={lib_path}', + ] + + super().build_arch(arch) + + +recipe = PyCairoRecipe() diff --git a/pythonforandroid/recipes/pycairo/meson.patch b/pythonforandroid/recipes/pycairo/meson.patch new file mode 100644 index 000000000..aabbf5ae3 --- /dev/null +++ b/pythonforandroid/recipes/pycairo/meson.patch @@ -0,0 +1,24 @@ +diff '--color=auto' -uNr pycairo-1.28.0/cairo/meson.build pycairo-1.28.0.mod/cairo/meson.build +--- pycairo-1.28.0/cairo/meson.build 2025-04-15 00:22:30.000000000 +0530 ++++ pycairo-1.28.0.mod/cairo/meson.build 2025-07-14 21:56:34.782983845 +0530 +@@ -28,7 +28,10 @@ + fs.copyfile(python_file, python_file) + endforeach + +-cairo_dep = dependency('cairo', version: cair_version_req, required: cc.get_id() != 'msvc') ++cairo_dep = declare_dependency( ++ include_directories: include_directories(get_option('cairo_include')), ++ link_args: ['-L' + get_option('cairo_lib'), '-lcairo'] ++) + + if cc.get_id() == 'msvc' and not cairo_dep.found() + if cc.has_header('cairo.h') +diff '--color=auto' -uNr pycairo-1.28.0/meson_options.txt pycairo-1.28.0.mod/meson_options.txt +--- pycairo-1.28.0/meson_options.txt 2025-04-15 00:22:30.000000000 +0530 ++++ pycairo-1.28.0.mod/meson_options.txt 2025-07-14 21:56:52.824191314 +0530 +@@ -1,3 +1,5 @@ + option('python', type : 'string', value : 'python3') + option('tests', type : 'boolean', value : true, description : 'build unit tests') + option('wheel', type : 'boolean', value : false, description : 'build for a Python wheel') ++option('cairo_include', type: 'string', value: '', description: 'Path to cairo headers') ++option('cairo_lib', type: 'string', value: '', description: 'Path to cairo libraries') diff --git a/setup.py b/setup.py index c9cebd231..0bf5b124a 100644 --- a/setup.py +++ b/setup.py @@ -21,7 +21,7 @@ # https://github.com/kivy/buildozer/issues/722 install_reqs = [ 'appdirs', 'colorama>=0.3.3', 'jinja2', - 'sh>=2, <3.0; sys_platform!="win32"', + 'sh>=2, <3.0; sys_platform!="win32"', 'meson', 'ninja', 'build', 'toml', 'packaging', 'setuptools', 'wheel~=0.43.0' ] # (build and toml are used by pythonpackage.py)