2017-03-16 2 views
2

Wir haben ein Go-Paket entwickelt, das von vielen von uns verwendet wird.Wie unbenutzten Code zur Kompilierzeit entfernen?

Es wird mit der Standardmethode import ("package-name") importiert.

Zur Kompilierungszeit enden alle unsere Dienstprogramme, einschließlich der sehr kleinen, als sehr große Binärdateien.

Wir haben alle Zeichenfolgen in den Dienstprogrammen extrahiert und festgestellt, dass das gesamte Paket in jedes Dienstprogramm kompiliert wird. Einschließlich Funktionen, die von diesen Dienstprogrammen nicht verwendet werden.

EDIT 1:

Vielen Dank an die Menschen, die auf diese Frage reagieren.

Hier ist, was wir sehen:

main.go

package main 

import "play/subplay" 

func main() { 
    subplay.A() 
} 

play/subplay.go

package subplay 

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

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

Funktion B() nie aufgerufen. Nach dem Erstellen der Binärdatei finden wir jedoch die Zeichenfolge "secret string" in der Datei "main.exe".

Wie können wir unbenutzten Code aus Go-Programmen zur Kompilierzeit entfernen?

+2

Welche Version von Go verwenden Sie? Weil '' secret string "' ** nicht ** in der ausführbaren Datei für mich erscheint, wenn 'subplay.B()' nicht aufgerufen wird (Go 1.8, sowohl für Linux als auch für Windows)! – icza

Antwort

5

Der Compiler tut dies bereits. Der gesamte Code landet in Paketdateien (.a), aber in der ausführbaren Binärdatei enthält das Go-Tool nicht alles aus importierten Paketen, sondern nur das, was benötigt wird (genauer gesagt: es schließt Dinge aus, die es nicht mehr erreichen kann).

Siehe mögliches Duplikat Splitting client/server code.

Eines ist hier zu beachten: Wenn ein importiertes Paket (von dem Sie nur die Dinge einbeziehen wollen, auf die Sie verweisen) andere Pakete importiert, muss dies natürlich rekursiv geschehen.

Zum Beispiel, wenn Sie dieses Paket importieren:

package subplay 

func A() {} 

Und daraus nichts nennen:

package main 

import _ "play/subplay" 

func main() { 
} 

Das Ergebnis binär (Go 1.8, Linux AMD64) wird 960.134 Bytes sein (etwa 1 MB).

Wenn Sie subplay ändern net/http zu importieren:

package subplay 

import _ "net/http" 

func A() {} 

Aber immer noch rufen nichts von net/http, wird das Ergebnis sein: 5.370.935 Bytes (ca. 5 MB)! (Beachten Sie, dass net/http importiert auch 39 other packages!)

Nun, wenn Sie voran gehen und mit Sachen von net/http starten:

package subplay 

import "net/http" 

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

Aber im main Paket, das Sie noch nicht nennen subplay.A(), die Größe der ausführbaren Datei Binär ändert sich nicht: bleibt 5.370.935 Bytes!

Und wenn Sie das main Paket ändern subplay.A() zu nennen:

package main 

import "play/subplay" 

func main() { 
    subplay.A() 
} 

Das Ergebnis binäre wächst: 5.877.919 Bytes!

Wenn Sie http.ListenAndServe() ändern http.ListenAndServeTLS():

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

Ergebnis binär ist: 6.041.535 Bytes.

Wie Sie sehen können, was in die ausführbare Binärdatei kompiliert wird hängt davon ab, was Sie von den importierten Paketen aufrufen/verwenden.

Vergessen Sie auch nicht, dass Go eine statisch verknüpfte Sprache ist, das Ergebnis ausführbare Binärdatei muss alles enthalten, was sie benötigt. Siehe verwandte Frage: Reason for huge size of compiled executable of Go

+0

Hallo Icza, danke für Ihre Antwort. Wir sehen unterschiedliche Ergebnisse an unserem Ende. Siehe oben eine aktualisierte Nachricht mit den Details. Vielen Dank im Voraus dafür, dass Sie sich das angesehen haben! –

+0

Es ist erwähnenswert, dass das Importieren eines Pakets, unabhängig davon, ob Sie es verwenden oder nicht, dazu führt, dass Paketvariablen initialisiert werden und die 'init()' -Funktion ausgeführt wird. Diese können auf andere Teile des Pakets verweisen, die ihrerseits auf andere verweisen können. Wenn Sie also nichts in dem Paket referenzieren, heißt das nicht, dass das ganze Paket unbenutzt bleibt oder dass der Compiler dies tut fähig, es zu ertragen. – Adrian

+0

@Adrian Ja, und das ist genau das, was mein zweites Beispiel beweisen sollte: Nichts von 'subplay' wird benutzt, aber die ausführbare Binärdatei wird um 4 MB erhöht, weil sie' net/http' referenziert. – icza

0

Sie können Ihr Paket in eine plugin verwandeln, wenn Sie die Einschränkungen beachten (Plugins benötigen Go 1.8 und funktionieren derzeit nur unter Linux).

[Bearbeiten] Da Sie Windows verwenden, ist dies keine Option für Sie.

+0

Und jedes Plugin selbst ist statisch verlinkt und wäre somit noch größer. –

+0

Das Extrahieren des Pakets in ein Plug-in bedeutet, dass der Paket-Binärcode nur in einer .so-Datei enthalten ist, nicht in den ausführbaren Dateien des Hilfsprogramms. Daher wird dieser Code wie angefordert aus den Dienstprogrammen entfernt. Natürlich ist das Plugin selbst statisch verknüpft, aber die Dienstprogramme laden es dynamisch, sie importieren es nicht. – Zoyd

+1

Während Plugins in manchen Fällen helfen können, die Größe von ausführbaren Binär + Plugin-Dateien zu reduzieren, können sie es auch erhöhen! Zum Beispiel, wenn das Plugin 'fmt' importiert und auch Ihre Haupt-App, wird das' fmt'-Paket sowohl in der ausführbaren Binärdatei als auch in der Plugin-Datei enthalten sein! Ganz zu schweigen davon, dass es viel weniger bequem ist, ein Plugin zu laden und zu benutzen, als ein Paket zu importieren und zu benutzen. Leistung nicht zu erwähnen ... – icza

Verwandte Themen