ldflags

介绍 (Introduction)

When deploying applications into a production environment, building binaries with version information and other metadata will improve your monitoring, logging, and debugging processes by adding identifying information to help track your builds over time. This version information can often include highly dynamic data, such as build time, the machine or user building the binary, the Version Control System (VCS) commit ID it was built against, and more. Because these values are constantly changing, coding this data directly into the source code and modifying it before every new build is tedious and prone to error: Source files can move around and variables/constants may switch files throughout development, breaking the build process.

在将应用程序部署到生产环境中时,使用版本信息和其他元数据构建二进制文件会通过添加标识信息来帮助您跟踪构建情况,从而改善您的监视,日志记录和调试过程。 此版本信息通常可以包括高度动态的数据,例如构建时间,构建二进制文件的机器或用户,针对其构建的版本控制系统(VCS)提交ID等。 由于这些值一直在变化,因此在每个新版本繁琐且容易出错之前,将这些数据直接编码为源代码并进行修改:源文件会四处移动, 变量/常量可能会在整个开发过程中切换文件,从而破坏了构建过程。

One way to solve this in Go is to use -ldflags with the go build command to insert dynamic information into the binary at build time, without the need for source code modification. In this flag, ld stands for linker, the program that links together the different pieces of the compiled source code into the final binary. ldflags, then, stands for linker flags. It is called this because it passes a flag to the underlying Go toolchain linker, cmd/link, that allows you to change the values of imported packages at build time from the command line.

在Go中解决此问题的一种方法是在构建时将-ldflagsgo build命令一起使用,以将动态信息插入二进制文件中,而无需修改源代码。 在此标志中, ld代表linker ,该程序将已编译的源代码的不同部分链接到最终的二进制文件中。 ldflags代表链接器标志 。 之所以这样称呼,是因为它向基础Go工具链链接器cmd/link传递了一个标志,该标志使您可以在构建时从命令行更改导入包的值。

In this tutorial, you will use -ldflags to change the value of variables at build time and introduce your own dynamic information into a binary, using a sample application that prints version information to the screen.

在本教程中,您将使用-ldflags在构建时更改变量的值,并使用将版本信息打印到屏幕的示例应用程序将自己的动态信息引入二进制文件。

先决条件 (Prerequisites)

To follow the example in this article, you will need:

要遵循本文中的示例,您将需要:

  • A Go workspace set up by following How To Install Go and Set Up a Local Programming Environment.

    通过遵循如何安装Go和设置本地编程环境来设置 Go工作区。

构建示例应用程序 (Building Your Sample Application)

Before you can use ldflags to introduce dynamic data, you first need an application to insert the information into. In this step, you will make this application, which will at this stage only print static versioning information. Let’s create that application now.

在使用ldflags引入动态数据之前,首先需要一个应用程序来将信息插入其中。 在此步骤中,您将创建此应用程序,该应用程序在此阶段将仅打印静态版本控制信息。 现在创建该应用程序。

In your src directory, make a directory named after your application. This tutorial will use the application name app:

src目录中,建立一个以应用程序命名的目录。 本教程将使用应用程序名称app

  • mkdir app

    mkdir 应用

Change your working directory to this folder:

将工作目录更改为此文件夹:

  • cd app

    光盘应用

Next, using the text editor of your choice, create the entry point of your program, main.go:

接下来,使用您选择的文本编辑器,创建程序的入口点main.go

  • nano main.go
    纳米main.go

Now, make your application print out version information by adding the following contents:

现在,通过添加以下内容使您的应用程序打印出版本信息:

app/main.go
app / main.go
package mainimport ("fmt"
)var Version = "development"func main() {fmt.Println("Version:\t", Version)
}

Inside of the main() function, you declared the Version variable, then printed the string Version:, followed by a tab character, \t, and then the declared variable.

main()函数内部,您声明了Version变量,然后打印了字符串 Version: :,后跟一个制表符\t ,然后声明了变量。

At this point, the variable Version is defined as development, which will be the default version for this app. Later on, you will change this value to be an official version number, arranged according to semantic versioning format.

此时,变量Version定义为development ,它将是此应用程序的默认版本。 稍后,您将把该值更改为正式版本号,根据语义版本格式进行排列。

