2017-08-13 03:24:00 +02:00
|
|
|
from pythonforandroid.recipe import PythonRecipe
|
2019-03-30 21:58:45 +01:00
|
|
|
from pythonforandroid.logger import shprint, info_notify
|
2017-08-13 03:24:00 +02:00
|
|
|
from pythonforandroid.util import current_directory, shutil
|
2019-03-30 21:58:45 +01:00
|
|
|
from os.path import exists, join
|
2017-08-13 03:24:00 +02:00
|
|
|
import sh
|
|
|
|
from multiprocessing import cpu_count
|
|
|
|
from pythonforandroid.toolchain import info
|
2019-03-30 21:58:45 +01:00
|
|
|
import sys
|
|
|
|
import os
|
2017-08-13 03:24:00 +02:00
|
|
|
|
|
|
|
|
|
|
|
class ProtobufCppRecipe(PythonRecipe):
|
2019-03-30 21:58:45 +01:00
|
|
|
name = 'protobuf_cpp'
|
|
|
|
version = '3.6.1'
|
|
|
|
url = 'https://github.com/google/protobuf/releases/download/v{version}/protobuf-python-{version}.tar.gz'
|
|
|
|
call_hostpython_via_targetpython = False
|
|
|
|
depends = ['cffi', 'setuptools']
|
|
|
|
site_packages_name = 'google/protobuf/pyext'
|
|
|
|
protoc_dir = None
|
|
|
|
|
|
|
|
def prebuild_arch(self, arch):
|
|
|
|
super(ProtobufCppRecipe, self).prebuild_arch(arch)
|
|
|
|
|
|
|
|
patch_mark = join(self.get_build_dir(arch.arch), '.protobuf-patched')
|
|
|
|
if self.ctx.python_recipe.name == 'python3' and not exists(patch_mark):
|
|
|
|
self.apply_patch('fix-python3-compatibility.patch', arch.arch)
|
|
|
|
shprint(sh.touch, patch_mark)
|
|
|
|
|
|
|
|
# During building, host needs to transpile .proto files to .py
|
|
|
|
# ideally with the same version as protobuf runtime, or with an older one.
|
|
|
|
# Because protoc is compiled for target (i.e. Android), we need an other binary
|
|
|
|
# which can be run by host.
|
|
|
|
# To make it easier, we download prebuild protoc binary adapted to the platform
|
|
|
|
|
|
|
|
info_notify("Downloading protoc compiler for your platform")
|
|
|
|
url_prefix = "https://github.com/protocolbuffers/protobuf/releases/download/v{version}".format(version=self.version)
|
|
|
|
if sys.platform.startswith('linux'):
|
|
|
|
info_notify("GNU/Linux detected")
|
|
|
|
filename = "protoc-{version}-linux-x86_64.zip".format(version=self.version)
|
|
|
|
elif sys.platform.startswith('darwin'):
|
|
|
|
info_notify("Mac OS X detected")
|
|
|
|
filename = "protoc-{version}-osx-x86_64.zip".format(version=self.version)
|
|
|
|
else:
|
|
|
|
info_notify("Your platform is not supported, but recipe can still "
|
|
|
|
"be built if you have a valid protoc (<={version}) in "
|
|
|
|
"your path".format(version=self.version))
|
|
|
|
return
|
|
|
|
|
|
|
|
protoc_url = join(url_prefix, filename)
|
|
|
|
self.protoc_dir = join(self.ctx.build_dir, "tools", "protoc")
|
|
|
|
if os.path.exists(join(self.protoc_dir, "bin", "protoc")):
|
|
|
|
info_notify("protoc found, no download needed")
|
|
|
|
return
|
|
|
|
try:
|
|
|
|
os.makedirs(self.protoc_dir)
|
|
|
|
except OSError as e:
|
|
|
|
# if dir already exists (errno 17), we ignore the error
|
|
|
|
if e.errno != 17:
|
|
|
|
raise e
|
|
|
|
info_notify("Will download into {dest_dir}".format(dest_dir=self.protoc_dir))
|
|
|
|
self.download_file(protoc_url, join(self.protoc_dir, filename))
|
|
|
|
with current_directory(self.protoc_dir):
|
|
|
|
shprint(sh.unzip, join(self.protoc_dir, filename))
|
|
|
|
|
|
|
|
def build_arch(self, arch):
|
|
|
|
env = self.get_recipe_env(arch)
|
|
|
|
|
|
|
|
# Build libproto.a
|
|
|
|
with current_directory(self.get_build_dir(arch.arch)):
|
|
|
|
env['HOSTARCH'] = 'arm-eabi'
|
|
|
|
env['BUILDARCH'] = shprint(sh.gcc, '-dumpmachine').stdout.decode('utf-8').split('\n')[0]
|
|
|
|
|
|
|
|
if not exists('configure'):
|
|
|
|
shprint(sh.Command('./autogen.sh'), _env=env)
|
|
|
|
|
|
|
|
shprint(sh.Command('./configure'),
|
|
|
|
'--host={}'.format(env['HOSTARCH']),
|
|
|
|
'--enable-shared',
|
|
|
|
_env=env)
|
|
|
|
|
|
|
|
with current_directory(join(self.get_build_dir(arch.arch), 'src')):
|
|
|
|
shprint(sh.make, 'libprotobuf.la', '-j'+str(cpu_count()), _env=env)
|
|
|
|
shprint(sh.cp, '.libs/libprotobuf.a', join(self.ctx.get_libs_dir(arch.arch), 'libprotobuf.a'))
|
|
|
|
|
|
|
|
# Copy stl library
|
|
|
|
shutil.copyfile(
|
|
|
|
self.ctx.ndk_dir + '/sources/cxx-stl/gnu-libstdc++/' + self.ctx.toolchain_version + '/libs/' + arch.arch + '/libgnustl_shared.so',
|
|
|
|
join(self.ctx.get_libs_dir(arch.arch), 'libgnustl_shared.so'))
|
|
|
|
|
|
|
|
# Build python bindings and _message.so
|
|
|
|
with current_directory(join(self.get_build_dir(arch.arch), 'python')):
|
|
|
|
hostpython = sh.Command(self.hostpython_location)
|
|
|
|
shprint(hostpython,
|
|
|
|
'setup.py',
|
|
|
|
'build_ext',
|
|
|
|
'--cpp_implementation', _env=env)
|
|
|
|
|
|
|
|
# Install python bindings
|
|
|
|
self.install_python_package(arch)
|
|
|
|
|
|
|
|
# Create __init__.py which is missing (cf. https://github.com/protocolbuffers/protobuf/issues/1296
|
|
|
|
# and https://stackoverflow.com/questions/13862562/google-protocol-buffers-not-found-when-trying-to-freeze-python-app)
|
|
|
|
open(join(self.ctx.get_site_packages_dir(), 'google', '__init__.py'), 'a').close()
|
|
|
|
|
|
|
|
def install_python_package(self, arch):
|
|
|
|
env = self.get_recipe_env(arch)
|
|
|
|
|
|
|
|
info('Installing {} into site-packages'.format(self.name))
|
|
|
|
|
|
|
|
with current_directory(join(self.get_build_dir(arch.arch), 'python')):
|
|
|
|
hostpython = sh.Command(self.hostpython_location)
|
|
|
|
|
|
|
|
hpenv = env.copy()
|
|
|
|
shprint(hostpython, 'setup.py', 'install', '-O2',
|
|
|
|
'--root={}'.format(self.ctx.get_python_install_dir()),
|
|
|
|
'--install-lib=.',
|
|
|
|
'--cpp_implementation',
|
|
|
|
_env=hpenv, *self.setup_extra_args)
|
|
|
|
|
|
|
|
def get_recipe_env(self, arch):
|
|
|
|
env = super(ProtobufCppRecipe, self).get_recipe_env(arch)
|
|
|
|
if self.protoc_dir is not None:
|
|
|
|
# we need protoc with binary for host platform
|
|
|
|
env['PROTOC'] = join(self.protoc_dir, 'bin', 'protoc')
|
|
|
|
env['TARGET_OS'] = 'OS_ANDROID_CROSSCOMPILE'
|
|
|
|
env['CFLAGS'] += (
|
|
|
|
' -I' + self.ctx.ndk_dir + '/platforms/android-' +
|
|
|
|
str(self.ctx.android_api) +
|
|
|
|
'/arch-' + arch.arch.replace('eabi', '') + '/usr/include' +
|
|
|
|
' -I' + self.ctx.ndk_dir + '/sources/cxx-stl/gnu-libstdc++/' +
|
|
|
|
self.ctx.toolchain_version + '/include' +
|
|
|
|
' -I' + self.ctx.ndk_dir + '/sources/cxx-stl/gnu-libstdc++/' +
|
|
|
|
self.ctx.toolchain_version + '/libs/' + arch.arch + '/include')
|
|
|
|
env['CFLAGS'] += ' -std=gnu++11'
|
|
|
|
env['CXXFLAGS'] = env['CFLAGS']
|
|
|
|
env['CXXFLAGS'] += ' -frtti'
|
|
|
|
env['CXXFLAGS'] += ' -fexceptions'
|
|
|
|
env['LDFLAGS'] += (
|
|
|
|
' -lgnustl_shared -landroid -llog' +
|
|
|
|
' -L' + self.ctx.ndk_dir +
|
|
|
|
'/sources/cxx-stl/gnu-libstdc++/' + self.ctx.toolchain_version +
|
|
|
|
'/libs/' + arch.arch)
|
|
|
|
return env
|
2017-08-13 03:24:00 +02:00
|
|
|
|
|
|
|
|
|
|
|
recipe = ProtobufCppRecipe()
|