cборка приложений Go

Вопросы написания собственного программного кода (на любых языках)

Модератор: Olej

Аватара пользователя
Olej
Писатель
Сообщения: 21338
Зарегистрирован: 24 сен 2011, 14:22
Откуда: Харьков
Контактная информация:

Re: cборка приложений Go

Непрочитанное сообщение Olej » 12 май 2017, 19:45

perseus писал(а): а при анализе файлов собранных им выдаются ссылки на библиотеки Линукс:

Код: Выделить всё

maksim@maksim-MS-7519 ~/Progy/Go/src/hellodb $ ls
hellodb  hellodb.go  outputDB  outputUsr
maksim@maksim-MS-7519 ~/Progy/Go/src/hellodb $ ldd hellodb
   linux-gate.so.1 =>  (0xb7745000)
   libpthread.so.0 => /lib/i386-linux-gnu/libpthread.so.0 (0xb770b000)
   libc.so.6 => /lib/i386-linux-gnu/libc.so.6 (0xb755c000)
   /lib/ld-linux.so.2 (0xb7746000)
1. Я свеже установил, в Mint 18.1 оба варианта GCC Go и Golang (система свежая, установка новая, чистая)... см. здесь.

2. Взял элементарное приложение, из старых залежалых... hello.go:

Код: Выделить всё

package main

import ( "fmt"
         "os" )

func main(){
   fmt.Println( "ты кто будешь?" )
   fmt.Printf( "> " )
   буфер := make( [] byte, 120 )
   длина, _ := os.Stdin.Read( буфер ) // возвращается 2 значения
   Ω := длина

   ответ := string( буфер[ : Ω  - 1 ] ) // убрали '\n'

   fmt.Printf( "какое длинное имя ... целых %d байт\n", Ω )
   fmt.Printf( "привет, %s\n", ответ )
}
3. Компилирую это хозяйство 2-мя разными компиляторами и их дефаултными опциями (не лезу разбираться и вмешиваться)...

Код: Выделить всё

olej@nvidia ~/2017_WORK/own.WORK/Go $ gccgo hello.go -o hello

olej@nvidia ~/2017_WORK/own.WORK/Go $ go build -o hello.gl hello.go

olej@nvidia ~/2017_WORK/own.WORK/Go $ ls -l
итого 2280
-rwxr-xr-x 1 olej olej   34040 май 12 19:16 hello
-rwxr-xr-x 1 olej olej 2292968 май 12 19:26 hello.gl
-rw-r--r-- 1 olej olej     601 авг 10  2014 hello.go
Обращаем внимание на разительную разницу в длине 2-х эквивалентных по исполнению приложений! hello - собран GCC Go, а hello.gl - Golang.

4. Сравниваем:

Код: Выделить всё

olej@nvidia ~/2017_WORK/own.WORK/Go $ ldd hello
	linux-vdso.so.1 =>  (0x00007fff2f960000)
	libgo.so.9 => /usr/lib/x86_64-linux-gnu/libgo.so.9 (0x00007f39d0d95000)
	libgcc_s.so.1 => /lib/x86_64-linux-gnu/libgcc_s.so.1 (0x00007f39d0b7f000)
	libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007f39d07b5000)
	/lib64/ld-linux-x86-64.so.2 (0x0000561b4ae26000)
	libpthread.so.0 => /lib/x86_64-linux-gnu/libpthread.so.0 (0x00007f39d0598000)
	libm.so.6 => /lib/x86_64-linux-gnu/libm.so.6 (0x00007f39d028f000)

Код: Выделить всё

olej@nvidia ~/2017_WORK/own.WORK/Go $ ldd hello.gl
	не является динамическим исполняемым файлом
olej@nvidia ~/2017_WORK/own.WORK/Go $ file hello.gl
hello.gl: ELF 64-bit LSB executable, x86-64, version 1 (SYSV), statically linked, not stripped
И где здесь ссылки на разделяемые библиотеки? ... даже libc.so , которую используют практически все приложения со всех языков программирования...

5. Выполняем/проверяем:

Код: Выделить всё

olej@nvidia ~/2017_WORK/own.WORK/Go $ ./hello.gl 
ты кто будешь?
> вася
какое длинное имя ... целых 9 байт
привет, вася
:lol:

Аватара пользователя
perseus
Писатель
Сообщения: 99
Зарегистрирован: 11 май 2017, 18:01
Откуда: Щёлково, Московская обл.
Контактная информация:

Re: cборка приложений Go

Непрочитанное сообщение perseus » 12 май 2017, 22:27