Save and exit the file. Once this is done, build and run the application to confirm that it prints the correct version:

保存并退出文件。 完成此操作后,构建并运行该应用程序以确认其打印正确的版本:

  • go build
    去建造
  • ./app

    ./ 应用

You will see the following output:

您将看到以下输出:

Output
输出量
  • Version: development
    版本:开发

You now have an application that prints default version information, but you do not yet have a way to pass in current version information at build time. In the next step, you will use -ldflags and go build to solve this problem.

现在,您有了一个可以打印默认版本信息的应用程序,但是您尚无法在构建时传递当前版本信息。 在下一步中,您将使用-ldflagsgo build以解决此问题。

go build使用ldflags (Using ldflags with go build)

As mentioned before, ldflags stands for linker flags, and is used to pass in flags to the underlying linker in the Go toolchain. This works according to the following syntax:

如前所述, ldflags代表链接器标志 ,用于将标志传递到Go工具链中的基础链接器。 这根据以下语法工作:

  • go build -ldflags="-flag"

    转到build -ldflags =“- flag ”

In this example, we passed in flag to the underlying go tool link command that runs as a part of go build. This command uses double quotes around the contents passed to ldflags to avoid breaking characters in it, or characters that the command line might interpret as something other than what we want. From here, you could pass in many different link flags. For the purposes of this tutorial, we will use the -X flag to write information into the variable at link time, followed by the package path to the variable and its new value:

在此示例中,我们将flag传递给了底层go tool link命令,该命令作为go build的一部分运行。 此命令在传递给ldflags的内容周围使用双引号,以避免破坏其中的字符或命令行可能解释为我们想要的字符以外的字符。 从这里,您可以传入许多不同的link标志 。 在本教程中,我们将使用-X标志在链接时将信息写入变量,然后是变量的包路径及其新值:

  • go build -ldflags="-X 'package_path.variable_name=new_value'"

    去构建-ldflags = “ - X 'package_path 变量名 = NEW_VALUE。'”

Inside the quotes, there is now the -X option and a key-value pair that represents the variable to be changed and its new value. The . character separates the package path and the variable name, and single quotes are used to avoid breaking characters in the key-value pair.

在引号内,现在有-X选项和一个键值对 ,代表要更改的变量及其新值。 的. 字符分隔包路径和变量名,并且单引号用于避免在键值对中破坏字符。

To replace the Version variable in your example application, use the syntax in the last command block to pass in a new value and build the new binary:

要在示例应用程序中替换Version变量,请使用最后一个命令块中的语法传递新值并构建新的二进制文件:

  • go build -ldflags="-X 'main.Version=v1.0.0'"
    go build -ldflags =“-X'main.Version = v1.0.0'”

In this command, main is the package path of the Version variable, since this variable is in the main.go file. Version is the variable that you are writing to, and v1.0.0 is the new value.

在此命令中, mainVersion变量的程序包路径,因为此变量位于main.go文件中。 Version是您要写入的变量,而v1.0.0是新值。

In order to use ldflags, the value you want to change must exist and be a package level variable of type string. This variable can be either exported or unexported. The value cannot be a const or have its value set by the result of a function call. Fortunately, Version fits all of these requirements: It was already declared as a variable in the main.go file, and the current value (development) and the desired value (v1.0.0) are both strings.

为了使用ldflags ,要更改的值必须存在并且必须是string类型的程序包级变量。 此变量可以导出或不导出。 该值不能是const或通过函数调用的结果来设置其值。 幸运的是, Version满足了所有这些要求:在main.go文件中已经将它声明为变量,并且当前值( development )和所需值( v1.0.0 )都是字符串。

Once your new app binary is built, run the application:

构建新的app二进制文件后,运行该应用程序:

  • ./app

    ./ 应用

You will receive the following output:

您将收到以下输出:

Output
输出量
  • Version: v1.0.0

    版本: v1.0.0

Using -ldflags, you have succesfully changed the Version variable from development to v1.0.0.

使用-ldflags成功地将Version变量从development更改为v1.0.0

You have now modified a string variable inside of a simple application at build time. Using ldflags, you can embed version details, licensing information, and more into a binary ready for distribution, using only the command line.

