• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1-include config.mk
2
3BUILDTYPE ?= Release
4PYTHON ?= python
5DESTDIR ?=
6SIGN ?=
7PREFIX ?= /usr/local
8FLAKY_TESTS ?= run
9TEST_CI_ARGS ?=
10STAGINGSERVER ?= node-www
11LOGLEVEL ?= silent
12OSTYPE := $(shell uname -s | tr '[:upper:]' '[:lower:]')
13COVTESTS ?= test-cov
14COV_SKIP_TESTS ?= core_line_numbers.js,testFinalizer.js,test_function/test.js
15GTEST_FILTER ?= "*"
16GNUMAKEFLAGS += --no-print-directory
17GCOV ?= gcov
18PWD = $(CURDIR)
19BUILD_WITH ?= make
20FIND ?= find
21
22ifdef JOBS
23	PARALLEL_ARGS = -j $(JOBS)
24else
25	PARALLEL_ARGS = -J
26endif
27
28ifdef ENABLE_V8_TAP
29	TAP_V8 := --junitout $(PWD)/v8-tap.xml
30	TAP_V8_INTL := --junitout $(PWD)/v8-intl-tap.xml
31	TAP_V8_BENCHMARKS := --junitout $(PWD)/v8-benchmarks-tap.xml
32endif
33
34V8_TEST_OPTIONS = $(V8_EXTRA_TEST_OPTIONS)
35ifdef DISABLE_V8_I18N
36	V8_BUILD_OPTIONS += i18nsupport=off
37endif
38# V8 build and test toolchains are not currently compatible with Python 3.
39# config.mk may have prepended a symlink for `python` to PATH which we need
40# to undo before calling V8's tools.
41OVERRIDE_BIN_DIR=$(dir $(abspath $(lastword $(MAKEFILE_LIST))))out/tools/bin
42NO_BIN_OVERRIDE_PATH=$(subst $() $(),:,$(filter-out $(OVERRIDE_BIN_DIR),$(subst :, ,$(PATH))))
43
44ifeq ($(OSTYPE), darwin)
45	GCOV = xcrun llvm-cov gcov
46endif
47
48BUILDTYPE_LOWER := $(shell echo $(BUILDTYPE) | tr '[:upper:]' '[:lower:]')
49
50# Determine EXEEXT
51EXEEXT := $(shell $(PYTHON) -c \
52		"import sys; print('.exe' if sys.platform == 'win32' else '')")
53
54NODE_EXE = node$(EXEEXT)
55NODE ?= ./$(NODE_EXE)
56NODE_G_EXE = node_g$(EXEEXT)
57NPM ?= ./deps/npm/bin/npm-cli.js
58
59# Flags for packaging.
60BUILD_DOWNLOAD_FLAGS ?= --download=all
61BUILD_INTL_FLAGS ?= --with-intl=full-icu
62BUILD_RELEASE_FLAGS ?= $(BUILD_DOWNLOAD_FLAGS) $(BUILD_INTL_FLAGS)
63
64# Default to quiet/pretty builds.
65# To do verbose builds, run `make V=1` or set the V environment variable.
66V ?= 0
67
68# Use -e to double check in case it's a broken link
69# Use $(PWD) so we can cd to anywhere before calling this
70available-node = \
71	if [ -x $(PWD)/$(NODE) ] && [ -e $(PWD)/$(NODE) ]; then \
72		$(PWD)/$(NODE) $(1); \
73	elif [ -x `command -v node` ] && [ -e `command -v node` ] && [ `command -v node` ]; then \
74		`command -v node` $(1); \
75	else \
76		echo "No available node, cannot run \"node $(1)\""; \
77		exit 1; \
78	fi;
79
80.PHONY: all
81# BUILDTYPE=Debug builds both release and debug builds. If you want to compile
82# just the debug build, run `make -C out BUILDTYPE=Debug` instead.
83ifeq ($(BUILDTYPE),Release)
84all: $(NODE_EXE) ## Default target, builds node in out/Release/node.
85else
86all: $(NODE_EXE) $(NODE_G_EXE)
87endif
88
89.PHONY: help
90# To add a target to the help, add a double comment (##) on the target line.
91help: ## Print help for targets with comments.
92	@printf "For more targets and info see the comments in the Makefile.\n\n"
93	@grep -E '^[[:alnum:]._-]+:.*?## .*$$' Makefile | sort | \
94		awk 'BEGIN {FS = ":.*?## "}; {printf "\033[36m%-15s\033[0m %s\n", $$1, $$2}'
95
96# The .PHONY is needed to ensure that we recursively use the out/Makefile
97# to check for changes.
98.PHONY: $(NODE_EXE) $(NODE_G_EXE)
99
100# The -r/-L check stops it recreating the link if it is already in place,
101# otherwise $(NODE_EXE) being a .PHONY target means it is always re-run.
102# Without the check there is a race condition between the link being deleted
103# and recreated which can break the addons build when running test-ci
104# See comments on the build-addons target for some more info
105ifeq ($(BUILD_WITH), make)
106$(NODE_EXE): build_type:=Release
107$(NODE_G_EXE): build_type:=Debug
108$(NODE_EXE) $(NODE_G_EXE): config.gypi out/Makefile
109	$(MAKE) -C out BUILDTYPE=${build_type} V=$(V)
110	if [ ! -r $@ ] || [ ! -L $@ ]; then \
111	  ln -fs out/${build_type}/$(NODE_EXE) $@; fi
112else
113ifeq ($(BUILD_WITH), ninja)
114ifeq ($(V),1)
115	NINJA_ARGS := $(NINJA_ARGS) -v
116endif
117ifdef JOBS
118	NINJA_ARGS := $(NINJA_ARGS) -j$(JOBS)
119else
120	NINJA_ARGS := $(NINJA_ARGS) $(filter -j%,$(MAKEFLAGS))
121endif
122$(NODE_EXE): config.gypi out/Release/build.ninja
123	ninja -C out/Release $(NINJA_ARGS)
124	if [ ! -r $@ ] || [ ! -L $@ ]; then ln -fs out/Release/$(NODE_EXE) $@; fi
125
126$(NODE_G_EXE): config.gypi out/Debug/build.ninja
127	ninja -C out/Debug $(NINJA_ARGS)
128	if [ ! -r $@ ] || [ ! -L $@ ]; then ln -fs out/Debug/$(NODE_EXE) $@; fi
129else
130$(NODE_EXE) $(NODE_G_EXE):
131	$(warning This Makefile currently only supports building with 'make' or 'ninja')
132endif
133endif
134
135
136ifeq ($(BUILDTYPE),Debug)
137CONFIG_FLAGS += --debug
138endif
139
140.PHONY: with-code-cache
141.PHONY: test-code-cache
142with-code-cache test-code-cache:
143	$(warning '$@' target is a noop)
144
145out/Makefile: config.gypi common.gypi node.gyp \
146	deps/uv/uv.gyp deps/llhttp/llhttp.gyp deps/zlib/zlib.gyp \
147	tools/v8_gypfiles/toolchain.gypi tools/v8_gypfiles/features.gypi \
148	tools/v8_gypfiles/inspector.gypi tools/v8_gypfiles/v8.gyp
149	$(PYTHON) tools/gyp_node.py -f make
150
151# node_version.h is listed because the N-API version is taken from there
152# and included in config.gypi
153config.gypi: configure configure.py src/node_version.h
154	@if [ -x config.status ]; then \
155		export PATH="$(NO_BIN_OVERRIDE_PATH)" && ./config.status; \
156	else \
157		echo Missing or stale $@, please run ./$<; \
158		exit 1; \
159	fi
160
161.PHONY: install
162install: all ## Installs node into $PREFIX (default=/usr/local).
163	$(PYTHON) tools/install.py $@ '$(DESTDIR)' '$(PREFIX)'
164
165.PHONY: uninstall
166uninstall: ## Uninstalls node from $PREFIX (default=/usr/local).
167	$(PYTHON) tools/install.py $@ '$(DESTDIR)' '$(PREFIX)'
168
169.PHONY: clean
170clean: ## Remove build artifacts.
171	$(RM) -r out/Makefile $(NODE_EXE) $(NODE_G_EXE) out/$(BUILDTYPE)/$(NODE_EXE) \
172		out/$(BUILDTYPE)/node.exp
173	@if [ -d out ]; then $(FIND) out/ -name '*.o' -o -name '*.a' -o -name '*.d' | xargs $(RM) -r; fi
174	$(RM) -r node_modules
175	@if [ -d deps/icu ]; then echo deleting deps/icu; $(RM) -r deps/icu; fi
176	$(RM) test.tap
177	$(MAKE) testclean
178	$(MAKE) test-addons-clean
179	$(MAKE) bench-addons-clean
180
181.PHONY: testclean
182testclean:
183# Next one is legacy remove this at some point
184	$(RM) -r test/tmp*
185	$(RM) -r test/.tmp*
186
187.PHONY: distclean
188distclean:
189	$(RM) -r out
190	$(RM) config.gypi icu_config.gypi config_fips.gypi
191	$(RM) config.mk
192	$(RM) -r $(NODE_EXE) $(NODE_G_EXE)
193	$(RM) -r node_modules
194	$(RM) -r deps/icu
195	$(RM) -r deps/icu4c*.tgz deps/icu4c*.zip deps/icu-tmp
196	$(RM) $(BINARYTAR).* $(TARBALL).*
197
198.PHONY: check
199check: test
200
201.PHONY: coverage-clean
202# Remove files generated by running coverage, put the non-instrumented lib back
203# in place
204coverage-clean:
205	$(RM) -r node_modules
206	$(RM) -r gcovr
207	$(RM) -r coverage/tmp
208	$(FIND) out/$(BUILDTYPE)/obj.target \( -name "*.gcda" -o -name "*.gcno" \) \
209		-type f -exec $(RM) {} \;
210
211.PHONY: coverage
212# Build and test with code coverage reporting. HTML coverage reports will be
213# created under coverage/. For C++ coverage reporting, this needs to be run
214# in conjunction with configure --coverage.
215# Related CI job: node-test-commit-linux-coverage-daily
216coverage: coverage-test ## Run the tests and generate a coverage report.
217
218.PHONY: coverage-build
219coverage-build: all
220	-$(MAKE) coverage-build-js
221	if [ ! -d gcovr ]; then $(PYTHON) -m pip install -t gcovr gcovr==4.2; fi
222	$(MAKE)
223
224.PHONY: coverage-build-js
225coverage-build-js:
226	mkdir -p node_modules
227	if [ ! -d node_modules/c8 ]; then \
228		$(NODE) ./deps/npm install c8 --no-save --no-package-lock;\
229	fi
230
231.PHONY: coverage-test
232coverage-test: coverage-build
233	$(FIND) out/$(BUILDTYPE)/obj.target -name "*.gcda" -type f -exec $(RM) {} \;
234	-NODE_V8_COVERAGE=coverage/tmp \
235		TEST_CI_ARGS="$(TEST_CI_ARGS) --type=coverage" $(MAKE) $(COVTESTS)
236	$(MAKE) coverage-report-js
237	-(cd out && PYTHONPATH=../gcovr $(PYTHON) -m gcovr \
238		--gcov-exclude='.*\b(deps|usr|out|cctest|embedding)\b' -v \
239		-r ../src/ --object-directory Release/obj.target \
240		--html --html-details -o ../coverage/cxxcoverage.html \
241		--gcov-executable="$(GCOV)")
242	@printf "Javascript coverage %%: "
243	@grep -B1 Lines coverage/index.html | head -n1 \
244		| sed 's/<[^>]*>//g'| sed 's/ //g'
245	@printf "C++ coverage %%: "
246	@grep -A3 Lines coverage/cxxcoverage.html | grep style  \
247		| sed 's/<[^>]*>//g'| sed 's/ //g'
248
249.PHONY: coverage-report-js
250coverage-report-js:
251	-$(MAKE) coverage-build-js
252	$(NODE) ./node_modules/.bin/c8 report
253
254.PHONY: cctest
255# Runs the C++ tests using the built `cctest` executable.
256cctest: all
257	@out/$(BUILDTYPE)/$@ --gtest_filter=$(GTEST_FILTER)
258	@out/$(BUILDTYPE)/embedtest "require('./test/embedding/test-embedding.js')"
259
260.PHONY: list-gtests
261list-gtests:
262ifeq (,$(wildcard out/$(BUILDTYPE)/cctest))
263	$(error Please run 'make cctest' first)
264endif
265	@out/$(BUILDTYPE)/cctest --gtest_list_tests
266
267.PHONY: v8
268# Related CI job: node-test-commit-v8-linux
269# Rebuilds deps/v8 as a git tree, pulls its third-party dependencies, and
270# builds it.
271v8:
272	export PATH="$(NO_BIN_OVERRIDE_PATH)" && \
273		tools/make-v8.sh $(V8_ARCH).$(BUILDTYPE_LOWER) $(V8_BUILD_OPTIONS)
274
275.PHONY: jstest
276jstest: build-addons build-js-native-api-tests build-node-api-tests ## Runs addon tests and JS tests
277	$(PYTHON) tools/test.py $(PARALLEL_ARGS) --mode=$(BUILDTYPE_LOWER) \
278		--skip-tests=$(CI_SKIP_TESTS) \
279		$(JS_SUITES) \
280		$(NATIVE_SUITES)
281
282.PHONY: tooltest
283tooltest:
284	@$(PYTHON) -m unittest discover -s ./test/tools
285
286.PHONY: coverage-run-js
287coverage-run-js:
288	$(RM) -r coverage/tmp
289	-NODE_V8_COVERAGE=coverage/tmp CI_SKIP_TESTS=$(COV_SKIP_TESTS) \
290					TEST_CI_ARGS="$(TEST_CI_ARGS) --type=coverage" $(MAKE) jstest
291	$(MAKE) coverage-report-js
292
293.PHONY: test
294# This does not run tests of third-party libraries inside deps.
295test: all ## Runs default tests, linters, and builds docs.
296	$(MAKE) -s tooltest
297	$(MAKE) -s test-doc
298	$(MAKE) -s build-addons
299	$(MAKE) -s build-js-native-api-tests
300	$(MAKE) -s build-node-api-tests
301	$(MAKE) -s cctest
302	$(MAKE) -s jstest
303
304.PHONY: test-only
305test-only: all  ## For a quick test, does not run linter or build docs.
306	$(MAKE) build-addons
307	$(MAKE) build-js-native-api-tests
308	$(MAKE) build-node-api-tests
309	$(MAKE) cctest
310	$(MAKE) jstest
311	$(MAKE) tooltest
312
313# Used by `make coverage-test`
314test-cov: all
315	$(MAKE) build-addons
316	$(MAKE) build-js-native-api-tests
317	$(MAKE) build-node-api-tests
318	$(MAKE) cctest
319	CI_SKIP_TESTS=$(COV_SKIP_TESTS) $(MAKE) jstest
320
321test-parallel: all
322	$(PYTHON) tools/test.py $(PARALLEL_ARGS) --mode=$(BUILDTYPE_LOWER) parallel
323
324test-valgrind: all
325	$(PYTHON) tools/test.py $(PARALLEL_ARGS) --mode=$(BUILDTYPE_LOWER) --valgrind sequential parallel message
326
327test-check-deopts: all
328	$(PYTHON) tools/test.py $(PARALLEL_ARGS) --mode=$(BUILDTYPE_LOWER) --check-deopts parallel sequential
329
330DOCBUILDSTAMP_PREREQS = tools/doc/addon-verify.mjs doc/api/addons.md
331
332ifeq ($(OSTYPE),aix)
333DOCBUILDSTAMP_PREREQS := $(DOCBUILDSTAMP_PREREQS) out/$(BUILDTYPE)/node.exp
334endif
335
336node_use_openssl = $(call available-node,"-p" \
337			 "process.versions.openssl != undefined")
338test/addons/.docbuildstamp: $(DOCBUILDSTAMP_PREREQS) tools/doc/node_modules
339	@if [ "$(shell $(node_use_openssl))" != "true" ]; then \
340		echo "Skipping .docbuildstamp (no crypto)"; \
341	else \
342		$(RM) -r test/addons/??_*/; \
343		[ -x $(NODE) ] && $(NODE) $< || node $< ; \
344		[ $$? -eq 0 ] && touch $@; \
345	fi
346
347ADDONS_BINDING_GYPS := \
348	$(filter-out test/addons/??_*/binding.gyp, \
349		$(wildcard test/addons/*/binding.gyp))
350
351ADDONS_BINDING_SOURCES := \
352	$(filter-out test/addons/??_*/*.cc, $(wildcard test/addons/*/*.cc)) \
353	$(filter-out test/addons/??_*/*.h, $(wildcard test/addons/*/*.h))
354
355ADDONS_PREREQS := config.gypi \
356	deps/npm/node_modules/node-gyp/package.json tools/build-addons.js \
357	deps/uv/include/*.h deps/v8/include/*.h \
358	src/node.h src/node_buffer.h src/node_object_wrap.h src/node_version.h
359
360define run_build_addons
361env npm_config_loglevel=$(LOGLEVEL) npm_config_nodedir="$$PWD" \
362	npm_config_python="$(PYTHON)" $(NODE) "$$PWD/tools/build-addons" \
363	"$$PWD/deps/npm/node_modules/node-gyp/bin/node-gyp.js" \
364	$1
365touch $2
366endef
367
368# Implicitly depends on $(NODE_EXE), see the build-addons rule for rationale.
369# Depends on node-gyp package.json so that build-addons is (re)executed when
370# node-gyp is updated as part of an npm update.
371test/addons/.buildstamp: $(ADDONS_PREREQS) \
372	$(ADDONS_BINDING_GYPS) $(ADDONS_BINDING_SOURCES) \
373	test/addons/.docbuildstamp
374	@$(call run_build_addons,"$$PWD/test/addons",$@)
375
376.PHONY: build-addons
377# .buildstamp needs $(NODE_EXE) but cannot depend on it
378# directly because it calls make recursively.  The parent make cannot know
379# if the subprocess touched anything so it pessimistically assumes that
380# .buildstamp is out of date and need a rebuild.
381# Just goes to show that recursive make really is harmful...
382# TODO(bnoordhuis) Force rebuild after gyp update.
383build-addons: | $(NODE_EXE) test/addons/.buildstamp
384
385JS_NATIVE_API_BINDING_GYPS := \
386	$(filter-out test/js-native-api/??_*/binding.gyp, \
387		$(wildcard test/js-native-api/*/binding.gyp))
388
389JS_NATIVE_API_BINDING_SOURCES := \
390	$(filter-out test/js-native-api/??_*/*.c, $(wildcard test/js-native-api/*/*.c)) \
391	$(filter-out test/js-native-api/??_*/*.cc, $(wildcard test/js-native-api/*/*.cc)) \
392	$(filter-out test/js-native-api/??_*/*.h, $(wildcard test/js-native-api/*/*.h))
393
394# Implicitly depends on $(NODE_EXE), see the build-js-native-api-tests rule for rationale.
395test/js-native-api/.buildstamp: $(ADDONS_PREREQS) \
396	$(JS_NATIVE_API_BINDING_GYPS) $(JS_NATIVE_API_BINDING_SOURCES) \
397	src/node_api.h src/node_api_types.h src/js_native_api.h \
398	src/js_native_api_types.h src/js_native_api_v8.h src/js_native_api_v8_internals.h
399	@$(call run_build_addons,"$$PWD/test/js-native-api",$@)
400
401.PHONY: build-js-native-api-tests
402# .buildstamp needs $(NODE_EXE) but cannot depend on it
403# directly because it calls make recursively.  The parent make cannot know
404# if the subprocess touched anything so it pessimistically assumes that
405# .buildstamp is out of date and need a rebuild.
406# Just goes to show that recursive make really is harmful...
407# TODO(bnoordhuis) Force rebuild after gyp or node-gyp update.
408build-js-native-api-tests: | $(NODE_EXE) test/js-native-api/.buildstamp
409
410NODE_API_BINDING_GYPS := \
411	$(filter-out test/node-api/??_*/binding.gyp, \
412		$(wildcard test/node-api/*/binding.gyp))
413
414NODE_API_BINDING_SOURCES := \
415	$(filter-out test/node-api/??_*/*.c, $(wildcard test/node-api/*/*.c)) \
416	$(filter-out test/node-api/??_*/*.cc, $(wildcard test/node-api/*/*.cc)) \
417	$(filter-out test/node-api/??_*/*.h, $(wildcard test/node-api/*/*.h))
418
419# Implicitly depends on $(NODE_EXE), see the build-node-api-tests rule for rationale.
420test/node-api/.buildstamp: $(ADDONS_PREREQS) \
421	$(NODE_API_BINDING_GYPS) $(NODE_API_BINDING_SOURCES) \
422	src/node_api.h src/node_api_types.h src/js_native_api.h \
423	src/js_native_api_types.h src/js_native_api_v8.h src/js_native_api_v8_internals.h
424	@$(call run_build_addons,"$$PWD/test/node-api",$@)
425
426.PHONY: build-node-api-tests
427# .buildstamp needs $(NODE_EXE) but cannot depend on it
428# directly because it calls make recursively.  The parent make cannot know
429# if the subprocess touched anything so it pessimistically assumes that
430# .buildstamp is out of date and need a rebuild.
431# Just goes to show that recursive make really is harmful...
432# TODO(bnoordhuis) Force rebuild after gyp or node-gyp update.
433build-node-api-tests: | $(NODE_EXE) test/node-api/.buildstamp
434
435BENCHMARK_NAPI_BINDING_GYPS := $(wildcard benchmark/napi/*/binding.gyp)
436
437BENCHMARK_NAPI_BINDING_SOURCES := \
438	$(wildcard benchmark/napi/*/*.c) \
439	$(wildcard benchmark/napi/*/*.cc) \
440	$(wildcard benchmark/napi/*/*.h)
441
442benchmark/napi/.buildstamp: $(ADDONS_PREREQS) \
443	$(BENCHMARK_NAPI_BINDING_GYPS) $(BENCHMARK_NAPI_BINDING_SOURCES)
444	@$(call run_build_addons,"$$PWD/benchmark/napi",$@)
445
446.PHONY: clear-stalled
447clear-stalled:
448	$(info Clean up any leftover processes but don't error if found.)
449	ps awwx | grep Release/node | grep -v grep | cat
450	@PS_OUT=`ps awwx | grep Release/node | grep -v grep | awk '{print $$1}'`; \
451	if [ "$${PS_OUT}" ]; then \
452		echo $${PS_OUT} | xargs kill -9; \
453	fi
454
455test-build: | all build-addons build-js-native-api-tests build-node-api-tests
456
457test-build-js-native-api: all build-js-native-api-tests
458
459test-build-node-api: all build-node-api-tests
460
461.PHONY: test-all
462test-all: test-build ## Run default tests with both Debug and Release builds.
463	$(PYTHON) tools/test.py $(PARALLEL_ARGS) --mode=debug,release
464
465test-all-valgrind: test-build
466	$(PYTHON) tools/test.py $(PARALLEL_ARGS) --mode=debug,release --valgrind
467
468.PHONY: test-all-suites
469test-all-suites: | clear-stalled test-build bench-addons-build doc-only ## Run all test suites.
470	$(PYTHON) tools/test.py $(PARALLEL_ARGS) --mode=$(BUILDTYPE_LOWER) test/*
471
472JS_SUITES ?= default
473NATIVE_SUITES ?= addons js-native-api node-api
474# CI_* variables should be kept synchronized with the ones in vcbuild.bat
475CI_NATIVE_SUITES ?= $(NATIVE_SUITES) benchmark
476CI_JS_SUITES ?= $(JS_SUITES)
477ifeq ($(node_use_openssl), false)
478	CI_DOC := doctool
479else
480	CI_DOC =
481endif
482
483.PHONY: test-ci-native
484# Build and test addons without building anything else
485# Related CI job: node-test-commit-arm-fanned
486test-ci-native: LOGLEVEL := info
487test-ci-native: | benchmark/napi/.buildstamp test/addons/.buildstamp test/js-native-api/.buildstamp test/node-api/.buildstamp
488	$(PYTHON) tools/test.py $(PARALLEL_ARGS) -p tap --logfile test.tap \
489		--mode=$(BUILDTYPE_LOWER) --flaky-tests=$(FLAKY_TESTS) \
490		$(TEST_CI_ARGS) $(CI_NATIVE_SUITES)
491
492.PHONY: test-ci-js
493# This target should not use a native compiler at all
494# Related CI job: node-test-commit-arm-fanned
495test-ci-js: | clear-stalled
496	$(PYTHON) tools/test.py $(PARALLEL_ARGS) -p tap --logfile test.tap \
497		--mode=$(BUILDTYPE_LOWER) --flaky-tests=$(FLAKY_TESTS) \
498		$(TEST_CI_ARGS) $(CI_JS_SUITES)
499	$(info Clean up any leftover processes, error if found.)
500	ps awwx | grep Release/node | grep -v grep | cat
501	@PS_OUT=`ps awwx | grep Release/node | grep -v grep | awk '{print $$1}'`; \
502	if [ "$${PS_OUT}" ]; then \
503		echo $${PS_OUT} | xargs kill -9; exit 1; \
504	fi
505
506.PHONY: test-ci
507# Related CI jobs: most CI tests, excluding node-test-commit-arm-fanned
508test-ci: LOGLEVEL := info
509test-ci: | clear-stalled bench-addons-build build-addons build-js-native-api-tests build-node-api-tests doc-only
510	out/Release/cctest --gtest_output=xml:out/junit/cctest.xml
511	$(PYTHON) tools/test.py $(PARALLEL_ARGS) -p tap --logfile test.tap \
512		--mode=$(BUILDTYPE_LOWER) --flaky-tests=$(FLAKY_TESTS) \
513		$(TEST_CI_ARGS) $(CI_JS_SUITES) $(CI_NATIVE_SUITES) $(CI_DOC)
514	out/Release/embedtest 'require("./test/embedding/test-embedding.js")'
515	$(info Clean up any leftover processes, error if found.)
516	ps awwx | grep Release/node | grep -v grep | cat
517	@PS_OUT=`ps awwx | grep Release/node | grep -v grep | awk '{print $$1}'`; \
518	if [ "$${PS_OUT}" ]; then \
519		echo $${PS_OUT} | xargs kill -9; exit 1; \
520	fi
521
522.PHONY: build-ci
523# Prepare the build for running the tests.
524# Related CI jobs: most CI tests, excluding node-test-commit-arm-fanned
525build-ci:
526	$(PYTHON) ./configure --verbose $(CONFIG_FLAGS)
527	$(MAKE)
528
529.PHONY: run-ci
530# Run by CI tests, exceptions:
531# - node-test-commit-arm-fanned (Raspberry Pis), where the binaries are
532#   cross-compiled, then transferred elsewhere to run different subsets
533#   of tests. See `test-ci-native` and `test-ci-js`.
534# - node-test-commit-linux-coverage: where the build and the tests need
535#   to be instrumented, see `coverage`.
536#
537# Using -j1 as the sub target in `test-ci` already have internal parallelism.
538# Refs: https://github.com/nodejs/node/pull/23733
539run-ci: build-ci
540	$(MAKE) test-ci -j1
541
542test-release: test-build
543	$(PYTHON) tools/test.py $(PARALLEL_ARGS) --mode=$(BUILDTYPE_LOWER)
544
545test-debug: test-build
546	$(PYTHON) tools/test.py $(PARALLEL_ARGS) --mode=debug
547
548test-message: test-build
549	$(PYTHON) tools/test.py $(PARALLEL_ARGS) message
550
551test-wpt: all
552	$(PYTHON) tools/test.py $(PARALLEL_ARGS) wpt
553
554test-simple: | cctest # Depends on 'all'.
555	$(PYTHON) tools/test.py $(PARALLEL_ARGS) parallel sequential
556
557test-pummel: all
558	$(PYTHON) tools/test.py $(PARALLEL_ARGS) pummel
559
560test-internet: all
561	$(PYTHON) tools/test.py $(PARALLEL_ARGS) internet
562
563test-benchmark: | bench-addons-build
564	$(PYTHON) tools/test.py $(PARALLEL_ARGS) benchmark
565
566test-tick-processor: all
567	$(PYTHON) tools/test.py $(PARALLEL_ARGS) tick-processor
568
569.PHONY: test-hash-seed
570# Verifies the hash seed used by V8 for hashing is random.
571test-hash-seed: all
572	$(NODE) test/pummel/test-hash-seed.js
573
574.PHONY: test-doc
575test-doc: doc-only lint-md ## Builds, lints, and verifies the docs.
576	@if [ "$(shell $(node_use_openssl))" != "true" ]; then \
577		echo "Skipping test-doc (no crypto)"; \
578	else \
579		$(PYTHON) tools/test.py $(PARALLEL_ARGS) doctool; \
580	fi
581
582.PHONY: test-doc-ci
583test-doc-ci: doc-only
584	$(PYTHON) tools/test.py --shell $(NODE) $(TEST_CI_ARGS) $(PARALLEL_ARGS) doctool
585
586test-known-issues: all
587	$(PYTHON) tools/test.py $(PARALLEL_ARGS) known_issues
588
589# Related CI job: node-test-npm
590test-npm: $(NODE_EXE) ## Run the npm test suite on deps/npm.
591	$(NODE) tools/test-npm-package --install --logfile=test-npm.tap deps/npm test
592
593test-npm-publish: $(NODE_EXE)
594	npm_package_config_publishtest=true $(NODE) deps/npm/test/run.js
595
596.PHONY: test-js-native-api
597test-js-native-api: test-build-js-native-api
598	$(PYTHON) tools/test.py $(PARALLEL_ARGS) --mode=$(BUILDTYPE_LOWER) js-native-api
599
600.PHONY: test-js-native-api-clean
601test-js-native-api-clean:
602	$(RM) -r test/js-native-api/*/build
603	$(RM) test/js-native-api/.buildstamp
604
605.PHONY: test-node-api
606test-node-api: test-build-node-api
607	$(PYTHON) tools/test.py $(PARALLEL_ARGS) --mode=$(BUILDTYPE_LOWER) node-api
608
609.PHONY: test-node-api-clean
610test-node-api-clean:
611	$(RM) -r test/node-api/*/build
612	$(RM) test/node-api/.buildstamp
613
614.PHONY: test-addons
615test-addons: test-build test-js-native-api test-node-api
616	$(PYTHON) tools/test.py $(PARALLEL_ARGS) --mode=$(BUILDTYPE_LOWER) addons
617
618.PHONY: test-addons-clean
619test-addons-clean:
620	$(RM) -r test/addons/??_*/
621	$(RM) -r test/addons/*/build
622	$(RM) test/addons/.buildstamp test/addons/.docbuildstamp
623	$(MAKE) test-js-native-api-clean
624	$(MAKE) test-node-api-clean
625
626test-async-hooks:
627	$(PYTHON) tools/test.py $(PARALLEL_ARGS) --mode=$(BUILDTYPE_LOWER) async-hooks
628
629test-with-async-hooks:
630	$(MAKE) build-addons
631	$(MAKE) build-js-native-api-tests
632	$(MAKE) build-node-api-tests
633	$(MAKE) cctest
634	NODE_TEST_WITH_ASYNC_HOOKS=1 $(PYTHON) tools/test.py $(PARALLEL_ARGS) --mode=$(BUILDTYPE_LOWER) \
635		$(JS_SUITES) \
636		$(NATIVE_SUITES)
637
638
639.PHONY: test-v8
640.PHONY: test-v8-all
641.PHONY: test-v8-benchmarks
642.PHONY: test-v8-intl
643.PHONY: test-v8-updates
644ifneq ("","$(wildcard deps/v8/tools/run-tests.py)")
645# Related CI job: node-test-commit-v8-linux
646test-v8: v8  ## Runs the V8 test suite on deps/v8.
647	export PATH="$(NO_BIN_OVERRIDE_PATH)" && \
648		deps/v8/tools/run-tests.py --gn --arch=$(V8_ARCH) $(V8_TEST_OPTIONS) \
649				mjsunit cctest debugger inspector message preparser \
650				$(TAP_V8)
651	$(info Testing hash seed)
652	$(MAKE) test-hash-seed
653
654test-v8-intl: v8
655	export PATH="$(NO_BIN_OVERRIDE_PATH)" && \
656		deps/v8/tools/run-tests.py --gn --arch=$(V8_ARCH) \
657				intl \
658				$(TAP_V8_INTL)
659
660test-v8-benchmarks: v8
661	export PATH="$(NO_BIN_OVERRIDE_PATH)" && \
662		deps/v8/tools/run-tests.py --gn --arch=$(V8_ARCH) \
663				benchmarks \
664				$(TAP_V8_BENCHMARKS)
665
666test-v8-updates:
667	$(PYTHON) tools/test.py $(PARALLEL_ARGS) --mode=$(BUILDTYPE_LOWER) v8-updates
668
669test-v8-all: test-v8 test-v8-intl test-v8-benchmarks test-v8-updates
670# runs all v8 tests
671else
672test-v8 test-v8-intl test-v8-benchmarks test-v8-all:
673	$(warning Testing V8 is not available through the source tarball.)
674	$(warning Use the git repo instead: $$ git clone https://github.com/nodejs/node.git)
675endif
676
677apidoc_dirs = out/doc out/doc/api out/doc/api/assets
678apidoc_sources = $(wildcard doc/api/*.md)
679apidocs_html = $(addprefix out/,$(apidoc_sources:.md=.html))
680apidocs_json = $(addprefix out/,$(apidoc_sources:.md=.json))
681
682apiassets = $(subst api_assets,api/assets,$(addprefix out/,$(wildcard doc/api_assets/*)))
683
684tools/doc/node_modules: tools/doc/package.json
685	@if [ "$(shell $(node_use_openssl))" != "true" ]; then \
686		echo "Skipping tools/doc/node_modules (no crypto)"; \
687	else \
688		cd tools/doc && $(call available-node,$(run-npm-ci)) \
689	fi
690
691.PHONY: doc-only
692doc-only: tools/doc/node_modules \
693	$(apidoc_dirs) $(apiassets)  ## Builds the docs with the local or the global Node.js binary.
694	@if [ "$(shell $(node_use_openssl))" != "true" ]; then \
695		echo "Skipping doc-only (no crypto)"; \
696	else \
697		$(MAKE) out/doc/api/all.html out/doc/api/all.json out/doc/api/stability; \
698	fi
699
700.PHONY: doc
701doc: $(NODE_EXE) doc-only
702
703out/doc:
704	mkdir -p $@
705
706# If it's a source tarball, doc/api already contains the generated docs.
707# Just copy everything under doc/api over.
708out/doc/api: doc/api
709	mkdir -p $@
710	cp -r doc/api out/doc
711
712# If it's a source tarball, assets are already in doc/api/assets
713out/doc/api/assets:
714	mkdir -p $@
715	if [ -d doc/api/assets ]; then cp -r doc/api/assets out/doc/api; fi;
716
717# If it's not a source tarball, we need to copy assets from doc/api_assets
718out/doc/api/assets/%: doc/api_assets/% | out/doc/api/assets
719	@cp $< $@ ; $(RM) out/doc/api/assets/README.md
720
721
722run-npm-ci = $(PWD)/$(NPM) ci
723
724LINK_DATA = out/doc/apilinks.json
725VERSIONS_DATA = out/previous-doc-versions.json
726gen-api = tools/doc/generate.mjs --node-version=$(FULLVERSION) \
727		--apilinks=$(LINK_DATA) $< --output-directory=out/doc/api \
728		--versions-file=$(VERSIONS_DATA)
729gen-apilink = tools/doc/apilinks.mjs $(LINK_DATA) $(wildcard lib/*.js)
730
731$(LINK_DATA): $(wildcard lib/*.js) tools/doc/apilinks.mjs | out/doc
732	$(call available-node, $(gen-apilink))
733
734# Regenerate previous versions data if the current version changes
735$(VERSIONS_DATA): CHANGELOG.md src/node_version.h tools/doc/versions.mjs
736	$(call available-node, tools/doc/versions.mjs $@)
737
738out/doc/api/%.json out/doc/api/%.html: doc/api/%.md tools/doc/generate.mjs \
739	tools/doc/markdown.mjs tools/doc/html.mjs tools/doc/json.mjs \
740	tools/doc/apilinks.mjs $(VERSIONS_DATA) | $(LINK_DATA) out/doc/api
741	$(call available-node, $(gen-api))
742
743out/doc/api/all.html: $(apidocs_html) tools/doc/allhtml.mjs \
744	tools/doc/apilinks.mjs | out/doc/api
745	$(call available-node, tools/doc/allhtml.mjs)
746
747out/doc/api/all.json: $(apidocs_json) tools/doc/alljson.mjs | out/doc/api
748	$(call available-node, tools/doc/alljson.mjs)
749
750.PHONY: out/doc/api/stability
751out/doc/api/stability: out/doc/api/all.json tools/doc/stability.mjs | out/doc/api
752	$(call available-node, tools/doc/stability.mjs)
753
754.PHONY: docopen
755docopen: out/doc/api/all.html
756	@$(PYTHON) -mwebbrowser file://$(abspath $<)
757
758.PHONY: docserve
759docserve: $(apidocs_html) $(apiassets)
760	@$(PYTHON) -m http.server 8000 --bind 127.0.0.1 --directory out/doc/api
761
762.PHONY: docclean
763docclean:
764	$(RM) -r out/doc
765	$(RM) "$(VERSIONS_DATA)"
766
767RAWVER=$(shell $(PYTHON) tools/getnodeversion.py)
768VERSION=v$(RAWVER)
769CHANGELOG=doc/changelogs/CHANGELOG_V$(firstword $(subst ., ,$(RAWVER))).md
770
771# For nightly builds, you must set DISTTYPE to "nightly", "next-nightly" or
772# "custom". For the nightly and next-nightly case, you need to set DATESTRING
773# and COMMIT in order to properly name the build.
774# For the rc case you need to set CUSTOMTAG to an appropriate CUSTOMTAG number
775
776ifndef DISTTYPE
777DISTTYPE=release
778endif
779ifeq ($(DISTTYPE),release)
780FULLVERSION=$(VERSION)
781else # ifeq ($(DISTTYPE),release)
782ifeq ($(DISTTYPE),custom)
783ifndef CUSTOMTAG
784$(error CUSTOMTAG is not set for DISTTYPE=custom)
785endif # ifndef CUSTOMTAG
786TAG=$(CUSTOMTAG)
787else # ifeq ($(DISTTYPE),custom)
788ifndef DATESTRING
789$(error DATESTRING is not set for nightly)
790endif # ifndef DATESTRING
791ifndef COMMIT
792$(error COMMIT is not set for nightly)
793endif # ifndef COMMIT
794ifneq ($(DISTTYPE),nightly)
795ifneq ($(DISTTYPE),next-nightly)
796$(error DISTTYPE is not release, custom, nightly or next-nightly)
797endif # ifneq ($(DISTTYPE),next-nightly)
798endif # ifneq ($(DISTTYPE),nightly)
799TAG=$(DISTTYPE)$(DATESTRING)$(COMMIT)
800endif # ifeq ($(DISTTYPE),custom)
801FULLVERSION=$(VERSION)-$(TAG)
802endif # ifeq ($(DISTTYPE),release)
803
804DISTTYPEDIR ?= $(DISTTYPE)
805RELEASE=$(shell sed -ne 's/\#define NODE_VERSION_IS_RELEASE \([01]\)/\1/p' src/node_version.h)
806PLATFORM=$(shell uname | tr '[:upper:]' '[:lower:]')
807NPMVERSION=v$(shell cat deps/npm/package.json | grep '"version"' | sed 's/^[^:]*: "\([^"]*\)",.*/\1/')
808
809UNAME_M=$(shell uname -m)
810ifeq ($(findstring x86_64,$(UNAME_M)),x86_64)
811DESTCPU ?= x64
812else
813ifeq ($(findstring amd64,$(UNAME_M)),amd64)
814DESTCPU ?= x64
815else
816ifeq ($(findstring ppc64,$(UNAME_M)),ppc64)
817DESTCPU ?= ppc64
818else
819ifeq ($(findstring ppc,$(UNAME_M)),ppc)
820DESTCPU ?= ppc
821else
822ifeq ($(findstring s390x,$(UNAME_M)),s390x)
823DESTCPU ?= s390x
824else
825ifeq ($(findstring s390,$(UNAME_M)),s390)
826DESTCPU ?= s390
827else
828ifeq ($(findstring arm64,$(UNAME_M)),arm64)
829DESTCPU ?= arm64
830else
831ifeq ($(findstring arm,$(UNAME_M)),arm)
832DESTCPU ?= arm
833else
834ifeq ($(findstring aarch64,$(UNAME_M)),aarch64)
835DESTCPU ?= arm64
836else
837ifeq ($(findstring powerpc,$(shell uname -p)),powerpc)
838DESTCPU ?= ppc64
839else
840DESTCPU ?= x86
841endif
842endif
843endif
844endif
845endif
846endif
847endif
848endif
849endif
850endif
851ifeq ($(DESTCPU),x64)
852ARCH=x64
853else
854ifeq ($(DESTCPU),arm)
855ARCH=arm
856else
857ifeq ($(DESTCPU),arm64)
858ARCH=arm64
859else
860ifeq ($(DESTCPU),ppc64)
861ARCH=ppc64
862else
863ifeq ($(DESTCPU),ppc)
864ARCH=ppc
865else
866ifeq ($(DESTCPU),s390)
867ARCH=s390
868else
869ifeq ($(DESTCPU),s390x)
870ARCH=s390x
871else
872ARCH=x86
873endif
874endif
875endif
876endif
877endif
878endif
879endif
880
881# node and v8 use different arch names (e.g. node 'x86' vs v8 'ia32').
882# pass the proper v8 arch name to $V8_ARCH based on user-specified $DESTCPU.
883ifeq ($(DESTCPU),x86)
884V8_ARCH=ia32
885else
886V8_ARCH ?= $(DESTCPU)
887
888endif
889
890# enforce "x86" over "ia32" as the generally accepted way of referring to 32-bit intel
891ifeq ($(ARCH),ia32)
892override ARCH=x86
893endif
894ifeq ($(DESTCPU),ia32)
895override DESTCPU=x86
896endif
897
898TARNAME=node-$(FULLVERSION)
899TARBALL=$(TARNAME).tar
900# Custom user-specified variation, use it directly
901ifdef VARIATION
902BINARYNAME=$(TARNAME)-$(PLATFORM)-$(ARCH)-$(VARIATION)
903else
904BINARYNAME=$(TARNAME)-$(PLATFORM)-$(ARCH)
905endif
906BINARYTAR=$(BINARYNAME).tar
907# OSX doesn't have xz installed by default, http://macpkg.sourceforge.net/
908HAS_XZ ?= $(shell command -v xz > /dev/null 2>&1; [ $$? -eq 0 ] && echo 1 || echo 0)
909# Supply SKIP_XZ=1 to explicitly skip .tar.xz creation
910SKIP_XZ ?= 0
911XZ = $(shell [ $(HAS_XZ) -eq 1 ] && [ $(SKIP_XZ) -eq 0 ] && echo 1 || echo 0)
912XZ_COMPRESSION ?= 9e
913PKG=$(TARNAME).pkg
914MACOSOUTDIR=out/macos
915
916ifeq ($(SKIP_XZ), 1)
917check-xz:
918	$(info SKIP_XZ=1 supplied, skipping .tar.xz creation)
919else
920ifeq ($(HAS_XZ), 1)
921check-xz:
922else
923check-xz:
924	$(error No xz command, cannot continue)
925endif
926endif
927
928.PHONY: release-only
929release-only: check-xz
930	@if [ "$(DISTTYPE)" = "release" ] && `grep -q REPLACEME doc/api/*.md`; then \
931		echo 'Please update REPLACEME tags in the following doc/api/*.md files (See doc/guides/releases.md):\n' ; \
932		REPLACEMES="$(shell grep -l REPLACEME doc/api/*.md)" ; \
933		echo "$$REPLACEMES\n" | tr " " "\n" ; \
934		exit 1 ; \
935	fi
936	@if [ "$(DISTTYPE)" = "release" ] && \
937		`grep -q DEP...X doc/api/deprecations.md`; then \
938		echo 'Please update DEP...X in doc/api/deprecations.md (See doc/guides/releases.md)' ; \
939		exit 1 ; \
940	fi
941	@if [ "$(shell git status --porcelain | egrep -v '^\?\? ')" = "" ]; then \
942		exit 0 ; \
943	else \
944		echo "" >&2 ; \
945		echo "The git repository is not clean." >&2 ; \
946		echo "Please commit changes before building release tarball." >&2 ; \
947		echo "" >&2 ; \
948		git status --porcelain | egrep -v '^\?\?' >&2 ; \
949		echo "" >&2 ; \
950		exit 1 ; \
951	fi
952	@if [ "$(DISTTYPE)" != "release" ] || [ "$(RELEASE)" = "1" ]; then \
953		exit 0; \
954	else \
955		echo "" >&2 ; \
956		echo "#NODE_VERSION_IS_RELEASE is set to $(RELEASE)." >&2 ; \
957		echo "Did you remember to update src/node_version.h?" >&2 ; \
958		echo "" >&2 ; \
959		exit 1 ; \
960	fi
961	@if [ "$(RELEASE)" = "0" ] || [ -f "$(CHANGELOG)" ]; then \
962		exit 0; \
963	else \
964		echo "" >&2 ; \
965		echo "#NODE_VERSION_IS_RELEASE is set to $(RELEASE) but " >&2 ; \
966		echo "$(CHANGELOG) does not exist." >&2 ; \
967		echo "" >&2 ; \
968		exit 1 ; \
969	fi
970
971$(PKG): release-only
972	$(RM) -r $(MACOSOUTDIR)
973	mkdir -p $(MACOSOUTDIR)/installer/productbuild
974	cat tools/macos-installer/productbuild/distribution.xml.tmpl  \
975		| sed -E "s/\\{nodeversion\\}/$(FULLVERSION)/g" \
976		| sed -E "s/\\{npmversion\\}/$(NPMVERSION)/g" \
977	>$(MACOSOUTDIR)/installer/productbuild/distribution.xml ; \
978
979	@for dirname in tools/macos-installer/productbuild/Resources/*/; do \
980		lang=$$(basename $$dirname) ; \
981		mkdir -p $(MACOSOUTDIR)/installer/productbuild/Resources/$$lang ; \
982		printf "Found localization directory $$dirname\n" ; \
983		cat $$dirname/welcome.html.tmpl  \
984			| sed -E "s/\\{nodeversion\\}/$(FULLVERSION)/g" \
985			| sed -E "s/\\{npmversion\\}/$(NPMVERSION)/g"  \
986		>$(MACOSOUTDIR)/installer/productbuild/Resources/$$lang/welcome.html ; \
987		cat $$dirname/conclusion.html.tmpl  \
988			| sed -E "s/\\{nodeversion\\}/$(FULLVERSION)/g" \
989			| sed -E "s/\\{npmversion\\}/$(NPMVERSION)/g"  \
990		>$(MACOSOUTDIR)/installer/productbuild/Resources/$$lang/conclusion.html ; \
991	done
992	$(PYTHON) ./configure \
993		--dest-cpu=x64 \
994		--tag=$(TAG) \
995		--release-urlbase=$(RELEASE_URLBASE) \
996		$(CONFIG_FLAGS) $(BUILD_RELEASE_FLAGS)
997	$(MAKE) install V=$(V) DESTDIR=$(MACOSOUTDIR)/dist/node
998	SIGN="$(CODESIGN_CERT)" PKGDIR="$(MACOSOUTDIR)/dist/node/usr/local" sh \
999		tools/osx-codesign.sh
1000	mkdir -p $(MACOSOUTDIR)/dist/npm/usr/local/lib/node_modules
1001	mkdir -p $(MACOSOUTDIR)/pkgs
1002	mv $(MACOSOUTDIR)/dist/node/usr/local/lib/node_modules/npm \
1003		$(MACOSOUTDIR)/dist/npm/usr/local/lib/node_modules
1004	unlink $(MACOSOUTDIR)/dist/node/usr/local/bin/npm
1005	unlink $(MACOSOUTDIR)/dist/node/usr/local/bin/npx
1006	$(NODE) tools/license2rtf.js < LICENSE > \
1007		$(MACOSOUTDIR)/installer/productbuild/Resources/license.rtf
1008	cp doc/osx_installer_logo.png $(MACOSOUTDIR)/installer/productbuild/Resources
1009	pkgbuild --version $(FULLVERSION) \
1010		--identifier org.nodejs.node.pkg \
1011		--root $(MACOSOUTDIR)/dist/node $(MACOSOUTDIR)/pkgs/node-$(FULLVERSION).pkg
1012	pkgbuild --version $(NPMVERSION) \
1013		--identifier org.nodejs.npm.pkg \
1014		--root $(MACOSOUTDIR)/dist/npm \
1015		--scripts ./tools/macos-installer/pkgbuild/npm/scripts \
1016			$(MACOSOUTDIR)/pkgs/npm-$(NPMVERSION).pkg
1017	productbuild --distribution $(MACOSOUTDIR)/installer/productbuild/distribution.xml \
1018		--resources $(MACOSOUTDIR)/installer/productbuild/Resources \
1019		--package-path $(MACOSOUTDIR)/pkgs ./$(PKG)
1020	SIGN="$(PRODUCTSIGN_CERT)" PKG="$(PKG)" sh tools/osx-productsign.sh
1021	sh tools/osx-notarize.sh $(FULLVERSION)
1022
1023.PHONY: pkg
1024# Builds the macOS installer for releases.
1025pkg: $(PKG)
1026
1027corepack-update:
1028	rm -rf /tmp/node-corepack-clone
1029	git clone 'https://github.com/nodejs/corepack.git' /tmp/node-corepack-clone
1030	cd /tmp/node-corepack-clone && yarn pack
1031	rm -rf deps/corepack && mkdir -p deps/corepack
1032	cd deps/corepack && tar xf /tmp/node-corepack-clone/package.tgz --strip-components=1
1033	chmod +x deps/corepack/shims/*
1034
1035# Note: this is strictly for release builds on release machines only.
1036pkg-upload: pkg
1037	ssh $(STAGINGSERVER) "mkdir -p nodejs/$(DISTTYPEDIR)/$(FULLVERSION)"
1038	chmod 664 $(TARNAME).pkg
1039	scp -p $(TARNAME).pkg $(STAGINGSERVER):nodejs/$(DISTTYPEDIR)/$(FULLVERSION)/$(TARNAME).pkg
1040	ssh $(STAGINGSERVER) "touch nodejs/$(DISTTYPEDIR)/$(FULLVERSION)/$(TARNAME).pkg.done"
1041
1042$(TARBALL): release-only doc-only
1043	git checkout-index -a -f --prefix=$(TARNAME)/
1044	mkdir -p $(TARNAME)/doc/api
1045	cp doc/node.1 $(TARNAME)/doc/node.1
1046	cp -r out/doc/api/* $(TARNAME)/doc/api/
1047	$(RM) -r $(TARNAME)/.editorconfig
1048	$(RM) -r $(TARNAME)/.git*
1049	$(RM) -r $(TARNAME)/.mailmap
1050	$(RM) -r $(TARNAME)/deps/openssl/openssl/demos
1051	$(RM) -r $(TARNAME)/deps/openssl/openssl/doc
1052	$(RM) -r $(TARNAME)/deps/openssl/openssl/test
1053	$(RM) -r $(TARNAME)/deps/uv/docs
1054	$(RM) -r $(TARNAME)/deps/uv/samples
1055	$(RM) -r $(TARNAME)/deps/uv/test
1056	$(RM) -r $(TARNAME)/deps/v8/samples
1057	$(RM) -r $(TARNAME)/deps/v8/tools/profviz
1058	$(RM) -r $(TARNAME)/deps/v8/tools/run-tests.py
1059	$(RM) -r $(TARNAME)/doc/images # too big
1060	$(RM) -r $(TARNAME)/test*.tap
1061	$(RM) -r $(TARNAME)/tools/cpplint.py
1062	$(RM) -r $(TARNAME)/tools/eslint-rules
1063	$(RM) -r $(TARNAME)/tools/license-builder.sh
1064	$(RM) -r $(TARNAME)/tools/node_modules
1065	$(RM) -r $(TARNAME)/tools/osx-*
1066	$(RM) -r $(TARNAME)/tools/osx-pkg.pmdoc
1067	find $(TARNAME)/deps/v8/test/* -type d ! -regex '.*/test/torque$$' | xargs $(RM) -r
1068	find $(TARNAME)/deps/v8/test -type f ! -regex '.*/test/torque/.*' | xargs $(RM)
1069	find $(TARNAME)/deps/zlib/contrib/* -type d ! -regex '.*/contrib/optimizations$$' | xargs $(RM) -r
1070	find $(TARNAME)/ -name ".eslint*" -maxdepth 2 | xargs $(RM)
1071	find $(TARNAME)/ -type l | xargs $(RM)
1072	tar -cf $(TARNAME).tar $(TARNAME)
1073	$(RM) -r $(TARNAME)
1074	gzip -c -f -9 $(TARNAME).tar > $(TARNAME).tar.gz
1075ifeq ($(XZ), 1)
1076	xz -c -f -$(XZ_COMPRESSION) $(TARNAME).tar > $(TARNAME).tar.xz
1077endif
1078	$(RM) $(TARNAME).tar
1079
1080.PHONY: tar
1081tar: $(TARBALL) ## Create a source tarball.
1082
1083# Note: this is strictly for release builds on release machines only.
1084tar-upload: tar
1085	ssh $(STAGINGSERVER) "mkdir -p nodejs/$(DISTTYPEDIR)/$(FULLVERSION)"
1086	chmod 664 $(TARNAME).tar.gz
1087	scp -p $(TARNAME).tar.gz $(STAGINGSERVER):nodejs/$(DISTTYPEDIR)/$(FULLVERSION)/$(TARNAME).tar.gz
1088	ssh $(STAGINGSERVER) "touch nodejs/$(DISTTYPEDIR)/$(FULLVERSION)/$(TARNAME).tar.gz.done"
1089ifeq ($(XZ), 1)
1090	chmod 664 $(TARNAME).tar.xz
1091	scp -p $(TARNAME).tar.xz $(STAGINGSERVER):nodejs/$(DISTTYPEDIR)/$(FULLVERSION)/$(TARNAME).tar.xz
1092	ssh $(STAGINGSERVER) "touch nodejs/$(DISTTYPEDIR)/$(FULLVERSION)/$(TARNAME).tar.xz.done"
1093endif
1094
1095# Note: this is strictly for release builds on release machines only.
1096doc-upload: doc
1097	ssh $(STAGINGSERVER) "mkdir -p nodejs/$(DISTTYPEDIR)/$(FULLVERSION)/docs/"
1098	chmod -R ug=rw-x+X,o=r+X out/doc/
1099	scp -pr out/doc/* $(STAGINGSERVER):nodejs/$(DISTTYPEDIR)/$(FULLVERSION)/docs/
1100	ssh $(STAGINGSERVER) "touch nodejs/$(DISTTYPEDIR)/$(FULLVERSION)/docs.done"
1101
1102.PHONY: $(TARBALL)-headers
1103$(TARBALL)-headers: release-only
1104	$(PYTHON) ./configure \
1105		--prefix=/ \
1106		--dest-cpu=$(DESTCPU) \
1107		--tag=$(TAG) \
1108		--release-urlbase=$(RELEASE_URLBASE) \
1109		$(CONFIG_FLAGS) $(BUILD_RELEASE_FLAGS)
1110	HEADERS_ONLY=1 $(PYTHON) tools/install.py install '$(TARNAME)' '/'
1111	find $(TARNAME)/ -type l | xargs $(RM)
1112	tar -cf $(TARNAME)-headers.tar $(TARNAME)
1113	$(RM) -r $(TARNAME)
1114	gzip -c -f -9 $(TARNAME)-headers.tar > $(TARNAME)-headers.tar.gz
1115ifeq ($(XZ), 1)
1116	xz -c -f -$(XZ_COMPRESSION) $(TARNAME)-headers.tar > $(TARNAME)-headers.tar.xz
1117endif
1118	$(RM) $(TARNAME)-headers.tar
1119
1120tar-headers: $(TARBALL)-headers ## Build the node header tarball.
1121
1122tar-headers-upload: tar-headers
1123	ssh $(STAGINGSERVER) "mkdir -p nodejs/$(DISTTYPEDIR)/$(FULLVERSION)"
1124	chmod 664 $(TARNAME)-headers.tar.gz
1125	scp -p $(TARNAME)-headers.tar.gz $(STAGINGSERVER):nodejs/$(DISTTYPEDIR)/$(FULLVERSION)/$(TARNAME)-headers.tar.gz
1126	ssh $(STAGINGSERVER) "touch nodejs/$(DISTTYPEDIR)/$(FULLVERSION)/$(TARNAME)-headers.tar.gz.done"
1127ifeq ($(XZ), 1)
1128	chmod 664 $(TARNAME)-headers.tar.xz
1129	scp -p $(TARNAME)-headers.tar.xz $(STAGINGSERVER):nodejs/$(DISTTYPEDIR)/$(FULLVERSION)/$(TARNAME)-headers.tar.xz
1130	ssh $(STAGINGSERVER) "touch nodejs/$(DISTTYPEDIR)/$(FULLVERSION)/$(TARNAME)-headers.tar.xz.done"
1131endif
1132
1133$(BINARYTAR): release-only
1134	$(RM) -r $(BINARYNAME)
1135	$(RM) -r out/deps out/Release
1136	$(PYTHON) ./configure \
1137		--prefix=/ \
1138		--dest-cpu=$(DESTCPU) \
1139		--tag=$(TAG) \
1140		--release-urlbase=$(RELEASE_URLBASE) \
1141		$(CONFIG_FLAGS) $(BUILD_RELEASE_FLAGS)
1142	$(MAKE) install DESTDIR=$(BINARYNAME) V=$(V) PORTABLE=1
1143	cp README.md $(BINARYNAME)
1144	cp LICENSE $(BINARYNAME)
1145ifeq ("$(wildcard $(CHANGELOG))","")
1146	cp CHANGELOG.md $(BINARYNAME)
1147else
1148	cp $(CHANGELOG) $(BINARYNAME)/CHANGELOG.md
1149endif
1150ifeq ($(OSTYPE),darwin)
1151	SIGN="$(CODESIGN_CERT)" PKGDIR="$(BINARYNAME)" sh tools/osx-codesign.sh
1152endif
1153	tar -cf $(BINARYNAME).tar $(BINARYNAME)
1154	$(RM) -r $(BINARYNAME)
1155	gzip -c -f -9 $(BINARYNAME).tar > $(BINARYNAME).tar.gz
1156ifeq ($(XZ), 1)
1157	xz -c -f -$(XZ_COMPRESSION) $(BINARYNAME).tar > $(BINARYNAME).tar.xz
1158endif
1159	$(RM) $(BINARYNAME).tar
1160
1161.PHONY: binary
1162# This requires NODE_VERSION_IS_RELEASE defined as 1 in src/node_version.h.
1163binary: $(BINARYTAR) ## Build release binary tarballs.
1164
1165# Note: this is strictly for release builds on release machines only.
1166binary-upload: binary
1167	ssh $(STAGINGSERVER) "mkdir -p nodejs/$(DISTTYPEDIR)/$(FULLVERSION)"
1168	chmod 664 $(TARNAME)-$(OSTYPE)-$(ARCH).tar.gz
1169	scp -p $(TARNAME)-$(OSTYPE)-$(ARCH).tar.gz $(STAGINGSERVER):nodejs/$(DISTTYPEDIR)/$(FULLVERSION)/$(TARNAME)-$(OSTYPE)-$(ARCH).tar.gz
1170	ssh $(STAGINGSERVER) "touch nodejs/$(DISTTYPEDIR)/$(FULLVERSION)/$(TARNAME)-$(OSTYPE)-$(ARCH).tar.gz.done"
1171ifeq ($(XZ), 1)
1172	chmod 664 $(TARNAME)-$(OSTYPE)-$(ARCH).tar.xz
1173	scp -p $(TARNAME)-$(OSTYPE)-$(ARCH).tar.xz $(STAGINGSERVER):nodejs/$(DISTTYPEDIR)/$(FULLVERSION)/$(TARNAME)-$(OSTYPE)-$(ARCH).tar.xz
1174	ssh $(STAGINGSERVER) "touch nodejs/$(DISTTYPEDIR)/$(FULLVERSION)/$(TARNAME)-$(OSTYPE)-$(ARCH).tar.xz.done"
1175endif
1176
1177.PHONY: bench-all
1178.PHONY: bench
1179bench bench-all: bench-addons-build
1180	$(warning Please use benchmark/run.js or benchmark/compare.js to run the benchmarks.)
1181
1182# Build required addons for benchmark before running it.
1183.PHONY: bench-addons-build
1184bench-addons-build: | $(NODE_EXE) benchmark/napi/.buildstamp
1185
1186.PHONY: bench-addons-clean
1187bench-addons-clean:
1188	$(RM) -r benchmark/napi/*/build
1189	$(RM) benchmark/napi/.buildstamp
1190
1191.PHONY: lint-md-rollup
1192lint-md-rollup:
1193	$(RM) tools/.*mdlintstamp
1194	cd tools/node-lint-md-cli-rollup && npm install
1195	cd tools/node-lint-md-cli-rollup && npm run build-node
1196
1197.PHONY: lint-md-clean
1198lint-md-clean:
1199	$(RM) -r tools/node-lint-md-cli-rollup/node_modules
1200	$(RM) tools/.*mdlintstamp
1201
1202.PHONY: lint-md-build
1203lint-md-build:
1204	$(warning Deprecated no-op target 'lint-md-build')
1205
1206ifeq ("$(wildcard tools/.mdlintstamp)","")
1207LINT_MD_NEWER =
1208else
1209LINT_MD_NEWER = -newer tools/.mdlintstamp
1210endif
1211
1212LINT_MD_TARGETS = doc src lib benchmark test tools/doc tools/icu $(wildcard *.md)
1213LINT_MD_FILES = $(shell $(FIND) $(LINT_MD_TARGETS) -type f \
1214	! -path '*node_modules*' ! -path 'test/fixtures/*' -name '*.md' \
1215	$(LINT_MD_NEWER))
1216run-lint-md = tools/lint-md.mjs -q -f --no-stdout $(LINT_MD_FILES)
1217# Lint all changed markdown files maintained by us
1218tools/.mdlintstamp: $(LINT_MD_FILES)
1219	$(info Running Markdown linter...)
1220	@$(call available-node,$(run-lint-md))
1221	@touch $@
1222
1223.PHONY: lint-md
1224# Lints the markdown documents maintained by us in the codebase.
1225lint-md: lint-js-doc | tools/.mdlintstamp
1226
1227
1228LINT_JS_TARGETS = .eslintrc.js benchmark doc lib test tools
1229
1230run-lint-js = tools/node_modules/eslint/bin/eslint.js --cache \
1231	--report-unused-disable-directives $(LINT_JS_TARGETS)
1232run-lint-js-fix = $(run-lint-js) --fix
1233
1234.PHONY: lint-js-fix
1235lint-js-fix:
1236	@$(call available-node,$(run-lint-js-fix))
1237
1238.PHONY: lint-js
1239.PHONY: lint-js-doc
1240# Note that on the CI `lint-js-ci` is run instead.
1241# Lints the JavaScript code with eslint.
1242lint-js-doc: LINT_JS_TARGETS=doc
1243lint-js lint-js-doc:
1244	@if [ "$(shell $(node_use_openssl))" != "true" ]; then \
1245		echo "Skipping $@ (no crypto)"; \
1246	else \
1247		echo "Running JS linter..."; \
1248		$(call available-node,$(run-lint-js)) \
1249	fi
1250
1251jslint: lint-js
1252	$(warning Please use lint-js instead of jslint)
1253
1254run-lint-js-ci = tools/node_modules/eslint/bin/eslint.js \
1255  --report-unused-disable-directives -f tap \
1256	-o test-eslint.tap $(LINT_JS_TARGETS)
1257
1258.PHONY: lint-js-ci
1259# On the CI the output is emitted in the TAP format.
1260lint-js-ci:
1261	$(info Running JS linter...)
1262	@$(call available-node,$(run-lint-js-ci))
1263
1264jslint-ci: lint-js-ci
1265	$(warning Please use lint-js-ci instead of jslint-ci)
1266
1267LINT_CPP_ADDON_DOC_FILES_GLOB = test/addons/??_*/*.cc test/addons/??_*/*.h
1268LINT_CPP_ADDON_DOC_FILES = $(wildcard $(LINT_CPP_ADDON_DOC_FILES_GLOB))
1269LINT_CPP_EXCLUDE ?=
1270LINT_CPP_EXCLUDE += src/node_root_certs.h
1271LINT_CPP_EXCLUDE += $(LINT_CPP_ADDON_DOC_FILES)
1272LINT_CPP_EXCLUDE += $(wildcard test/js-native-api/??_*/*.cc test/js-native-api/??_*/*.h test/node-api/??_*/*.cc test/node-api/??_*/*.h)
1273# These files were copied more or less verbatim from V8.
1274LINT_CPP_EXCLUDE += src/tracing/trace_event.h src/tracing/trace_event_common.h
1275
1276LINT_CPP_FILES = $(filter-out $(LINT_CPP_EXCLUDE), $(wildcard \
1277	benchmark/napi/*/*.cc \
1278	src/*.c \
1279	src/*.cc \
1280	src/*.h \
1281	src/*/*.c \
1282	src/*/*.cc \
1283	src/*/*.h \
1284	test/addons/*/*.cc \
1285	test/addons/*/*.h \
1286	test/cctest/*.cc \
1287	test/cctest/*.h \
1288	test/embedding/*.cc \
1289	test/embedding/*.h \
1290	test/js-native-api/*/*.cc \
1291	test/js-native-api/*/*.h \
1292	test/node-api/*/*.cc \
1293	test/node-api/*/*.h \
1294	tools/icu/*.cc \
1295	tools/icu/*.h \
1296	tools/code_cache/*.cc \
1297	tools/code_cache/*.h \
1298	tools/snapshot/*.cc \
1299	tools/snapshot/*.h \
1300	))
1301
1302# Code blocks don't have newline at the end,
1303# and the actual filename is generated so it won't match header guards
1304ADDON_DOC_LINT_FLAGS=-whitespace/ending_newline,-build/header_guard
1305
1306format-cpp-build:
1307	cd tools/clang-format && $(call available-node,$(run-npm-ci))
1308
1309format-cpp-clean:
1310	$(RM) -r tools/clang-format/node_modules
1311
1312CLANG_FORMAT_START ?= HEAD
1313.PHONY: format-cpp
1314# To format staged changes:
1315#  $ make format-cpp
1316# To format HEAD~1...HEAD (latest commit):
1317#  $ CLANG_FORMAT_START=`git rev-parse HEAD~1` make format-cpp
1318# To format diff between master and current branch head (master...HEAD):
1319#  $ CLANG_FORMAT_START=master make format-cpp
1320format-cpp: ## Format C++ diff from $CLANG_FORMAT_START to current changes
1321ifneq ("","$(wildcard tools/clang-format/node_modules/)")
1322	$(info Formatting C++ diff from $(CLANG_FORMAT_START)..)
1323	@$(PYTHON) tools/clang-format/node_modules/.bin/git-clang-format \
1324		--binary=tools/clang-format/node_modules/.bin/clang-format \
1325		--style=file \
1326		$(CLANG_FORMAT_START) -- \
1327		$(LINT_CPP_FILES)
1328else
1329	$(info clang-format is not installed.)
1330	$(info To install (requires internet access) run: $$ make format-cpp-build)
1331endif
1332
1333ifeq ($(V),1)
1334CPPLINT_QUIET =
1335else
1336CPPLINT_QUIET = --quiet
1337endif
1338.PHONY: lint-cpp
1339# Lints the C++ code with cpplint.py and checkimports.py.
1340lint-cpp: tools/.cpplintstamp
1341
1342tools/.cpplintstamp: $(LINT_CPP_FILES)
1343	$(info Running C++ linter...)
1344	@$(PYTHON) tools/cpplint.py $(CPPLINT_QUIET) $?
1345	@$(PYTHON) tools/checkimports.py $?
1346	@touch $@
1347
1348.PHONY: lint-addon-docs
1349lint-addon-docs: tools/.doclintstamp
1350
1351tools/.doclintstamp: test/addons/.docbuildstamp
1352	$(info Running C++ linter on addon docs...)
1353	@$(PYTHON) tools/cpplint.py $(CPPLINT_QUIET) --filter=$(ADDON_DOC_LINT_FLAGS) \
1354		$(LINT_CPP_ADDON_DOC_FILES_GLOB)
1355	@touch $@
1356
1357cpplint: lint-cpp
1358	$(warning Please use lint-cpp instead of cpplint)
1359
1360.PHONY: lint-py-build
1361# python -m pip install flake8
1362# Try with '--system' is to overcome systems that blindly set '--user'
1363lint-py-build:
1364	$(info Pip installing flake8 linter on $(shell $(PYTHON) --version)...)
1365	$(PYTHON) -m pip install --upgrade -t tools/pip/site-packages flake8 || \
1366		$(PYTHON) -m pip install --upgrade --system -t tools/pip/site-packages flake8
1367
1368ifneq ("","$(wildcard tools/pip/site-packages)")
1369.PHONY: lint-py
1370# Lints the Python code with flake8.
1371# Flag the build if there are Python syntax errors or undefined names
1372lint-py:
1373	PYTHONPATH=tools/pip $(PYTHON) -m flake8 --count --show-source --statistics .
1374else
1375lint-py:
1376	$(warning Python linting with flake8 is not available)
1377	$(warning Run 'make lint-py-build')
1378endif
1379
1380.PHONY: lint
1381.PHONY: lint-ci
1382ifneq ("","$(wildcard tools/node_modules/eslint/)")
1383lint: ## Run JS, C++, MD and doc linters.
1384	@EXIT_STATUS=0 ; \
1385	$(MAKE) lint-js || EXIT_STATUS=$$? ; \
1386	$(MAKE) lint-cpp || EXIT_STATUS=$$? ; \
1387	$(MAKE) lint-addon-docs || EXIT_STATUS=$$? ; \
1388	$(MAKE) lint-md || EXIT_STATUS=$$? ; \
1389	exit $$EXIT_STATUS
1390CONFLICT_RE=^>>>>>>> [[:xdigit:]]+|^<<<<<<< [[:alpha:]]+
1391
1392# Related CI job: node-test-linter
1393lint-ci: lint-js-ci lint-cpp lint-py lint-md lint-addon-docs
1394	@if ! ( grep -IEqrs "$(CONFLICT_RE)" benchmark deps doc lib src test tools ) \
1395		&& ! ( $(FIND) . -maxdepth 1 -type f | xargs grep -IEqs "$(CONFLICT_RE)" ); then \
1396		exit 0 ; \
1397	else \
1398		echo "" >&2 ; \
1399		echo "Conflict marker detected in one or more files. Please fix them first." >&2 ; \
1400		exit 1 ; \
1401	fi
1402else
1403lint lint-ci:
1404	$(info Linting is not available through the source tarball.)
1405	$(info Use the git repo instead: $$ git clone https://github.com/nodejs/node.git)
1406endif
1407
1408.PHONY: lint-clean
1409lint-clean:
1410	$(RM) tools/.*lintstamp
1411	$(RM) .eslintcache
1412
1413HAS_DOCKER ?= $(shell command -v docker > /dev/null 2>&1; [ $$? -eq 0 ] && echo 1 || echo 0)
1414
1415ifeq ($(HAS_DOCKER), 1)
1416DOCKER_COMMAND ?= docker run -it -v $(PWD):/node
1417IS_IN_WORKTREE = $(shell grep '^gitdir: ' $(PWD)/.git 2>/dev/null)
1418GIT_WORKTREE_COMMON = $(shell git rev-parse --git-common-dir)
1419DOCKER_COMMAND += $(if $(IS_IN_WORKTREE), -v $(GIT_WORKTREE_COMMON):$(GIT_WORKTREE_COMMON))
1420gen-openssl: ## Generate platform dependent openssl files (requires docker)
1421	docker build -t node-openssl-builder deps/openssl/config/
1422	$(DOCKER_COMMAND) node-openssl-builder make -C deps/openssl/config
1423else
1424gen-openssl:
1425	$(error No docker command, cannot continue)
1426endif
1427