glib, gtk 팝업 사전 만들기 2화


사전 이름을 tiandict 로 하자. minidict 하려고 했더니 그걸 사용하는 상업용 어플이 있는 거

같음. 상표권 등록 여부는 모르겠고, 혹시라도 상표권 문제 발생하면 안 되니까..

tiandict 라고 구글에서 검색해보니 별거 없음. 그래서 tiandict 로 함.

어플 이름 정할 때는 상표권 문제가 발생할 소지가 있는 이름은 필히 피해야함.


맨땅에서 만들 수 있도록 c 에 대해서도 대략적으로 설명할 거임

c 언어로 만들 수 있는게 두 종류가 있음.


실행형 파일, 라이브러리(리눅스에서는 .so .a)


여기서 다루는 거는 실행형 파일임


실행이 되려면 main () 함수는 필수적이고,

main () 함수 원형은


int main (int argc, char **argv);

int main (int argc, char *argv[]); 이렇게 쓰기도 함.


argc 는 인수 갯수, argv 는 인수 문자열 배열임.

시작부터 포인터 나왔네? 어쩌지... 겁먹지 말구, 일단 넘어가자구^^

많이 쓰는거는 char *, char ** 이렇게 두가지임. char 이런건 타입(type, 형)이라는거구

sometype *, sometype ** 이렇게 많이 쓰지.


char c;


여기에는 보통 'a' 이런 문자 딱 1개 들어감. 1바이트 범위내의 숫자도 넣을 수 있음.


char *text;


여기에는 "Hello" 이런 문자열이 들어가구, text 로 "Hello" 통으로 문자열 받을 수 있음.

마지막엔 NULL 문자가 들어 있음. text[0], text[1] 이런 식으로 문자 1개씩 접근 가능.

"Hello" 하면 메모리가 5 바이트 를 차지하는게 아니라, 마지막에 NULL ('\0') 을 자동으로 넣기

때문에, 메모리가 6 바이트가 차지함.


char **text_list;


여기에는 "Hello 1", "Hello 2", "Hello 3" 이런 식으로 문자열 리스트를

구성할 수 있음. text_list[0] 에는 "Hello 1", text_list[1] 에는 "Hello 2", ...

이런 식으로 들어감. 1개의 문자에 접근할 때는 text_list[0][0], text_list[0][1]

이런 식으로 하면 됨. 그리고 text++ 이런식으로 포인터 연산가능하고 1씩 증가하는게 아니라

sizeof (char *) 씩 증가함. 실제 해보니 8씩 증가하는거 같음.

옛날에 sizeof (void *) 했을 때 4씩 증가했던거 같은데.

char *c; 에서 c++ 하면 sizeof (char) 1씩 증가하구.

포인터 연산이나, var[i] 이렇게 접근할 때 주의할 점이 있는데, 마지막 값에서 정지를 시키지 않으면

프로그램 죽음. 그래서 문자열 마지막에는 '\0' (NULL) 이라는 걸 넣어줌.

"aoeu" 이런식으로 큰 따옴표 쓰면 마지막에 '\0' 이 자동으로 들어감.

char **text_list 여기에 뭔가를 할당했다면, 마지막에는 NULL 이라는 걸 넣어줘야 함.

안 넣어도 되는데 NULL 을 넣는게 좋음.

(sometype *** 이런건 거의 안쓰므로 여기서는 패스)


#include <stdio.h> #include <stdlib.h> #include <string.h> int main (int argc, char *argv[]) { char **text_array; int text_array_len = 3; char **p; int i; /* NULL 넣을려구 메모리를 1개 더 할당 */ text_array = malloc (sizeof (char *) * (text_array_len + 1)); text_array[0] = strdup ("Hello 1"); text_array[1] = strdup ("Hello 2"); text_array[2] = strdup ("Hello 3"); text_array[3] = NULL; /* 이렇게 접근하는 방법 있고 */ for (i = 0; i < text_array_len; i++) /* 0 1 2 총 3개 반복 */ printf ("%s\n", text_array[i]); puts (""); /* 이렇게 접근하는 방법 있음 text_array[i] 가 NULL 일때 탈출 */ /* 이 경우 text_array_len 을 몰라도 됨 */ for (i = 0; text_array[i]; i++) /* for (i = 0; text_array[i] != NULL; i++) */ printf ("%s\n", text_array[i]); free (text_array); return 0; }


다들 포인터 때문에 어렵다고 느끼고 일부 사람들은 포기를 하지 ㅋㅋㅋㅋㅋㅋ

포기하지 말구 포인터 예제만 나와있는 책 한 권에 컴퓨터 구조나 운영체제 책에

메모리 직접 주소, 간접 주소, 가상 페이징 챕터 보면 포인터는 다 이해할 수 있음.

대부분의 책이 그림으로 설명되어 있음.


c 언어에서 또 반드시 알아야 할 부분이 main() 함수


파일 이름을 tiandict.c 라고 하자.


#include <stdio.h> int main (int argc, char **argv) /* int main (int argc, char *argv[]) */ { int i; for (i = 0; i < argc; i++) printf ("argc[%d]: %s\n", i, argv[i]); return 0; }


컴파일은 이렇게 함.


$ cc tiandict.c -o tiandict


명령 줄에서 ./tiandict -v -h 이렇게 명령을 내리면, (./ 는 현재 디렉토리를 의미)


argc 가 3이 됨.

argv[0] 에는 ./tiandict (참고로 프로그램 이름을 알아내는 함수가 있음)

argv[1] 에는 -v

argv[2] 에는 -h


main() 함수 이거는 기본적으로 알아야 하는 내용임.

