github.com/google/grumpy@v0.0.0-20171122020858-3ec87959189c/Makefile (about) 1 # Copyright 2016 Google Inc. All Rights Reserved. 2 # 3 # Licensed under the Apache License, Version 2.0 (the "License"); 4 # you may not use this file except in compliance with the License. 5 # You may obtain a copy of the License at 6 # 7 # http://www.apache.org/licenses/LICENSE-2.0 8 # 9 # Unless required by applicable law or agreed to in writing, software 10 # distributed under the License is distributed on an "AS IS" BASIS, 11 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 # See the License for the specific language governing permissions and 13 # limitations under the License. 14 15 # ------------------------------------------------------------------------------ 16 # General setup 17 # ------------------------------------------------------------------------------ 18 19 GO_ENV := $(shell go env GOOS GOARCH) 20 GOOS ?= $(word 1,$(GO_ENV)) 21 GOARCH ?= $(word 2,$(GO_ENV)) 22 ROOT_DIR := $(realpath .) 23 PKG_DIR := build/pkg/$(GOOS)_$(GOARCH) 24 25 # Try python2 and then python if PYTHON has not been set 26 ifeq ($(PYTHON),) 27 ifneq ($(shell which python2),) 28 PYTHON = python2 29 else 30 PYTHON = python 31 endif 32 endif 33 PYTHON_BIN := $(shell which $(PYTHON)) 34 PYTHON_VER := $(word 2,$(shell $(PYTHON) -V 2>&1)) 35 GO_REQ_MAJ := 1 36 GO_REQ_MIN := 9 37 GO_MAJ_MIN := $(subst go,, $(word 3,$(shell go version 2>&1)) ) 38 GO_MAJ := $(word 1,$(subst ., ,$(GO_MAJ_MIN) )) 39 GO_MIN := $(word 2,$(subst ., ,$(GO_MAJ_MIN) )) 40 41 ifeq ($(filter 2.7.%,$(PYTHON_VER)),) 42 $(error unsupported Python version $(PYTHON_VER), Grumpy only supports 2.7.x. To use a different python binary such as python2, run: 'make PYTHON=python2 ...') 43 endif 44 45 ifneq ($(shell test $(GO_MAJ) -ge $(GO_REQ_MAJ) -a $(GO_MIN) -ge $(GO_REQ_MIN) && echo ok),ok) 46 $(error unsupported Go version $(GO_VER), Grumpy requires at least $(GO_REQ_MAJ).$(GO_REQ_MIN). Please update Go) 47 endif 48 49 PY_DIR := build/lib/python2.7/site-packages 50 PY_INSTALL_DIR := $(shell $(PYTHON) -c "from distutils.sysconfig import get_python_lib; print(get_python_lib())") 51 52 export GOPATH := $(ROOT_DIR)/build 53 export PYTHONPATH := $(ROOT_DIR)/$(PY_DIR) 54 export PATH := $(ROOT_DIR)/build/bin:$(PATH) 55 56 GOPATH_PY_ROOT := $(GOPATH)/src/__python__ 57 58 PYTHONPARSER_SRCS := $(patsubst third_party/%,$(PY_DIR)/grumpy/%,$(wildcard third_party/pythonparser/*.py)) 59 60 COMPILER_BIN := build/bin/grumpc 61 COMPILER_SRCS := $(addprefix $(PY_DIR)/grumpy/compiler/,$(notdir $(shell find compiler -name '*.py' -not -name '*_test.py'))) $(PY_DIR)/grumpy/__init__.py 62 COMPILER_TESTS := $(patsubst %.py,grumpy/%,$(filter-out compiler/expr_visitor_test.py compiler/stmt_test.py,$(wildcard compiler/*_test.py))) 63 COMPILER_TEST_SRCS := $(patsubst %,$(PY_DIR)/%.py,$(COMPILER_TESTS)) 64 COMPILER_SHARDED_TEST_SRCS := $(patsubst %,$(PY_DIR)/grumpy/compiler/%,expr_visitor_test.py stmt_test.py) 65 COMPILER_PASS_FILES := $(patsubst %,$(PY_DIR)/%.pass,$(COMPILER_TESTS)) 66 COMPILER_EXPR_VISITOR_PASS_FILES := $(patsubst %,$(PY_DIR)/grumpy/compiler/expr_visitor_test.%of32.pass,$(shell seq 32)) 67 COMPILER_STMT_PASS_FILES := $(patsubst %,$(PY_DIR)/grumpy/compiler/stmt_test.%of16.pass,$(shell seq 16)) 68 COMPILER_D_FILES := $(patsubst %,$(PY_DIR)/%.d,$(COMPILER_TESTS)) 69 COMPILER := $(COMPILER_BIN) $(COMPILER_SRCS) $(PYTHONPARSER_SRCS) 70 71 PKGC_BIN := build/bin/pkgc 72 73 RUNNER_BIN := build/bin/grumprun 74 RUNTIME_SRCS := $(addprefix build/src/grumpy/,$(notdir $(wildcard runtime/*.go))) 75 RUNTIME := $(PKG_DIR)/grumpy.a 76 RUNTIME_PASS_FILE := build/runtime.pass 77 RUNTIME_COVER_FILE := $(PKG_DIR)/grumpy.cover 78 RUNNER = $(RUNNER_BIN) $(COMPILER) $(RUNTIME) $(STDLIB) 79 80 LIB_SRCS := $(patsubst lib/%,$(GOPATH_PY_ROOT)/%,$(shell find lib -name '*.py')) 81 THIRD_PARTY_STDLIB_SRCS := $(patsubst third_party/stdlib/%,$(GOPATH_PY_ROOT)/%,$(shell find third_party/stdlib -name '*.py')) 82 THIRD_PARTY_PYPY_SRCS := $(patsubst third_party/pypy/%,$(GOPATH_PY_ROOT)/%,$(shell find third_party/pypy -name '*.py')) 83 THIRD_PARTY_OUROBOROS_SRCS := $(patsubst third_party/ouroboros/%,$(GOPATH_PY_ROOT)/%,$(shell find third_party/ouroboros -name '*.py')) 84 STDLIB_SRCS := $(LIB_SRCS) $(THIRD_PARTY_STDLIB_SRCS) $(THIRD_PARTY_PYPY_SRCS) $(THIRD_PARTY_OUROBOROS_SRCS) 85 86 STDLIB_PACKAGES := $(patsubst $(GOPATH_PY_ROOT)/%.py,%,$(patsubst $(GOPATH_PY_ROOT)/%/__init__.py,%,$(STDLIB_SRCS))) 87 STDLIB := $(patsubst %,$(PKG_DIR)/__python__/%.a,$(STDLIB_PACKAGES)) 88 STDLIB_TESTS := \ 89 itertools_test \ 90 math_test \ 91 os/path_test \ 92 os_test \ 93 random_test \ 94 re_tests \ 95 sys_test \ 96 tempfile_test \ 97 test/test_bisect \ 98 test/test_colorsys \ 99 test/test_datetime \ 100 test/test_dict \ 101 test/test_dircache \ 102 test/test_dummy_thread \ 103 test/test_fpformat \ 104 test/test_genericpath \ 105 test/test_list \ 106 test/test_md5 \ 107 test/test_mimetools \ 108 test/test_mutex \ 109 test/test_operator \ 110 test/test_quopri \ 111 test/test_queue \ 112 test/test_rfc822 \ 113 test/test_sched \ 114 test/test_select \ 115 test/test_slice \ 116 test/test_stat \ 117 test/test_string \ 118 test/test_threading \ 119 test/test_tuple \ 120 test/test_uu \ 121 time_test \ 122 types_test \ 123 weetest_test 124 STDLIB_PASS_FILES := $(patsubst %,build/testing/%.pass,$(notdir $(STDLIB_TESTS))) 125 126 ACCEPT_TESTS := $(patsubst %.py,%,$(wildcard testing/*.py)) 127 ACCEPT_PASS_FILES := $(patsubst %,build/%.pass,$(ACCEPT_TESTS)) 128 ACCEPT_PY_PASS_FILES := $(patsubst %,build/%_py.pass,$(filter-out %/native_test,$(ACCEPT_TESTS))) 129 130 BENCHMARKS := $(patsubst %.py,%,$(wildcard benchmarks/*.py)) 131 BENCHMARK_BINS := $(patsubst %,build/%_benchmark,$(BENCHMARKS)) 132 133 TOOL_BINS = $(patsubst %,build/bin/%,benchcmp coverparse diffrange genmake pydeps) 134 135 GOLINT_BIN = build/bin/golint 136 PYLINT_BIN = build/bin/pylint 137 138 all: $(COMPILER) $(RUNNER) $(RUNTIME) $(TOOL_BINS) 139 140 benchmarks: $(BENCHMARK_BINS) 141 142 clean: 143 @rm -rf build 144 145 # Convenient wrapper around grumprun that avoids having to set up PATH, etc. 146 run: $(RUNNER) 147 @$(RUNNER_BIN) 148 149 test: $(ACCEPT_PASS_FILES) $(ACCEPT_PY_PASS_FILES) $(COMPILER_PASS_FILES) $(COMPILER_EXPR_VISITOR_PASS_FILES) $(COMPILER_STMT_PASS_FILES) $(RUNTIME_PASS_FILE) $(STDLIB_PASS_FILES) 150 151 precommit: cover gofmt lint test 152 153 .PHONY: all benchmarks clean cover gofmt golint install lint precommit pylint run test 154 155 # ------------------------------------------------------------------------------ 156 # grumpc compiler 157 # ------------------------------------------------------------------------------ 158 159 $(COMPILER_BIN) $(RUNNER_BIN) $(TOOL_BINS): build/bin/%: tools/% 160 @mkdir -p build/bin 161 @cp -f $< $@ 162 @sed -i.bak -e '1s@/usr/bin/env python@$(PYTHON_BIN)@' $@ 163 @rm -f $@.bak 164 165 $(COMPILER_SRCS) $(COMPILER_TEST_SRCS) $(COMPILER_SHARDED_TEST_SRCS): $(PY_DIR)/grumpy/%.py: %.py 166 @mkdir -p $(PY_DIR)/grumpy/compiler 167 @cp -f $< $@ 168 169 $(COMPILER_PASS_FILES): %.pass: %.py $(COMPILER) $(COMPILER_TEST_SRCS) 170 @$(PYTHON) $< -q 171 @touch $@ 172 @echo compiler/`basename $*` PASS 173 174 # NOTE: In the regex below we use (\.|$) instead of \> because the latter is 175 # not available in the awk available on OS X. 176 $(COMPILER_D_FILES): $(PY_DIR)/%.d: $(PY_DIR)/%.py $(COMPILER_SRCS) $(PYTHONPARSER_SRCS) 177 @$(PYTHON) -m modulefinder $< | awk '{if (match($$2, /^grumpy(\.|$$)/)) { print "$(PY_DIR)/$*.pass: " substr($$3, length("$(ROOT_DIR)/") + 1) }}' > $@ 178 179 -include $(COMPILER_D_FILES) 180 181 # Does not depend on stdlibs since it makes minimal use of them. 182 $(COMPILER_EXPR_VISITOR_PASS_FILES): $(PY_DIR)/grumpy/compiler/expr_visitor_test.%.pass: $(PY_DIR)/grumpy/compiler/expr_visitor_test.py $(RUNNER_BIN) $(COMPILER) $(RUNTIME) $(PKG_DIR)/__python__/traceback.a 183 @$(PYTHON) $< --shard=$* 184 @touch $@ 185 @echo 'compiler/expr_visitor_test $* PASS' 186 187 COMPILER_STMT_PASS_FILE_DEPS := \ 188 $(PKG_DIR)/__python__/__go__/grumpy.a \ 189 $(PKG_DIR)/__python__/__go__/os.a \ 190 $(PKG_DIR)/__python__/__go__/runtime.a \ 191 $(PKG_DIR)/__python__/__go__/time.a \ 192 $(PKG_DIR)/__python__/__go__/unicode.a \ 193 $(PKG_DIR)/__python__/sys.a \ 194 $(PKG_DIR)/__python__/traceback.a 195 196 # Does not depend on stdlibs since it makes minimal use of them. 197 $(COMPILER_STMT_PASS_FILES): $(PY_DIR)/grumpy/compiler/stmt_test.%.pass: $(PY_DIR)/grumpy/compiler/stmt_test.py $(RUNNER_BIN) $(COMPILER) $(RUNTIME) $(COMPILER_STMT_PASS_FILE_DEPS) 198 @$(PYTHON) $< --shard=$* 199 @touch $@ 200 @echo 'compiler/stmt_test $* PASS' 201 202 $(PKGC_BIN): tools/pkgc.go 203 @mkdir -p $(@D) 204 @go build -o $@ $< 205 206 # ------------------------------------------------------------------------------ 207 # Grumpy runtime 208 # ------------------------------------------------------------------------------ 209 210 $(RUNTIME_SRCS): build/src/grumpy/%.go: runtime/%.go 211 @mkdir -p build/src/grumpy 212 @cp -f $< $@ 213 214 $(RUNTIME): $(filter-out %_test.go,$(RUNTIME_SRCS)) 215 @mkdir -p $(PKG_DIR) 216 @go tool compile -o $@ -p grumpy -complete -I $(PKG_DIR) -pack $^ 217 218 $(RUNTIME_PASS_FILE): $(RUNTIME) $(filter %_test.go,$(RUNTIME_SRCS)) 219 @go test grumpy 220 @touch $@ 221 @echo 'runtime/grumpy PASS' 222 223 $(RUNTIME_COVER_FILE): $(RUNTIME) $(filter %_test.go,$(RUNTIME_SRCS)) 224 @go test -coverprofile=$@ grumpy 225 226 cover: $(RUNTIME_COVER_FILE) $(TOOL_BINS) 227 @bash -c 'comm -12 <(coverparse $< | sed "s/^grumpy/runtime/" | sort) <(git diff --dst-prefix= $(DIFF_COMMIT) | diffrange | sort)' | sort -t':' -k1,1 -k2n,2 | sed 's/$$/: missing coverage/' | tee errors.err 228 @test ! -s errors.err 229 230 build/gofmt.diff: $(wildcard runtime/*.go) 231 @gofmt -d $^ > $@ 232 233 gofmt: build/gofmt.diff 234 @if [ -s $< ]; then echo 'gofmt found errors, run: gofmt -w $(ROOT_DIR)/runtime/*.go'; false; fi 235 236 $(GOLINT_BIN): 237 @go get -u github.com/golang/lint/golint 238 239 golint: $(GOLINT_BIN) 240 @$(GOLINT_BIN) -set_exit_status runtime 241 242 # Don't use system pip for this since behavior varies a lot between versions. 243 # Instead build pylint from source. Dependencies will be fetched by distutils. 244 $(PYLINT_BIN): 245 @mkdir -p build/third_party 246 @cd build/third_party && curl -sL https://pypi.io/packages/source/p/pylint/pylint-1.6.4.tar.gz | tar -zx 247 @cd build/third_party/pylint-1.6.4 && $(PYTHON) setup.py install --prefix $(ROOT_DIR)/build 248 249 pylint: $(PYLINT_BIN) $(COMPILER_SRCS) $(PYTHONPARSER_SRCS) $(COMPILER_BIN) $(RUNNER_BIN) $(TOOL_BINS) 250 @$(PYTHON) $(PYLINT_BIN) $(COMPILER_SRCS) $(COMPILER_BIN) $(RUNNER_BIN) $(TOOL_BINS) 251 252 lint: golint pylint 253 254 # ------------------------------------------------------------------------------ 255 # Native modules 256 # ------------------------------------------------------------------------------ 257 258 $(PKG_DIR)/__python__/__go__/%.a: build/src/__python__/__go__/%/module.go $(RUNTIME) 259 @mkdir -p $(@D) 260 @go install __python__/__go__/$* 261 262 build/src/__python__/__go__/%/module.go: $(PKGC_BIN) $(RUNTIME) 263 @mkdir -p $(@D) 264 @$(PKGC_BIN) $* > $@ 265 266 $(PKG_DIR)/__python__/__go__/grumpy.a: $(RUNTIME) 267 268 .PRECIOUS: build/src/__python__/__go__/%/module.go $(PKG_DIR)/__python__/__go__/%.a 269 270 # ------------------------------------------------------------------------------ 271 # Standard library 272 # ------------------------------------------------------------------------------ 273 274 $(LIB_SRCS): $(GOPATH_PY_ROOT)/%: lib/% 275 @mkdir -p $(@D) 276 @cp -f $< $@ 277 278 $(THIRD_PARTY_STDLIB_SRCS): $(GOPATH_PY_ROOT)/%: third_party/stdlib/% 279 @mkdir -p $(@D) 280 @cp -f $< $@ 281 282 $(THIRD_PARTY_PYPY_SRCS): $(GOPATH_PY_ROOT)/%: third_party/pypy/% 283 @mkdir -p $(@D) 284 @cp -f $< $@ 285 286 287 $(THIRD_PARTY_OUROBOROS_SRCS): $(GOPATH_PY_ROOT)/%: third_party/ouroboros/% 288 @mkdir -p $(@D) 289 @cp -f $< $@ 290 291 build/stdlib.mk: build/bin/genmake | $(STDLIB_SRCS) 292 @genmake build > $@ 293 294 -include build/stdlib.mk 295 296 $(patsubst %,build/src/__python__/%/module.go,$(STDLIB_PACKAGES)): $(COMPILER) 297 $(patsubst %,build/src/__python__/%/module.d,$(STDLIB_PACKAGES)): build/bin/pydeps $(PYTHONPARSER_SRCS) $(COMPILER) 298 $(patsubst %,$(PKG_DIR)/__python__/%.a,$(STDLIB_PACKAGES)): $(RUNTIME) 299 300 define GRUMPY_STDLIB_TEST 301 build/testing/$(notdir $(1)).pass: $(RUNTIME) $(PKG_DIR)/__python__/$(1).a $(RUNNER_BIN) $(PKG_DIR)/__python__/traceback.a 302 @mkdir -p $$(@D) 303 @$(RUNNER_BIN) -m $(subst /,.,$(1)) 304 @touch $$@ 305 @echo 'lib/$(1) PASS' 306 307 endef 308 309 $(eval $(foreach x,$(STDLIB_TESTS),$(call GRUMPY_STDLIB_TEST,$(x)))) 310 311 # ------------------------------------------------------------------------------ 312 # Acceptance tests & benchmarks 313 # ------------------------------------------------------------------------------ 314 315 $(PY_DIR)/weetest.py: lib/weetest.py 316 @cp -f $< $@ 317 318 $(PYTHONPARSER_SRCS): $(PY_DIR)/grumpy/%: third_party/% 319 @mkdir -p $(@D) 320 @cp -f $< $@ 321 322 $(ACCEPT_PASS_FILES): build/%_test.pass: %_test.py $(RUNTIME) $(STDLIB) $(RUNNER_BIN) 323 @mkdir -p $(@D) 324 @$(RUNNER_BIN) < $< 325 @touch $@ 326 @echo '$*_test PASS' 327 328 NATIVE_TEST_DEPS := \ 329 $(PKG_DIR)/__python__/__go__/encoding/csv.a \ 330 $(PKG_DIR)/__python__/__go__/image.a \ 331 $(PKG_DIR)/__python__/__go__/math.a \ 332 $(PKG_DIR)/__python__/__go__/strings.a 333 334 build/testing/native_test.pass: $(NATIVE_TEST_DEPS) 335 336 $(ACCEPT_PY_PASS_FILES): build/%_py.pass: %.py $(PY_DIR)/weetest.py 337 @mkdir -p $(@D) 338 @$(PYTHON) $< 339 @touch $@ 340 @echo '$*_py PASS' 341 342 $(patsubst %,build/%.go,$(BENCHMARKS)): build/%.go: %.py $(COMPILER) 343 @mkdir -p $(@D) 344 @$(COMPILER_BIN) $< > $@ 345 346 $(BENCHMARK_BINS): build/benchmarks/%_benchmark: build/benchmarks/%.go $(RUNTIME) $(STDLIB) 347 @mkdir -p $(@D) 348 @go build -o $@ $< 349 350 # ------------------------------------------------------------------------------ 351 # Installation 352 # ------------------------------------------------------------------------------ 353 354 install: $(RUNNER_BIN) $(COMPILER) $(RUNTIME) $(STDLIB) 355 # Binary executables 356 install -d "$(DESTDIR)/usr/bin" 357 install -m755 build/bin/grumpc "$(DESTDIR)/usr/bin/grumpc" 358 install -m755 build/bin/grumprun "$(DESTDIR)/usr/bin/grumprun" 359 # Python module 360 install -d "$(DESTDIR)"{/usr/lib/go,"$(PY_INSTALL_DIR)"} 361 cp -rv "$(PY_DIR)/grumpy" "$(DESTDIR)$(PY_INSTALL_DIR)" 362 # Go package and sources 363 install -d "$(DESTDIR)/usr/lib/go/" 364 cp -rv build/pkg build/src "$(DESTDIR)/usr/lib/go/"