tar의 f 옵션은 반드시 마지막에 와야 한다. 바로 뒤의 인자를 "아카이브 파일 이름"으로 읽기 때문이다. tar -zxvf file.tar.gz에서 f 다음의 file.tar.gz가 대상이다. -zxfv처럼 순서를 바꾸면 v를 파일명으로 오해해 오류가 난다. 압축 종류(z/j/J)는 풀 때 생략해도 최신 tar는 자동 감지하지만, 시험에서는 명시한 보기를 답으로 본다.
풀린 디렉터리에는 거의 항상 README, INSTALL, configure 스크립트, Makefile.in 등이 있다. 설치 전 INSTALL 파일을 읽는 것이 정석이다 — 필요한 빌드 도구나 라이브러리, 특이한 옵션이 거기 적혀 있다. tar -tzvf file.tar.gz로 풀기 전에 내용 목록만 미리 확인할 수도 있다(t = list).
./configure는 소스 디렉터리에 포함된 셸 스크립트로, 내 시스템 환경을 조사한다.
점검 항목: 어떤 컴파일러가 있는지, 필요한 라이브러리와 헤더가 설치돼 있는지, CPU 아키텍처가 무엇인지.
그 결과를 바탕으로 이 시스템에 맞는 Makefile을 만들어 낸다.
./configure # 기본 설정으로 점검 + Makefile 생성./configure --prefix=/usr/local/nginx # 설치 위치 지정./configure --with-http_ssl_module # SSL 모듈 포함(기능 켜기)./configure --without-http_rewrite_module # 특정 기능 빼기./configure --help # 사용 가능한 옵션 전체 보기
--prefix는 나중에 make install이 파일을 복사할 최상위 경로를 정한다. 기본값은 보통 /usr/local이다. --prefix=/opt/myapp로 주면 실행 파일은 /opt/myapp/bin, 라이브러리는 /opt/myapp/lib에 들어간다. 소스 설치를 한 디렉터리에 격리하고 싶을 때 핵심이 되는 옵션이다. 패키지 관리자와 충돌하지 않도록 보통 /usr/local이나 /opt를 쓴다.
⚠️ 함정: ./configure가 "필요한 라이브러리가 없다(configure: error: ... not found)"며 멈추는 일이 매우 흔하다. 이는 개발용 헤더 패키지(-devel 또는 -dev 접미사)가 없어서다. 예컨대 SSL 기능을 빌드하려면 openssl-devel(RHEL) 또는 libssl-dev(Debian)가 필요하다. 컴파일 오류의 대부분이 이 단계에서, 의존 개발 패키지 누락으로 발생한다.
모든 소스에 configure가 있는 것은 아니다. 이 스크립트는 GNU Autotools(autoconf/automake)가 생성한 것으로, 그 자체로는 소스에 포함돼 배포된다. CMake를 쓰는 프로젝트는 cmake .로, Python은 setup.py로 대신한다. 하지만 리눅스마스터가 묻는 전통적 흐름은 Autotools 기반 ./configure다.
make # Makefile에 따라 컴파일 + 링크make -j4 # CPU 4코어로 병렬 컴파일(속도↑)make clean # 컴파일 산출물 제거(다시 빌드 전)
컴파일은 사실 두 하위 단계다. (1) 컴파일: 각 .c 소스를 .o(오브젝트, 기계어 조각)로 번역. (2) 링크: 여러 .o와 라이브러리(.so/.a)를 묶어 하나의 실행 파일을 완성. make 출력에서 gcc -c ...(컴파일)와 마지막의 gcc -o 실행파일 ...(링크)을 구분해 보면 이 흐름이 보인다. "undefined reference" 오류는 거의 항상 링크 단계에서 라이브러리를 못 찾을 때 난다.
make는 파일의 수정 시각을 비교해 바뀐 부분만 다시 컴파일한다. 그래서 큰 프로젝트에서 코드 한 줄만 고친 뒤 make를 다시 돌리면 전체가 아니라 해당 파일과 그에 의존하는 부분만 빌드돼 빠르다. 처음부터 깨끗이 다시 빌드하려면 make clean 후 make를 한다. make는 인자 없이 실행하면 Makefile의 첫 번째 타깃(보통 all)을 수행한다.
마지막 make install은 완성된 실행 파일·라이브러리·문서를 --prefix로 지정한 시스템 경로에 복사한다.
이 단계만 보통 root 권한이 필요하다(/usr/local 등 시스템 영역에 쓰기 때문).
sudo make install # 빌드 산출물을 시스템 경로로 복사(설치)
단계
명령
하는 일
산출물/결과
1
tar -zxvf
압축 해제
소스 디렉터리
2
./configure
시스템 점검
Makefile 생성
3
make
컴파일 + 링크
실행 파일(빌드 디렉터리 안)
4
make install
시스템 경로 복사
/usr/local/...에 설치 완료
⚠️ 함정: 소스 컴파일로 설치한 프로그램은 패키지 데이터베이스(rpm/dpkg)에 기록되지 않는다. 따라서 rpm -qa나 dpkg -l에 나타나지 않고, yum remove로 지울 수도 없다. 삭제하려면 make uninstall(Makefile이 지원할 때)을 쓰거나 설치된 파일을 수동으로 지워야 한다. 이 "관리 사각지대"가 소스 설치의 가장 큰 단점이다.
# 직접 쳐보기 — 전형적 소스 설치 흐름 (개발 도구 설치되어 있다고 가정)tar -zxvf hello-2.12.tar.gzcd hello-2.12./configure --prefix=/usr/local/hellomakesudo make install/usr/local/hello/bin/hello # 설치한 프로그램 실행
여러 프로그램이 공통으로 쓰는 코드(예: 수학 함수, 암호화)는 라이브러리로 묶여 재사용된다.
링크 방식에 따라 두 종류로 갈린다.
구분
정적(static)
동적(shared)
확장자
.a
.so
연결 시점
컴파일 시 실행 파일에 포함
실행 시 로드
실행 파일 크기
큼(코드 복사됨)
작음
메모리
프로그램마다 별도 사본
여러 프로그램이 공유
라이브러리 교체
재컴파일 필요
.so 교체만으로 반영
배포
독립 실행(의존성 없음)
.so 함께 있어야 동작
정적 라이브러리(.a)는 컴파일할 때 그 코드가 실행 파일 안으로 복사된다. 그래서 실행 파일이 크지만 혼자서도 돈다. 동적 라이브러리(.so, shared object)는 실행 파일에 "이 라이브러리가 필요하다"는 참조만 남기고, 실행되는 순간 동적 링커가 메모리로 로드한다. 그래서 실행 파일이 작고, 같은 .so를 여러 프로그램이 메모리에서 공유한다. 보안 패치가 나오면 .so 하나만 교체해 모든 프로그램에 반영되는 것도 동적의 장점이다.
동적 라이브러리는 보통 libNAME.so.X.Y.Z 형태의 실제 파일과, 그것을 가리키는 심볼릭 링크 libNAME.so.X(soname), libNAME.so(개발용)로 구성된다. 버전 번호 체계 덕분에 호환되는 범위 안에서 라이브러리를 교체할 수 있다. 실행 파일은 soname(libssl.so.1.1 등)으로 의존성을 기록한다.
ldd /usr/bin/nginx # 이 실행 파일이 의존하는 동적 라이브러리 목록ldconfig # 라이브러리 캐시(/etc/ld.so.cache) 재생성ldconfig -p # 현재 캐시에 등록된 라이브러리 목록
# 새 라이브러리 경로를 동적 링커에 등록하기echo "/usr/local/mylib/lib" > /etc/ld.so.conf.d/mylib.confldconfig # 캐시 갱신 → 이제 그 경로의 .so를 찾을 수 있음
ldd(list dynamic dependencies)는 실행 파일이 의존하는 동적 라이브러리와 그것이 실제로 어디에 연결되는지를 보여준다. not found가 뜨면 그 라이브러리를 시스템이 못 찾는 것이고, 프로그램 실행이 실패한다. 이때 라이브러리 경로를 /etc/ld.so.conf(또는 /etc/ld.so.conf.d/*.conf)에 추가하고 ldconfig로 캐시를 갱신해야 한다.
동적 링커는 매번 디렉터리를 뒤지는 대신 /etc/ld.so.cache라는 바이너리 캐시를 참조해 빠르게 라이브러리를 찾는다. ldconfig는 /lib, /usr/lib, 그리고 /etc/ld.so.conf에 적힌 경로들을 스캔해 이 캐시를 다시 만든다. 그래서 새 .so를 시스템 경로 밖에 설치했다면 ldconfig를 반드시 실행해야 인식된다. 임시로는 환경변수 LD_LIBRARY_PATH로 경로를 더할 수도 있지만, 영구 등록은 ld.so.conf + ldconfig가 정석이다.
소스 설치한 프로그램이 "error while loading shared libraries: libxxx.so.1: cannot open shared object file"로 실행 실패하는 일이 잦다. 원인은 그 .so가 /usr/local/lib 같은 비표준 경로에 있는데 동적 링커가 모르기 때문이다. 해결: 그 경로를 ld.so.conf.d에 추가하고 ldconfig. 이 시나리오가 시험과 실무 모두에서 겪는 상황이다.
초기 유닉스는 정적 링크만 썼다. 메모리가 귀하던 시절, 같은 라이브러리 코드가 모든 실행 파일에 중복 복사되는 건 큰 낭비였다. 1980년대 후반 동적 공유 라이브러리(.so)가 도입되면서 디스크와 메모리를 극적으로 아꼈고, 보안 패치를 라이브러리 하나만 교체해 전 시스템에 적용하는 길이 열렸다. 2014년 Heartbleed(OpenSSL 취약점) 대응이 빨랐던 것도, libssl.so 하나만 갈아 끼우면 그것에 동적 링크된 모든 프로그램이 즉시 패치됐기 때문이다. 동적 링크의 가치를 보여주는 대표 사례다.