如何在编译时删除未使用的代码?

时间:2017-03-16 05:25:03

标签: go compilation compiler-optimization

我们已经构建了一个我们很多人都使用的Go包。

使用标准import ("package-name")方法导入。

在编译时,我们所有的实用程序,包括非常小的实用程序,最终都是非常大的二进制文件。

我们已经提取了实用程序中的所有字符串,并发现整个包正在编译到每个实用程序中。包括那些实用程序未使用的函数。

编辑1:

感谢回答这个问题的人们。

以下是我们所看到的:

main.go

package main

import "play/subplay"

func main() {
    subplay.A()
}

播放/ subplay.go

package subplay

func A() {
    fmt.Printf("this is function A()")
}

func B() {
    fmt.Printf("secret string")
}

永远不会调用函数B()。然而,在构建二进制文件之后,我们在main.exe中找到字符串“secret string”。

如何在编译时从Go程序中删除未使用的代码?

2 个答案:

答案 0 :(得分:7)

编译器已经这样做了。所有代码都以包文件(.a)结束,但在可执行二进制文件中,Go工具不包含导入包中的所有内容,只包含所需内容(或更准确地说:它排除了可以证明无法访问的内容)。

请参阅可能的重复Splitting client/server code

这里要注意的一件事:如果一个导入的包(你只想包含你引用的东西)导入其他包,那么当然必须以递归的方式完成。

例如,如果您导入此包:

package subplay

func A() {}

并且不给它打电话:

package main

import _ "play/subplay"

func main() {
}

结果二进制文件(Go 1.8,linux,amd64)将是960,134字节(大约1 MB)。

如果您更改subplay以导入net/http

package subplay

import _ "net/http"

func A() {}

但仍然不会从net/http调用任何内容,结果将是: 5,370,935字节(大约5 MB)! (请注意,net/http还会导入39 other packages!)

现在,如果您继续使用net/http中的内容:

package subplay

import "net/http"

func A() {
    http.ListenAndServe("", nil)
}

但是在main包中你仍然没有调用subplay.A(),可执行二进制文件的大小不会改变:仍为5,370,935字节

当您更改main包以致电subplay.A()时:

package main

import "play/subplay"

func main() {
    subplay.A()
}

结果二进制文件增长:5,877,919字节

如果您将http.ListenAndServe()更改为http.ListenAndServeTLS()

func A() {
    http.ListenAndServeTLS("", "", "", nil)
}

结果二进制文件是: 6,041,535字节

正如您所看到的,编译成可执行二进制文件的内容取决于您从导入的包中调用/使用的内容。

另外不要忘记Go是一种静态链接语言,结果可执行二进制文件必须包含它所需的一切。请参阅相关问题:Reason for huge size of compiled executable of Go

答案 1 :(得分:0)

如果你不介意这些限制(插件需要Go 1.8,目前只适用于Linux),你可以将你的软件包变成plugin

[edit]由于您使用的是Windows,因此无法选择。