너무나 막막합니다...C++프로그램의 임베디드화... 도움을 부탁드립니다...

scan15g의 이미지

안녕하세요.

저는 전기,컴퓨터 공학을 공부하고 있는 대학원생 입니다.
저는 C언어는 많이 접해 보았지만, C++언어를 잘 알지 못하며, C++의 새로운 코드를 만나면 책과 인터넷을 찾아가면서 C++ 코드를 해석하고 이미 존재하는 코드를 수정할 수 있는 정도의 수준입니다.
또한, 처음부터 대형 프로그램을 작성해 본적이 없어서 여러개의 파일들을 리눅스 환경에서 컴파일 하며 필요한 라이브러리와 헤더파일을 찾아 링킹하는 경험이 거의 전무합니다.
거의 for, if, while로 이루어진 충실한 기본 C 스타일의 프로그램만을 작성하고 수정해 왔으며, 가끔 동적 메모리 할당이 나오면 머리 아파하는 정도의 학생 입니다.
그리고 대형 프로그램을 만질 때에는 다른 사람들이 환경을 Make 파일로 잘 정의해 놓은 코드에서 내부를 수정하고 코드를 추가하는 일만 많이 해 보았습니다.

이런 저에게,
최근 제가 전혀 경험해 보지 못한, 그리고 어떻게 진행 해 나가야 할지 전혀 앞이 보이지 않는 일이 주어졌습니다.

그 일은 바로
"잘 짜여진 C++ 프로그램을 임베디드 환경에서 실행할 수 있도록 하라."
였습니다.
여기서 말하는 C++ 프로그램은 수십 개의 클래스를 가지고 있고 긴밀한 상속으로 얽혀 있으며 C++의 다양한 라이브러리들(vector, linked list등)을 사용하여 잘 짜여진 수십개의 파일들과 수만여 줄의 코드로 이루어진 프로그램 입니다.
(HM이라는 최근 표준화가 완료된 새로운 동영상 압축 표준 HEVC, H.265 의 인코딩/디코딩 소프트웨어 입니다.)

제가 C++을 해석하는 정도의 능력만 가지고 있기 때문에, 잘 짜여진 프로그램인 HM은 해석 하기에도 가끔 벅찰 때가 있었습니다.
그런데, 이 프로그램을 임베디드 환경에서 실행할 수 있는 프로그램으로 바꾸라는 지시가 떨어졌습니다.

제 보스가 생각하는 임베디드 환경은 C++코드를 실행 하기에는 거의 불가능 하기 떄문에 C++을 사용할 수는 없다. 입니다.
그래서 가장 처음에 떨어진 지시는 "C++ 코드를 C 코드로 변환하라" 였습니다.

처음 생각에는
"C++ 코드 C 로 바꾸는거 까짓거 클래스를 구조체로 변환하고 멤버함수는 전역 함수로 바꾸고... 하면 되겠지."
였습니다.
그러나 저의 무식에서 온 큰 오산이었습니다. C++ 코드를 잘 들여다 보니, C와는 훨씬 더 상위레벨의 추상화개념과 지원하는 다양한 라이브러리로 소프트웨어를 사용하는데에는 정말 편리했지만, C언어로 이를 바꾼 다는 것은 정말 막막해 보였습니다.
몇 가지 짧은 지식으로 보이는 어려운 점 들을 나열해 보겠습니다.

1. 상속 관계 :
상속이 계층 구조로 이루어져있어서, 구조체를 만들 경우에는 상속의 윗단 클래스는 점점 덩치가 커져가는점이 있었습니다. 또한 생성자에 있는 가상 함수는 낯선 개념인 데다가 구조체로 갈 때는 어떻게 해야 할 지 막막했습니다.

2. 중간 검증의 불가능 :
서로 호출하는 구조와 상속이 긴밀한 코드로 만일 특정 클래스를 구조체로 바꾸게 되면 구조체로 된 클래스를 참조하는, 그리고 상속하는 다른 클래스들에 대한 영향이 전파되는 구조라서, 일부만 바꾸고 동작시켜 정상 동작하는지 알아볼 방법이 없었습니다.

3. C++ 라이브러리 :
라이브러리라는 개념 자체가 제게는 사용해 본 경험이 없었고(iostream, stdio 정도만 헤더로 사용하고 다른 헤더는 이미 인클루드 된 코드를 사용해 왔기 때문에),
C++ 라이브러리는 제게 낯선 것 이었습니다. 메모리 관리를 편리하게 하려는 vector, C언어를 배울 때 직접 고생하면서 구현했던 linked list 등...이러한 것들이 그냥 라이브러리로 편리하게 사용되어 있는 것 입니다.
만일 이를 C로 바꾸려 한다면 제가 직접 라이브러리를 해석해서 C 코드로 구현해 넣어야 하는 것인가에 대한 막막한 고민을 하게 되었습니다.