а теперь самое интересное:
я соберу два файла -первый это ваш код helloVasya.go,
- второй файл - моя прога imitproto
соберу их одним и тем же компилятором и одной и тойже командой

Код: Выделить всё

maksim@ASUS ~/Progy/Go/src/hello $ go version
go version go1.2.1 linux/386
maksim@ASUS ~/Progy/Go/src/hello $ go build helloVasya.go
maksim@ASUS ~/Progy/Go/src/hello $ ls
hello  hello.go  helloVasya  helloVasya.go
maksim@ASUS ~/Progy/Go/src/hello $ file helloVasya
helloVasya: ELF 32-bit LSB  executable, Intel 80386, version 1 (SYSV), statically linked, not stripped
maksim@ASUS ~/Progy/Go/src/hello $ cd ../imitator
maksim@ASUS ~/Progy/Go/src/imitator $ ls
dumpIMIT  dumpSHS  imit.go  imitgui  imitgui.go  imitproto  imitproto.go  params
maksim@ASUS ~/Progy/Go/src/imitator $ rm imitproto
maksim@ASUS ~/Progy/Go/src/imitator $ ls
dumpIMIT  dumpSHS  imit.go  imitgui  imitgui.go  imitproto.go  params
maksim@ASUS ~/Progy/Go/src/imitator $ go build imitproto.go
maksim@ASUS ~/Progy/Go/src/imitator $ ls
dumpIMIT  dumpSHS  imit.go  imitgui  imitgui.go  imitproto  imitproto.go  params
maksim@ASUS ~/Progy/Go/src/imitator $ file imitproto
imitproto: ELF 32-bit LSB  executable, Intel 80386, version 1 (SYSV), dynamically linked (uses shared libs), not stripped
в случае с вашим кодом получилась статическая сборка, а в случае с моим кодом - динамическая сборка.
в чем разница? думаю в импортированных пакетах

Аватара пользователя
perseus
Писатель
Сообщения: 99
Зарегистрирован: 11 май 2017, 18:01
Откуда: Щёлково, Московская обл.
Контактная информация:

Re: cборка приложений Go

Непрочитанное сообщение perseus » 12 май 2017, 22:30

секция импортирования файла helloVasya:

Код: Выделить всё

package main

import ( "fmt"
         "os" )

func main(){
   fmt.Println( "ты кто будешь?" )
   fmt.Printf( "> " )
   буфер := make( [] byte, 120 )
   длина, _ := os.Stdin.Read( буфер ) // возвращается 2 значения
   Ω := длина

   ответ := string( буфер[ : Ω  - 1 ] ) // убрали '\n'

   fmt.Printf( "какое длинное имя ... целых %d байт\n", Ω )
   fmt.Printf( "привет, %s\n", ответ )
}
секция импортирования файла imitproto:

Код: Выделить всё

// Имитатор ШС
package main

import (
	"fmt"
	"imitator/params"
	"io"
	"log"
	"my_package/structures"
	"net"
	"os"
	"time"
	"unsafe"
)
почувствуйте разницу

Аватара пользователя
perseus
Писатель
Сообщения: 99
Зарегистрирован: 11 май 2017, 18:01
Откуда: Щёлково, Московская обл.
Контактная информация:

Re: cборка приложений Go

Непрочитанное сообщение perseus » 12 май 2017, 22:37

можно конечно последовательно попробовать исключать из программы импортированные пакеты по одному и снова компилирвать каждый раз прогу, чтобы вычислить, кто из них влияет на динамическую сборку...
Но может у вас будут другие идеи ?

Аватара пользователя
Olej
Писатель
Сообщения: 21338
Зарегистрирован: 24 сен 2011, 14:22
Откуда: Харьков
Контактная информация:

Re: cборка приложений Go

Непрочитанное сообщение Olej » 12 май 2017, 22:42

perseus писал(а):почувствуйте разницу
Никакой особо разницы нет - выясняйте что тянет за собой такие эффекты:
- ничто из импортированных пакетов самого Go такого тянуть не должно;
- возможно, что-то из импортированных вами библиотек не имеет статически собранных аналогов в системе - такое бывало уже и не раз (в других ситуациях).

Аватара пользователя
perseus
Писатель
Сообщения: 99
Зарегистрирован: 11 май 2017, 18:01
Откуда: Щёлково, Московская обл.
Контактная информация:

Re: cборка приложений Go

Непрочитанное сообщение perseus » 13 май 2017, 11:55

