2021년 10월 6일 수요일

CNN 딥러닝 파라메터에 따른 예측 정확도 변화 확인

이 글은 CNN(Convolution Neural Network) 딥러닝 파라메터에 따른 예측 정확도 변화 확인 결과를 간략히 정리한다. 딥러닝 모델은 파라메터가 어떻게 되느냐에 따라 정확도가 달라진다. 얼마나 차이가 나는지를 확인해 보기 위해, CNN 모델을 정의하고, 파라메터를 조정해 본다. 

기본 모델 정의
기본 모델은 다음과 같다. 이 모델은 주어진 이미지를 2개의 클래스로 구분한다. 
# Our input feature map is 150x150x3: 150x150 for the image pixels, and 3 for
# the three color channels: R, G, and B
img_input = layers.Input(shape=(150, 150, 3))
x = layers.Conv2D(16, 3, activation='relu')(img_input)
x = layers.MaxPooling2D(2)(x)
x = layers.Conv2D(32, 3, activation='relu')(x)
x = layers.MaxPooling2D(2)(x)
x = layers.Conv2D(64, 3, activation='relu')(x)
x = layers.MaxPooling2D(2)(x)
x = layers.Flatten()(x)
x = layers.Dense(512, activation='relu')(x)
output = layers.Dense(1, activation='sigmoid')(x)
model = Model(img_input, output)

실제 학습은 아래 CoLab으로 진행해본다.

대표적인 CNN 분류 예시

모델 파라메터 조정 결과
CNN 커널 크기와 계층수를 변화시켜보도록 한다. 모델 파라메터를 조정한 결과는 다음과 같다.


커널 3계층 표준



커널 크기 증가1



커널 크기 증가2



커널 2계층


커널 4계층
결론
결과는 CNN 필터를 배수로 증가시켜가면서 모델을 추가했을 때 정확도가 높았다. 또한, 커널 계층을 삭제하거나 증가할때 정확도나 손실은 좋아지지 않았다. 이런 파라메터는 입력 데이터 특성 등에 따라 조정해 나가야 한다. 참고로, 이런 노가다는 AutoML같은 최적 모델 선택 도구를 통해 줄일 수 있다.

레퍼런스
  • 텐서플로우 라이트 저장
  • AutoML

2021년 10월 4일 월요일

CDE 개발 지원 오픈소스 BIM 라이브러리 IFC.js 분석 및 사용방법

이 글은 CDE(Common Data Environment) 개발 지원 BIM(Building Information Modeling) 라이브러리 IFC.js 분석 및 사용방법을 간략히 설명한다. IFC는 3차원 건설 정보 모델로 건설 부재의 객체별로 형상과 속성을 저장할 수 있다. 


IFC.js는 최근 개발된 IFC관련 라이브러리로 이를 이용한 개발 사례가 조금씩 나타나고 있다.
IFC.js 활용 BIM-GIS 기반 CityLite 개발 사례

IFC.js 소개
IFC.js는 BIM 개방형 표준파일포맷인 IFC(Industry Foundation Classes)파일을 로딩, 디스플레이 및 편집할 수 있는 자바스크립트 라이브러리이다. 이 라이브러리는 안토니오 곤잘레스(Antonio Gonzalez Viegas)에 의해 개발이 주도되고 있다. 참고로, 그는 스페인 2018년 ETSAS 건축과를 졸업하고, BIM 연구 개발 경험이 많은 디지털 아키텍처이며, 재즈를 좋아한다.
IFC는 읽고 쓰기 어려운 복잡한 포맷이다. 실제 IFC 구조는 다음과 같다. 이 파일 포맷을 해석(parse, 파싱)하기 위한 여러 라이브러리가 이미 오래전부터 있었다. IFC.js는 웹기반으로 동작되는 순수 Javascript와 빠른 렌더링 성능을 지원하는 C++ WASM(Web assembly. 예제)기술을 이용해 개발되었다. 이를 통해 웹브라우져에서도 60 fps까지 렌더링 처리 된다. 그러므로, 스마트폰을 포함한 모든 컴퓨터 디스플레이에서 IFC.js 기능을 사용할 수 있다.

소스코드는 아래 github에 있으며, node, npm으로 실행할 수 있다.

