Workaround broken gnumake realpath on Windows.

Also, added missing build scripts for flatc on Windows and fixed
numerous issues in the flatbuffers/android/jni/include.mk makefile.

Tested:
Verified dependent project (motive) can generate flatbuffers headers
with these changes on Android.

Bug: 25780616

Change-Id: I73f0dec8f7a6a7eb4e71951a8f1cd3e0d343a9ff
This commit is contained in:
Stewart Miles 2015-11-18 21:02:13 -08:00
parent 331d2d835c
commit 8212da5d5d
5 changed files with 242 additions and 29 deletions

View File

@ -14,26 +14,29 @@
# misrepresented as being the original software.
# 3. This notice may not be removed or altered from any source distribution.
LOCAL_PATH := $(call my-dir)
LOCAL_PATH := $(call my-dir)/../..
include $(LOCAL_PATH)/android/jni/include.mk
LOCAL_PATH := $(call realpath-portable,$(LOCAL_PATH))
# Empty static library so that other projects can include FlatBuffers as a
# module.
include $(CLEAR_VARS)
LOCAL_MODULE := flatbuffers
LOCAL_EXPORT_C_INCLUDES := $(LOCAL_PATH)/../../include
LOCAL_EXPORT_C_INCLUDES := $(LOCAL_PATH)/include
LOCAL_EXPORT_CPPFLAGS := -std=c++11 -fexceptions -Wall -Wno-literal-suffix
include $(BUILD_STATIC_LIBRARY)
# FlatBuffers test
include $(CLEAR_VARS)
LOCAL_MODULE := FlatBufferTest
LOCAL_SRC_FILES := main.cpp \
../../tests/test.cpp \
../../src/idl_parser.cpp \
../../src/idl_gen_text.cpp \
../../src/idl_gen_fbs.cpp \
../../src/idl_gen_general.cpp \
../../src/reflection.cpp
LOCAL_SRC_FILES := android/jni/main.cpp \
tests/test.cpp \
src/idl_parser.cpp \
src/idl_gen_text.cpp \
src/idl_gen_fbs.cpp \
src/idl_gen_general.cpp \
src/reflection.cpp
LOCAL_LDLIBS := -llog -landroid
LOCAL_STATIC_LIBRARIES := android_native_app_glue flatbuffers
LOCAL_ARM_MODE := arm
@ -41,4 +44,4 @@ include $(BUILD_SHARED_LIBRARY)
$(call import-module,android/native_app_glue)
$(call import-add-path,../..)
$(call import-add-path,$(LOCAL_PATH)/../..)

68
android/jni/build_flatc.bat Executable file
View File

@ -0,0 +1,68 @@
@rem Copyright (c) 2013 Google, Inc.
@rem
@rem This software is provided 'as-is', without any express or implied
@rem warranty. In no event will the authors be held liable for any damages
@rem arising from the use of this software.
@rem Permission is granted to anyone to use this software for any purpose,
@rem including commercial applications, and to alter it and redistribute it
@rem freely, subject to the following restrictions:
@rem 1. The origin of this software must not be misrepresented; you must not
@rem claim that you wrote the original software. If you use this software
@rem in a product, an acknowledgment in the product documentation would be
@rem appreciated but is not required.
@rem 2. Altered source versions must be plainly marked as such, and must not be
@rem misrepresented as being the original software.
@rem 3. This notice may not be removed or altered from any source distribution.
@echo off
setlocal enabledelayedexpansion
set thispath=%~dp0
rem Path to cmake passed in by caller.
set cmake=%1
rem Path to cmake project to build.
set cmake_project_path=%2
rem Newest and oldest version of Visual Studio that it's possible to select.
set visual_studio_version_max=20
set visual_studio_version_min=8
rem Determine the newest version of Visual Studio installed on this machine.
set visual_studio_version=
for /L %%a in (%visual_studio_version_max%,-1,%visual_studio_version_min%) do (
echo Searching for Visual Studio %%a >&2
reg query HKLM\SOFTWARE\Microsoft\VisualStudio\%%a.0 /ve 1>NUL 2>NUL
if !ERRORLEVEL! EQU 0 (
set visual_studio_version=%%a
goto found_vs
)
)
echo Unable to determine whether Visual Studio is installed. >&2
exit /B 1
:found_vs
rem Map Visual Studio version to cmake generator name.
if "%visual_studio_version%"=="8" (
set cmake_generator=Visual Studio 8 2005
)
if "%visual_studio_version%"=="9" (
set cmake_generator=Visual Studio 9 2008
)
if %visual_studio_version% GEQ 10 (
set cmake_generator=Visual Studio %visual_studio_version%
)
rem Set visual studio version variable for msbuild.
set VisualStudioVersion=%visual_studio_version%.0
rem Generate Visual Studio solution.
echo Generating solution for %cmake_generator%. >&2
cd "%cmake_project_path%"
%cmake% -G"%cmake_generator%"
if %ERRORLEVEL% NEQ 0 (
exit /B %ERRORLEVEL%
)
rem Build flatc
python %thispath%\msbuild.py flatc.vcxproj
if ERRORLEVEL 1 exit /B 1

