리눅스에서“컴파일 스스로”정신의 근원은 무엇인가? 이 질문은 의견 기반

나는 대학에서 리눅스를 조금 사용했고 그 용어에 익숙하다. .NET 언어로 정기적으로 개발하므로 컴퓨터를 잘 모르는 사람이 아닙니다.

즉, 나는 * nix 서클에 존재하는 “직접 컴파일”[CIY] 사고 방식을 이해한다고 말할 수 없습니다. 나는 그것이 사라지는 것을 알고 있지만 때때로 그것을 듣습니다. 개발자는 컴파일러와 필요한 종속성을 설정하는 것이 쉽지 않다는 것을 알고 있습니다. 따라서 CIY 작업 흐름이 * nix의 액세스 가능성을 크게 낮추는 데 도움이 된 것 같습니다.

어떤 사회적 또는 기술적 요인으로 인해 CIY 사고가 증가 했습니까?



답변

간단히 말해서 * nix의 많은 역사에서 다른 선택은 없었습니다. 프로그램은 소스 타르볼로 배포되었으며이를 사용하는 유일한 방법은 소스에서 컴파일하는 것입니다. 그러므로 그것은 필요한 악만큼 정신이 아닙니다.

즉, 하드웨어를 위해 특별히 컴파일되기 때문에 직접 컴파일 해야하는 매우 좋은 이유가 있습니다. 활성화 할 옵션을 선택할 수 있으므로 원하는 방식으로 미세 조정 된 실행 파일로 끝날 수 있습니다 . 그러나 이는 분명히 전문 사용자에게는 의미가 있으며, 작업중인 컴퓨터에서 전자 메일을 읽기를 원하는 사람들에게는 적합하지 않습니다.

이제 Linux 세계에서 주요 배포판은 수년 전에 이로부터 멀어졌습니다. 젠투와 같이 이것을 좋아하는 사람들을 위해 특별히 고안된 배포판을 사용하지 않는 한, 요즘에는 아무것도 컴파일 할 필요가 없습니다. 그러나 대부분의 배포판의 경우 일반 사용자는 배포 저장소에 필요한 거의 모든 것이 존재하고 컴파일되므로 컴파일 할 필요가 없습니다.

따라서이 CIY 사고 방식은 본질적으로 사라졌습니다. 유닉스 세계에서는 여전히 살아 있고 발길질은 있지만 경험이 없지만 Linux에서는 적절한 저장소로 인기있는 배포판을 사용하는 경우 직접 컴파일 할 필요가 거의 없습니다.


답변

최종 사용자, 배포 관리자 및 코드 공급 업체 / 개발자 / 프로젝트 그룹에서 이러한 사고 방식에 대한 몇 가지 원인이 있으며 이들 각각은 완벽하게 유효합니다.

오픈 소스 측면

자유 소프트웨어를 사용하고 있다는 사실을 알고 소스에서 컴파일하도록 선택하여 검증하는 사람들이 있습니다. Linux From Scratch 프로젝트 / 하우투 / 가이드 / 북과 같은 것들이 들어옵니다.

최적화 및 옵션 측면

특정 CPU 아키텍처에 맞게 특정 최적화로 자료를 컴파일하고 싶습니까? 필요한 특정 기능을 활성화 또는 비활성화하기위한 컴파일 시간 옵션 (또는 패치를 만들기위한 패치)이있을 수 있습니다. 예를 들어 할당량을 관리 할 수있는 postfix 패치 또는 systemd를 사용하지 않도록 선택할 수있는 Gentoo와 같은 배포판을 사용하거나 라이센스 문제로 인해 ogg / theora / vorbis / whatever 및 NOT mp3를 지원하도록 특별히 선택할 수 있습니다. 또는 무엇이든.

CPU 아키텍처 측면

직장에서 x86 / amd64 이외의 고급 컴퓨터를 사용합니까? 필요한 / 원치 않는 패키지는 CPU 아키텍처를 위해 사전 컴파일 된 상태로 제공되지 않을 수 있습니다. 물론, 이런 종류의 하드웨어를 실행하는 대부분의 장소는 IBM 등의 지원을 받고 있으며 설치 / 컴파일을하지 않을 것입니다. 그러나 잉여 판매 중 하나를 선택하고 기존 iMac w / PPC 프로세서 등을 파는 경우 어떻게해야합니까?

배포 측면

