20

Looks like it's possible, but my script produces odd results:

LOCAL_PATH:= $(call my-dir)
include $(CLEAR_VARS)

include $(LOCAL_PATH)/libos/Android.mk
include $(LOCAL_PATH)/libbase/Android.mk
include $(LOCAL_PATH)/utils/Android.mk

LOCAL_MODULE := native
include $(BUILD_SHARED_LIBRARY)

Only the first include is being parsed fine, other Android.mk files are being seacrhed at odd paths. Suggestions?

Update: I have broken my building environment... It was OK in the office, but at home LOCAL_PATH:= $(call my-dir) defines LOCAL_PATH to NDK dir instead of project dir. This is my batch for building:

set BASHPATH=K:\cygwin\bin\bash
set PROJECTDIR=/cygdrive/h/Alex/Alex/Work/Android/remote-android
set NDKDIR=/cygdrive/h/Alex/Programming_Docs/Android/android-ndk-r6/ndk-build
set APP_BUILD_SCRIPT=/cygdrive/h/Alex/Alex/Work/Android/project/jni/Android.mk
set DEV_ROOT=h:/Alex/Alex/Work/Android/project

%BASHPATH% --login -c "cd %PROJECTDIR% && %NDKDIR%"

Update: I absolutely don't understand how does this thing compose paths. I'm getting errors with paths like "/cygdrive/d/project/jni//cygdrive/d/Soft/project/jni/libos/src/libos.cpp'. This is after I decided to specify all files in the root Android.mk instead of including submodules.

Update 2: No luck, this doesn't work either:

LOCAL_PATH:= $(call my-dir)
# Include makefiles here.
include $(LOCAL_PATH)/libos/Android.mk
include $(LOCAL_PATH)/libbase/Android.mk
include $(LOCAL_PATH)/utils/Android.mk

# Clear variables here.
 include $(CLEAR_VARS)
Violet Giraffe
  • 32,368
  • 48
  • 194
  • 335
  • 2
    I'll go out on a limb and suggest that maybe the first `Android.mk` is redefining `LOCAL_PATH`. Try using some other variable name, like `AARDVARK`, and see what happens. – Beta Aug 04 '11 at 16:36

6 Answers6

21

Pretty late here, but in case somebody reads this question, one way to get past the problem of broken paths(pointing to the ndk insted of your files from the jni) is to have in your jni folder:

include $(call all-subdir-makefiles)

and then in every subfolder of it (libos, libbase and ustils inthe case of OP) an Android.mk of this form:

LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
LOCAL_C_INCLUDES        := $(LOCAL_PATH)
LOCAL_MODULE            := utils
LOCAL_SRC_FILES         := one.c
LOCAL_SRC_FILES         += two.c

where this second Android.mk in with the one.c and two.c files in a subfolder found in the jni folder.

Note that trying something as

LOCAL_PATH_BIS_WEIRD_OTHER_NAME := $(call my-dir)
include $(CLEAR_VARS)
LOCAL_C_INCLUDES        := $(LOCAL_PATH_OTHER_FUNKY_NAME)
LOCAL_MODULE            := utils
LOCAL_SRC_FILES         := one.c
LOCAL_SRC_FILES         += two.c

will lead again to a confused compiler looking for your source code where the ndk is.

So, use the LOCAL_PATH := $(call my-dir) EXACTLY in this form in every subdirectory of the jni and include $(call all-subdir-makefiles) in the jni itself and you shouldn't have problems.

Hope this will help someone.

Edit: this behaviour happens because what is kept in LOCAL_PATH is not deleted by include $(CLEAR_VARS).

Mona Paun
  • 386
  • 3
  • 8
  • Lifesaver! Make messed up all my paths and stuff up until I used this solution... I always dread working with the NDK build system because of quirks like this. – Pär Nils Amsen Jan 31 '18 at 11:07
13

Here's how I do it.

One caveat is that I don't put any of my C++ source code in the build dir, since most of it is platform-independent. This just means that LOCAL_PATH is not a subdir of the project dir, and the only files in /jni are the 2 .mk files.

Anyway, here's a full top-level Android.mk and one of the included ones for a real project:

Top level:

