Contoh membuat aplikasi Makefile for Go

Dalam tutorial ini, kita akan melihat bagaimana pengembang Go dapat menggunakan Makefile untuk mengembangkan aplikasi mereka sendiri.

gambar

Apa itu Makefile?


Makefile adalah alat otomatisasi yang sangat berguna yang dapat Anda gunakan untuk menjalankan dan membangun aplikasi tidak hanya di Go, tetapi juga di sebagian besar bahasa pemrograman lainnya.

Ini sering terlihat di direktori root dari banyak aplikasi Go di Github dan Gitlab. Ini banyak digunakan sebagai alat untuk mengotomatisasi tugas-tugas yang sering menyertai pengembang.

Jika Anda menggunakan Go untuk membuat layanan web, maka Makefile akan membantu menyelesaikan tugas-tugas berikut:

  • Otomatis permintaan perintah sederhana, seperti: kompilasi, mulai, berhenti, tonton, dll.
  • Kelola variabel lingkungan spesifik proyek. Itu harus menyertakan file .env.
  • Mode pengembangan yang secara otomatis dikompilasi pada perubahan.
  • Mode pengembangan yang menunjukkan kesalahan kompilasi.
  • Menentukan GOPATH untuk proyek tertentu sehingga kami dapat menyimpan dependensi di folder vendor.
  • Pemantauan file yang disederhanakan, misalnya, membuat watch run = "go test. / ... "

Berikut adalah struktur direktori khas untuk suatu proyek:

.env Makefile main.go bin/ src/ vendor/ 

Jika kita memanggil perintah make dalam direktori ini, kita mendapatkan output berikut:

 $ make Choose a command run in my-web-server: install Install missing dependencies. Runs `go get` internally. start Start in development mode. Auto-starts when code changes. stop Stop development mode. compile Compile the binary. watch Run given command when code changes. eg; make watch run="go test ./..." exec Run given command, wrapped with custom GOPATH. eg; make exec run="go test ./..." clean Clean build files. Runs `go clean` internally. 

Variabel lingkungan


Hal pertama yang kita inginkan dari Makefile adalah memasukkan variabel lingkungan yang kita definisikan untuk proyek. Oleh karena itu, baris pertama akan terlihat seperti ini:

 include .env 

Selanjutnya, kita tentukan nama proyek, Go folder / file, path ke pid ...

 PROJECTNAME=$(shell basename "$(PWD)") # Go . GOBASE=$(shell pwd) GOPATH=$(GOBASE)/vendor:$(GOBASE):/home/azer/code/golang #       . GOBIN=$(GOBASE)/bin GOFILES=$(wildcard *.go) #     ,       . STDERR=/tmp/.$(PROJECTNAME)-stderr.txt # PID-    ,       PID=/tmp/.$(PROJECTNAME)-api-server.pid # Make     Linux.   silent. MAKEFLAGS += --silent 

Di sisa Makefile, kita akan sering menggunakan variabel GOPATH. Semua tim kami harus dikaitkan dengan GOPATH dari proyek tertentu, jika tidak mereka tidak akan bekerja. Ini memberikan isolasi bersih dari proyek kami, tetapi pada saat yang sama menyulitkan pekerjaan. Untuk menyederhanakan tugas, kita dapat menambahkan perintah exec yang akan mengeksekusi perintah apa pun dengan GOPATH kita.

 # exec:     GOPATH. : make exec run = " go test ./...” exec: @GOPATH=$(GOPATH) GOBIN=$(GOBIN) $(run) 

Namun, perlu diingat bahwa Anda perlu menggunakan exec hanya jika Anda ingin melakukan sesuatu yang tidak dapat ditulis dalam makefile.

Mode pengembangan


Mode pengembangan harus:

  • Bersihkan cache yang dibangun
  • Kompilasi kode
  • Jalankan layanan di latar belakang
  • Ulangi langkah ini ketika kode berubah.

Kedengarannya mudah. Namun, kesulitannya terletak pada kenyataan bahwa kami menjalankan layanan dan pengamat file secara bersamaan. Sebelum memulai proses baru, kita harus memastikan bahwa itu berhenti dengan benar dan bahwa kita tidak melanggar perilaku baris perintah yang biasa ketika menekan Control-C atau Control-D.

 start: bash -c "trap 'make stop' EXIT; $(MAKE) compile start-server watch run='make compile start-server'" stop: stop-server 

