[关闭]
@cyysu 2017-10-13T09:09:48.000000Z 字数 5076 阅读 967

Makefile-项目篇(二)

  • 时间:2017年10月13日
  • 作者:Kali
  • 邮箱:cyysu.github.io@gmail.com
  • 版本:3.0
  • 描述:Makefile-项目二,介绍一片编译go程序的makefile

Makefile系列教程


项目实战

  1. # 定义模块名字
  2. PACKAGE = hellogopher
  3. # 设置时间
  4. DATE ?= $(shell date +%FT%T%z)
  5. # git describe命令显示离当前提交最近的标签。如果第一条命令执行成功 ,那么就不会执行第二条命令
  6. VERSION ?= $(shell git describe --tags --always --dirty --match=v* 2> /dev/null || \
  7. cat $(CURDIR)/.version 2> /dev/null || echo v0)
  8. GOPATH = $(CURDIR)/.gopath~
  9. BIN = $(GOPATH)/bin
  10. BASE = $(GOPATH)/src/$(PACKAGE)
  11. # 这里的逻辑我们先不分析,后面有需要在去分析
  12. PKGS = $(or $(PKG),$(shell cd $(BASE) && env GOPATH=$(GOPATH) $(GO) list ./... | grep -v "^$(PACKAGE)/vendor/"))
  13. TESTPKGS = $(shell env GOPATH=$(GOPATH) $(GO) list -f '{{ if or .TestGoFiles .XTestGoFiles }}{{ .ImportPath }}{{ end }}' $(PKGS))
  14. GO = go
  15. GODOC = godoc
  16. GOFMT = gofmt
  17. TIMEOUT = 15
  18. V = 0
  19. # 在V中找到属于1的字符串,如果找到了返回就是空,如果没有找到返回的就是@ 如果用在命令前面就是不回显命令
  20. Q = $(if $(filter 1,$V),,@)
  21. M = $(shell printf "\033[34;1m▶\033[0m")
  22. .PHONY: all
  23. # ; 表示这个之后就是命令,这个时本目标开头先执行的
  24. # | 这个我查找了一下也没有找到具体意义,我写了一个测试发现没什么作用。可能就是一个规范,如果目标时变量,前面就加上 | 这个大家先这么记住,如果后面遇到我会告诉大家
  25. # @ 这个也是没有找到定义的,目前只能当做是规范。
  26. all: fmt lint vendor | $(BASE) ; $(info $(M) building executable…) @ ## Build program binary
  27. $Q cd $(BASE) && $(GO) build \
  28. -tags release \
  29. -ldflags '-X $(PACKAGE)/cmd.Version=$(VERSION) -X $(PACKAGE)/cmd.BuildDate=$(DATE)' \
  30. -o bin/$(PACKAGE) main.go
  31. # $@ 表示目标 这里表示$(BASE)
  32. # 这个目标表示将项目文件复制链接到GOPATH目录
  33. $(BASE): ; $(info $(M) setting GOPATH…)
  34. @mkdir -p $(dir $@)
  35. @ln -sf $(CURDIR) $@
  36. # Tools
  37. GODEP = $(BIN)/dep
  38. GODEPVERSION = 0.3.1
  39. #go get -d 表示让命令只执行下载操作,而不执行安装动作
  40. $(BIN)/dep: | $(BASE) ; $(info $(M) building go dep…)
  41. $Q go get -d github.com/golang/dep/cmd/dep
  42. $Q cd $(GOPATH)/src/github.com/golang/dep ; git checkout -q v$(GODEPVERSION)
  43. $Q go get github.com/golang/dep/cmd/dep
  44. GOLINT = $(BIN)/golint
  45. $(BIN)/golint: | $(BASE) ; $(info $(M) building golint…)
  46. $Q go get github.com/golang/lint/golint
  47. GOCOVMERGE = $(BIN)/gocovmerge
  48. $(BIN)/gocovmerge: | $(BASE) ; $(info $(M) building gocovmerge…)
  49. $Q go get github.com/wadey/gocovmerge
  50. GOCOV = $(BIN)/gocov
  51. $(BIN)/gocov: | $(BASE) ; $(info $(M) building gocov…)
  52. $Q go get github.com/axw/gocov/...
  53. GOCOVXML = $(BIN)/gocov-xml
  54. $(BIN)/gocov-xml: | $(BASE) ; $(info $(M) building gocov-xml…)
  55. $Q go get github.com/AlekSi/gocov-xml
  56. GO2XUNIT = $(BIN)/go2xunit
  57. $(BIN)/go2xunit: | $(BASE) ; $(info $(M) building go2xunit…)
  58. $Q go get github.com/tebeka/go2xunit
  59. # Tests
  60. TEST_TARGETS := test-default test-bench test-short test-verbose test-race
  61. .PHONY: $(TEST_TARGETS) test-xml check test tests
  62. test-bench: ARGS=-run=__absolutelynothing__ -bench=. ## Run benchmarks
  63. test-short: ARGS=-short ## Run only short tests
  64. test-verbose: ARGS=-v ## Run tests in verbose mode with coverage reporting
  65. test-race: ARGS=-race ## Run tests with race detector
  66. $(TEST_TARGETS): NAME=$(MAKECMDGOALS:test-%=%)
  67. $(TEST_TARGETS): test
  68. check test tests: fmt lint vendor | $(BASE) ; $(info $(M) running $(NAME:%=% )tests…) @ ## Run tests
  69. $Q cd $(BASE) && $(GO) test -timeout $(TIMEOUT)s $(ARGS) $(TESTPKGS)
  70. test-xml: fmt lint vendor | $(BASE) $(GO2XUNIT) ; $(info $(M) running $(NAME:%=% )tests…) @ ## Run tests with xUnit output
  71. $Q cd $(BASE) && 2>&1 $(GO) test -timeout 20s -v $(TESTPKGS) | tee test/tests.output
  72. $(GO2XUNIT) -fail -input test/tests.output -output test/tests.xml
  73. COVERAGE_MODE = atomic
  74. COVERAGE_PROFILE = $(COVERAGE_DIR)/profile.out
  75. COVERAGE_XML = $(COVERAGE_DIR)/coverage.xml
  76. COVERAGE_HTML = $(COVERAGE_DIR)/index.html
  77. .PHONY: test-coverage test-coverage-tools
  78. test-coverage-tools: | $(GOCOVMERGE) $(GOCOV) $(GOCOVXML)
  79. test-coverage: COVERAGE_DIR := $(CURDIR)/test/coverage.$(shell date -u +"%Y-%m-%dT%H:%M:%SZ")
  80. test-coverage: fmt lint vendor test-coverage-tools | $(BASE) ; $(info $(M) running coverage tests…) @ ## Run coverage tests
  81. $Q mkdir -p $(COVERAGE_DIR)/coverage
  82. $Q cd $(BASE) && for pkg in $(TESTPKGS); do \
  83. $(GO) test \
  84. -coverpkg=$$($(GO) list -f '{{ join .Deps "\n" }}' $$pkg | \
  85. grep '^$(PACKAGE)/' | grep -v '^$(PACKAGE)/vendor/' | \
  86. tr '\n' ',')$$pkg \
  87. -covermode=$(COVERAGE_MODE) \
  88. -coverprofile="$(COVERAGE_DIR)/coverage/`echo $$pkg | tr "/" "-"`.cover" $$pkg ;\
  89. done
  90. $Q $(GOCOVMERGE) $(COVERAGE_DIR)/coverage/*.cover > $(COVERAGE_PROFILE)
  91. $Q $(GO) tool cover -html=$(COVERAGE_PROFILE) -o $(COVERAGE_HTML)
  92. $Q $(GOCOV) convert $(COVERAGE_PROFILE) | $(GOCOVXML) > $(COVERAGE_XML)
  93. .PHONY: lint
  94. lint: vendor | $(BASE) $(GOLINT) ; $(info $(M) running golint…) @ ## Run golint
  95. $Q cd $(BASE) && ret=0 && for pkg in $(PKGS); do \
  96. test -z "$$($(GOLINT) $$pkg | tee /dev/stderr)" || ret=1 ; \
  97. done ; exit $$ret
  98. .PHONY: fmt
  99. fmt: ; $(info $(M) running gofmt…) @ ## Run gofmt on all source files
  100. @ret=0 && for d in $$($(GO) list -f '{{.Dir}}' ./... | grep -v /vendor/); do \
  101. $(GOFMT) -l -w $$d/*.go || ret=$$? ; \
  102. done ; exit $$ret
  103. # Dependency management
  104. vendor: Gopkg.toml Gopkg.lock | $(BASE) $(GODEP) ; $(info $(M) retrieving dependencies…)
  105. $Q cd $(BASE) && $(GODEP) ensure
  106. @ln -nsf . vendor/src
  107. @touch $@
  108. .PHONY: vendor-update
  109. vendor-update: vendor | $(BASE) $(GODEP)
  110. ifeq "$(origin PKG)" "command line"
  111. $(info $(M) updating $(PKG) dependency…)
  112. $Q cd $(BASE) && $(GODEP) ensure -update $(PKG)
  113. else
  114. $(info $(M) updating all dependencies…)
  115. $Q cd $(BASE) && $(GODEP) ensure -update
  116. endif
  117. @ln -nsf . vendor/src
  118. @touch vendor
  119. # Misc
  120. .PHONY: clean
  121. clean: ; $(info $(M) cleaning…) @ ## Cleanup everything
  122. @rm -rf $(GOPATH)
  123. @rm -rf bin
  124. @rm -rf test/tests.* test/coverage.*
  125. # $(MAKEFILE_LIST) 表示
  126. # grep -E 将范本样式为延伸的普通表示法来使用,意味着使用能使用扩展正则表达式。
  127. # RS是记录分割符: 表示 \n 符号 awk '{print $0}' test1 //awk 'BEGIN{RS="\n"};{print $0}' test1 这二个是一样的
  128. # FS是指定列分隔符
  129. # printf "\033[36m%-15s\033[0m %s\n", $$1, $$2 其中的 - 表示左对齐为15和字符 $$1 表示分割出来第一段 $$2 表示分割出来第二段
  130. .PHONY: help
  131. help:
  132. @grep -E '^[ a-zA-Z_-]+:.*?## .*$$' $(MAKEFILE_LIST) | \
  133. awk 'BEGIN {FS = ":.*?## "}; {printf "\033[36m%-20s\033[0m %s\n", $$1, $$2}'
  134. .PHONY: version
  135. version:
  136. @echo $(VERSION)

打赏

                    支付宝                                                         微信

微信与支付宝支付

添加新批注
在作者公开此批注前,只有你和作者可见。
回复批注