위에 argc, argv 는 나중에 -h 하면 help 메시지, -v 하면 버전 나오게 하려고 필요한거임.

c 기본 라이브러리에 옵션 파싱하는 함수 있음. 그걸 이용해도 되지만 glib 에서는 좀 더 편리한 방법을

제공함. 게다가 --version, --help 이렇게 할 수 있음.


c 언어 얘기는 여기까지만 하구 우리는 glib 를 사용할 것이므로 저런 거 몰라도 glib 에서

제공해주는 함수와 api 설명을 이용하여 그냥 자바 프로그램 짜듯이 짜면 됨. 진짜임!!!


$ cc tiandict.c -o tiandict 일일히 이렇게 타이핑하려면 짜증나니까.. Makefile 만들자구


Makefile, configure 제작법 설명하자면 한 세월 걸리니까...

아래는 미리 만들어 놓은 Makefile 템플릿. 저거 수정하면 다른데도 사용할 수 있음.

Makefile 로 저장하면 되구.


include ./config.mk TARGET = tiandict TARGET_DEPS_CFLAGS = `pkg-config --cflags glib-2.0 gobject-2.0 gtk+-3.0` TARGET_DEPS_LIBS = `pkg-config --libs glib-2.0 gobject-2.0 gtk+-3.0` SOURCES = tiandict.c CFLAGS = \     $(TARGET_DEPS_CFLAGS) \     $(EXTRA_CFLAGS) \     -DVERSION=\"$(VERSION)\" \     -DTARGET_LOCALE_DIR=\"$(TARGET_LOCALE_DIR)\" LDFLAGS = $(TARGET_DEPS_LIBS) $(EXTRA_LDFLAGS) all: $(TARGET) $(TARGET): $(SOURCES) Makefile     $(CC) $(CFLAGS) $(SOURCES) \     -Wl,--as-needed $(LDFLAGS) -o $(TARGET) clean:     rm -f $(TARGET) config.mk install:     install -D -m 755 $(TARGET) -t $(DESTDIR)$(prefix)/bin uninstall:     rm -f $(DESTDIR)$(prefix)/bin/$(TARGET)     -rmdir -p $(DESTDIR)$(prefix)/bin


위에 보면 config.mk 라는 파일을 include 하네.. 고거는 자동생성한 makefile 파일임.

autotools 이런거 써도 되는데 이렇게 configure 파일을 이렇게 직접 만들어도 됨.

손맛이 있어야지... 그래야 속도두 빠르고^^


아래는 configure 파일


#!/bin/sh # default variables prefix="/usr/local" EXTRA_CFLAGS="-Wall -Werror" EXTRA_LDFLAGS="-Wl,-z,relro" hardening="-D_FORTIFY_SOURCE=2 -O1" for i in "$@" do case $i in --disable-hardening) hardening="" ;; --libdir=*) libdir="${i#*=}" ;; --prefix=*) prefix="${i#*=}" ;; --help|*) echo "Usage: ./configure [OPTION]..." echo " --help Show help messages" echo " --disable-hardening Disable hardening" echo " --libdir=PATH Set PATH to libdir" echo " --prefix=DIRECTORY Set DIRECTORY to prefix" exit 1 ;; esac done [ -z $libdir ] && libdir="$prefix/lib" eval libdir=$libdir EXTRA_CFLAGS=$EXTRA_CFLAGS" $hardening" errmsg="" # check required packages if ! pkg-config --exists glib-2.0; then errmsg+=" glib-2.0"; fi if ! pkg-config --exists gobject-2.0; then errmsg+=" gobject-2.0"; fi if ! pkg-config --exists gtk+-3.0; then errmsg+=" gtk+-3.0"; fi # print error messages if test -n "$errmsg"; then echo "Not found: $errmsg" exit 1 fi # generate config.mk cat > config.mk <<- EOF EXTRA_CFLAGS = $EXTRA_CFLAGS EXTRA_LDFLAGS = $EXTRA_LDFLAGS VERSION = 2020.03.07 CC = cc top_srcdir = $(pwd) prefix = $prefix libdir = $libdir datadir = $prefix/share GETTEXT_PACKAGE = tiandict TARGET_LOCALE_DIR = $prefix/share/locale MKDIR_P = mkdir -p EOF echo "Generated config.mk" echo "----------------------------------------------------------------" cat config.mk echo "----------------------------------------------------------------"


어떻게 써먹냐면,


chmod +x configure 이렇게 실행 권한 주고.

설명 보려면 ./configure --help 하면 되구

./configure 이렇게 명령하면 config.mk 라는 makefile 생성됨.

에러나면 에러 메시지 보고 필요한 패키지 설치하면 되구. autotools 보다 속도 50배~100배 빠름.

config.mk 생성 후

make 때리면 됨

에러나면 위에 tiandict.c Makefile 저장해놓았는지 확인하구.

Makefile 안에 all: clean: .... 이렇게 있는데, 그 다음 줄은 TAB 으로 시작되어야 함.

Space(공백 문자) 로 시작하면 에러 떨어짐. 원래 그게 Makefile 문법 규칙임.

make clean 하면 생성된 파일들 깔끔하게 모두 삭제됨.

make install 하면 인스톨되구,

make uninstall 하면 언인스톨

여기까지 하면 빌드시스템 구축이 완료된 거임.

c 로 뭐 만들 때 저런 걸 자동으로 해주는 툴들이 별로 없어서 손으로 cc -L.. -I.. -l... 이런

명령 때리다가 멘붕오는 사태 많이 벌어지지 ㅋㅋ Makefile, configure 템플릿 파일 저장해

놓았다가 나중에 뭐 만들 때, 수정해서 써먹으면 좋음. 참 쉽죠잉?