Kode yang dijelaskan di atas menyelesaikan tugas-tugas berikut:

  • Mengkompilasi dan menjalankan layanan di latar belakang.
  • Proses utama tidak berjalan di latar belakang, jadi kita bisa menghentikannya menggunakan Control-C.
  • Menghentikan proses latar belakang saat proses utama terganggu. perangkap dibutuhkan hanya untuk ini.
  • Mengkompilasi ulang dan me-restart server ketika kode berubah.

Di bagian berikut, saya akan menjelaskan perintah-perintah ini secara lebih rinci.

Kompilasi


Perintah kompilasi tidak hanya memanggil kompilasi go di latar belakang - itu menghapus output kesalahan dan mencetak versi yang disederhanakan.

Ini adalah apa yang tampak seperti output baris perintah ketika kami melakukan penyuntingan:

gambar

 compile: @-touch $(STDERR) @-rm $(STDERR) @-$(MAKE) -s go-compile 2> $(STDERR) @cat $(STDERR) | sed -e '1s/.*/\nError:\n/' | sed 's/make\[.*/ /' | sed "/^/s/^/ /" 1>&2 

Server mulai / berhenti


start-server memulai biner yang dikompilasi di latar belakang, menyimpan PID-nya ke file sementara. stop-server membaca PID dan membunuh proses jika perlu.

 start-server: @echo " > $(PROJECTNAME) is available at $(ADDR)" @-$(GOBIN)/$(PROJECTNAME) 2>&1 & echo $$! > $(PID) @cat $(PID) | sed "/^/s/^/ \> PID: /" stop-server: @-touch $(PID) @-kill `cat $(PID)` 2> /dev/null || true @-rm $(PID) restart-server: stop-server start-server 

Ubah pemantauan


Kami membutuhkan file pengamat untuk melacak perubahan. Saya mencoba banyak, tetapi tidak dapat menemukan yang cocok, jadi saya menulis alat pemantauan file saya sendiri - yolo . Instal menggunakan perintah:

 $ go get github.com/azer/yolo 

Setelah instalasi, kami dapat mengamati perubahan dalam direktori proyek, tidak termasuk folder vendor dan bin.

 ## watch:      ,  make watch run="echo 'hey'" watch: @yolo -i . -e vendor -e bin -c $(run) 

Kami sekarang memiliki perintah arloji yang secara rekursif melacak perubahan ke direktori proyek, dengan pengecualian dari direktori vendor. Kita bisa melewatkan perintah apa saja untuk dijalankan.
Misalnya, mulai panggilan make-start-server ketika kode berubah:

 make watch run="make compile start-server" 

Kita dapat menggunakannya untuk menjalankan tes atau memeriksa kondisi lomba secara otomatis. Variabel lingkungan akan ditetapkan pada saat runtime, sehingga Anda tidak perlu khawatir tentang GOPATH:

 make watch run="go test ./..." 

Fitur bagus Yolo adalah antarmuka webnya. Jika Anda mengaktifkannya, Anda dapat langsung melihat output dari perintah Anda di antarmuka web. Yang perlu Anda lakukan adalah memberikan opsi -a:

 yolo -i . -e vendor -e bin -c "go run foobar.go" -a localhost:9001 

Buka localhost: 9001 di browser dan segera lihat hasil pekerjaan:

gambar

Instalasi Ketergantungan


Ketika kami membuat perubahan pada kode, kami ingin dependensi yang hilang dimuat sebelum kompilasi. Perintah instal akan melakukan pekerjaan untuk kita:

 install: go-get 

Kami akan mengotomatiskan panggilan instal ketika file berubah sebelum kompilasi, sehingga dependensi akan diinstal secara otomatis. Jika Anda ingin menginstal dependensi secara manual, Anda dapat menjalankan:

 make install get="github.com/foo/bar" 

Secara internal, perintah ini akan dikonversi ke:

 $ GOPATH=~/my-web-server GOBIN=~/my-web-server/bin go get github.com/foo/bar 

Bagaimana cara kerjanya? Lihat bagian selanjutnya di mana kami menambahkan perintah Go biasa untuk mengimplementasikan perintah tingkat yang lebih tinggi.

Pergi Perintah


Karena kita ingin menginstal GOPATH di direktori proyek untuk menyederhanakan manajemen dependensi, yang belum secara resmi diputuskan dalam ekosistem Go, kita perlu membungkus semua perintah Go di Makefile.

 go-compile: go-clean go-get go-build go-build: @echo " > Building binary..." @GOPATH=$(GOPATH) GOBIN=$(GOBIN) go build -o $(GOBIN)/$(PROJECTNAME) $(GOFILES) go-generate: @echo " > Generating dependency files..." @GOPATH=$(GOPATH) GOBIN=$(GOBIN) go generate $(generate) go-get: @echo " > Checking if there is any missing dependencies..." @GOPATH=$(GOPATH) GOBIN=$(GOBIN) go get $(get) go-install: @GOPATH=$(GOPATH) GOBIN=$(GOBIN) go install $(GOFILES) go-clean: @echo " > Cleaning build cache" @GOPATH=$(GOPATH) GOBIN=$(GOBIN) go clean 

