مثال على إنشاء تطبيقات Makefile لـ Go

في هذا البرنامج التعليمي ، سنبحث كيف يمكن لمطوري Go استخدام Makefile لتطوير تطبيقاتهم الخاصة.

صورة

ما هي Makefiles؟


Makefile هي أداة أتمتة مفيدة بشكل لا يصدق يمكنك استخدامها لتشغيل وبناء التطبيقات ليس فقط على الذهاب ، ولكن أيضا في معظم لغات البرمجة الأخرى.

يمكن رؤيته غالبًا في الدليل الجذر للعديد من تطبيقات Go على Github و Gitlab. يستخدم على نطاق واسع كأداة لأتمتة المهام التي كثيرا ما تصاحب المطورين.

إذا كنت تستخدم Go لإنشاء خدمات الويب ، فسوف يساعدك Makefile على حل المهام التالية:

  • أتمتة استدعاء الأوامر البسيطة ، مثل: الترجمة ، البداية ، الإيقاف ، المشاهدة ، إلخ.
  • إدارة متغيرات البيئة الخاصة بالمشروع. يجب أن يتضمن ملف .env.
  • وضع تطوير يجمع تلقائيًا عند التغيير.
  • وضع تطوير يعرض أخطاء الترجمة.
  • تحديد GOPATH لمشروع معين حتى نتمكن من تخزين التبعيات في مجلد البائع.
  • مراقبة الملفات المبسطة ، على سبيل المثال ، قم بتشغيل watch = "go test. / ... "

فيما يلي بنية دليل نموذجية للمشروع:

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

إذا قمنا باستدعاء الأمر make في هذا الدليل ، فسوف نحصل على الإخراج التالي:

 $ 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. 

متغيرات البيئة


أول شيء نريده من Makefile هو تضمين متغيرات البيئة التي حددناها للمشروع. لذلك ، سيبدو السطر الأول كما يلي:

 include .env 

بعد ذلك ، نحدد اسم المشروع ، انتقل إلى المجلدات / الملفات ، ومسارات معرف المنتج ...

 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 

في الجزء المتبقي من Makefile ، سوف نستخدم متغير GOPATH غالبًا. يجب أن ترتبط جميع فرقنا بـ GOPATH لمشروع معين ، وإلا فلن تعمل. هذا يوفر عزلًا نظيفًا لمشاريعنا ، ولكن في نفس الوقت يعقد العمل. لتبسيط المهمة ، يمكننا إضافة أمر exec يقوم بتنفيذ أي أمر من خلال GOPATH.

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

ومع ذلك ، تجدر الإشارة إلى أنك تحتاج إلى استخدام exec فقط إذا كنت تريد القيام بشيء لا يمكن كتابته في ملف التعريف.

وضع التنمية


يجب وضع التنمية:

  • مسح بناء ذاكرة التخزين المؤقت
  • ترجمة رمز
  • قم بتشغيل الخدمة في الخلفية
  • كرر هذه الخطوات عندما يتغير الرمز.

هذا يبدو سهلا. ومع ذلك ، تكمن الصعوبة في حقيقة أننا ندير الخدمة ومراقب الملفات في وقت واحد. قبل بدء عملية جديدة ، يجب علينا التأكد من توقفها بشكل صحيح وعدم انتهاك السلوك المعتاد لسطر الأوامر عند الضغط على Control-C أو Control-D.

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

يحل الكود الموضح أعلاه المهام التالية:

  • يجمع ويدير الخدمة في الخلفية.
  • لا تعمل العملية الرئيسية في الخلفية ، لذلك يمكننا مقاطعة ذلك باستخدام Control-C.
  • توقف العمليات الخلفية عند مقاطعة العملية الرئيسية. هناك حاجة إلى فخ فقط لهذا الغرض.
  • إعادة تجميع وإعادة تشغيل الخادم عندما يتغير الرمز.

