Skip to main content

The devil's in the details.

정말 오랫만에 글을 쓰네요. XMLCPP 라이브러리 만드는데 재미를 붙여서 잠시 글쓰기를 안했더니 금방 글쓰기가 귀찮아지네요. 아니면 두려워진건지도... -_-;

최근에 했던 일은 XMLCPP에 autoconf를 적용하는 것이었습니다. autoconf란 소스 코드 패키지를 다양한 Posix-like 시스템에서 build할 수 있도록 도와주는 shell script를 만들어주는 도구입니다. 보통 소스 코드로 된 패키지를 구하면 하는 configure, make, make install의 과정이 대부분 autoconf가 만들어준 것들입니다.

왠지 configure하는 패키지들은 멋있어 보여 저도 한번 써보고 싶었는데 기회가 그간 없었지요. 일단 책을 보고 따라하기 하여 뚝딱뚝딱 적용을 했습니다. 이걸 적용하는데도 꽤나 까다로웠지요. 다음은 책에 나온 예제들에는 없어 헤맨 몇가지 사항들입니다.

  • $includedir 이 아니라 $includedir/xmlcpp 디렉토리에 헤더 파일을 install 하고 싶다.

  • make dist시에 tests 디렉토리 밑의 *.xml 파일도 tar되어야 한다. 하지만 install되진 않아야 한다.

  • make check시에 boost_unittest_framework으로 작성한 unit test가 수행되어야 한다.

  • --with-iconv 옵션을 추가한다.

  • boost 라이브러리 존재 여부를 검사해야 한다.



그래도 여기까지 작업 하고 나서 configure 실행시키면 쭈욱 올라가는 check list들을 보니 뿌듯하더군요. 이제 다음 단계로 제가 코딩한 Ubuntu 환경이 아닌 다른 환경에서도 정말 동작하는지 확인하기로 했습니다.

먼저 Redhat. 정말 다를게 없어보였습니다. 같은 리눅스라 그냥 되려니 생각했는데 make test하니 에러가 와장창 나더군요. ㅜㅜ

차이점은 gcc 버전... 검색해보니 특정 버전의 libstdc++.a 에 버그가 있더군요. fstream에 있는 버그인데 이로 인해 StreamCharDecoder에서 사용한 fs.readsome() 함수가 전혀 파일을 읽지 못했던 것이었습니다. 그래서 readsome()과 peek()를 사용하던 것을 바로 read(), gcount(), clear()를 사용하는 것으로 수정해서 Redhat으로의 포팅(? 좀더 정확히는 g++ 3.2.3으로의 포팅)은 성공.

다음으로 제가 access할 수 있는 Posix-like 시스템으로는 SunOS5.8과 윈도우에 설치한 Cygwin, MinGW등이 있었습니다. 그래서 다음으로 시도한 것이 SunOS 5.8. 이건 바로 포기가 되더군요. -_-;

XMLCPP는 XML 파싱을 위해 boost의 spirit 라이브러리를 사용하는데 boost의 문서를 읽어보니 저희 SunOS에 설치되어 있는 Sun WorkShop 6 update 2에 대해 다음과 같은 note가 있더군요.

The most recent reports seem to imply that this release is “hopeless for Boost”, but patches and workarounds are welcome.


다음은 Cygwin과 MinGW들에 도전해 보았습니다만 이것도 역시 포기... 이유는... Cygwin과 MinGW에서는 wstring과 wcout이 없답니다. ㅜㅜ

이러고 보니 성공한 플랫폼은 겨우 Ubuntu와 Redhat... 거의 똑같은 리눅스 두개... -_-; 하나는 더 있어야겠다 싶어 VMWare에 Solaris10을 인스톨하고 관련 개발 툴들을 인스톨했습니다. (회사에서 눈치를 봐가며 설치하느라 사흘이나 걸렸습니다. 게다가 OS 인스톨 다하고 다른 프로그램들 다 깔아 놓으면 네트웍이 안되는 바람에 세번이나 다시 OS를 깔았답니다. 원인은 Solaris 10용 vmware-tools는 버그가 있고 아직 수정된 버전은 없다는 것. ㅜㅜ)

결국 Solaris 10에서 g++을 사용하여 configure 성공... 이때도 그냥 configure로는 되지 않았고 --with-gnu-ld를 사용해야 되더군요. (끝까지 발목을 잡는 녀석들... -_-;)

떨리는 마음으로 make... 성공! make test... ... 성공!!! 비록 같은 g++을 사용한 것이지만 정말 기쁘더군요. 이제 그만 해야지 하는 마음으로 samples 디렉토리에 있는 xmlprint 프로그램으로 tests 디렉토리에 있는 utf8test.xml 파일을 읽어 보았습니다. 이게 왠일... ascii 범위를 벗어나는 문자가 시작되는 부분까지만 출력하고 중단되어버리더군요. ㅜㅜ

첫째로 든 생각은 또 실패했다는 oTL, 둘째로는 unit test들이 부족했나? 잘못 만들어졌나?라는 생각...

여기까지가 어제까지의 상태입니다. 이런 것들을 겪다보니 제목의 "The devil's in the details"라는 말이 자연스럽게 생각나더군요. -_-

내일부터 다시 Solaris 10으로의 포팅(?)에 도전해 볼 생각입니다. 해결되면 Solaris 10의 g++과 Linux의 g++의 차이점을 알게 되겠죠? 아님 또 버그? ㅜㅜ