4. 많은 파일들을 묶어서 새로운 프로젝트 생성에 대한 어려움 :
저는 많은 파일들로 이루어진 프로그램을 다루어 본 적이 없습니다. 자신이 처음 부터 고민해 가면서 파일을 하나 둘 늘려갔다면 제가 익숙해져 있겠지만,
이미 여러개의 파일들로 이루어진 프로그램을 각 파일 단위로 수정해 왔기 때문에 이에 대한 경험이 전무합니다.
그래서 Make에 관한 책들도 닥치는 대로 찾아다가 읽어 보고 gcc 컴파일러, 링커 스크립트, 바이너리 유틸리티에 관한 내용을 찾아보려 애썼지만,
단기간(1~2주)동안 원하는 대로 프로젝트를 만들고 파일을 링킹하고 라이브러리를 링킹하는 방법을 현재까지는 알 수 없었습니다.

그래서 제가 나름대로 돌파구를 찾아 보려고 C++를 지원하는 임베디드 환경을 구성할 수 있는지 사례를 찾아보고 직접 간단한 C++ 프로그램을 올려 돌려보는 일을 시작했습니다.

1. opencore에서 무료로 배포하는 openrisc 1200 환경을 세팅하였습니다.
openrisc와 가상의 SRAM을 연결하여 CPU와 메모리가 있는 시뮬레이션 환경을 만들었습니다. 그리고 openrisc를 위한 바이너리를 생성하기 위해 opencore에서 제공하는
크로스 컴파일러를 어렵게 설치하여 gcc, g++, ld 등의 컴파일, 링커 도구를 준비했으며 이를 이용해서 예제가 있는 간단한 C 프로그램을 시뮬레이션하는데에 성공했습니다.

2. openrisc 환경에서 C++ 프로그램을 수행하기 위한 방법을 찾아다녔습니다.
크로스 컴파일러와 링커를 사용하여 간단한 C 프로그램을 실행하기 위해 노력했습니다.
여태까지 make 명령어만 치면 제가 수정한 프로그램이 간단하게 실행 파일로 나타났기 때문에, 컴파일, 링킹, 라이브러리와 같은 것들은 너무나 생소했습니다.
개별 파일을 컴파일 하는 것에서 부터 라이브러리를 찾아서 헤매였고, 컴파일 옵션과 명령어를 몰라 찾는데 시간을 소비했으며, 링킹 과정에서는 더욱 많은
라이브러리를 링킹하지 않은데에서 오는 에러 메세지와의 싸움 이었습니다.
그리고 일반적인 컴퓨터 상의 프로그램과 가장 달라서 막막했던 점은 바로 메모리에 내가 짠 프로그램과을 올리는 과정에 신경을 써 주어야 한다는 것 이었습니다.
예제로 구한 부트로더 어셈블리 파일에서 main 함수로 점프하여 프로그램을 수행할 수 있는 환경을 만들었습니다. 이 과정부터 시작하여 저는 계속 제가 멍청하다는 생각을 하게 되었습니다.
특히 링커 스크립트라는 녀석은 저를 계속 괴롭혔습니다. OS가 있는 환경에서는 굳이 링커 스크립트를 신경 쓰지 않아도 괜찮았던 것 같은데, 임베디드 환경은 그게 아니었습니다.
어찌어찌 에러 메세지와 싸워 가면서 인터넷에서 본 단편적 지식들로 예제 링커 스크립트를 수정하여 간단한 행렬 연산을 수행하는 C 프로그램을 돌려보았습니다.
별다른 라이브러리를 사용하지 않았고 오직 for, if, 배열 로만 이루어진 프로그램이었습니다.
그래서 다음 과정으로 간단한 C++ 프로그램을 수행해 보자 였습니다. 상속 개념을 이해하는데 사용되는 채 50줄 남짓의 예제 코드였습니다.
그런데 여기서 부터 본격적으로 좌절스런 시간이 시작됐습니다.
링킹과정에서 계속되는 라이브러리 필요 에러 메세지를 인터넷과 컴퓨터를 뒤져가면서 연결해 주었더니, 예상치 못한 에러가 나는 것 이었습니다. 이 에러에 대한 질문으로 가는 링크가 이 글 가장 마지막 있습니다.

