Are unused functions compiled?

agolangf · · 790 次点击    
这是一个分享于 的资源,其中的信息可能已经有所发展或是发生改变。
<p>When there is a function in your code that is not being called in the rest of your code... does it gets compiled, or does the compiler detect that no one is referencing it and therefore not included in the binary?</p> <hr/>**评论:**<br/><br/>elagergren: <pre><p>The linker strips out the unused functions. Note that, to my knowledge, using <code>reflect</code> removes this guarantee somewhat. </p> <p>You can test this by building a Go binary, disassembling it with <code>objdump</code>, and then grepping for the function you&#39;re looking for. </p> <p>édit: here&#39;s some context wrt the linker not being able to do DCE as well when <code>reflect</code> is used: <a href="https://github.com/golang/go/issues/15583#issuecomment-217995359">https://github.com/golang/go/issues/15583#issuecomment-217995359</a></p></pre>captncraig: <pre><p>Reflect makes it harder, but that should just affect exported methods on structs, right? You can&#39;t call package level functions or unexported functions via reflect.</p></pre>endophage: <pre><p>Exported functions are the things that call non-exported functions. If I&#39;m uncertain about what exported functions are used I&#39;m transitively uncertain about what non-exported functions are called. </p></pre>captncraig: <pre><p>This is a good point. It does make more things transitively &#34;dirty&#34; that way. It is still possible to have an unexported method that is only invoked from package level functions (or not at all), we can confidently reason will not be used by our main application. </p></pre>endophage: <pre><p>Such a function would be truly dead code (or only used for testing). If it&#39;s not used for testing, it probably shouldn&#39;t exist, and if it is only there for package scope testing, it should be in an _test.go file. </p></pre>purpleidea: <pre><p>Have you heard of libraries before?</p></pre>endophage: <pre><p>Ones where I can call non-exported functions? No. If a non-exported function is unreachable from any exported function (or the init() ), it&#39;s dead code. </p></pre>int32_t: <pre><blockquote> <p>Note that, to my knowledge, using reflect removes this guarantee somewhat.</p> </blockquote> <p>That&#39;s a bad news. Does that mean any program that contains <code>fmt.Printf</code> would lead to a much more bloated binary?</p></pre>elagergren: <pre><p>Not entirely. For example, if the linker simply didn&#39;t strip <em>anything</em> then <code>xxx.T</code> and its one method <code>Bar</code> would show up in the diassembled code.</p> <pre><code>0:0 ~/gopath/src/github.com/ericlagergren/test $ cat main.go package main import &#34;github.com/ericlagergren/test/xxx&#34; func main() { xxx.Foo() } 0:0 ~/gopath/src/github.com/ericlagergren/test $ cat xxx/xxx.go package xxx import &#34;fmt&#34; //go:noinline func Foo() { fmt.Println(&#34;hello from Foo!&#34;) } type T struct{} //go:noinline func (t T) Bar() int { return 12 } 0:0 ~/gopath/src/github.com/ericlagergren/test $ go build 0:0 ~/gopath/src/github.com/ericlagergren/test $ objdump -D test | grep &#39;xxx&#39; github.com/ericlagergren/test/xxx.Foo: 108704d: 0f 86 8d 00 00 00 jbe 141 &lt;github.com/ericlagergren/test/xxx.Foo+0xA0&gt; 10870e5: e9 56 ff ff ff jmp -170 &lt;github.com/ericlagergren/test/xxx.Foo&gt; github.com/ericlagergren/test/xxx.init: 10870fd: 76 45 jbe 69 &lt;github.com/ericlagergren/test/xxx.init+0x54&gt; 1087114: 76 09 jbe 9 &lt;github.com/ericlagergren/test/xxx.init+0x2F&gt; 108711f: 75 07 jne 7 &lt;github.com/ericlagergren/test/xxx.init+0x38&gt; 1087149: eb a5 jmp -91 &lt;github.com/ericlagergren/test/xxx.init&gt; 108716b: e8 d0 fe ff ff callq -304 &lt;github.com/ericlagergren/test/xxx.Foo&gt; 10871bf: e8 2c ff ff ff callq -212 &lt;github.com/ericlagergren/test/xxx.init&gt; github.com/ericlagergren/test/xxx.initdone.: </code></pre> <p>It&#39;d make sense that they&#39;d work with the toolchain to make sure that simply importing <code>reflect</code> doesn&#39;t keep <em>every</em> function, since a <em>ton</em> of packages (especially in the stdlib) import <code>fmt</code>.</p></pre>recurrency: <pre><p>Are there any tools out there to discover such funcs in a project? Can be nice for spring cleaning.</p></pre>_zombiezen_: <pre><p><a href="https://github.com/dominikh/go-tools/tree/master/cmd/unused">https://github.com/dominikh/go-tools/tree/master/cmd/unused</a></p></pre>dlsniper: <pre><p>Gogland can show you these as you type/browse the files or you can run yhe inspection on the project.</p></pre>gerbs: <pre><p>Which is super annoying when it shows warnings for unused exported functions. </p></pre>dlsniper: <pre><p>They aren&#39;t used in your whole GOPATH. What would be the use-case to not show them as unused? You can also disable that specific inspection if you really want to.</p></pre>cristiandeives: <pre><p>If my project is a library, some exported functions might not be used and still be useful.</p></pre>dlsniper: <pre><p>Then you should include tests for the exported functions. Gogland won&#39;t complain for exported symbols that are used in tests.</p></pre>cristiandeives: <pre><p>OK, that makes sense :)</p></pre>everdev: <pre><p>Why aren&#39;t unused functions considered a compile error like unused variables?</p></pre>captncraig: <pre><p>A library package can export functions that never get called by a given main application.</p> <p>A struct may have functions that are never explicitly called, but are potentially invoked via reflect, so its hard to even detect.</p></pre>drvd: <pre><p>Getting compiled and being put in the object file during linkage are two different things: It is always compiled. What the current linkers (there are several) can do: Don&#39;t know.</p></pre>dlsspy: <pre><p>Yes they are complied. No they are not in you binaries.</p></pre>

入群交流(和以上内容无关):加入Go大咖交流群,或添加微信:liuxiaoyan-s 备注:入群;或加QQ群:692541889

790 次点击  
加入收藏 微博
暂无回复
添加一条新回复 (您需要 登录 后才能回复 没有账号 ?)
  • 请尽量让自己的回复能够对别人有帮助
  • 支持 Markdown 格式, **粗体**、~~删除线~~、`单行代码`
  • 支持 @ 本站用户;支持表情(输入 : 提示),见 Emoji cheat sheet
  • 图片支持拖拽、截图粘贴等方式上传