Kokizzu
Kokizzu

Reputation: 26888

Are unused const/function of golang package included in executable binary?

Are unused const/function/struct's method of golang package included in executable binary?

for example:

  1. If I have a package Const which contains bunch of constants (containing SQL queries), but only few of them used in main, would it all included in the executable binary when compiled?
package Const
const (
   InsertA = `insert into ...` 
   InsertB = `insert into ...`
   UpdateA1 = `update ...` // certain column
   UpdateA2 = `update ...` // other columns, different where, etc..
   ...
)
// in main, only some of them used/prepared
  1. If I have a package Func which contains bunch of functions returning literals (SQL strings), but only few of them used in main, would it all included in the executable binary when compiled?
package Func
func InsertA() string { return `insert into ...` }
func InsertB() string { return `insert into ...` }
func UpdateA() string { return `Update ...` }
...
  1. If I have a package mix, which contains bunch of functions returning/using all constants like in number 1, but only some of the functions used in main would it all included in the executable binary when compiled?
package mix
const (
   insertA = `insert into ...`
   insertB = `insert into ...`
   updateA = `update ...`
   ...
)
func InsertA() string { return insertA }
func InsertB() string { return insertB }
func UpdateA() string { return updateA }
// in main, only some of the const are prepared
  1. If I have a package Struct, which contains a lot of structs with bunch of methods (categorized SQL per table), but only some of the struct called in main, would all constant, struct definitions, methods included in the executable binary when compiled?
package Struct
const (
   insertA = `insert into ...`
   insertB = `insert into ...`
   updateA = `update ...`
   ...
)
// in main only some of them prepared
type A struct {db *DB}
func (a *A) Prepare() error {} 
func (a *A) InsertA(...) error {} 
func (a *A) UpdateA(...) error {} 
type B struct {db *DB}
func (b *B) Prepare() error {} 
func (b *B) InsertB(...) error {} 
// in main only some of them used (eg. only struct `A` used)

the context/case was for refactoring old codebase, so it can be better for debugging/understanding the code for new programmers (to know easily which functions/methods that modify that table by merging into one struct per table or one package per table) without sacrificing binary size, because currently all command-queries scattered in multiple binaries/packages (have to manually ctrl+F INSERT INTO tablename or UPDATE tablename or DELETE FROM tablename to look which functions/methods that write/modify records on that table). So I can decide whether it better to have one package for each table (250+) or one single package with multiple files containing empty structs of each table.

old codebase was something like this:

package hugeX
func foo() map[constQ]string {
  return map[constQ]string{
    insertB: `insert into...`,
    updateA: `update ...`,
    ...
  }
}
package hugeY
func foo() map[constQ]string {
  return map[constQ]string{
    insertA: `insert into...`,
    updateB: `update ...`,
    ...
  }
}
package foo
const (
  insertB = `insert into..`
  updateA = `update ...`
  ...
)
package bar // importing hugeX
const ( 
  insertA = `insert into ...` 
  updateA = `update ...` // by something, sometimes duplicates
  ... 
)
package baz 
const (
  ...
)
... and so on..

Upvotes: 1

Views: 853

Answers (1)

Kokizzu
Kokizzu

Reputation: 26888

after testing those and using strings and grep

strings binaryName | grep CONSTANTSPREFIX
strings binaryName | grep CONSTANTRETURNEDBYFUNCS
strings binaryName | grep CONSTANTRETURNEDBYMETHODS

the code something like this

package a
const (
   A0 = `ZAAA0` // use this on main
   A1 = `ZAAA1`
   A2 = `ZAAA2`
   A3 = `ZAAA3`
   A4 = `ZAAA4`
   A5 = `ZAAA5`
   A6 = `ZAAA6`
)
func B1() string { return A1 } // call this on main
func B2() string { return A2 }
func B3() string { return `ZBBB3` } // call this on main
func B4() string { return `ZBBB4` }
type C1 struct{}
func (c *C1) C3() string { return A3 } // call this on main
func (c *C1) C4() string { return A4 }
type D1 struct{}
func (c *D1) D5() string { return A5 }
func (c *D1) D6() string { return A6 }

the main:

package main
import "a"
import "fmt"
func main() {
        c := a.C1{}
        fmt.Println(a.A0,a.B1(),a.B3(),c.C3())
}

the result

$ go version
go version go1.15.6 linux/amd64
$ go build main.go
$ strings main | grep ZAAA
ZAAA0ZAAA1ZAAA3ZBBB3

only those that are called are included in the executable binary.

Upvotes: 2

Related Questions