я провел эксперимент:
взял тестовую программку test.go (просто набор операторов) с небольшим набором пакетов, которая у меня при сборке давала динамически собранный файл. После чего стал по одному исключать пакеты из программки пока не получил статически собранный файл. В результате выяснилось, что при импортировании в программу пакета "net" при сборке получается динамически собранный файл.
Ниже прикладываю распечатки кода и результаты команды на сборку.

Код: Выделить всё

// Тестовая прогарамма
package main

import(
"io"
"fmt"
"log"
"net"
"time"
)

func main() {
   
   // Адрес
   myAddr, err := net.ResolveUDPAddr("udp", "localhost:8000")
   if err != nil {
      fmt.Println("ResolveUDPAddr:",err)
   }
   conn, err := net.ListenUDP("udp", myAddr)
   if err != nil {
      fmt.Println("ListenUDP:",err)
   }
   defer conn.Close() 

 	buf := make([]byte, 100)
   // Таймер
   tick := time.Tick(500*time.Millisecond)   

	//Задержка отправления
    <- tick
	end := io.EOF
	if end != io.EOF {
		log.Fatal(end)
	}
    fmt.Println("send to ",buf, end, myAddr)
   
}
его сборка даёт динамически собранную версию программы

исключаю пакет "net"

Код: Выделить всё

// Тестовая прогарамма
package main

import(
"io"
"fmt"
"log"
//"net"
"time"
)

func main() {
   
/*   // Адрес
   myAddr, err := net.ResolveUDPAddr("udp", "localhost:8000")
   if err != nil {
      fmt.Println("ResolveUDPAddr:",err)
   }
   conn, err := net.ListenUDP("udp", myAddr)
   if err != nil {
      fmt.Println("ListenUDP:",err)
   }
   defer conn.Close() */

 	buf := make([]byte, 100)
   // Таймер
   tick := time.Tick(500*time.Millisecond)   

	//Задержка отправления
    <- tick
	end := io.EOF
	if end != io.EOF {
		log.Fatal(end)
	}
    fmt.Println("send to ",buf, end, /*myAddr*/)
   
}
его сборка даёт статически собранную программу

команды по сборке этих двух версий программ:

Код: Выделить всё

maksim@ASUS ~/Progy/Go/src/test $ rm test
maksim@ASUS ~/Progy/Go/src/test $ go build test.go
maksim@ASUS ~/Progy/Go/src/test $ file test
test: ELF 32-bit LSB  executable, Intel 80386, version 1 (SYSV), dynamically linked (uses shared libs), not stripped
maksim@ASUS ~/Progy/Go/src/test $ rm test
maksim@ASUS ~/Progy/Go/src/test $ go build test.go
maksim@ASUS ~/Progy/Go/src/test $ file test
test: ELF 32-bit LSB  executable, Intel 80386, version 1 (SYSV), statically linked, not stripped
что скажете, Олег Иванович ?

Аватара пользователя
perseus
Писатель
Сообщения: 99
Зарегистрирован: 11 май 2017, 18:01
Откуда: Щёлково, Московская обл.
Контактная информация:

Re: cборка приложений Go

Непрочитанное сообщение perseus » 13 май 2017, 14:21

и вот эти библиотеки пакет "net" и тянет за собой

Код: Выделить всё

maksim@ASUS ~/Progy/Go/src/test $ rm test
maksim@ASUS ~/Progy/Go/src/test $ go build test.go
maksim@ASUS ~/Progy/Go/src/test $ file test
test: ELF 32-bit LSB  executable, Intel 80386, version 1 (SYSV), dynamically linked (uses shared libs), not stripped
maksim@ASUS ~/Progy/Go/src/test $ ldd test
	linux-gate.so.1 =>  (0xb779f000)
	libpthread.so.0 => /lib/i386-linux-gnu/libpthread.so.0 (0xb7763000)
	libc.so.6 => /lib/i386-linux-gnu/libc.so.6 (0xb75b4000)
	/lib/ld-linux.so.2 (0xb77a0000)

Аватара пользователя
Olej
Писатель
Сообщения: 21338
Зарегистрирован: 24 сен 2011, 14:22
Откуда: Харьков
Контактная информация:

Re: cборка приложений Go

Непрочитанное сообщение Olej » 13 май 2017, 15:44

perseus писал(а): взял тестовую программку test.go (просто набор операторов) с небольшим набором пакетов, которая у меня при сборке давала динамически собранный файл. После чего стал по одному исключать пакеты из программки пока не получил статически собранный файл. В результате выяснилось, что при импортировании в программу пакета "net" при сборке получается динамически собранный файл.
Есть подсистемы для которых обслуживающие их библиотеки нельзя собрать статически с приложением.