배포판 “가족”-즉, 데비안 w / 우분투, 민트, 등 및 RedHat with CentOS, 화이트 박스, 페도라 등-는 모두 다른 패키지 형식을 사용합니다. 각 버전에는 다른 라이브러리 버전 등이 함께 제공됩니다. 간단한 단일 파일 쉘 스크립트의 경우에도 적절한 데비안 .deb 파일을 설정하는 데 시간과 노력이 필요합니다. 가려운 부분을 긁을 수있는 소프트웨어를 작성하고 무료로 만들고 자신의 웹 서버 인 gitlab에 게시하려는 경우 오히려 빌드에 대한 지침이있는 소스의 일반 .tar.gz 파일을 게시하겠습니까? 데비안 2 가지 버전 (안정적이고 테스트, 아마도 구식)을위한 버전, RPM으로 여러 버전의 Redhat과 Fedora, 슬랙웨어를위한 TGZ, 젠투를위한 ebuild 프로파일 등.


답변

@terdon이 말했듯이 요즘에는 특히 가정용 사용자의 경우 컴파일해야 할 필요성이 상당히 적습니다.

과거에는 유닉스 세계에서 벤더가 때때로 더 이상 유지 관리하지 않는 Solaris, AIX, Ultrix, Digital Ultrix 및 HP / UX 시스템을 관리하거나 구현하는 경우와 같이 컴파일 소스에 크게 의존했습니다. 일반적인 서비스 중 Linux를 포함한 다른 Unix가 일반적으로 사용했던 것보다 훨씬 뒤 떨었습니다.

현재 저장소에없는 더 모호하거나 더 이상 사용되지 않는 소프트웨어를 가져 오거나 호환 가능한 바이너리가없는 패키지의 최신 버전을 사용하기 위해 현재 컴파일 할 필요가 여전히 있습니다. 패치 나 모듈을 작성할 수있는 경우 추가 기능을 추가하거나 드물게 추가하려고합니다.

또한 OS에서 더 이상 지원하지 않는 프레임 워크를 가진 데비안 및 / 또는 데비안의 새로운 버전으로 포팅하기 위해 시스템을 리엔지니어링 할 때 소프트웨어를 직접 컴파일해야했습니다.

예를 들어, 과거에는 수동으로 DHCP 데몬을 컴파일하여 프로토콜에 대한 (최근에 따른) Windows 변경을 지원하거나 통신 세계에서 프로비저닝을위한 특정 패치를 지원해야했습니다.

데비안에서 (심각한) 버그가있는 안정된 버전의 문자열이 있었고 일반적으로 데비안 / 우분투에 대한 해당 .deb는 없었기 때문에 여전히 개발자 git repo에서 직접 컴파일 한 FreeRadius 버전의 로컬 저장소 deb를 유지합니다. 우리의 필요에 적합합니다.

그리고 종종 우리는 종종 우리 자신이 작성한 것들을 실행하거나 컴파일해야한다는 것은 말할 필요도 없습니다.

오늘날 의존성을 설치하는 것은 과거처럼 어렵지 않으며, 일부 소프트웨어에는 의존성 목록을 사용하여 패키지 파일을 작성하고 컴파일하는 의존성을 명명하는 공통 Linux 배포판에 대한 사용자 지정 규칙 파일도 있습니다. 로컬 리포지토리에서 이러한 패키지를 설치하는 것은 공식 리포지토리에서 동일한 패키지를 설치하는 것과 크게 다르지 않습니다.


답변

어떤 사회적 또는 기술적 요인으로 인해 CIY 사고 가 증가 했습니까?

근본 원인은 분명히 기술적 이유입니다. 이진 이식성은 소스 이식보다 어렵습니다 . 배포판 패키지 이외에도 대부분의 자유 소프트웨어는 여전히 소스 형식으로 만 사용할 수 있습니다. 저작자 / 관리자에게 훨씬 편리하기 때문입니다.

리눅스 배포판이 일반 사람들이 사용하고자하는 대부분의 것들을 패키징하기 시작할 때까지 유일한 옵션은 소스를 가져 와서 자신의 시스템에 맞게 컴파일하는 것이 었습니다. 상용 유닉스 벤더들은 일반적으로 거의 모든 사람들이 원했던 것들 (예 : GNU bash나 그와 비슷한 멋진 쉘)을 포함하지 않았으며 , 자체 구현 sh및 / 또는을 포함 csh하고 있기 때문에 (sys-admin으로) 원한다면 직접 빌드해야했습니다. 대화식 사용을 위해 사용자에게 멋진 유닉스 환경을 제공합니다.

