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