설치
node.js, npm 패키지를 설치한다. 윈도우, 우분투, 리눅스 모두 가능하다.
node.js 설치(윈도우 버전 경우)

우분투 리눅스나 윈도우 파워쉘 터미널에서 아래 명령을 실행한다.
node -v
npm -v

버전이 제대로 출력되면, 아래 명령을 실행한다.
cd web-ifc-viewer
npm i yarn
혹시 설치 안되면, 몇몇 라이브러리와 버전 불일치 발생할 수 있으니 다음 명령으로 설치한다. 
npm install --legacy-peer-deps
npm install --force

실행 화면(터미널)
실행한다.
npm run init-repo
npm run start

다음 링크를 클릭해, 클롬에서 열어본다.
그럼, 다음과 같은 IFC BIM viewer 화면을 확인할 수 있다. 

IFC.js 사용 방법
뷰어에서 왼쪽 side bar에서 파일 열기 메뉴를 통해, IFC 파일을 로딩할 수 있다.

주요 API 사용 방법은 다음과 같다.
// 라이브러리 임포트
import { IfcLoader } from 'web-ifc-three';
import { Scene } from 'three';

// THREE.js scene 생성
const scene = new Scene();

// IFC 로딩 및 scene 추가
const ifcLoader = new IfcLoader();
ifcLoader.load(ifcURL, (geometry) => scene.add(geometry));

이외에 BIM 속성 검색, 자료값 얻기, 섹션 표시 등 다양한 기능을 지원한다.

BIM 뷰어 화면 구조 분석
index.html은 다음과 같이 간단히 정의되어 있다. side bar와 viewer 요소가 정의되어 있다.
<!DOCTYPE html>
<html lang="en">
  <head>
    <link rel="stylesheet" type="text/css" href="./styles.css" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>IFC.js</title>
  </head>
  <body>
    <aside class="side-menu" id="side-menu-left"></aside>
      <div id="viewer-container"></div>
    <script type="module" src="./build/main.js"></script>
  </body>
</html>

화면 구조는 다음과 같다.

대부분의 기능은 main.js 자바스크립트에 구현되어 있다. 
이 main.js는 10만라인이 넘게 구현된 자바스크립트 파일이며, IFC로딩, 렌더링, 이벤트처리, 계산 등 대부분의 기능이 구현되어 있다.
시퀀스 구조 분석
주요 시퀀스 구조는 다음과 같다.
1. HTML 렌더링
2. VIEWER WEBGL 렌더링
3. OPEN FILE 이벤트 발생
4. loadIFC(url)
5. url이 가리키는 파일로 부터 파싱해 IFC element 데이터 구조 생성
6. 렌더링 가속을 위해 IFC element의 geometry 추출하여 메쉬(mesh) 그래픽 구조 생성
7. load 완료 시 scene 렌더링 루프에 추가
8. scene의 geometry의 vertex buffer를 WASM에 전달해 WebGL로 렌더링
 
주요 루틴은 다음과 같다.
class IFCLoader extends Loader {
  load(url, onLoad, onProgress, onError) {
    const scope = this;
    const loader = new FileLoader(scope.manager);
    loader.setPath(scope.path);
    loader.setResponseType('arraybuffer');
    loader.setRequestHeader(scope.requestHeader);
    loader.setWithCredentials(scope.withCredentials);
    loader.load(url, async function (buffer) {

      try {
        onLoad(await scope.parse(buffer));  // 1. IFC 데이터가 있는 buffer를 파싱함
      }
    }, onProgress, onError);
  }

  parse(buffer) {
    return this.ifcManager.parse(buffer);    // 2. ifcManager 객체의 parse 함수 호출
  }
}

async parse(buffer) {   // 파일 구조 해석
  if (this.state.api.wasmModule === undefined)
    await this.state.api.Init();
  await this.newIfcModel(buffer);  // Ifc모델 생성
  this.loadedModels++;
  return this.loadAllGeometry();    // Geometry 정보 해석
}

async loadAllGeometry() {
  await this.saveAllPlacedGeometriesByMaterial();   // Mesh 그래픽 구조 생성
  return this.generateAllGeometriesByMaterial();
}

