make 命令执行时,需要一个 makefile 文件,以告诉 make 命令需要怎么样的去编译和链接程序。

makefile的规则

在讲述这个 makefile 之前,还是让我们先来粗略地看一看 makefile 的规则。

  1. target ... : prerequisites ...
  2. command
  3. ...
  4. ...

target
可以是一个object file(目标文件),也可以是一个执行文件,还可以是一个标签(label)。对于标签这种特性,在后续的“伪目标”章节中会有叙述。

prerequisites
生成该 target 所依赖的文件和/target

command
该target要执行的命令(任意的shell命令)
这是一个文件的依赖关系,也就是说,target这一个或多个的目标文件依赖于 prerequisites 中的文件,其生成规则定义在 command 中。说白一点就是说:

prerequisites 中如果有一个以上的文件比target文件要新的话,command所定义的命令就会被执行。

这就是makefile的规则,也就是makefile中最核心的内容。

Mage

Mage是一个使用Go的类似 make/rake 的构建工具。你编写普通的 Go 函数,Mage 会自动将它们作为类似Makefile 的可运行目标。

使用说明

  1. mage [options] [target]
  2. Mage is a make-like command runner. See https://magefile.org for full docs.
  3. Commands:
  4. -clean clean out old generated binaries from CACHE_DIR
  5. -compile <string>
  6. output a static binary to the given path
  7. -h show this help
  8. -init create a starting template if no mage files exist
  9. -l list mage targets in this directory
  10. -version show version info for the mage binary
  11. Options:
  12. -d <string>
  13. directory to read magefiles from (default ".")
  14. -debug turn on debug messages
  15. -f force recreation of compiled magefile
  16. -goarch sets the GOARCH for the binary created by -compile (default: current arch)
  17. -gocmd <string>
  18. use the given go binary to compile the output (default: "go")
  19. -goos sets the GOOS for the binary created by -compile (default: current OS)
  20. -h show description of a target
  21. -keep keep intermediate mage files around after running
  22. -t <string>
  23. timeout in duration parsable format (e.g. 5m30s)
  24. -v show verbose output when running mage targets
  25. -w <string>
  26. working directory where magefiles will run (default -d value)

https://magefile.org/

示例

示例来源 elasticbeats 项目。

D:\Projects\Github\elastic\beats\filebeat\Makefile

  1. BEAT_NAME?=filebeat
  2. BEAT_TITLE?=Filebeat
  3. SYSTEM_TESTS?=true
  4. TEST_ENVIRONMENT?=true
  5. GOX_FLAGS=-arch="amd64 386 arm ppc64 ppc64le"
  6. ES_BEATS?=..
  7. EXCLUDE_COMMON_UPDATE_TARGET=true
  8. include ${ES_BEATS}/libbeat/scripts/Makefile
  9. .PHONY: update
  10. update: mage
  11. mage update
  12. # Creates a new module. Requires the params MODULE.
  13. .PHONY: create-module
  14. create-module: mage
  15. mage generate:module
  16. # Creates a new fileset. Requires the params MODULE and FILESET.
  17. .PHONY: create-fileset
  18. create-fileset: mage
  19. mage generate:fileset
  20. # Creates a fields.yml based on a pipeline.json file. Requires the params MODULE and FILESET.
  21. .PHONY: create-fields
  22. create-fields: mage
  23. mage generate:fields

