common.mk revision 7d4cd473f85ac64c3747c96c277f9e506a0d2246
1# Copyright (c) 2012 The Chromium Authors. All rights reserved.
2# Use of this source code is governed by a BSD-style license that can be
3# found in the LICENSE file.
4
5#
6# GNU Make based build file.  For details on GNU Make see:
7#   http://www.gnu.org/software/make/manual/make.html
8#
9
10#
11# Toolchain
12#
13# By default the VALID_TOOLCHAINS list contains newlib and glibc.  If your
14# project only builds in one or the other then this should be overridden
15# accordingly.
16#
17VALID_TOOLCHAINS ?= newlib glibc
18TOOLCHAIN ?= $(word 1,$(VALID_TOOLCHAINS))
19
20
21#
22# Top Make file, which we want to trigger a rebuild on if it changes
23#
24TOP_MAKE := $(word 1,$(MAKEFILE_LIST))
25
26
27#
28# Figure out which OS we are running on.
29#
30GETOS = python $(NACL_SDK_ROOT)/tools/getos.py
31OSNAME := $(shell $(GETOS))
32
33
34#
35# TOOLCHAIN=all recursively calls this Makefile for all VALID_TOOLCHAINS.
36#
37ifeq ($(TOOLCHAIN),all)
38
39# Define the default target
40all:
41
42#
43# Generate a new MAKE command for each TOOLCHAIN.
44#
45# Note: We use targets for each toolchain (instead of an explicit recipe) so
46# each toolchain can be built in parallel.
47#
48# $1 = Toolchain Name
49#
50define TOOLCHAIN_RULE
51TOOLCHAIN_TARGETS += $(1)_TARGET
52.PHONY: $(1)_TARGET
53$(1)_TARGET:
54	+$(MAKE) TOOLCHAIN=$(1) $(MAKECMDGOALS)
55endef
56
57#
58# The target for all versions
59#
60USABLE_TOOLCHAINS=$(filter $(OSNAME) newlib glibc pnacl,$(VALID_TOOLCHAINS))
61
62ifeq ($(NO_HOST_BUILDS),1)
63USABLE_TOOLCHAINS:=$(filter-out $(OSNAME),$(USABLE_TOOLCHAINS))
64endif
65
66# Define the toolchain targets for all usable toolchains via the macro.
67$(foreach tool,$(USABLE_TOOLCHAINS),$(eval $(call TOOLCHAIN_RULE,$(tool))))
68
69.PHONY: all clean install
70all: $(TOOLCHAIN_TARGETS)
71clean: $(TOOLCHAIN_TARGETS)
72install: $(TOOLCHAIN_TARGETS)
73
74else  # TOOLCHAIN=all
75
76#
77# Verify we selected a valid toolchain for this example
78#
79ifeq (,$(findstring $(TOOLCHAIN),$(VALID_TOOLCHAINS)))
80  $(warning Availbile choices are: $(VALID_TOOLCHAINS))
81  $(error Can not use TOOLCHAIN=$(TOOLCHAIN) on this example.)
82endif
83
84
85#
86# Build Configuration
87#
88# The SDK provides two sets of libraries, Debug and Release.  Debug libraries
89# are compiled without optimizations to make debugging easier.  By default
90# this will build a Debug configuration.
91#
92CONFIG ?= Debug
93
94
95#
96# Note for Windows:
97#   The GCC and LLVM toolchains (include the version of Make.exe that comes
98# with the SDK) expect and are capable of dealing with the '/' seperator.
99# For this reason, the tools in the SDK, including Makefiles and build scripts
100# have a preference for POSIX style command-line arguments.
101#
102# Keep in mind however that the shell is responsible for command-line escaping,
103# globbing, and variable expansion, so those may change based on which shell
104# is used.  For Cygwin shells this can include automatic and incorrect expansion
105# of response files (files starting with '@').
106#
107# Disable DOS PATH warning when using Cygwin based NaCl tools on Windows.
108#
109ifeq ($(OSNAME),win)
110  CYGWIN?=nodosfilewarning
111  export CYGWIN
112endif
113
114
115#
116# If NACL_SDK_ROOT is not already set, then set it relative to this makefile.
117#
118THIS_MAKEFILE := $(CURDIR)/$(lastword $(MAKEFILE_LIST))
119NACL_SDK_ROOT ?= $(realpath $(dir $(THIS_MAKEFILE))/..)
120
121
122#
123# Check that NACL_SDK_ROOT is set to a valid location.
124# We use the existence of tools/oshelpers.py to verify the validity of the SDK
125# root.
126#
127ifeq (,$(wildcard $(NACL_SDK_ROOT)/tools/oshelpers.py))
128  $(error NACL_SDK_ROOT is set to an invalid location: $(NACL_SDK_ROOT))
129endif
130
131
132#
133# If this makefile is part of a valid nacl SDK, but NACL_SDK_ROOT is set
134# to a different location this is almost certainly a local configuration
135# error.
136#
137LOCAL_ROOT := $(realpath $(dir $(THIS_MAKEFILE))/..)
138ifneq (,$(wildcard $(LOCAL_ROOT)/tools/oshelpers.py))
139  ifneq ($(realpath $(NACL_SDK_ROOT)), $(realpath $(LOCAL_ROOT)))
140    $(error common.mk included from an SDK that does not match the current NACL_SDK_ROOT)
141  endif
142endif
143
144
145#
146# Alias for standard POSIX file system commands
147#
148OSHELPERS = python $(NACL_SDK_ROOT)/tools/oshelpers.py
149WHICH := $(OSHELPERS) which
150ifdef V
151RM := $(OSHELPERS) rm
152CP := $(OSHELPERS) cp
153MKDIR := $(OSHELPERS) mkdir
154MV := $(OSHELPERS) mv
155else
156RM := @$(OSHELPERS) rm
157CP := @$(OSHELPERS) cp
158MKDIR := @$(OSHELPERS) mkdir
159MV := @$(OSHELPERS) mv
160endif
161
162
163
164#
165# Compute path to requested NaCl Toolchain
166#
167TC_PATH := $(abspath $(NACL_SDK_ROOT)/toolchain)
168
169
170#
171# Check for required minimum SDK version.
172#
173ifdef NACL_SDK_VERSION_MIN
174  VERSION_CHECK:=$(shell $(GETOS) --check-version=$(NACL_SDK_VERSION_MIN) 2>&1)
175  ifneq ($(VERSION_CHECK),)
176    $(error $(VERSION_CHECK))
177  endif
178endif
179
180
181#
182# The default target
183#
184# If no targets are specified on the command-line, the first target listed in
185# the makefile becomes the default target.  By convention this is usually called
186# the 'all' target.  Here we leave it blank to be first, but define it later
187#
188all:
189.PHONY: all
190
191
192#
193# The install target is used to install built libraries to thier final destination.
194# By default this is the NaCl SDK 'lib' folder.
195#
196install:
197.PHONY: install
198
199
200OUTBASE ?= .
201OUTDIR := $(OUTBASE)/$(TOOLCHAIN)/$(CONFIG)
202STAMPDIR ?= $(OUTDIR)
203LIBDIR ?= $(NACL_SDK_ROOT)/lib
204
205
206#
207# Target to remove temporary files
208#
209.PHONY: clean
210clean:
211	$(RM) -f $(TARGET).nmf
212	$(RM) -rf $(OUTDIR)
213	$(RM) -rf user-data-dir
214
215
216#
217# Rules for output directories.
218#
219# Output will be places in a directory name based on Toolchain and configuration
220# be default this will be "newlib/Debug".  We use a python wrapped MKDIR to
221# proivde a cross platform solution. The use of '|' checks for existance instead
222# of timestamp, since the directory can update when files change.
223#
224%dir.stamp :
225	$(MKDIR) -p $(dir $@)
226	@echo Directory Stamp > $@
227
228
229#
230# Dependency Macro
231#
232# $1 = Name of stamp
233# $2 = Directory for the sub-make
234# $3 = Extra Settings
235#
236define DEPEND_RULE
237ifndef $(IGNORE_DEPS)
238.PHONY: rebuild_$(1)
239
240rebuild_$(1) :| $(STAMPDIR)/dir.stamp
241ifeq (,$(2))
242	+$(MAKE) -C $(NACL_SDK_ROOT)/src/$(1) STAMPDIR=$(abspath $(STAMPDIR)) $(abspath $(STAMPDIR)/$(1).stamp) $(3)
243else
244	+$(MAKE) -C $(2) STAMPDIR=$(abspath $(STAMPDIR)) $(abspath $(STAMPDIR)/$(1).stamp) $(3)
245endif
246
247all: rebuild_$(1)
248$(STAMPDIR)/$(1).stamp: rebuild_$(1)
249
250else
251
252.PHONY: $(STAMPDIR)/$(1).stamp
253$(STAMPDIR)/$(1).stamp:
254	@echo Ignore $(1)
255endif
256endef
257
258
259ifeq ($(TOOLCHAIN),win)
260HOST_EXT = .dll
261else
262HOST_EXT = .so
263endif
264
265
266#
267# Common Compile Options
268#
269ifeq ($(CONFIG),Release)
270POSIX_FLAGS ?= -g -O2 -pthread -MMD
271else
272POSIX_FLAGS ?= -g -O0 -pthread -MMD -DNACL_SDK_DEBUG
273endif
274
275NACL_CFLAGS ?= -Wno-long-long -Werror
276NACL_CXXFLAGS ?= -Wno-long-long -Werror
277NACL_LDFLAGS ?= -Wl,-as-needed
278
279#
280# Default Paths
281#
282ifeq (,$(findstring $(TOOLCHAIN),linux mac win))
283INC_PATHS ?= $(NACL_SDK_ROOT)/include $(EXTRA_INC_PATHS)
284else
285INC_PATHS ?= $(NACL_SDK_ROOT)/include/$(OSNAME) $(NACL_SDK_ROOT)/include $(EXTRA_INC_PATHS)
286endif
287
288LIB_PATHS ?= $(NACL_SDK_ROOT)/lib $(EXTRA_LIB_PATHS)
289
290#
291# Define a LOG macro that allow a command to be run in quiet mode where
292# the command echoed is not the same as the actual command executed.
293# The primary use case for this is to avoid echoing the full compiler
294# and linker command in the default case.  Defining V=1 will restore
295# the verbose behavior
296#
297# $1 = The name of the tool being run
298# $2 = The target file being built
299# $3 = The full command to run
300#
301ifdef V
302define LOG
303$(3)
304endef
305else
306ifeq ($(OSNAME),win)
307define LOG
308@echo   $(1) $(2) && $(3)
309endef
310else
311define LOG
312@echo "  $(1) $(2)" && $(3)
313endef
314endif
315endif
316
317
318#
319# Convert a source path to a object file path.
320#
321# $1 = Source Name
322# $2 = Arch suffix
323#
324define SRC_TO_OBJ
325$(OUTDIR)/$(basename $(subst ..,__,$(1)))$(2).o
326endef
327
328
329#
330# Convert a source path to a dependency file path.
331#
332# $1 = Source Name
333# $2 = Arch suffix
334#
335define SRC_TO_DEP
336$(patsubst %.o,%.d,$(call SRC_TO_OBJ,$(1),$(2)))
337endef
338
339
340#
341# If the requested toolchain is a NaCl or PNaCl toolchain, the use the
342# macros and targets defined in nacl.mk, otherwise use the host sepecific
343# macros and targets.
344#
345ifneq (,$(findstring $(TOOLCHAIN),linux mac))
346include $(NACL_SDK_ROOT)/tools/host_gcc.mk
347endif
348
349ifneq (,$(findstring $(TOOLCHAIN),win))
350include $(NACL_SDK_ROOT)/tools/host_vc.mk
351endif
352
353ifneq (,$(findstring $(TOOLCHAIN),glibc newlib))
354include $(NACL_SDK_ROOT)/tools/nacl_gcc.mk
355endif
356
357ifneq (,$(findstring $(TOOLCHAIN),pnacl))
358include $(NACL_SDK_ROOT)/tools/nacl_llvm.mk
359endif
360
361#
362# File to redirect to to in order to hide output.
363#
364ifeq ($(OSNAME),win)
365DEV_NULL = nul
366else
367DEV_NULL = /dev/null
368endif
369
370#
371# Assign a sensible default to CHROME_PATH.
372#
373CHROME_PATH ?= $(shell python $(NACL_SDK_ROOT)/tools/getos.py --chrome 2> $(DEV_NULL))
374
375#
376# Verify we can find the Chrome executable if we need to launch it.
377#
378.PHONY: check_for_chrome
379check_for_chrome:
380ifeq (,$(wildcard $(CHROME_PATH)))
381	$(warning No valid Chrome found at CHROME_PATH=$(CHROME_PATH))
382	$(error Set CHROME_PATH via an environment variable, or command-line.)
383else
384	$(warning Using chrome at: $(CHROME_PATH))
385endif
386
387
388#
389# Variables for running examples with Chrome.
390#
391RUN_PY := python $(NACL_SDK_ROOT)/tools/run.py
392
393# Add this to launch Chrome with additional environment variables defined.
394# Each element should be specified as KEY=VALUE, with whitespace separating
395# key-value pairs. e.g.
396# CHROME_ENV=FOO=1 BAR=2 BAZ=3
397CHROME_ENV ?=
398
399# Additional arguments to pass to Chrome.
400CHROME_ARGS += --enable-nacl --enable-pnacl --no-first-run
401CHROME_ARGS += --user-data-dir=$(CURDIR)/user-data-dir
402
403
404# Paths to Debug and Release versions of the Host Pepper plugins
405PPAPI_DEBUG = $(abspath $(OSNAME)/Debug/$(TARGET)$(HOST_EXT));application/x-ppapi-debug
406PPAPI_RELEASE = $(abspath $(OSNAME)/Release/$(TARGET)$(HOST_EXT));application/x-ppapi-release
407
408
409PAGE ?= index.html
410PAGE_TC_CONFIG = "$(PAGE)?tc=$(TOOLCHAIN)&config=$(CONFIG)"
411
412.PHONY: run
413run: check_for_chrome all
414ifeq (,$(wildcard $(PAGE)))
415	$(error No valid HTML page found at $(PAGE))
416endif
417	$(RUN_PY) -C $(CURDIR) -P $(PAGE_TC_CONFIG) \
418	    $(addprefix -E ,$(CHROME_ENV)) -- $(CHROME_PATH) $(CHROME_ARGS) \
419	    --register-pepper-plugins="$(PPAPI_DEBUG),$(PPAPI_RELEASE)"
420
421.PHONY: run_package
422run_package: check_for_chrome all
423	$(CHROME_PATH) --load-and-launch-app=$(CURDIR) $(CHROME_ARGS)
424
425
426SYSARCH = $(shell python $(NACL_SDK_ROOT)/tools/getos.py --nacl-arch)
427GDB_ARGS += -D $(TC_PATH)/$(OSNAME)_x86_$(TOOLCHAIN)/bin/$(SYSARCH)-nacl-gdb
428GDB_ARGS += -D $(abspath $(OUTDIR))/$(TARGET)_$(SYSARCH).nexe
429
430.PHONY: debug
431debug: check_for_chrome all
432	$(RUN_PY) $(GDB_ARGS) \
433	    -C $(CURDIR) -P $(PAGE_TC_CONFIG) \
434	    $(addprefix -E ,$(CHROME_ENV)) -- $(CHROME_PATH) $(CHROME_ARGS) \
435	    --enable-nacl-debug \
436	    --register-pepper-plugins="$(PPAPI_DEBUG),$(PPAPI_RELEASE)"
437
438
439# uppercase aliases (for backward compatibility)
440.PHONY: CHECK_FOR_CHROME DEBUG LAUNCH RUN
441CHECK_FOR_CHROME: check_for_chrome
442DEBUG: debug
443LAUNCH: run
444RUN: run
445
446endif  # TOOLCHAIN=all
447