현재 대부분의 사람들이 데스크탑에있는 유일한 관리자이자 컴퓨터 사용자 인 상황은 기존 Unix 모델과 크게 다릅니다. 시스템 관리자는 중앙 시스템과 모든 사람의 데스크탑에서 소프트웨어를 유지 관리했습니다. (사람의 워크 스테이션을 NFS 마운트 /opt/usr/local/중앙 서버에서 가져 와서 설치하는 경우가 종종 있습니다.)


.NET 및 Java와 같은 이전에는 다른 CPU 아키텍처에서 진정한 이진 이식성이 불가능했습니다. 이러한 이유로 인해 Unix culture는 소스 이식성을 기본으로 발전 시켰으며 LSB와 같은 최근 Linux 노력이있을 때까지 바이너리 이식성을 활성화하려는 노력은 거의 없었습니다. 예를 들어, POSIX ( 주요 유닉스 표준)에만도 최신 버전으로, 소스 이동성을 표준화하려고 시도합니다.

관련 문화적 요인 : 초기 상용 AT & T Unix는 소스 코드 (테이프)와 함께 제공되었습니다. 당신은하지 않았다 가지고 당신이 뭔가를 어떻게보고 싶었다 경우 그냥 거기에 있었다, 소스로부터 시스템을 구축하기 위해 정말 워드 프로세서가 충분히되지 않은 경우했다.

위키 백과는 말합니다 :

“온라인 문서에 대한 광범위한 유닉스 정책과 (몇 년 동안) 모든 시스템 소스 코드에 대한 준비된 액세스는 프로그래머의 기대를 높이고 1983 년 자유 소프트웨어 운동의 시작에 기여했습니다.”

고객에게 상용 소프트웨어의 소스 코드에 대한 액세스 권한을 부여하는 것이 현재로서는 전례가 없기 때문에이 결정에 동기가 된 것이 확실하지 않습니다. 이 방향에는 초기 문화적 편견이 분명히 있지만, 아마도 다른 하드웨어 용으로 컴파일 될 수있는 C (조립 언어가 아닌)로 작성된 휴대용 OS로서 Unix의 뿌리에서 비롯된 것일 수 있습니다. 많은 초기 OS가 특정 CPU에 대해 더 많은 코드를 asm으로 작성했다고 생각하므로 소스 레벨 이식성은 초기 Unix의 강점 중 하나였습니다. (나는 이것에 대해 틀릴 수도 있습니다. 나는 초기 유닉스의 전문가는 아니지만 유닉스와 C는 관련이 있습니다.)


소스 형태의 소프트웨어 배포는 사람들이 원하는 모든 시스템에 소프트웨어를 적용 할 수있는 가장 쉬운 방법입니다. (최종 사용자 또는 Linux 배포판 용으로 패키징하는 사람). 소프트웨어가 이미 배포에 의해 / 배포 용으로 패키지 된 경우 최종 사용자는 해당 소프트웨어를 사용할 수 있습니다.

그러나 대부분의 패키지 작성자가 가능한 모든 시스템 자체에 대해 바이너리를 만들 것으로 기대하기에는 너무 많은 일입니다. 일부 주요 프로젝트는 몇 가지 일반적인 경우에 바이너리를 제공합니다 (특히 OS에 빌드 환경이 제공되지 않는 x86 / windows, OS 공급 업체는 바이너리 전용 설치 프로그램 배포에 중점을 두었습니다).

저자가 사용한 것과 다른 시스템에서 소프트웨어를 실행하려면 약간의 변경이 필요할 수 있습니다 . 누군가 자신의 가려움증을 긁기 위해 작성한 작은 일회성 프로그램은 아마도 대부분의 모호한 시스템에서 테스트 된 적이 없습니다. 소스가 있으면 그러한 변경을 수행 할 수 있습니다. 원저자는 무언가 간과했거나 시간이 많이 절약되어 이식성이 떨어지는 코드를 의도적으로 작성했을 수 있습니다. Info-ZIP 와 같은 주요 패키지조차도 모든 플랫폼에 즉시 테스터가 없었으며 문제가 발견되면 사람들이 이식성 패치를 보내야했습니다.

