diff --git a/android/jni/Android.mk b/android/jni/Android.mk index e00713528..1d89d8864 100755 --- a/android/jni/Android.mk +++ b/android/jni/Android.mk @@ -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)/../..) diff --git a/android/jni/build_flatc.bat b/android/jni/build_flatc.bat new file mode 100755 index 000000000..0b3f2ad18 --- /dev/null +++ b/android/jni/build_flatc.bat @@ -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 diff --git a/android/jni/include.mk b/android/jni/include.mk index 02d345e4e..f0f20ec5b 100644 --- a/android/jni/include.mk +++ b/android/jni/include.mk @@ -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_ - diff --git a/android/jni/msbuild.py b/android/jni/msbuild.py new file mode 100644 index 000000000..5f92d70f4 --- /dev/null +++ b/android/jni/msbuild.py @@ -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()) diff --git a/android/jni/run_flatc.py b/android/jni/run_flatc.py new file mode 100755 index 000000000..cda13bbf8 --- /dev/null +++ b/android/jni/run_flatc.py @@ -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())