Статическая сборка с 3-мя (например) приложениями означает, что собираются 3 экземпляра библиотеки - по одной копии к каждому приложению.
Но есть подсистемы в Linux (да и в любой операционной системе), которые могут существовать только единственном экземпляре ... как солитон.
Самая классическая в этом смысле подсистема - это X11 и её библиотеки: у вас в компьютере не может быть 3-х, 5-ти, или 10-ти графических подсистем ... и библиотеки X11, как я понимаю, можно использовать только в единичном, эксклюзивном варианте, когда приложения "из разных рук" обращаются к X11 согласовано.

Точно такая же, нужно думать, и подсистема сетевого стека Linux: у вас может быть множество сетевых интерфейсов, но их обслуживает единый сетевой стек. Я достаточно хорошо знаю сетевую систему в ядре Linux ... и там существует единая очередь продвижения сетевых сокетных буферов (struct sk_buff) - основных структур сетевого стека, снующих вверх-вниз между уровнями сетевого стека.
P.S. Наглядно (и вносит большую ясность) про это можете почитать здесь: Сетевое программирование в Linux. Я пока не написал этот курс лекций, прочитанный на заказ для программистов крупной софтверной разработческой компании - сам не понимал на со 100% прозрачностью всю работу сетевого стека Linux :-? . А тут отдельные фрагменты, давно, в общем, известные - уложились в единую картину. ;-)

Аватара пользователя
perseus
Писатель
Сообщения: 99
Зарегистрирован: 11 май 2017, 18:01
Откуда: Щёлково, Московская обл.
Контактная информация:

Re: cборка приложений Go

Непрочитанное сообщение perseus » 13 май 2017, 19:49

Большое спасибо за разъяснения. С интересом изучу ваш труд о сетевом программировании в Linux.
Если я правильно понял, собранное Go таким динамическим образом (как в моём случае) автономное приложение должно запускаться и работать на такой же операционной системе на другой машине, потому как там установлены такие же разделяемые другими программами только динамически компилируемые библиотеки. :-D

Аватара пользователя
Olej
Писатель
Сообщения: 21338
Зарегистрирован: 24 сен 2011, 14:22
Откуда: Харьков
Контактная информация:

Re: cборка приложений Go

Непрочитанное сообщение Olej » 13 май 2017, 20:40

perseus писал(а):Если я правильно понял, собранное Go таким динамическим образом (как в моём случае) автономное приложение должно запускаться и работать на такой же операционной системе на другой машине, потому как там установлены такие же разделяемые другими программами только динамически компилируемые библиотеки. :-D
perseus писал(а):Касательно намерений (цели) сделать статическую сборку, мне нужно это по работе,
нужна автономная программа которая будет выполняться на удаленном оборудовании с ограниченным доступом, куда нет возможности грузить разделяемые библиотеки поддержки сторонних языков программирования.
Вернёмся к этому вопросу...

То, что полностью статическая сборка решает все вопросы переносимости, панацея - это иллюзия. При такой сборке к программе прикомпонован, в том числе, и интерфейс к системным вызовам (libc.so) и при значительном отличии версии ядра Linux такое приложение может пойти вообще в разнос.
Это не говоря о том, что если у вас не одно, а 2, 3, 4 приложения в проекте, комплекте, то при каждом из них будет свой экземпляр всех библиотек, которые могут занимать по 80-90% объёма каждого из приложений.

Статическая компоновка совершенно уместна для малых embedded реализаций ... но не нужно путать одно с другим - это когда речь идёт о создании автономного ПО, работающего без операционной системы. А вот когда там стоит, пусть даже встроенный, Linux - то это уже совершенно другая ситуация.

Но динамическая компоновка, с разделяемыми библиотеками, вплоть до всякой экзотики (Tcl/Tk) может тоже создать проблемы с наличием таких экзотических библиотек - их придётся держать в инсталляционном комплекте проекта при каждой установке.

Но вы можете и сами управлять тем, какие библиотеки прикомпоновать к приложению статически (что-то специфическое), а какие загружать и использовать в качестве DLL (все системные интерфейсы, X11 и GUI фреймворки, сетевые библиотеки, ...).

P.S. Меня заинтересовало, в вашем раньше описании, ваше упоминание Tcl/Tk в контексте Go, и то, что вы собираетесь с ним делать?

Ответить

Вернуться в «Программирование»

Кто сейчас на конференции

Сейчас этот форум просматривают: нет зарегистрированных пользователей и 12 гостей