GTK+ 어플리케이션 컴파일

1. gcc

GNU C 컴파일러이다. 리눅스 뿐만 아니라 솔라리스나 MS 윈도우즈에서도 사용 가능하다. 기본적으로 libc는 glibc를 사용한다.

$gcc test.c -o test

가장 기본적인 형식이다. '-o'는 output 즉 결과물인 실행파일이다.

다음과 같은 프로그램을 만들어 실행해 보자 후에 pkg-config를 설명할때도 사용할것이니 한번 만들어보자. 파일명은 test.c로 작성하도록 하자.

int main (int argc, char *argv[]) {

int i = 0; // i = 1부터 시작해야한다. 1부터 명령행에 넣은 인자이다.

for (i = 1; i < argc; i++) {

printf(" %s", argv[i]);

}

printf("\n");

return 0;

}

그럼 이것을 위에 설명했던 방법으로 컴파일한뒤 실행해보자.

$gcc test.c -o test $./test hi hi

아무문제없이 컴파일되었다면 위와같은 결과가 나온다.

2. pkg-config

'man pkg-config' 를 해보면 NAME의 항목에 "Return metainformation about installed libraries"와 같이 설명되어있다. 간단하지만 가장 잘 설명해 놓은 말이다. 현재 내 시스템에 설치되어있는 라이브러리의 META정보를 반환한다.

pkg-config는 우리가 컴파일시에 주로 하던 '-I/usr/include...'와 '-lglib-2.0'등과 같은 라이브러리의 인크루딩 플래그와 링크 플래그를 미리 METAFILE에 정의해 하나의 패키지로 사용한다. gcc로 컴파일시에 인크루딩 플래그와 링크 플래그를 옵션으로 일일이 직접넣지않고 패키지명만으로도 원하는 플래그들을 자동으로 완성하여 넣어준다.

아래와 같이 실행해보자 보통 glib은 모두들 설치되어있으므로 왠만하면 될것이다.

$pkg-config --cflags --libs glib-2.0 -I/usr/include/glib-2.0 -I/usr/lib/glib-2.0.include -lglib-2.0

나의 시스템에서는 위와같이 나온다. 설명한 바와 같이 뭔가 반환했다. 그럼 저것은 무엇일까? 바로 gcc 컴파일시에 사용할 수 있는 옵션들이다. pkg-config 명령이 인크루딩 플래그와 링크 플래그를 반환했음을 알 수 있다.

이제 대충 감이 올것이다. pkg-config는 미리 METAFILE을 만들어 패키지화 시켜놓고 컴파일시을 편리하게 해 주는 것이다. 그럼 저 내용을 어떻게 컴파일시 gcc 명령에 포함하는지는 조금 더 뒤에 알아보도록 한다.

METAFILE

pkg의 약자는 무엇일까? 너무나 쉬운가? 패키지이다. pkg-config는 라이브러리의 인크루딩 플래그와 링크 플래그를 미리 METAFILE에 정의해놓고 컴파일시에 사용한다는건 이미 설명한 바로부터 알 수 있다. 시스템에 아무리 라이브러리가 깔려있다해도 METAFILE이 없으면 pkg-config는 인식할 수 없다. METAFILE을 만듬으로서 패키지화 시키게 되는것이다.

본인은 우분투를 사용하는데 우분투에는 '/usr/lib/pkgconfig'밑에 METAFILE들이 존재한다. 확장자는 '.pc'이며 패키지명 + 확장자이다. 만약 어떤 라이브러리에 대해 'sohalee.pc'라고 METAFILE을 생성한다면 패키지명은 'sohalee'가 되는것이다. 위에서 보았던 'glib-2.0.pc'라는 파일도 있을것이다. 내용은 아래와 같다.

prefix=/usr

exec_prefix=${prefix}

libdir=${exec_prefix}/lib

includedir=${prefix/include

...

Libs: -L${libdir} -lglib-2.0

Cflags: -I${includedir}/glib-2.0 -I${libdir}/glib02.0/include

리눅스 머신에서 내용을 보며 윈도우에서 글을 작성중이라 다 치고 앉아있기 너무 힘들어 중간은 생략했으나 각자들 파일을 열어보기 바란다 ㅡ.ㅡ

보면 'Libs'와 'Cflags'의 내용이 실제 컴파일시에 옵션으로 들어간다는것을 알 수 있을것이다. 자 그럼 여기서 또 하나알수 있는것이 위에서는 생략하고 넘어온 pkg-config 명령의 옵션에 대한 설명이다. '--cflags'는 'Cflags'에 정의된 내용을, '--libs'는 'Libs'에 정의된 내용을 반환값에 포함시키도록 한다.

'glib-2.0' 패키지에는 없는 내용인데 중요한것이 있다. 'gtk+-2.0.pc' 정도 되는 파일을 열어보게 되면 'Requires'라는게 있다 저곳에는 pkg-config의 다른 패키지명을 넣는것이다. 너무 많을땐 'Libs'와 'Cflags'에 일일이 쳐넣기 귀찮기도 하고 또 만약 함께 사용하는 다른 라이브러리의 구성이 바뀌기라도 한다면 관련된 METAFILE들을 모두 다 바꿀수는 없는 노릇이다. 그래서 각각의 패키지를 METAFILE로 구성해놓고 서로서로 불러서 마치 자신의 METAFILE에 직접 지정한것과 같은 효과를 보게 된다.

pkg-config를 이용한 컴파일

이렇게 장황하게 설명했는데 그럼 대체 컴파일은 어떻게 하란 말인가? 아래를 보자

$gcc `pkg-config --cflags --libs gtk+-2.0` hello.c -o hello

*) 주의사항 pkg-config 옵션을 감싸고 있는 따옴표는 쌍따옴표와 함께있는 외따옴표가 아니라