async saveAllPlacedGeometriesByMaterial() {
  const flatMeshes = await this.state.api.LoadAllGeometry(this.currentWebIfcID);
  for (let i = 0; i < flatMeshes.size(); i++) {
    const flatMesh = flatMeshes.get(i);
    const placedGeom = flatMesh.geometries;
    for (let j = 0; j < placedGeom.size(); j++) {
      await this.savePlacedGeometry(placedGeom.get(j), flatMesh.expressID);
    }
  }
}

이벤트 처리는 다음과 같다.
const loadButton = createSideMenuButton('./resources/folder-icon.svg');
loadButton.addEventListener('click', () => {
  loadButton.blur();
  inputElement.click();  // IFC 파일 열기
});

const sectionButton = createSideMenuButton('./resources/section-plane-down.svg');
sectionButton.addEventListener('click', () => {
  sectionButton.blur();
  viewer.toggleClippingPlanes();  // 클리핑 처리
});

const dropBoxButton = createSideMenuButton('./resources/dropbox-icon.svg');
dropBoxButton.addEventListener('click', () => {
  dropBoxButton.blur();
  viewer.openDropboxWindow();  // 드롭박스 처리
});

const handleKeyDown = (event) => {
  if (event.code === 'Delete') {
    // viewer.removeClippingPlane();
    viewer.dimensions.delete();     // 치수 삭제
    viewer.context.ifcCamera.unlock();
  }
  if (event.code === 'KeyH') {
    viewer.context.ifcCamera.goToHomeView();  // 카메라 홈 위치로 이동
  }
  if (event.code === 'KeyD') {
    viewer.context.ifcCamera.setNavigationMode(NavigationModes.FirstPerson);  // 1인칭 시점 카메라 이동
  }
  if (event.code === 'Escape') {
    window.onmousemove = viewer.IFC.prePickIfcItem;  // Ifc 요소 선택 모드
  }
  if (event.code === "KeyP") {
    viewer.context.ifcCamera.toggleProjection();  // 카메라 프로젝션 모드
  }
};

정적 구조 분석
정적 구조를 분석하기 위해 UML(Unified Modeling Language)로 역설계해 보았다.
패키지 구조

앞서 설명된 라이브러리 이외에 애니메이션 엔진인 GSAP(GreenSock animation platform) 코드가 일부 사용되었다.
GASP

주요 클래스는 다음과 같다. IFCManager가 IfcAPI, model, parser 등 전체를 관리하고, Loader가 파일을 파싱하는 구조이다.

카메라 등 애니메이션 처리는 GreenSock을 사용한다. 치수 등 측정을 지원하기 위한 클래스가 구현되어 있다. 

main.js 모듈은 기타 벡터, 행렬 등 유틸리티 클래스와 함수가 정의되어 있다.

BIM 객체 속성 표시 기능 구현해 보기
앞서 분석된 내용을 참고하여, BIM 객체의 속성을 표시하는 기능을 간단히 구현해 본다. 우선, 각 소스코드를 아래와 같이 편집한다.

// web-ifc-viewer\example\index.html 파일을 열고, 아래와 같이 section, textarea 요소 추가
  ...
  <body>
    <aside class="side-half-menu" id="side-menu-left"></aside>

    <div id="viewer-container"></div>
    <section class="panel-botton" id="side-panel-bottom">
      <textarea class="textarea-bottom" id="textarea-bottom" spellcheck="false" readonly>test</textarea>
    </section>    
    <script type="module" src="./build/main.js"></script>
  </body>

// web-ifc-viewer\example\styles.css 파일을 열고, 아래 style을 추가함
...
.side-menu {
    z-index: 1;
    position: fixed;
    background-color: #36393F;
    height: 100vh;
}

.side-half-menu {
    z-index: 1;
    position: fixed;
    background-color: #36393F;
    height: 80vh;
}

.panel-botton {
    z-index: 1;
    position: fixed;    
    background-color: #FFB555;
    width: 100%;
    height: 20vh;    
}

.textarea-bottom {
    width: 100%;
    height: 80%; 
}

.side-sub-menu {
    width: 100%;
    height: inherit;
    margin: 2px;
}

