레이블이 make인 게시물을 표시합니다. 모든 게시물 표시
레이블이 make인 게시물을 표시합니다. 모든 게시물 표시

Undefined symbols for architecture arm64

# mac m1(arm64) 환경에서 my 라는 프로젝트에서 빌드를 할때
# my/include 와 my/lib 에 디렉토리에 소스로 빌드한 protobuf 등의 라이브리 결과물이 있고 
# 이를 링크하는 my 프로젝트에서 cmake > make 빌드 중 다음과 같은 에러가 발생했다.
Undefined symbols for architecture arm64:
"grpc_call_run_in_event_engine(grpc_call const*, absl::lts_20250127::AnyInvocable<void ()>)", referenced from:
... 생략 ...  "google::protobuf::internal::AssignDescriptors(google::protobuf::internal::DescriptorTable const* (*)(), absl::lts_20250127::once_flag*, google::protobuf::Metadata const&)", referenced from:
... 생략 ...

# 동적라이브러리(.dylib) 파일들 경로는 이상 없이 lib/을 링킹하고 있었다
# 해당 dylib 파일의 타입도 다음과 같이 arm64 로 빌드되어 있었다.
file /Users/ysoftman/workspace/my/lib/libprotobuf.25.6.0.dylib
/Users/ysoftman/workspace/my/lib/libprotobuf.25.6.0.dylib: Mach-O 64-bit dynamically linked shared library arm64

# protobuf 에서 AssignDescriptors() 심볼도 다음과 같이 확인하니 존재했다.
nm -gU /Users/ysoftman/workspace/my/lib/libprotobuf.25.6.0.dylib | rg AssignDescriptors
00000000000d2fa8 T __ZN6google8protobuf8internal17AssignDescriptorsEPFPKNS1_15DescriptorTableEvEPN4absl12lts_202407229once_flagERKNS0_8MetadataE
00000000000d2ff4 T __ZN6google8protobuf8internal17AssignDescriptorsEPKNS1_15DescriptorTableE

# protobuf 라이브러리에서 사용하는 dylib 를 다음과 같이 확인하니
# abseil(absl, c++ standard 에 없는 기능들이 있는 구글에서 만든 오픈소스 라이브러리) 2407 버전을 사용하게 되어 있다.(/opt/homebrew/opt.. 경로를 사용하고 있음)
# 그런데 위 에러에 보이는 absl 20250127 보다 이전이다.
otool -L  /Users/ysoftman/workspace/my/lib/libprotobuf.25.6.0.dylib
... 생략 ...
/opt/homebrew/opt/abseil/lib/libabsl_log_initialize.2407.0.0.dylib (compatibility version 2407.0.0, current version 0.0.0)
/opt/homebrew/opt/abseil/lib/libabsl_statusor.2407.0.0.dylib (compatibility version 2407.0.0, current version 0.0.0)
... 생략 ...

# my/lib/libprotobuf.25.6.0.dylib 소스 빌드시 프로젝트 absl 은 패키지(시스템 기본 설정, brew install abseil로 설치됨)를 이용하게 되어 있는게 문제였다.
# 참고로 brew uninstall abseil 하면 시스템에서 이미 mysql 등에서 사용하고 있어 디펜던시가 있다.
cmake -DCMAKE_BUILD_TYPE=RelWithDebInfo \
-DCMAKE_INSTALL_PREFIX:PATH=$PREFIX \
-DCMAKE_INSTALL_LIBDIR:PATH=lib \
-DCMAKE_CXX_STANDARD=17 \
-DBUILD_SHARED_LIBS=1 \
-Dprotobuf_BUILD_TESTS=0 \
-Dprotobuf_ABSL_PROVIDER=package .

# 정리하면 abseil 버전이 다음과 같이 2개가 있는 상태다.
# 시스템에 기본 버전: /opt/homebrew/Cellar/abseil/20240722.1
# 커스텀 빌드: /Users/ysoftman/workspace/my/lib/libabsl_xxx.2501.0.0.dylib

