ko
ko
가우딘, 전체보기

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

윌슨의 개발지식

개발환경과 빌드(1)

개발환경과 빌드는 도메인마다 다 다르고, 복잡해 보이기 때문에 접근하려고 마음 먹기 전에 두려움이 먼저 자리 잡는 것 같아요. 이러한 새로운 개발환경을 처음 접할 때 가장 어려운 부분은 전체 시스템에 대한 이해가 완벽하지 않기 때문에, 한 수 한 수 둘 때마다 이것이 어떠한 사이드 이펙트를 만들지에 대해서 불안감과 두려움이 먼저 생긴다는 것이죠. 전체 시스템에 대해서 확신을 가지고 있는 누군가가 옆에서 불확실하다고 여겨질 때마다, 확신을 준다면, 배움의 속도도 빨라지고, 응용의 속도도 빨라질 것 같다는 생각이 들었습니다.

그래서 도메인 별로 개발환경에 대해서 한 번 정리하고 많은 분들이 불안한 마음으로 다루고 있는 빌드 시스템에 대해서 알리고자 이 문서를 기획했습니다.

Native C,C++,WebAssembly 빌드

바라건대, 이 문서를 읽고 새로운 타겟 플랫폼에 대한 빌드 요청이 들어 왔을 때, 기반이 되는 개념모델을 활용하여 유연하게 문제를 해결해 나갈 수 있었으면 합니다. 🙂

컴파일이란?

작성된 소스 파일들을 특정 플랫폼(런타임)에서 이해할 수 있는 언어(일반적으로 기계어에 가까운 언어를 지칭)로 변환하는 프로세스에요.

플랫폼이란?

플랫폼이라는 용어는 일반적으로 “아키텍쳐“와 그 위에 올라오는 “운영체제” 쌍을 의미합니다. 그러나 최근에는 좀 더 의미가 확장되어 운영체제 위에 “소프트웨어“가 추가된 형태로 얘기되는 것 같아요. 저는 좀 더 일반적으로 생각하기 위해서 “소프트웨어 또는 라이브러리가 실행될 수 있는 환경을 위한 조건“이라는 개념을 가지고 있되, 컨텍스트에 따라서 해석하고는 합니다. 예로 들어, C++환경에서는, “아키텍쳐-OS”로 생각하는 것이죠.

빌드란?

특정 플랫폼의 빌드머신에서, 타겟 플랫폼의 런타임 위에서 동작하는 프로그램이나 사용할 수 있는 플러그인, 프레임워크, 라이브러리, SDK 등을 제작하는 프로세스. 일반적으로 컴파일 과정을 포함해요.

그러면 크로스플랫폼 빌드란?

특정 플랫폼의 빌드머신에서,하나 이상의 다양한 타겟 플랫폼의 런타임 위에서 동작하는 프로그램이나 플러그인, 프레임워크, 라이브러리, SDK 등을 생산하는 프로세스.

런타임

이렇게 프로그램이 실행될 수 있는 환경을 실행환경(이것도 결국 프로그램), 즉 Runtime Environment라고 합니다. 예로, Java는 해당 OS에 설치된 JRE(=Java Runtime Environment)라는 프로그램 위에서 자바의 IR 코드가 컴파일되어 실행되는 것이죠.

그러면 C++ 컴파일이란?

컴파일 프로세스

  • 오브젝트 파일 컴파일

정적 라이브러리나 실행파일을 빌드한다고 해도 기본적으로 오브젝트 파일부터 컴파일을 마치고 그 결과물이 입력이 되어 정적 라이브러리나 실행파일 컴파일이 진행됩니다. 따라서 가장 기본이 되는 것은 C/C++ 컴파일 과정이라고 볼 수 있는데, 크게 다음의 과정으로 진행됩니다.

  1. 전처리

    이 과정은 전처리매크로(Pre-processor Macro)를 읽고 처리하는 과정입니다. 가장 많이 알고 있고 많이 쓰는 전처리 매크로는 다음과 같아요.

    #include 

    컴파일러가 위 전처리 매크로를 만나면 hello.h 파일을 읽어서 #include한 .cpp파일에 복붙합니다.

  1. 컴파일

    전처리 과정을 거친 소스파일(.i)들은 컴파일 과정을 거치면서 어셈블리로 출력됩니다. 이 과정을 수행하는 툴채인 프로그램이 compiler입니다. 이 단계가 마지막 Human Readable한 코드에요. 그리고 이 단계에서 Architecture 인스트럭션으로 코드가 생산됩니다. 즉, 어셈블리 코드는 타겟 아키텍쳐에 dependant합니다. *참고로 Assembly라는 용어는 일반적으로 기계어에 가장 가까운 Human Readable한 코드를 말한다고 하네요.

  1. 어셈블

    컴파일을 거쳐서 나온 어셈블리 파일들을 어셈블하면 최종적으로 머신코드인 오브젝트 코드 파일(.o)들이 생성됩니다. 이 과정은 assembler가 수행합니다.

  • 오브젝트 코드란?