지금 C++ 코드가 필요로하는 라이브러리를 어떻게 찾아서 링킹을 시켜주며, 또한 필요한 헤더 파일들을 어떻게 찾아 인클루드 해 주는지에 대한 지식이 전무했던 저는,
달랑 50줄 짜리 간단한 C++코드도 제대로 올리지 못하는데 어떻게 수만여 줄과 각종 C++ 표준 라이브러리를 사용한 프로그램을 임베디드 환경에 올릴수 있을지에 대한 좌절감을 느꼈습니다.

현재 제 머릿속에는 C++을 임베디드 환경에 올리는 것은 남들이 안하는 것이니 나도 하지 말자는 식으로 거의 포기하려는 생각까지 다다랐습니다.
왜냐하면 복잡한 C++프로그램에 사용된 라이브러리를 임베디드 크로스컴파일러가 모두 지원 하는지도 의문이며, 그 라이브러리들이 왜 사용됐는지 이해하는 것 조차 너무 막막했기 때문입니다.
차라리 처음 생각처럼 C++코드를 기계적으로 C로 바꾸는 데에 큰 노력을 들일까도 생각하게되었습니다.
한편으로는 C++ 코드의 내용을 모조리 이해해 버리고 제가 처음부터 C로 다시 작성해 볼까도 생각하지만, 실현 가능성은 너무나 낮습니다.

부족한 제가 생각할 수 있는 해결책과 그 고민들은 위와 같습니다.
누군가 이런 일을 경험 해 보신분, C++ 코드를 임베디드 환경에서 실행 하기 위해서는 어쩔 수 없이 C 코드로 일일이 수작업을 하는 방법밖에는 없는 것인지,
이 상황을 헤쳐나갈 수 있는 다른 방법, 임베디드환경에 C++ 프로그램을 수행하기 위한 과정과 팁을
이곳에 계신 경험을 가진 개발자 여러분들게 감히 여쭈어 봅니다.

어떤 말씀 이시든지 좋습니다. 부족한 저에게 간단한 키워드라도 주시면 구글링과 책을 읽어 공부라도 해 보려고 합니다.

제가 이곳 kldp에서 돌파구와 자신감을 찾아나갈 수 있다면 정말 좋겠습니다.

긴 글 읽어 주셔서 감사합니다.

P.S. 저의 질문을 포럼에 올려 두었습니다. 링크 --> http://kldp.org/node/137189

empty2fill의 이미지

"제 보스가 생각하는 임베디드 환경은 C++코드를 실행 하기에는 거의 불가능 하기 떄문에 C++을 사용할 수는 없다. 입니다."

거의 불가능 하다는 것이 어떤 뜻 인가요?

C++의 성능 문제로 사용하기 힘들다는 이야기 인가요. 아니면 지원이 안돼 실행할 수 없다는 것인가요.

그리고 프로그램이 실행될 임베디드 환경이 구체적으로 어떻게 되나요?

임베디드 환경이 결정된 것이 아니라면 구현 언어를 바꾸기 보단 C++을 지원하는 임베디드 환경 찾아보는 것이 쉬울 듯 싶네요.
(임베디드도 응용에 따라 다르지만 C++을 지원하는 환경도 많이 있습니다)

일이 안풀린 때는 당연하게 생각하고 있는 가정이나 전제를 바꿔보세요.

——
———
Life is a tragedy when seen in close-up, but a comedy in long-shot. - Chaplin, Charlie -

scan15g의 이미지

이전에는 임베디드 환경에 C로된 코드를 올리는 작업을 해 본적이있다고 합니다. 그래서 이전에 해 본 환경에 동일한 방법으로 진행하려고 C로 프로그램을바꾸려 하는거죠...

그게 몇년 전이었다고 합니다. 당시에는 C++ 을 지원하는 환경이 없었다고 합니다...

현재는 어떤건지 사실 아는 사람이 없습니다.
어느 환경이 어느정도까지 C++를 지원 하는 지...

그래서 오픈리스크 라는 cpu에서 크로스 컴파일을 시도하고있지만 처음 하는 일이고 막막해서, 누군가 C++를 오픈리스크가 지원 한다 안한다 만이라고 알려주면 좋겠습니다 ㅠㅜ

klyx의 이미지

C를 이용하여 상속이나 가상함수등을 구현하는 법은 이미 잘 알려져 있으므로 그리 어려운 일이 아닙니다.
개인적으로는 그보다 생성자와 소멸자를 수동으로 구현해야하는데, 이걸 빠짐없이 할수 있는가가 걱정되네요.
손으로 일일이 생성자와 소멸자를 호출해준다면 스택에 올라간 객체들을 모두 찾아서 스코프가 끝나는 지점을 찾아서 소멸자를 불러줘야하는데, 이게 사람이 실수없이 할수 있는일일까요?

