make 命令执行时,需要一个 makefile 文件,以告诉 make 命令需要怎么样的去编译和链接程序。
makefile的规则
在讲述这个 makefile 之前,还是让我们先来粗略地看一看 makefile 的规则。
target ... : prerequisites ...command......
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 的可运行目标。
使用说明
mage [options] [target]Mage is a make-like command runner. See https://magefile.org for full docs.Commands:-clean clean out old generated binaries from CACHE_DIR-compile <string>output a static binary to the given path-h show this help-init create a starting template if no mage files exist-l list mage targets in this directory-version show version info for the mage binaryOptions:-d <string>directory to read magefiles from (default ".")-debug turn on debug messages-f force recreation of compiled magefile-goarch sets the GOARCH for the binary created by -compile (default: current arch)-gocmd <string>use the given go binary to compile the output (default: "go")-goos sets the GOOS for the binary created by -compile (default: current OS)-h show description of a target-keep keep intermediate mage files around after running-t <string>timeout in duration parsable format (e.g. 5m30s)-v show verbose output when running mage targets-w <string>working directory where magefiles will run (default -d value)
示例
示例来源 elastic 的 beats 项目。
D:\Projects\Github\elastic\beats\filebeat\Makefile
BEAT_NAME?=filebeatBEAT_TITLE?=FilebeatSYSTEM_TESTS?=trueTEST_ENVIRONMENT?=trueGOX_FLAGS=-arch="amd64 386 arm ppc64 ppc64le"ES_BEATS?=..EXCLUDE_COMMON_UPDATE_TARGET=trueinclude ${ES_BEATS}/libbeat/scripts/Makefile.PHONY: updateupdate: magemage update# Creates a new module. Requires the params MODULE..PHONY: create-modulecreate-module: magemage generate:module# Creates a new fileset. Requires the params MODULE and FILESET..PHONY: create-filesetcreate-fileset: magemage generate:fileset# Creates a fields.yml based on a pipeline.json file. Requires the params MODULE and FILESET..PHONY: create-fieldscreate-fields: magemage generate:fields
D:\Projects\Github\elastic\beats\filebeat\magefile.go
// Licensed to Elasticsearch B.V. under one or more contributor// license agreements. See the NOTICE file distributed with// this work for additional information regarding copyright// ownership. Elasticsearch B.V. licenses this file to you under// the Apache License, Version 2.0 (the "License"); you may// not use this file except in compliance with the License.// You may obtain a copy of the License at//// http://www.apache.org/licenses/LICENSE-2.0//// Unless required by applicable law or agreed to in writing,// software distributed under the License is distributed on an// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY// KIND, either express or implied. See the License for the// specific language governing permissions and limitations// under the License.//go:build mage// +build magepackage mainimport ("context""fmt""time""github.com/magefile/mage/mg"devtools "github.com/elastic/beats/v7/dev-tools/mage"filebeat "github.com/elastic/beats/v7/filebeat/scripts/mage"// mage:import"github.com/elastic/beats/v7/dev-tools/mage/target/common"// mage:import generate_ "github.com/elastic/beats/v7/filebeat/scripts/mage/generate"// mage:import_ "github.com/elastic/beats/v7/dev-tools/mage/target/unittest"// mage:import"github.com/elastic/beats/v7/dev-tools/mage/target/test")func init() {common.RegisterCheckDeps(Update)test.RegisterDeps(IntegTest)devtools.BeatDescription = "Filebeat sends log files to Logstash or directly to Elasticsearch."}// Build builds the Beat binary.func Build() error {return devtools.Build(devtools.DefaultBuildArgs())}// GolangCrossBuild builds the Beat binary inside the golang-builder.// Do not use directly, use crossBuild instead.func GolangCrossBuild() error {return filebeat.GolangCrossBuild()}// BuildGoDaemon builds the go-daemon binary (use crossBuildGoDaemon).func BuildGoDaemon() error {return devtools.BuildGoDaemon()}// CrossBuild cross-builds the beat for all target platforms.func CrossBuild() error {return filebeat.CrossBuild()}// CrossBuildGoDaemon cross-builds the go-daemon binary using Docker.func CrossBuildGoDaemon() error {return devtools.CrossBuildGoDaemon()}// Package packages the Beat for distribution.// Use SNAPSHOT=true to build snapshots.// Use PLATFORMS to control the target platforms.// Use VERSION_QUALIFIER to control the version qualifier.func Package() {start := time.Now()defer func() { fmt.Println("package ran for", time.Since(start)) }()devtools.UseElasticBeatOSSPackaging()devtools.PackageKibanaDashboardsFromBuildDir()filebeat.CustomizePackaging()mg.Deps(Update)mg.Deps(CrossBuild, CrossBuildGoDaemon)mg.SerialDeps(devtools.Package, TestPackages)}// TestPackages tests the generated packages (i.e. file modes, owners, groups).func TestPackages() error {return devtools.TestPackages(devtools.WithModules(), devtools.WithModulesD())}// Update is an alias for executing fields, dashboards, config, includes.func Update() {mg.SerialDeps(Fields, Dashboards, Config, includeList, fieldDocs,filebeat.CollectDocs,filebeat.PrepareModulePackagingOSS)}// Config generates both the short/reference/docker configs and populates the// modules.d directory.func Config() {mg.Deps(devtools.GenerateDirModulesD, configYML)mg.SerialDeps(devtools.ValidateDirModulesD, devtools.ValidateDirModulesDDatasetsDisabled)}func configYML() error {return devtools.Config(devtools.AllConfigTypes, filebeat.OSSConfigFileParams(), ".")}// includeList generates include/list.go with imports for inputs.func includeList() error {options := devtools.DefaultIncludeListOptions()options.ImportDirs = []string{"input/*"}return devtools.GenerateIncludeListGo(options)}// Fields generates fields.yml and fields.go files for the Beat.func Fields() {mg.Deps(libbeatAndFilebeatCommonFieldsGo, moduleFieldsGo)mg.Deps(fieldsYML)}// libbeatAndFilebeatCommonFieldsGo generates a fields.go containing both// libbeat and filebeat's common fields.func libbeatAndFilebeatCommonFieldsGo() error {if err := devtools.GenerateFieldsYAML(); err != nil {return err}return devtools.GenerateAllInOneFieldsGo()}// moduleFieldsGo generates a fields.go for each module.func moduleFieldsGo() error {return devtools.GenerateModuleFieldsGo("module")}// fieldsYML generates the fields.yml file containing all fields.func fieldsYML() error {return devtools.GenerateFieldsYAML("module")}// fieldDocs generates docs/fields.asciidoc containing all fields// (including x-pack).func fieldDocs() error {inputs := []string{devtools.OSSBeatDir("module"),devtools.XPackBeatDir("module"),devtools.OSSBeatDir("input"),devtools.XPackBeatDir("input"),devtools.XPackBeatDir("processors"),}output := devtools.CreateDir("build/fields/fields.all.yml")if err := devtools.GenerateFieldsYAMLTo(output, inputs...); err != nil {return err}return devtools.Docs.FieldDocs(output)}// Dashboards collects all the dashboards and generates index patterns.func Dashboards() error {return devtools.KibanaDashboards("module")}// ExportDashboard exports a dashboard and writes it into the correct directory.//// Required environment variables:// - MODULE: Name of the module// - ID: Dashboard idfunc ExportDashboard() error {return devtools.ExportDashboard()}// IntegTest executes integration tests (it uses Docker to run the tests).func IntegTest() {mg.SerialDeps(GoIntegTest, PythonIntegTest)}// GoIntegTest executes the Go integration tests.// Use TEST_COVERAGE=true to enable code coverage profiling.// Use RACE_DETECTOR=true to enable the race detector.func GoIntegTest(ctx context.Context) error {runner, err := devtools.NewDockerIntegrationRunner()if err != nil {return err}return runner.Test("goIntegTest", func() error {return devtools.GoTest(ctx, devtools.DefaultGoTestIntegrationArgs())})}// PythonIntegTest executes the python system tests in the integration environment (Docker).// Use GENERATE=true to generate expected log files.// Use TESTING_FILEBEAT_MODULES=module[,module] to limit what modules to test.// Use TESTING_FILEBEAT_FILESETS=fileset[,fileset] to limit what fileset to test.func PythonIntegTest(ctx context.Context) error {if !devtools.IsInIntegTestEnv() {mg.Deps(Fields, Dashboards)}runner, err := devtools.NewDockerIntegrationRunner(append(devtools.ListMatchingEnvVars("TESTING_FILEBEAT_", "PYTEST_"), "GENERATE")...)if err != nil {return err}return runner.Test("pythonIntegTest", func() error {mg.Deps(devtools.BuildSystemTestBinary)args := devtools.DefaultPythonTestIntegrationArgs()args.Env["MODULES_PATH"] = devtools.CWD("module")return devtools.PythonTest(args)})}
PS D:\Projects\Github\elastic\beats\filebeat> ./make -debug updateD:\Projects\Go\bin\mageD:\Projects\Go\bin\mage.exe
参考链接
https://seisman.github.io/how-to-write-makefile/introduction.html