# my/lib/ 로 설치 전 커스텀 빌드 소스들(cmake 정보등) my/abseil-cpp-20250127.0 에 있다.
# protobuf dylib 빌드시 다음 2개의 값을 설정하면 커스텀한(absl 2501버전) dylib 를 참조해 빌드할 수 있다.
# 참고로 아래 변수이름은 protobuf 소스 > cmake > abseil-cpp.cmake 를 참고해 알 수 있었다.
# protobuf cmake 에 수행시 다음과 같이 커스텀 absl 을 사용해 빌드(cmake and build)
-Dprotobuf_ABSL_PROVIDER=module \
-DABSL_ROOT_DIR="/Users/ysoftman/workspace/my/abseil-cpp-20250127.0" \

# grpc 도 에러나 발생하니 수정
# grpc 빌드는 absl protobuf re2 cares 다음과 같이 빌드(cmake and bulid)
# 참고로 아래 변수이름은 gproc 소스 > cmake > xxx.cmake 를 참고해 알 수 있었다.
-DgRPC_ABSL_PROVIDER=module \
-DABSL_ROOT_DIR="/Users/ysoftman/workspace/my/abseil-cpp-20250127.0" \
-DgRPC_PROTOBUF_PROVIDER=module \
-DPROTOBUF_ROOT_DIR="/Users/ysoftman/workspace/my/protobuf-25.6" \
-DgRPC_RE2_PROVIDER=module \
-DRE2_ROOT_DIR="/Users/ysoftman/workspace/my/re2-2024-07-02" \
-DgRPC_CARES_PROVIDER=module \
-DCARES_ROOT_DIR="/Users/ysoftman/workspace/my/c-ares-1.34.4" \

# 또는 PROVIDER=package 로 둔 상태에서 CMAKE_PREFIX_PATH(include,header경로)를 설정해도 된다.
-DCMAKE_PREFIX_PATH="/Users/ysoftman/workspace/my"

# 위와 같은 커스텀 dylib 를 생성하려면 
# absl, re2 --> protobuf
# absl, re2, protobuf --> grpc
# 로 관련된 모든 ~/Users/ysoftman/workspace/my...의 커스텀 경로를 해줘야해서 복잡하고 불편한다.
# 그리고 my 프로젝트에서 빌드시 커스텀 라이브러리 사용으로 또 다른 에러가 발생했다.
# 그냥 다음 패키지(라이브러리)들은 소스 빌드를 하지 않고 설치하고 -DxxxPROVIDER=package 로 원복
# 커스텀 라이브러리들 목록에서 제외(my/{include,lib}에 생성되지 않아)하면 my 프로젝트도 다음 시스템 패키지를 사용해 문제 없이 빌드됐다.
brew install abseil re2 protobuf grpc

go download error in etcd build

# etcd 소스 빌드
wget https://github.com/etcd-io/etcd/archive/refs/tags/v3.5.18.tar.gz
tar zxvf v3.5.18.tar.gz
cd etcd-3.5.18
make

# make > build.sh > script/test_lib.sh > determine_go_version 에서
# .go-version 파일에서 사용할 go version 을 찾고 다운로드 한다.
# 여기서 exit code 1 발생으로 빌드가 중지된다.
GO_BUILD_FLAGS="-v" ./build.sh
go: downloading go1.22.11 (darwin/arm64)
go: download go1.22.11: golang.org/toolchain@v0.0.1-go1.22.11.darwin-arm64: verifying module: checksum database disabled by GOSUMDB=off

# 수동으로 해당 go 버전을 설치하면 된다.
# /Users/ysoftman/workspace/gopath/bin/go1.22.11 가 생긴다.
go install golang.org/dl/go1.22.11@latest

# ~/sdk/go1.22.11/ 에 go 소스 빌드 파일이 생긴다.
go1.22.11 download

# 또는 다음 환경변수 설정으로 시스템 go 버전을 사용해 빌드할 수 있다.
FORCE_HOST_GO=ON make

centos bash 4.4 설치

# centos 7.7 사용중인데 bash 최신 버전(4.4이상)을 설치하려고
# yum 으로 시도하면 4.2.46 만 설치된다.
sudo yum install bash

# 때문에 소스를 다운로드 받아 빌드 및 설치해본다.
wget https://ftp.gnu.org/gnu/bash/bash-4.4.tar.gz
tar zxvf bash-4.4.tar.gz
cd ./bash-4.4
./configure
make -j4
sudo make install