직접 자동 변환 코드를 만들겠다면, 그건 사실상 C++파서를 구현하는거나 마찬가지이므로 추천하지 않습니다.
이미 알려진 자동으로 C++을 C로 바꾸는 방법은 몇가지 존재합니다.
가장 유명한건 Comeau C++일듯합니다. 이는 C++코드를 C로 해석하여 컴파일해줍니다.
또다른 방법으로는 llvm을 이용하는 수가 있습니다.
llvm으로 C++코드를 바이트코드로 변환한후에, 이를 다시 C코드로 변환하면 되는데, 이렇게 해서 생성된 C코드가 인간이 보기 좋은 코드일지는 의문입니다.
구글에서 C++ to C 또는 C++ to C converter 따위로 검색해보면 많은 정보가 나올겁니다.

그런데 그보다 근본적으로 어째서 임베디드에서 C++은 쓸수 없는가, 라는 걸 생각해보시는게 좋을듯합니다.
만약 C++의 코드를 완벽하게 C로 바꿀수 있다고 해도, 거기에서 얻어지는 성능은 전무합니다.
예를 들어 C++의 가상함수가 느리다고해봤자 그걸 일괄적으로 함수포인터로 변경하면 결국 발생하는 오버해드는 동일합니다.
따라서 C++을 쓸수없는(?) 저사양환경에서 C++을 기계적으로 C로 바꾼 코드는 마찬가지로 쓸수없는 코드가 됩니다.
동일한 기능을 하는 코드를 최적화된 C코드로 구현하는게 아니라면, 애당초 쓸데없는 노동력낭비가 될수 있습니다.
그러므로 가장 먼저할 일은 C++코드를 그대로 임베디드에서 돌려보고 성능이 정말 못써먹을정도인지 아닌지를 확인하는거 아닐까요?

scan15g의 이미지

C++ 코드를 C로 바꾸는 일은 너무 문제가 많을 것으로 생각하고있습니다..
사실 C++도 잘 모르는데 바꿀수 있다 없다를 논하는것 자체가 무의미한 것 같습니다...

말씀하신 C++ to C 관련 툴에 대헤 공부해보도록하겠습니다.

그리고 임베디드 환경에서의 성능은 크게 문제가 되지않습니다.
우선 모든 코드를 올려 돌아가는지 확인 한 뒤에 주요 기능은 하드웨어 가속기로 대체할 예정이기 때문에, 올라가는지 라도 확인이 되면 되기 때문입니다.

C++ to C 관련 해서 혹은 C++의 임베디드 환경에서의 실행에 대해 참조할수있는 웹이나 책 등이 너무 찾기힘든 것 같습니다 ㅠㅜ

klyx의 이미지

임베디드라고 해도 요즘은 대부분 C++지원합니다.

http://opencores.org/or1k/OpenRISC_GNU_tool_chain
At present OpenRISC is supported by a 32-bit GNU toolchain offering C and C++ support with static libraries only.

scan15g의 이미지

C++의 정적 라이브러리를 지원한다는 말이,
오픈코어에서 제공하는 크로스컴파일러에 있는 라이브러리 이외에도 제가 자유롭게 리눅스 환경의 어떤 정적 라이브러리도 사용할 수 있다는 뜻인지요...?

불확실한 것이 임베디드에 올리고 싶은 소프트웨어가 다양한 C++ 라이브러리를 사용하고있는데 이를 모두 사용할 수있어야 올리는게 가능하니까요...

크로스컴파일러와 라이브러리에 대한 개념이 제대로 잡혀있지 않아 이런 질문을 드립니다...

klyx의 이미지

그냥 쉽게 생각하세요. 해당 페이지에 근거하면, 제공하는 조건이 C도 C++도 동일하므로 C로 되는건 C++로도 다 됩니다. C++로 안되는건 C로도 안됩니다.
정적라이브러리만 지원되므로 다른 C++ 라이브러리들도 전부 정적 라이브러리로 빌드해서 올릴수 있으면 되는겁니다.

scan15g의 이미지

어떤 C++ 라이브러리라고 해도 정적 라이브러리를 만든 다음에 크로스 컴파일러와 링커로 링킹만 해주면 오픈리스크에서도 사용이 가능하다는 말씀이시군요!

감사합니다.

더불어 죄송합니다만...; 임베디드환경을 위한 컴파일러와 링커에 대한 공부가될만한 책이나 웹이있다면 알려주시면 너무 감사하겠습니다 ㅠㅜ