systemd, 새 말단 실행 파일에 Rust 지원 추가…공유 라이브러리는 C 유지
systemd가 다른 구성요소가 의존하지 않는 새 말단 프로그램을 Rust로 작성하는 지원을 main 브랜치에 병합했습니다. Rust 프로그램은 기존 C 공유 라이브러리를 동적으로 연결해 래퍼를 통해 기능을 사용하며, Rust 빌드는 Meson과 지정된 도구 체인을 갖춘 경우 선택적으로 활성화됩니다.
systemd 프로젝트가 다른 구성요소가 의존하지 않는 새 말단 프로그램을 Rust로 작성할 수 있도록 하는 지원을 main 브랜치에 병합했습니다. 기존 C 프로그램과 다른 구성요소의 기반이 되는 라이브러리는 C로 유지합니다. Amutable에 실린 설명 글의 공동 저자인 Christian Brauner와 Lennart Poettering은 새 언어를 도입하면서도 공통 기능과 빌드 체계를 기존 방식에 연결한 설계라고 설명했습니다.
공유 라이브러리는 C로, 새 프로그램은 Rust로
systemd에서 Rust를 쓸 수 있는 대상은 다른 구성요소가 의존하지 않는 새 개별 실행 프로그램입니다. 공용 라이브러리 자체에 Rust를 도입하는 문제는 별개입니다. Brauner와 Poettering은 Rust 코드가 공유 라이브러리에서 안정된 ABI를 제공해야 한다고 설명했습니다. 이 기반 없이 Rust를 핵심 공유 계층에 넣으면 라이브러리와 여러 실행 파일에 코드가 중복될 수 있습니다. 180개가 넘는 작은 바이너리로 나뉜 systemd에서는 정적 링크 방식도 실용적이지 않다는 것이 유지자들의 판단입니다.
대신 Rust 프로그램은 기존 C 공유 라이브러리인 libsystemd-shared를 동적으로 연결해 기능을 호출합니다. 빌드 과정에서 bindgen이 systemd의 C 헤더를 바탕으로 Rust 바인딩을 만들고, 그 위에 프로젝트 내부의 systemd_shared 크레이트가 놓입니다. 이 크레이트는 C 함수의 오류 규칙과 로깅, 명령행 처리 방식을 Rust 코드가 사용할 인터페이스로 감쌉니다. Rust용 크레이트는 실행 파일에 정적으로 연결되지만, 공통 기능은 기존 C 라이브러리에서 가져옵니다.
이 구조는 경로 처리에서 드러납니다. systemd의 chase 계열 함수는 파일 디스크립터를 기준으로 경로를 조회하는 공통 C API입니다. 유지자들은 보안에 민감한 systemd 구성요소에서 Rust 기본 경로 기능을 사용하기 어렵다고 설명했습니다. chase 계열 API는 경로 조회의 보안과 신뢰성을 높이는 새 커널 기능도 공통으로 반영하므로, Rust 프로그램은 이 C API를 호출해 systemd의 기존 처리 방식을 이용합니다.
첫 Rust 프로그램인 systemd-keyring-setup은 이 역할 분담을 보여줍니다. 이 프로그램은 운영체제 산출물 검증용 파일 계층(VOA)에 있는 X.509 인증서를 부팅 과정에서 커널 키링에 등록한 뒤 키링을 봉인합니다. VOA 파일 조회와 키링 조작, X.509 처리는 C 공유 라이브러리가 맡고 Rust 프로그램은 해당 기능을 호출합니다. 이 서비스는 기본적으로 활성화되지 않습니다.
빌드와 메모리 처리도 systemd 방식으로
systemd는 Meson만 빌드 도구로 사용하고 Cargo는 추가하지 않았습니다. 유지자들은 빌드 체계를 하나 더 도입하면 배포판 유지관리자의 부담이 늘 수 있고 Cargo의 의존성·공급망 위험도 고려해야 한다고 설명했습니다. 프로젝트는 Rust 생태계에 더 익숙해질 때까지 외부 크레이트 의존성을 넣지 않는 보수적 방침을 택했습니다.
Rust 코드에서는 std와 alloc을 사용하지 않습니다. systemd는 표준 라이브러리의 경로 처리 기능을 보안 민감한 구성요소에 적합하지 않다고 판단하며, alloc의 컬렉션은 메모리가 부족할 때 프로그램을 중단시킬 수 있다고 설명했습니다. 대신 프로젝트 내부의 Box와 Vec는 자체 할당기를 사용하고, 할당 실패를 오류로 돌려줍니다. 메모리 부족을 처리하는 방식도 기존 C 코드의 규칙에 맞춘 것입니다.
사용자가 보는 명령행 동작도 C 프로그램과 같게 맞췄습니다. Rust 프로그램은 기존 옵션 파서와 도움말 형식을 사용하고 오류도 systemd의 규칙에 따라 출력합니다. 프로젝트의 비교 테스트는 같은 명령을 선언한 C·Rust 프로그램의 출력을 바이트 단위로 대조합니다. 구현 언어에 따라 명령 사용법이 달라지지 않도록 한 구성입니다.
Rust 지원은 빌드 선택 사항입니다. 현재 개발 문서는 rustc 1.85, bindgen 0.71.1, Meson 1.4.0 이상을 요구합니다. 기본 설정인 -Drust=auto는 필요한 도구가 없거나 버전이 낮으면 Rust 지원을 끄고, -Drust=enabled는 조건을 충족하지 못할 때 빌드를 실패시킵니다. Rust를 지원하지 않는 빌드도 계속 사용할 수 있습니다.
참고 자료
- systemd ❤️ Rust
- rust: support programs written in Rust by brauner · Pull Request #44324 · systemd/systemd
- systemd/docs/CODING_STYLE.md at main · systemd/systemd · GitHub
- systemd/docs/HACKING.md at main · systemd/systemd · GitHub
- keyring-setup: add systemd-keyring-setup by brauner · Pull Request #44114 · systemd/systemd