OLD | NEW |
(Empty) | |
| 1 #!/usr/bin/env python |
| 2 # coding: utf-8 |
| 3 """This script fixes the support of manually compiled static libraries for |
| 4 android NDK build system. |
| 5 |
| 6 Issue: |
| 7 Let's say there are some manually compiled libraries specified in |
| 8 link_settings.libraries or in ldflags of a gyp file. In this case ndk-build |
| 9 passes them to a linker after system libraries, like c++_static, and |
| 10 as the result linker cannot find functions from system libraries. |
| 11 |
| 12 Desire: |
| 13 Pass manually compiled libraries after regular dependencies. |
| 14 |
| 15 How it works: |
| 16 The recommended way to do it is to use LOCAL_STATIC_LIBRARIES. However, to |
| 17 simply add libraries to the list is not enough because here ndk-build is trying |
| 18 to be too smart and removes any libraries which are not defined in Makefiles. |
| 19 |
| 20 So, the idea is to monkey patch gyp to inject definition of static libraries |
| 21 and add them to LOCAL_STATIC_LIBRARIES. The former is to prevent them from |
| 22 being removed. |
| 23 |
| 24 Firstly some excerpts from gyp codebase: |
| 25 source: gyp/pylib/gyp/generator/make.py |
| 26 |
| 27 MakefileWriter(object): |
| 28 def Write(self, qualified_target, base_path, output_filename, spec, configs, |
| 29 part_of_all): |
| 30 // The main entry point: writes a .mk file for a single target. |
| 31 ... |
| 32 if android: |
| 33 self.WriteAndroidNdkModuleRule(...) |
| 34 |
| 35 def WriteAndroidNdkModuleRule(self, module_name, all_sources, link_deps): |
| 36 /* Write a set of LOCAL_XXX definitions for Android NDK. |
| 37 |
| 38 These variable definitions will be used by Android NDK but do nothing for |
| 39 non-Android applications. |
| 40 |
| 41 Arguments: |
| 42 module_name: Android NDK module name, which must be unique among all |
| 43 module names. |
| 44 all_sources: A list of source files (will be filtered by Compilable). |
| 45 link_deps: A list of link dependencies, which must be sorted in |
| 46 the order from dependencies to dependents. |
| 47 */ |
| 48 ... |
| 49 self.WriteList( |
| 50 DepsToModules(link_deps, |
| 51 generator_default_variables['STATIC_LIB_PREFIX'], |
| 52 generator_default_variables['STATIC_LIB_SUFFIX']), |
| 53 'LOCAL_STATIC_LIBRARIES') |
| 54 .... |
| 55 |
| 56 def WriteList(self, value_list, variable=None, prefix='', |
| 57 quoter=QuoteIfNecessary): |
| 58 // Write a variable definition that is a list of values. |
| 59 |
| 60 The only class which is writing Makefiles is MakefileWriter and the "entry |
| 61 point" is MakefileWriter.Write. To write LOCAL_STATIC_LIBRARIES it uses |
| 62 MakefileWriter.WriteList, so one could simply override |
| 63 - Write method to store all required information and to define (CLEAR_VARS, |
| 64 LOCAL_MODULE, etc) libraries. |
| 65 - WriteList to change the value of LOCAL_STATIC_LIBRARIES. |
| 66 However merely to reduce any potential influence we override |
| 67 MakefileWriter.WriteAndroidNdkModuleRule to define manually compiled libraries |
| 68 and override WriteList only while we are in the WriteAndroidNdkModuleRule method
. |
| 69 The aim of the latter method is exactly to write Rules for ndk-build and it is |
| 70 called at the end of Write. However, since WriteAndroidNdkModuleRule lacks |
| 71 required information, we override method Write to store configurations as |
| 72 _abp_configs attribute of instance of MakefileWriter. |
| 73 """ |
| 74 |
| 75 import os |
| 76 import sys |
| 77 import types |
| 78 |
| 79 base_dir = os.path.abspath(os.path.dirname(__file__)) |
| 80 sys.path.append(os.path.join(base_dir, 'third_party', 'gyp', 'pylib')) |
| 81 import gyp |
| 82 from gyp.generator.make import MakefileWriter, QuoteIfNecessary |
| 83 |
| 84 |
| 85 orig_MakefileWriter_Write = MakefileWriter.Write |
| 86 orig_MakefileWriter_WriteAndroidNdkModuleRule = MakefileWriter.WriteAndroidNdkMo
duleRule |
| 87 |
| 88 def overridden_Write(self, qualified_target, base_path, output_filename, spec, c
onfigs, part_of_all): |
| 89 if hasattr(self, "_abp_configs"): |
| 90 sys.exit("MakefileWriter already has property _abp_configs") |
| 91 self._abp_configs = configs |
| 92 orig_MakefileWriter_Write(self, qualified_target, base_path, output_filename
, spec, configs, part_of_all) |
| 93 delattr(self, "_abp_configs") |
| 94 |
| 95 def overridden_WriteAndroidNdkModuleRule(self, module_name, all_sources, link_de
ps): |
| 96 for config in self._abp_configs: |
| 97 libs = self._abp_configs[config].get("user_libraries") |
| 98 if not libs: |
| 99 continue |
| 100 self.WriteLn("ifeq (${{BUILDTYPE}}, {})".format(config)) |
| 101 for lib in libs: |
| 102 self.WriteLn("include $(CLEAR_VARS)") |
| 103 self.WriteLn("LOCAL_MODULE := {}".format(lib)) |
| 104 self.WriteLn("LOCAL_SRC_FILES := {}".format(lib)) |
| 105 self.WriteLn("include $(PREBUILT_STATIC_LIBRARY)") |
| 106 self.WriteLn("ABP_STATIC_LIBRARIES_${{BUILDTYPE}} += {}".format(lib)
) |
| 107 self.WriteLn("endif") |
| 108 orig_WriteList = self.WriteList |
| 109 def overridden_WriteList(self, orig_value_list, variable=None, prefix='', qu
oter=QuoteIfNecessary): |
| 110 value_list = orig_value_list[:] |
| 111 if variable == "LOCAL_STATIC_LIBRARIES": |
| 112 value_list.append("${ABP_STATIC_LIBRARIES_${BUILDTYPE}}") |
| 113 orig_WriteList(value_list, variable, prefix, quoter) |
| 114 self.WriteList = types.MethodType(overridden_WriteList, self) |
| 115 orig_MakefileWriter_WriteAndroidNdkModuleRule(self, module_name, all_sources
, link_deps) |
| 116 self.WriteList = orig_WriteList |
| 117 |
| 118 MakefileWriter.Write = overridden_Write |
| 119 MakefileWriter.WriteAndroidNdkModuleRule = overridden_WriteAndroidNdkModuleRule |
| 120 |
| 121 if __name__ == '__main__': |
| 122 gyp.main(sys.argv[1:]) |
OLD | NEW |