나는 대학에서 Linux를 약간 사용했으며 용어에 익숙합니다. 나는 종종 .NET 언어로 개발하므로 컴퓨터에 능숙하지 않습니다.
그렇긴 하지만, 나는 *nix 서클에 존재하는 "직접 컴파일"[CIY] 사고방식을 이해한다고 말할 수 없습니다. 나는 그것이 사라질 것이라는 것을 알고 있지만 여전히 때때로 그것을 듣습니다. 개발자로서 저는 컴파일러와 필요한 종속성을 설정하는 것이 어려울 수 있다는 것을 알고 있으므로 CIY 워크플로가 *nix의 접근성을 높이는 데 도움이 된다고 생각합니다.
CIY 사고방식이 부상하게 된 사회적, 기술적 요인은 무엇입니까?
답변1
간단히 말해서, *nix의 역사 대부분 동안 대안은 없었습니다. 프로그램은 소스 코드 타르볼로 배포되며 이를 사용하는 유일한 방법은 소스에서 컴파일하는 것입니다. 따라서 그것은 필요악만큼 사고 방식이 아닙니다.
즉, 하드웨어에 맞게 특별히 컴파일되고 어떤 옵션을 활성화할지 여부를 선택할 수 있으므로 직접 컴파일해야 하는 좋은 이유가 있습니다. 그렇게 하면 원하는 대로 미세하게 조정된 실행 파일을 얻을 수 있습니다. 그러나 이는 단순히 업무용 기계로 이메일을 읽는 사용자가 아니라 전문 사용자에게만 의미가 있습니다.
이제 Linux 세계에서는 주요 배포판이 수년 전에 이를 포기했습니다. 요즘에는 Gentoo처럼 컴파일을 좋아하는 사람들을 위해 설계된 배포판을 사용하지 않는 한 직접 컴파일할 필요가 거의 없습니다. 그러나 대부분의 배포판의 경우 일반 사용자는 필요한 거의 모든 것이 존재하고 배포판 저장소에 컴파일되어 있으므로 아무것도 컴파일할 필요가 없습니다.
그래서 당신이 말하는 CIY 사고방식은 기본적으로 사라졌습니다. UNIX 세계에는 여전히 존재할 가능성이 높습니다. 저는 거기에 대한 경험이 없습니다. 그러나 Linux에서는 괜찮은 저장소가 있는 인기 있는 배포판을 사용한다면 아무것도 직접 컴파일할 필요가 거의 없습니다.
답변2
이러한 사고방식에는 최종 사용자, 배포 관리자, 코드 공급업체/개발자/프로젝트 팀을 포함하여 여러 가지 이유가 있으며 각각은 완전히 타당합니다.
오픈 소스
어떤 사람들은 자신이 자유 소프트웨어를 사용하고 있다는 사실을 알고 소스에서 컴파일하도록 선택하여 이를 확인하고 싶어합니다. 여기가 Linux From Scratch 프로젝트/howto/guide/book과 같은 콘텐츠가 들어오는 곳입니다.
최적화 및 옵션
특정 CPU 아키텍처에 대한 특정 최적화로 컴파일된 것을 원하십니까? 필요한 특정 기능을 활성화하거나 비활성화하는 컴파일 타임 옵션(또는 패치 생성)이 있을 수 있습니다. 이에 대한 예로는 할당량을 관리할 수 있도록 postfix를 패치하거나 systemd를 사용하지 않기로 선택한 Gentoo와 같은 배포판을 사용하거나 라이센스 때문에 mp3 파이프 대신 ogg/theora/vorbis/whatever를 지원하기로 특별히 선택한 경우가 있습니다. 문제 그 사람에 관해서는.
CPU 아키텍처
귀하의 직장에서는 x86/amd64가 아닌 고급 시스템을 사용합니까? 실행 중인 배포판은 물론, 필요하거나 원하는 패키지가 CPU 아키텍처에 맞게 사전 컴파일되지 않을 수도 있습니다. 물론 이러한 하드웨어를 실행하는 대부분의 장소는 IBM 등에서도 지원되며 아무렇게나 설치/컴파일하지 않습니다. 하지만 잉여 세일로 하나 사거나, PPC 프로세서 등을 탑재한 오래된 아이맥을 파헤친다면 어떻게 될까요?
분포
Distro "패밀리"(즉, Ubuntu, Mint 등의 Debian과 CentOS, Whitebox, Fedora 등의 RedHat)는 모두 서로 다른 패키지 형식을 사용합니다. 각 버전에는 서로 다른 라이브러리 버전 등이 함께 제공됩니다. 간단한 단일 파일 셸 스크립트의 경우에도 올바른 Debian .deb 파일을 설정하려면 시간과 노력이 필요합니다. 어떤 문제를 해결하기 위해 소프트웨어를 작성하고 이를 무료로 만들어 gitlab, 자신의 웹 서버 등에 게시하고 싶다면 빌드 지침과 함께 일반 .tar.gz 소스 파일을 게시하시겠습니까? 두 가지 버전의 Debian(안정 버전과 베타, 아마도 이전 안정 버전), RPM으로 Redhat과 Fedora의 여러 버전, Slackware의 TGZ, Gentoo의 ebuild 구성 파일 등을 패키징할 의향이 있습니다.
답변3
@terdon이 말했듯이 요즘에는 특히 가정 사용자의 경우 항목을 컴파일해야 할 필요성이 매우 적습니다.
과거 Unix 세계에서는 예를 들어 Solaris, AIX, Ultrix, Digital Ultrix 및 HP/UX 시스템을 관리할 때 컴파일된 소스에 크게 의존했는데, 이러한 시스템은 때때로 공급업체에서 더 이상 유지 관리하지 않거나 훨씬 적은 수로 구현되었습니다. 일반적인 서비스는 Linux를 포함한 다른 Unix 시스템에서 일반적으로 사용되는 서비스보다 훨씬 뒤떨어집니다.
저장소에 없는 좀 더 모호하거나 오래된 소프트웨어를 구하거나, 호환되는 바이너리가 없는 최신 버전의 패키지를 사용하거나, 작성할 수 있을 때 컴파일해야 할 것들이 여전히 있습니다. 패치 또는 모듈의 경우 추가 기능을 추가하거나 약간의 기능을 추가하고 싶습니다.
운영 체제에서 더 이상 프레임워크를 지원하지 않는 Debian 및/또는 새 버전의 Debian으로 포팅하기 위해 시스템을 재설계할 때 소프트웨어도 수동으로 컴파일해야 합니다.
예를 들어, 과거에는 프로토콜에 대한 Windows 변경 사항을 지원하거나 통신 도메인 구성에 대한 특정 패치를 지원하기 위해 DHCP 데몬을 수동으로 컴파일해야 했습니다.
저는 여전히 dev git 저장소에서 컴파일된 내 FreeRadius 버전의 debs를 로컬 저장소에 보관하고 있습니다. 왜냐하면 데비안에는 다양한 안정 릴리스에 대한 (심각한) 버그가 있고 일반적으로 Debian/Ubuntu에 해당하는 .debs는 없기 때문입니다. 우리의 필요에 맞게 충분히 출시되었습니다.
때로는 우리가 직접 작성한 내용을 실행/컴파일해야 하는 경우도 있다는 것은 말할 필요도 없습니다.
종속성을 설치하는 것은 예전만큼 어렵지 않으며 일부 소프트웨어에는 일부 일반적인 Linux 배포판에 대한 사용자 정의 규칙 파일이 있어 컴파일할 종속성의 이름을 지정하고 내장된 종속성 목록을 사용하여 패키지 파일을 생성하는 무거운 작업을 수행합니다. 로컬 저장소에서 이러한 패키지를 설치하는 것은 공식 저장소에서 동일한 패키지를 설치하는 것과 크게 다르지 않습니다.
답변4
사회적, 기술적 요인은 무엇인가상승을 일으켰다CIY 사고방식?
근본 원인은 분명히 기술적입니다. 바이너리 이식성은 소스 코드 이식성보다 어렵습니다.. 배포 패키지 외에 대부분의 무료 소프트웨어는 여전히 소스 코드 형식으로만 제공됩니다. 이는 작성자/유지관리자에게 훨씬 더 편리하기 때문입니다.
Linux 배포판이 일반 사람들이 사용하고 싶어하는 대부분의 항목을 패키징하기 전에는 유일한 옵션은 소스 코드를 구하여 자신의 시스템에 맞게 컴파일하는 것이었습니다. 상업용 Unix 공급업체는 일반적으로 거의 모든 사람이 원하는 것(예: bash
GNU 또는 이와 유사한 멋진 쉘)을 포함하지 않고 자체 sh
구현 만 csh
포함하며 시스템 관리자로서 이를 원한다면 직접 구축해야 합니다. stuff는 사용자에게 대화형 사용을 위한 멋진 Unix 환경을 제공합니다.
현재 상황은 대부분의 사람들이 데스크톱에 앉아 있는 유일한 관리자이자 컴퓨터의 유일한 사용자라는 것입니다. 이는 전통적인 Unix 모델과 매우 다릅니다. 시스템 관리자는 모든 사람의 데스크탑에 있는 중앙 시스템과 소프트웨어를 유지 관리합니다. (일반적으로 NFS /opt
와 /usr/local/
중앙 서버를 통해 사람들의 워크스테이션을 마운트 하고 거기에 설치합니다.)
.NET 및 Java가 출현하기 전에는 다양한 CPU 아키텍처 간의 진정한 바이너리 이식이 불가능했습니다. 이러한 이유로 Unix 문화는 소스 코드 이식성을 기본값으로 설정하도록 발전했으며 LSB와 같은 최근 Linux 노력이 있기 전까지는 바이너리 이식성을 활성화하려는 시도조차 거의 하지 않았습니다. 예를 들어,POSIX(이것주요 Unix 표준)은 최신 버전에서도 소스 코드 이식성을 표준화하려고 시도합니다.
관련 문화적 요인: 초기 상용 AT&T Unix는 소스 코드(테이프에 포함)와 함께 제공되었습니다. 너는 ..하지 않았다가지다소스에서 시스템을 구축하는 경우, 어떤 것이 어떻게 보이는지 확인하려는 경우에 적합합니다.진짜문서가 충분하지 않을 때 작동합니다.
"Unix의 광범위한 온라인 문서와 (수년에 걸쳐) 모든 시스템 소스 코드에 즉시 액세스할 수 있는 정책은 프로그래머의 기대를 높이고 1983년 자유 소프트웨어 운동의 시작에 기여했습니다."
고객에게 상용 소프트웨어의 소스 코드에 대한 액세스 권한을 제공하는 것은 요즘 들어 본 적이 없는 일이기 때문에 이러한 결정을 내리게 된 동기가 무엇인지 잘 모르겠습니다. 분명히 이 방향에 대한 초기 문화적 편견이 있었지만 아마도 이는 어셈블리 언어가 아닌 C로 주로 작성되고 다른 하드웨어용으로 컴파일될 수 있는 이식 가능한 운영 체제인 Unix의 뿌리에서 비롯되었을 것입니다. 초기 운영 체제의 대부분은 asm으로 작성된 CPU 관련 코드였기 때문에 소스 코드 수준 이식성은 초기 Unix의 강점 중 하나였습니다. (제가 틀렸을 수도 있습니다. 저는 초기 Unix 전문가는 아니지만 Unix와 C는 관련이 있습니다.)
소스 코드 형식으로 소프트웨어를 배포하는 것은 사람들이 실행하려는 시스템에 소프트웨어를 적용할 수 있는 가장 쉬운 방법입니다. (최종 사용자 또는 Linux 배포판으로 패키지하는 사람) 소프트웨어가 배포판에 의해/배포용으로 패키지된 경우 최종 사용자는 이를 직접 사용할 수 있습니다.
그러나 대부분의 패키지 작성자가 가능한 모든 시스템에 대해 자체 바이너리를 만들 것이라고 기대하는 것은 너무 많은 것입니다. 일부 주요 프로젝트에서는 일반적인 경우에 대한 바이너리를 제공합니다(특히 OS가 빌드 환경과 함께 제공되지 않고 OS 공급업체가 바이너리 설치 프로그램 배포에만 중점을 두는 x86/windows).
작성자가 사용하는 시스템이 아닌 다른 시스템에서 소프트웨어를 실행하려면 약간의 변경이 필요할 수도 있습니다. 이는 소스 코드를 사용하면 쉽습니다.. 누군가 자신의 가려움증을 해결하기 위해 작성한 작은 일회성 프로그램은 아마도 대부분의 알려지지 않은 시스템에서 테스트된 적이 없을 것입니다. 소스 코드가 있으면 이러한 변경이 가능합니다. 원저자가 뭔가를 간과했을 수도 있고, 시간을 많이 절약할 수 있다는 이유로 의도적으로 이식성이 떨어지는 코드를 작성했을 수도 있습니다. 이와 같은 주요 패키지조차도정보 우편번호모든 플랫폼에 바로 테스터가 있는 것은 아니며 사람들은 문제를 발견하면 이식성 패치를 보내야 합니다.
(단순히 빌드 환경의 차이로 인해 발생하며 여기서의 문제와 실제로 관련이 없는 다른 종류의 소스 수준 이식성 문제가 있습니다. Java 스타일 바이너리 이식성, 자동 도구(autoconf
/ auto-make
) 및 이와 유사한 것은 cmake
필요하지 않습니다. 우리 이런 일은 없을 거에요<netinet/in.h>
대신 일부 시스템에는 다음이 포함되어야 합니다 .<arpa/inet.h>
~을 위한ntohl(3)
. ( ntohl()
애초에 다른 바이트 순서 항목이 없을 수도 있습니다!)
나는 종종 .NET 언어로 개발하므로 컴퓨터에 능숙하지 않습니다.
한 번 컴파일하고 어디서나 실행하는 것은 .NET 및 Java의 주요 목표 중 하나이므로 이렇게 말하는 것이 타당합니다.이 문제를 해결하기 위해 모든 언어가 발명되었습니다, 귀하의 개발 경험도 그중 하나입니다. .NET을 사용하면 바이너리가 다음에서 실행될 수 있습니다.휴대용 런타임 환경(CLR). Java는 런타임 환경을 호출합니다.자바 가상 머신. 모든 시스템(적어도 JVM 또는 CLR을 구현한 모든 시스템)에서 실행할 수 있는 바이너리를 배포하기만 하면 됩니다. 물론 경로 구분 기호 /
, \
인쇄 방법 또는 GUI 레이아웃 세부 정보와 같은 이식성 문제가 여전히 발생할 수 있습니다.
많은 소프트웨어가 다음 언어로 작성되었습니다.네이티브 코드로 완전히 컴파일됨. Java 바이트코드 는 없으며 .net
이를 실행하는 CPU의 기본 기계어 코드만 이식 가능하지 않은 실행 파일 형식으로 저장됩니다. C와 C++는 특히 Unix 세계에서 대표적인 예입니다. 분명히 이것은 의미바이너리는 특정 CPU 아키텍처에 맞게 컴파일되어야 합니다.
라이브러리 버전은 또 다른 문제입니다. 라이브러리는 소스 수준 API를 안정적으로 유지하면서 바이너리 수준 ABI를 변경할 수 있고 종종 변경합니다. (바라보다API와 ABI의 차이점. ) 예를 들어 불투명 구조에 다른 멤버를 추가하면 struct
크기가 계속 변경되며 동적(malloc), 정적(전역) 여부에 관계없이 해당 구조에 공간을 할당하는 모든 코드에 대해 새 라이브러리 버전의 헤더를 다시 컴파일해야 합니다. ) 또는 자동(스택의 로컬)입니다.
운영체제도 중요해요. 동일한 CPU 아키텍처의 경우 Unix의 종류에 따라 바이너리 파일 형식, 시스템 호출을 위한 ABI, 상수 값이 다를 수 있습니다.fopen(3)
의 O_RDONLY
, O_APPEND
,O_TRUNC
.
동적으로 링크된 바이너리라도 main()
Windows에서는 여전히 일부를 가지고 있습니다.crt0
. Unix와 Linux는 일부 C 런타임 시작 코드가 각 바이너리에 정적으로 연결되어 있다는 점에서 동일합니다. 이론적으로는 코드가 동적으로 링크되고 libc나 동적 링커 자체의 일부가 되는 시스템을 설계할 수 있을 것 같지만, 제가 아는 운영 체제에서는 실제로 작동하는 방식이 아닙니다. 이는 표준 라이브러리 함수 상수의 수치 문제가 아닌 시스템 호출 ABI 문제만 해결합니다. (보통 시스템 호출은 libc 래퍼 함수를 통해 이루어집니다. 사용되는 일반 x86-64 Linux 바이너리에는 이 명령어가 mmap()
포함되어 있지 않으며 동일한 이름의 libc 래퍼 함수에 대한 명령어만 포함되어 있습니다.syscall
call
이것이 i386-FreeBSD 바이너리가 i386-Linux에서 실행될 수 없는 이유 중 하나입니다. (한동안 리눅스 커널에는 시스템 호출 호환성 계층이 있었습니다. 비슷한 호환성 계층을 가진 Linux 바이너리를 실행할 수 있는 BSD가 적어도 하나는 있었던 것 같지만 당연히 Linux 라이브러리가 필요했습니다.)
바이너리를 배포하려면 CPU/OS-flavor+version/installed-library-versions 조합마다 별도의 바이너리를 만들어야 합니다..
1980년대/90년대 초에는 Unix 시스템(MIPS, SPARC, POWER, PA-RISC, m68k 등)에서 일반적으로 사용되는 다양한 유형의 CPU와 다양한 Unix 버전(IRIX, SunOS, Solaris)이 있었습니다. , AIX, HP-UX, BSD 등).
그건 그냥유닉스체계. 많은 소스 코드 패키지를 컴파일하고 실행할 수도 있습니다.다른VAX/VMS, MacOS(m68k 및 PPC), Amiga, PC/MS-DOS, Atari ST 등과 같은 시스템
오늘날 대부분의 데스크톱은 세 가지 주요 운영 체제 중 하나를 실행하는 x86이지만 여전히 많은 CPU 아키텍처와 운영 체제가 있습니다.
따라서 시스템마다 버전이 다를 수 있는 타사 라이브러리에 대한 종속성을 생각하기 전에도 CPU/OS 조합의 수가 압도적입니다. (운영 체제 공급업체에서 패키지하지 않은 항목은 수동으로 설치해야 합니다.)
바이너리로 컴파일된 모든 경로는 시스템마다 다릅니다. (이렇게 하면 시작 시 구성 파일에서 RAM을 읽는 것에 비해 RAM과 시간이 절약됩니다.) 이전 Unix 시스템에는 일반적으로많은손으로 직접 맞춤 제작한 것이므로 무엇이 어디로 가는지에 대해 유효한 가정을 할 수 없습니다.
모든 주요 조합에서 구축하고 테스트할 수 있는 대규모 상용 프로젝트를 제외하고 바이너리 배포는 기존 Unix에서는 완전히 실행 불가능합니다..
단지 목적으로 i386-linux-gnu
바이너리를 만드는 것 조차 amd64-linux-gnu
어렵습니다. 다음과 같은 일에 많은 시간과 에너지를 소비합니다.리눅스 표준 라이브러리휴대용 바이너리를 가능하게 만들기. 바이너리를 정적으로 연결한다고 해서 모든 문제가 해결되는 것은 아닙니다. (예를 들어, RedHat 시스템과 Debian 시스템에서 워드 프로세싱 프로그램은 어떻게 인쇄해야 합니까? 설치 시 어떻게 사용자 또는 그룹을 데몬에 추가하고 재부팅할 때마다 시작 스크립트가 실행되도록 예약해야 합니까?) 이는 좋은 예가 아닙니다. 소스에서 다시 컴파일해도 이러한 문제가 해결되지 않습니다.
게다가 그때의 추억은 지금보다 훨씬 더 소중해요. 컴파일 타임에 선택적 기능 생략더 작은 바이너리를 생성할 수 있으며(더 작은 코드 크기) 해당 데이터 구조도 더 적은 메모리를 사용합니다. 기능에 추가 멤버가 필요 class
하거나 특정 인스턴스의 모든 인스턴스에서 무언가를 추적하는 struct
경우 해당 기능을 비활성화하면 객체가 프로그래밍 방식으로 100,000개 객체에 할당된 경우(예를 들어) 객체가 4바이트만큼 줄어들지만 괜찮습니다.
오늘날 선택적 컴파일 시간 기능은 추가 라이브러리를 선택적으로 만드는 데 가장 일반적으로 사용됩니다. 예를 들어, 특정 비디오/오디오 인코더, 자막 처리 등에 대한 , , 및 기타 여러 라이브러리를 포함 하거나 ffmpeg
포함하지 않고 컴파일할 수 있습니다. 보다 일반적으로는 많은 항목을 포함하거나 포함하지 않고 컴파일할 수 있습니다 . 런타임을 사용할 수 있는 경우 결과 바이너리는 라이브러리에 따라 달라지며 터미널에서 읽을 때 아름다운 줄 편집을 제공합니다. 그렇지 않은 경우 프로그램은 일부 대체 지원을 사용하여 표준 입력에서 행이나 내용을 읽습니다 . )libx264
libx265
libvorbis
libreadline
./configure
fgets()
성능상의 이유로 일부 프로젝트에서는 여전히 선택적 기능을 사용하여 불필요한 코드를 생략합니다. 예를 들어, Linux 커널 자체는 SMP 지원 없이 구축될 수 있습니다(예: 임베디드 시스템 또는 오래된 데스크탑의 경우). 이 경우 많은 잠금이 더 간단합니다. 또는많은드라이버나 기타 하드웨어 기능을 무시하는 것이 아니라 일부 핵심 코드에 영향을 미치는 기타 선택적 기능입니다. (아키텍처별 및 하드웨어별 구성 옵션이많은전체 소스 코드. 바라보다Linux 커널에 1,500만 줄 이상의 코드가 있는 이유는 무엇입니까?)