기술 노트

MacOS 개발 첫 발: 환경 설정부터 코드 호출까지

anothel 2022. 3. 18. 12:22

서론: 드디어 MacOS 첫 발을 떼게 된 이유

바쁜 현대인을 위한 요약: Swift로 C 기반의 모듈을 호출하는 iOS App 제작을 일주일 만에 성공했다.

Swift로 C 기반의 모듈을 호출하는 iOS 앱을 무려 일주일 만에 완성했다. 환경설정으로 고생 좀 했지만, 드디어 해냈다.

오랫동안 애증의 대상이었던 나의 가계부 iOS 애플리케이션이 있다. 2017년 초부터 사용해온 이 앱은 대부분 수작업으로 이루어지지만, 오히려 이 자유도 덕분에 시중의 자산 관리 앱과는 비교할 수 없는 매력을 가진다. 다만, 더 이상 업데이트가 없어서 iPhone SE부터 iPhone 12 Pro Max까지의 화면 차이에 적응하기가 쉽지 않다.

이 애플리케이션 만들어주신 분 상드립니다. 댓글 달아주세요.

그러던 중, 회사에서 다양한 OS에서 암호화 모듈을 테스트해야 하는 과제가 주어졌다. 그중 iOS도 포함되어 있어, 드디어 MacOS에 발을 들이게 되었다. 기대 반 두려움 반으로 시작한 MacOS 설정 작업이 일주일을 넘기게 될 줄은 그때는 몰랐다.


MacOS 환경 설정에서의 좌절기

codesign 문제로 첫 벽에 부딪히다

다행히 .dylib 파일을 빌드할 스크립트는 있었지만, 이게 제대로 된 것인지 알 수가 없었다. 그저 될 거라 믿고 빌드를 시작했지만, 예상대로 실패했다. 에러 메시지?

"The specified item could not be found in the keychain."

이 문제는 키체인에 인증서가 없어서 발생한 것이었다. 방법은 간단했다. 키체인을 새로 만들고 비밀번호를 설정한 후에 SSH 접속으로 MacOS에 붙어서 codesign을 진행할 수 있었다. 왜냐면 이 .dylib 파일이 앱에 포함될 때 반드시 서명되어 있어야 하기 때문이다. 아무리 모바일이라지만, 할 건 다 해야 했다.

같은 CPU인데 왜 실행이 안 될까? 당연한 건 없다

이제 빌드를 끝냈으니 iOS 옵션으로 빌드한 프로그램을 Mac에서 실행해보자. 그런데 프로그램이 죽었다.

Killed: 9

무슨 일인가 싶었지만, 당연히 MacOS에서 iOS 빌드 옵션을 사용해 만든 프로그램이 돌아갈 리가 없었다. 겉으로는 같은 ARM64 CPU 아키텍처라 할지라도, Mac과 iOS는 전혀 다른 환경이었다. iOS도 MacOS도 같은 cpu(이름)을 사용하기 때문에 당연히 돼야 한다고 생각했다. 그런데 당연히 안될 리가 없다고 생각한 게 문제였다. 정확하게는 모르겠지만 비록 서로 cpu(이름)가 같다고 하더라도 iOS빌드 옵션으로 빌드한 프로그램은 MacOS에서 사용할 수 없다. 당연한 건 없었다.


코드로 해결해 나간 문제들

모듈 경로를 찾기 위한 새로운 접근법

디버깅 중에 현재 모듈의 경로를 찾아야 하는 순간이 있었다. 무결성 검증을 위해 전자서명 값을 파일 뒤에 붙였는데, 이때 파일을 읽기 위해서 GetModuleFileName, 리눅스에서는 현재 path를 환경변수를 넘겨줬고, AIX에서는 access, unlink, link를 사용해서 현재 로드된 모듈의 위치를 가져올 수 있었다. 그리고 iOS에서는 방법이 달랐다. 다행히 dladdr라는 함수를 사용해 모듈 경로를 간신히 얻어냈다.

#include <stdio.h>
#include <dlfcn.h>

void test(void) {
    Dl_info info;
    if (dladdr(test, &info)) {
        printf("Loaded from path = %s\n", info.dli_fname);
    }
}

코드는 단순해 보이지만, iOS에서는 의외로 복잡한 과정이었다. 덕분에 무결성 검증을 위해 전자서명 값을 파일 뒤에 붙이는 과정도 완성할 수 있었다.


짧지만 강렬했던 성취감

이 과정을 기록으로 남기는 이유는, 이 과정에서 얻은 작은 성취감을 잊지 않기 위해서다. 테스트 장비에 하얀 화면이 뜨고 숫자 0 하나가 나타났을 때의 감격적인 순간을 아직도 기억한다. 앞으로 더 빠르게 문제를 해결할 수 있기를 바랄 뿐이다.


번외: iOS 버전 체크, 한 줄로 끝내는 방법

한 줄로 짤 코드를 누가 열 줄로 만들어놨어요? 에러 찾기 힘들게. (잠시 뒤) 코드가 길어서 프로그램만 무거워졌잖습니까? 이러니까 서비스가 버벅대지.

프로그램이 무거워지는 걸 막기 위해서 코드도 간단하게 작성해야 한다. 예를 들어, iOS 버전을 확인하는 코드가 길면 서비스가 느려진다.

Text(String(UIDevice.current.systemVersion)).padding()
한 줄이면 충분하다. 쓸데없이 길어지지 않도록, 효율적으로 코드 작성하자.

그리고 나는 iOS 개발과는 아직 인연이 아닌가보다.


Reference

http://www.ventoy.com/
https://stackoverflow.com/questions/24023639/xcode-command-usr-bin-codesign-failed-with-exit-code-1-errsecinternalcomponen%EF%BB%BF
https://stackoverflow.com/questions/39868578/security-codesign-in-sierra-keychain-ignores-access-control-settings-and-ui-p%EF%BB%BF
https://stackoverflow.com/questions/24503001/check-os-version-in-swift
https://stackoverflow.com/questions/7583163/how-do-i-retrieve-the-path-to-my-dylib-at-runtimehttps://stackoverflow.com/questions/7583163/how-do-i-retrieve-the-path-to-my-dylib-at-runtime

728x90