(단 때문에 빌드 ENV의 차이 발생, 여기에 문제가있을 수 있습니다. 자바 스타일의 진 이동성, 자동 도구 (정말 관련이없는 것으로 소스 레벨 이식성 문제의 다른 종류가있다 autoconf/ auto-make)와 같은 유사한 것 cmake같으면는 ‘t은 필요하다. 그리고처럼 우리는 일을하지 않았을 일부 시스템의 포함 요구하는 <netinet/in.h>대신<arpa/inet.h> 에를ntohl(3) . (그리고 어쩌면 우리는하지 않았을 ntohl()또는 첫 번째 장소에서 다른 바이트 순서 물건!)


.NET 언어로 정기적으로 개발하므로 컴퓨터를 잘 모르는 사람이 아닙니다.

한 번만 실행하면 어느 곳에서나 .NET 및 Java의 주요 목표 중 하나 이므로이 문제를 해결하기 위해 전체 언어가 발명되었으며 개발자 경험이 그 중 하나와 관련 있다고 말할 수 있습니다. .NET을 사용하면 바이너리가 CLR (Portable Runtime Environment)에서 실행됩니다 . Java는 런타임 환경을 Java Virtual Machine이라고 합니다. 모든 시스템 (적어도 누군가가 이미 JVM 또는 CLR을 구현 한 시스템)에서 작동하는 바이너리 하나만 배포하면됩니다. 당신은 여전히 같은 이동성 문제가있을 수 있습니다 /\경로 분리 방법 또는 인쇄, 또는 GUI는 물론, 세부 사항을 레이아웃.

많은 소프트웨어가 기본 코드로 완전히 컴파일 된 언어로 작성되었습니다 . .net이식 가능하지 않은 실행 파일 형식으로 저장된 CPU의 기본 시스템 코드는 Java 바이트 코드 가 없거나 Java 바이트 코드 가 없습니다 . C와 C ++는 특히 유닉스 세계에서 이것의 주요 예입니다. 분명히 이것은 특정 CPU 아키텍처를 위해 바이너리를 컴파일해야 함을 의미 합니다.

라이브러리 버전은 또 다른 문제 입니다. 라이브러리는 이진 수준 ABI를 변경하는 동안 소스 수준 API를 안정적으로 유지할 수 있습니다. ( API와 ABI의 차이점을 참조하십시오 .) 예를 들어, 불투명에 다른 멤버를 추가하면 struct여전히 크기가 변경되며 동적인지 여부에 관계없이 이러한 구조체에 대한 공간을 할당하는 코드에 대해 새 라이브러리 버전의 헤더로 다시 컴파일해야합니다 (malloc ), 정적 (전역) 또는 자동 (스택의 로컬).

운영 체제도 중요 합니다. 동일한 CPU 아키텍처에서 다른 유닉스 계열은 다른 이진 파일 형식, 시스템 호출을위한 다른 ABI 및 fopen(3)‘s O_RDONLY,, O_APPEND등 의O_TRUNC 상수에 대한 다른 숫자 값을 가질 수 있습니다 .

동적으로 연결된 바이너리조차도 이전에 실행되는 일부 OS 관련 시작 코드가 main()있습니다. Windows에서 이것은입니다 crt0. 유닉스와 리눅스는 같은 것이 있는데 일부 C- 런타임 스타트 업 코드는 모든 바이너리에 정적으로 링크되어 있습니다. 이론적으로 해당 코드가 동적으로 링크 된 시스템과 libc 또는 동적 링커 자체의 일부를 설계 할 수는 있지만 이것이 내가 알고있는 OS에서 실제로 작동하는 방식은 아닙니다. 표준 라이브러리 함수의 상수에 대한 숫자 값의 문제가 아니라 시스템 호출 ABI 문제 만 해결합니다. (일반적으로 시스템 호출은 libc 래퍼 함수를 ​​통해 이루어집니다. 소스를 사용하는 일반적인 x86-64 Linux 바이너리 mmap()syscall명령어를 포함하지 않습니다 .call 같은 이름의 libc 래퍼 함수에 대한 명령.

이것이 i386-Linux에서 i386-FreeBSD 바이너리를 실행할 수없는 이유의 일부입니다. (한동안 Linux 커널에는 시스템 호출 호환성 계층이있었습니다. 적어도 하나의 BSD 중 하나는 비슷한 compat 계층을 가진 Linux 바이너리를 실행할 수 있지만 물론 Linux 라이브러리가 필요하다고 생각합니다.)


바이너리를 배포하려면 CPU / OS-flavour + version / installed-library-versions의 모든 조합에 대해 별도의 바이너리를 만들어야합니다 .

80 년대 / 90 년대로 돌아가서 유닉스 시스템 (MIPS, SPARC, POWER, PA-RISC, m68k 등)에 일반적으로 사용되는 다양한 유형의 CPU와 다양한 유닉스 (IRIX, SunOS, Solaris, AIX, HP-UX, BSD 등).
그리고 그것은 유닉스 시스템 일뿐 입니다. 많은 소스 패키지는 VAX / VMS, MacOS (m68k 및 PPC), Amiga, PC / MS-DOS, Atari ST 등과 같은 다른 시스템 에서도 컴파일되고 작동합니다 .

여전히 대다수의 데스크톱이 3 개의 주요 OS 중 하나를 실행하는 x86이지만 여전히 많은 CPU 아키텍처와 OS가 있습니다.

따라서 다른 시스템의 다른 버전에있을 수있는 타사 라이브러리에 대한 종속성을 생각하기 전에도 이미 많은 CPU / OS 조합이 있습니다. (OS 벤더가 패키지하지 않은 것은 수동으로 설치해야합니다.)

바이너리로 컴파일 된 경로는 시스템마다 다릅니다. 이렇게하면 시작시 구성 파일에서 RAM을 읽는 것과 비교하여 RAM과 시간이 절약됩니다. 구식 유닉스 시스템은 일반적으로 수작업으로 사용자 정의 된 많은 것들을 가지고 있었으므로 어디에 있는지에 대한 유효한 가정을 할 수있는 방법이 없습니다.

바이너리를 배포하는 것은 모든 주요 조합에서 빌드하고 테스트 할 수있는 주요 상업 프로젝트를 제외하고는 구식 Unix에서 완전히 실현 불가능했습니다 .

심지어 단지 바이너리을 i386-linux-gnu하고 amd64-linux-gnu어렵다. 이식 가능한 바이너리를 가능하게하기 위해 Linux Standard Base 와 같은 것들에 많은 시간과 노력이 들었다 . 바이너리를 정적으로 연결한다고해서 모든 것이 해결되지는 않습니다. (예 : 워드 프로세싱 프로그램은 RedHat 시스템과 데비안 시스템에서 어떻게 인쇄해야합니까? 설치시 데몬의 사용자 나 그룹을 추가하고 재부팅 할 때마다 시작 스크립트가 실행되도록 어떻게 배치해야합니까?) 예를 들어 소스에서 다시 컴파일해도 문제가 해결되지 않습니다.


그 외에도, 당시의 기억은 지금보다 더 소중했습니다. 컴파일 타임에 선택적 기능을 사용하지 않으면 데이터 구조에 더 적은 메모리를 사용하는 더 작은 바이너리 (코드 크기가 더 작은)를 만들 수 있습니다. 기능이 특정 인스턴스의 모든 인스턴스에서 추가 멤버를 필요로 class하거나 struct무언가를 추적하는 경우 해당 기능을 비활성화하면 개체가 4 바이트 씩 축소됩니다 (예 : 프로그램이 100k를 할당하는 개체 인 경우 좋습니다).

선택적 컴파일 타임 기능은 요즘 추가 라이브러리를 선택적으로 만드는 데 가장 많이 사용됩니다. 예를 들어, 당신이 컴파일 ffmpeg또는없이 libx264, libx265, libvorbis더 일반적으로, 많은 것들을 함께 또는없이 컴파일 될 수 등 등 특정 비디오 / 오디오 인코더, 자막 처리를위한, 그리고 많은 다른 라이브러리 libreadline:가 사용할 수 있다면 당신은 실행할 때 ./configure의 결과 바이너리는 라이브러리에 의존하며 터미널에서 읽을 때 멋진 라인 편집 기능을 제공합니다. 그렇지 않은 경우 프로그램은 일부 대체 지원을 사용하여 stdin의 줄 fgets()이나 무언가를 읽 습니다.)

일부 프로젝트는 여전히 성능상의 이유로 불필요한 기능을 제거하기 위해 선택적 기능을 사용합니다. 예를 들어 Linux 커널 자체는 SMP 지원없이 내장 될 수 있습니다 (예 : 임베디드 시스템 또는 고대 데스크탑).이 경우 많은 잠금이 더 간단합니다. 또는 드라이버 나 기타 하드웨어 기능을 제외하고 일부 핵심 코드에 영향을주는 다른 많은 옵션 기능이 있습니다. (아키텍처 및 하드웨어 별 구성 옵션 이 전체 소스 코드 의 많은 부분 을 차지 하지만 Linux 커널이 1,500 만 줄의 코드 인 이유는 무엇입니까? 참조 )