github.com/tetratelabs/wazero@v1.2.1/Makefile (about)

     1  
     2  gofumpt       := mvdan.cc/gofumpt@v0.5.0
     3  gosimports    := github.com/rinchsan/gosimports/cmd/gosimports@v0.3.8
     4  golangci_lint := github.com/golangci/golangci-lint/cmd/golangci-lint@v1.52.2
     5  asmfmt        := github.com/klauspost/asmfmt/cmd/asmfmt@v1.3.2
     6  # sync this with netlify.toml!
     7  hugo          := github.com/gohugoio/hugo@v0.112.5
     8  
     9  # Make 3.81 doesn't support '**' globbing: Set explicitly instead of recursion.
    10  all_sources   := $(wildcard *.go */*.go */*/*.go */*/*/*.go */*/*/*.go */*/*/*/*.go)
    11  all_testdata  := $(wildcard testdata/* */testdata/* */*/testdata/* */*/testdata/*/* */*/*/testdata/*)
    12  all_testing   := $(wildcard internal/testing/* internal/testing/*/* internal/testing/*/*/*)
    13  all_examples  := $(wildcard examples/* examples/*/* examples/*/*/* */*/example/* */*/example/*/* */*/example/*/*/*)
    14  all_it        := $(wildcard internal/integration_test/* internal/integration_test/*/* internal/integration_test/*/*/*)
    15  # main_sources exclude any test or example related code
    16  main_sources  := $(wildcard $(filter-out %_test.go $(all_testdata) $(all_testing) $(all_examples) $(all_it), $(all_sources)))
    17  # main_packages collect the unique main source directories (sort will dedupe).
    18  # Paths need to all start with ./, so we do that manually vs foreach which strips it.
    19  main_packages := $(sort $(foreach f,$(dir $(main_sources)),$(if $(findstring ./,$(f)),./,./$(f))))
    20  
    21  go_test_options ?= -timeout 300s
    22  
    23  ensureCompilerFastest := -ldflags '-X github.com/tetratelabs/wazero/internal/integration_test/vs.ensureCompilerFastest=true'
    24  .PHONY: bench
    25  bench:
    26  	@go test -run=NONE -benchmem -bench=. ./internal/engine/compiler/...
    27  	@go build ./internal/integration_test/bench/...
    28  	@# Don't use -test.benchmem as it isn't accurate when comparing against CGO libs
    29  	@for d in vs/time vs/wasmedge vs/wasmtime ; do \
    30  		cd ./internal/integration_test/$$d ; \
    31  		go test -bench=. . -tags='wasmedge' $(ensureCompilerFastest) ; \
    32  		cd - ;\
    33  	done
    34  
    35  bench_testdata_dir := internal/integration_test/bench/testdata
    36  .PHONY: build.bench
    37  build.bench:
    38  	@tinygo build -o $(bench_testdata_dir)/case.wasm -scheduler=none --no-debug -target=wasi $(bench_testdata_dir)/case.go
    39  
    40  .PHONY: test.examples
    41  test.examples:
    42  	@go test $(go_test_options) ./examples/... ./imports/assemblyscript/example/... ./imports/emscripten/... ./experimental/gojs/example/... ./imports/wasi_snapshot_preview1/example/...
    43  
    44  .PHONY: build.examples.as
    45  build.examples.as:
    46  	@cd ./imports/assemblyscript/example/testdata && npm install && npm run build
    47  
    48  %.wasm: %.zig
    49  	@(cd $(@D); zig build -Doptimize=ReleaseSmall)
    50  	@mv $(@D)/zig-out/*/$(@F) $(@D)
    51  
    52  .PHONY: build.examples.zig
    53  build.examples.zig: examples/allocation/zig/testdata/greet.wasm imports/wasi_snapshot_preview1/example/testdata/zig/cat.wasm imports/wasi_snapshot_preview1/testdata/zig/wasi.wasm
    54  	@cd internal/testing/dwarftestdata/testdata/zig; zig build; mv zig-out/*/main.wasm ./ # Need DWARF custom sections.
    55  
    56  tinygo_sources := examples/basic/testdata/add.go examples/allocation/tinygo/testdata/greet.go examples/cli/testdata/cli.go imports/wasi_snapshot_preview1/example/testdata/tinygo/cat.go
    57  .PHONY: build.examples.tinygo
    58  build.examples.tinygo: $(tinygo_sources)
    59  	@for f in $^; do \
    60  	    tinygo build -o $$(echo $$f | sed -e 's/\.go/\.wasm/') -scheduler=none --no-debug --target=wasi $$f; \
    61  	done
    62  
    63  # We use zig to build C as it is easy to install and embeds a copy of zig-cc.
    64  # Note: Don't use "-Oz" as that breaks our wasi sock example.
    65  c_sources := imports/wasi_snapshot_preview1/example/testdata/zig-cc/cat.c imports/wasi_snapshot_preview1/testdata/zig-cc/wasi.c
    66  .PHONY: build.examples.zig-cc
    67  build.examples.zig-cc: $(c_sources)
    68  	@for f in $^; do \
    69  	    zig cc --target=wasm32-wasi -o $$(echo $$f | sed -e 's/\.c/\.wasm/') $$f; \
    70  	done
    71  
    72  # Here are the emcc args we use:
    73  #
    74  # * `-Oz` - most optimization for code size.
    75  # * `--profiling` - adds the name section.
    76  # * `-s STANDALONE_WASM` - ensures wasm is built for a non-js runtime.
    77  # * `-s EXPORTED_FUNCTIONS=_malloc,_free` - export allocation functions so that
    78  #   they can be used externally as "malloc" and "free".
    79  # * `-s WARN_ON_UNDEFINED_SYMBOLS=0` - imports not defined in JavaScript error
    80  #   otherwise. See https://github.com/emscripten-core/emscripten/issues/13641
    81  # * `-s TOTAL_STACK=8KB -s TOTAL_MEMORY=64KB` - reduce memory default from 16MB
    82  #   to one page (64KB). To do this, we have to reduce the stack size.
    83  # * `-s ALLOW_MEMORY_GROWTH` - allows "memory.grow" instructions to succeed, but
    84  #   requires a function import "emscripten_notify_memory_growth".
    85  emscripten_sources := $(wildcard imports/emscripten/testdata/*.cc)
    86  .PHONY: build.examples.emscripten
    87  build.examples.emscripten: $(emscripten_sources)
    88  	@for f in $^; do \
    89  		em++ -Oz --profiling \
    90  		-s STANDALONE_WASM \
    91  		-s EXPORTED_FUNCTIONS=_malloc,_free \
    92  		-s WARN_ON_UNDEFINED_SYMBOLS=0 \
    93  		-s TOTAL_STACK=8KB -s TOTAL_MEMORY=64KB \
    94  		-s ALLOW_MEMORY_GROWTH \
    95  		--std=c++17 -o $$(echo $$f | sed -e 's/\.cc/\.wasm/') $$f; \
    96  	done
    97  
    98  %/greet.wasm : cargo_target := wasm32-unknown-unknown
    99  %/cat.wasm : cargo_target := wasm32-wasi
   100  %/wasi.wasm : cargo_target := wasm32-wasi
   101  
   102  .PHONY: build.examples.rust
   103  build.examples.rust: examples/allocation/rust/testdata/greet.wasm imports/wasi_snapshot_preview1/example/testdata/cargo-wasi/cat.wasm imports/wasi_snapshot_preview1/testdata/cargo-wasi/wasi.wasm internal/testing/dwarftestdata/testdata/rust/main.wasm.xz
   104  
   105  # Normally, we build release because it is smaller. Testing dwarf requires the debug build.
   106  internal/testing/dwarftestdata/testdata/rust/main.wasm.xz:
   107  	cd $(@D) && cargo wasi build
   108  	mv $(@D)/target/wasm32-wasi/debug/main.wasm $(@D)
   109  	cd $(@D) && xz -k -f ./main.wasm # Rust's DWARF section is huge, so compress it.
   110  
   111  # Builds rust using cargo normally, or cargo-wasi.
   112  %.wasm: %.rs
   113  	@(cd $(@D); cargo $(if $(findstring wasi,$(cargo_target)),wasi build,build --target $(cargo_target)) --release)
   114  	@mv $(@D)/target/$(cargo_target)/release/$(@F) $(@D)
   115  
   116  spectest_base_dir := internal/integration_test/spectest
   117  spectest_v1_dir := $(spectest_base_dir)/v1
   118  spectest_v1_testdata_dir := $(spectest_v1_dir)/testdata
   119  spec_version_v1 := wg-1.0
   120  spectest_v2_dir := $(spectest_base_dir)/v2
   121  spectest_v2_testdata_dir := $(spectest_v2_dir)/testdata
   122  # Latest draft state as of May 23, 2023.
   123  spec_version_v2 := 2e8912e88a3118a46b90e8ccb659e24b4e8f3c23
   124  
   125  .PHONY: build.spectest
   126  build.spectest:
   127  	@$(MAKE) build.spectest.v1
   128  	@$(MAKE) build.spectest.v2
   129  
   130  .PHONY: build.spectest.v1
   131  build.spectest.v1: # Note: wabt by default uses >1.0 features, so wast2json flags might drift as they include more. See WebAssembly/wabt#1878
   132  	@rm -rf $(spectest_v1_testdata_dir)
   133  	@mkdir -p $(spectest_v1_testdata_dir)
   134  	@cd $(spectest_v1_testdata_dir) \
   135  		&& curl -sSL 'https://api.github.com/repos/WebAssembly/spec/contents/test/core?ref=$(spec_version_v1)' | jq -r '.[]| .download_url' | grep -E ".wast" | xargs -Iurl curl -sJL url -O
   136  	@cd $(spectest_v1_testdata_dir) && for f in `find . -name '*.wast'`; do \
   137  		perl -pi -e 's/\(assert_return_canonical_nan\s(\(invoke\s"f32.demote_f64"\s\((f[0-9]{2})\.const\s[a-z0-9.+:-]+\)\))\)/\(assert_return $$1 \(f32.const nan:canonical\)\)/g' $$f; \
   138  		perl -pi -e 's/\(assert_return_arithmetic_nan\s(\(invoke\s"f32.demote_f64"\s\((f[0-9]{2})\.const\s[a-z0-9.+:-]+\)\))\)/\(assert_return $$1 \(f32.const nan:arithmetic\)\)/g' $$f; \
   139  		perl -pi -e 's/\(assert_return_canonical_nan\s(\(invoke\s"f64\.promote_f32"\s\((f[0-9]{2})\.const\s[a-z0-9.+:-]+\)\))\)/\(assert_return $$1 \(f64.const nan:canonical\)\)/g' $$f; \
   140  		perl -pi -e 's/\(assert_return_arithmetic_nan\s(\(invoke\s"f64\.promote_f32"\s\((f[0-9]{2})\.const\s[a-z0-9.+:-]+\)\))\)/\(assert_return $$1 \(f64.const nan:arithmetic\)\)/g' $$f; \
   141  		perl -pi -e 's/\(assert_return_canonical_nan\s(\(invoke\s"[a-z._0-9]+"\s\((f[0-9]{2})\.const\s[a-z0-9.+:-]+\)\))\)/\(assert_return $$1 \($$2.const nan:canonical\)\)/g' $$f; \
   142  		perl -pi -e 's/\(assert_return_arithmetic_nan\s(\(invoke\s"[a-z._0-9]+"\s\((f[0-9]{2})\.const\s[a-z0-9.+:-]+\)\))\)/\(assert_return $$1 \($$2.const nan:arithmetic\)\)/g' $$f; \
   143  		perl -pi -e 's/\(assert_return_canonical_nan\s(\(invoke\s"[a-z._0-9]+"\s\((f[0-9]{2})\.const\s[a-z0-9.+:-]+\)\s\([a-z0-9.\s+-:]+\)\))\)/\(assert_return $$1 \($$2.const nan:canonical\)\)/g' $$f; \
   144  		perl -pi -e 's/\(assert_return_arithmetic_nan\s(\(invoke\s"[a-z._0-9]+"\s\((f[0-9]{2})\.const\s[a-z0-9.+:-]+\)\s\([a-z0-9.\s+-:]+\)\))\)/\(assert_return $$1 \($$2.const nan:arithmetic\)\)/g' $$f; \
   145  		perl -pi -e 's/\(assert_return_canonical_nan\s(\(invoke\s"[a-z._0-9]+"\s\((f[0-9]{2})\.const\s[a-z0-9.+:-]+\)\))\)/\(assert_return $$1 \($$2.const nan:canonical\)\)/g' $$f; \
   146  		perl -pi -e 's/\(assert_return_arithmetic_nan\s(\(invoke\s"[a-z._0-9]+"\s\((f[0-9]{2})\.const\s[a-z0-9.+:-]+\)\))\)/\(assert_return $$1 \($$2.const nan:arithmetic\)\)/g' $$f; \
   147  		wast2json \
   148  			--disable-saturating-float-to-int \
   149  			--disable-sign-extension \
   150  			--disable-simd \
   151  			--disable-multi-value \
   152  			--disable-bulk-memory \
   153  			--disable-reference-types \
   154  			--debug-names $$f; \
   155  	done
   156  
   157  .PHONY: build.spectest.v2
   158  build.spectest.v2: # Note: SIMD cases are placed in the "simd" subdirectory.
   159  	@mkdir -p $(spectest_v2_testdata_dir)
   160  	@cd $(spectest_v2_testdata_dir) \
   161  		&& curl -sSL 'https://api.github.com/repos/WebAssembly/spec/contents/test/core?ref=$(spec_version_v2)' | jq -r '.[]| .download_url' | grep -E ".wast" | xargs -Iurl curl -sJL url -O
   162  	@cd $(spectest_v2_testdata_dir) \
   163  		&& curl -sSL 'https://api.github.com/repos/WebAssembly/spec/contents/test/core/simd?ref=$(spec_version_v2)' | jq -r '.[]| .download_url' | grep -E ".wast" | xargs -Iurl curl -sJL url -O
   164  	@cd $(spectest_v2_testdata_dir) && for f in `find . -name '*.wast'`; do \
   165  		wast2json --debug-names --no-check $$f; \
   166  	done
   167  
   168  .PHONY: test
   169  test:
   170  	@go test $(go_test_options) $$(go list ./... | grep -vE '$(spectest_v1_dir)|$(spectest_v2_dir)')
   171  	@cd internal/version/testdata && go test $(go_test_options) ./...
   172  
   173  .PHONY: coverage
   174  # replace spaces with commas
   175  coverpkg = $(shell echo $(main_packages) | tr ' ' ',')
   176  coverage: ## Generate test coverage
   177  	@go test -coverprofile=coverage.txt -covermode=atomic --coverpkg=$(coverpkg) $(main_packages)
   178  	@go tool cover -func coverage.txt
   179  
   180  .PHONY: spectest
   181  spectest:
   182  	@$(MAKE) spectest.v1
   183  	@$(MAKE) spectest.v2
   184  
   185  spectest.v1:
   186  	@go test $(go_test_options) $$(go list ./... | grep $(spectest_v1_dir))
   187  
   188  spectest.v2:
   189  	@go test $(go_test_options) $$(go list ./... | grep $(spectest_v2_dir))
   190  
   191  golangci_lint_path := $(shell go env GOPATH)/bin/golangci-lint
   192  
   193  $(golangci_lint_path):
   194  	@go install $(golangci_lint)
   195  
   196  golangci_lint_goarch ?= $(shell go env GOARCH)
   197  
   198  .PHONY: lint
   199  lint: $(golangci_lint_path)
   200  	@GOARCH=$(golangci_lint_goarch) CGO_ENABLED=0 $(golangci_lint_path) run --timeout 5m
   201  
   202  .PHONY: format
   203  format:
   204  	@go run $(gofumpt) -l -w .
   205  	@go run $(gosimports) -local github.com/tetratelabs/ -w $(shell find . -name '*.go' -type f)
   206  	@go run $(asmfmt) -w $(shell find . -name '*.s' -type f)
   207  
   208  .PHONY: check  # Pre-flight check for pull requests
   209  check:
   210  # The following checks help ensure our platform-specific code used for system
   211  # calls safely falls back on a platform unsupported by the compiler engine.
   212  # This makes sure the intepreter can be used. Most often the package that can
   213  # drift here is "platform" or "sysfs":
   214  #
   215  # Ensure we build on windows:
   216  	@GOARCH=amd64 GOOS=windows go build ./...
   217  # Ensure we build on an arbitrary operating system:
   218  	@GOARCH=amd64 GOOS=dragonfly go build ./...
   219  # Ensure we build on solaris/illumos:
   220  	@GOARCH=amd64 GOOS=illumos go build ./...
   221  	@GOARCH=amd64 GOOS=solaris go build ./...
   222  # Ensure we build on linux arm for Dapr:
   223  #	gh release view -R dapr/dapr --json assets --jq 'first(.assets[] | select(.name = "daprd_linux_arm.tar.gz") | {url, downloadCount})'
   224  	@GOARCH=arm GOOS=linux go build ./...
   225  # Ensure we build on linux 386 for Trivy:
   226  #	gh release view -R aquasecurity/trivy --json assets --jq 'first(.assets[] | select(.name| test("Linux-32bit.*tar.gz")) | {url, downloadCount})'
   227  	@GOARCH=386 GOOS=linux go build ./...
   228  # Ensure we build on FreeBSD amd64 for Trivy:
   229  #	gh release view -R aquasecurity/trivy --json assets --jq 'first(.assets[] | select(.name| test("FreeBSD-64bit.*tar.gz")) | {url, downloadCount})'
   230  	@GOARCH=amd64 GOOS=freebsd go build ./...
   231  	@$(MAKE) lint golangci_lint_goarch=arm64
   232  	@$(MAKE) lint golangci_lint_goarch=amd64
   233  	@$(MAKE) format
   234  	@go mod tidy
   235  	@if [ ! -z "`git status -s`" ]; then \
   236  		echo "The following differences will fail CI until committed:"; \
   237  		git diff --exit-code; \
   238  	fi
   239  
   240  .PHONY: site
   241  site: ## Serve website content
   242  	@git submodule update --init
   243  	@cd site && go run $(hugo) server --minify --disableFastRender --baseURL localhost:1313 --cleanDestinationDir -D
   244  
   245  .PHONY: clean
   246  clean: ## Ensure a clean build
   247  	@rm -rf dist build coverage.txt
   248  	@go clean -testcache
   249  
   250  fuzz_timeout_seconds ?= 10
   251  .PHONY: fuzz
   252  fuzz:
   253  	@cd internal/integration_test/fuzz && cargo fuzz run basic -- -max_total_time=$(fuzz_timeout_seconds)
   254  	@cd internal/integration_test/fuzz && cargo fuzz run memory_no_diff -- -max_total_time=$(fuzz_timeout_seconds)
   255  	@cd internal/integration_test/fuzz && cargo fuzz run validation -- -max_total_time=$(fuzz_timeout_seconds)
   256  
   257  #### CLI release related ####
   258  
   259  VERSION ?= dev
   260  # Default to a dummy version 0.0.1.1, which is always lower than a real release.
   261  # Legal version values should look like 'x.x.x.x' where x is an integer from 0 to 65534.
   262  # https://learn.microsoft.com/en-us/windows/win32/msi/productversion?redirectedfrom=MSDN
   263  # https://stackoverflow.com/questions/9312221/msi-version-numbers
   264  MSI_VERSION ?= 0.0.1.1
   265  non_windows_platforms := darwin_amd64 darwin_arm64 linux_amd64 linux_arm64
   266  non_windows_archives  := $(non_windows_platforms:%=dist/wazero_$(VERSION)_%.tar.gz)
   267  windows_platforms     := windows_amd64 # TODO: add arm64 windows once we start testing on it.
   268  windows_archives      := $(windows_platforms:%=dist/wazero_$(VERSION)_%.zip) $(windows_platforms:%=dist/wazero_$(VERSION)_%.msi)
   269  checksum_txt          := dist/wazero_$(VERSION)_checksums.txt
   270  
   271  # define macros for multi-platform builds. these parse the filename being built
   272  go-arch = $(if $(findstring amd64,$1),amd64,arm64)
   273  go-os   = $(if $(findstring .exe,$1),windows,$(if $(findstring linux,$1),linux,darwin))
   274  # msi-arch is a macro so we can detect it based on the file naming convention
   275  msi-arch     = $(if $(findstring amd64,$1),x64,arm64)
   276  
   277  build/wazero_%/wazero:
   278  	$(call go-build,$@,$<)
   279  
   280  build/wazero_%/wazero.exe:
   281  	$(call go-build,$@,$<)
   282  
   283  dist/wazero_$(VERSION)_%.tar.gz: build/wazero_%/wazero
   284  	@echo tar.gz "tarring $@"
   285  	@mkdir -p $(@D)
   286  # On Windows, we pass the special flag `--mode='+rx' to ensure that we set the executable flag.
   287  # This is only supported by GNU Tar, so we set it conditionally.
   288  	@tar -C $(<D) -cpzf $@ $(if $(findstring Windows_NT,$(OS)),--mode='+rx',) $(<F)
   289  	@echo tar.gz "ok"
   290  
   291  define go-build
   292  	@echo "building $1"
   293  	@# $(go:go=) removes the trailing 'go', so we can insert cross-build variables
   294  	@$(go:go=) CGO_ENABLED=0 GOOS=$(call go-os,$1) GOARCH=$(call go-arch,$1) go build \
   295  		-ldflags "-s -w -X github.com/tetratelabs/wazero/internal/version.version=$(VERSION)" \
   296  		-o $1 $2 ./cmd/wazero
   297  	@echo build "ok"
   298  endef
   299  
   300  # this makes a marker file ending in .signed to avoid repeatedly calling codesign
   301  %.signed: %
   302  	$(call codesign,$<)
   303  	@touch $@
   304  
   305  # This requires osslsigncode package (apt or brew) or latest windows release from mtrojnar/osslsigncode
   306  #
   307  # Default is self-signed while production should be a Digicert signing key
   308  #
   309  # Ex.
   310  # ```bash
   311  # keytool -genkey -alias wazero -storetype PKCS12 -keyalg RSA -keysize 2048 -storepass wazero-bunch \
   312  # -keystore wazero.p12 -dname "O=wazero,CN=wazero.io" -validity 3650
   313  # ```
   314  WINDOWS_CODESIGN_P12      ?= packaging/msi/wazero.p12
   315  WINDOWS_CODESIGN_PASSWORD ?= wazero-bunch
   316  define codesign
   317  	@printf "$(ansi_format_dark)" codesign "signing $1"
   318  	@osslsigncode sign -h sha256 -pkcs12 ${WINDOWS_CODESIGN_P12} -pass "${WINDOWS_CODESIGN_PASSWORD}" \
   319  	-n "wazero is the zero dependency WebAssembly runtime for Go developers" -i https://wazero.io -t http://timestamp.digicert.com \
   320  	$(if $(findstring msi,$(1)),-add-msi-dse) -in $1 -out $1-signed
   321  	@mv $1-signed $1
   322  	@printf "$(ansi_format_bright)" codesign "ok"
   323  endef
   324  
   325  # This task is only supported on Windows, where we use candle.exe (compile wxs to wixobj) and light.exe (link to msi)
   326  dist/wazero_$(VERSION)_%.msi: build/wazero_%/wazero.exe.signed
   327  ifeq ($(OS),Windows_NT)
   328  	@echo msi "building $@"
   329  	@mkdir -p $(@D)
   330  	@candle -nologo -arch $(call msi-arch,$@) -dVersion=$(MSI_VERSION) -dBin=$(<:.signed=) -o build/wazero.wixobj packaging/msi/wazero.wxs
   331  	@light -nologo -o $@ build/wazero.wixobj -spdb
   332  	$(call codesign,$@)
   333  	@echo msi "ok"
   334  endif
   335  
   336  dist/wazero_$(VERSION)_%.zip: build/wazero_%/wazero.exe.signed
   337  	@echo zip "zipping $@"
   338  	@mkdir -p $(@D)
   339  	@zip -qj $@ $(<:.signed=)
   340  	@echo zip "ok"
   341  
   342  # Darwin doesn't have sha256sum. See https://github.com/actions/virtual-environments/issues/90
   343  sha256sum := $(if $(findstring darwin,$(shell go env GOOS)),shasum -a 256,sha256sum)
   344  $(checksum_txt):
   345  	@cd $(@D); touch $(@F); $(sha256sum) * >> $(@F)
   346  
   347  dist: $(non_windows_archives) $(if $(findstring Windows_NT,$(OS)),$(windows_archives),) $(checksum_txt)