View File

@ -37,6 +37,10 @@
ifeq (,$(FLATBUFFERS_INCLUDE_MK_))
FLATBUFFERS_INCLUDE_MK_ := 1
# Portable version of $(realpath) that omits drive letters on Windows.
realpath-portable = $(join $(filter %:,$(subst :,: ,$1)),\
$(realpath $(filter-out %:,$(subst :,: ,$1))))
PROJECT_OS := $(OS)
ifeq (,$(OS))
PROJECT_OS := $(shell uname -s)
@ -50,26 +54,31 @@ endif
# rebuilt from flatbuffers schemas.
FLATBUFFERS_CMAKELISTS_DIR := \
$(realpath $(dir $(lastword $(MAKEFILE_LIST)))/../..)
$(call realpath-portable,$(dir $(lastword $(MAKEFILE_LIST)))/../..)
# Directory that contains the FlatBuffers compiler.
ifeq (Windows,$(PROJECT_OS))
FLATBUFFERS_FLATC_PATH?=$(CURDIR)/bin
FLATBUFFERS_FLATC := $(FLATBUFFERS_FLATC_PATH)/Debug/flatc.exe
FLATBUFFERS_FLATC_PATH?=$(FLATBUFFERS_CMAKELISTS_DIR)
FLATBUFFERS_FLATC := $(lastword \
$(wildcard $(FLATBUFFERS_FLATC_PATH)/*/flatc.exe) \
$(wildcard $(FLATBUFFERS_FLATC_PATH)/flatc.exe))
endif
ifeq (Linux,$(PROJECT_OS))
FLATBUFFERS_FLATC_PATH?=$(CURDIR)/bin
FLATBUFFERS_FLATC_PATH?=$(FLATBUFFERS_CMAKELISTS_DIR)
FLATBUFFERS_FLATC := $(FLATBUFFERS_FLATC_PATH)/flatc
endif
ifeq (Darwin,$(PROJECT_OS))
FLATBUFFERS_FLATC_PATH?=$(FLATBUFFERS_CMAKELISTS_DIR)
FLATBUFFERS_FLATC := $(FLATBUFFERS_FLATC_PATH)/Debug/flatc
FLATBUFFERS_FLATC := $(lastword \
$(wildcard $(FLATBUFFERS_FLATC_PATH)/*/flatc) \
$(wildcard $(FLATBUFFERS_FLATC_PATH)/flatc))
endif
FLATBUFFERS_FLATC_ARGS?=
# Search for cmake.
CMAKE_ROOT := $(realpath $(LOCAL_PATH)/../../../../../../prebuilts/cmake)
CMAKE_ROOT := \
$(call realpath-portable,$(LOCAL_PATH)/../../../../../../prebuilts/cmake)
ifeq (,$(CMAKE))
ifeq (Linux,$(PROJECT_OS))
CMAKE := $(wildcard $(CMAKE_ROOT)/linux-x86/current/bin/cmake*)
@ -97,15 +106,14 @@ endif
# Generate a host build rule for the flatbuffers compiler.
ifeq (Windows,$(PROJECT_OS))
define build_flatc_recipe
cd & jni\build_flatc.bat $(CMAKE)
$(FLATBUFFERS_CMAKELISTS_DIR)\android\jni\build_flatc.bat \
$(CMAKE) $(FLATBUFFERS_CMAKELISTS_DIR)
endef
endif
ifeq (Linux,$(PROJECT_OS))
define build_flatc_recipe
+mkdir -p bin && \
cd bin && \
$(CMAKE) \
$(FLATBUFFERS_CMAKELISTS_DIR) && \
+cd $(FLATBUFFERS_CMAKELISTS_DIR) && \
$(CMAKE) && \
$(MAKE) flatc
endef
endif
@ -125,6 +133,9 @@ endif
ifeq ($(strip $(FLATBUFFERS_FLATC)),)
flatc_target := build_flatc
.PHONY: $(flatc_target)
FLATBUFFERS_FLATC := \
python $(FLATBUFFERS_CMAKELISTS_DIR)/android/jni/run_flatc.py \
$(FLATBUFFERS_CMAKELISTS_DIR)
else
flatc_target := $(FLATBUFFERS_FLATC)
endif
@ -166,6 +177,15 @@ $(eval \
$(foreach include,$(4),-I $(include)) -o $$(dir $$@) -c $$<)
endef
# TODO: Remove when the LOCAL_PATH expansion bug in the NDK is fixed.
# Override the default behavior of local-source-file-path to workaround
# a bug which prevents the build of deeply nested projects when NDK_OUT is
# set.
local-source-file-path=\
$(if $(call host-path-is-absolute,$1),$1,$(call \
realpath-portable,$(LOCAL_PATH)/$1))
# $(flatbuffers_header_build_rules schema_files,schema_dir,output_dir,\
# schema_include_dirs,src_files,[build_target],[dependencies]))
#
@ -187,6 +207,13 @@ endef
# $(call flatbuffers_header_build_rules,$(MY_PROJ_SCHEMA_FILES),\
# $(MY_PROJ_SCHEMA_DIR),$(MY_PROJ_GENERATED_OUTPUT_DIR),
# $(MY_PROJ_SCHEMA_INCLUDE_DIRS),$(LOCAL_SRC_FILES))
#
# NOTE: Due problesm with path processing in ndk-build when presented with
# deeply nested projects must redefine LOCAL_PATH after include this makefile
# using:
#
# LOCAL_PATH := $(call realpath-portable,$(LOCAL_PATH))
#
define flatbuffers_header_build_rules
$(foreach schema,$(1),\
$(call flatbuffers_header_build_rule,\
@ -207,12 +234,4 @@ $(if $(7),\
$(eval $(6): $(dependency))),)
endef
# TODO: Remove when the LOCAL_PATH expansion bug in the NDK is fixed.
# Override the default behavior of local-source-file-path to workaround
# a bug which prevents the build of deeply nested projects when NDK_OUT is
# set.
local-source-file-path = \
$(if $(call host-path-is-absolute,$1),$1,$(realpath $(LOCAL_PATH)/$1))
endif # FLATBUFFERS_INCLUDE_MK_

77
android/jni/msbuild.py Normal file
View File

@ -0,0 +1,77 @@
#!/usr/bin/python
# Copyright 2014 Google Inc. All rights reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
"""Simple script that locates the newest MSBuild in one of several locations.
This script will find the highest version number of MSBuild and run it,
passing its arguments through to MSBuild.
"""
import glob
import os
import re
import string
import subprocess
import sys
SYSTEMROOT = os.getenv("SYSTEMROOT", "c:\\windows")
PROGRAM_FILES = os.getenv("ProgramFiles", "c:\\Program Files")
PROGRAM_FILES_X86 = os.getenv("ProgramFiles(x86)", "c:\\Program Files (x86)")
SEARCH_FOLDERS = [ PROGRAM_FILES + "\\MSBuild\\*\\Bin\\MSBuild.exe",
PROGRAM_FILES_X86 + "\\MSBuild\\*\\Bin\\MSBuild.exe",
SYSTEMROOT + "\\Microsoft.NET\Framework\\*\\MSBuild.exe" ]
def compare_version(a, b):
"""Compare two version number strings of the form W.X.Y.Z.
The numbers are compared most-significant to least-significant.
For example, 12.345.67.89 > 2.987.88.99.
Args:
a: First version number string to compare
b: Second version number string to compare
Returns:
0 if the numbers are identical, a positive number if 'a' is larger, and
a negative number if 'b' is larger.
"""
aa = string.split(a, ".")
bb = string.split(b, ".")
for i in range(0, 4):
if aa[i] != bb[i]:
return cmp(int(aa[i]), int(bb[i]))
return 0
def main():
msbuilds = []
for folder in SEARCH_FOLDERS:
for file in glob.glob(folder):
p = subprocess.Popen([file, "/version"], stdout=subprocess.PIPE)
out, err = p.communicate()
match = re.search("^[0-9]+\\.[0-9]+\\.[0-9]+\\.[0-9]+$", out, re.M)
if match:
msbuilds.append({ 'ver':match.group(), 'exe':file })
msbuilds.sort(lambda x, y: compare_version(x['ver'], y['ver']), reverse=True)
if len(msbuilds) == 0:
print "Unable to find MSBuild.\n"
return -1;
cmd = [msbuilds[0]['exe']]
cmd.extend(sys.argv[1:])
return subprocess.call(cmd)
if __name__ == '__main__':
sys.exit(main())

46
android/jni/run_flatc.py Executable file
View File

@ -0,0 +1,46 @@
#!/usr/bin/python
# Copyright 2015 Google Inc. All rights reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
import os
import platform
import subprocess
import sys
EXECUTABLE_EXTENSION = '.exe' if platform.system() == 'Windows' else ''
# Paths to search for flatc relative to the current working directory.
FLATC_SEARCH_PATHS = [os.path.curdir, 'Release', 'Debug']
def main():
"""Script that finds and runs flatc built from source."""
if len(sys.argv) < 2:
sys.stderr.write('Usage: run_flatc.py flatbuffers_dir [flatc_args]\n')
return 1
cwd = os.getcwd()
flatc = ''
flatbuffers_dir = sys.argv[1]
for path in FLATC_SEARCH_PATHS:
current = os.path.join(flatbuffers_dir, path,
'flatc' + EXECUTABLE_EXTENSION)
if os.path.exists(current):
flatc = current
break
if not flatc:
sys.stderr.write('flatc not found\n')
return 1
command = [flatc] + sys.argv[2:]
return subprocess.call(command)
if __name__ == '__main__':
sys.exit(main())