现在,您已在构建时在简单应用程序内部修改了string变量。 使用ldflags ,您可以仅使用命令行将版本详细信息,许可信息以及其他内容嵌入准备分发的二进制文件中。

In this example, the variable you changed was in the main program, reducing the difficulty of determining the path name. But sometimes the path to these variables is more complicated to find. In the next step, you will write values to variables in sub-packages to demonstrate the best way to determine more complex package paths.

在这个例子中,你改变了变量是在main程序,减少确定路径名称的难度。 但是有时候找到这些变量的路径更加复杂。 在下一步中,您将把值写入子包中的变量,以演示确定更复杂的包路径的最佳方法。

定位子包变量 (Targeting Sub-Package Variables)

In the last section, you manipulated the Version variable, which was at the top-level package of the application. But this is not always the case. Often it is more practical to place these variables in another package, since main is not an importable package. To simulate this in your example application, you will create a new sub-package, app/build, that will store information about the time the binary was built and the name of the user that issued the build command.

在上一节中,您操纵了Version变量,该变量位于应用程序的顶级程序包中。 但这并非总是如此。 通常将这些变量放在另一个包中更为实用,因为main并不是可导入的包。 为了在示例应用程序中对此进行模拟,您将创建一个新的子包app /build ,该子包将存储有关生成二进制文件的时间和发出build命令的用户名的信息。

To add a new sub-package, first add a new directory to your project named build:

要添加一个新的子包,首先向您的项目中添加一个名为build的新目录:

  • mkdir -p build
    mkdir -p构建

Then create a new file named build.go to hold the new variables:

然后创建一个名为build.go的新文件来保存新变量:

  • nano build/build.go
    纳米bu​​ild / build.go

In your text editor, add new variables for Time and User:

在您的文本编辑器中,为TimeUser添加新变量:

app/build/build.go
app / build / build.go
package buildvar Time stringvar User string

The Time variable will hold a string representation of the time when the binary was built. The User variable will hold the name of the user who built the binary. Since these two variables will always have values, you don’t need to initialize these variables with default values like you did for Version.

Time变量将保存二进制文件生成时间的字符串表示形式。 User变量将保存构建二进制文件的用户的名称。 由于这两个变量将始终具有值,因此您无需像对Version那样使用默认值初始化这些变量。

Save and exit the file.

保存并退出文件。

Next, open main.go to add these variables to your application:

接下来,打开main.go将这些变量添加到您的应用程序中:

  • nano main.go
    纳米main.go

Inside of main.go, add the following highlighted lines:

main.go内部,添加以下突出显示的行:

main.go
main.go
package mainimport ("app/build""fmt"
)var Version = "development"func main() {fmt.Println("Version:\t", Version)fmt.Println("build.Time:\t", build.Time)fmt.Println("build.User:\t", build.User)
}

In these lines, you first imported the app/build package, then printed build.Time and build.User in the same way you printed Version.

在这些行中,您首先导入了app /build包,然后以与打印Version相同的方式打印build.Timebuild.User

Save the file, then exit from your text editor.

保存文件,然后退出文本编辑器。

Next, to target these variables with ldflags, you could use the import path app/build followed by .User or .Time, since you already know the import path. However, to simulate a more complex situation in which the path to the variable is not evident, let’s instead use the nm command in the Go tool chain.

接下来,要使用ldflags定位这些变量,可以使用导入路径app /build后跟.User.Time ,因为您已经知道导入路径。 但是,要模拟一个更复杂的情况(其中变量的路径不明显),让我们在Go工具链中使用nm命令。

The go tool nm command will output the symbols involved in a given executable, object file, or archive. In this case, a symbol refers to an object in the code, such as a defined or imported variable or function. By generating a symbol table with nm and using grep to search for a variable, you can quickly find information about its path.

go tool nm命令将输出给定可执行文件,目标文件或归档文件中涉及的符号 。 在这种情况下,符号指代代码中的对象,例如已定义或导入的变量或函数。 通过使用nm生成符号表并使用grep搜索变量,您可以快速找到有关其路径的信息。

Note: The nm command will not help you find the path of your variable if the package name has any non-ASCII characters, or a " or % character, as that is a limitation of the tool itself.