Comments

Popular posts from this blog

1의 개수 세기 - 해답

벌써 어제 말한 내일이 되었는데 답을 주신 분이 아무도 없어서 좀 뻘쭘하네요. :-P 그리고 어제 문제에 O(1)이라고 적었는데 엄밀히 얘기하자면 O(log 10 n)이라고 적었어야 했네요. 죄송합니다. ... 문제를 잠시 생각해보면 1~n까지의 수들 중 1의 개수를 얻기 위해서는 해당 숫자 n의 각 자리의 1의 개수가 모두 몇개나 될지를 구해서 더하면 된다는 사실을 알 수 있습니다. 예를 들어 13이라는 수를 생각해 보면 1~13까지의 수에서 1의 자리에는 1이 모두 몇개나 되는지와 10의 자리에는 모두 몇개나 되는지를 구해 이 값을 더하면 됩니다. 먼저 1의 자리를 생각해 보면 1, 11의 두 개가 있으며 10의 자리의 경우, 10, 11, 12, 13의 네 개가 있습니다. 따라서 2+4=6이라는 값을 구할 수 있습니다. 이번엔 234라는 수에서 10의 자리를 예로 들어 살펴 보겠습니다. 1~234라는 수들 중 10의 자리에 1이 들어가는 수는 10, 11, ..., 19, 110, 111, ... 119, 210, 211, ..., 219들로 모두 30개가 있음을 알 수 있습니다. 이 규칙들을 보면 해당 자리수의 1의 개수를 구하는 공식을 만들 수 있습니다. 234의 10의 자리에 해당하는 1의 개수는 ((234/100)+1)*10이 됩니다. 여기서 +1은 해당 자리수의 수가 0이 아닌 경우에만 더해집니다. 예를 들어 204라면 ((204/100)+0)*10으로 30개가 아닌 20개가 됩니다. 이런 방식으로 234의 각 자리수의 1의 개수를 구하면 1의 자리에 해당하는 1의 개수는 ((234/10)+1)*1=24개가 되고 100의 자리에 해당하는 개수는 ((234/1000)+1)*100=100이 됩니다. 이들 세 수를 모두 합하면 24+30+100=154개가 됩니다. 한가지 추가로 생각해야 할 점은 제일 큰 자리의 수가 1인 경우 위의 공식이 아닌 다른 공식이 필요하다는 점입니다. 예를 들어 123에서 100의 자리에 해당하는 1의 개수는 ((123/1...

CodeHighlighter plugin test page.

This post is for testing CodeHighlighter plugin which uses GeSHi as a fontifier engine. ((Those code blocks are acquired from Google Code Search .)) ((For more supported languages, go CodeHighlighter plugin or GeSHi homepage.)) C++ (<pre lang="cpp" lineno="1">) class nsScannerBufferList { public: /** * Buffer objects are directly followed by a data segment. The start * of the data segment is determined by increment the |this| pointer * by 1 unit. */ class Buffer : public PRCList { public: Buffer() { ++index_; } PHP (<pre lang="php" lineno="4">) for ($i = 0; $i $value = ord( $utf8_string[ $i ] ); if ( $value < 128 ) { // ASCII $unicode .= chr($value); } else { if ( count( $values ) == 0 ) { $num_octets = ( $value } $values[] = $value; Lisp (<pre lang="lisp">) ;;; Assignment (define-caller-pattern setq ((:star var fo...

C++ of the Day #43 - SQLite3 C++ wrapper #1

The Definitive Guide to SQLite 를 읽다가 공부 겸 해서 C++ wrapper를 만들어 보았습니다. 최대한 C++ 냄새(?)가 나도록 만들어 보았습니다. :-) ((SQLite는 복잡한 관리가 필요없이 사용가능한, 파일이나 메모리 기반의, 라이브러리로 제공되는, 약 250kb 용량의, 대부분의 SQL92문을 지원하는, open source RDB입니다.)) 이 wrapper를 사용하기 위해서는 (당연하게도!) sqlite3 와 (당연하게도?) boost 라이브러리가 필요합니다. 사용 예들을 살펴보는 것으로 설명을 대신합니다. 이번 글에서는 다음과 같은 contacts 테이블이 test.db에 존재한다고 가정합니다. CREATE TABLE contacts ( id INTEGER PRIMARY KEY, name TEXT NOT NULL, phone TEXT NOT NULL, UNIQUE(name, phone) ); Command 먼저 test.db 파일을 사용하기 위해 다음과 같이 파일 이름을 주어 connection 객체를 생성합니다. 생성과 동시에 test.db와 연결이 이루어집니다. ((생성자외에 open() 함수를 사용할 수도 있습니다.)) sqlite3pp::connection conn("test.db"); 다음은 contacts 테이블에 정보를 추가하는 가장 간단한 방법입니다. connection 클래스에서 제공하는 execute 함수를 사용합니다. ((executef 함수를 사용하면 printf와 같은 문법을 사용하여 query문을 작성할 수 있습니다.)) conn.execute("INSERT INTO contacts (name, phone) VALUES ('user', '1234')"); 위와 동일한 작업을 parameterized query를 사용하여 할 수도 있습니다. ((step()함수가 실제 query문을 수행하는 함수입니다. ...