[액티브X 대체기술 4부] - 액티브X를 뛰어넘는 기능과 호환성 XPCOM 개발 테크닉
더 큰 세상으로 가는 문 액티브X 대체기술
마소 독자치고 액티브X 문제와 무관하다고 할 수 있는 사람은 별로 없을 것이다. 그런데, 참 이상한 일은 액티브X 이야기만 나오면 문제의 원인이나 해결책을 이야기하기 보단 목에 핏대부터 세운다. 누군가를 탓하기 위함이다. 하지만 막상 따지고 보면 누구의 잘못이라고 하기는 어려운 일이다. 워낙 오랫동안 쌓아온 일이기 때문이다.
그렇다고 곪을 대로 곪은 상처를 그냥 놓아둘 수도 없는 일. 이번 달 특집에서는 이 상처의 원인에 대해 알아보고, 그 치료방법인 액티브X의 대체 기술들에 대해서도 함께 알아본다. 다들 잘 알다시피 아직 액티브X를 1대1로 대신해 줄 수 있는 기술은 없다. 하지만, 여러 기술들을 이용하여 산적한 문제들을 보완하며 차츰 치료해 나갈 수는 있을 것이다. 깊이 박힌 상처가 하루아침에 낫는 걸 보았는가?
1부 | 백조에서 미운오리로 전락한 액티브X 문제와 해결방안 | 정희용
3부 | UI 대체는 내게 맡겨라 Ajax를 이용한 UI 개발 | 박영록
4부 | 액티브X 뛰어넘는 기능과 호환성 XPCOM 개발전략 | 김민수
5부 | MS가 내놓은 액티브X의 대안 실버라이트 활용법 | 한용희
액티브X를 뛰어넘는 기능과 호환성 XPCOM 개발 테크닉
액티브X 문제로 때 아닌 진통을 겪고 있는 나라는 놀랍게도 우리나라뿐이다. 미국이나 유럽 대부분의 국가들은 https 프로토콜 하나로 ID만으로 인증하면 그걸로 끝인 탓이다. 보안 능력을 높이기 위해 사용자에게 그 이상의 요구를 하지 않는다. 그들의 보안 의식이 낮은 탓일까? 필자는 그렇게 생각하지 않는다. MS의 조국인 미국에서 조차 선호하지 않고 있는 액티브X의 지나친 사용을 이제는 되돌아보고 바로잡을 때다. 특집 4부에서는 XPCOM을 통해 기존의 액티브X를 어떻게 대체할 수 있는지에 대해 알아본다.
XPCOM, 앞에 두 글자 XP와 뒤에 COM를 보면 Windows XP와 무슨 관련이 있는 기술처럼 보인다. 그도 그럴 것이 COM와 COM+로 대표되는 액티브X를 위시한 마이크로소프트(이하 MS)의 컴포넌트 기술과 비슷한 단어인 Cross Platform Compo nent Object Model의 약자이기 때문이다. 그래서 어느 정도 관련이 있다고도 볼 수 있는 기술이다. 하지만, 결정적으로 MS는 수익을 추구하는 회사란 집단이고 XPCOM을 만든 모질라 재단은 비영리단체라는 것이다. 물론, 수익 추구라는 차이를 내세워 표준인지 아닌지를 가름 할 수는 없다. 하지만 MS의 브라우저 IE는 리눅스용이 없다. 하지만 모질라재단의 파이어폭스는 윈도우는 물론 리눅스와 유닉스, 맥OS, OS/2 등등 현존하는 거의 모든 OS를 지원하고 있다. 즉, 지원하는 플랫폼이 다양하기 때문에 더욱 범용적으로 사용할 수 있고 액티브X를 대체하는 것에 더하여 표준으로 자리 잡기에 충분하다고 얘기할 수 있겠다.
이번 특집에서는 기존에 마소를 통해 소개된 적 있는 XPCOM의 소개 기사는 최대한 배제하고, 다양한 플랫폼에 XPCOM을 어떻게 적용하면 좋을 지에 대한 활용 기사 위주로 다룰 것이다. XPCOM에 대해 더 궁금한 독자들은 원고 중에 제시된 링크를 참조하길 바란다.
SDK 다운로드와 설치하기
XPCOM으로 개발하려면 SDK를 다운로드 받아 설치해야 한다. 다음의 링크를 통해 필요한 파일을 다운로드 받을 수 있다.
Mozilla Gecko SDK 다운로드
● Branch
- 윈도우즈 환경의 Visual C++ 컴파일러 버전
ftp://ftp.mozilla.org/pub/mozilla.org/mozilla/nightly/latest-1.7/gecko-sdk-i586-pc-msvc.zip
- 윈도우즈 환경의 Cygwin GCC 컴파일러 버전
ftp://ftp.mozilla.org/pub/mozilla.org/mozilla/nightly/latest-1.7/gecko-sdk-i686-pc-cygwin.zip
- 리눅스 환경의 GCC 컴파일러 버전
ftp://ftp.mozilla.org/pub/mozilla.org/mozilla/nightly/latest-1.7/gecko-sdk-i686-pc-linux-gnu.tar.gz
- 리눅스 환경의 GCC 컴파일러 GTK2+XFT 버전
ftp://ftp.mozilla.org/pub/mozilla.org/mozilla/nightly/latest-1.7/gecko-sdk-i686-pc-linux-gnu-gtk2+xft.tar.gz
● Trunk
- 윈도우즈 환경의 Visual C++ 컴파일러 버전
ftp://ftp.mozilla.org/pub/mozilla.org/mozilla/nightly/latest-trunk/gecko-sdk-i586-pc-msvc.zip
- 리눅스 환경의 GCC 컴파일러 버전
ftp://ftp.mozilla.org/pub/mozilla.org/mozilla/nightly/latest-trunk/gecko-sdk-i686-pc-linux-gnu.tar.gz
- 리눅스 환경의 GCC 컴파일러 GTK2+XFT 버전
ftp://ftp.mozilla.org/pub/mozilla.org/mozilla/nightly/latest-trunk/gecko-sdk-i686-pc-linux-gnu-gtk2+xft.tar.gz
C++로 작성하는 XPCOM
먼저 각각의 과정을 살펴보면 가장 먼저 xxIxxx.idl를 만들고, 그 뒤에 xpidl를 이용하여 xxIxxx.xpt와 xxIxxx.h를 작성한다. 또, xxIxxx.h로부터 xxxxx.h, xxxxx.cpp와 xxxxxModule.cpp를 작성하고 나서 Makefile.in를 작성하고 파이어폭스와 함께 빌드하면 된다.
<리스트 1> xxIxxx.idl
#include "nsISupports.idl"
[scriptable, uuid(xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx)]
interface xxIxxx : nsISupports
{
long add(in long a, in long b);
};
<리스트 1>은 두 개의 숫자를 입력받아 더하는 역할을 하는 xxlxxx.idl 코드다. 이제 다음과 같이 xpidl를 이용하여 xxIxxx.xpt 와 xxIxxx.h를 작성해 보자.
xpidl -m typelib -I c:xxx_gecko_sdk xxIxxx.idl
xpidl -m header -I c:xxx_gecko_sdk xxIxxx.idl
다음으로 해야 할 일은 xxxxx.ccp를 작성하기 위해 xxIxxx.h에 있는 /* Header file */ 부터 /* Implementation file */ 의 앞까지를 xxxxx.h에 복사한 뒤에 xxxxx()를 virtual xxxxx()로 바꾸는 것이다.
<리스트 2> xxxxx.h 작성
#ifndef _XX_XXX_H_
#define _XX_XXX_H_
#include "xxIxxx.h"
#define XX_XXX_CONTRACTID "@xxx.xxx.kr/xx_ext/xxx;1"
#define XX_XXX_CLASSNAME "This is Sample"
#define XX_XXX_CID {0x00000000, 0x0000, 0x0000,
{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }}
// 위의 내용을 앞에 추가한다. XX_XXX_CID 는 xxIxxx.h 의 XXXXX_IID 를 복사한다.
#endif //_XX_XXX_H_
xxxxx.cpp는 xxIxxx.h에 있는 /* Implementation file */부터 /* End of implementation class template. */ 까지를 복사하여 만들면 된다.
<리스트 3> xxxxx.cpp 작성
#include "xxxxx.h"
// 위의 헤더를 추가
이번에는 모듈 등록을 위해 <리스트 4>와 같이 xxxxxModule. cpp 파일을 만든다.
<리스트 4> xxxxxModule.cpp
#include "nsIGenericFactory.h"
#include "xxxxx.h"
NS_GENERIC_FACTORY_CONSTRUCTOR(xxxxx)
static nsModuleComponentInfo components[] =
{
{
XX_XXX_CLASSNAME,
XX_XXX_CID,
XX_XXX_CONTRACTID,
xxxxxConstructor,
},
};
NS_IMPL_NSGETMODULE(xxxxxModule, components)
C++ 의 XPCOM on Linux
이번에는 리눅스에 C++ XPCOM을 적용하는 방법에 대해 알아볼 것이다. 여기에서는 Debian GNU/Linux를 기준으로 하여 진행한다. 리눅스에서는 .so 형식의 셰어드 라이브러리로 만들어야 한다.
가장 먼저 다음과 같은 방법으로 작업용 디렉토리를 만든다.
% mkdir -p xpcom-sample/{content/xpcom-sample,components}
% cd xpcom-sample
코드를 작성하기 전에 일단 XPCOM을 인스톨 하는 확장 기능을 만들어 보자.
<리스트 5> install.rdf
<?xml version="1.0"?>
<RDF xmlns="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:em="http://www.mozilla.org/2004/em-rdf#">
<Description about="urn:mozilla:install-manifest">
<em:id>xpcom-sample@imaso.co.kr</em:id>
<em:name>XPCOM sample</em:name>
<em:version>0.1</em:version>
<em:description>XPCOM sample</em:description>
<em:creator>Min-su Kim</em:creator>
<em:targetApplication>
<Description>
<em:id>{ec8030f7-c20a-464f-9b0e-13a3a9e97384}</em:id>
<em:minVersion>2.0</em:minVersion>
<em:maxVersion>2.0.0.*</em:maxVersion>
</Description>
</em:targetApplication>
</Description>
</RDF>
파이어폭스의 사용자 유저 인터페이스의 환경을 저장하는 chrome 파일을 확인한다.
<리스트 6> chrome.manifest
content xpcom_sample content/
overlay chrome://browser/content/browser.xul chrome://xpcom_sample/content/overlay.xul
인스톨러 작성 스크립트도 만든다.
<리스트 7> dist.sh
#!/bin/sh
cd `dirname $0`
#basename=`basename $PWD`
basename=xpcom-sample
version=`grep '<em:version>' install.rdf | sed -e 's,</?em:version>,,g'`
version=`echo $version | sed -e 's/[[:space:]]//g'`
xpi=$basename-$version.xpi
if [ -f components/Makefile ]; then
(cd components && make) || exit 1
component_shared="components/myCalc.so"
component_xpt="components/myICalc.xpt"
components="$component_xpt $component_shared"
fi
xpi_contents="content $components chrome.manifest install.rdf"
rm -f $xpi
zip -q -r -9 $xpi $xpi_contents -x */.svn/* || exit 1
<리스트 7>처럼 dist.sh가 만들어졌으면 다음과 같이 입력하여 .xpi를 작성한다.
% ./dist.sh
현재 디렉토리에 xpcom-sample-0.1.xpi을 인스톨하기 위해 다음과 같이 입력한다.
% iceweasel xpcom-sample-0.1.xpi
파이어폭스에서 [툴] - [애드 온(add-on)] 메뉴를 선택하여 ‘XPCOM sample’이 인스톨 되어 있는지 확인한다.
자 이제 XPCOM을 사용할 모든 준비가 끝났으니 실제 코드들을 만들어보자.
IDL의 작성 편집
가장 먼저 할 일은 components 디렉토리에 myICalc.idl를 작성하는 것이다. components 디렉토리 아래에 작성하여 파이어폭스가 자동으로 XPCOM를 검출해 읽어 들일 수 있도록 해 준다. 그렇게 하지 않으면 수동으로 등록하지 않으면 안 된다.
IDL 안의 uuid를 uuidgen(참고링크3)로 생성한다.
% uuidgen
c95498ae-16f5-4b46-8713-2cf79e30d4ef
<리스트 8> compornts/myICalc.idl
#include "nsISupports.idl"
[scriptable, uuid(c95498ae-16f5-4b46-8713-2cf79e30d4ef)]
interface myICalc : nsISupports
{
long add(in long a, in long b);
};
.xpt와 .h 생성하기와 편집하기
IDL이 다 만들어졌다면 이번에는 만들어 놓은 IDL 로부터 .xpt와 .h를 생성할 차례다. xpidl를 사용하여 .xpi와 .h를 만든다. 이 두 파일은 .idl 를 수정할 때마다 만들어야 하므로 Makefile로 만들어 두는 것이 좋다.
여기에서는 XULRunner를 사용하고 있는데 데비안 이외의 리눅스 환경에서는 GECKO_PATH나 GECKO_XXX_PATH를 변경 할 필요가 있을 것이다.
<리스트 9> components/Makefile
GECKO_PATH = /usr/lib/xulrunner
GECKO_SDK_PATH = $(GECKO_PATH)/sdk
GECKO_IDL_PATH = $(GECKO_SDK_PATH)/idl
XPIDL = $(GECKO_PATH)/xpidl
IDL = myICalc.idl
XPT = myICalc.xpt
IHEADER = myICalc.h
all: $(XPT) $(IHEADER)
$(XPT): $(IDL)
$(XPIDL) -m typelib -I$(GECKO_IDL_PATH) $(IDL)
$(IHEADER): $(IDL)
$(XPIDL) -m header -I$(GECKO_IDL_PATH) $(IDL)
clean:
rm -f $(XPT) $(IHEADER)
dist.sh를 실행해 .xpi 를 생성한 후에 다시 인스톨한다.
% ./dist.sh
/usr/lib/xulrunner/xpidl -m typelib -I/usr/lib/xulrunner/sdk/idl myICalc.idl
/usr/lib/xulrunner/xpidl -m header -I/usr/lib/xulrunner/sdk/idl myICalc.idl
% iceweasel xpcom-sample-0.1.xpi
.xpt가 인식되고 있는지 확인하려면 다음과 같이 입력해 보자.
% grep xpcom-sample /.mozilla/firefox/*/xpti.dat
다음과 같은 결과가 출력되면 .xpt가 정상적으로 인식된 것이다.
4,.../extentions/xpcom-sample@imaso.co.kr/components
XPCOM의 설치하기
우선은 myCalc.h를 작성해야 하는데 여기에서도 UUID가 필요하다. 다음과 같이 입력하여 사전에 UUID를 만들어 둔다.
% uuidgen
8931dfd3-edf3-4b7d-bd44-1da72064f0dc
이렇게 만들어진 uuid를 16진수로 나누어 코드에 적용하기 위해 다음과 같이 포맷을 변환해 두어야 한다.
8931dfd3-edf3-4b7d-bd44-1da72064f0dc
↓
8931dfd3 edf3 4b7d bd 44 1d a7 20 64 f0 dc
↓
0x8931dfd3 0xedf3 0x4b7d 0xbd 0x44 0x1d 0xa7 0x20 0x64 0xf0 0xdc
↓
{0x8931dfd3, 0xedf3, 0x4b7d, {0xbd, 0x44, 0x1d, 0xa7, 0x20, 0x64, 0xf0, 0xdc}}
이것을 요즘 유행하는 스크립트 언어인 루비를 이용해서 만들어 보자.
<리스트 10> split-uuid.rb
#!/usr/bin/env ruby
ARGV.each do |uuid|
uuid_components = uuid.split(/-/)
first_components = uuid_components.slice!(0, 3)
second_components = []
uuid_components.each do |uuid_component|
second_components.concat(uuid_component.scan(/../))
end
first_components = first_components.collect do |component|
"0x#{component}"
end.join(", ")
second_components = second_components.collect do |component|
"0x#{component}"
end.join(", ")
puts "{#{first_components}, {#{second_components}}}"
end
혹은 이렇게 한다.
<리스트 11> split-uuid2.rb
#!/usr/bin/env ruby
ARGV.each do |uuid|
uuid_components = uuid.split(/-/)
first_components = uuid_components.slice!(0, 3)
second_components = uuid_components.inject([]) do |result, component|
result + component.scan(/../)
end
first, second = [first_components, second_components].collect do |components|
components.collect do |component|
"0x#{component}"
end.join(", ")
end
puts "{#{first}, {#{second}}}"
end
<리스트 10>이나 <리스트 11>과 같이 하면 다음과 같은 두 형식의 UUID가 만들어진다.
8931dfd3-edf3-4b7d-bd44-1da72064f0dc
{0x8931dfd3, 0xedf3, 0x4b7d, {0xbd, 0x44, 0x1d, 0xa7, 0x20, 0x64, 0xf0, 0xdc}}
헤더 파일은 components/myICalc.h에 있는 것을 카피하여 사용한다.
<리스트 12> components/myCalc.h
#ifndef __MYCALC_H__
#define __MYCALC_H__
#include "myICalc.h"
#define MY_CALC_CONTRACT_ID "@imaso.co.kr/xpcom-sample/Calc;1"
#define MY_CALC_CLASS_NAME "Calculator"
#define MY_CALC_CID_STR "8931dfd3-edf3-4b7d-bd44-1da72064f0dc"
#define MY_CALC_CID
{0x8931dfd3, 0xedf3, 0x4b7d,
{0xbd, 0x44, 0x1d, 0xa7, 0x20, 0x64, 0xf0, 0xdc}}
class myCalc : public myICalc
{
public:
NS_DECL_ISUPPORTS
NS_DECL_MYICALC
myCalc();
private:
myCalc();
protected:
/* additional members */
};
#endif
cpp도 components/myICalc.cpp에 있으므로 그것을 복사하고 add를 추가한다.
<리스트 13> components/myCalc.cpp
#include "mozilla-config.h"
#include "myCalc.h"
NS_IMPL_ISUPPORTS1(myCalc, myICalc)
myCalc::myCalc()
{
/* member initializers and constructor code */
}
myCalc::myCalc()
{
/* destructor code */
}
/* long add (in long a, in long b); */
NS_IMETHODIMP myCalc::Add(PRInt32 a, PRInt32 b, PRInt32 *_retval)
{
*_retval = a + b;
return NS_OK;
}
#include "mozilla-config.h"
#include "myCalc.h"
NS_IMPL_ISUPPORTS1(myCalc, myICalc)
myCalc::myCalc()
{
/* member initializers and constructor code */
}
myCalc::myCalc()
{
/* destructor code */
}
/* long add (in long a, in long b); */
NS_IMETHODIMP myCalc::Add(PRInt32 a, PRInt32 b, PRInt32 *_retval)
{
*_retval = a + b;
return NS_OK;
}
components/Makefile를 수정하여 컴파일 할 수 있도록 한다.
<리스트 14> components/Makefile
CXX = c++
CXXFLAGS = -g -Wall -fno-rtti -fno-exceptions -shared
GECKO_PATH = /usr/lib/xulrunner
GECKO_SDK_PATH = $(GECKO_PATH)/sdk
GECKO_IDL_PATH = $(GECKO_SDK_PATH)/idl
GECKO_INCLUDE_PATH = $(GECKO_SDK_PATH)/include
GECKO_LIB_PATH = $(GECKO_SDK_PATH)/lib
XPIDL = $(GECKO_PATH)/xpidl
GECKO_INCLUDES = -I$(GECKO_INCLUDE_PATH)
GECKO_CFLAGS = -DXPCOM_GLUE $(GECKO_INCLUDES)
GECKO_LDFLAGS = -L$(GECKO_LIB_PATH)
GECKO_LIBS = -lxpcomglue
-lnspr4
-lplds4
OBJS = myCalc.o
IDL = myICalc.idl
XPT = myICalc.xpt
IHEADER = myICalc.h
SHARED = myCalc.so
all: $(XPT) $(IHEADER) $(SHARED)
$(XPT): $(IDL)
$(XPIDL) -m typelib -I$(GECKO_IDL_PATH) $(IDL)
$(IHEADER): $(IDL)
$(XPIDL) -m header -I$(GECKO_IDL_PATH) $(IDL)
$(SHARED): $(IHEADER) $(OBJS)
$(CXX) $(CXXFLAGS) $(GECKO_LDFLAGS) -o $(SHARED) $(OBJS) $(GECKO_LIBS)
clean:
rm -f $(XPT) $(IHEADER) $(OBJS) $(SHARED)
.cpp.o:
$(CXX) $(CXXFLAGS) $(GECKO_CFLAGS) -c $<
dist.sh를 실행해 컴파일 할 때 모질라의 헤더 파일에 warning 메시지가 표시되지만 큰 문제는 없다.
컴파일 시 warning 메시지들
% ./dist.sh
c++ -g -Wall -fno-rtti -fno-exceptions -shared -DXPCOM_GLUE -I/usr/lib/xulrunner/sdk/include -c myCalc.cpp
/usr/lib/xulrunner/sdk/include/nsISupportsBase.h:80: warning:
‘class nsISupports
' has virtual functions but non-virtual destructor
/usr/lib/xulrunner/sdk/include/nsIProgrammingLanguage.h:32: warning:
‘class nsIProgrammingLanguage
' has virtual functions but non-virtual destructor
/usr/lib/xulrunner/sdk/include/nsIClassInfo.h:33: warning:
‘class nsIClassInfo
' has virtual functions but non-virtual destructor
myICalc.h:25: warning:
‘class myICalc
' has virtual functions but non-virtual destructor
c++ -g -Wall -fno-rtti -fno-exceptions -shared -L/usr/lib/ xulrunner/sdk/lib -o myCalc.so myCalc.o -lxpcomglue -lnspr4 -lplds4
이것으로 components/myCalc.so를 만들어 사용 할 수 있다. 하지만, 이것만으로는 아직 부족하다.
XPCOM 등록하기
공유 라이브러리가 읽혔을 때에 XPCOM을 등록하는 기능이 필요하다면 그 기능은 <리스트 15>와 같이 components/my CalcModule.cpp로 구현하면 된다.
<리스트 15> components/myCalcModule.cpp
#include "nsIGenericFactory.h"
#include "myCalc.h"
NS_GENERIC_FACTORY_CONSTRUCTOR(myCalc)
static nsModuleComponentInfo components[] =
{
{
MY_CALC_CLASS_NAME,
MY_CALC_CID,
MY_CALC_CONTRACT_ID,
myCalcConstructor,
}
};
NS_IMPL_NSGETMODULE("myCalcModule", components)
또한 components/Makefile의 OBJS에도 추가한다.
<리스트 16> components/Makefile
...
OBJS = myCalc.o myCalcModule.o
...
예제에서는 myCalc 하나만을 등록하고 있지만 복수의 XPCOM이 하나의 공유 라이브러리에 들어갈 수도 있다. 프로그램 패키지를 묶어서 인스톨하기 위해 다음과 같이 스크립트를 입력한다.
% ./dist.sh
...
% iceweasel xpcom-sample-0.1.xpi
myCalc가 등록되었는지 확인하려면 다음과 같이 입력한다.
% grep myCalc /.mozilla/firefox/*/compreg.dat
이렇게 입력한 결과가 다음과 같이 나오면 제대로 등록된 것이다.
abs:/.../xpcom-sample@imaso.co.kr/components/myCalc. so,1173322260000
{8931dfd3-edf3-4b7d-bd44-1da72064f0dc},,,,abs: /.../myCalc.so
테스트용 인터페이스
대화형으로 xul을 사용하여 팝업의 인터페이스를 만들어 자바스크립트의 식을 테스트하는 인터페이스를 만들어 보자.
<리스트 17> content/overlay.xul
<?xml version="1.0"?>
<overlay
id="test-overlay"
xmlns="http://www.mozilla.org/keymaster/gatekeeper/ there.is.only.xul">
<menubar id="main-menubar">
<menu label="XPCOM sample">
<menupopup>
<menuitem label="Call sample XPCOM"
oncommand=”
(function () {
var obj;
try {
const cid = '@imaso.co.kr/xpcom-sample/Calc;1';
obj = Components.classes[cid].createInstance();
obj = obj.QueryInterface(Components.interfaces.myICalc);
} catch (err) {
alert(err);
return;
}
alert('3 + 4 = ' + obj.add(3, 4));
})();
"/>
</menupopup>
</menu>
</menubar>
</overlay>
역시 .xpi 를 다시 인스톨 한다.
% ./dist.sh
% iceweasel xpcom-sample-0.1.xpi
[XPCOM sample] 메뉴에서 [Call sample XPCOM]를 실현한 뒤에 ‘3 + 4 = 7’라는 메시지가 표시되면 성공이다.
C++ 의 XPCOM on Mac OS X
이번에는 Mac OS X에서 실행되는 C++ XPCOM을 만들어보자.
Mac OS X에서는 GCC 대신 Xcode를 사용하여 컴파일 한다. Mac에서 라이브러리는 dylib 형식으로 만들기 때문에 리눅스용 Makefile을 사용할 수 없을 뿐 아니라 dist.sh도 변경해야 한다.
Xcode의 프로젝트는 components/myCalc.xcodeproj/ 에 위치한다.
가장 먼저 <리스트 18>과 같이 dist.sh를 수정해 보자.
<리스트 18> Mac OS X 환경에 맞게 인스톨 패스와 파일 확장자를 수정한 dist.sh
#!/bin/sh
cd dirname $0
if [ -x "which gnused" ]; then
SED=gnused
else
SED=sed
fi
#basename=basename $PWD
basename=xpcom-sample
version=grep '<em:version>' install.rdf | $SED -e 's,</?em:version>,,g'
version=echo $version | $SED -e 's/[[:space:]]//g'
xpi=$basename-$version.xpi
case uname in
Linux)
(cd components && make) || exit 1
component_shared="components/myCalc.so"
;;
Darwin)
build_type=Release
xcodebuild_args="-project myCalc.xcodeproj -configuration $build_type"
(cd components && xcodebuild $xcodebuild_args) || exit 1
component_shared="components/libmyCalc.dylib"
cp components/build/$build_type/libmyCalc.dylib $component_shared
;;
*)
echo "Unknown environment"
exit 1
;;
esac
component_xpt="components/myICalc.xpt"
components="$component_xpt $component_shared"
xpi_contents="content $components chrome.manifest install.rdf"
rm -f $xpi
zip -q -r -9 $xpi $xpi_contents -x */.svn/* || exit 1
Mac OS X의 gecko-sdk에는 xpidl이 들어있는데, 여기에는 요즘은 오래된 버전의 glib와 libIDL이 포함되어 있다. 이 정도의 버전은 최근의 MacPorts로는 가져오기가 어렵기 때문에 Linux에서 생성한 .xpt와 .h를 불러와서 사용해야 한다.
다음과 같이 dist.sh를 실행하여 .xpi를 작성한다.
% ./dist.sh
만들어진 xpcom-sample-0.1.xpi를 파이어폭스에 마우스로 드래그앤드롭하면 인스톨 되고 메뉴에 [XPCOM sample]이 표시된다. [Call sample XPCOM]를 선택하여 ‘3 + 4 = 7’라는 메시지가 표시되면 성공이다.
커맨드 라인으로부터 확인하려면 리눅스에서와 마찬가지로 다음과 같이 입력하면 된다.
% grep myICalc /Library/Application Support/Firefox/Profiles/ */xpti.dat
Xcode 프로젝트 작성하기
다음은 Xcode 프로젝트를 작성하는 과정을 간략하게 설명한 것이다. 지면 관계상 각 단계들을 일일이 설명할 수 없는 탓이다. 어려운 과정이 아니므로 다음 과정들을 참고하여 Xcode 프로젝트를 만들어보자.
1. 파일 → 신규 프로젝트
2. 프로젝트
· 프로젝트명: myCalc
· 디렉토리: .../xpcom-sample/components/
3. 왼쪽의 myCalc 라는 곳에서 오른쪽 클릭
· 추가 → 신규 타깃
· BSD/Dynamic Library
- 타깃 명: myCalc
4. [타깃 myCalc의 정보] 대화상자가 나타나면 지운다.
5. 왼쪽의 myCalc라는 곳에서 오른쪽 클릭
· 추가 → 기존의 파일
· myCalc.cpp, myCalc.h myCalcModule.cpp, myCalc.h를 선택, 정리하여 추가
· prompt가 나오면 디폴트 추가(타깃으로 추가한 조금 전 만든 myCalc에 체크가 있는 것을 확인)
6. 왼쪽의 myCalc라는 곳에서 더블 클릭
· [프로젝트 myCalc의 정보] 대화상자가 표시된다
· [일반] 탭 → [타깃 SDK를 사용한 크로스 개발]: [Mac OS X 10.4 (Universal)]
· [빌드] 탭 → [구성]: [모든 구성]
· [아키텍처] → 아래쪽에 있는 [편집] 버튼: [PowerPC]와 [Intel]에 체크
· [헤더 검색 패스] → 아래쪽에 있는 [편집]버튼: 아래에 있는 [+] 버튼을 누르고 항목을 늘려 gecko-sdk/include에 패스를 정한다
- 상대 패스로 하는 경우에는 소스 중에서 components/ 디렉토리로부터 지정
- 샘플 소스 중에서는 톱 디렉토리(xpcom-sample)와 같은 디렉토리에 gecko-sdk로 있다
· [라이브러리 검색 패스] → 아래쪽에 있는 [편집] 버튼: 아래에 있는 [+] 버튼을 누르고 항목을 늘려 Firefox.app/Contents/Mac OS에 패스워드를 정한다
- 샘플 소스 중에서는 /Applications/ 이하에 Firefox.app 하지만 인스톨 되어 있다
· [다른 링커 옵션] → 아래쪽에 있는 [편집] 버튼: 아래에 있는 [+] 버튼을 5회 누르고 항목을 늘려, 각각 [-lxpcom_core]와 [-lxpcom], [-lnspr4], [-lplds4], [-lplc4] 추가
7. 메뉴로부터 [빌드] → [모든 타깃을 클리닝]
8. 메뉴로부터 [빌드] → [빌드]
9. 메인 윈도우의 왼쪽의 [에러와 경고]를 보고 경고·에러가 나와 있지 않은 것을 확인
비주얼 스튜디오의 솔루션 작성 방법
다음은 비주얼 스튜디오에서 솔루션을 작성하는 방법을 간단히 정리한 것이다. 만약 비주얼 스튜디오의 사용법이 익숙지 않다면 다음 내용을 참조하여 솔루션을 작성해 보자.
1. 파일 → 신규 작성 → 프로젝트
2. Visual C++ → 프로젝트
· 프로젝트명: myCalc
· 장소: .../xpcom-sample/components/
· 솔루션의 디렉토리를 작성: 체크 하지 않음
3. 완료
4. 왼쪽의 myCalc → 원시 파일로 오른쪽 클릭
· 추가 → 기존의 항목 → 상의 폴더에 말해 myCalc.cpp와 myCalcModule.cpp 선택 → 추가
5. 왼쪽의 myCalc → 헤더 파일로 오른쪽 클릭
· 추가 → 기존의 항목 → 상위 폴더에서 myCalc.h와 myICalc.h를 선택 → 추가
6. 프로젝트 → myCalc 의 프롭퍼티
· 왼쪽 위의 드롭다운 리스트의 구성: 모든 구성
· 구성 프로퍼티 → C/C++ → 전반 → 추가의 인클루드 디렉토리
- ......gecko-sdkinclude(xpcom-sample와 같은 레벨의 gecko-sdk)
· 구성 프롭퍼티 → 링커 → 전반 → 추가의 라이브러리 디렉토리
- ......gecko-sdklib(xpcom-sample와 같은 레벨에 gecko-sdk)
· 구성 프롭퍼티 → 링커 → 입력 → 추가의 의존 파일
- xpcomglue_s.lib xpcom.lib nspr4.lib
- Rlease로 구성하여 libcmt.lib 추가
- 구성을 모든 구성에 되돌린다
· 구성 프롭퍼티 → 링커 → 입력 → 특정의 라이브러리의 무시
- MSVCRT
· 구성 프롭퍼티 → 링커 → 마니페스트 → 마니페스트의 생성
- 아니오
다음과 같이 나오면 .xpt의 인스톨은 성공한 것이다.
142,myICalc.xpt,6,134,1173341340000
1294,myICalc,{c95498ae-16f5-4b46-8713-2cf79e30d4ef},142,-1,1
이번에는 XPCOM이 정상적으로 인스톨 되었는지 확인하기 위해 다음과 같이 입력해 본다.
% grep myCalc /Library/Application Support/Firefox/Profiles/*/ compreg.dat
입력한 내용의 성공 메시지는 다음과 같다.
abs:/.../xpcom-sample@imaso.co.kr/components/libmyCalc. dylib,1173345060000
{8931dfd3-edf3-4b7d-bd44-1da72064f0dc},,,,abs:/.../ libmyCalc.dylib
C++ 의 XPCOM on 윈도우
윈도우에서의 XPCOM 확장자(extension)는 .dll이다. 또, 비주얼 스튜디오는 Makefile이 아니라, 솔루션 파일을 사용해 컴파일 한다. 이런 특징에 유연하게 대처하려면 dist.sh를 변경해야 한다.
비주얼 스튜디오 8의 솔루션 파일은 components/myCalc/my Calc.sln에 배치하기로 한다. 또, devenv.exe(비주얼 스튜디오 8의 커맨드 명)에 패스워드가 걸리지 않은 경우는 C:Program Files\Microsoft Visual Studio 8\Common7IDE\devenv.exe 에 있다고 가정한다.
<리스트 19> 윈도우 환경에 맞게 인스톨 패스와 파일 확장자를 수정한 dist.sh
#!/bin/sh
cd dirname $0
if [ -x "which gnused 2>&1 /dev/null" ]; then
SED=gnused
else
SED=sed
fi
#basename=basename $PWD
basename=xpcom-sample
version=grep '<em:version>' install.rdf | $SED -e 's,</?em:version>,,g'
version=echo $version | $SED -e 's/[[:space:]]//g'
xpi=$basename-$version.xpi
case uname in
Linux)
(cd components && make) || exit 1
component_shared="components/myCalc.so"
;;
Darwin)
build_type=Release
xcodebuild_args="-project myCalc.xcodeproj -configuration $build_type"
(cd components && xcodebuild $xcodebuild_args) || exit 1
component_shared="components/libmyCalc.dylib"
cp components/build/$build_type/libmyCalc.dylib $component_shared
;;
CYGWIN*)
build_type=Release
if which devenv > /dev/null; then
DEVENV="devenv"
else
DEVENV="/cygdrive/c/Program Files/Microsoft Visual Studio 8/Common7/IDE/devenv.exe"
fi
"$DEVENV" /Build $build_type components/myCalc/myCalc.sln || exit 1
component_shared="components/myCalc.dll"
cp components/myCalc/$build_type/myCalc.dll $component_shared
;;
*)
echo "Unknown environment"
exit 1
;;
esac
component_xpt="components/myICalc.xpt"
components="$component_xpt $component_shared"
xpi_contents="content $components chrome.manifest install.rdf"
rm -f $xpi
zip -q -r -9 $xpi $xpi_contents -x */.svn/* || exit 1
.xpt 와 .h 의 생성
윈도우용의 gecko-sdk에 들어 있는 xpidl은 오래된 버전의 glib와 libIDL이 컴파일 되어 있다. 이것은 다음과 같이 하면 확인할 수 있다.
% objdump -p ../gecko-sdk/bin/xpidl.exe | grep -i dll
DllCharacteristics 00000000
vma: Hint Time Forward DLL First
DLL Name: libIDL-0.6.dll
DLL Name: glib-1.2.dll
DLL Name: MSVCRT.dll
xpidl의 옵션은 리눅스와 같아서 생략한다.
인스톨 편집
다른 OS에서와 마찬가지로 다음과 같이 dist.sh를 실행해하여 .xpi를 작성한다.
% ./dist.sh
인스톨 하려면 다른 플랫폼과 똑같이 xpcom-sample-0.1.xpi를 파이어폭스에 드래그앤드롭하면 인스톨 된다. 메뉴에 [XP COM sample]이 표시되면 [Call sample XPCOM]를 실행시켜 ‘3 + 4 = 7’라는 메시지가 표시되는지 확인한다.
인스톨 여부를 커맨드 라인에서 확인하려면 다음과 같이 입력한다.
% grep myICalc /cygdrive/c/Documents and Settings/$USER/ Application Data/Mozilla/Firefox/Profiles/*/xpti.dat
다음과 같은 결과가 표시되면 .xpt의 인스톨은 성공이다.
4,myICalc.xpt,3,134,1173668700000
587,myICalc,{c95498ae-16f5-4b46-8713-2cf79e30d4ef},4,-1,1
마지막으로 XPCOM이 인스톨 되었는지 확인하기 위해 다음과 같이 입력하면 된다.
% grep myCalc /cygdrive/c/Documents and Settings/$USER /Application Data/Mozilla/Firefox/Profiles/*/compreg.dat
XPCOM 인스톨 확인 메시지는 다음과 같다.
abs:C:\...\xpcom-sample@imaso.co.kr\components\ myCalc.dll,1173763800000
{8931dfd3-edf3-4b7d-bd44-1da72064f0dc},,,,abs:C:\ ...\myCalc.dll
지금까지 각 운영체제별 XPCOM 개발 예제에 대해 간단히 알아보았다. 지면 한계상 의도했던 내용의 절반 정도 밖에는 소개하지 못하여 아쉬움이 남는다. 하지만 우리에겐 인터넷과 커뮤니티가 있다. 아직 한국의 모질라 개발자 커뮤니티 등에는 다양한 자료와 질문, 답변들이 준비되어 있다. 특집 4부의 내용을 기반으로 커뮤니티의 자료들을 참고하면 XPCOM에 대해 좀 더 다양한 지식들을 얻을 수 있을 것이다.
'WEB2.0' 카테고리의 다른 글
JSON...javascript에 대한 짧은 이야기... (0) | 2007.11.28 |
---|---|
[액티브X 대체기술 5부] - MS가 내놓은 액티브X 컨트롤의 대안 실버라이트 활용법 (0) | 2007.09.27 |
[액티브X 대체기술 3부] - Ajax를 이용한 UI개발 (0) | 2007.09.27 |
[액티브X 대체기술 2부] - 발등의 불끄기 공인인증서 대체 기술 (0) | 2007.09.27 |
[액티브X 대체기술 1부] - 백조에서 미운오리로 전략한 액티브X의 문제와 해결방안 (0) | 2007.09.27 |