注意:如果程序包名称包含任何非ASCII字符或"%字符,则nm命令将无法帮助您找到变量的路径,因为这是工具本身的限制。

To use this command, first build the binary for app:

要使用此命令,请首先为app构建二进制文件:

  • go build
    去建造

Now that app is built, point the nm tool at it and search through the output:

现在已经构建了该app ,将nm工具指向它并搜索输出:

  • go tool nm ./app | grep app

    工具nm ./ app | grep 应用

When run, the nm tool will output a lot of data. Because of this, the preceding command used | to pipe the output to the grep command, which then searched for terms that had the top-level app in the title.

运行时, nm工具将输出大量数据。 因此,前面的命令使用了| 将输出传递给grep命令,然后该命令搜索标题中具有顶级app术语。

You will receive output similar to this:

您将收到类似于以下的输出:


Output
  55d2c0 D app/build.Time55d2d0 D app/build.User4069a0 T runtime.appendIntStr462580 T strconv.appendEscapedRune
. . .

In this case, the first two lines of the result set contain the paths to the two variables you are looking for: app/build.Time and app/build.User.

在这种情况下,结果集的前两行包含您要查找的两个变量的路径: app /build.Timeapp /build.User

Now that you know the paths, build the application again, this time changing Version, User, and Time at build time. To do this, pass multiple -X flags to -ldflags:

现在您已经知道了路径,再次构建应用程序,这次在构建时更改VersionUserTime 。 为此, -ldflags多个-X标志传递给-ldflags

  • go build -v -ldflags="-X 'main.Version=v1.0.0' -X 'app/build.User=$(id -u -n)' -X 'app/build.Time=$(date)'"
    去建立-v -ldflags =“-X'main.Version = v1.0.0'-X'app / build.User = $(id -u -n)'-X'app / build.Time = $(date) '”

Here you passed in the id -u -n Bash command to list the current user, and the date command to list the current date.

在这里,您传入了id -u -n Bash命令以列出当前用户,并传递了date命令以列出当前日期。

Once the executable is built, run the program:

生成可执行文件后,运行程序:

  • ./app

    ./ 应用

This command, when run on a Unix system, will generate similar output to the following:

在Unix系统上运行时,此命令将产生与以下类似的输出:


Output
Version:     v1.0.0
build.Time:  Fri Oct  4 19:49:19 UTC 2019
build.User:  sammy

Now you have a binary that contains versioning and build information that can provide vital assistance in production when resolving issues.

现在,您有了一个二进制文件,其中包含版本控制和构建信息,这些信息可以在解决问题时为生产提供重要的帮助。

结论 (Conclusion)

This tutorial showed how, when applied correctly, ldflags can be a powerful tool for injecting valuable information into binaries at build time. This way, you can control feature flags, environment information, versioning information, and more without introducing changes to your source code. By adding ldflags to your current build workflow you can maximize the benefits of Go’s self-contained binary distribution format.

本教程说明了正确应用ldflags可以如何在构建时将有价值的信息注入二进制文件的强大工具。 这样,您可以控制功能标志,环境信息,版本信息等,而无需对源代码进行更改。 通过将ldflags添加到当前的构建工作流程中,您可以最大限度地利用Go的自包含二进制分发格式的好处。

If you would like to learn more about the Go programming language, check out our full How To Code in Go series. If you are looking for more solutions for version control, try our How To Use Git reference guide.

如果您想了解有关Go编程语言的更多信息,请查看我们完整的“ 如何在Go中编码”系列文章 。 如果您正在寻找版本控制的更多解决方案,请尝试我们的《 如何使用Git》参考指南。

翻译自: https://www.digitalocean.com/community/tutorials/using-ldflags-to-set-version-information-for-go-applications

ldflags