في الأقسام التالية ، سأشرح هذه الأوامر بمزيد من التفصيل.

مجموعة


لا يقوم أمر التحويل البرمجي بالاتصال برقم التحويل البرمجي في الخلفية فحسب - بل يمسح ناتج الخطأ ويطبع إصدارًا مبسطًا.

هذا هو ما يبدو عليه إخراج سطر الأوامر عندما قمنا بإجراء تعديلات فاصلة:

صورة

 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 

خادم بدء / توقف


start-server يقوم بتشغيل ثنائي تم تجميعه في الخلفية ، مع حفظ معرف المنتج الخاص به في ملف مؤقت. توقف خادم يقرأ PID ويقتل العملية إذا لزم الأمر.

 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 

تغيير الرصد


نحتاج إلى ملف مراقب لتتبع التغييرات. جربت الكثير ، لكن لم أجد أداة مناسبة ، لذلك كتبت أداة مراقبة الملفات الخاصة بي - yolo . تثبيته باستخدام الأمر:

 $ go get github.com/azer/yolo 

بعد التثبيت ، يمكننا ملاحظة التغييرات في دليل المشروع ، باستثناء مجلدات البائع والمجلد.

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

لدينا الآن أمر مراقبة يتتبع التغييرات بشكل متكرر إلى دليل المشروع ، باستثناء دليل البائع. يمكننا فقط تمرير أي أمر لتشغيل.
على سبيل المثال ، ابدأ مكالمات make-start-server عندما يتغير الرمز:

 make watch run="make compile start-server" 

يمكننا استخدامه لتشغيل الاختبارات أو التحقق من ظروف السباق تلقائيًا. سيتم تعيين متغيرات البيئة في وقت التشغيل ، لذلك لا داعي للقلق بشأن GOPATH:

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

ميزة لطيفة من Yolo هي واجهة الويب الخاصة به. إذا قمت بتمكينه ، يمكنك على الفور رؤية إخراج الأمر الخاص بك في واجهة الويب. كل ما عليك القيام به هو تمرير الخيار -a:

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

افتح المضيف المحلي: 9001 في المستعرض وشاهد على الفور نتيجة العمل:

صورة

تركيب التبعية


عندما نجري تغييرات على الكود ، نود تحميل التبعيات المفقودة قبل التحويل البرمجي. سيقوم الأمر install بتنفيذ المهمة لنا:

 install: go-get 

سنقوم بأتمتة مكالمة التثبيت عندما يتغير الملف قبل التحويل البرمجي ، لذلك سيتم تثبيت التبعيات تلقائيًا. إذا كنت ترغب في تثبيت التبعية يدويًا ، يمكنك تشغيل:

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

داخليًا ، سيتم تحويل هذا الأمر إلى:

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

كيف يعمل؟ راجع القسم التالي حيث نضيف أوامر Go العادية لتنفيذ أوامر المستوى الأعلى.

الذهاب الأوامر


نظرًا لأننا نريد تثبيت GOPATH في دليل المشروع من أجل تبسيط إدارة التبعية ، والتي لم يتم تحديدها رسميًا بعد في نظام Go البيئي ، نحتاج إلى التفاف جميع أوامر Go في 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 

مساعدة


أخيرًا ، نحتاج إلى أمر المساعدة لرؤية قائمة بالأوامر المتاحة. يمكننا تلقائيًا إنشاء إخراج مساعدة منسق بشكل جميل باستخدام أوامر sed والعمود:

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

يقوم الأمر التالي بمسح Makefile للخطوط التي تبدأ بـ ## ويعرضها. وبهذه الطريقة ، يمكنك ببساطة التعليق على أوامر محددة ، وسيتم عرض التعليقات باستخدام أمر المساعدة.

إذا أضفنا بعض التعليقات:

 ## 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 

سوف نحصل على:

 $ 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. 

النسخة النهائية


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


All Articles