C++ 라이브러리 호환성 지원

Cute_Security15·2025년 4월 4일

linux dev

목록 보기
13/16

상황

정형체적 알고리즘에선 opencv 라이브러리를 사용하고 있다.

opencv 라이브러리는 ubuntu22 에서, aarch64-linux-gnu-g++ 로 빌드하였는데
라이브러리에는 어떤 심볼이 들어가 있다

  • ZNSt18condition_variable4waitERSt11unique_lockISt5mutexE@GLIBCXX_3.4.30
root@user-virtual-machine:/mnt/hgfs/shared/libopencv# strings libopencv_core.so.4.5.5 | grep GLIBCXX_3.4.30
GLIBCXX_3.4.30
_ZNSt18condition_variable4waitERSt11unique_lockISt5mutexE@GLIBCXX_3.4.30
root@user-virtual-machine:/mnt/hgfs/shared/libopencv#

🔍 Symbol:
_ZNSt18condition_variable4waitERSt11unique_lockISt5mutexE
🧩 Demangled:
std::condition_variable::wait(std::unique_lock<std::mutex>&)

이 심볼로 인해, opencv 라이브러리를 노바텍 보드에서 제공하는 rtsp
어플리케이션과 링크할때
링크에러가 발생하게 된다

libstdc++.so.6: version `GLIBCXX_3.4.30' not found

상황에 대한 이해를 위해 2가지 전략을 취하였다

  • 자유도를 높이고, 테스트나 확인을 하기 용이한, 가벼운 구조를 채택 (빌드구조)
  • 심볼이 어떤 경로로 들어가게 되었는지, 들어가게 되는 과정에서 갖는 의미는
    무엇이며, 자연스럽게 이걸 제거할수 있는 과정에는 어떤 것이 있을지,
    열린 마인드로 접근 (의미구조)

chatgpt 와 대화하며 2가지 전략을 사용하였고,
구글링 과정에서 빌드구조와 의미구조가 대략적으로 정립되었다

  • 가벼운 conan opencv consumer project 를 구성 (빌드구조)
  • _ZNSt18condition_variable4waitERSt11unique_lockISt5mutexE 심볼 보다는
    뒤에 있는 _GLIBCXX_3.4.30 가 더 중요하다. 따라서 opencv 의존성 코드보다는,
    apt 로 설치되는 시스템 라이브러리에서 들어갔을 가능성이 높다 (의미구조)

여러번의 테스트를 통해, 3가지 감각을 만들수 있었다.

  • libstdc++.so.6 을 링크하는 바이너리 / 라이브러리에는 GLIBCXX 심볼이 들어간다.
  • libstdc++.so.6 는 심볼릭 링크로, 실제 파일명은 libstdc++.so.6.X.Y.Z 이다.
  • ( 이 당시에는 libstdc++6:arm64 패키지가 이 파일을 만든다는 것까지는
    파악하지 못한 시점 )
  • GLIBCXX 심볼은 바이너리 / 라이브러리 빌드당시 사용한 컴파일러 (g++) 버전
    알려준다.

GLIBCXX_3.4.30 심볼은 GCC 12 에서 만들어진다.
https://gcc.gnu.org/onlinedocs/libstdc++/manual/abi.html

GCC 12.1.0: GLIBCXX_3.4.30, CXXABI_1.3.13

ubuntu22 의 libstdc++.6.0.30 은 conan install 중 설치되는 apt 패키지에 의해 생성된 파일이다.

  • libstdc++6:arm64 (apt 패키지)

이 파일에 GLIBCXX_3.4.30 심볼이 들어있다.

strings libstdc++.so.6.0.30 | grep ^GLIBCXX
...
GLIBCXX_3.4.30

따라서, 보드 rootfs 에 있는 libstdc++.so.6.0.28 (GCC 9/10) 가 지원하는 범위를 넘어서게 되고
라이브러리 link 시 에러가 발생하게 된다.

root@ubuntu:~/DISK1/ns02201_linux_sdk/BSP/root-fs/rootfs# find . -name "libstdc++*"
./usr/lib/libstdc++.so.6.0.28
./usr/lib/libstdc++.so.6
root@ubuntu:~/DISK1/ns02201_linux_sdk/BSP/root-fs/rootfs# 

root@ubuntu:~/DISK1/ns02201_linux_sdk/BSP/root-fs/rootfs/usr/lib# strings libstdc++.so.6.0.28 | grep ^GLIBCXX
GLIBCXX_3.4
GLIBCXX_3.4.1
...
GLIBCXX_3.4.27
GLIBCXX_3.4.28
GLIBCXX_DEBUG_MESSAGE_LENGTH
root@ubuntu:~/DISK1/ns02201_linux_sdk/BSP/root-fs/rootfs/usr/lib#

목표

보드에서 지원하는 abi standard 에 맞춰서 opencv 라이브러리를 빌드
정형체적 알고리즘을 만들고 rtsp 어플리케이션과 링크한다

  • a.k.a : GLIBCXX_3.4.30 심볼을 제거하는 자연스러운 방법을 찾고, 수행한다.

확인한 내용

확인사항

경험적으로 다음 사항들을 고려하게 된다.

  • 라이브러리 중 하나라도 libstdc++11 을 사용하면 GLIBCXX_3.4.30 심볼이 들어갈수 있다.
  • conan install 시 설치된 apt 패키지들, 빌드된 라이브러리들 중에 들어갈 우려가 있다.

따라서 다음 확인작업을 수행하였다.

conan target profile 수정 (libstdc++11 --> libstdc++)

  • old library 와의 abi compatibility 유지
  • _GLIBCXX_USE_CXX11_ABI=0 를 부여하는 conan 세팅
[settings]
...
compiler.libcxx=libstdc++

conan install 시 libstdc++6:arm64 가 설치된다.
설치된 파일중 libstdc++.so.6 버전을 확인한다.

  • 문제상황에서는 ubuntu22 에서 작업하고 있었는데,
    문득, launchpad 에 올라와있는 'libstdc++6:arm64 버전' 은
    ubuntu 버전을 낮추면 같이 낮아질수 있겠다는 생각이 들었다.
  • ubuntu22 를 ubuntu18 로 변경 후 libstdc++.so.6 버전을 확인하였다.
  • libstdc++.so.6.0.25 를 쓰고 있다.
  • GCC 8.1.0 이고, GLIBCXX_3.4.25 심볼까지 생성이 가능하다.
  • 따라서 GLIBCXX_3.4.30 심볼은 생성이 불가할 것이다.
root@ubuntu:/usr/lib/aarch64-linux-gnu# ls -l libstdc++.so.6
lrwxrwxrwx 1 root root 19 Mar 10  2020 libstdc++.so.6 -> libstdc++.so.6.0.25
root@ubuntu:/usr/lib/aarch64-linux-gnu#

GCC 8.1.0: libstdc++.so.6.0.25

GCC 8.1.0: GLIBCXX_3.4.25, CXXABI_1.3.11

환경구성

보드 sdk 가이드에선 ubuntu18 에서 빌드할 것을 권고하고 있다.

ubuntu18 로 이동하여 gcc7 설치

apt-get install gcc-7-aarch64-linux-gnu g++-7-aarch64-linux-gnu

libgtk-2.0-dev:arm64 설치가 필요하나 일부 의존성 resolve 가 실패

aptitude 로 설치

aptitude install libgtk2.0-dev:arm64

libiconf/1.17 에서 바이너리 생성 테스트 실패

  • 컴파일러에서 미지원 옵션이 있어서 실패 (-V, -m64)

gcc-7 --> gcc-8 로 교체

sudo apt-get install gcc-8-aarch64-linux-gnu g++-8-aarch64-linux-gnu

dav1d/1.4.3 meson 에서 python 버전 테스트 실패

dav1d/1.4.3: Calling build()
dav1d/1.4.3: Meson configure cmd: meson setup --cross-file "/root/.conan2/p/b/dav1d6607e18d69b5c/b/build-release/conan/conan_meson_cross.ini" "/root/.conan2/p/b/dav1d6607e18d69b5c/b/build-release" "/root/.conan2/p/b/dav1d6607e18d69b5c/b/src" --prefix=/
dav1d/1.4.3: RUN: meson setup --cross-file "/root/.conan2/p/b/dav1d6607e18d69b5c/b/build-release/conan/conan_meson_cross.ini" "/root/.conan2/p/b/dav1d6607e18d69b5c/b/build-release" "/root/.conan2/p/b/dav1d6607e18d69b5c/b/src" --prefix=/
Meson works correctly only with python 3.7+.
You have python 3.6.9 (default, Mar 10 2023, 16:46:00)

python 3.6.9 --> python 3.8 로 교체

sudo apt install software-properties-common -y
sudo add-apt-repository ppa:deadsnakes/ppa -y
sudo apt update

apt-get install python3.8 python3.8-venv python3.8-dev -y
sudo update-alternatives --install /usr/bin/python3 python3 /usr/bin/python3.6 1
sudo update-alternatives --install /usr/bin/python3 python3 /usr/bin/python3.8 2

sudo update-alternatives --config python3
There are 2 choices for the alternative python3 (providing /usr/bin/python3).

  Selection    Path                Priority   Status
------------------------------------------------------------
* 0            /usr/bin/python3.8   2         auto mode
  1            /usr/bin/python3.6   1         manual mode
  2            /usr/bin/python3.8   2         manual mode

Press <enter> to keep the current choice[*], or type selection number: 2

python3
Python 3.8.0 (default, Dec  9 2021, 17:53:27)
[GCC 8.4.0] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>>

python 관련 패키지들 업그레이드 (pip, setuptools, wheel, PyYAML)

python3 -m pip install --upgrade pip setuptools wheel

sudo apt remove --purge python3-yaml
python3 -m pip install --no-cache-dir PyYAML

no module named aptpkg 에러 수정

sudo apt-get install python3-apt --reinstall
cd /usr/lib/python3/dist-packages
cp apt_pkg.cpython-[35m]-x86_64-linux-gnu.so apt_pkg.so

conan 재설치

python3 -m pip install --upgrade --no-cache-dir conan

root@ubuntu:~/opencv# conan --version
Migration: Successfully updated settings.yml
Conan version 2.15.0
root@ubuntu:~/opencv# conan --version
Conan version 2.15.0
root@ubuntu:~/opencv#

opencv 설치확인

  • GLIBCXX_3.4.30 심볼이 없는것을 확인
root@ubuntu:~/.conan2/p/b/openceaa445f7da0c4/b/build/Release/lib# strings libopencv_core.so | grep ^GLIBCXX
GLIBCXX_3.4.20
GLIBCXX_3.4.17
GLIBCXX_3.4.18
GLIBCXX_3.4.11
GLIBCXX_3.4.9
GLIBCXX_3.4.14
GLIBCXX_3.4.19
GLIBCXX_3.4
root@ubuntu:~/.conan2/p/b/openceaa445f7da0c4/b/build/Release/lib# 

영상

https://asciinema.org/a/714858

테스트

링크 및 정상실행 확인

git

https://gitlab.com/feather973/opencv_armv8_porting

caveat

위 문제는 노바텍 보드에서 제공한 크로스 컴파일러를 사용하지 않아서 발생한 문제이다

conan 빌드 시 크로스 컴파일러를 쓸 경우 빌드에러가 발생할 것을 우려해서
aarch64-linux-gnu 를 썼던게 판단미스 였다.

하지만, 그 과정에서 알게된 점이 한가지 있다.

opencv 는 빌드시, 미사용 라이브러리에 대해 as-needed 옵션을 줌으로서,
의존성이 덜 걸리게 하는 옵션을 사용하고 있다.

문제는 해당기능이 ld 버전을 탄다는 점이다.

aarch64-linux-gnu-ld 버전은 아래와 같다.

  • ubuntu18 : GNU ld (GNU Binutils for Ubuntu) 2.30
  • ubuntu20 : GNU ld (GNU Binutils for Ubuntu) 2.34
  • ubuntu22 : GNU ld (GNU Binutils for Ubuntu) 2.38

ubuntu18 ld, ubuntu20 ld 는 as-needed 가 적용되어 있음에도
pthread / dl 에 대한 의존성을 제거하지 않고 있다.

root@ubuntu:~/.conan2/p/b/openc46fffbced2c04/p/lib# /root/ldd libopencv_core.so.405
 0x0000000000000001 (NEEDED)             Shared library: [libdl.so.2]
 0x0000000000000001 (NEEDED)             Shared library: [libpthread.so.0]
 0x0000000000000001 (NEEDED)             Shared library: [libm.so.6]
 0x0000000000000001 (NEEDED)             Shared library: [libstdc++.so.6]
 0x0000000000000001 (NEEDED)             Shared library: [libgcc_s.so.1]
 0x0000000000000001 (NEEDED)             Shared library: [libc.so.6]
 0x0000000000000001 (NEEDED)             Shared library: [ld-linux-aarch64.so.1]
root@ubuntu:~/.conan2/p/b/openc46fffbced2c04/p/lib#

따라서, GLIBCXX 버전문제와 별개로, as-needed 미적용으로 인한 문제로
노바텍 보드에서 실행 시점에 문제가 된다.

  • pthread / dl 은 glibc 에서 제공하는데,
  • 보드 rootfs 에 있는 glibc 에서는 해당 기능이 빠져있다.
profile
관심분야 : Filesystem, Data structure, user/kernel IPC

0개의 댓글