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/"