D:\Projects\Github\elastic\beats\filebeat\magefile.go

  1. // Licensed to Elasticsearch B.V. under one or more contributor
  2. // license agreements. See the NOTICE file distributed with
  3. // this work for additional information regarding copyright
  4. // ownership. Elasticsearch B.V. licenses this file to you under
  5. // the Apache License, Version 2.0 (the "License"); you may
  6. // not use this file except in compliance with the License.
  7. // You may obtain a copy of the License at
  8. //
  9. // http://www.apache.org/licenses/LICENSE-2.0
  10. //
  11. // Unless required by applicable law or agreed to in writing,
  12. // software distributed under the License is distributed on an
  13. // "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
  14. // KIND, either express or implied. See the License for the
  15. // specific language governing permissions and limitations
  16. // under the License.
  17. //go:build mage
  18. // +build mage
  19. package main
  20. import (
  21. "context"
  22. "fmt"
  23. "time"
  24. "github.com/magefile/mage/mg"
  25. devtools "github.com/elastic/beats/v7/dev-tools/mage"
  26. filebeat "github.com/elastic/beats/v7/filebeat/scripts/mage"
  27. // mage:import
  28. "github.com/elastic/beats/v7/dev-tools/mage/target/common"
  29. // mage:import generate
  30. _ "github.com/elastic/beats/v7/filebeat/scripts/mage/generate"
  31. // mage:import
  32. _ "github.com/elastic/beats/v7/dev-tools/mage/target/unittest"
  33. // mage:import
  34. "github.com/elastic/beats/v7/dev-tools/mage/target/test"
  35. )
  36. func init() {
  37. common.RegisterCheckDeps(Update)
  38. test.RegisterDeps(IntegTest)
  39. devtools.BeatDescription = "Filebeat sends log files to Logstash or directly to Elasticsearch."
  40. }
  41. // Build builds the Beat binary.
  42. func Build() error {
  43. return devtools.Build(devtools.DefaultBuildArgs())
  44. }
  45. // GolangCrossBuild builds the Beat binary inside the golang-builder.
  46. // Do not use directly, use crossBuild instead.
  47. func GolangCrossBuild() error {
  48. return filebeat.GolangCrossBuild()
  49. }
  50. // BuildGoDaemon builds the go-daemon binary (use crossBuildGoDaemon).
  51. func BuildGoDaemon() error {
  52. return devtools.BuildGoDaemon()
  53. }
  54. // CrossBuild cross-builds the beat for all target platforms.
  55. func CrossBuild() error {
  56. return filebeat.CrossBuild()
  57. }
  58. // CrossBuildGoDaemon cross-builds the go-daemon binary using Docker.
  59. func CrossBuildGoDaemon() error {
  60. return devtools.CrossBuildGoDaemon()
  61. }
  62. // Package packages the Beat for distribution.
  63. // Use SNAPSHOT=true to build snapshots.
  64. // Use PLATFORMS to control the target platforms.
  65. // Use VERSION_QUALIFIER to control the version qualifier.
  66. func Package() {
  67. start := time.Now()
  68. defer func() { fmt.Println("package ran for", time.Since(start)) }()
  69. devtools.UseElasticBeatOSSPackaging()
  70. devtools.PackageKibanaDashboardsFromBuildDir()
  71. filebeat.CustomizePackaging()
  72. mg.Deps(Update)
  73. mg.Deps(CrossBuild, CrossBuildGoDaemon)
  74. mg.SerialDeps(devtools.Package, TestPackages)
  75. }
  76. // TestPackages tests the generated packages (i.e. file modes, owners, groups).
  77. func TestPackages() error {
  78. return devtools.TestPackages(devtools.WithModules(), devtools.WithModulesD())
  79. }
  80. // Update is an alias for executing fields, dashboards, config, includes.
  81. func Update() {
  82. mg.SerialDeps(Fields, Dashboards, Config, includeList, fieldDocs,
  83. filebeat.CollectDocs,
  84. filebeat.PrepareModulePackagingOSS)
  85. }
  86. // Config generates both the short/reference/docker configs and populates the
  87. // modules.d directory.
  88. func Config() {
  89. mg.Deps(devtools.GenerateDirModulesD, configYML)
  90. mg.SerialDeps(devtools.ValidateDirModulesD, devtools.ValidateDirModulesDDatasetsDisabled)
  91. }
  92. func configYML() error {
  93. return devtools.Config(devtools.AllConfigTypes, filebeat.OSSConfigFileParams(), ".")
  94. }
  95. // includeList generates include/list.go with imports for inputs.
  96. func includeList() error {
  97. options := devtools.DefaultIncludeListOptions()
  98. options.ImportDirs = []string{"input/*"}
  99. return devtools.GenerateIncludeListGo(options)
  100. }
  101. // Fields generates fields.yml and fields.go files for the Beat.
  102. func Fields() {
  103. mg.Deps(libbeatAndFilebeatCommonFieldsGo, moduleFieldsGo)
  104. mg.Deps(fieldsYML)
  105. }
  106. // libbeatAndFilebeatCommonFieldsGo generates a fields.go containing both
  107. // libbeat and filebeat's common fields.
  108. func libbeatAndFilebeatCommonFieldsGo() error {
  109. if err := devtools.GenerateFieldsYAML(); err != nil {
  110. return err
  111. }
  112. return devtools.GenerateAllInOneFieldsGo()
  113. }
  114. // moduleFieldsGo generates a fields.go for each module.
  115. func moduleFieldsGo() error {
  116. return devtools.GenerateModuleFieldsGo("module")
  117. }
  118. // fieldsYML generates the fields.yml file containing all fields.
  119. func fieldsYML() error {
  120. return devtools.GenerateFieldsYAML("module")
  121. }
  122. // fieldDocs generates docs/fields.asciidoc containing all fields
  123. // (including x-pack).
  124. func fieldDocs() error {
  125. inputs := []string{
  126. devtools.OSSBeatDir("module"),
  127. devtools.XPackBeatDir("module"),
  128. devtools.OSSBeatDir("input"),
  129. devtools.XPackBeatDir("input"),
  130. devtools.XPackBeatDir("processors"),
  131. }
  132. output := devtools.CreateDir("build/fields/fields.all.yml")
  133. if err := devtools.GenerateFieldsYAMLTo(output, inputs...); err != nil {
  134. return err
  135. }
  136. return devtools.Docs.FieldDocs(output)
  137. }
  138. // Dashboards collects all the dashboards and generates index patterns.
  139. func Dashboards() error {
  140. return devtools.KibanaDashboards("module")
  141. }
  142. // ExportDashboard exports a dashboard and writes it into the correct directory.
  143. //
  144. // Required environment variables:
  145. // - MODULE: Name of the module
  146. // - ID: Dashboard id
  147. func ExportDashboard() error {
  148. return devtools.ExportDashboard()
  149. }
  150. // IntegTest executes integration tests (it uses Docker to run the tests).
  151. func IntegTest() {
  152. mg.SerialDeps(GoIntegTest, PythonIntegTest)
  153. }
  154. // GoIntegTest executes the Go integration tests.
  155. // Use TEST_COVERAGE=true to enable code coverage profiling.
  156. // Use RACE_DETECTOR=true to enable the race detector.
  157. func GoIntegTest(ctx context.Context) error {
  158. runner, err := devtools.NewDockerIntegrationRunner()
  159. if err != nil {
  160. return err
  161. }
  162. return runner.Test("goIntegTest", func() error {
  163. return devtools.GoTest(ctx, devtools.DefaultGoTestIntegrationArgs())
  164. })
  165. }
  166. // PythonIntegTest executes the python system tests in the integration environment (Docker).
  167. // Use GENERATE=true to generate expected log files.
  168. // Use TESTING_FILEBEAT_MODULES=module[,module] to limit what modules to test.
  169. // Use TESTING_FILEBEAT_FILESETS=fileset[,fileset] to limit what fileset to test.
  170. func PythonIntegTest(ctx context.Context) error {
  171. if !devtools.IsInIntegTestEnv() {
  172. mg.Deps(Fields, Dashboards)
  173. }
  174. runner, err := devtools.NewDockerIntegrationRunner(append(devtools.ListMatchingEnvVars("TESTING_FILEBEAT_", "PYTEST_"), "GENERATE")...)
  175. if err != nil {
  176. return err
  177. }
  178. return runner.Test("pythonIntegTest", func() error {
  179. mg.Deps(devtools.BuildSystemTestBinary)
  180. args := devtools.DefaultPythonTestIntegrationArgs()
  181. args.Env["MODULES_PATH"] = devtools.CWD("module")
  182. return devtools.PythonTest(args)
  183. })
  184. }
  1. PS D:\Projects\Github\elastic\beats\filebeat> ./make -debug update
  2. D:\Projects\Go\bin\mage
  3. D:\Projects\Go\bin\mage.exe

参考链接

https://seisman.github.io/how-to-write-makefile/introduction.html