오브젝트 코드는 기계가 이해할 수 있는 코드로 구조는 위 그림과 같아요.

여기서 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” 에러가 이 때 발생(아래 스크린샷 참고)하죠.

툴체인이란?

개발용 프로그램 도구 집합을 툴체인이라고 하는데요. 툴체인이라고 부르는 이유는 한 프로그램 출력이 다른 프로그램의 입력이 되어 서로 체인처럼 연결되어 실행되기 때문이라네요. 컴파일러의 출력은 어셈블러의 입력이 되고 어셈블러의 출력은 아카이버의 입력이 되는 것처럼 말이죠.

컴파일러 툴체인 생산자

컴파일러 툴채인의 생산자는 크게 2개로 나뉘어 집니다.

  • GNU의 GCC
  • LLVM Developer Group의 LLVM(Low Level Virtual Machine)

두 생산자의 차이점을 이해하려면 컴파일러의 구조를 이해해야 해요. 전통적으로 컴파일러의 구조는 아래처럼 “3 Phase Design”을 따르고 있다네요.

문제는 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이 필요할까요?

  • 어떤 툴채인을 사용하는가?
    • 어떤 compiler를 사용하는가?
    • 어떤 assembler를 사용하는가?
    • 어떤 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개 프로세스로 구분됩니다.

  1. Configure Step
  1. Generate Step

“Configure Step” 때는 CMakeCache.txt파일이 생성됩니다. 이 CMakeCache.txt파일에는 다음이 정의되어 있습니다.

  • 컴파일러, 아카이버, 링커 경로
  • C,C++ 컴파일러 옵션
  • 유저가 정의한 변수

그리고 이 파일이 이미 있으면, CMake는 “Build System”을 생성하는 Generate 스텝으로 바로 넘어갑니다.

빌드시스템을 한 번 생성하면 부분 컴파일을 지원하기 때문에, 소스를 수정하고 빌드해도 변경된 소스만 재컴파일합니다.

그러나, CMake로 빌드시스템을 재생성하게 되면 전체 파일을 다시 컴파일해야 하기 때문에 효율적이지 않습니다.

따라서 개발할 때는 최대한 빌드시스템을 재생성하는 것을 지양해야 하는데, 문제는 “그러면 언제 빌드시스템을 재생성해야 하는가?”입니다.

CMakeCache.txt파일을 재생성해야 하는 경우가 그렇습니다. CMakeCache.txt는 언제 재생성해야 할까요? CMakeCache

더 자세한 CMake 명령어와 팁들을 보려면 아래를 참고한다.

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
Object Codes
Windows
Web Assembly란?
2 Comments
  • 앤드류
    11:54 오전, 11월 2019

    CMake와 전체빌드 시스템을 이해하는데 많은 도움이 됩니다. 감사합니다.

  • Andrew
    11:55 오전, 11월 2019

    CMake와 전체빌드 시스템을 이해하는데 많은 도움이 됩니다. 감사합니다.

댓글 남기기

이메일은 공개되지 않습니다. 필수 입력창은 * 로 표시되어 있습니다

Privacy Settings
We use cookies to enhance your experience while using our website. If you are using our Services via a browser you can restrict, block or remove cookies through your web browser settings. We also use content and scripts from third parties that may use tracking technologies. You can selectively provide your consent below to allow such third party embeds. For complete information about the cookies we use, data we collect and how we process them, please check our Privacy Policy
Youtube
Consent to display content from Youtube
Vimeo
Consent to display content from Vimeo
Google Maps
Consent to display content from Google
Spotify
Consent to display content from Spotify
Sound Cloud
Consent to display content from Sound