ldflags_使用ldflags设置Go应用程序的版本信息相关推荐

  1. python打包加版本信息_使用pyi-set_version为PyInstaller打包出来的程序附加版本信息...

    本文将讲述如何使用 pyi-grab_version获取版本信息的模板文件,以及使用 pyi-set_version为打包好的程序附加版本信息. 当然了,在开始前,需要你已经安装好了 PyInstal ...

  2. 给Qt程序加上版本信息

    2019独角兽企业重金招聘Python工程师标准>>> windows下的可执行文件的属性中有版本这个信息,她含有版本信息,描述,版权等等.对于qt的程序,要含有这样的信息,该怎么办 ...

  3. 删除隐藏版本信息 版本回退_Qt如何给程序添加版本信息

    " 阅读本文需要3分钟 自己亲手编译过 Qt Creator 源码的朋友都有这样的疑惑,为啥编译完成后最终生成的动态库.插件以及 exe 都会带数字 4 后缀,下面记录下如何出现以及如何解决 ...

  4. Maven设置指定jar包依赖版本信息

    我们在配置Spark core 的 maven依赖的时候jackson-module-scala_2.11的版本冲突,解决办法如下: <dependencies><dependenc ...

  5. 14.Go程序版本信息(一)

    Go程序版本信息(一) 日期:2022-01-25 11:02:18 作者:JonathanJiang 此文章为个人笔记,有误请指正,推荐读者查看参考资料的原文 一.参考资料 Golang中管理程序的 ...

  6. uni-app APP 打包设置版本号和获取当前应用版本信息

    设置版本号 获取当前应用版本信息 plus.runtime.getProperty(plus.runtime.appid,(appInfo)=>{// appInfo为当前应用程序的所有信息co ...

  7. plt.figure(figsize(x,y))设置后后续程序都跟着改变,如何处理?走破解它!

    plt.figure(figsize(x,y))设置后后续程序都跟着改变,如何处理?走破解它! 目录 plt.figure(figsize(x,y))设置后后续程序都跟着改变,如何处理?走破解它!

  8. 设置Eclipse RCP程序的外观和首选项

    RCP应用程序的缺省外观是一个空白窗口,一般我们要通过一个WorkbenchAdvisor类对界面进行定制. WorkbenchAdvisor有很多回调方法,可以在preWindowOpen()方法里 ...

  9. Linux打开rtf文档,在linux下设置开机自动启动程序的方法_精品.rtf

    您所在位置:网站首页 > 海量文档 &nbsp>&nbsp计算机&nbsp>&nbsplinux/Unix相关 在linux下设置开机自动启动程序的方 ...

最新文章

  1. [ASP.NET笔记] 5.验证控件
  2. 『ACM--算法--KMP』信息竞赛进阶指南--KMP算法(模板)
  3. MarkDownPad2 注册码
  4. leetcode374. 猜数字大小
  5. 二维码图像去噪文献调研(1)--Real Image Denoising with Feature Attention
  6. linux7ip路由,Centos7源地址访问路由(双IP双网关配置)
  7. 新手程序员必学的代码编程技巧
  8. JAR文件概述(2021版)
  9. 一年四个P(Project)
  10. (转)人工智能公司Kensho是如何改变华尔街的?
  11. 3.19 使用钢笔工具绘制一枚诱人的梨子 [Illustrator CC教程]
  12. 科研小助手PubMed的插件PubMedy
  13. Calander 的小程序 简单日历的制作
  14. Arduino与JavaScript开发实例-舵机驱动
  15. 使用vscode利用vue脚手架创建项目每次修改代码都会频繁编译
  16. 《JavaScript实现页面图片滚动播放》
  17. 人脸识别方案(包含tcp ,http,socket 三者的区别)
  18. Appium+python+夜神模拟器微信公众号 记录第一次写用例所踩的坑
  19. 如何让arduino中的loop和Processing中的draw停下来
  20. 因为接了一个外包 我在监狱蹲了456天!

热门文章

  1. Linux命令--hexdump(以16进制查看文件内容)
  2. linux查看端口号占用命令-netstat
  3. MongoDB备份的两种方法
  4. 时光金科php_湖北随州交投·金科府 | 安道设计
  5. Srt字幕的视频用它就能批量制作
  6. java时间戳转Date类型精确到毫秒或微秒存储到mysql
  7. C语言网络编程(3)— 通过DNS连接到百度
  8. vue数组刷新_详解VUE 数组更新
  9. OpenSSL密码库算法笔记——第5.4.1章 椭圆曲线上点的仿射坐标表示
  10. 稀疏学习:从人脑得到灵感,让深度学习突破算力限制