LOCAL_PATH := $(abspath $(call my-dir)/../../../src)

# utility to create paths for included makefiles
local-rel-path = $(patsubst /%,%,$(subst $(LOCAL_PATH),,$(abspath $1)))

include $(CLEAR_VARS)

LOCAL_MODULE := NativeApp

LOCAL_LDLIBS := -lGLESv1_CM

# As opposed to "thumb"
LOCAL_ARM_MODE := arm

LOCAL_SRC_FILES :=

#
# includes
#
# Note that LOCAL_C_INCLUDE is relative to thr NDK root, unlike source paths
# (or you can just make 'em absolute)
#
STL_INC_DIR = /cygdrive/c/STLport-5.2.1/stlport

MY_LOCAL_C_INCLUDES := core satcalc bruce/bruce/inc bruce/gfx/inc bruce/ui/inc bruce/unzip bruce/libpng

LOCAL_C_INCLUDES := $(addprefix $(LOCAL_PATH)/,$(MY_LOCAL_C_INCLUDES)) $(STL_INC_DIR) 

ifeq ($(APP_OPTIM),debug)
# debug
LOCAL_CFLAGS = -DPLATFORM_ANDROID -D_DEBUG -fvisibility=hidden
else
#release
LOCAL_CFLAGS = -DPLATFORM_ANDROID -fvisibility=hidden
endif

LOCAL_STATIC_LIBRARIES := 

#
# Code
#
include $(LOCAL_PATH)/core/Android.mk
include $(LOCAL_PATH)/satcalc/Android.mk
include $(LOCAL_PATH)/bruce/bruce/src/Android.mk
include $(LOCAL_PATH)/bruce/gfx/src/Android.mk
include $(LOCAL_PATH)/bruce/ui/src/Android.mk
include $(LOCAL_PATH)/bruce/unzip/Android.mk
include $(LOCAL_PATH)/bruce/libpng/Android.mk

#
# Build it
#
include $(BUILD_SHARED_LIBRARY)

...and an included Android.mk:

MY_PATH = $(call my-dir)

MY_LOCAL = $(call local-rel-path, $(MY_PATH))

MY_SRC_FILES = Font.cpp Gfx2d_ogles.cpp SgaState.cpp \
        Sprite.cpp TImage.cpp TImageOgles.cpp 

LOCAL_SRC_FILES += $(addprefix $(MY_LOCAL)/,$(MY_SRC_FILES))
jimkberry
  • 1,317
  • 7
  • 8
10

My approah is like this:

LOCAL_PATH:= $(call my-dir)

# Clear variables here.
include $(CLEAR_VARS)

# Current module settings.
LOCAL_MODULE := native
# setup some source files
LOCAL_SRC_FILES := file1.c file2.c
# setup some includes
LOCAL_C_INCLUDES := $(LOCAL_PATH)/libos/include
# setup the included libs for the main module
LOCAL_STATIC_LIBRARIES := libos libbase utils # note that order matters here

include $(BUILD_SHARED_LIBRARY)

# Include makefiles here. Its important that these 
# includes are done after the main module, explanation below.

# create a temp variable with the current path, because it 
# changes after each include
ZPATH := $(LOCAL_PATH)

include $(ZPATH)/libos/Android.mk
include $(ZPATH)/libbase/Android.mk
include $(ZPATH)/utils/Android.mk

Note, that includes are done after the setup of current module variables. This is needed because each include modifies the LOCAL_PATH variable (actually it modifes what $(call my-dir) returns) and thats why includes must be done last.

This will automatically compile all included modules (or clean then if called with clean) and then link with all the included libraries.

This setup was tested in a real project and works correctly.

answer taken from here: https://docs.google.com/document/d/1jDmWgVgorTY_njX68juH5vt0KY_FXWgxkxmi2v_W_a4/edit

user2021201
  • 370
  • 3
  • 10
5

Very late answer here, but I had this problem and none of these solutions were useful. The solution turns out to be straightforward: as detailed here, set a MY_LOCAL_PATH variable and reallocate LOCAL_PATH every time:

MY_LOCAL_PATH := $(call my-dir)

LOCAL_PATH := $(MY_LOCAL_PATH)

