Search code examples
androidwindowsandroid-ndkndk-build

Hello-Jni on Windows, Android NDK - build-local.mk: No such file


I have tried scouring the Internet and StackOverflow (too many articles to count) but cannot find assistance that is all of these things:

  1. More recent than 2013
  2. Does not require Cygwin if developing on Windows
  3. Is geared to Android Studio, NOT Eclipse.

I am diving head first into Android development for the very first time and the project I have newly joined depends on developing with the NDK. I've been reading the docs that come with the NDK but have run into a stone wall with this sample.

I am trying to build hello-jni, the sample project within the NDK. Here is my environment:

  • Android Studio 1.4 (most up to date, stable version currently available)
  • NDK version: r10e
  • OS: Windows 7

Contents of Application.mk file:

APP_ABI := all64 // Came with 'all', read somewhere on SO that it 
                 // should be 'all64'. Result is the same.

Contents of Android.mk file:

LOCAL_PATH := $(call my-dir)

include $(CLEAR_VARS)

LOCAL_MODULE    := hello-jni
LOCAL_SRC_FILES := hello-jni.c

include $(BUILD_SHARED_LIBRARY)

My PATH environment variable includes a path to my NDK root folder and to \prebuilt\windows-x86_64\bin (because I read on one of many articles that it should.) When I navigate to the hello-jni root folder though, and call ndk-build, I am only presented with errors.

c:\NDK\android-ndk-r10e\build\core\build-local.mk:40: c:/NDK/android-ndk-r10e/build/core/build/core/init.mk: No such file or directory
c:\NDK\android-ndk-r10e\build\core\build-local.mk:191: \add-application.mk: No such file or directory
c:\NDK\android-ndk-r10e\build\core\build-local.mk:206: \setup-imports.mk: No such file or directory
c:\NDK\android-ndk-r10e\build\core\build-local.mk:223: \build-all.mk: No such file or directory
make.exe: *** No rule to make target `\build-all.mk'.  Stop.

If anything else is required for people to assist me, say the word I will provide what I can. All help will be greatly appreciated.

EDIT: Most of the articles of I've seen for Windows mention Cygwin, but according to the docs, it isn't needed. If this is incorrect, please correct me?

Except from \android-ndk-r10e\docs\Programmers_Guide\html\md_3__key__topics__building__s_t_a_n_d_a_l_o_n_e-_t_o_o_l_c_h_a_i_n.html

Windows support

The Windows binaries do not depend on Cygwin. The good news is that they are thus faster, the bad news is that they do not understand the Cygwin path specification like /cygdrive/c/foo/bar (instead of C:/foo/bar).

The NDK build system ensures that all paths passed to the compiler from Cygwin are automatically translated, and deals with other horrors for you. If you have a custom build system, you may need to deal with the problem yourself.


Solution

  • I can't take the credit for this answer, a coworker kindly sleuthed it out for me. When he found the answer, I demanded to know what else he had done, because clearly I must have missed some magic? I only saw him switch two lines in a make file, there had to be more? Alas, no. This alone was the source of my woe.

    While I'm hesitant to call it an error within the NDK because I don't know how it works with Cygwin, neither of us can understand how this has ever worked for anyone building in native Windows, as the line I will be referencing is recorded in the git repository as being added back in 2011 or 2010. ( https://android.googlesource.com/platform/ndk/+/master/build/core/build-local.mk )

    To aid explanation, here is the first line of my error again:

    c:\NDK\android-ndk-r10e\build\core\build-local.mk:40: c:/NDK/android-ndk-r10e/build/core/build/core/init.mk: No such file or directory

    The first file that is unable to found is ...build/core/build/core/init.mk, which of course doesn't exist because build/core should not be repeated.

    The command that begins the build, ndk-build.cmd, calls build\core\build-local.mk to begin the process. Inside this file the environment variable, NDK_ROOT, is recreated upon entry. Whatever my NDK_ROOT is, is irrelevant.

    NDK_ROOT := $(dir $(lastword $(MAKEFILE_LIST)))
    NDK_ROOT := $(strip $(NDK_ROOT:%build/core/=%))
    NDK_ROOT := $(subst \,/,$(NDK_ROOT))
    NDK_ROOT := $(NDK_ROOT:%/=%)
    .
    .
    .
    

    The second line strips the end of the current directory (the build/core/) from the end of my new NDK_ROOT, because the true root should be the parent directory of build and because it will be added back later to find all those 'missing' files. That's fine, except note the forward-slashes (/) used in the search. Windows does not use (or in my experience at least, usually does not return) forward-slashes, though it will often parse them if that is what it's given. (When changing directories, for example, I've found either to be acceptable as long as I already know where I need to go. Tab completion does not seem to function if my path ends with a /.)

    Oh, but look at the third line (added way back in 2011)! A substitution is made of every backslash (\) in NDK_ROOT, replaced with forward-slash (/). So the replacement of build/core/ should go off without a hitch, right? Problem: it's too late.

    The strip call has already occurred and if the NDK_ROOT received a path with backslashes instead of forward-slashes, build/core/ is never found and stripped from the variable. How did my coworker fix it? Easy. He switched the lines around:

    NDK_ROOT := $(dir $(lastword $(MAKEFILE_LIST)))
    NDK_ROOT := $(subst \,/,$(NDK_ROOT))
    NDK_ROOT := $(strip $(NDK_ROOT:%build/core/=%))
    NDK_ROOT := $(NDK_ROOT:%/=%)
    

    My hello-jni project now builds, along with Teapot, another sample from the NDK, which I tried just to be sure. And so does native-audio, native-codec, native-media, and More Teapots. Haven't tried to run them yet... but I have no build errors.

    I don't know if this fix will break Cygwin users, I don't have that on my box. I also don't know if it would break Linux environments because I don't have Linux on my box. But this may help native Windows users, and I hope so, because I uselessly beat my head on this for 3 or 4 days and read more SO articles than I ever care to at once.