숫자 1 왼쪽에 있는 물결 밑의 따옴표이다.

위에서 'test.c'를 컴파일 할때와 무엇이 달라졌는가? 바로 컴파일 명령에 pkg-config에 관련된 내용이 추가 되었다. 위에서도 설명했듯이 pkg-config는 인크루딩 플래그와 링크 플래그를 반환한다. 실제로 GTK 어플리케이션을 컴파일 하기 위해선 엄청난 옵션이 줄줄이 붙어야하지만 pkg-config가 'gtk+-2.0.pc'를 읽어와 필요한 플래그들을 완성한뒤 반환해 주게되는것이다.

다음을 직접 실행하여 결과를 보도록 하자.

$ pkg-config --cflags gtk+-2.0

-I/usr/include/gtk-2.0 -I/usr/lib/gtk-2.0/include -I/usr/include/glib-2.0

-I/usr/lib/glib-2.0/include -I/usr/include/pango-1.0 -I/usr/X11R6/include

-I/usr/include/freetype2 -I/usr/include/atk-1.0

$ pkg-config --libs gtk+-2.0

-L/usr/lib -L/usr/X11R6/lib -lgtk-x11-2.0 -lgdk-x11-2.0 -lXi

-lgdk_pixbuf-2.0 -lm -lpangox -lpangoxft -lXft -lXrender -lXext -lX11

-lfreetype -lpango -latk -lgobject-2.0 -lgmodule-2.0 -ldl -lglib-2.0

사실 우리는 저걸 컴파일 명령행에 다 넣어주었어야하는것이다. pkg-config를 이용하면 실제로 'gcc 위의결과내용들 hello.c -o hello'와 같은 컴파일 명령을 내린것이 되는것이다.

여러개의 패키지를 사용하여 컴파일 하려면 아래와 와같이 패키지명을 나열해주면된다.

`pkg-config --cflags --libs gtk+-2.0 libgnomecups-1.0`

만약 GTK 개발용 라이브러리도 설치되어있는데 컴파일이 안된다면 pkg-config 패키지 설정파일중 GTK와 관련된 파일명이 무엇인지 확인해 보아야 할 것이다.

오는 길이 이리도 멀었는데 결과가 너무 허무한가? 딱 저한줄만 보면 허무하겠지만 저 한줄을 만들어내기위해 pkg-config를 만드느라 날밤깠을 개발자에게 경의를 좀 표해주자. 별거아니라 생각할 수도 있겠으나 그대는 했는가?

(제길 재미없으니 농담은 그만 집어 치우자 -_-; 이렇게 간단한걸 왜이리도 어렵고 길게 설명했지라고 생각한다면 그대는 더이상 이 강좌를 볼 필요가 없다. 앞으로도 이럴것이기 때문이다. 여기까지 쭉 강좌가 이어지며 왜 그래야하는가를 누누히 설명하였으므로 생략하겠다. 그나마 pkg-config는 이 강좌에서 권외라고 생각되기도 하고 본인의 역량을 뛰어넘는 부분이라 아는것만 줄여서 짧게한것이다.)

사용법은 의외로 간단하지만 저렇게 만들기 위해 pkg-config라는것이 있어야하고 pkg-config에서 사용할 수 있게 METAFILE을 만들어 패키지화 시켜놓아야한다. pkg-config에 대한 배려가 되지 않은 라이브러리를 사용할때라도 매번 컴파일 옵션을 일일이 쳐 넣는것이 아니라 METAFILE을 만들어 사용한다면 매우 편리하게 사용할 수 있을것이다. 본인 역시 예전에 gtkmozembed였나 poppler였나 여튼 무언가를 사용하기 위해 만들어 썼던 기억이 있다.

헉 이런 젠장

강좌를 보며 흡족해 하고 있는데 움찔해버렸다. 위에서 'test.c'를 만든 이유를 까마득히 잊고 있었다. 머리에 '무안단물'이라도 뿌려줘야하는건가. 그래 그건 pkg-config가 하는것을 확실하게 보여주기 위해서였다. 한번 해보자 --;

$./test `pkg-config --cflags --libs gtk+-2.0`

-I/usr/include/gtk-2.0 -I/usr/lib/gtk+-2.0/include... (늠흐 길다 -0-)

위에서 'test.c'는 명령행에 인자로 넘어오는 내용들을 모두 출력하게끔 제작되어졌다 그렇다 `pkg-config --cflags --libs gtk+-2.0` 바로 이것으로 인해 실제 명령행에는 위와같은 내용이 포함되어진 것이다.

만약 아직 gtk+-2.0이 아직 없다면 glib-2.0이나 METAFILE이 존재하는 다른 패키지명을 넣어서 결과를 확인해보라