Bantuan


Akhirnya, kita memerlukan perintah bantuan untuk melihat daftar perintah yang tersedia. Kami dapat secara otomatis menghasilkan output bantuan yang diformat dengan indah menggunakan perintah sed dan kolom:

 help: Makefile @echo " Choose a command run in "$(PROJECTNAME)":" @sed -n 's/^##//p' $< | column -t -s ':' | sed -e 's/^/ /' 

Perintah berikut memindai Makefile untuk baris yang dimulai dengan ## dan menampilkannya. Dengan begitu, Anda cukup mengomentari perintah tertentu, dan komentar akan ditampilkan dengan perintah bantuan.

Jika kami menambahkan beberapa komentar:

 ## install: Install missing dependencies. Runs `go get` internally. install: go-get ## start: Start in development mode. Auto-starts when code changes. start: ## stop: Stop development mode. stop: stop-server 

Kami akan mendapatkan:

 $ make help Choose a command run in my-web-server: install Install missing dependencies. Runs `go get` internally. start Start in development mode. Auto-starts when code changes. stop Stop development mode. 

Versi final


 include .env PROJECTNAME=$(shell basename "$(PWD)") # Go related variables. GOBASE=$(shell pwd) GOPATH="$(GOBASE)/vendor:$(GOBASE)" GOBIN=$(GOBASE)/bin GOFILES=$(wildcard *.go) # Redirect error output to a file, so we can show it in development mode. STDERR=/tmp/.$(PROJECTNAME)-stderr.txt # PID file will keep the process id of the server PID=/tmp/.$(PROJECTNAME).pid # Make is verbose in Linux. Make it silent. MAKEFLAGS += --silent ## install: Install missing dependencies. Runs `go get` internally. eg; make install get=github.com/foo/bar install: go-get ## start: Start in development mode. Auto-starts when code changes. start: bash -c "trap 'make stop' EXIT; $(MAKE) compile start-server watch run='make compile start-server'" ## stop: Stop development mode. stop: stop-server start-server: stop-server @echo " > $(PROJECTNAME) is available at $(ADDR)" @-$(GOBIN)/$(PROJECTNAME) 2>&1 & echo $$! > $(PID) @cat $(PID) | sed "/^/s/^/ \> PID: /" stop-server: @-touch $(PID) @-kill `cat $(PID)` 2> /dev/null || true @-rm $(PID) ## watch: Run given command when code changes. eg; make watch run="echo 'hey'" watch: @GOPATH=$(GOPATH) GOBIN=$(GOBIN) yolo -i . -e vendor -e bin -c "$(run)" restart-server: stop-server start-server ## compile: Compile the binary. compile: @-touch $(STDERR) @-rm $(STDERR) @-$(MAKE) -s go-compile 2> $(STDERR) @cat $(STDERR) | sed -e '1s/.*/\nError:\n/' | sed 's/make\[.*/ /' | sed "/^/s/^/ /" 1>&2 ## exec: Run given command, wrapped with custom GOPATH. eg; make exec run="go test ./..." exec: @GOPATH=$(GOPATH) GOBIN=$(GOBIN) $(run) ## clean: Clean build files. Runs `go clean` internally. clean: @(MAKEFILE) go-clean go-compile: go-clean go-get go-build go-build: @echo " > Building binary..." @GOPATH=$(GOPATH) GOBIN=$(GOBIN) go build -o $(GOBIN)/$(PROJECTNAME) $(GOFILES) go-generate: @echo " > Generating dependency files..." @GOPATH=$(GOPATH) GOBIN=$(GOBIN) go generate $(generate) go-get: @echo " > Checking if there is any missing dependencies..." @GOPATH=$(GOPATH) GOBIN=$(GOBIN) go get $(get) go-install: @GOPATH=$(GOPATH) GOBIN=$(GOBIN) go install $(GOFILES) go-clean: @echo " > Cleaning build cache" @GOPATH=$(GOPATH) GOBIN=$(GOBIN) go clean .PHONY: help all: help help: Makefile @echo @echo " Choose a command run in "$(PROJECTNAME)":" @echo @sed -n 's/^##//p' $< | column -t -s ':' | sed -e 's/^/ /' @echo 

Source: https://habr.com/ru/post/id461467/


All Articles