# 이제 로그아웃 후 다시 로그인해 버전 확인
bash --version
GNU bash, version 4.4.0(1)-release (x86_64-unknown-linux-gnu)
Copyright (C) 2016 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>
This is free software; you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.

make -j option in docker container

# 6cores(12threads), 32GB RAM 맥북에서
# 도커 컨테이너를 띄우고 c++ make 속도를 높이기 위해
# make -j 4 -> make -j 8 로 같이 병렬 컴파일 잡 개수를 높였다.
# 그런데 다음과 같은 에러가 발생한다.
g++: internal compiler error: Killed (program cc1plus)
Please submit a full bug report,
with preprocessed source if appropriate.
See <http://bugzilla.redhat.com/bugzilla> for instructions.
make[1]: *** [util/utf8_string_bounder.o] Error 4
make[1]: *** Waiting for unfinished jobs....

# 위와 같은 에러는 빌드시 메모리 부족으로 스왑 파일을 사용하는데
# 스왑파일도 1GB 로 적어 컴파일을 끝낼 수 없어 발생한 에러다.
# 컨테이너의 메모리가 2GB 로 설정되어 있었다.
# 컨테이너에서 사용할 cpu, memory 를 늘려야 한다.(스왑파일도 늘리 수 있다.)
# 도커 setting -> resources -> advanced 에서 변경한다.


# 이제 컨테이너를 run 하고
docker run --name ysoftman_centos -dit ysoftman/centos

# 컨테이너에 접속해서
docker exec -u root -e COLUMNS=$(tput cols) -e LINES=$(tput lines) -it ysoftman_centos /bin/bash

# cpu, memroy 를 확인해 보면
# cpu 6, memory 8G 로 설정된것을 볼 수 있다.
cat /proc/cpuinfo  | \grep processor
processor : 0
processor : 1
processor : 2
processor : 3
processor : 4
processor : 5

free -h
              total        used        free      shared  buff/cache   available
Mem:           7.8G        326M        7.1G        868K        384M        7.2G
Swap:          1.0G          0B        1.0G

# 이제 make -j 8 을 수행하면 잘 된다.
time make -j8

# 컨테이너 리소스 증가에 따라 make 빌드 소요 시간도 줄지만
# 같은 리소스상태에서는 -j 값이 어느정도 부터는 시간이 더 이상 줄지 않는다.
# 2CPUs, 2GB mem, make -j 8 --> (2:12초)
# 6CPUs, 8GB mem, make -j 8 --> (1:42초)
# 10CPUs, 16GB mem, make -j 10 --> (1:39초)
# 10CPUs, 16GB mem, make -j 12 --> (1:39초)

# 참고
# make -j 옵션 사용시 값을 명시하지 않으면 무한대로 설정된다.
make --help | \grep  '\-j'
  -j [N], --jobs[=N]          Allow N jobs at once; infinite jobs with no arg.

# 무한대로 하면 모든 cpp 파일이 동시 컴파일 되고 더 많은 메모리를 필요로 해서
# 에러가 또 발생할 수 있어 memory 리소스에 따른 적절한 -j 수치를 정해야 한다.

Visual C++ Make multi process(job) option

컴파일을 빠르게 하기 위해서 멀티 프로세스 옵션을 사용한다.
예를 들어 8개의 프로세스로 컴파일을 실행한다면 아래와 같다.

[Windows 에서 Visual Studio C++ 를 사용할 경우]
프로젝트 속성 -> C/C++ -> 명령줄 -> 추가 옵션 -> /MP8
단, /MP 옵션을 사용하기 위해선 /Gm /Yc 옵션을 사용하지 말아야 한다.
/Gm 은 변경된 소스파일만 다시 컴파일하는 옵션으로 프로젝트 속성 -> C/C++ -> 코드생성 -> 최소 다시 빌드 기능 에서 선택한다.(VS2008기준)
/Yc 은 미리 컴파일된 헤더 만드는 옵션으로 프로젝트 속성 -> C/C++ >미리 컴파일된 헤더 만들기/사용 에서 선택한다.(VS2008기준)

[Linux 에서 Make 를 사용할 경우]
make -j8