Nodejs가 다양한 Linux 배포판 간에 겉보기에 바이너리 호환성을 달성하는 방법

Nodejs가 다양한 Linux 배포판 간에 겉보기에 바이너리 호환성을 달성하는 방법

다운로드 사이트에 방문하시면노드 js(다른 파일 중에서) 라는 파일이 Linux Binaries (x64)포함된 tar 아카이브를 선택할 수 있습니다 .bin/nodejs

Nodejs가 실행될 수 있다고 알려진(또는 나타나는) "범용" 바이너리를 제공하는 방법어느리눅스 배포판? 나는 그들이 그들의 웹사이트에 그러한 진술을 하지 않는다는 것을 알고 있지만 특정 OS 버전(예: Ubuntu, Debian 등의 Nodejs)이 없기 때문에 그것이 내가 가정하는 것입니다.

이 주제(Linux 배포판 간의 바이너리 호환성)를 읽는 동안 기본적으로 이것이 실제로는 아니라는 여러 답변을 발견했습니다.

아니요, Debian과 Ubuntu는 바이너리와 호환되지 않습니다. 데비안과 우분투는 서로 다른 ABI, 서로 다른 커널 버전, 서로 다른 라이브러리, 서로 다른 패키지/버전 등을 갖춘 서로 다른 컴파일러를 사용할 수 있습니다. 모든 Ubuntu 패키지가 Debian에 있는 것은 아니며(그 반대도 마찬가지이므로) deb 패키지도 제거 가능한 버전에 따라 달라질 수 있습니다.

...

따라서 기술적으로 바이너리와 호환되지 않습니다.

답변질문 "Ubuntu LTS 바이너리는 Debian과 호환되나요?"

알겠어요일부부분에 대해ABI아키텍처, 호출 규칙, 시스템 호출 등과 같은 것들은 동일한 아키텍처와 호출 규칙이 사용된다면 어느 정도 호환성이 있을 것이라는 것이 제 생각에는 이해가 됩니다. 왜냐하면 모든 Linux 배포판의 핵심은 Linux 커널이기 때문입니다.

하지만 여전히 이해하기 어렵습니다.사람들은 두 개의 Linux 배포판이 바이너리와 호환되지 않는다고 말합니다.

무엇그거 호환 안되는데요?

NodeJS가 "모든" Linux 배포판에 대해 하나의 바이너리 버전만 제공하는 것처럼 보이는 이유는 무엇입니까?

이것은 "바이너리 X를 배포판 x, y 및 z와 호환되게 만드는 방법"보다 교육적인 질문에 가깝습니다.

답변1

ABI(Application Binary Interface)에는 여러 수준이 있습니다. 어디에서나 작동하는 바이너리를 만들려면 다음 수준 중 하나를 대상으로 해야 합니다. 대상으로 하는 두 가지 수준은 커널 ABI 또는 LSB ABI입니다.

.deb 패키지는 데비안과 우분투 사이에서 호환되지 않을 수 있습니다. 왜냐하면 한 가지 또는 다른 것에 의존할 수 있지만 동시에 두 가지 모두에 의존할 수는 없기 때문입니다. 그러나 많은 .deb 패키지는 일부 Ubuntu 및 Debian 버전에서 실행됩니다. 설상가상으로 RedHat rpm은 패키징 형식을 이해할 수 없기 때문에 Ubuntu 시스템에서 실행될 가능성이 없습니다.

종속성은 실행 파일이 다른 Linux 버전에서 실행되는 것을 방지합니다. 거의 모든 프로그램은 외부 라이브러리에 의존합니다. 실행 파일을 빌드할 때 Linux(및 Windows 및 기타 UNIX를 포함한 다른 많은 운영 체제)는 이러한 외부 라이브러리를 실행 파일의 일부로 포함하지 않고 스텁에만 링크하며 실제 라이브러리는 많은 실행 파일에 포함되지 않습니다. 실행 파일 간 공유. 이렇게 하면 디스크와 메모리의 실행 파일 크기가 줄어들고 경우에 따라 실행 파일을 다시 빌드하지 않고도 라이브러리의 버그를 수정할 수 있습니다. 그러나 Linux 버전에 올바른 버전의 공유 라이브러리가 없으면 실행 파일이 작동하지 않습니다.

공유 라이브러리를 사용하는 실행 파일은 동적으로 연결된다고 합니다. 즉, 공유 라이브러리에 대한 최종 연결이 런타임에 동적으로 수행된다는 의미입니다. 실행 파일을 정적으로 링크하는 것도 가능합니다. 그 결과 더 큰 실행 파일이 생성되지만 더 넓은 범위의 시스템에서 실행될 수 있습니다. 그 시점에서 ABI는 더 이상 Linux 버전이 아니라 커널 자체입니다. 일반적으로 커널은 이전 버전과 호환되고 실행 파일은 이후 버전과 호환됩니다. 즉(일부 광범위한 커널 버전 내에서) 이전 실행 파일은 최신 커널에서 실행되고 최신 커널은 이전 실행 파일을 실행할 수 있습니다. 실행 파일 형식 자체는 Linux 역사상 거의 변경되지 않았으므로 제한적입니다.

운영 체제를 실행하는 CPU의 아키텍처도 몇 가지 예외를 제외하고 실행 파일과 일치해야 합니다. (일반적으로 관련 일치 라이브러리가 있는 경우 i386 바이너리는 x86_64 시스템에서 실행될 수 있습니다.) 여러 CPU 아키텍처에 대한 코드를 포함하는 팻 바이너리를 만드는 것이 가능합니다. 이는 일부 운영 체제에서는 일반적이지만 Linux에서는 드뭅니다.

