Home | History | Annotate | Download | only in text
      1 Android module paths (sharing code made easy):
      2 ==============================================
      3 
      4 Starting from r5, the Android NDK comes with a cool feature that allows
      5 you to share and reuse other people's modules more easily.
      6 
      7 I. Overview:
      8 ------------
      9 
     10 The main idea behind this feature are:
     11 
     12   - You can install NDK modules outside of your main project source tree.
     13   - You can easily 'import' them into your project with a one-line command.
     14 
     15 In practice, here's how this works:
     16 
     17   1. Your NDK_MODULE_PATH environment variable will contain a list
     18      of search paths on your system to lookup for modules.
     19 
     20      It is up to you to set the variable, and to copy other modules
     21      to the directories you listed in it.
     22 
     23 
     24   2. To import a module, place a line like the following to, preferably at
     25      the *end* of, your Android.mk:
     26 
     27           $(call import-module,<tag>)
     28 
     29      This will look for <tag>/Android.mk under any of the directories
     30      listed in your NDK_MODULE_PATH.
     31 
     32      (The reason why it must be at the end is to avoid messing with
     33      the results of the 'my-dir' function. See its description in
     34      docs/ANDROID-MK.html for details).
     35 
     36 
     37   3. Declare that your project's modules depend on the imported one by
     38      listing them in either your LOCAL_STATIC_LIBRARIES or
     39      LOCAL_SHARED_LIBRARIES. For example:
     40 
     41           LOCAL_STATIC_LIBRARIES += <tag>
     42 
     43 
     44   4. Rebuild!
     45 
     46      Remember that NDK r5 also added the ability for a module to "export"
     47      declarations to other modules that depend on it (for example, see the
     48      definition of LOCAL_EXPORT_CFLAGS in docs/ANDROID-MK.html).
     49 
     50      A well-written module will correctly export all the things its
     51      dependees need, et voila.
     52 
     53 
     54 Now for the full details:
     55 
     56 I. NDK_MODULE_PATH:
     57 -------------------
     58 
     59 The NDK_MODULE_PATH variable must contain a list of directories.
     60 
     61   * Due to GNU Make limitations, NDK_MODULE_PATH must not contain any space.
     62     The NDK will complain if this is not the case.
     63 
     64   * Use ':' as the path separator.
     65 
     66   * On Windows, use '/' as the directory separator.
     67 
     68 The directories of NDK_MODULE_PATH will be searched in order. The first
     69 <path>/<tag>/Android.mk file that is found during the lookup will be
     70 included automatically.
     71 
     72 
     73 As a convenience, $NDK/sources is appended to your NDK_MODULE_PATH
     74 definition by the NDK build system. This allows you to easily import
     75 the helper libraries that come with it (see docs/CPU-FEATURES.html for
     76 a practical example).
     77 
     78 
     79 II. Writing an import module:
     80 -----------------------------
     81 
     82 Writing an import module is trivial and very similar to what you do when
     83 writing project modules:
     84 
     85   1. Create a sub-directory from one of your NDK_MODULE_PATH directories.
     86 
     87     For example, if NDK_MODULE_PATH is defined to /home/user/ndk-modules,
     88     then create the directory /home/user/ndk-modules/my-module/
     89 
     90 
     91   2. Place an Android.mk and eventual source code there.
     92 
     93     Just like you would for a project module, where these files normally
     94     go to $PROJECT_PATH/Android.mk. In the example above, this would go
     95     to /home/user/ndk-modules/my-module/Android.mk
     96 
     97     NOTE: Any Application.mk file here will be ignored.
     98 
     99 
    100   3. Any module that depends on your new module, would import by calling
    101     the import-module function. For example:
    102 
    103           $(call import-module,my-first-module)
    104 
    105 
    106 Import modules *can* import other modules, but circular dependencies are
    107 not permitted and will be detected. Dependencies are transitive and the build
    108 system will compute all the things that need to be built for you.
    109 
    110 The NDK build system will not place object files or executables in your
    111 import module directory (they will all be placed under the project's
    112 build directory, e.g. $PROJECT_PATH/obj/).
    113 
    114 You can however distribute prebuilt binaries in your import module with
    115 the new PREBUILT_STATIC_LIBRARIES or PREBUILT_SHARED_LIBRARIES feature
    116 (see docs/ANDROID-MK.html).
    117 
    118 This makes it easy to package and redistribute your import module directory
    119 to third-parties.
    120 
    121 
    122 III. Naming an import module:
    123 -----------------------------
    124 
    125 It is important to understand a few things related to the naming of
    126 your import module:
    127 
    128   - What 'import-module' does is really search for a file named Android.mk
    129     using the list provided by NDK_MODULE_PATH, then include while performing
    130     very little bit of house-keeping.
    131 
    132     Your imported Android.mk can define any number of modules, with
    133     any name. As a consequence, there is no direct relationship between
    134     <name> in the following line:
    135 
    136           $(call import-module,<tag>/<name>)
    137 
    138     And the names of the modules defined under <tag>/<name>/Android.mk.
    139 
    140     IN CASE OF DOUBT, KEEP IT SIMPLE!
    141 
    142     If you only plan to provide one import module, just name it like the
    143     base import directory.
    144 
    145     On the other hand, you may want to provide a static and a shared
    146     version of your module: use distinct names under the same top-level
    147     Android.mk. Consider the following build script:
    148 
    149         $NDK_MODULE_PATH/foo/bar/Android.mk:
    150 
    151            LOCAL_PATH := $(call my-dir)
    152 
    153            # Static version of the library is named 'bar_static'
    154            include $(CLEAR_VARS)
    155            LOCAL_MODULE := bar_static
    156            LOCAL_SRC_FILES := bar.c
    157            # Ensure our dependees can include <bar.h> too
    158            LOCAL_EXPORT_C_INCLUDES := $(LOCAL_PATH)
    159            include $(BUILD_STATIC_LIBRARY)
    160 
    161            # Shared version of the library is named 'bar_shared'
    162            LOCAL_MODULE := bar_shared
    163            LOCAL_SRC_FILES := bar.c
    164            LOCAL_EXPORT_C_INCLUDES := $(LOCAL_PATH)
    165            include $(BUILD_SHARED_LIBRARY)
    166 
    167     Another module would refer to it by doing the following:
    168 
    169          1. Import 'foo/bar', as in:
    170 
    171                   $(call import-module,foo/bar)
    172 
    173          2. To use the static library:
    174 
    175                 ...
    176                 LOCAL_STATIC_LIBRARIES := bar_static
    177 
    178          3. Or to use the shared library:
    179 
    180                 ...
    181                 LOCAL_SHARED_LIBRARIES := bar_shared
    182 
    183 
    184    - The module namespace is flat, so try to give your modules names that
    185      are likely to not collide with other. Note that your can use
    186      LOCAL_MODULE_FILENAME to give the name of your module's binary
    187      file, independently from its LOCAL_MODULE (see docs/ANDROID-MK.html
    188      for definition and usage). For example:
    189 
    190              include $(CLEAR_VARS)
    191              LOCAL_MODULE := super_foo
    192              LOCAL_MODULE_FILENAME := foo   # will give libfoo.so
    193              LOCAL_SRC_FILES := foo-src.c
    194              LOCAL_CFLAGS := -DVOLUME=11
    195              include $(BUILD_SHARED_LIBRARY)
    196 
    197              include $(CLEAR_VARS)
    198              LOCAL_MODULE := normal_foo
    199              LOCAL_MODULE_FILENAME := foo   # will also give libfoo.so
    200              LOCAL_SRC_FILES := foo-src.c
    201              include $(BUILD_SHARED_LIBRARY)
    202 
    203       Defines two modules named "super_foo" and "normal_foo"
    204       which both produce a shared library named 'libfoo.so'
    205 
    206       As a consequence, only one of them can be used by your project or
    207       a conflict will happen at build time. This allows you to select either
    208       the normal or optimized version in your NDK build scripts, while
    209       keeping the same simple loading instruction in your Java sources as:
    210 
    211             static {
    212                 System.loadLibrary("foo");
    213             }
    214 
    215 
    216 IV. Tips & Recommendations:
    217 ---------------------------
    218 
    219 * You don't need to import a module before you can reference it!
    220 
    221 * Use import-module at the *end* of your Android.mk to avoid messing with
    222   the result of 'my-dir'. See the description of this function in
    223   docs/ANDROID-MK.html to understand why.
    224 
    225 * It is *strongly* suggested to use a subdirectory for your import tags,
    226   that describes its origin, as in:
    227 
    228         $(call import-module,gtk/glib)
    229 
    230 > or something like:
    231 
    232           $(call import-module,com.example/awesomelib)
    233 
    234   IMPORTANT: THE 'android' IMPORT DIRECTORY, AND ANY OF ITS SUB-DIRECTORIES
    235              IS *RESERVED* FOR NDK USAGE. FEEL FREE TO ORGANIZE YOUR OTHER
    236              IMPORT MODULES AS YOU WANT OTHERWISE.
    237