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#
17ifneq ($(ENABLE_BIONIC),)
18ALL_TOOLCHAINS ?= pnacl newlib glibc bionic
19else
20ALL_TOOLCHAINS ?= pnacl newlib glibc
21endif
22
23VALID_TOOLCHAINS ?= $(ALL_TOOLCHAINS)
24TOOLCHAIN ?= $(word 1,$(VALID_TOOLCHAINS))
25
26#
27# Top Make file, which we want to trigger a rebuild on if it changes
28#
29TOP_MAKE := $(word 1,$(MAKEFILE_LIST))
30
31
32#
33# Figure out which OS we are running on.
34#
35GETOS := python $(NACL_SDK_ROOT)/tools/getos.py
36NACL_CONFIG := python $(NACL_SDK_ROOT)/tools/nacl_config.py
37FIXDEPS := python $(NACL_SDK_ROOT)/tools/fix_deps.py -c
38OSNAME := $(shell $(GETOS))
39
40
41#
42# TOOLCHAIN=all recursively calls this Makefile for all VALID_TOOLCHAINS.
43#
44ifeq ($(TOOLCHAIN),all)
45
46# Define the default target
47all:
48
49#
50# Generate a new MAKE command for each TOOLCHAIN.
51#
52# Note: We use targets for each toolchain (instead of an explicit recipe) so
53# each toolchain can be built in parallel.
54#
55# $1 = Toolchain Name
56#
57define TOOLCHAIN_RULE
58TOOLCHAIN_TARGETS += $(1)_TARGET
59.PHONY: $(1)_TARGET
60$(1)_TARGET:
61	+$(MAKE) TOOLCHAIN=$(1) $(MAKECMDGOALS)
62endef
63
64#
65# The target for all versions
66#
67USABLE_TOOLCHAINS=$(filter $(OSNAME) $(ALL_TOOLCHAINS),$(VALID_TOOLCHAINS))
68
69ifeq ($(NO_HOST_BUILDS),1)
70USABLE_TOOLCHAINS:=$(filter-out $(OSNAME),$(USABLE_TOOLCHAINS))
71endif
72
73# Define the toolchain targets for all usable toolchains via the macro.
74$(foreach tool,$(USABLE_TOOLCHAINS),$(eval $(call TOOLCHAIN_RULE,$(tool))))
75
76.PHONY: all clean install
77all: $(TOOLCHAIN_TARGETS)
78clean: $(TOOLCHAIN_TARGETS)
79install: $(TOOLCHAIN_TARGETS)
80
81else  # TOOLCHAIN=all
82
83#
84# Verify we selected a valid toolchain for this example
85#
86ifeq (,$(findstring $(TOOLCHAIN),$(VALID_TOOLCHAINS)))
87
88# Only fail to build if this is a top-level make. When building recursively, we
89# don't care if an example can't build with this toolchain.
90ifeq ($(MAKELEVEL),0)
91  $(warning Availbile choices are: $(VALID_TOOLCHAINS))
92  $(error Can not use TOOLCHAIN=$(TOOLCHAIN) on this example.)
93else
94
95# Dummy targets for recursive make with unsupported toolchain...
96.PHONY: all clean install
97all:
98clean:
99install:
100
101endif
102
103else  # TOOLCHAIN is valid...
104
105#
106# Build Configuration
107#
108# The SDK provides two sets of libraries, Debug and Release.  Debug libraries
109# are compiled without optimizations to make debugging easier.  By default
110# this will build a Release configuration. When debugging via "make debug",
111# build the debug configuration by default instead.
112#
113ifneq (,$(findstring debug,$(MAKECMDGOALS)))
114CONFIG ?= Debug
115else
116CONFIG ?= Release
117endif
118
119
120#
121# Verify we selected a valid configuration for this example.
122#
123VALID_CONFIGS ?= Debug Release
124ifeq (,$(findstring $(CONFIG),$(VALID_CONFIGS)))
125  $(warning Availbile choices are: $(VALID_CONFIGS))
126  $(error Can not use CONFIG=$(CONFIG) on this example.)
127endif
128
129
130#
131# Note for Windows:
132#   The GCC and LLVM toolchains (include the version of Make.exe that comes
133# with the SDK) expect and are capable of dealing with the '/' seperator.
134# For this reason, the tools in the SDK, including Makefiles and build scripts
135# have a preference for POSIX style command-line arguments.
136#
137# Keep in mind however that the shell is responsible for command-line escaping,
138# globbing, and variable expansion, so those may change based on which shell
139# is used.  For Cygwin shells this can include automatic and incorrect expansion
140# of response files (files starting with '@').
141#
142# Disable DOS PATH warning when using Cygwin based NaCl tools on Windows.
143#
144ifeq ($(OSNAME),win)
145  CYGWIN?=nodosfilewarning
146  export CYGWIN
147endif
148
149
150#
151# If NACL_SDK_ROOT is not already set, then set it relative to this makefile.
152#
153THIS_MAKEFILE := $(CURDIR)/$(lastword $(MAKEFILE_LIST))
154NACL_SDK_ROOT ?= $(realpath $(dir $(THIS_MAKEFILE))/..)
155
156
157#
158# Check that NACL_SDK_ROOT is set to a valid location.
159# We use the existence of tools/oshelpers.py to verify the validity of the SDK
160# root.
161#
162ifeq (,$(wildcard $(NACL_SDK_ROOT)/tools/oshelpers.py))
163  $(error NACL_SDK_ROOT is set to an invalid location: $(NACL_SDK_ROOT))
164endif
165
166
167#
168# If this makefile is part of a valid nacl SDK, but NACL_SDK_ROOT is set
169# to a different location this is almost certainly a local configuration
170# error.
171#
172LOCAL_ROOT := $(realpath $(dir $(THIS_MAKEFILE))/..)
173ifneq (,$(wildcard $(LOCAL_ROOT)/tools/oshelpers.py))
174  ifneq ($(realpath $(NACL_SDK_ROOT)), $(realpath $(LOCAL_ROOT)))
175    $(error common.mk included from an SDK that does not match the current NACL_SDK_ROOT)
176  endif
177endif
178
179
180#
181# Alias for standard POSIX file system commands
182#
183OSHELPERS = python $(NACL_SDK_ROOT)/tools/oshelpers.py
184WHICH := $(OSHELPERS) which
185ifdef V
186RM := $(OSHELPERS) rm
187CP := $(OSHELPERS) cp
188MKDIR := $(OSHELPERS) mkdir
189MV := $(OSHELPERS) mv
190else
191RM := @$(OSHELPERS) rm
192CP := @$(OSHELPERS) cp
193MKDIR := @$(OSHELPERS) mkdir
194MV := @$(OSHELPERS) mv
195endif
196
197
198
199#
200# Compute path to requested NaCl Toolchain
201#
202TC_PATH := $(abspath $(NACL_SDK_ROOT)/toolchain)
203
204
205#
206# Check for required minimum SDK version.
207# A makefile can declare NACL_SDK_VERSION_MIN of the form "<major>.<position>",
208# where <major> is the major Chromium version number, and <position> is the
209# Chromium Cr-Commit-Position number. eg. "39.295386".
210#
211ifdef NACL_SDK_VERSION_MIN
212  VERSION_CHECK:=$(shell $(GETOS) --check-version=$(NACL_SDK_VERSION_MIN) 2>&1)
213  ifneq ($(VERSION_CHECK),)
214    $(error $(VERSION_CHECK))
215  endif
216endif
217
218
219#
220# The default target
221#
222# If no targets are specified on the command-line, the first target listed in
223# the makefile becomes the default target.  By convention this is usually called
224# the 'all' target.  Here we leave it blank to be first, but define it later
225#
226all:
227.PHONY: all
228
229
230#
231# The install target is used to install built libraries to thier final destination.
232# By default this is the NaCl SDK 'lib' folder.
233#
234install:
235.PHONY: install
236
237ifdef SEL_LDR
238STANDALONE = 1
239endif
240
241OUTBASE ?= .
242ifdef STANDALONE
243OUTDIR := $(OUTBASE)/$(TOOLCHAIN)/standalone_$(CONFIG)
244else
245OUTDIR := $(OUTBASE)/$(TOOLCHAIN)/$(CONFIG)
246endif
247STAMPDIR ?= $(OUTDIR)
248LIBDIR ?= $(NACL_SDK_ROOT)/lib
249
250
251#
252# Target to remove temporary files
253#
254.PHONY: clean
255clean:
256	$(RM) -f $(TARGET).nmf
257	$(RM) -rf $(OUTDIR)
258	$(RM) -rf user-data-dir
259
260
261#
262# Rules for output directories.
263#
264# Output will be places in a directory name based on Toolchain and configuration
265# be default this will be "newlib/Debug".  We use a python wrapped MKDIR to
266# proivde a cross platform solution. The use of '|' checks for existance instead
267# of timestamp, since the directory can update when files change.
268#
269%dir.stamp :
270	$(MKDIR) -p $(dir $@)
271	@echo Directory Stamp > $@
272
273
274#
275# Dependency Macro
276#
277# $1 = Name of stamp
278# $2 = Directory for the sub-make
279# $3 = Extra Settings
280#
281define DEPEND_RULE
282ifndef IGNORE_DEPS
283.PHONY: rebuild_$(1)
284
285rebuild_$(1) :| $(STAMPDIR)/dir.stamp
286ifeq (,$(2))
287	+$(MAKE) -C $(NACL_SDK_ROOT)/src/$(1) STAMPDIR=$(abspath $(STAMPDIR)) $(abspath $(STAMPDIR)/$(1).stamp) $(3)
288else
289	+$(MAKE) -C $(2) STAMPDIR=$(abspath $(STAMPDIR)) $(abspath $(STAMPDIR)/$(1).stamp) $(3)
290endif
291
292all: rebuild_$(1)
293$(STAMPDIR)/$(1).stamp: rebuild_$(1)
294
295else
296
297.PHONY: $(STAMPDIR)/$(1).stamp
298$(STAMPDIR)/$(1).stamp:
299	@echo Ignore $(1)
300endif
301endef
302
303ifeq ($(TOOLCHAIN),win)
304ifdef STANDALONE
305HOST_EXT = .exe
306else
307HOST_EXT = .dll
308endif
309else
310ifdef STANDALONE
311HOST_EXT =
312else
313HOST_EXT = .so
314endif
315endif
316
317
318#
319# Common Compile Options
320#
321# For example, -DNDEBUG is added to release builds by default
322# so that calls to assert(3) are not included in the build.
323#
324ifeq ($(CONFIG),Release)
325POSIX_FLAGS ?= -g -O2 -pthread -MMD -DNDEBUG
326NACL_LDFLAGS ?= -O2
327PNACL_LDFLAGS ?= -O2
328else
329POSIX_FLAGS ?= -g -O0 -pthread -MMD -DNACL_SDK_DEBUG
330endif
331
332NACL_CFLAGS ?= -Wno-long-long -Werror
333NACL_CXXFLAGS ?= -Wno-long-long -Werror
334NACL_LDFLAGS += -Wl,-as-needed -pthread
335
336#
337# Default Paths
338#
339INC_PATHS := $(shell $(NACL_CONFIG) -t $(TOOLCHAIN) --include-dirs) $(EXTRA_INC_PATHS)
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 bionic))
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
479ifneq ($(OSNAME),win)
480  CHROME_PATH_ESCAPE := $(subst $(SPACE),\ ,$(CHROME_PATH))
481  SANDBOX_ARGS :=
482else
483  CHROME_PATH_ESCAPE := $(CHROME_PATH)
484  SANDBOX_ARGS := --no-sandbox
485endif
486
487GDB_PATH := $(shell $(NACL_CONFIG) -t $(TOOLCHAIN) --tool=gdb)
488
489.PHONY: check_for_chrome
490check_for_chrome:
491ifeq (,$(wildcard $(CHROME_PATH_ESCAPE)))
492	$(warning No valid Chrome found at CHROME_PATH=$(CHROME_PATH))
493	$(error Set CHROME_PATH via an environment variable, or command-line.)
494else
495	$(warning Using chrome at: $(CHROME_PATH))
496endif
497PAGE ?= index.html
498PAGE_TC_CONFIG ?= "$(PAGE)?tc=$(TOOLCHAIN)&config=$(CONFIG)"
499
500.PHONY: run
501run: check_for_chrome all $(PAGE)
502	$(RUN_PY) -C $(CURDIR) -P $(PAGE_TC_CONFIG) \
503	    $(addprefix -E ,$(CHROME_ENV)) -- $(CHROME_PATH_ESCAPE) \
504	    $(CHROME_ARGS) \
505	    --register-pepper-plugins="$(PPAPI_DEBUG),$(PPAPI_RELEASE)"
506
507.PHONY: run_package
508run_package: check_for_chrome all
509	@echo "$(TOOLCHAIN) $(CONFIG)" > $(CURDIR)/run_package_config
510	$(CHROME_PATH_ESCAPE) --load-and-launch-app=$(CURDIR) $(CHROME_ARGS)
511
512GDB_ARGS += -D $(GDB_PATH)
513# PNaCl's nexe is acquired with "remote get nexe <path>" instead of the NMF.
514ifeq (,$(findstring $(TOOLCHAIN),pnacl))
515GDB_ARGS += -D --eval-command="nacl-manifest $(abspath $(OUTDIR))/$(TARGET).nmf"
516GDB_ARGS += -D $(GDB_DEBUG_TARGET)
517endif
518
519.PHONY: debug
520debug: check_for_chrome all $(PAGE)
521	$(RUN_PY) $(GDB_ARGS) \
522	    -C $(CURDIR) -P $(PAGE_TC_CONFIG) \
523	    $(addprefix -E ,$(CHROME_ENV)) -- $(CHROME_PATH_ESCAPE) \
524	    $(CHROME_ARGS) $(SANDBOX_ARGS) --enable-nacl-debug \
525	    --register-pepper-plugins="$(PPAPI_DEBUG),$(PPAPI_RELEASE)"
526
527.PHONY: serve
528serve: all
529	$(HTTPD_PY) -C $(CURDIR)
530endif
531
532# uppercase aliases (for backward compatibility)
533.PHONY: CHECK_FOR_CHROME DEBUG LAUNCH RUN
534CHECK_FOR_CHROME: check_for_chrome
535DEBUG: debug
536LAUNCH: run
537RUN: run
538
539endif  # TOOLCHAIN is valid...
540
541endif  # TOOLCHAIN=all
542