컨테이너화된 실행 파일도 있을 수 있습니다. 이 경우 거북이와 마찬가지로 실행 파일은 파일 시스템(예: squashfs)에 내장되어 있으며 모든 종속 라이브러리와 지원 파일을 바이너리 내에서 별도의 파일로 전달합니다. 이것이 appimage가 하는 일입니다.

file위에서 언급한 것처럼 명령은 ldd때때로 바이너리가 어떻게 빌드되었는지 알려줄 수 있습니다. 예를 들어:

$ file /bin/ls
/bin/ls: ELF 64-bit LSB pie executable, x86-64, version 1 (SYSV), dynamically linked, interpreter /lib64/ld-linux-x86-64.so.2, BuildID[sha1]=897f49cafa98c11d63e619e7e40352f855249c13, for GNU/Linux 3.2.0, stripped
$ ldd /bin/ls
    linux-vdso.so.1 (0x00007fff95ae1000)
    libselinux.so.1 => /lib/x86_64-linux-gnu/libselinux.so.1 (0x00007fc6aebb8000)
    libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007fc6ae990000)
    libpcre2-8.so.0 => /lib/x86_64-linux-gnu/libpcre2-8.so.0 (0x00007fc6ae8f9000)
    /lib64/ld-linux-x86-64.so.2 (0x00007fc6aec50000)

이 바이너리는 x86_64 아키텍처용이며 동적 링커 버전 2에 동적으로 연결되며 위에 나열된 다양한 공유 라이브러리의 특정 버전이 필요합니다...(참고: 주 버전은 일치해야 하며 부 버전은 위에 나열되지도 않습니다.)

이것을 다음과 비교해보세요:

$ file /bin/busybox
/bin/busybox: ELF 64-bit LSB executable, x86-64, version 1 (GNU/Linux), statically linked, BuildID[sha1]=36c64fc4707a00db11657009501f026401385933, for GNU/Linux 3.2.0, stripped
$ ldd /bin/busybox
    not a dynamic executable

이 정적으로 링크된 바이너리는 x86_64 ELF 버전 1을 지원하는 모든 Linux 커널에서 실행됩니다.

$ file prusaslicer.AppImage
prusaslicer.AppImage: ELF 64-bit LSB executable, x86-64, version 1 (SYSV), dynamically linked, interpreter /lib64/ld-linux-x86-64.so.2, for GNU/Linux 2.6.18, stripped
$ ldd prusaslicer.AppImage
    not a dynamic executable

이는 동적으로 링크된 실행 파일처럼 보이지만 동적 링커 자체 이외의 공유 라이브러리 종속성은 없습니다. 이는 실제로 컨테이너화된 실행 파일이며 실행 시 내부 파일 시스템을 마운트하고 내부에서 실제 실행 파일을 실행합니다. (실행하지 않고) 유일한 단서는 파일 이름(및 크기)입니다. 이를 실행한 후 Fuse가 마운트된 파일 시스템을 검사할 수 있지만 이는 다소 숨겨져 있습니다.

질문하신 구체적인 예를 살펴보면... node.js의 x86_64 Linux 버전을 다운로드하고 다음을 발견했습니다.

$ file bin/node 
bin/node: ELF 64-bit LSB executable, x86-64, version 1 (GNU/Linux), dynamically linked, interpreter /lib64/ld-linux-x86-64.so.2, for GNU/Linux 2.6.32, BuildID[sha1]=e8b23b15ec6280a0d4838fbba1171cb8d94667c5, with debug_info, not stripped
$ ldd bin/node
    linux-vdso.so.1 (0x00007ffd633f0000)
    libdl.so.2 => /lib/x86_64-linux-gnu/libdl.so.2 (0x00007efec3198000)
    libstdc++.so.6 => /lib/x86_64-linux-gnu/libstdc++.so.6 (0x00007efec2f6c000)
    libm.so.6 => /lib/x86_64-linux-gnu/libm.so.6 (0x00007efec2e85000)
    libgcc_s.so.1 => /lib/x86_64-linux-gnu/libgcc_s.so.1 (0x00007efec2e65000)
    libpthread.so.0 => /lib/x86_64-linux-gnu/libpthread.so.0 (0x00007efec2e60000)
    libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007efec2c36000)
    /lib64/ld-linux-x86-64.so.2 (0x00007efec31e5000)

따라서 상당한 수의 외부 공유 라이브러리 종속성을 가진 동적으로 링크된 실행 파일로서 실행할 수 있는 시스템이 제한되지만 해당 특정 라이브러리를 포함하거나 설치할 수 있는 버전의 범위는 상당히 넓을 수 있습니다. 이는 대부분의 Linux 시스템에 있어야 하는 기본 라이브러리이며 다양한 운영 체제 버전에 이러한 라이브러리의 버전이 있을 정도로 안정적입니다. 때로는 그 중 일부가 누락된 경우 Linux 버전에 적합한 lsb-base 또는 lsb-core 패키지를 설치하면 사용할 수 있습니다. LSB(Linux Standard Base)는 타사 개발자에게 공통 목표를 제공하려는 모든 Linux 배포판의 최소 공통 분모가 되는 기본 표준 라이브러리 및 기타 프로젝트 집합을 포함하는 ABI 표준입니다.

실행되지는 않지만 실행되어야 한다고 말하는 실행 파일이 있는 경우 위와 같은 검색 작업을 수행하여 시스템에 누락된 항목을 확인하고 누락된 라이브러리를 설치할 수 있습니다.

관련 정보