// E:\Projects\web-ifc-viewer\example\build.js 파일을 열고, ondblclick 이벤트 위치에 아래 코드를 추가함
...
    window.onkeydown = handleKeyDown;
    window.ondblclick = async () => {
      viewer.clipper.createPlane();

      const item = await viewer.IFC.pickIfcItem(true);  // 현재 마우스 클릭 위치의 Ifc element pick해 얻기
      if(item.modelID === undefined || item.id === undefined ) return;

      const pset = await viewer.IFC.getProperties(item.modelID, item.id, true);
      console.log(pset);

      var data = "";
      const text = document.getElementById('textarea-bottom'); // 2021.10. Pset 출력 text area 획득

      for(var i = 0; i < pset.type.length; i++) {
        data = data + pset.type[i].constructor.name + '\n';
      }

      for(var i = 0; i < pset.psets.length; i++) {
        data = data + pset.psets[i].Name.value + '\n';
        for(var j = 0; j < pset.psets[i].HasProperties.length; j++) {
            data = data + '   ' + pset.psets[i].HasProperties[j].value + '\n';    
        }
      }

      text.value = data;
...

구현 결과는 다음과 같다. IFC를 로딩한 후, 벽체 등 객체를 더블클릭하면 아래 패널창에 속성값이 출력될 것이다. 
벽체 객체 선택 후 속성 출력된 모습

IFC.js 응용과 한계
IFC.js를 응용하는 방법은 다양하다. 개발자가 언급한 것처럼 CDE를 구현할 수도 있고, BIM 모델 체커를 만들 수도 있다. IFC의 Property Set에 외부 정보를 연결하면, IoT, 디지털 트윈 등을 구현할 수 있다. GIS와 연계하면 BIM-GIS 개발이 가능할 것이다. 

다만, 유사한 오픈소스 프로젝트인 xBIM과 비교를 해보면, 정보 쿼리 기능, BIM 서버 연계, 대용량 처리, 확장성 등의 개선이 필요해 보인다. 그럼에도 가장 간편하게 BIM 응용 서비스를 웹 기반으로 개발할 수 있다는 점, WASM을 이용한 그래픽 가속 기능은 큰 장점이다.

마무리
이 글에서는 간단히 CDE 개발을 지원하는 오픈소스 BIM 라이브러리인 IFC.js를 분석하고 사용방법을 확인해 보았다. IFC.js는 구조가 복잡하고 사용이 쉽지는 않다. 그럼에도 앞서 언급한 장점이 많은 라이브러리이다. 
IFC.js 기여자
레퍼런스
xBIM web viewer example

부록: IFC viewer 오픈소스 license
현 시점에서 ifc viewer 중 MIT, BSD 라이센스는 web-ifc-viewer, ifc.js, ifcplusplus밖에 없다. 성능이 좋은 xbim, xeokit은 copyleft에 해당하는 오픈소스로 이를 사용한 코드를 오픈소스로 공개하도록 강제한다. 이를 어길 시 소송을 당할 수 있다.

부록: 2025년 시점 IFC viewer
IFC.js 를 사용해 발전된 다음과 같은 웹 뷰어들이 있다. 동작 방식은 유사하다. 다만, 로딩되는 IFC파일 방법 등에 차이가 있다. 
부록: ISO 19650 CDE 관련 참고
ISO 19650와 호환되는 CDE 개발 시 참고 자료는 다음과 같다. 
산출물 정보 컨테이너 ID 관리
CDE 작업흐름 관리
부록: IFC.js 형상 파싱 및 메쉬 생성 그래픽 엔진 분석
IFC.js의 그래픽 엔진은 Three.js 의 메쉬 생성 부분을 사용한다. 코드를 다운로드한 후 분석을 해 보면, IFC 파싱을 담당하고 있는 IFCWorker.js 의 Geometry to Mesh 코드가 Three.js 코드를 사용하고 있는 것을 확인할 수 있다. IFC는 각 Product의 형상을 파라메터만 가지고 있으므로, 이를 디스플레이하거나 메쉬 간 연산을 위해서는 다음과 같은 변환 작업이 필요하다.

   mesh = convert(product.geometry.{type, parameters})
   // display(mesh) 

IFCWorker.js는 각 IFC버전별로 파싱하는 함수를 다음과 같은 맵 테이블로 정의하고 있다 

각 IFC product의 지오메트리는 다음과 같은 BufferGeometry에서 파생받은 클래스에 의해 파라메터가 해석되어 mesh 정보로 생성된다. 이 메쉬 생성 전략은 Solid model의 B-rep 형식에 따라 각각 다르므로, 이에 적합한 메쉬 생성 함수를 사용하도록 코딩된다. 생성된 메쉬 정보는 BufferGeometry에 저장된다. 
ExtrudeGeometry (build.js)

파싱되어 생성된 메쉬는 다음과 같이 접근되어 사용된다. 

퍼버 지오메트리는 IFC file serialize 성능 속도 개선을 위해 file로 저장 및 로딩되는 캐쉬 전략을 사용한다. 

부록: ifcviewer 초기화 루틴
ifcviewer는 아직 완벽한 CRUD(create, read, update, delete) 모델을 지원하지 않는다. 그러므로, 일부 소스 수정이 필요하다. 다음은 ifc viewer 초기화 관련 주요 코드를 보여준다. 

      const container = document.getElementById('viewer-container');
      const ifcviewer = new IfcViewerAPI({ container, backgroundColor: new Color(255, 255, 255) });
      ifcviewer.axes.setAxes();
      ifcviewer.grid.setGrid();
      ifcviewer.shadowDropper.darkness = 0.0;
      ifcviewer.context.ifcCamera.cameraControls;
      ifcviewer.IFC.loader.ifcManager;
      ifcviewer.IFC.setWasmPath('files/');
      ifcviewer.IFC.loader.ifcManager.applyWebIfcConfig({
         USE_FAST_BOOLS: true,
         COORDINATE_TO_ORIGIN: true
      });
      ifcviewer.context.renderer.postProduction.active = true;
      let first = true;
      let model;
      const loadIfc = async (event) => {
         const selectedFile = event.target.files[0];
         if(!selectedFile) return;
         ifcviewer.IFC.loader.ifcManager.parser.setupOptionalCategories({
         [IFCSPACE]: false,
         [IFCOPENINGELEMENT]: false
         });
         model = await ifcviewer.IFC.loadIfc(selectedFile, false);
         if(first) first = false;
         else {
            ClippingEdges.forceStyleUpdate = true;
         }
      };

      const inputElement = document.createElement('input');
      inputElement.setAttribute('type', 'file');
      inputElement.classList.add('hidden');
      inputElement.addEventListener('change', loadIfc, false);

      const handleKeyDown = async (event) => {
         if (event.code === 'Delete') {
         ifcviewer.clipper.deletePlane();
         ifcviewer.dimensions.delete();
         }
         if (event.code === 'Escape') {
         ifcviewer.IFC.selector.unHighlightIfcItems();
         }
         if (event.code === 'KeyC') {
         ifcviewer.context.ifcCamera.toggleProjection();
         }
         if (event.code === 'KeyD') {
         ifcviewer.IFC.removeIfcModel(0);
         }
         if (event.code === 'KeyI') {
         const ifcUrl = "/static/test.ifc";
         await ifcviewer.IFC.loadIfcUrl(ifcUrl);
         }   
      };

      window.onmousemove = () => ifcviewer.IFC.selector.prePickIfcItem();
      window.onkeydown = handleKeyDown;
      window.ondblclick = async () => {
         if (ifcviewer.clipper.active) {
            ifcviewer.clipper.createPlane();
         } else {
            const result = await ifcviewer.IFC.selector.highlightIfcItem(true);
            if (!result) 
               return;
            const { modelID, id } = result;
            const props = await ifcviewer.IFC.getProperties(modelID, id, true, false);
            console.log(props);
         }
      }
   
      window.IfcViewerAPI = IfcViewerAPI;
      window.ifcviewer = ifcviewer;

부록: web assembly 예제 (참고)
웹어셈블리는 C++과 같은 다양한 언어로부터, 클라이언트에 실행되는 웹 바이너리 실행코드를 생성한다. Emscripten은 웹 어셈블리를 컴파일한다. 참고로, Emscripten은 오픈소스 컴파일러로, C/C++ 등 소스코드를 컴파일해 웹에서 실행할 수 있는 코드를 생성한다. 이 도구는 언리얼, 유티니와 같은 상용 코드베이스를 포함하고 있다. 이 도구를 통해, 웹 켄버스 그래픽, 이벤트 등 다양한 웹 브라이져 객체를 다룰수 있다(링크). 또한, 게임 등 다양한 소프트웨어를 웹 버전으로 포팅할 때도 사용된다(데모).
포팅된 3차원 유니티 게임 스크린샷(링크)

이 예제는 모질라에서 제공하는 튜토리얼 중 일부를 참고한 것이다(링크).

1. 코딩
#include <stdio.h>

int main() {
    printf("Hello World\n");
    return 0;
}

2. 웹 어셈플리 컴파일
emcc hello.c -o hello.html

이 결과로, hello.wasm, hello.js, hello.html 파일이 생성된다.

3. 생성된 html 을 웹브라우저에 로딩
이 결과로 앞의 프린트 문 내용이 웹페이지에 출력되는 것을 볼 수 있다.

웹어셈블리를 이용해 웹에서 제공되지 않는 기능을 추가할 수 있다. 예를 들어, 다음 예는 커스텀 그래픽 객체를 추가한다.



2021년 9월 22일 수요일

우분투 리눅스 기반 프로그램 디버거 소개 및 사용법

이 글은 우분투 리눅스 기반 프로그램 디버거 소개 및 사용법을 공유한다. 개발하던 프로그램이 제대로 동작하지 않으면, 디버깅이 필요하다. 여기서는 리눅스에서 가장 많이 사용되는 디버거인 GDB, KDbg, Eclipse를 소개하고, 사용방법을 간단히 공유한다.

디버그란
디버그는 컴퓨터로 실행되는 프로그램에 오류가 있을 경우, 이 오류를 해결하는 방법 및 행위를 말한다. 최초의 컴퓨터 버그는 1947년 실제 컴퓨터 부품 내에 들어가 오동작을 일으킨 벌래였다.
최초의 컴퓨터 버그(1947)

디버그를 위해서는 다음과 같은 기본적인 기능이 필요하다. 여기서, 브레이크포인트(break point)는 디버깅 실행 중 멈추는 지점을 의미한다. 모든 디버거는 이와 같은 기본 기능을 지원한다.
  • 브레이크포인트 설정
  • 브레이크포인트까지 계속 실행
  • 명령행 한단계 실행
  • 함수 진입
  • 함수 빠져나오기
  • 현재 변수값 확인
GDB는 GNU 소프트웨어 기본 디버거이다. GDB는 유닉스 기반에서 개발되어, 리눅스에도 이식되어 있다. 설치를 위해 우분투 터미널에서 다음 명령을 입력한다.
sudo apt-get install gdb

설치 후, 실행파일이 있는 폴더에서 다음과 같이 명령을 입력한다.
gdb --args [프로그램명] [입력인자1] [입력인자2...]

그럼 다음과 같이 디버그가 실행된다. 이제, gdb 명령어를 이용해 디버깅을 하면 된다.

gdb 명령창이 실행되면, b main 명령으로 main 엔트리에 브레이크포인트를 설정한다. r 명령을 입력하면, 브레이크포인트까지 실행될 것이다. p argc 명령으로 argc 변수값을 확인해 본다. 이런식으로 디버깅을 할 수 있다.

이외, 주요 명령어는 다음과 같다. 
b main - Puts a breakpoint at the beginning of the program
b - Puts a breakpoint at the current line
b N - Puts a breakpoint at line N
b +N - Puts a breakpoint N lines down from the current line
b fn - Puts a breakpoint at the beginning of function "fn"
d N - Deletes breakpoint number N
info break - list breakpoints
r - Runs the program until a breakpoint or error
c - Continues running the program until the next breakpoint or error
f - Runs until the current function is finished. step out
s - Runs the next line of the program. step in
s N - Runs the next N lines of the program
n - Like s, but it does not step into functions. next
u N - Runs until you get N lines in front of the current line
p var - Prints the current value of the variable "var"
bt - Prints a stack trace
u - Goes up a level in the stack
d - Goes down a level in the stack
q - Quits gdb

KDBG는 GNU 소프트웨어 디버그용 무료 오픈소스 프로그램이다. KDE 아키텍처를 이용해 GUI(Graphic User Interface)를 지원한다.

사용을 위해서는 우분투 터미널에서 다음 명령을 입력한다. 소스를 다운로드 받고, 빌드 및 설치한다. 
sudo apt install extra-cmake-modules
git clone -b maint https://github.com/j6t/kdbg.git 
cd kdbg/
git tag -l
git checkout kdbg-3.0.1
cmake .
sudo make install

만약, CMake에서 에러가 발생하면, 해당 패키지를 apt-get 으로 설치한 후, 다시 시도하여 빌드한다. 빌드에 성공하면 다음과 같이 관련 모듈이 설치된다.

kdbg를 명령창에 입력하면, 다음과 같이 GUI가 표시된다. 소스와 실행파일 위치를 메뉴를 통해 선택하고 Run을 하면 디버깅을 할 수 있다. 브레이크 포인트는 편집창 왼쪽 줄 옆에 클릭하면된다. 변수는 Expression 창에서 그 값을 확인할 수 있다.

이클립스는 IBM의 웹스피어 스튜디오란 개발자 지원 도구에서 파생된 것으로, 엔진부분이 오픈소스로 공개된을 사용해 개발된 것이다. 현재는 이클립스 재단에서 통합 관리한다.


사용을 위해, 여기에서 프로그램을 다운받아 설치한다.
설치 후, 이클립스를 실행하고, 간단한 C++ 어플리케이션 프로젝트를 생성한다. 이름은 hello로 한다. 사용방법은 Visual Studio와 유사하게, 메뉴나 프로젝트 탐색창에서 Build, Run, Debug를 실행할 수 있도록 되어 있다.

디버깅을 위해, 프로젝트 탐색기의 프로젝트를 선택하고, cpp파일을 만든다. 해당 소스 파일 내에 hello world 출력 코드를 코딩하고, 빌드한다. 

#include <stdio.h>

int main()
{
char* szHello = "hello world! from stjohns";
printf(szHello);
return 0;
}

빌드가 성공하면, 실행 및 디버깅 환경 설정을 다음과 같이 실행한다. 

소스 편집기 창의 라인번호 왼쪽을 더블클릭해, 브레이크포인트를 만든 후 디버깅을 실행하면 다음과 같이 해당 지점에 실행이 멈추고, 변수값 등을 확인할 수 있다.
 
기존 프로젝트를 가져와서 디버깅을 하고 싶으면, File > import > C/C++ > Existing Code as Makefile Project 를 선택하고, 프로젝트의 Makefile이 있는 루트 폴더를 선택하면 된다. 그럼, 다음과 같이 프로젝트에서 생성된 실행파일을 디버깅할 수 있다. 아울러, 디버그 심벌이 있으면, 소스코드는 함께 표시된다. 참고로, 디버그 심벌이 제대로 연결되지 않으면, 해당 부분의 소스 라인은 디버그할 수 없다. 

pdb
python디버거이다. 소스코드를 디버깅할 수 있으며, 앞서 언급한 gdb와 유사한 명령어를 지원한다.
명령은 다음과 같다.
python -m pdb example.py

PDB를 사용하여 디버깅 모드로 진입 후, 다음 명령어를 사용해 디버깅하면 된다.
help: 도움말
next: 다음 문장 이동
print: 변수값 화면 표시
list: 소스코드 리스트 출력. 현재 위치 화살표 표시
where: 콜스택 출력
continue: 계속 실행. 다음 중단점에 멈추거나 중단점 없으면 끝까지 실행
step: Step Into. 함수 내부 진입
return: 현재 함수의 리턴 직전까지 실행
!변수명 = 값: 변수에 값 재설정

pdb 사용 예시

printf
오래전에 아는 선배가 제일 좋은 디버깅 도구로 추천한 것이 printf였다. 앞의 디버깅도구들은 심벌을 로딩하지 못하는 환경에서는 디버깅이 어렵다. 이 경우, 에러가 있을만한 코드를 printf로 표시해 나가면서 디버깅하면 된다.
printf은 가장 단순하면서도, 가장 확실하게 디버깅할 수 있는 도구이다.

참고