1# Copyright 2014 Google Inc. All rights reserved.
2#
3# Licensed under the Apache License, Version 2.0 (the "License");
4# you may not use this file except in compliance with the License.
5# You may obtain a copy of the License at
6#
7#     http://www.apache.org/licenses/LICENSE-2.0
8#
9# Unless required by applicable law or agreed to in writing, software
10# distributed under the License is distributed on an "AS IS" BASIS,
11# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12# See the License for the specific language governing permissions and
13# limitations under the License.
14
15# This file contains utility functions for Android projects using Flatbuffers.
16# To use this file, include it in your project's Android.mk by calling near the
17# top of your android makefile like so:
18#
19#     include $(FLATBUFFERS_DIR)/android/jni/include.mk
20#
21# You will also need to import the flatbuffers module using the standard
22# import-module function.
23#
24# The main functionality this file provides are the following functions:
25# flatbuffers_fbs_to_h: Converts flatbuffer schema paths to header paths.
26# flatbuffers_header_build_rule:
27#     Creates a build rule for a schema's generated header. This build rule
28#     has a dependency on the flatc compiler which will be built if necessary.
29# flatbuffers_header_build_rules:
30#     Creates build rules for generated headers for each schema listed and sets
31#     up depenedendies.
32#
33# More information and example usage can be found in the comments preceeding
34# each function.
35
36# Targets to build the Flatbuffers compiler as well as some utility definitions
37ifeq (,$(FLATBUFFERS_INCLUDE_MK_))
38FLATBUFFERS_INCLUDE_MK_ := 1
39
40# Portable version of $(realpath) that omits drive letters on Windows.
41realpath-portable = $(join $(filter %:,$(subst :,: ,$1)),\
42                      $(realpath $(filter-out %:,$(subst :,: ,$1))))
43
44PROJECT_OS := $(OS)
45ifeq (,$(OS))
46PROJECT_OS := $(shell uname -s)
47else
48ifneq ($(findstring Windows,$(PROJECT_OS)),)
49PROJECT_OS := Windows
50endif
51endif
52
53# The following block generates build rules which result in headers being
54# rebuilt from flatbuffers schemas.
55
56FLATBUFFERS_CMAKELISTS_DIR := \
57  $(call realpath-portable,$(dir $(lastword $(MAKEFILE_LIST)))/../..)
58
59# Directory that contains the FlatBuffers compiler.
60ifeq (Windows,$(PROJECT_OS))
61FLATBUFFERS_FLATC_PATH?=$(FLATBUFFERS_CMAKELISTS_DIR)
62FLATBUFFERS_FLATC := $(lastword \
63                       $(wildcard $(FLATBUFFERS_FLATC_PATH)/*/flatc.exe) \
64                       $(wildcard $(FLATBUFFERS_FLATC_PATH)/flatc.exe))
65endif
66ifeq (Linux,$(PROJECT_OS))
67FLATBUFFERS_FLATC_PATH?=$(FLATBUFFERS_CMAKELISTS_DIR)
68FLATBUFFERS_FLATC := $(FLATBUFFERS_FLATC_PATH)/flatc
69endif
70ifeq (Darwin,$(PROJECT_OS))
71FLATBUFFERS_FLATC_PATH?=$(FLATBUFFERS_CMAKELISTS_DIR)
72FLATBUFFERS_FLATC := $(lastword \
73                       $(wildcard $(FLATBUFFERS_FLATC_PATH)/*/flatc) \
74                       $(wildcard $(FLATBUFFERS_FLATC_PATH)/flatc))
75endif
76
77FLATBUFFERS_FLATC_ARGS?=
78
79# Search for cmake.
80CMAKE_ROOT := \
81  $(call realpath-portable,$(LOCAL_PATH)/../../../../../../prebuilts/cmake)
82ifeq (,$(CMAKE))
83ifeq (Linux,$(PROJECT_OS))
84CMAKE := $(wildcard $(CMAKE_ROOT)/linux-x86/current/bin/cmake*)
85endif
86ifeq (Darwin,$(PROJECT_OS))
87CMAKE := \
88  $(wildcard $(CMAKE_ROOT)/darwin-x86_64/current/*.app/Contents/bin/cmake)
89endif
90ifeq (Windows,$(PROJECT_OS))
91CMAKE := $(wildcard $(CMAKE_ROOT)/windows/current/bin/cmake*)
92endif
93endif
94ifeq (,$(CMAKE))
95CMAKE := cmake
96endif
97
98# Windows friendly portable local path.
99# GNU-make doesn't like : in paths, must use relative paths on Windows.
100ifeq (Windows,$(PROJECT_OS))
101PORTABLE_LOCAL_PATH =
102else
103PORTABLE_LOCAL_PATH = $(LOCAL_PATH)/
104endif
105
106# Generate a host build rule for the flatbuffers compiler.
107ifeq (Windows,$(PROJECT_OS))
108define build_flatc_recipe
109	$(FLATBUFFERS_CMAKELISTS_DIR)\android\jni\build_flatc.bat \
110        $(CMAKE) $(FLATBUFFERS_CMAKELISTS_DIR)
111endef
112endif
113ifeq (Linux,$(PROJECT_OS))
114define build_flatc_recipe
115	+cd $(FLATBUFFERS_CMAKELISTS_DIR) && \
116      $(CMAKE) . && \
117      $(MAKE) flatc
118endef
119endif
120ifeq (Darwin,$(PROJECT_OS))
121define build_flatc_recipe
122	cd $(FLATBUFFERS_CMAKELISTS_DIR) && "$(CMAKE)" -GXcode . && \
123        xcodebuild -target flatc
124endef
125endif
126ifeq (,$(build_flatc_recipe))
127ifeq (,$(FLATBUFFERS_FLATC))
128$(error flatc binary not found!)
129endif
130endif
131
132# Generate a build rule for flatc.
133ifeq ($(strip $(FLATBUFFERS_FLATC)),)
134flatc_target := build_flatc
135.PHONY: $(flatc_target)
136FLATBUFFERS_FLATC := \
137  python $(FLATBUFFERS_CMAKELISTS_DIR)/android/jni/run_flatc.py \
138    $(FLATBUFFERS_CMAKELISTS_DIR)
139else
140flatc_target := $(FLATBUFFERS_FLATC)
141endif
142$(flatc_target):
143	$(call build_flatc_recipe)
144
145# $(flatbuffers_fbs_to_h schema_dir,output_dir,path)
146#
147# Convert the specified schema path to a Flatbuffers generated header path.
148# For example:
149#
150# $(call flatbuffers_fbs_to_h,$(MY_PROJ_DIR)/schemas,\
151#   $(MY_PROJ_DIR)/gen/include,$(MY_PROJ_DIR)/schemas/example.fbs)
152#
153# This will convert the file path `$(MY_PROJ_DIR)/schemas/example.fbs)` to
154# `$(MY_PROJ_DIR)/gen/include/example_generated.h`
155define flatbuffers_fbs_to_h
156$(subst $(1),$(2),$(patsubst %.fbs,%_generated.h,$(3)))
157endef
158
159# $(flatbuffers_header_build_rule schema_file,schema_dir,output_dir,\
160#   schema_include_dirs)
161#
162# Generate a build rule that will convert a Flatbuffers schema to a generated
163# header derived from the schema filename using flatbuffers_fbs_to_h. For
164# example:
165#
166# $(call flatbuffers_header_build_rule,$(MY_PROJ_DIR)/schemas/example.fbs,\
167#   $(MY_PROJ_DIR)/schemas,$(MY_PROJ_DIR)/gen/include)
168#
169# The final argument, schema_include_dirs, is optional and is only needed when
170# the schema files depend on other schema files outside their own directory.
171define flatbuffers_header_build_rule
172$(eval \
173  $(call flatbuffers_fbs_to_h,$(2),$(3),$(1)): $(1) $(flatc_target)
174	$(call host-echo-build-step,generic,Generate) \
175      $(subst $(LOCAL_PATH)/,,$(call flatbuffers_fbs_to_h,$(2),$(3),$(1)))
176	$(hide) $$(FLATBUFFERS_FLATC) $(FLATBUFFERS_FLATC_ARGS) \
177      $(foreach include,$(4),-I $(include)) -o $$(dir $$@) -c $$<)
178endef
179
180# TODO: Remove when the LOCAL_PATH expansion bug in the NDK is fixed.
181# Override the default behavior of local-source-file-path to workaround
182# a bug which prevents the build of deeply nested projects when NDK_OUT is
183# set.
184local-source-file-path=\
185$(if $(call host-path-is-absolute,$1),$1,$(call \
186    realpath-portable,$(LOCAL_PATH)/$1))
187
188
189# $(flatbuffers_header_build_rules schema_files,schema_dir,output_dir,\
190#   schema_include_dirs,src_files,[build_target],[dependencies]))
191#
192# $(1) schema_files: Space separated list of flatbuffer schema files.
193# $(2) schema_dir: Directory containing the flatbuffer schemas.
194# $(3) output_dir: Where to place the generated files.
195# $(4) schema_include_dirs: Directories to include when generating schemas.
196# $(5) src_files: Files that should depend upon the headers generated from the
197#   flatbuffer schemas.
198# $(6) build_target: Name of a build target that depends upon all generated
199#   headers.
200# $(7) dependencies: Space seperated list of additional build targets src_files
201#   should depend upon.
202#
203# Use this in your own Android.mk file to generate build rules that will
204# generate header files for your flatbuffer schemas as well as automatically
205# set your source files to be dependent on the generated headers. For example:
206#
207# $(call flatbuffers_header_build_rules,$(MY_PROJ_SCHEMA_FILES),\
208#   $(MY_PROJ_SCHEMA_DIR),$(MY_PROJ_GENERATED_OUTPUT_DIR),
209#   $(MY_PROJ_SCHEMA_INCLUDE_DIRS),$(LOCAL_SRC_FILES))
210#
211# NOTE: Due problesm with path processing in ndk-build when presented with
212# deeply nested projects must redefine LOCAL_PATH after include this makefile
213# using:
214#
215# LOCAL_PATH := $(call realpath-portable,$(LOCAL_PATH))
216#
217define flatbuffers_header_build_rules
218$(foreach schema,$(1),\
219  $(call flatbuffers_header_build_rule,\
220    $(schema),$(strip $(2)),$(strip $(3)),$(strip $(4))))\
221$(foreach src,$(strip $(5)),\
222  $(eval $(call local-source-file-path,$(src)): \
223    $(foreach schema,$(strip $(1)),\
224      $(call flatbuffers_fbs_to_h,$(strip $(2)),$(strip $(3)),$(schema)))))\
225$(if $(6),\
226  $(foreach schema,$(strip $(1)),\
227    $(eval $(6): \
228      $(call flatbuffers_fbs_to_h,$(strip $(2)),$(strip $(3)),$(schema)))),)\
229$(if $(7),\
230  $(foreach src,$(strip $(5)),\
231      $(eval $(call local-source-file-path,$(src)): $(strip $(7)))),)\
232$(if $(7),\
233  $(foreach dependency,$(strip $(7)),\
234      $(eval $(6): $(dependency))),)
235endef
236
237endif  # FLATBUFFERS_INCLUDE_MK_
238