성태의 닷넷 이야기
홈 주인
모아 놓은 자료
프로그래밍
질문/답변
사용자 관리
사용자
메뉴
아티클
외부 아티클
유용한 코드
온라인 기능
MathJax 입력기
최근 덧글
[정성태] 제가 큰 실수를 했군요. ^^; Delegate를 통한 Bein...
[정성태] Working with Rust Libraries from C#...
[정성태] Detecting blocking calls using asyn...
[정성태] 아쉽게도, 커뮤니티는 아니고 개인 블로그입니다. ^^
[정성태] 질문이 잘 이해가 안 됩니다. 우선, 해당 소스코드에서 ILis...
[양승조
] var대신 dinamic으로 선언해서 해결은 했습니다. 맞는 해...
[양승조
] 또 막혔습니다. ㅠㅠ var list = props[i].Ge...
[양승조
] 아. 감사합니다. 어제는 안됐던것 같은데....정신을 차려야겠네...
[정성태] "props[i].GetValue(props[i])" 코드에서 ...
[정성태] 저렇게 조각 코드 말고, 실제로 재현이 되는 예제 프로젝트를 압...
글쓰기
제목
이름
암호
전자우편
HTML
홈페이지
유형
제니퍼 .NET
닷넷
COM 개체 관련
스크립트
VC++
VS.NET IDE
Windows
Team Foundation Server
디버깅 기술
오류 유형
개발 환경 구성
웹
기타
Linux
Java
DDK
Math
Phone
Graphics
사물인터넷
부모글 보이기/감추기
내용
<div style='display: inline'> <h1 style='font-family: Malgun Gothic, Consolas; font-size: 20pt; color: #006699; text-align: center; font-weight: bold'>Golang - GLIBC 의존을 없애는 정적 빌드 방법</h1> <p> 닷넷 AOT 빌드에서 GLIBC 버전 문제를 겪었더니,<br /> <br /> <pre style='margin: 10px 0px 10px 10px; padding: 10px 0px 10px 10px; background-color: #fbedbb; overflow: auto; font-family: Consolas, Verdana;' > C# - 리눅스용 AOT 빌드를 docker에서 수행 ; <a target='tab' href='https://www.sysnet.pe.kr/2/0/13487#glibc'>https://www.sysnet.pe.kr/2/0/13487#glibc</a> </pre> <br /> Go 언어로 빌드한 바이너리에 대해서도 확인이 필요하겠다 싶었습니다. 우선, Ubuntu 22.04에서 빌드한 경우,<br /> <br /> <pre style='margin: 10px 0px 10px 10px; padding: 10px 0px 10px 10px; background-color: #fbedbb; overflow: auto; font-family: Consolas, Verdana;' > $ <span style='color: blue; font-weight: bold'>go build -o /mnt/c/temp/testapp testapp</span> $ <span style='color: blue; font-weight: bold'>file /mnt/c/temp/testapp</span> /mnt/c/temp/testapp: ELF 64-bit LSB executable, x86-64, version 1 (SYSV), <span style='color: blue; font-weight: bold'>dynamically linked</span>, interpreter /lib64/ld-linux-x86-64.so.2, Go BuildID=kjE...[생략]...3Doy, with debug_info, not stripped $ <span style='color: blue; font-weight: bold'>objdump -p /mnt/c/temp/testapp</span> ...[생략]... Version References: required from libc.so.6: 0x069691b4 0x00 02 <span style='color: blue; font-weight: bold'>GLIBC_2.34</span> 0x069691b2 0x00 03 <span style='color: blue; font-weight: bold'>GLIBC_2.32</span> 0x09691972 0x00 04 GLIBC_2.3.2 0x09691974 0x00 05 GLIBC_2.3.4 0x09691a75 0x00 06 GLIBC_2.2.5 </pre> <br /> 기본적으로는 저렇게 glibc에 의존적인 바이너리를 생성합니다. 당연히 저 실행 모듈을 20.04, 18.04에서 실행하면 버전 오류가 발생합니다.<br /> <br /> <pre style='margin: 10px 0px 10px 10px; padding: 10px 0px 10px 10px; background-color: #fbedbb; overflow: auto; font-family: Consolas, Verdana;' > // 22.04에서 빌드한 바이너리를 20.04에서 실행 $ <span style='color: blue; font-weight: bold'>/mnt/c/temp/testapp</span> /mnt/c/temp/testapp: /lib/x86_64-linux-gnu/libc.so.6: version `GLIBC_2.34' not found (required by /mnt/c/temp/testapp) /mnt/c/temp/testapp: /lib/x86_64-linux-gnu/libc.so.6: version `GLIBC_2.32' not found (required by /mnt/c/temp/testapp) </pre> <br /> 재미있는 점은, 저 빌드를 Ubuntu 20.04에서 하면 glibc의 버전이 확 낮춰진다는 점입니다.<br /> <br /> <pre style='margin: 10px 0px 10px 10px; padding: 10px 0px 10px 10px; background-color: #fbedbb; overflow: auto; font-family: Consolas, Verdana;' > // Ubuntu 20.04에서 빌드한 경우 $ <span style='color: blue; font-weight: bold'>objdump -p /mnt/c/temp/testapp</span> ...[생략]... Version References: required from libpthread.so.0: 0x09691972 0x00 02 GLIBC_2.3.2 0x09691a75 0x00 03 GLIBC_2.2.5 required from libc.so.6: 0x09691974 0x00 04 <span style='color: blue; font-weight: bold'>GLIBC_2.3.4</span> 0x09691a75 0x00 05 GLIBC_2.2.5 </pre> <br /> 가장 높은 버전이 2.3.4니까... <a target='tab' href='https://www.sysnet.pe.kr/2/0/13494#linux_glibc'>웬만한 리눅스 환경에서 전부 실행</a>된다고 보면 됩니다.<br /> <br /> <hr style='width: 50%' /><br /> <br /> 그런데, 저 빌드를 Windows 환경에서 GOARCH, GOOS 환경변수와 함께 cross-compile로 빌드하면,<br /> <br /> <pre style='margin: 10px 0px 10px 10px; padding: 10px 0px 10px 10px; background-color: #fbedbb; overflow: auto; font-family: Consolas, Verdana;' > C:\temp\testapp> <span style='color: blue; font-weight: bold'>set GOARCH=amd64</span> C:\temp\testapp> <span style='color: blue; font-weight: bold'>set GOOS=linux</span> C:\temp\testapp> <span style='color: blue; font-weight: bold'>go build -o c:\temp\testapp testapp</span> </pre> <br /> 해당 결과물은 Ubuntu 18.04에서조차 실행이 잘됩니다. 왜냐하면,<br /> <br /> <pre style='margin: 10px 0px 10px 10px; padding: 10px 0px 10px 10px; background-color: #fbedbb; overflow: auto; font-family: Consolas, Verdana;' > $ <span style='color: blue; font-weight: bold'>ldd /mnt/c/temp/testapp</span> not a dynamic executable $ <span style='color: blue; font-weight: bold'>file /mnt/c/temp/testapp</span> /mnt/c/temp/testapp: ELF 64-bit LSB executable, x86-64, version 1 (SYSV), <span style='color: blue; font-weight: bold'>statically linked</span>, with debug_info, not stripped </pre> <br /> glibc에 대해 정적 링킹이 됐기 때문입니다. 아마도 Windows 환경에서 빌드하는 경우, 현재 시스템에 glibc가 아예 존재조차 하지 않으니 어쩔 수 없이 정적 링킹을 할 수밖에 없었을 것입니다.<br /> <br /> <hr style='width: 50%' /><br /> <a name='cgo_enabled'></a> <br /> 리눅스 환경에서 빌드하는 경우에도 정적 링킹을 명시적으로 하고 싶다면, CGO_ENABLED=0 환경변수를 설정하면 됩니다.<br /> <br /> <pre style='margin: 10px 0px 10px 10px; padding: 10px 0px 10px 10px; background-color: #fbedbb; overflow: auto; font-family: Consolas, Verdana;' > $ <span style='color: blue; font-weight: bold'>CGO_ENABLED=0</span> go build -o /mnt/c/temp/testapp testapp $ <span style='color: blue; font-weight: bold'>file /mnt/c/temp/testapp</span> /mnt/c/temp/testapp: ELF 64-bit LSB executable, x86-64, version 1 (SYSV), <span style='color: blue; font-weight: bold'>statically linked</span>, Go BuildID=w...[생략]...Hc6, with debug_info, not stripped </pre> <br /> 참고로 dockerfile을 경유해 빌드하고 싶다면, <br /> <br /> <pre style='margin: 10px 0px 10px 10px; padding: 10px 0px 10px 10px; background-color: #fbedbb; overflow: auto; font-family: Consolas, Verdana;' > FROM golang:1.21.4 WORKDIR /app </pre> <br /> 이미지를 만들고,<br /> <br /> <pre style='margin: 10px 0px 10px 10px; padding: 10px 0px 10px 10px; background-color: #fbedbb; overflow: auto; font-family: Consolas, Verdana;' > c:\temp> <span style='color: blue; font-weight: bold'>docker build -t go-build-machine -f build.dockerfile .</span> </pre> <br /> 다음과 같이 명령을 수행하면 <br /> <br /> <pre style='margin: 10px 0px 10px 10px; padding: 10px 0px 10px 10px; background-color: #fbedbb; overflow: auto; font-family: Consolas, Verdana;' > <span style='color: blue; font-weight: bold'>docker run -e CGO_ENABLED=0 -v /c/temp/testapp:/app -v /c/temp:/output --name go-build-machine-instance --rm -it go-build-machine /bin/bash -c "go build -o /output/testapp testapp"</span> </pre> <br /> c:\temp 디렉터리에 testapp 바이너리가 생성됩니다.<br /> <br /> "golang:1.21.4" 이미지의 기반 버전이 bookworm이므로 Ubuntu로는 22.04 또는 22.10 버전에 해당합니다. 만약 CGO_ENABLED=0 옵션 없이 빌드했다면 2.34 의존성을 갖게 됩니다.<br /> <br /> <hr style='width: 50%' /><br /> <br /> 마치기 전에, go build의 ldflags에 준 옵션을 보면, <br /> <br /> <pre style='margin: 10px 0px 10px 10px; padding: 10px 0px 10px 10px; background-color: #fbedbb; overflow: auto; font-family: Consolas, Verdana;' > $ <span style='color: blue; font-weight: bold'>go build -ldflags="-help"</span> ...[생략]... -s disable symbol table ...[생략]... -w disable DWARF generation ...[생략]... </pre> <br /> "-w" 옵션은 DWARF 정보 생성을, "-s" 옵션은 디버깅 심벌 테이블 정보를 제어합니다. 실제로 테스트를 해보면, 크기에서 약간 차이가 나고,<br /> <br /> <pre style='margin: 10px 0px 10px 10px; padding: 10px 0px 10px 10px; background-color: #fbedbb; overflow: auto; font-family: Consolas, Verdana;' > [기본 옵션] 4,781 KB [-s 적용] 3,136 KB [-w 적용] 3,393 KB [-s, -w 2개 적용] 3,136 KB </pre> <br /> -s를 적용 시와 2개 모두 적용했을 때의 크기가 같은 것을 보면 symbol table이 없다면 DWARF 정보도 생성하지 않는다는 것을 추측할 수 있습니다.<br /> <br /> file 결과도 비교해 볼까요?<br /> <br /> <pre style='margin: 10px 0px 10px 10px; padding: 10px 0px 10px 10px; background-color: #fbedbb; overflow: auto; font-family: Consolas, Verdana;' > // CGO_ENABLED=0 $ file /mnt/c/temp/testapp [기본 옵션] /mnt/c/temp/testapp: ELF 64-bit LSB executable, x86-64, version 1 (SYSV), statically linked, <span style='color: blue; font-weight: bold'>with debug_info, not stripped</span> [-s 적용] /mnt/c/temp/testapp: ELF 64-bit LSB executable, x86-64, version 1 (SYSV), statically linked, <span style='color: blue; font-weight: bold'>stripped</span> [-w 적용] /mnt/c/temp/testapp: ELF 64-bit LSB executable, x86-64, version 1 (SYSV), statically linked, <span style='color: blue; font-weight: bold'>not stripped</span> [-s, -w 2개 적용] /mnt/c/temp/testapp: ELF 64-bit LSB executable, x86-64, version 1 (SYSV), statically linked, <span style='color: blue; font-weight: bold'>stripped</span> </pre> <br /> 보는 바와 같이, -s 옵션은 -s -w 2개 모두 적용했을 때와 동일하게 stripped로 나오고, -w 옵션은 "with debug_info"만을 없앤 효과를 가집니다.<br /> </p><br /> <br /><hr /><span style='color: Maroon'>[이 글에 대해서 여러분들과 의견을 공유하고 싶습니다. 틀리거나 미흡한 부분 또는 의문 사항이 있으시면 언제든 댓글 남겨주십시오.]</span> </div>
첨부파일
스팸 방지용 인증 번호
1001
(왼쪽의 숫자를 입력해야 합니다.)