▷ 0 A.D. 게임 프로젝트의 <main.cpp> 파일에 아래와 같은 코드가 있었다. main.cpp 파일은 그 이름이 임시하듯이 실행 파일(exe)로 빌드되도록 vcxproj 빌드 파일에 설정되어 있었다.
▷ 우선 이 코드 자체는 AMD나 NVIDIA가 개발한 그래픽 카드(전자는 라데온 시리즈, 후자는 RTX 시리즈가 유명하다)를 선택할 수 있도록 각 회사의 공식 문서에서 개발자에게 요구하는 코드다. 정확한 목적은 이 애플리케이션(게임)이 내장 그래픽 카드가 아니라 외장 그래픽 카드를 사용하도록 만드는 것이다.
▷ NVIDIA와 AMD에서 관련된 사항을 구글링해서 알아본 결과, 아래와 같이 Executable 파일에 코드를 삽입하면 런타임에 그래픽 카드 드라이버가 실행파일의 변수를 검색하여 그 값을 확인한 뒤에 내장/외장 그래픽 카드를 선택해서 렌더링한다고 말하고 있다.
▷ 보통 외장 그래픽 카드를 AMD/NVIDIA 둘 중 하나를 사용하는 경우가 많으니 두 요청 사항을 동시에 만족할 수 있도록 0 A.D. 게임 프로젝트가 아래와 같이 두 가지 변수를 모두 넣은 코드를 짠 것이라 추측할 수 있다.
▷ extern "C" 라는 키워드가 있는데, 이것은 C++ 컴파일러 특유의 네임 맹글링(Name Wangling)을 방지하도록 조치한 것이다. C++ 컴파일러는 함수나 변수의 이름을 규칙에 따라(컴파일러마다 다름) 이름을 바꾼다. 이렇게 해서 네임스페이스나 함수 오버로딩을 멋지게 중복을 피해 처리하는 것이다. 그러나 이렇게 하면 외부 모듈에서 이 변수나 함수를 참조하고 싶을 때 이름을 가지고 찾을 수 없으므로 extern "C"를 붙인 것이다. C 스타일로 코딩하면 맹글링을 하지 않는다는 점에서 따온 키워드다. 따라서 NvOptimusEnablement와 같은 변수는 외부에서 이 이름 그대로 참조할 수 있다.
▷ __declspec(dllexport) 키워드는 외부에 제공할 변수나 함수를 공개(export)할 때 사용된다. DLL 동적 라이브러리 빌드 시, 이 키워드를 써야만 외부에서 검색하고 사용할 수 있다.
▷ 따라서 AMD와 NVIDIA 그래픽카드 디바이스 드라이버가 파일에서 위 변수를 이름 그대로 검색해 그 값을 가져와서 무언가 처리할 수 있는 것이다. 오픈소스 코드에서는 1 값이 들어있는데, 이것은 외장 그래픽 카드를 사용하라는 뜻이다. 실제로 나는 이 게임을 빌드해서 플레이하고 있는데 NVIDIA의 외장 그래픽카드가 잘 돌아간다.
▷ 하지만 이 포스팅의 핵심은 그래픽 디바이스가 아니다. 내가 이 포스팅을 통해 정리하려는 내용은 바로 __declspec(dllexport)의 독특한 쓰임새였다. 왜냐하면 나는 이 키워드를 동적 라이브러리를 만들 때 배웠기 때문이다.
▷ 이 키워드는 보통 dll 동적 라이브러리를 만들 때 함수나 변수 앞에 붙여서 외부 모듈이 내가 만든 동적 라이브러리의 함수를 호출할 수 있도록 하는 문법이다. 그런데 정작 이 키워드를 dll이 아닌 executable 파일을 빌드하는 소스코드에 넣어서 헷갈리기 시작했다.
▷ 실행 파일에 이걸 넣어도 되나 싶었다. 이름 자체가 dllexport인데, DLL이 아니라 exe(PE) 파일을 만드려는 소스코드에 작성해도 되는건가 싶었다. 놀랍게도 이 키워드는 DLL과 상관 없이 실행 파일에도 작성해서 넣을 수가 있다..! 문법적으로 오류도 없다.
▷ Windows에서 빌드되는 executable 파일인 PE 포맷을 보면 실행 파일이어도 export table이 정의될 수 있음을 확인할 수 있었다.
▷ 실제로 0 A.D. 게임의 실행 파일을 PE 뷰어로 보면 아래와 같이 특정 변수를 이름 그대로 검색해서 활용할 수 있는 테이블이 검색된다. (구체적인 실행 방법은 자세히 모르겠지만, 어쨌든 활용 가능한 형태로 외부에서 참조될 수 있는 테이블이 생성된다는 것이 중요하다)
▷ dllexport 라는 단어에서 DLL에 내가 속았던 것 같다. 어쨌든 결론은 꼭 DLL 동적 라이브러리뿐만이 아니라, executable 실행 파일에도 declspec(dllexport) 키워드를 사용해 외부의 다른 모듈이 이름을 검색해서 값을 가져올 수 있다는 것이다.
Can a standard executable have an export table?
I have an executable written in C that has some functions in it that I would like to use from a c# application. I have written plenty of dlls before and was able to use functions in them by prepend...
stackoverflow.com
참고자료...
'IT 공부 > C, C++' 카테고리의 다른 글
[C/C++] - 크로스 플랫폼 오픈소스 라이브러리에서 OS 종속적인 부분은 어떻게? (공부 중...) (0) | 2025.01.01 |
---|---|
[C/C++] - int main() 함수에 extern "C" ?? (1) | 2024.12.31 |
[C언어] - 왜 long 타입은 windows에서만 32bit인가? (0) | 2024.12.29 |
[C언어] - 헤더 파일이 필요한 이유 (1) | 2024.12.27 |
[C언어] - C언어의 이식성에 대해 정리 (1) | 2024.12.26 |