Repository: kivy/python-for-android

Issue:
ffi.h: No such file or directory (solutions included)
# Problem summary
On Gentoo Linux `cffi` recipe host install fails with the error below:
```
c/_cffi_backend.c:13:17: fatal error: ffi.h: No such file or directory
```

# Detailed description
This is because `ffi.h` is installed in `/usr/lib64/libffi-3.2.1/include/ffi.h` which is not part of gcc default include paths.
Here is where `ffi.h` is installed (`equery f` is the Gentoo equivalent to Debian-like `dpkg -L`):
```
$ equery f dev-libs/libffi | grep ffi.h
/usr/lib64/libffi-3.2.1/include/ffi.h
```
Or with `dpkg-config`:
```
$ pkg-config --cflags libffi
-I/usr/lib64/libffi-3.2.1/include
```
And here are the gcc default include paths:
```
$ echo | gcc -E -Wp,-v -
#include "..." search starts here:
#include <...> search starts here:
 /usr/lib/gcc/x86_64-pc-linux-gnu/5.4.0/include
 /usr/lib/gcc/x86_64-pc-linux-gnu/5.4.0/include-fixed
 /usr/include
End of search list.
```

# Complete error output
Below is the detailed `buildozer android debug` (cffi) output log:
```
[INFO]:    Installing cffi into site-packages                                                                                                                                                                                                                     [66/1768]
[INFO]:    -> directory context /home/andre/Progz/PyWallet/.buildozer/android/platform/build/build/other_builds/cffi-python2/armeabi-v7a/cffi                                                                                                                              
[INFO]:    -> running python.host setup.py install -O2                                                                                                                                                                                                                     
[INFO]:    Rebuilding compiled components in cffi                                                                                                                                                                                                                          
[INFO]:    -> running hostpython setup.py clean --all                                                                                
[INFO]:    -> running hostpython setup.py build_ext -v                                                                               
Exception in thread background thread for pid 19037:                                                                                 
Traceback (most recent call last):                                                                                                   
  File "/usr/lib64/python3.4/threading.py", line 911, in _bootstrap_inner                                                            
    self.run()                                                                                                                       
  File "/usr/lib64/python3.4/threading.py", line 859, in run                                                                         
    self._target(*self._args, **self._kwargs)                                                                                        
  File "/home/andre/.local/lib64/python3.4/site-packages/sh.py", line 2170, in background_thread                                     
    handle_exit_code(exit_code)                                                                                                      
  File "/home/andre/.local/lib64/python3.4/site-packages/sh.py", line 1929, in fn                                                    
    return self.command.handle_command_exit_code(exit_code)                                                                          
  File "/home/andre/.local/lib64/python3.4/site-packages/sh.py", line 672, in handle_command_exit_code                               
    raise exc                                                                                                                        
sh.ErrorReturnCode_1:                                                                                                                
                                                                                                                                     
  RAN: /home/andre/Progz/PyWallet/.buildozer/android/platform/build/build/other_builds/hostpython2/desktop/hostpython2/hostpython setup.py build_ext -v
                                                                                                                                     
  STDOUT:                                                                                                                            
running build_ext                                                                                                                    
building '_cffi_backend' extension
creating build
creating build/temp.linux-x86_64-2.7
creating build/temp.linux-x86_64-2.7/c
gcc -pthread -fno-strict-aliasing -g -O2 -DNDEBUG -g -fwrapv -O3 -Wall -Wstrict-prototypes -fPIC -DUSE__THREAD -I/home/andre/Progz/PyWallet/.buildozer/android/platform/build/build/other_builds/hostpython2/desktop/hostpython2/Include -I/home/andre/Progz/PyWallet/.buildozer/android/platform/build/build/other_builds/hostpython2/desktop/hostpython2 -c c/_cffi_backend.c -o build/temp.linux-x86_64-2.7/c/_cffi_backend.o
c/_cffi_backend.c:13:17: fatal error: ffi.h: No such file or directory
compilation terminated.
```

# Solutions / workarounds
Below are few solutions/workarounds I had in mind.

## Quick'n dirty
Symlink libffi includes to gcc default include path:
```
ln -sfn /usr/lib64/libffi-3.2.1/include/ffi.h /usr/include/
ln -sfn /usr/lib64/libffi-3.2.1/include/ffitarget.h /usr/include/
```
While it works it's an unsatisfying solution.

## `dpkg-config` when possible (i.e. host)
We could update current [disable-pkg-config.patch](https://github.com/kivy/python-for-android/blob/0.5.3/pythonforandroid/recipes/cffi/disable-pkg-config.patch) to `try` to run, but `except` silently. That way if `dpkg-config` is available on the host, we can use it, but it won't fail if not.

## `dpkg-config` recipe
Since `cffi` is not the first package, nor the last needing `dpkg-config`, we could create a recipe for it to make it available for the target architecture.
https://autotools.io/pkgconfig/cross-compiling.html

## Install `libffi` recipe for the host
I'm not too sure about that one, but the idea would be to update the `libffi` recipe so it also makes the library/headers available for the host so we could point to it. But it could be a mess.

# Final word
I have a preference for the "`dpkg-config` when possible (i.e. host)" solution. It seems easy enough to implement and it would fix the issue. For the long run I prefer if we had `dpkg-config` available for the target, but I'm not sure how achievable it is.
I would be glad to contribute more to python-for-android, so please let me know which solution you prefer and I could work on a pull request when I get time.


Discussion:
For what it worth, the problem could also exist on Arch Linux since libffi headers are not installed in gcc default include paths:
```
$ pkg-config --cflags libffi
-I/usr/lib/libffi-3.2.1/include
```


Resolving patch:
diff --git a/pythonforandroid/recipes/cffi/__init__.py b/pythonforandroid/recipes/cffi/__init__.py
--- a/pythonforandroid/recipes/cffi/__init__.py
+++ b/pythonforandroid/recipes/cffi/__init__.py
@@ -14,6 +14,14 @@ class CffiRecipe(CompiledComponentsPythonRecipe):
     # call_hostpython_via_targetpython = False
     install_in_hostpython = True
 
+    def get_hostrecipe_env(self, arch=None):
+        # fixes missing ffi.h on some host systems (e.g. gentoo)
+        env = super(CffiRecipe, self).get_hostrecipe_env(arch)
+        libffi = self.get_recipe('libffi', self.ctx)
+        includes = libffi.get_include_dirs(arch)
+        env['FFI_INC'] = ",".join(includes)
+        return env
+
     def get_recipe_env(self, arch=None):
         env = super(CffiRecipe, self).get_recipe_env(arch)
         # sets linker to use the correct gcc (cross compiler)


Test patch: