뒤로가기back

청력은 회복되지 않아요 (ft. ELEQ의 필요성)

2019.08.28 by Gaudio Lab

ELEQ의 필요성

청력은 회복되지 않아요!

카드뉴스 제작: PAUL AHN

 

소리‘는 눈에 보이지 않는 것이라 많은 분들이 EQ 를 ‘있어도 그만~ 없어도 그만~’ 처럼 가볍게 생각하실 수 있을 거같아요. 혹은 EQ기능이 없어서 생기는 문제점 자체를 알지 못하시는 분도 계실거구요. 👀👂🏻

 

오늘은 청력과 관련하여 ELEQ가 뮤직/콘텐츠 플랫폼에 얼마나 경쟁력에 있고 매력있는 기술인지 쉽게 풀어드리고자 준비해보았습니다.

pre-image
The Effect of Multichannel Audio on Presence | 논문 읽어주는 제임스

Here, There, and Everywhere: The Effect of Multichannel Audio on Presence J. Freeman & J. Lessiter Psychology DepartmentGoldsmiths CollegeUniversity of LondonUK Proceedings of the 2001 International Conference on Auditory Display, Espoo, Finland, July 29 – August 1, 2001     실재감 (Presence, Being there) 의 느낌은 VR/AR을 연구하는 사람들에게 가장 중요한 개념 중 하나입니다. 결국 어떠한 시스템을 통해 한 경험이 실제의 경험처럼 느껴지려면 의식적이든 무의식적이든 체험자의 감각으로 들어온 자극들이 실제 세계에서의 그것과 동일하거나 유사해야 합니다.   이 논문에서는 그것을 다각적 미디어 시스템 (multi-modal media system) 중오디오 디스플레이의 성능을 평가하는 척도 (metric) 로 사용할 것을 제안합니다. 꽤나 오래전 논문이긴 하지만, 3-D 오디오를 이용한 몰입감있는 경험을 제공하고자 하는 가우디오에서는 한번 읽어볼 만한 논문이라 이렇게 시작을 해 봅니다. 이후에도 관련 내용들을 시리즈처럼 엮어볼까 합니다.   보통 논문을 읽으면서 소개 (introduction) 부분을 거의 읽지 않는데, 재밌는 내용이 있어서 일단 그 이야기를 먼저 시작해 볼까 합니다. B. Reeves와 C. Nass 의 연구에 따르면 사람들은 어느 정도 좀 품질이 떨어지는 시각적 형상에 대해서는 용인하고 넘어간다고 합니다. 그 이유가 우리가 받아들이는 시각 영상들은 그 대부분이 주변 시야이고, 이 주변 시야는 해상도가 낮기 때문이라는 거죠. 반면, 열화된 충실도의 오디오는 상대적으로 덜 익숙한 경험이기 때문에 이를 쉽게 용인하지 못한다고 합니다. [1]물론 다각적 미디어 시스템에서 어느 하나 중요하지 않은 자극은 없겠지만, 우리가 생각하는 것보다 오디오 신호의 품질은 사람들의 몰입감, 실재감에 많은 영향을 미치고 있다는 걸 알 수 있겠네요.   이 논문이 밝혀보고자 하는 목표는 다음과 같습니다. 재생되는 오디오 채널의 숫자가 실재감에 주는 영향, bass 신호가 실재감에 주는 영향, 소리의 크기 (volume) 이 실재감에 주는 영향   이런 요소들이 실재감에 주는 영향을 밝혀보기 위해 가설 (hypothesis) 을 몇 가지 세웠습니다.   5 채널 시스템은 2 채널 시스템보다 훨씬 더 정확한 공간을 재현할 것이고, 피실험자들은 더 높은 실재감을 경험하며, 5채널 시스템의 오디오 품질에 더 높은 점수를 부여할 것이다. 저역 신호를 포함한 오디오 신호는 부가적인 감각 자극을 만들어 낼 것이며, 이는 자극에 진동을 추가로 제공하는 형태가 될 것이다. 따라서 저역 신호를 포함한 오디오 신호는 더 높은 평가를 받을 것이다. 오디오 신호의 가공은 제시된 시각적 자극에 대한 평가를 향상시킬 것이다. 저역 신호의 기여도와 청각/시각적 특징에 대한 평가는 전체적인 소리크기의 증가에만 기인하는 것은 아닐 것이다.   일단 이렇게 가설들을 정리해 놓고 실험을 진행했네요. 실험방법은 아래와 같습니다. 30명의 참가자 신호는 2.0 (stereo), 2.1 (stereo with bass), 2.0_control (2.1 신호와 동일하게 음량을 맞춘 2.0 신호), 5.0, 5.1, 5.0_control 로 구성 rally car 운행할 때 발생하는 소리들 (engine noise, gear noise 등)을 사용 영상은 28인치 텔레비전으로 제공 whitout bass 는 기본적으로 pink noise를 사용했을 때 70dB SPL, with bass 는 83/84 dB SPL 의 음량이 되도록 생성 2.0 신호를 기반으로 2.1, 2.0_control, 5.0, 5.1, 5.0_control 신호를 쌍비교 (pair-wise comparison) 저자의 research group 에서 개발한 ITC-SOPI (ITC-Sense of Presence Inventory), The Media Experience Questionnaire 를 완성하도록 피실험자들에게 요청.   ITC-SOPI는 총 44개의 항목으로 구성된 실재감 질문지(1점 매우 불일치 – 5점 매우 일치 스케일을 갖고 있음) Sense of Physical space 에 관련된 19개의 항목 Engagement – sense of involvement 에 관련된 13개의 항목 Ecological Validity – sense of naturalness에 관련된 5개의 항목 Negative Effect 에 관련된 6개의 항목 합산하면 43개인데, 1개가 빠진 건지, 항목 개수가 잘못된 건지 모르겠네요.   Media Experience Questionnaire는 총 18개의 항목으로 구성 오디오 신호에 대해서 1) excitement, 2) spaciousness/surrounding, 3) full/completeness, 4) clarity, 5) loudness, 6) uncomfortableness of volume, 7) audibility of extraneous sounds, 8) fidelity/quality, 9) enjoyableness 에 대해 평가 비디오 신호에 대해서 1) uncomfortableness, 2) depth/3Dness, 3) excitement, 4) fidelity/quality, 5) enjoyableness에 대해 평가 이후 overall quality 에 대한 평가를 추가로 진행 그럼 결과를 한번 살펴보지요. 역시 그래프가 결과를 한눈에 보여주기에는 제일 쉬운 방법이라 그래프로 한번 먼저 보고 가겠습니다. Figure 1. The effects of bass and channel manipulations on (a)Sense of Physical Space, (b) Engagement, (c)Ecological Validity, and (d) Negative Effects   그래프에 따로 신뢰구간이나 분산값이 표현되어 있지 않은 이유는 ANOVA (Analysis of Variance) 를 통해서 해당 결과의 신뢰도를 따로 제공했기 때문입니다. ITC-SOPI 의 네 가지 평가 요소 중, Sense of Physical Space와 Engagement는 bass 신호가 포함된 경우 유의미한 개선이 있음을 확인할 수 있습니다.   각각 (F(1,29) = 11.12, p<0.01), F(1,29)=16.26, p<0.001) 의 분석결과가 나왔다고 합니다. 반면, 평균값만으로 봤을 때 Naturalness와 Negative effect 의 경우 bass 신호가 포함된 경우 향상된 것으로 보여지긴 하는데, 통계적으로 유의수준을 달성하진 못했네요. 그리고 채널 수가 많아진 것도 역시 통계적 유의수준을 달성하지는 못했습니다. 채널 수가 많아진 경우는 Sense of Physical Space 정도에서만 의미있는 결과를 보였구요.   다른 평가항목에 대해서는 채널 수가 적은 쪽이 더 높은 점수를 보이는 경우도 있습니다. 이 결과로부터 bass와 channel 개수의 상호영향은 없다고 볼 수 있겠네요.   해당 결과를 T-test를 통해 쌍비교도 해 봤는데, 이 역시 재미있는 결과를 보입니다. 2.0_control과 2.1 신호를 비교하는 경우를 예로 들어보죠. 이 두경우는 음량은 동일하게 맞춰졌습니다. bass 신호가 포함되어 있는지, 아닌지만 차이가 나겠네요. 일단 위 그래프에서 봐도 2.0_control 에 비교해서 2.1은 모두 더 높은 점수를 받고 있음이 보입니다. 음량이 같아도 bass 신호가 있는 것이 모든 면에서 훌륭한 점수를 보여주고 있는 거죠. 특히 Engagement와 Ecological Validity 는 통계적으로 유의미한 차이를 보이고 있습니다.   반면 Sense of Physical Space는 차이는 보이고 있긴 하지만, 통계적 유의수준을 만족하지는 못하고 있습니다. 이러한 결과로 봤을 때, bass 신호는 실재감을 향상시키는데 어느 정도 기여를 하고 있음을 확인할 수 있습니다. 또 하나 눈 여겨볼 것은 Naturalness 의 관점에서는 2.0_control 신호가 5채널 신호보다 더 좋은 성능을 보인다는 것이겠네요.   Media Experience Questionnaire (MEQ)에 대해서도 채널 수에 관계없이 bass 신호를 포함한 신호가 모든 항목에서 더 좋은 평가를 받았음을 확인할 수 있습니다. 불행히도 해당 결과 그래프는 보여주지 않고, 통계수치만을 제시했네요. 또 하나 재미있는 결과는 저역을 포함한 오디오 신호를 제공한 경우, 영상의 품질에 대해서도 더 높은 평가를 한다는 사실입니다. 청각-시각 인터액션을 반영하는 결과이기도 하네요. 다만 보통의 실험에서는 시각 자극이 좋은 경우 청각 자극도 좋게 느껴진다는 결론인데, 반대의 결과도 존재하네요.   그럼 위 결과들을 바탕으로 처음 세웠던 가설들을 한번 검증해 보죠.   bass가 포함된 음원이 더 높은 평가를 받은 것으로 가설 2번은 지지가 되네요. 다만, 2.1 mix에 대해서 ITC-SOPI Sense of Physical Space평가와 MEQ 평가에서의 bass와 관련된 증가치는  볼륨의 증가치에 영향을 주었기 때문에 가설 4번은 부분적인 지지만 인정할 수 있겠습니다.   채널 수와 관련된 가설 1은 전체적으로 2채널과 5채널 사이의 유의미한 차이를 보이지 않았기 때문에 기각되었습니다. 다만, 이번에 사용된 청각 자극의 종류로 인한 차이 때문에 이러한 결과가 나왔으므로, 이에 대한 부분은 추가 실험이 필요하다고 저자들도 밝히고 있네요. 마지막으로 가설 3 역시 청각 자극의 변형 (bass를 더한다거나 더 큰 소리로 들려주는 것)이 시각 자극의 평가에 긍정적인 영향을 보여준다는 결과로 봤을 때 역시 지지받는 가설이 되겠습니다.   이 논문의 결과로만 보면, bass 음원이 포함되고, 최종 재생되는 소리가 충분히 큰 경우가 그렇지 않은 경우보다 실재감을 높여줄 수 있는 요소라고 보고 있습니다. 반면, 2채널 시스템보다 5채널 시스템이 더 높은 실재감을 준다고 보장은 할 수 없다는 점이네요. 이 논문은 결국 실재감이라는 평가요소를 전반적인 특징과 구체적인 특징으로 나누고, 그 둘의 결합을 통해 평가할 수 있다는 걸 보여주고 싶었던 것 같습니다. 두 가지 평가 방법 (ITC_SOPI와 MEQ)틀 통해 두 결과가 일치하는 것들을 보여줬고, 실재감이라는 것이 immersive audio system 의 궁극적인 목표에 대한 주관적 지표가 될 수 있음을 보여주고 있습니다.   다소 짧은 학회 논문이라서 논문의 길이가 그리 길진 않은데요. 해당 제목을 구글링하시면 논문도 쉽게 보실 수 있으니, 시간 나실 때 한번 읽어보셔도 좋겠네요.   [1] Reeves, B. & Nass, C. (1996). The media equation: How people treat computers, televisions, and new media like real people and places. Cambridge University Press.   Gaudio Lab 은… 가우디오랩(주)은 VR/AR, 스트리밍 미디어, 모바일, 홈 등 소리가 있는 어디에서나 사람들에게 훌륭한 소리 경험을 제공하는 일을 합니다. 가상세계를  더욱 현실처럼 만드는 소리, 현실을 넘어 초현실적인 소리를 만드는 혁신적인 기술들로 전세계를 누비며 활약하는 국가대표 오디오 공학집단입니다. “올해의 최고 VR 혁신 기업상 수상(VR Awards, 런던, 2017)“, “ISO/IEC MPEG-H 3D Audio 국제표준 채택 (2013,2018)“으로 혁신성을 인정받은 6인의 음향공학박사와 오디오 Geek들은 실리콘밸리와 서울에 있습니다. The Science of Sound.

2019.08.27
after-image
윌슨의 개발지식- 개발환경과 빌드(1)

개발환경과 빌드(1) 개발환경과 빌드는 도메인마다 다 다르고, 복잡해 보이기 때문에 접근하려고 마음 먹기 전에 두려움이 먼저 자리 잡는 것 같아요. 이러한 새로운 개발환경을 처음 접할 때 가장 어려운 부분은 전체 시스템에 대한 이해가 완벽하지 않기 때문에, 한 수 한 수 둘 때마다 이것이 어떠한 사이드 이펙트를 만들지에 대해서 불안감과 두려움이 먼저 생긴다는 것이죠. 전체 시스템에 대해서 확신을 가지고 있는 누군가가 옆에서 불확실하다고 여겨질 때마다, 확신을 준다면, 배움의 속도도 빨라지고, 응용의 속도도 빨라질 것 같다는 생각이 들었습니다.   그래서 도메인 별로 개발환경에 대해서 한 번 정리하고 많은 분들이 불안한 마음으로 다루고 있는 빌드 시스템에 대해서 알리고자 이 문서를 기획했습니다.   Native C,C++,WebAssembly 빌드 바라건대, 이 문서를 읽고 새로운 타겟 플랫폼에 대한 빌드 요청이 들어 왔을 때, 기반이 되는 개념모델을 활용하여 유연하게 문제를 해결해 나갈 수 있었으면 합니다. 🙂   컴파일이란? 작성된 소스 파일들을 특정 플랫폼(런타임)에서 이해할 수 있는 언어(일반적으로 기계어에 가까운 언어를 지칭)로 변환하는 프로세스에요.   플랫폼이란? 플랫폼이라는 용어는 일반적으로 “아키텍쳐“와 그 위에 올라오는 “운영체제” 쌍을 의미합니다. 그러나 최근에는 좀 더 의미가 확장되어 운영체제 위에 “소프트웨어“가 추가된 형태로 얘기되는 것 같아요. 저는 좀 더 일반적으로 생각하기 위해서 “소프트웨어 또는 라이브러리가 실행될 수 있는 환경을 위한 조건“이라는 개념을 가지고 있되, 컨텍스트에 따라서 해석하고는 합니다. 예로 들어, C++환경에서는, “아키텍쳐-OS”로 생각하는 것이죠.   빌드란? 특정 플랫폼의 빌드머신에서, 타겟 플랫폼의 런타임 위에서 동작하는 프로그램이나 사용할 수 있는 플러그인, 프레임워크, 라이브러리, SDK 등을 제작하는 프로세스. 일반적으로 컴파일 과정을 포함해요.   그러면 크로스플랫폼 빌드란? 특정 플랫폼의 빌드머신에서,하나 이상의 다양한 타겟 플랫폼의 런타임 위에서 동작하는 프로그램이나 플러그인, 프레임워크, 라이브러리, SDK 등을 생산하는 프로세스.   런타임 이렇게 프로그램이 실행될 수 있는 환경을 실행환경(이것도 결국 프로그램), 즉 Runtime Environment라고 합니다. 예로, Java는 해당 OS에 설치된 JRE(=Java Runtime Environment)라는 프로그램 위에서 자바의 IR 코드가 컴파일되어 실행되는 것이죠.     그러면 C++ 컴파일이란? 컴파일 프로세스 오브젝트 파일 컴파일   정적 라이브러리나 실행파일을 빌드한다고 해도 기본적으로 오브젝트 파일부터 컴파일을 마치고 그 결과물이 입력이 되어 정적 라이브러리나 실행파일 컴파일이 진행됩니다. 따라서 가장 기본이 되는 것은 C/C++ 컴파일 과정이라고 볼 수 있는데, 크게 다음의 과정으로 진행됩니다.   전처리 이 과정은 전처리매크로(Pre-processor Macro)를 읽고 처리하는 과정입니다. 가장 많이 알고 있고 많이 쓰는 전처리 매크로는 다음과 같아요. #include 컴파일러가 위 전처리 매크로를 만나면 hello.h 파일을 읽어서 #include한 .cpp파일에 복붙합니다.   컴파일 전처리 과정을 거친 소스파일(.i)들은 컴파일 과정을 거치면서 어셈블리로 출력됩니다. 이 과정을 수행하는 툴채인 프로그램이 compiler입니다. 이 단계가 마지막 Human Readable한 코드에요. 그리고 이 단계에서 Architecture 인스트럭션으로 코드가 생산됩니다. 즉, 어셈블리 코드는 타겟 아키텍쳐에 dependant합니다. *참고로 Assembly라는 용어는 일반적으로 기계어에 가장 가까운 Human Readable한 코드를 말한다고 하네요.   어셈블 컴파일을 거쳐서 나온 어셈블리 파일들을 어셈블하면 최종적으로 머신코드인 오브젝트 코드 파일(.o)들이 생성됩니다. 이 과정은 assembler가 수행합니다. 오브젝트 코드란? 출처: Compiler Design | Introduction of Object Code   오브젝트 코드는 기계가 이해할 수 있는 코드로 구조는 위 그림과 같아요.   여기서 Header에는 별 정보가 없고 그 아래 Text Segment, Data Segment 등의 위치에 대한 인덱스를 담고 있다네요.   여기서 중요한 정보는 “Symbol Table”과 “Debugging Information” 정도일 것 같아요. 이 “Symbol Table”을 이용해서 Linking이 일어나고, “Debugging Information”을 이용해서 디버깅이 이루어집니다. (참고로 Debugging Information은 컴파일러에 -g 옵션(GCC 기준)을 주어야 포함됩니다.)   Symbol에 대한 정보는 Mac에서는 otool, nm 툴 등을 이용해서 확인할 수 있습니다. 간단히 보면, 아래와 같습니다.   > nm libExampleFx.a example_filter.cpp.o: U __ZN12Example13processEP9AudioNodePKsPs -------- T _example_context_create 위를 해석하면, libExampleFX.a라는 정적 라이브러리는 example_filter.cpp의 오브젝트 코드를 포함하고 있다. 그 오브젝트 코드에는 두 개 함수가 선언되어 있다. Example::Process… example_context_create “U”라고 앞에 표시된 Example::Process…은 이 오브젝트 코드의 Undefined된 함수다. “T”라고 앞에 표시된 example_context_create는 이 오브젝트의 정의된 함수다. 이 밖에도 많은 심볼이 있지만, 지금은 “U”라는 키워드가 정의되지 않은 심볼이라 링킹 과정을 통해 심볼이 정의되어야resolved 한다는 점만 기억하시면 되요.   정적 라이브러리(static library) 빌드 정적 라이브러리 빌드는 오브젝트 파일 컴파일 프로세스 뒷단에 아카이브 과정이 포함됩니다. 그리고 이 아카이브를 수행하는 툴채인 프로그램이 archiver에요. 아카이브는 오브젝트 파일을 zip한다는 개념으로 보시면 되요. 소스파일의 개수만큼 출력되는 오브젝트 파일을 하나의 파일로 합쳐서, 좀 더 포터블한 형태로 만드는 과정이죠. 실행파일(executable) & 동적 라이브러리(shared library, dynamic library) 컴파일 동적 라이브러리 또는 실행파일 컴파일 또한 오브젝트 파일 컴파일 프로세스 뒷단에 링킹 과정이 포함된 빌드 과정이에요. 링킹 프로세스에서는 오브젝트 파일을 하나로 병합합니다. 그리고 이 링킹을 수행하는 툴채인 프로그램이 linker입니다. 이 때 각각의 오브젝트 파일에 Undefined되어 있는 심볼(함수, 변수 클래스 등등)을 다른 오브젝트에서 찾아서 교체하는 작업이 일어납니다. 따라서 링킹 과정이 일어나기 전까지는 내가 사용하려는 정적 라이브러리가 제대로 빌드된 것인지를 확인하기가 어렵습니다. 빌드 도중 많이 접하게 되는 “symbol not found” 에러가 이 때 발생(아래 스크린샷 참고)하죠.   출처: Symbol(s) not found for architecture x86_64 when using C/C++ library in Xcode project   툴체인이란? 개발용 프로그램 도구 집합을 툴체인이라고 하는데요. 툴체인이라고 부르는 이유는 한 프로그램 출력이 다른 프로그램의 입력이 되어 서로 체인처럼 연결되어 실행되기 때문이라네요. 컴파일러의 출력은 어셈블러의 입력이 되고 어셈블러의 출력은 아카이버의 입력이 되는 것처럼 말이죠.   컴파일러 툴체인 생산자 컴파일러 툴채인의 생산자는 크게 2개로 나뉘어 집니다. GNU의 GCC LLVM Developer Group의 LLVM(Low Level Virtual Machine) 두 생산자의 차이점을 이해하려면 컴파일러의 구조를 이해해야 해요. 전통적으로 컴파일러의 구조는 아래처럼 “3 Phase Design”을 따르고 있다네요. 참조: http://www.aosabook.org/en/llvm.html   문제는 GCC를 포함해서 많은 컴파일러가 이 구조를 따르고 있음에도 불구하고, Frontend, Optimizer, Backend가 깔끔하게 분리 되기에는 아직 의존성이 너무 얽혀 있다고 하네요. 그런데, LLVM은 중간과정에 LLVM IR(Intermediate Representation)을 도입하면서 재사용이 용이한 컴파일러를 구현해 냅니다. 우선 각각의 파트가 담당하는 역할을 정리해 보면 다음과 같아요. Frontend: 언어해석. C++, C, Rust low한 언어를 해석 Optimization: 최적화 Backend: 머신언어로 변환. 이 때 Machine Dependent한 코드가 생산됩니다. 즉 해당 아키텍쳐만 이해할 수 있는 언어로 번역되는 것이죠.   그렇다면 C++ 언어를 해석하는 Frontend와 x86_64 아키텍쳐용 백엔드를 각각 한 번만 만든 후에 이후에는 이를 독립적인 프로그램으로 빌드해서 운영하면, 타겟 플랫폼과 사용언어에 따라 필요한 Frontend, Backend 툴채인을 선택해서 빌드하면 되는 것입니다. 따라서 기존 컴파일러가 각각의 파트가 서로 의존성이 있기 때문에, 언어 하나와 백엔드 하나당 컴파일러가 한 대씩 있어야 했다면, LLVM은 호스트 플랫폼용으로 한 번만 빌드하면, 이후에는 프론트엔드 언어가 추가되거나, 머신이 추가될 때에만 툴채인을 받아서 배포하면 되는 것이죠. 참고로, 여기서 LLVM의 C/C++ 언어 Frontend로 사용되는 것이 바로 Clang입니다.   스탠다드 라이브러리(STD)란?  “C++ 스탠다드 라이브러리는 C++과 C++ ISO 표준 자체로 쓰여진 클래스들과 함수들의 집합” – 출처: Wikipedia 신기한 점은 ISO에서 헤더만 표준으로 제안할 뿐 구현은 각 벤더(?)가 해야 한다는 점이에요. 따라서 Microsoft는 본인들의 구현 라이브러리를 가지고 있고, GNU도 Linux용 독자적인 구현 라이브러리를 가지고 있는 거죠. 그럴 수 밖에 없는 이유라면 STD의 특정 파트의 구현은 OS의 System API에 의존적일 수 밖에 없기 때문이죠. 예로 들어, 같은 경우가 그렇습니다. 이 헤더의 구현은 OS C API를 사용해서 구현하게 됩니다. 가끔 접하게 되는 gnustl, stdc++ 등의 단어들은 서로 다른 벤더가 구현한 STD 라이브러리를 얘기합니다.   스탠다드 라이브러리 Extension이란? ISO에서 스탠다드 라이브러리의 기능을 확장한 표준안이 발표되면, 이 또한 각 벤더들이 새롭게 구현해야 합니다. 그런데 벤더들마다 구현의 속도가 다르고 어떤 벤더는 구현을 했고, 또 어떤 벤더는 구현을 못한 경우가 있기 때문에, 툴채인마다 확장기능을 제공하는 수준이 다릅니다.   그러면 C++ 크로스플랫폼 빌드란? “특정 플랫폼 빌드머신에서 C++로 작성된 소스를 하나 이상의 다양한 타겟 플랫폼의 런타임 위에 설치하여 동작하는 프로그램이나 플러그인, 프레임워크, 라이브러리, SDK 등을 생산하는 프로세스“라 말할 수 있겠죠. 이에 따르면, 크로스플랫폼 빌드를 위해 다음을 고려해야 합니다. 빌드 머신 또는 호스트 시스템의 플랫폼 타겟 플랫폼 빌드 툴채인 타겟 플랫폼 스탠다드 라이브러리   쉽게 예를 들어 보면, 내가 만약 armeabi-v7a 아키텍쳐, Android OS 위에서 동작하는 C++로 개발된 라이브러리를 빌드하려면, 먼저 어디서 빌드할 것인지를 결정해야 합니다. 만약 Mac OSX로 선정했다면 이 OS에서 타겟 플랫폼인 “armeabi-v7a-android”를 컴파일할 수 있는 빌드 툴채인과 스탠다드 라이브러리를 지원하는지 확인합니다. 지원하면 빌드할 수 있는 거겠죠. 그렇다면, 위에서 살펴본 고려사항에 기반해서 주요 5개 타겟 플랫폼의 빌드환경을 살펴보자.   타겟 플랫폼별 빌드환경     타겟 플랫폼 빌드 FAQ Windows /MD, /MT 옵션이란? 윈도우에서는 Standard Library가 CRT 라이브러리에 의존적인데, MD는 CRT dll라이브러리를 동적으로 링킹해서 사용하는 옵션이고, MT는 CRT lib라이브러리로 링킹해서 사용하겠다는 것이에요.   MD의 경우, CRT 라이브러리가 최종 바이너리에 포함되지 않기 때문에, 파일 사이즈가 작아집니다. 반면에, 시스템에 CRT dll이 없는 경우 동작하지 않겠죠. 반대로 MT는 라이브러리가 최종 바이너리에 포함되기 때문에 시스템과 상관없이 항상 동작합니다. 반면에 파일 사이즈가 크겠죠.   *주의할 점은 MD옵션으로 빌드한 라이브러리를 사용하려면 마찬가지로 MD옵션으로 라이브러리 또는 실행프로그램을 빌드해야 합니다. (MT도 마찬가지)   왜 윈도우는 동적 라이브러리가 .lib와 .dll로 생성되는가? 앞에서 얘기했듯이, 오브젝트 코드는 Symbol Table을 포함하고 있기 때문에, 이를 기반으로 링킹이 진행되죠. 마찬가지로 이 오브젝트 코드가 병합된 형태인 dynamic 라이브러리(또는 shared library) 또한 로드 타임에 이 심볼테이블을 이용해서 링킹이 일어납니다. 이 심볼테이블이 윈도우에서는 .lib파일에 포함된 것입니다. 그리고 .lib파일을 “Import Library”라고 부릅니다. 다른 플랫폼은 윈도우와는 다르게 동적 라이브러리 파일 하나에 심볼 테이블이 포함되어 있다고 합니다. 참고로 Dynamic 라이브러리의 링킹방법은 두 가지가 있고 하나는 load 타임 링킹이고 두 번째는 runtime 링킹입니다. 후자는 심볼 테이블이 필요없이 함수를 다이렉트로 호출하는 것으로 알고 있습니다. Cygwin vs MinGW vs MinGW-w64 윈도우 빌드를 윈도우가 아닌 다른 빌드머신에서 하려고 할 때 가장 혼란을 주는 개념들이 바로 Cygwin, MinGW, MinGW-w64입니다.   MinGW는 “Minimalist GNU for Windows의 약자로 윈도우 환경에서 GNU 툴채인을 이용하기 위한 환경을 의미합니다.” MinGW에는 컴파일러 툴채인 및 플랫폼 헤더와 라이브러리가 포함되어 있습니다. Microsoft에서는 이 플랫폼 라이브러리 소스를 오픈하지 않았기 때문에, MinGW는 플랫폼 라이브러리 헤더인 windows.h를 MSDN에 문서에 기반해서 순수히 구현했다고 하네요. 따라서 불완전하기도 하고 최신 API는 빠져있는 경우가 있다네요. 또한, MSVC로 빌드한 C++라이브러리는 C Runtime Library에 의존적인데 이 또한 오픈되어 있지 않기 때문에 손수 구현했다고 합니다.   MinGW-w64는 MingGW와는 완전히 별개라고 합니다. OneVision이라는 회사에서는 자사 라이브러리를 64bit 윈도우 타겟으로 포팅하기 위해 64비트 윈도우용 툴채인을 직접 제작했다고 합니다. 이렇게 제작된 툴채인을 MinGW에 제출했지만, 코드를 확신할 수 없었던 MinGW에서 코드를 거절했고, 이에 완전히 별개로 MinGW-w64 라는 이름으로 프로젝트를 운영하기 시작했다고 합니다. MinGW가 32비트만 지원하는 반면, MinGW-w64는 64비트 뿐 아니라 32비트도 지원한다고 하네요.   Cygwin은 완전히 타겟이 다른 빌드환경입니다. Cygwin은 윈도우 OS위에 리눅스 에뮬레이팅 레이어를 올리고 그 OS에서 동작하는 라이브러리 또는 실행 프로그램을 빌드합니다. 결국, Cygwin으로 빌드하면 Cygwin이 타겟인 것입니다. 프로그램을 받은 유저 또한 Cygwin이 설치되어 있어야 해당 바이너리를 실행할 수 있습니다.   Android NDK란? ndk-bundle은 많은 툴채인들이 포함된 도구집합이다. 이 중 ndk-build 프로그램은 Android.mk와 Application.mk를 입력파일로 받아서 여기에 정의된 설정값에 따라 ndk-bundle에 포함되어 있는 clang, gcc, archiver, assembler 등 툴채인들을 선택해서 빌드를 수행한다.   Web Browser와 Web Assembly Emscripten이란? Emscripten은 LLVM을 이용해서 만든 컴파일러로, Frontend는 그대로 사용하되 Optimizer와 Backend를 웹어셈블리용으로 개발한 컴파일러다. 여기서 Emscripten에 포함된 웹어셈블리용 Optimizer를 Binaryen이라고 부른다. 자세한 컴파일 과정은 아래와 같다. (웹어셈블리에 대해서는 다음에 더 자세히 설명하도록 할게요)   CMake란? 위에서 언급한 C++ 컴파일 프로세스를 고려하면, 특정 타겟 플랫폼에 대해서 소스를 컴파일, 패키지하고, 헤더파일 추가나 소스파일 변경을 감지하는 것이 바로 “빌드시스템”이죠. 이 빌드시스템이 바로 make, ninja고 Visual Studio고, XCode에요. 그리고 빌드시스템을 생성하는 것이 바로 “CMake”입니다.   타겟 플랫폼으로 소스를 빌드하는 시스템을 생성하려면 어떤 입력Input이 필요할까요? 용하는가? 어떤 linker를 사용하는가? 컴파일 대상이 되는 소스 파일과 헤더 파일은? 빌드 옵션을 어떻게 줄 것인가? compiler 옵션을 어떻게 줄 것인가? assembler 옵션을 어떻게 줄 것인가? linker 옵션을 어떻게 줄 것인가? 스탠다드 라이브러리는 무엇을 쓸 것인가? 어떤 형태의 라이브러리 또는 실행파일을 빌드할 것인가? 어떤 빌드 시스템을 생성할 것인가? 여기에 크로스 컴파일을 위해서 추가적으로 고려해야 하는 점은 다음과 같아요. 빌드 툴채인마다 다른 컴파일러, 어셈블러, 링커 옵션들 : 왜냐하면, gcc와 clang, MSVC에 따라 컴파일러 옵션의 컨벤션과 키워드가 다릅니다. *따라서 CMake에서 컴파일 옵션을 문자열로 주면 특정 컴파일러에서만 동작할 리스크가 있습니다. 예로 들어, “-std=c++11” *CMake에서는 컴파일에 상관없이 표준화된 인터페이스를 제공하기 위해 가급적으로 CMake에서 제공되는 feature로 이러한 옵션을 정의하기를 권장하는 추세죠. 다만, 아직까지 완벽하지는 않습니다. 다음은 CMake에서 지원하는 feature 옵션 함수에요. target_compile_features(myTarget PUBLIC cxx_variadic_templates cxx_nullptr PRIVATE cxx_lambdas )   위와 같은 입력은 다음처럼 CMake의 커맨드 또는 파일에 매핑될 수 있어요.   이렇게 보면 CMake의 각각의 커맨드가 어떤 역할을 하는지 명확하지 않나요?   CMakeLists.txt에서는, add_library로 내가 정한 이름으로 target 객체를 생성합니다. 그리고 이 추가된 타겟 객체에 target_compile_options, target_compile_features, target_include_directories 명령어를 호출하여 컴파일 옵션, 컴파일 기능, 그리고 헤더파일을 추가하죠.   cmake명령어의 옵션 중 DCMAKE_TOOLCHAIN_FILE에 툴채인 파일을 넘깁니다. 마찬가지로 -G 옵션을 추가해서 빌드시스템 타입을 정의합니다. 다만 Make 빌드시스템은 기본값으로 설정되어 있어서 -G 옵션을 줄 필요가 없습니다.   타겟이란? 계속해서 “타겟”이라는 단어를 언급했는데, CMake와 빌드시스템 등을 이해할 때 가장 핵심이 되는 것은 위에서 얘기한 빌드에 대한 이해도와 타겟의 개념이에요.   타겟은 빌드의 최소 단위에요. 그리고 그 빌드의 최소가 되는 단위를 만드는 CMake command는 아래처럼 딱 3개 뿐입니다.   add_library. 옵션은 OBJECT, STATIC, SHARED add_executable add_custom_target   CMake Process file:///Users/gaudio-el/Downloads/wilson-dev-blog/Untitled/Untitled/Native%20C%20C%20WebAssembly/CMake.html그러면 CMake는 입력들을 받아서 어떤 프로세스를 거칠까요?   위에 다이어그램에 표시되어 있듯이, 크게 2개 프로세스로 구분됩니다. Configure Step Generate Step “Configure Step” 때는 CMakeCache.txt파일이 생성됩니다. 이 CMakeCache.txt파일에는 다음이 정의되어 있습니다. 컴파일러, 아카이버, 링커 경로 C,C++ 컴파일러 옵션 유저가 정의한 변수 그리고 이 파일이 이미 있으면, CMake는 “Build System”을 생성하는 Generate 스텝으로 바로 넘어갑니다.   빌드시스템을 한 번 생성하면 부분 컴파일을 지원하기 때문에, 소스를 수정하고 빌드해도 변경된 소스만 재컴파일합니다.   그러나, CMake로 빌드시스템을 재생성하게 되면 전체 파일을 다시 컴파일해야 하기 때문에 효율적이지 않습니다.   따라서 개발할 때는 최대한 빌드시스템을 재생성하는 것을 지양해야 하는데, 문제는 “그러면 언제 빌드시스템을 재생성해야 하는가?”입니다.   CMakeCache.txt파일을 재생성해야 하는 경우가 그렇습니다. CMakeCache.txt는 언제 재생성해야 할까요?   Modern CMake 앞에서 설명한커맨드와 개념들은 CMake의 지향점을 기준으로 설명된 내용입니다. 따라서 막상 CMake로 구성된 오픈소스 프로젝트를 접하게 되면, 위에서 사용하는 커맨드와는 다른 방식으로 구현된 것을 자주 보시게 될 것입니다.   CMake도 긴 역사를 가지고 있습니다. 그 과정 속에서 언어도 많은 변천을 겪었죠. 이전에 사용하던 커맨드들은 여러가지 문제점을 야기했는데, 첫 번째로 CMakeLists.txt 파일에 정의된 변수의 스코프가 항상 글로벌로 설정되어, 타겟을 여러 개 정의하는 프로젝트에서 알 수 없는 사이드 이펙트를 발생하게 되는 것입니다. 두 번째로는, 특정 툴채인에 의존성이 강하기 때문에, 컴파일러가 바뀌거나, 빌드시스템이 변경될 경우 작성한 CMakeLists.txt파일이 정상동작하지 않는 상황이 오는 것이죠. 예를 들어, 컴파일 옵션으로 “-std=c++11″처럼 하드코딩된 문자열 형태로 값을 설정하는 경우, 컴파일러가 변경되면 옵션 문법이 달라지면서 동작하지 않는 경우가 있다. 또한 CMake로 생성된 make 빌드시스템을 make 명령어로 빌드하는 것은 make빌드시스템에 대한 의존성을 만들어서 차후 다른 빌드시스템으로 변경할 때 코스트가 따르기 마련이다. 그래서 다음처럼 cmake를 이용해서 빌드명령을 하는 것이 더 유연한 방법이다. cmake --build . 이처럼 현재 CMake문법은 과도기에 있다고 볼 수 있고, 레거시 문법과 현대 문법이 공존하는 상황이라 개발자에게 혼란을 주고 있는 상황이죠. 다행히도, 이러한 문제점을 해결하여 많은 개발자들이 좀 더 모듈화된 CMake 프로젝트를 운영하도록 돕고자 “Effective Modern CMake”라는 발표를 하고 좋은 문법을 공유하려는 시도가 있었습니다. 아래는 그 내용을 요약한 글입니다.    FAQ LLVM을 이용하면 윈도우용 라이브러리도 빌드할 수 있을까요? 이론적으로는 가능하지만, 아직 해결해야 할 난제들이 몇 개 있는 상황이라네요. 그 문제들은 다음과 같아요. 플랫폼 라이브러리와 헤더가 필요합니다. 즉 윈도우 라이브러리와 헤더가 있어야 라이브러리를 빌드할 수 있습니다. 일반적으로 LLVM 프로젝트는 lld라는 링커를 포함하고 이 링커는 크로스플랫폼 링커라고 하네요. 이 링커를 사용한다면, 문제가 없겠지만, OSX에서는 아직도 Clang 링커로 ld를 사용하고 있다네요. 마찬가지로 윈도우 Clang도 기본값으로 link.exe 가 사용된다고 합니다.   참고로 예전에는 C++ name mangling와 RTTI 지원 이슈가 있었지만 요즘에는 해결됐다고 하네요. Linux 에서 윈도우용 라이브러리를 빌드하고 싶다면 어떻게 해야 하는가? 다른 컴파일러로 빌드하고 싶을 때 고려해야 하는 요인은 다음과 같습니다. 타겟플랫폼의 라이브러리, executable 파일 포맷을 컴파일러에서 지원하는가? 플랫폼 라이브러리와 헤더가 있는가? C Runtime Library가 있는가? GCC는 윈도우용 라이브러리 포맷을 지원하지만, 플랫폼 라이브러리와 헤더는 지원하지 않습니다. 따라서, MingW 또는 MingW-w64에서 지원하는 플랫폼 라이브러리를 가져와야 합니다.     레퍼런스 Compilation The C++ compilation process  What Every Computer Programmer Should Know About Windows API, CRT, and the Standard C++ Library – CodeProject https://www.codeproject.com/Articles/22642/What-Every-Computer-Programmer-Should-Know-About-W dll – Difference between load-time dynamic linking and run-time dynamic linking – Stack Overflow https://stackoverflow.com/questions/2055840/difference-between-load-time-dynamic-linking-and-run-time-dynamic-linking c++ – How does the Import Library work? Details? – Stack Overflow https://stackoverflow.com/questions/3573475/how-does-the-import-library-work-details Clang C++ Cross Compiler – Generating Windows Executable from Mac OS X – Stack Overflow https://stackoverflow.com/questions/23248989/clang-c-cross-compiler-generating-windows-executable-from-mac-os-x Are C++ applications cross-platform? – Stack Overflow https://stackoverflow.com/questions/33238345/are-c-applications-cross-platform   Object Codes compilation – What’s an object file in C? – Stack Overflow https://stackoverflow.com/questions/7718299/whats-an-object-file-in-c Compiler Design | Introduction of Object Code – GeeksforGeeks https://www.geeksforgeeks.org/compiler-design-introduction-object-code/ Object Files and Symbols – Nick Desaulniers http://nickdesaulniers.github.io/blog/2016/08/13/object-files-and-symbols/ Demangling C++ Symbols https://fitzgeraldnick.com/2017/02/22/cpp-demangle.html   Windows MinGW & MinGW-w64  Cygwin vs MinGW · snowdeer’s Code Holic http://snowdeer.github.io/c++/2017/07/16/cygwin-vs-mingw/ windows minimalist Cygwin과 MinGW의 차이점은 무엇입니까? / not working https://src-bin.com/ko/q/bc6ac   Web Assembly란? WebAssembly https://webassembly.org/ Creating WebAssembly-powered library for modern web – By https://hackernoon.com/creating-webassembly-powered-library-for-modern-web-846da334f8fc 웹어셈블리 | MDN https://developer.mozilla.org/ko/docs/WebAssembly WebAssembly, the Journey — What is WASM? – By https://hackernoon.com/webassembly-the-journey-what-is-wasm-caf9871108aa  

2019.10.22