... declare one module

include $(LOCAL_PATH)/foo/Android.mk

LOCAL_PATH := $(MY_LOCAL_PATH)

... declare another module
imh0tep
  • 88
  • 1
  • 7
5

You're on the right track. That is the proper way to include Android.mk files within another - it's actually required by the Android make system. One thing to note is that the line to clear variables should appear -after- you include the other makefiles, like this:

LOCAL_PATH:= $(call my-dir)

# Include makefiles here.
include $(LOCAL_PATH)/libos/Android.mk
include $(LOCAL_PATH)/libbase/Android.mk
include $(LOCAL_PATH)/utils/Android.mk

# Clear variables here.
include $(CLEAR_VARS)

# Final settings.
LOCAL_MODULE := native
include $(BUILD_SHARED_LIBRARY)

I'd also mention that there's other important flags you may or may not want to set, including the following (an example from one of my makefiles):

# Settings.
LOCAL_C_INCLUDES             := $(MY_INCLUDES)
LOCAL_STATIC_LIBRARIES       := $(MY_MODULES) 
LOCAL_WHOLE_STATIC_LIBRARIES := $(MY_WHOLE_MODULES) 
LOCAL_LDLIBS                 := -lz -llog -lGLESv1_CM -lGLESv2 
LOCAL_ARM_MODE               := arm
LOCAL_MODULE                 := game

Finally, I've found the documentation that comes embedded within the Android ndk to be especially helpful. Mine is found in the following location:

android-ndk-r6/documentation.html

Let me know if you have further questions. Hope this helps! :)

Kevin Depue
  • 415
  • 1
  • 5
  • 9
  • Also, do I need to specify things like LOCAL_ARM_MODE := arm in every icluded .mk, or only once in top-level? – Violet Giraffe Aug 04 '11 at 20:22
  • 4
    CLEAR_VARS clears all of the "LOCAL_" variables in the makefile with the exception of "LOCAL_PATH". Also, all of the settings are local (hence the "LOCAL_" in the name) so they only apply to the makefile they are in, so you'll have to put them everywhere. Finally, in the documentation, check out the Application.mk file - it can be used to specify flags that apply to all makefiles. :) – Kevin Depue Aug 04 '11 at 21:06
  • Understood, thank you. So, the included .mk cannot redefine the LOCAL_PATH of the top-level .mk? Or is it included so that it is not a standalone entity but rather a part of top-level file? – Violet Giraffe Aug 04 '11 at 21:29
  • 1
    Tried your advice - doesn't work either. I feel I'm losing sanity. – Violet Giraffe Aug 05 '11 at 08:48
  • I always get wrong paths with $(LOCAL_PATH) obtainded by LOCAL_PATH := $(call my-dir), often - path to NDK. Depending on whether I spell LOCAL_SRC_FILES := src/libos.cpp or LOCAL_SRC_FILES := $(LOCAL_PATH)/src/libos.cpp I get different results, always strange and different in different makefiles. I just don't get the logic of parser's operation. – Violet Giraffe Aug 05 '11 at 20:01
0

I test the below code ok.

# I want only second-level mk files, that is the direct sub-directories
# in the current path.
include $(wildcard */*/Android.mk)
# include $(call all-subdir-makefiles)  ## $(wildcard $(call my-dir)/*/Android.mk)
# include $(call all-makefiles-under,$(LOCAL_PATH))

Android.mk

# I dunno why it's an empty result for $(call all-subdir-makefiles).
# $(info [^-^ print-test] all-subdir-makefiles = "$(call all-subdir-makefiles) ")
$(info [print-test] assert "jni/Android.mk" = "$(wildcard */Android.mk)") # print: jni/Android.mk
$(info [print-test] $$(wildcard */*/Android.mk) = "$(wildcard */*/Android.mk)") # print: jni/xxdir/Android.mk

I print the result :

$ cd your_project_path
$ ndk-build
[print-test] assert "jni/Android.mk" = "jni/Android.mk"
[print-test] (wildcard */*/Android.mk) = "jni/HelloWorld/Android.mk jni/MessagePack/Android.mk"
samm
  • 620
  • 10
  • 22