<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0">
	<channel>
		<title>Superkkt Blog</title>
		<link>http://superkkt.com/</link>
		<description>프로그램 개발과 관련된 지식을 정리하는 공간입니다.</description>
		<language>ko</language>
		<pubDate>Thu, 17 May 2012 12:28:34 +0900</pubDate>
		<generator>Textcube 1.7.8 : Con moto</generator>
		<image>
		<title>Superkkt Blog</title>
		<url>http://superkkt.com/attach/1/9636956052.gif</url>
		<link>http://superkkt.com/</link>
		<width>140</width>
		<height>120</height>
		<description>프로그램 개발과 관련된 지식을 정리하는 공간입니다.</description>
		</image>
		<item>
			<title>Android Compile</title>
			<link>http://superkkt.com/748</link>
			<description>&lt;h3&gt;1. 안드로이드 컴파일&lt;/h3&gt;&lt;div&gt;&lt;br&gt;&lt;/div&gt;안드로이드(커널 제외)를 컴파일해서 전화기에 설치하는 기본적인 과정은 아래 공식 사이트를 참조한다.&lt;div&gt;&lt;br&gt;&lt;/div&gt;&lt;div&gt;&lt;a href=&quot;http://source.android.com/source/initializing.html&quot;&gt;http://source.android.com/source/initializing.html&lt;/a&gt;&lt;br&gt;&lt;/div&gt;&lt;div&gt;&lt;br&gt;&lt;/div&gt;&lt;div&gt;참고로 안드로이드 소스코드에는 pre-built된 커널 이미지가 들어있기 때문에 커널 컴파일을 별도로 하지 않고 안드로이드만 컴파일해서 설치해도 상관없다. 하지만 커널을 수정하거나 또는 기타 다른 이유로 커널 컴파일을 직접 하는 경우에는 먼저 안드로이드 소스코드를 다운로드 받은 상태에서 커널을 먼저 컴파일하고, 컴파일된 커널 파일을 안드로이드 소스트리로 복사한 후에 안드로이드를 컴파일하고 전화기에 설치해야 한다. (2. 안드로이드 커널 컴파일 부분 참조)&lt;/div&gt;&lt;div&gt;&lt;br&gt;&lt;/div&gt;&lt;div&gt;아래는 안드로이드 컴파일 중에 주의해야 할 내용들이다.&lt;br&gt;&lt;/div&gt;&lt;div&gt;&lt;br&gt;&lt;/div&gt;&lt;h4&gt;1) Device Specific Files&lt;/h4&gt;&lt;div&gt;&lt;br&gt;&lt;/div&gt;&lt;div&gt;안드로이드를 특정 전화기 모델에 올리기 위해 컴파일 할 때에는 해당 전화기에서 사용하는 proprietary binaries를 전화기에서 추출해서 안드로이드 소스코드 트리에 저장하고 컴파일을 해야 한다.&lt;/div&gt;&lt;div&gt;&lt;br&gt;&lt;/div&gt;&lt;div&gt;이 예제에서는 갤럭시 넥서스(maguro)를 사용한다고 가정하고, 먼저 안드로이드 소스트리의 최상위 디렉토리에서 아래와 같이 빌드 환경을 구축한다.&lt;/div&gt;&lt;div&gt;&lt;br&gt;&lt;/div&gt;&lt;div&gt;&lt;div style=&quot;padding:10px; background-color:#E4E4E4&quot;&gt;&lt;div&gt;$ . build/envsetup.sh&lt;/div&gt;&lt;div&gt;$ lunch full_maguro-userdebug&lt;/div&gt;&lt;div&gt;$ make fastboot adb&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;br&gt;&lt;/div&gt;&lt;div&gt;전화기를 호스트 PC에 USB 케이블로 연결하고, 아래와 같이 proprietary binaries를 전화기에서 추출한다.&lt;/div&gt;&lt;div&gt;&lt;br&gt;&lt;/div&gt;&lt;div style=&quot;padding:10px; background-color:#E4E4E4&quot;&gt;&lt;div&gt;$ cd device/samsung/maguro&lt;/div&gt;&lt;div&gt;$ ./extract-files.sh&lt;br&gt;&lt;/div&gt;&lt;div&gt;$ cd ../../../&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;br&gt;&lt;/div&gt;&lt;div&gt;그럼 vendor라는 디렉토리가 소스코드 최상위 디렉토리에 생성되고, 추출된 파일들이 여기에 저장되어 있을것이다.&lt;/div&gt;&lt;div&gt;&lt;br&gt;&lt;/div&gt;&lt;div&gt;이제 안드로이드 소스코드를 컴파일하면 된다. 추출된 proprietary binaries 파일들은 system.img 파일에 포함되어서 전화기에 설치된다. 자세한 컴파일 및 설치 과정은 공식 사이트를 참조한다.&lt;/div&gt;&lt;div&gt;&lt;br&gt;&lt;/div&gt;&lt;div style=&quot;padding:10px; background-color:#E4E4E4&quot;&gt;&lt;div&gt;$ make -j8&lt;br&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;br&gt;&lt;/div&gt;&lt;h4&gt;2) Radio / Bootloader 설치&lt;/h4&gt;&lt;div&gt;&lt;br&gt;&lt;/div&gt;&lt;div&gt;&lt;a href=&quot;http://source.android.com/source/building-devices.html&quot; target=&quot;_blank&quot;&gt;여기&lt;/a&gt;를 보면 안드로이드 버전별로 호환되는 Cell Radio / Bootloader 버전이 명시되어 있다. 만약 전화기에 설치된 Cell Radio / Bootloader 중 하나라도 현재 설치하려는 안드로이드 버전과 호환되지 않는다면 컴파일한 안드로이드를 전화기에 설치(flash) 할 수 없다.&lt;/div&gt;&lt;div&gt;&lt;br&gt;&lt;/div&gt;&lt;div&gt;새로운 Cell Radio / Bootloader를 구할 수 있는 공식적인 경로는 찾지 못했는데, 대신 구글에서 배포하는 전화기별 Pre-built Factory Image에서 필요한 파일들을 뽑아낼 수 있다. Factory Image는 &lt;a href=&quot;http://code.google.com/intl/ko-KR/android/nexus/images.html&quot; target=&quot;_blank&quot;&gt;여기&lt;/a&gt;에서 버전별로 다운로드 받을 수 있고, 갤럭시 넥서스용 안드로이드 4.0.2에는 radio-maguro-i9250xxkk6.img와 bootloader-maguro-primekk15.img라는 파일로 들어가 있다. 이 파일들을 전화기에 설치하는 방법은 Factory Image의 flash-all.sh 파일에서 하는대로 아래와 같이 하면 된다. 단, 아래 작업은 전화기가 fastboot mode로 들어간 상태에서 해야 한다.&lt;/div&gt;&lt;div&gt;&lt;br&gt;&lt;/div&gt;&lt;div style=&quot;padding:10px; background-color:#E4E4E4&quot;&gt;&lt;div&gt;$ fastboot flash bootloader bootloader-maguro-primekk15.img&lt;/div&gt;&lt;div&gt;$ fastboot reboot-bootloader&lt;/div&gt;&lt;div&gt;$ fastboot flash radio radio-maguro-i9250xxkk6.img&lt;/div&gt;&lt;div&gt;$ fastboot reboot-bootloader&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;br&gt;&lt;/div&gt;&lt;div&gt;&amp;nbsp;&lt;/div&gt;&lt;h4&gt;3) Ubuntu 11.10에서 발생하는 컴파일 에러&lt;/h4&gt;&lt;div&gt;&lt;br&gt;&lt;/div&gt;&lt;div&gt;Ubuntu 11.10(gcc-4.6)에서 Android 4.0.x를 컴파일 할 때 여러 에러가 발생한다. 임시방편으로 gcc-4.4와 g++4.4를 설치해서 대신 사용하면 문제 없이 컴파일 할 수 있다.&lt;/div&gt;&lt;div&gt;&lt;br&gt;&lt;/div&gt;&lt;div style=&quot;padding:10px; background-color:#E4E4E4&quot;&gt;&lt;div&gt;$ sudo apt-get install gcc-4.4 gcc-4.4-multilib g++-4.4 g++-4.4-multilib&lt;/div&gt;&lt;div&gt;$ make -j8 CC=gcc-4.4 CXX=g++-4.4&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;br&gt;&lt;/div&gt;&lt;div&gt;컴파일러 버전을 바꾸는 대신 아래 참고 사이트의 내용대로 직접 소스코드를 수정해서 해결할 수도 있다.&lt;/div&gt;&lt;div&gt;&lt;br&gt;&lt;/div&gt;&lt;div&gt;참고로 4.0.3 버전이 나온 현 시점에서 Android master 브랜치의 코드는 Ubuntu 11.10(gcc-4.6)에서 발생하던 에러가 모두 해결되어서 정상적으로 컴파일이 된다.&lt;/div&gt;&lt;div&gt;&lt;br&gt;&lt;/div&gt;&lt;div&gt;참고: &lt;a href=&quot;http://groups.google.com/group/android-building/browse_thread/thread/0207abb98ed72304&quot;&gt;http://groups.google.com/group/android-building/browse_thread/thread/0207abb98ed72304&lt;/a&gt;&lt;/div&gt;&lt;div&gt;&lt;br&gt;&lt;/div&gt;&lt;div&gt;&lt;br&gt;&lt;/div&gt;&lt;h3&gt;2. 안드로이드 커널 컴파일&lt;/h3&gt;&lt;div&gt;&lt;br&gt;&lt;/div&gt;&lt;div&gt;안드로이드 커널은 별도로 분리되어서 관리된다. 안드로이드 소스코드에 pre-built된 커널 코드가 들어있어서 안드로이드만 컴파일해서 전화기에 설치해도 바로 사용이 가능하지만, 커널 레벨에서 뭔가 수정을 하려면 직접 안드로이드 커널 소스코드를 컴파일해야 한다.&lt;/div&gt;&lt;div&gt;&lt;br&gt;&lt;/div&gt;&lt;div&gt;&lt;div style=&quot;font: normal normal normal 13px/1.6 NanumGothic, 나눔고딕, &#039;Malgun Gothic&#039;, &#039;맑은 고딕&#039;, AppleGothic, 바탕, verdana, dotum, sans-serif; &quot;&gt;&lt;div&gt;커널은 디바이스별로 따로 구해야 하는데, 보통 전화기 제조사 사이트에서 구할 수 있다. 내가 사용하는 갤럭시 넥서스는 삼성에서 제조했지만 레퍼런스 폰이라서 관리는 구글이 직접한다. 따라서 커널 코드도 구글이 관리하기 때문에 &lt;a href=&quot;http://source.android.com/source/downloading.html&quot; target=&quot;_blank&quot;&gt;구글 공식 사이트&lt;/a&gt;에서 커널을 다운로드 받을 수 있다. 갤럭시 넥서스는 OMAP 프로세서를 사용하기 때문에 커널 트리 중에서 omap.git를 clone 받으면 된다.&lt;/div&gt;&lt;div&gt;&amp;nbsp;&lt;/div&gt;&lt;div&gt;&lt;div style=&quot;padding-top: 10px; padding-right: 10px; padding-bottom: 10px; padding-left: 10px; background-color: rgb(228, 228, 228); &quot;&gt;$ git clone https://android.googlesource.com/kernel/omap.git&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;br&gt;&lt;/div&gt;&lt;div&gt;그리고 clone 받은 omap 트리에서 한국에 판매된 GSM/HSDPA용 갤럭시 넥서스(코드네임: tuna)의 커널 코드를 체크아웃한다. 참고로 git branch -a를 사용하면 어떤 브랜치들이 있는지 볼 수 있다.&lt;/div&gt;&lt;div&gt;&lt;br&gt;&lt;/div&gt;&lt;div style=&quot;padding:10px; background-color:#E4E4E4&quot;&gt;&lt;div&gt;$ cd omap&lt;/div&gt;&lt;div&gt;$ git checkout remotes/origin/android-omap-tuna-3.0&lt;br&gt;&lt;/div&gt;&lt;div&gt;$ git checkout -b remotes/origin/android-omap-tuna-3.0&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;br&gt;&lt;/div&gt;&lt;div&gt;이제 체크아웃 받은 커널 코드의 README 파일을 먼저 읽어보고, 아래 순서에 따라 커널을 컴파일한다.&lt;/div&gt;&lt;div&gt;&lt;br&gt;&lt;/div&gt;&lt;div&gt;참고로 OMAP 프로세서는 ARM 아키텍쳐에 ARM-EABI 인터페이스를 사용하기 때문에 적절한 tool-chain이 있어야만 크로스 컴파일을 할 수 있는데, 안드로이드 소스코드 트리의 prebuilt 디렉토리에 필요한 tool-chain이 들어있다.&lt;/div&gt;&lt;div&gt;&lt;br&gt;&lt;/div&gt;&lt;div&gt;이 예제에서는 호스트 머신으로 Ubuntu 11.04 x86 머신을 사용하고, 안드로이드 소스코드(커널 아님)는 /android-4.0.2_r1 디렉토리에 존재하고, 빌드된 커널 파일들은 /omap-build 디렉토리에 저장된다고 가정한다.&lt;/div&gt;&lt;div&gt;&lt;br&gt;&lt;/div&gt;&lt;div&gt;우선 갤럭시 넥서스용으로 만들어진 config 파일을 사용해서 커널 컴파일 옵션을 설정한다.&lt;/div&gt;&lt;div&gt;&lt;br&gt;&lt;/div&gt;&lt;div&gt;&lt;div style=&quot;padding:10px; background-color:#E4E4E4&quot;&gt;$ ARCH=arm make O=/omap-build tuna_defconfig&lt;/div&gt;&lt;br&gt;&lt;/div&gt;&lt;div&gt;이제 본격적으로 커널 코드를 컴파일하는데, -j 옵션을 사용해서 컴파일 속도를 높여준다. -j 옵션 뒤의 숫자는 호스트 머신에 설치된 CPU 코어 수의 두배로 설정하면 된다.&lt;/div&gt;&lt;div&gt;&lt;span style=&quot;background-color: rgb(228, 228, 228); &quot;&gt;&lt;br&gt;&lt;/span&gt;&lt;/div&gt;&lt;div style=&quot;padding:10px; background-color:#E4E4E4&quot;&gt;&lt;div&gt;$ ARCH=arm CROSS_COMPILE=/android-4.0.2_r1/prebuilt/linux-x86/toolchain/arm-eabi-4.4.3/bin/arm-eabi- make O=/omap-build -j8&lt;br&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;br&gt;&lt;/div&gt;&lt;div&gt;위 과정이 정상적으로 끝나면 컴파일된 커널은 /omap-build/arch/arm/boot/zImage 파일로 저장된다. 이제 안드로이드 소스코드의 pre-built 커널 파일을 방금 새로 컴파일한 zImage 파일로 교체한다.&lt;/div&gt;&lt;div&gt;&lt;br&gt;&lt;/div&gt;&lt;div&gt;&lt;div style=&quot;padding:10px; background-color:#E4E4E4&quot;&gt;$ cp /omap-build/arch/arm/boot/zImage &amp;nbsp;/android-4.0.2_r1/device/samsung/tuna/kernel&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;br&gt;&lt;/div&gt;&lt;div&gt;끝으로 /android-4.0.2_r1 디렉토리로 이동해서 안드로이드를 컴파일하면 새로운 커널을 포함한 안드로이드 이미지가 만들어진다. 참고로 kernel 파일은 안드로이드가 컴파일되고 난 후 boot.img 파일에 포함되어서 전화기에 설치된다. 자세한 컴파일 및 설치 과정은 공식 사이트를 참조한다.&lt;/div&gt;&lt;div&gt;&amp;nbsp; &amp;nbsp;&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;</description>
			<category>컴퓨터</category>
			<category>Android</category>
			<category>ubuntu</category>
			<category>우분투</category>
			<author>(김기태)</author>
			<guid>http://superkkt.com/748</guid>
			<comments>http://superkkt.com/748#entry748comment</comments>
			<pubDate>Sun, 29 Jan 2012 14:16:26 +0900</pubDate>
		</item>
		<item>
			<title>Qt - 하나의 프로젝트 내에서 여러 개의 바이너리 생성</title>
			<link>http://superkkt.com/729</link>
			<description>QT에서는 하나의 프로젝트(.pro) 내에서 여러 개의 바이너리를 생성하는게 autotools 보다는 조금 복잡하다.&lt;div&gt;&lt;br&gt;&lt;/div&gt;&lt;div&gt;우선 아래와 같이 두 개의 바이너리에 대한 mda.pro 파일을 만들어준다. 여기서는 mda와 mda_retrain 두 개의 바이너리가 생성된다. 각각의 바이너리는 서로 다른 라이브러리와 소스파일로 구성된다.&lt;/div&gt;&lt;div&gt;&lt;br&gt;&lt;/div&gt;&lt;div&gt;&lt;div style=&quot;padding:10px; background-color:#E4E4E4&quot;&gt;&lt;div&gt;mda {&lt;/div&gt;&lt;div&gt;&amp;nbsp; &amp;nbsp; QT += core sql network&lt;/div&gt;&lt;div&gt;&amp;nbsp; &amp;nbsp; QT -= gui&lt;/div&gt;&lt;div&gt;&amp;nbsp; &amp;nbsp; TARGET = mda&lt;/div&gt;&lt;div&gt;&amp;nbsp; &amp;nbsp; CONFIG += console&lt;/div&gt;&lt;div&gt;&lt;br&gt;&lt;/div&gt;&lt;div&gt;&amp;nbsp; &amp;nbsp; SOURCES += main.cpp \&lt;/div&gt;&lt;div&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;syslog_logger.cpp \&lt;/div&gt;&lt;div&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;mda.cpp \&lt;/div&gt;&lt;div&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;archiver.cpp \&lt;/div&gt;&lt;div&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;parser.cpp \&lt;/div&gt;&lt;div&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;utils.cpp \&lt;/div&gt;&lt;div&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;spf.cpp \&lt;/div&gt;&lt;div&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;resolver.cpp \&lt;/div&gt;&lt;div&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;spamfilter.cpp&lt;/div&gt;&lt;div&gt;&lt;br&gt;&lt;/div&gt;&lt;div&gt;&amp;nbsp; &amp;nbsp; HEADERS += logger.h \&lt;/div&gt;&lt;div&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;syslog_logger.h \&lt;/div&gt;&lt;div&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;mda.h \&lt;/div&gt;&lt;div&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;archiver.h \&lt;/div&gt;&lt;div&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;parser.h \&lt;/div&gt;&lt;div&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;utils.h \&lt;/div&gt;&lt;div&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;spf.h \&lt;/div&gt;&lt;div&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;resolver.h \&lt;/div&gt;&lt;div&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;spamfilter.h&lt;/div&gt;&lt;div&gt;&lt;br&gt;&lt;/div&gt;&lt;div&gt;&amp;nbsp; &amp;nbsp; INCLUDEPATH = /usr/local/dspam/include&lt;/div&gt;&lt;div&gt;&amp;nbsp; &amp;nbsp; LIBS += `pkg-config --libs vmime` -L/usr/local/dspam/lib -lspf2 -lresolv -ldspam&lt;/div&gt;&lt;div&gt;&amp;nbsp; &amp;nbsp; QMAKE_CXXFLAGS += -g -std=c++0x `pkg-config --cflags vmime`&lt;/div&gt;&lt;div&gt;}&lt;/div&gt;&lt;div&gt;&lt;br&gt;&lt;/div&gt;&lt;div&gt;mda_retrain {&lt;/div&gt;&lt;div&gt;&amp;nbsp; &amp;nbsp; QT += core&lt;/div&gt;&lt;div&gt;&amp;nbsp; &amp;nbsp; QT -= gui&lt;/div&gt;&lt;div&gt;&amp;nbsp; &amp;nbsp; TARGET = mda_retrain&lt;/div&gt;&lt;div&gt;&amp;nbsp; &amp;nbsp; CONFIG += console&lt;/div&gt;&lt;div&gt;&lt;br&gt;&lt;/div&gt;&lt;div&gt;&amp;nbsp; &amp;nbsp; SOURCES += mda_retrain.cpp \&lt;/div&gt;&lt;div&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;syslog_logger.cpp&lt;/div&gt;&lt;div&gt;&lt;br&gt;&lt;/div&gt;&lt;div&gt;&amp;nbsp; &amp;nbsp; HEADERS += logger.h \&lt;/div&gt;&lt;div&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;syslog_logger.h&lt;/div&gt;&lt;div&gt;&lt;br&gt;&lt;/div&gt;&lt;div&gt;&amp;nbsp; &amp;nbsp; INCLUDEPATH = /usr/local/dspam/include&lt;/div&gt;&lt;div&gt;&amp;nbsp; &amp;nbsp; LIBS += -L/usr/local/dspam/lib -ldspam&lt;/div&gt;&lt;div&gt;&amp;nbsp; &amp;nbsp; QMAKE_CXXFLAGS += -g -std=c++0x&lt;/div&gt;&lt;div&gt;}&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;br&gt;&lt;/div&gt;&lt;div&gt;&lt;br&gt;&lt;/div&gt;&lt;div&gt;이제 qmake로 Makefile을 생성할 때 어떤 바이너리를 만들건지 지정해야 한다. 먼저 mda를 만드는 방법을 살펴보자.&lt;/div&gt;&lt;div&gt;&lt;br&gt;&lt;/div&gt;&lt;div style=&quot;padding:10px; background-color:#E4E4E4&quot;&gt;&lt;div&gt;$ qmake mda.pro CONFIG+=mda&lt;/div&gt;&lt;div&gt;$ make&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;br&gt;&lt;/div&gt;&lt;div&gt;mda_retrain 바이너리를 만들려면 CONFIG+= 뒷 부분만 mda_retrain으로 변경해주면 된다.&lt;/div&gt;&lt;div&gt;&lt;br&gt;&lt;/div&gt;&lt;div&gt;한번의 make로 만드는 방법도 있는데, 이건 소스코드를 서브 디렉토리로 분할하는 방식을 사용한다. 자세한 내용은 레퍼런스 사이트를 참조한다.&lt;/div&gt;&lt;div&gt;&lt;br&gt;&lt;/div&gt;&lt;div&gt;&lt;br&gt;&lt;/div&gt;&lt;h3&gt;&amp;lt;References&amp;gt;&lt;/h3&gt;&lt;div&gt;&lt;br&gt;&lt;/div&gt;&lt;div&gt;&lt;a href=&quot;http://stackoverflow.com/questions/2259192/building-multiple-targets-in-qt-qmake&quot; target=&quot;_blank&quot;&gt;Building multiple targets in Qt / Qmake&lt;/a&gt;&lt;br&gt;&lt;/div&gt;&lt;div&gt;&lt;a href=&quot;http://stackoverflow.com/questions/1538398/how-do-i-use-qmake-to-build-multiple-binaries-in-a-single-project&quot; target=&quot;_blank&quot;&gt;How do I use qmake to build multiple binaries in a single project?&lt;/a&gt;&lt;br&gt;&lt;/div&gt;</description>
			<category>프로그래밍</category>
			<category>qmake</category>
			<author>(김기태)</author>
			<guid>http://superkkt.com/729</guid>
			<comments>http://superkkt.com/729#entry729comment</comments>
			<pubDate>Fri, 30 Sep 2011 11:51:50 +0900</pubDate>
		</item>
		<item>
			<title>Go Language - cgo</title>
			<link>http://superkkt.com/708</link>
			<description>&lt;div&gt;&lt;b&gt;참고: SWIG를 사용하면 cgo보다 더 편하게 C 코드를 호출할 수 있고, 또 C++도 호출 가능한것 같다. 그런데 아직 문서가 제대로 안 만들어진것 같은데, 예제 코드는 $GOROOT/misc/swig/ 디렉토리를 참조한다. 그리고 SWIG 사이트에서 Go를 지원하는 내용을 간단하게 정리한 문서는 &lt;a href=&quot;http://www.swig.org/Doc2.0/Go.html&quot; target=&quot;_blank&quot;&gt;여기&lt;/a&gt;를 참조한다. SWIG 2.0부터 지원하는것 같은데 우분투 10.10에 설치된 SWIG는 버전이 낮아서 Go를 지원하지 않는다.&lt;/b&gt;&lt;/div&gt;&lt;div&gt;&lt;br&gt;&lt;/div&gt;cgo를 사용해서 go 코드에서 C 코드를 사용할 수 있다.&lt;div&gt;&lt;br&gt;&lt;/div&gt;&lt;div&gt;먼저 C 코드를 호출하는 루틴을 별도 패키지로 작성한다. 여기서는 cgotest라는 이름으로 만든다. 이 패키지는 CgoTest() 메소드를 가지는데, 문자열을 출력하고 0을 리턴하는 간단한 C 함수(f)를 호출한다. cgotest.go 파일을 생성하고 아래 내용을 입력하자. &lt;/div&gt;&lt;div&gt;&lt;br&gt;&lt;/div&gt;&lt;div&gt;&lt;div style=&quot;padding:10px; background-color:#E4E4E4&quot;&gt;&lt;div&gt;package cgotest&lt;/div&gt;&lt;div&gt;&lt;br&gt;&lt;/div&gt;&lt;div&gt;/*&lt;/div&gt;&lt;div&gt;#include &amp;lt;stdio.h&amp;gt;&lt;/div&gt;&lt;div&gt;&lt;br&gt;&lt;/div&gt;&lt;div&gt;int f(const char *str)&lt;/div&gt;&lt;div&gt;{&lt;/div&gt;&lt;div&gt;&amp;nbsp; &amp;nbsp; printf(&quot;%s\n&quot;, str);&lt;/div&gt;&lt;div&gt;&amp;nbsp; &amp;nbsp; return 0;&lt;/div&gt;&lt;div&gt;}&lt;/div&gt;&lt;div&gt;*/&lt;/div&gt;&lt;div&gt;import &quot;C&quot;&lt;/div&gt;&lt;div&gt;import &quot;fmt&quot;&lt;/div&gt;&lt;div&gt;import &quot;os&quot;&lt;/div&gt;&lt;div&gt;&lt;br&gt;&lt;/div&gt;&lt;div&gt;func CgoTest(s string) {&lt;/div&gt;&lt;div&gt;&amp;nbsp; &amp;nbsp; str := C.CString(s)&lt;/div&gt;&lt;div&gt;&amp;nbsp; &amp;nbsp; r, err := C.f(str)&lt;/div&gt;&lt;div&gt;&amp;nbsp; &amp;nbsp; if err != nil {&lt;/div&gt;&lt;div&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; fmt.Printf(&quot;error: %v\n&quot;, err)&lt;/div&gt;&lt;div&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; os.Exit(1)&lt;/div&gt;&lt;div&gt;&amp;nbsp; &amp;nbsp; }&lt;/div&gt;&lt;div&gt;&amp;nbsp; &amp;nbsp; fmt.Printf(&quot;ret: %v\n&quot;, r)&lt;/div&gt;&lt;div&gt;}&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;br&gt;&lt;/div&gt;&lt;div&gt;&lt;br&gt;&lt;/div&gt;&lt;div&gt;그리고 cgotest 패키지를 사용하는 main 코드를 생성한다. cgomain.go 파일을 생성하고 아래 내용을 입력한다.&lt;/div&gt;&lt;div&gt;&lt;br&gt;&lt;/div&gt;&lt;div&gt;&lt;div style=&quot;padding:10px; background-color:#E4E4E4&quot;&gt;&lt;div&gt;package main&lt;/div&gt;&lt;div&gt;&lt;br&gt;&lt;/div&gt;&lt;div&gt;import &quot;cgotest&quot;&lt;/div&gt;&lt;div&gt;&lt;br&gt;&lt;/div&gt;&lt;div&gt;func main() {&lt;/div&gt;&lt;div&gt;&amp;nbsp; &amp;nbsp; cgotest.CgoTest(&quot;test&quot;)&lt;/div&gt;&lt;div&gt;}&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;br&gt;&lt;/div&gt;&lt;div&gt;&lt;br&gt;&lt;/div&gt;&lt;div&gt;마지막으로 Makefile을 생성하고 아래 내용을 입력한다. 단, 주의할 점은 들여쓰기는 반드시 탭으로 구성되어 있어야 한다.&lt;/div&gt;&lt;div&gt;&lt;br&gt;&lt;/div&gt;&lt;div&gt;&lt;div style=&quot;padding:10px; background-color:#E4E4E4&quot;&gt;&lt;div&gt;include $(GOROOT)/src/Make.inc&lt;/div&gt;&lt;div&gt;&lt;br&gt;&lt;/div&gt;&lt;div&gt;TARG=cgotest&lt;/div&gt;&lt;div&gt;&lt;br&gt;&lt;/div&gt;&lt;div&gt;CGOFILES=\&lt;/div&gt;&lt;div&gt;&amp;nbsp; &amp;nbsp; cgotest.go&lt;/div&gt;&lt;div&gt;&lt;br&gt;&lt;/div&gt;&lt;div&gt;CLEANFILES+=cgomain&lt;/div&gt;&lt;div&gt;&lt;br&gt;&lt;/div&gt;&lt;div&gt;include $(GOROOT)/src/Make.pkg&lt;/div&gt;&lt;div&gt;&lt;br&gt;&lt;/div&gt;&lt;div&gt;all: cgomain&lt;/div&gt;&lt;div&gt;&lt;br&gt;&lt;/div&gt;&lt;div&gt;cgomain: install cgomain.go&lt;/div&gt;&lt;div&gt;&amp;nbsp; &amp;nbsp; $(GC) cgomain.go&lt;/div&gt;&lt;div&gt;&amp;nbsp; &amp;nbsp; $(LD) -o $@ cgomain.$O&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;br&gt;&lt;/div&gt;&lt;div&gt;참고로 위 Makefile은 cgotest.a 파일을 $GOROOT/pkg/linux_amd64 디렉토리에 복사를 한다. 그래서 이후에 6g나 6l에서 cgotest 패키지를 사용할 수 있도록 만들어준다. 만약 이와 같이 패키지 파일을 $GOROOT 밑으로 복사하고 싶지 않다면, 아래와 같이 Makefile의 cgomain: 부분을 수정해서 임시 파일을 사용하도록 변경한다.&lt;/div&gt;&lt;div&gt;&lt;br&gt;&lt;/div&gt;&lt;div&gt;&lt;div style=&quot;padding:10px; background-color:#E4E4E4&quot;&gt;&lt;div&gt;cgomain: &lt;/div&gt;&lt;div&gt;&amp;nbsp; &amp;nbsp; $(GC) -I_obj cgomain.go&lt;/div&gt;&lt;div&gt;&amp;nbsp; &amp;nbsp; $(LD) -L_obj -o $@ cgomain.$O&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;br&gt;&lt;/div&gt;&lt;div&gt;&lt;br&gt;&lt;/div&gt;&lt;div&gt;이제 쉘에서 make를 치면 cgo 프로그램이 실행되면서 C 코드와 연동되는 임시 코드를 생성하고, 최종적으로 이 패키지를 사용하는 cgomain 바이너리를 생성한다.&lt;/div&gt;&lt;div&gt;&lt;br&gt;&lt;/div&gt;&lt;div&gt;&lt;div style=&quot;padding:10px; background-color:#E4E4E4&quot;&gt;&lt;div&gt;superkkt@~/tmp/go$ make&lt;/div&gt;&lt;div&gt;CGOPKGPATH= cgo -- &amp;nbsp;cgotest.go&lt;/div&gt;&lt;div&gt;touch _obj/_cgo_run&lt;/div&gt;&lt;div&gt;6g &amp;nbsp;-o _go_.6 &amp;nbsp;_obj/cgotest.cgo1.go _obj/_cgo_gotypes.go&lt;/div&gt;&lt;div&gt;6c -FVw -I/usr/local/go/pkg/linux_amd64 -I . -o &quot;_cgo_defun.6&quot; _obj/_cgo_defun.c&lt;/div&gt;&lt;div&gt;gcc -m64 -I . -g -fPIC -O2 -o _cgo_main.o -c &amp;nbsp; _obj/_cgo_main.c&lt;/div&gt;&lt;div&gt;gcc -m64 -I . -g -fPIC -O2 -o cgotest.cgo2.o -c &amp;nbsp; _obj/cgotest.cgo2.c&lt;/div&gt;&lt;div&gt;gcc -m64 -I . -g -fPIC -O2 -o _cgo_export.o -c &amp;nbsp; _obj/_cgo_export.c&lt;/div&gt;&lt;div&gt;gcc -m64 -g -fPIC -O2 -o _cgo1_.o _cgo_main.o cgotest.cgo2.o _cgo_export.o &amp;nbsp;&lt;/div&gt;&lt;div&gt;cgo -dynimport _cgo1_.o &amp;gt;_obj/_cgo_import.c_ &amp;amp;&amp;amp; mv -f _obj/_cgo_import.c_ _obj/_cgo_import.c&lt;/div&gt;&lt;div&gt;6c -FVw -I . -o &quot;_cgo_import.6&quot; _obj/_cgo_import.c&lt;/div&gt;&lt;div&gt;rm -f _obj/cgotest.a&lt;/div&gt;&lt;div&gt;gopack grc _obj/cgotest.a _go_.6 &amp;nbsp;_cgo_defun.6 _cgo_import.6 cgotest.cgo2.o _cgo_export.o&lt;/div&gt;&lt;div&gt;cp _obj/cgotest.a &quot;/usr/local/go/pkg/linux_amd64/cgotest.a&quot;&lt;/div&gt;&lt;div&gt;6g cgomain.go&lt;/div&gt;&lt;div&gt;6l -o cgomain cgomain.6&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;br&gt;&lt;br&gt;&lt;/div&gt;&lt;div&gt;이제 생성된 cgomain 바이너리를 실행해보자. C 코드와 연동된 코드가 정상적으로 실행되는걸 확인할 수 있다.&lt;/div&gt;&lt;div&gt;&lt;br&gt;&lt;/div&gt;&lt;div&gt;&lt;div style=&quot;padding:10px; background-color:#E4E4E4&quot;&gt;&lt;div&gt;superkkt@~/tmp/go$ ./cgomain&lt;/div&gt;&lt;div&gt;test&lt;/div&gt;&lt;div&gt;ret: 0&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;br&gt;&lt;/div&gt;&lt;div&gt;&lt;br&gt;&lt;/div&gt;&lt;div&gt;&lt;br&gt;&lt;/div&gt;&lt;div&gt;&lt;b&gt;&amp;lt;References&amp;gt;&lt;/b&gt;&lt;/div&gt;&lt;div&gt;&lt;br&gt;&lt;/div&gt;&lt;div&gt;&lt;meta http-equiv=&quot;content-type&quot; content=&quot;text/html; charset=utf-8&quot;&gt;&lt;a href=&quot;http://golang.org/cmd/cgo/&quot;&gt;http://golang.org/cmd/cgo/&lt;/a&gt;&lt;br&gt;&lt;/div&gt;&lt;div&gt;&lt;meta http-equiv=&quot;content-type&quot; content=&quot;text/html; charset=utf-8&quot;&gt;&lt;a href=&quot;http://blog.golang.org/2011/03/c-go-cgo.html&quot;&gt;http://blog.golang.org/2011/03/c-go-cgo.html&lt;/a&gt;&lt;br&gt;&lt;/div&gt;&lt;div&gt;&lt;meta http-equiv=&quot;content-type&quot; content=&quot;text/html; charset=utf-8&quot;&gt;&lt;a href=&quot;http://code.google.com/p/gosqlite/source/browse/sqlite/&quot;&gt;http://code.google.com/p/gosqlite/source/browse/sqlite/&lt;/a&gt;&lt;br&gt;&lt;/div&gt;&lt;div&gt;&lt;meta http-equiv=&quot;content-type&quot; content=&quot;text/html; charset=utf-8&quot;&gt;&lt;a href=&quot;http://golang.org/misc/cgo/&quot;&gt;http://golang.org/misc/cgo/&lt;/a&gt;&lt;/div&gt;</description>
			<category>프로그래밍</category>
			<category>cgo</category>
			<category>go</category>
			<author>(김기태)</author>
			<guid>http://superkkt.com/708</guid>
			<comments>http://superkkt.com/708#entry708comment</comments>
			<pubDate>Sun, 10 Jul 2011 01:15:45 +0900</pubDate>
		</item>
		<item>
			<title>Go Language - Debugging with GDB</title>
			<link>http://superkkt.com/688</link>
			<description>Go native linker(6l)는 DWARF 디버깅 심볼을 바이너리에 넣어주기 때문에 gdb 7.x 이상에서는 디버깅이 가능하다.&lt;div&gt;&lt;br&gt;&lt;/div&gt;&lt;div&gt;하지만 아직 몇 가지 제약사항이 있기 때문에 불편한 점이 좀 있다. 예를 들어서 gdb에서 바이너리를 로딩한 후에 main 함수에 브레이크 포인트를 걸려면 아래와 같이 패키지명과 함수명을 같이 적어줘야 한다.&lt;/div&gt;&lt;div&gt;&lt;br&gt;&lt;/div&gt;&lt;div&gt;&lt;div style=&quot;padding:10px; background-color:#E4E4E4&quot;&gt;&lt;div&gt;(gdb) file test&lt;/div&gt;&lt;div&gt;Reading symbols from /home/superkkt/tmp/test...warning: Loadable segment &quot;.interp&quot; outside of ELF segments&lt;/div&gt;&lt;div&gt;done.&lt;/div&gt;&lt;div&gt;Loading Go Runtime support.&lt;/div&gt;&lt;div&gt;(gdb) list&lt;/div&gt;&lt;div&gt;1&lt;span class=&quot;Apple-tab-span&quot; style=&quot;white-space:pre&quot;&gt;	&lt;/span&gt;package main&lt;/div&gt;&lt;div&gt;2&lt;span class=&quot;Apple-tab-span&quot; style=&quot;white-space:pre&quot;&gt;	&lt;/span&gt;&lt;/div&gt;&lt;div&gt;3&lt;span class=&quot;Apple-tab-span&quot; style=&quot;white-space:pre&quot;&gt;	&lt;/span&gt;import &quot;fmt&quot;&lt;/div&gt;&lt;div&gt;4&lt;span class=&quot;Apple-tab-span&quot; style=&quot;white-space:pre&quot;&gt;	&lt;/span&gt;&lt;/div&gt;&lt;div&gt;5&lt;span class=&quot;Apple-tab-span&quot; style=&quot;white-space:pre&quot;&gt;	&lt;/span&gt;func main() {&lt;/div&gt;&lt;div&gt;6&lt;span class=&quot;Apple-tab-span&quot; style=&quot;white-space:pre&quot;&gt;	&lt;/span&gt; &amp;nbsp; &amp;nbsp;v := &quot;test\n&quot;&lt;/div&gt;&lt;div&gt;7&lt;span class=&quot;Apple-tab-span&quot; style=&quot;white-space:pre&quot;&gt;	&lt;/span&gt; &amp;nbsp; &amp;nbsp;fmt.Printf(v)&lt;/div&gt;&lt;div&gt;8&lt;span class=&quot;Apple-tab-span&quot; style=&quot;white-space:pre&quot;&gt;	&lt;/span&gt;}&lt;/div&gt;&lt;div&gt;(gdb) b &lt;font class=&quot;Apple-style-span&quot; color=&quot;#d41a01&quot;&gt;&lt;b&gt;main.main&lt;/b&gt;&lt;/font&gt;&lt;/div&gt;&lt;div&gt;Breakpoint 1 at 0x400c00: file /home/superkkt/tmp/test.go, line 5.&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;br&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;br&gt;&lt;/div&gt;&lt;div&gt;참조: &lt;a href=&quot;http://stackoverflow.com/questions/3400702/how-do-i-debug-a-program-written-in-the-go-language&quot; target=&quot;_blank&quot;&gt;How do I debug a program written in the Go language?&lt;/a&gt;&lt;/div&gt;&lt;/div&gt;</description>
			<category>프로그래밍</category>
			<category>DWARF</category>
			<category>GDB</category>
			<category>go</category>
			<author>(김기태)</author>
			<guid>http://superkkt.com/688</guid>
			<comments>http://superkkt.com/688#entry688comment</comments>
			<pubDate>Tue, 14 Jun 2011 13:29:08 +0900</pubDate>
		</item>
		<item>
			<title>Go Language - Vim Sytax Highlighting</title>
			<link>http://superkkt.com/684</link>
			<description>일단 Go 설치 디렉토리에 있는 Vim Syntax 파일을 ~/.vim/syntax/ 디렉토리 밑에 복사한다.&lt;div&gt;&lt;br&gt;&lt;/div&gt;&lt;div style=&quot;padding:10px; background-color:#E4E4E4&quot;&gt;&lt;div&gt;$ mkdir ~/.vim/syntax&lt;/div&gt;&lt;div&gt;$ cp $GOROOT/misc/vim/go.vim ~/.vim/syntax/&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;br&gt;&lt;/div&gt;&lt;div&gt;기존에 사용중인 .vimrc 파일에 cindent 옵션을 사용하고 있다면 방금 복사한 go.vim 파일의 제일 앞 부분(주석 제외)에 아래 내용을 추가해서 cindent를 꺼야한다.&lt;/div&gt;&lt;div&gt;&lt;br&gt;&lt;/div&gt;&lt;div&gt;&lt;div style=&quot;padding:10px; background-color:#E4E4E4&quot;&gt;set nocindent&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;br&gt;&lt;/div&gt;&lt;div&gt;그리고 ~/.vim/ftdetect/go.vim 파일을 생성하고 아래 내용을 입력한다.&lt;/div&gt;&lt;div&gt;&lt;br&gt;&lt;/div&gt;&lt;div&gt;&lt;div style=&quot;padding:10px; background-color:#E4E4E4&quot;&gt;au BufRead,BufNewFile *.go set filetype=go&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;br&gt;&lt;/div&gt;&lt;div&gt;이제 확장자가 go인 파일을 vim으로 열어보면 하이라이팅이 되는걸 확인할 수 있다.&lt;/div&gt;&lt;div&gt;&lt;br&gt;&lt;/div&gt;&lt;div&gt;&lt;div style=&quot;padding:10px; background-color:#E4E4E4&quot;&gt;$ vi test.go&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;br&gt;&lt;/div&gt;&lt;div&gt;&lt;br&gt;&lt;/div&gt;</description>
			<category>프로그래밍</category>
			<category>go</category>
			<category>vim</category>
			<author>(김기태)</author>
			<guid>http://superkkt.com/684</guid>
			<comments>http://superkkt.com/684#entry684comment</comments>
			<pubDate>Thu, 09 Jun 2011 10:56:00 +0900</pubDate>
		</item>
		<item>
			<title>Upstart - event-based init daemon</title>
			<link>http://superkkt.com/660</link>
			<description>Upstart는 우분투에서 개발한 System-V init을 대체하는 init daemon 프로그램이다. 우분투 6.10부터 도입된걸로 보이며, 10.10 버전은 기본적으로 Upstart를 사용하고, 하위호환성을 위해서 Upstart에서 init.d에 있는 스크립트들을 실행(/etc/init/rc*.conf)시키도록 되어있다.&lt;div&gt;&lt;br&gt;&lt;/div&gt;&lt;div&gt;Upstart는 /etc/init 디렉토리에 실행시킬 서비스를 텍스트 파일로 설정하면 된다. 파일명은 서비스명.conf 형식이고, 이 파일에 실행 권한을 줄 필요는 없다.&lt;/div&gt;&lt;div&gt;&lt;br&gt;&lt;/div&gt;&lt;div&gt;아래는 Asterisk를 Upstart 서비스로 등록하기 위해 /etc/init/asterisk.conf 파일을 생성하고 추가한 내용이다.&lt;/div&gt;&lt;meta http-equiv=&quot;content-type&quot; content=&quot;text/html; charset=utf-8&quot;&gt;&lt;div&gt;&lt;br&gt;&lt;/div&gt;&lt;div&gt;&lt;div style=&quot;padding:10px; background-color:#E4E4E4&quot;&gt;&lt;div&gt;# Asterisk Service&lt;/div&gt;&lt;div&gt;&lt;br&gt;&lt;/div&gt;&lt;div&gt;description &amp;nbsp; &amp;nbsp; &quot;Asterisk server&quot;&lt;/div&gt;&lt;div&gt;author &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;&quot;Kitae Kim &amp;lt;superkkt@sds.co.kr&amp;gt;&quot;&lt;/div&gt;&lt;div&gt;&lt;br&gt;&lt;/div&gt;&lt;div&gt;start on startup&lt;/div&gt;&lt;div&gt;stop on shutdown&lt;/div&gt;&lt;div&gt;&lt;br&gt;&lt;/div&gt;&lt;div&gt;respawn&lt;/div&gt;&lt;div&gt;expect fork&lt;/div&gt;&lt;div&gt;&lt;br&gt;&lt;/div&gt;&lt;div&gt;exec /usr/local/asterisk/sbin/asterisk&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;br&gt;&lt;/div&gt;&lt;div&gt;위 파일은 시스템 부팅 시 /usr/local/asterisk/sbin/asterisk를 실행시키고, 셧다운 과정에서 종료하도록 설정한다. &lt;/div&gt;&lt;div&gt;&lt;br&gt;&lt;/div&gt;&lt;div&gt;그리고 서비스가 정상적으로 stop되지 않고 종료되는 경우(kill 또는 segfault 발생 등) 자동으로 재실행 하도록 respawn 옵션을 설정했다. 이를 위해서는 Upstart가 PID를 추적해야 하는데 실행하려는 프로그램이 한번 fork를 해서 자식 프로세스를 만들거나, 두번 fork 해서 daemon이 되는 경우는 expect 옵션을 사용해서 Upstart에게 미리 알려줘야 한다. 그렇지 않으면 해당 서비스가 비정상 종료되었을 때 자동으로 재실행되지 않는다.&lt;/div&gt;&lt;div&gt;&lt;br&gt;&lt;/div&gt;&lt;div&gt;Asterisk는 한번만 fork해서 자식 프로세스를 만드는 형태로 실행되기 때문에 expect fork를 사용했다. 등록하려는 프로그램이 몇 번 fork를 하는지 모를때는 일단 expect daemon으로 설정한다. 그리고 아래에서 설명하는 방법으로 서비스를 시작했을 때 프롬프트가 다시 떨어지지 않고 hang이 걸리면 한번만 fork하는 프로그램이므로 expect fork로 설정하고, 프롬프트가 떨어지면 expect daemon을 그대로 사용하면 된다.&lt;/div&gt;&lt;div&gt;&lt;br&gt;&lt;/div&gt;&lt;div&gt;이제 Asterisk는 시스템 부팅시 자동으로 실행된다. 여기서는 아래와 같이 재부팅 없이 바로 서비스를 시작해보자.&lt;/div&gt;&lt;div&gt;&lt;br&gt;&lt;/div&gt;&lt;div style=&quot;padding:10px; background-color:#E4E4E4&quot;&gt;&lt;div&gt;$sudo start asterisk&lt;/div&gt;&lt;div&gt;&lt;div&gt;asterisk start/running, process 30295&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;br&gt;&lt;/div&gt;&lt;div&gt;비정상 종료시 자동으로 재실행되는지 확인하기 위해 asterisk 프로세스를 kill로 죽여보자. 새로운 PID를 가지는 asterisk 프로세스가 다시 생기면 정상적으로 동작하고 있는것이다.&lt;/div&gt;&lt;div&gt;&lt;br&gt;&lt;/div&gt;&lt;div&gt;서비스 종료는 아래와 같이 할 수 있다.&lt;/div&gt;&lt;div&gt;&lt;br&gt;&lt;/div&gt;&lt;div style=&quot;padding:10px; background-color:#E4E4E4&quot;&gt;&lt;div&gt;$ sudo stop asterisk&lt;/div&gt;&lt;div&gt;asterisk stop/waiting&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;br&gt;&lt;/div&gt;&lt;div&gt;위에서 설명한 내용 외에도 Upstart는 다양한 설정이 가능하다. 예를 들어서 특정 런레벨에서 서비스가 실행되도록 하거나, 또는 특정 서비스가 먼저 실행된 후에 서비스가 실행되도록 설정할 수 있다. 그리고 exec로 특정 명령어를 실행하는 대신 script/end script 구문을 사용해서 쉘 스크립트를 직접 작성할 수도 있다. &lt;/div&gt;&lt;div&gt;&lt;br&gt;&lt;/div&gt;&lt;div&gt;자세한 내용은 아래 레퍼런스를 참조한다.&lt;/div&gt;&lt;div&gt;&lt;br&gt;&lt;/div&gt;&lt;div&gt;&lt;meta http-equiv=&quot;content-type&quot; content=&quot;text/html; charset=utf-8&quot;&gt;&lt;a href=&quot;http://upstart.ubuntu.com/getting-started.html&quot;&gt;http://upstart.ubuntu.com/getting-started.html&lt;/a&gt;&lt;br&gt;&lt;/div&gt;&lt;div&gt;&lt;meta http-equiv=&quot;content-type&quot; content=&quot;text/html; charset=utf-8&quot;&gt;&lt;a href=&quot;http://upstart.ubuntu.com/cookbook/&quot;&gt;http://upstart.ubuntu.com/cookbook/&lt;/a&gt;&lt;br&gt;&lt;/div&gt;&lt;meta http-equiv=&quot;content-type&quot; content=&quot;text/html; charset=utf-8&quot;&gt;</description>
			<category>컴퓨터</category>
			<category>init</category>
			<category>ubuntu</category>
			<category>Upstart</category>
			<category>우분투</category>
			<author>(김기태)</author>
			<guid>http://superkkt.com/660</guid>
			<comments>http://superkkt.com/660#entry660comment</comments>
			<pubDate>Thu, 21 Apr 2011 00:25:29 +0900</pubDate>
		</item>
		<item>
			<title>공유 스토리지 용도의 NFS 설정</title>
			<link>http://superkkt.com/629</link>
			<description>NFS4를 사용해서 서버를 설정하고, 여러 클라이언트가 nobody 계정을 사용해서 여기에 접근하도록 설정하는 방법을 설명한다. 참고로 기본 옵션으로 NFS 연결을 하면 각각의 클라이언트 사용자의 UID로 파일이 생성되기 때문에 여러 클라이언트가 파일을 공유하기가 어려워진다. (각 클라이언트의 사용자 UID가 모두 동일하지 않다면 퍼미션 에러 발생)&lt;div&gt;&lt;br&gt;&lt;/div&gt;&lt;h3&gt;1. 서버 &lt;/h3&gt;&lt;div&gt;&lt;br&gt;&lt;/div&gt;&lt;div&gt;/etc/exports 파일에서 지정한 all_squash 옵션이 모든 사용자가 nobody 권한으로 NFS 스토리지에 접근하도록 지정한다.&lt;/div&gt;&lt;meta charset=&quot;utf-8&quot;&gt;&lt;div&gt;&lt;br&gt;&lt;/div&gt;&lt;div style=&quot;padding:10px; background-color:#E4E4E4&quot;&gt;&lt;div&gt;$ sudo apt-get install nfs-kernel-server&lt;/div&gt;&lt;div&gt;&lt;br&gt;&lt;/div&gt;&lt;div&gt;$ sudo mkdir /export&lt;/div&gt;&lt;div&gt;&lt;br&gt;&lt;/div&gt;&lt;div&gt;$ sudo vi /etc/fstab&lt;/div&gt;&lt;div&gt;..(중략)..&lt;/div&gt;&lt;div&gt;&lt;i&gt;/공유할_디렉토리&lt;/i&gt; &amp;nbsp;/export none &amp;nbsp; &amp;nbsp;bind &amp;nbsp; &amp;nbsp;0 &amp;nbsp; 0&lt;br&gt;&lt;/div&gt;&lt;div&gt;&lt;br&gt;&lt;/div&gt;&lt;div&gt;$ sudo mount /export&lt;/div&gt;&lt;div&gt;&lt;br&gt;&lt;/div&gt;&lt;div&gt;$ sudo vi /etc/exports&lt;/div&gt;&lt;div&gt;..(중략)..&lt;/div&gt;&lt;div&gt;/export &amp;nbsp; &amp;nbsp; &amp;nbsp; 111.111.111.111(rw,fsid=0,insecure,no_subtree_check,sync,all_squash)&lt;br&gt;&lt;/div&gt;&lt;div&gt;&lt;br&gt;&lt;/div&gt;&lt;div&gt;$ sudo /etc/init.d/nfs-kernel-server restart&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;br&gt;&lt;/div&gt;&lt;div&gt;&lt;br&gt;&lt;/div&gt;&lt;h3&gt;2. 클라이언트&lt;/h3&gt;&lt;div&gt;&lt;br&gt;&lt;/div&gt;&lt;div&gt;&lt;font color=&quot;#D41A01&quot;&gt;(주의)&lt;/font&gt; NFSv4를 사용해서 마운트하는 경우에는 서버의 전체 경로를 지정하지 않고 그냥 &#039;/&#039;로 지정한다.&lt;/div&gt;&lt;div&gt;&lt;br&gt;&lt;/div&gt;&lt;h4&gt;1) Mac OS X&lt;/h4&gt;&lt;div&gt;&lt;br&gt;&lt;/div&gt;&lt;div&gt;&lt;div style=&quot;padding:10px; background-color:#E4E4E4&quot;&gt;$ &lt;span style=&quot;font-family: NanumGothic; font-size: 12px; line-height: normal; &quot;&gt;sudo mount -t nfs -o vers=4.0alpha,proto=tcp,port=2049 서버_주소:/ /Users/superkkt/projects&lt;/span&gt;&amp;nbsp;&lt;/div&gt;&lt;/div&gt;&lt;meta http-equiv=&quot;Content-Type&quot; content=&quot;text/html; charset=UTF-8&quot;&gt;
&lt;meta http-equiv=&quot;Content-Style-Type&quot; content=&quot;text/css&quot;&gt;

&lt;meta name=&quot;Generator&quot; content=&quot;Cocoa HTML Writer&quot;&gt;
&lt;meta name=&quot;CocoaVersion&quot; content=&quot;1038.35&quot;&gt;
&lt;style type=&quot;text/css&quot;&gt;
p.p1 {margin: 0.0px 0.0px 0.0px 0.0px; font: 12.0px NanumGothic}
&lt;/style&gt;


&lt;div&gt;&lt;br&gt;&lt;/div&gt;&lt;div&gt;리부팅 후에도 계속 마운트가 되길 원하면 아래와 같이 추가 작업을 해준다.&lt;/div&gt;&lt;div&gt;&lt;br&gt;&lt;/div&gt;&lt;div style=&quot;padding:10px; background-color:#E4E4E4&quot;&gt;&lt;div&gt;1. 어플리케이션 -&amp;gt; 유틸리티 -&amp;gt; 디스크 유틸리티 실행&lt;/div&gt;&lt;div&gt;&lt;br&gt;&lt;/div&gt;&lt;div&gt;2. 파일 -&amp;gt; NFS 마운트 선택&lt;/div&gt;&lt;div&gt;&lt;br&gt;&lt;/div&gt;&lt;div&gt;3. 추가(+) 선택&lt;/div&gt;&lt;div&gt;&lt;br&gt;&lt;/div&gt;&lt;div&gt;4. 아래와 같이 입력&lt;/div&gt;&lt;div&gt;원격 NFS URL: nfs://superkkt.sds.co.kr/&lt;/div&gt;&lt;div&gt;마운트 위치: /Users/superkkt/projects&lt;/div&gt;&lt;div&gt;고급 마운트 매개변수: vers=4.0alpha,proto=tcp,port=2049&lt;/div&gt;&lt;div&gt;&lt;br&gt;&lt;/div&gt;&lt;div&gt;5. automount 설정 업데이트 후 실제 마운트 실행&lt;/div&gt;&lt;div&gt;$ sudo automount -vc&lt;br&gt;&lt;/div&gt;&lt;div&gt;$ sudo mount -a&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;br&gt;&lt;/div&gt;&lt;div&gt;&lt;b&gt;&amp;nbsp;&amp;lt;참고&amp;gt; &lt;/b&gt;&lt;/div&gt;&lt;div&gt;&lt;br&gt;&lt;/div&gt;&lt;div&gt;Mac OS X Snow leopard에서는 위와 같이 해도 재부팅 후에 자동 NFS 마운트가 제대로 작동하지 않는다. 참고로 sudo mount -a를 수동으로 한번 실행시켜주면 마운트가 된다.&lt;/div&gt;&lt;div&gt;&lt;br&gt;&lt;/div&gt;&lt;h4&gt;2) Linux&lt;/h4&gt;&lt;div&gt;&lt;br&gt;&lt;/div&gt;&lt;div&gt;&lt;meta charset=&quot;utf-8&quot;&gt;&lt;div style=&quot;padding:10px; background-color:#E4E4E4&quot;&gt;$ &lt;span style=&quot;margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; font-family: NanumGothic; font-size: 12px; line-height: normal; &quot;&gt;sudo mount -t nfs4 -o proto=tcp,port=2049 서버_주소:/ /Users/superkkt/projects&lt;/span&gt;&amp;nbsp;&lt;/div&gt;&lt;br&gt;&lt;/div&gt;&lt;div&gt;&lt;meta charset=&quot;utf-8&quot;&gt;리부팅 후에도 계속 마운트가 되길 원하면 /etc/fstab에 적절하게 추가해준다.&lt;br&gt;&lt;/div&gt;&lt;div&gt;&lt;br&gt;&lt;/div&gt;&lt;div&gt;&lt;br&gt;&lt;/div&gt;&lt;h3&gt;3. References&lt;/h3&gt;&lt;div&gt;&lt;br&gt;&lt;/div&gt;&lt;div&gt;&lt;a href=&quot;https://help.ubuntu.com/community/SettingUpNFSHowTo&quot; target=&quot;_blank&quot;&gt;Setting up NFS howto&lt;/a&gt;&lt;br&gt;&lt;/div&gt;</description>
			<category>컴퓨터</category>
			<category>NFS</category>
			<category>NFSv4</category>
			<author>(김기태)</author>
			<guid>http://superkkt.com/629</guid>
			<comments>http://superkkt.com/629#entry629comment</comments>
			<pubDate>Wed, 23 Feb 2011 14:45:32 +0900</pubDate>
		</item>
		<item>
			<title>리눅스에서 Mac OS의 타임머신 백업 따라하기</title>
			<link>http://superkkt.com/625</link>
			<description>Mac OS에는 타임머신이라는 좋은 백업 툴이 있는데 이걸 리눅스에서 따라하는 방법을 정리했다.&lt;div&gt;&lt;br&gt;&lt;/div&gt;&lt;div&gt;이 방법에서는 rsync를 사용하는데, 바로 직전에 백업된 데이터와 비교해서 변하지 않은 파일들은 직전 백업된 파일과 하드링크로 연결하고, 변경된 파일만 새로 백업하는 방식을 사용한다. 따라서 incremental backup을 구현할 수 있고, 또 이전에 백업된 디렉토리를 삭제해도 하드링크 카운트를 파일시스템에서 관리하기 때문에 최근에 백업된 데이터에 영향을 주지 않는다. (프로그래밍의 레퍼런스 카운터와 같은 개념)&lt;/div&gt;&lt;div&gt;&lt;br&gt;&lt;/div&gt;&lt;div&gt;그리고 참고 사이트의 아이디어를 약간 변형해서 계속 데이터가 쌓이지 않고, 최근 일주일간의 데이터만 유지되도록 했다. 단, 이 방법에서는 컴퓨터 사용 빈도에 따라서 백업 디렉토리의 순서가 일관적이지 않을 수 있으니 자세한 내용은 스크립트의 주석을 참조한다.&lt;/div&gt;&lt;div&gt;&lt;br&gt;&lt;/div&gt;&lt;div&gt;&lt;b&gt;1. 백업 스크립트 (/usr/local/bin/timemachine_backup.sh)&lt;/b&gt;&lt;/div&gt;&lt;div&gt;&lt;br&gt;&lt;/div&gt;&lt;div&gt;&lt;div style=&quot;padding:10px; background-color:#E4E4E4&quot;&gt;&lt;div&gt;&lt;div&gt;#!/bin/sh&lt;/div&gt;&lt;div&gt;&lt;br&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;# 이미 실행중인 프로세스가 있으면 그대로 종료&lt;/div&gt;&lt;div&gt;ps -ef | grep -v &quot;grep&quot; | grep &quot;timemachine_backup.sh&quot; &amp;gt; /dev/null&lt;/div&gt;&lt;div&gt;if [ $? = 0 ]; then&lt;/div&gt;&lt;div&gt;&amp;nbsp; &amp;nbsp; exit 0&lt;/div&gt;&lt;div&gt;fi&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;br&gt;&lt;/div&gt;&lt;div&gt;# &quot;요일(0~6)-시간(0~23)&quot;으로 디렉토리를 만들어서 일주일치 데이터를 보관한다.&lt;/div&gt;&lt;div&gt;# 단, 이 방법의 단점은 컴퓨터를 켜놓는 시간에 따라서 백업 디렉토리의 순서가&lt;/div&gt;&lt;div&gt;# 달라질 수 있다는 점이다. 예를 들어서 한 주 동안 매일 컴퓨터를 켜서 백업이&lt;/div&gt;&lt;div&gt;# 이상적으로 이루어진 후, 그 다음 주에는 수요일에만 컴퓨터를 켰다면 월요일,&lt;/div&gt;&lt;div&gt;# 화요일에 백업된 데이터는 이번 주가 아닌 일주일 전 데이터를 가지고 있는 것이다.&lt;/div&gt;&lt;div&gt;# 따라서 복구를 할 때는 백업 디렉토리를 날짜별로 정렬해서 원하는 복구 지점을&lt;/div&gt;&lt;div&gt;# 선택해야 한다. (백업디렉토리/BACKUP_TIMESTAMP_FILE의 생성 시간 참조)&lt;/div&gt;&lt;div&gt;date=`date &quot;+%u-%H&quot;`&lt;/div&gt;&lt;div&gt;BACKUP_BASE_DIR=/backup&lt;/div&gt;&lt;div&gt;&lt;br&gt;&lt;/div&gt;&lt;div&gt;# 일주일전 데이터 제거&lt;/div&gt;&lt;div&gt;rm -rf $BACKUP_BASE_DIR/$date&lt;/div&gt;&lt;div&gt;&lt;br&gt;&lt;/div&gt;&lt;div&gt;# 비정상 종료된 임시 디렉토리 제거&lt;/div&gt;&lt;div&gt;rm -rf $BACKUP_BASE_DIR/*.tmp&lt;/div&gt;&lt;div&gt;&lt;br&gt;&lt;/div&gt;&lt;div&gt;# 임시 디렉토리로 백업 &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &lt;/div&gt;&lt;div&gt;rsync -aP \&lt;/div&gt;&lt;div&gt;&amp;nbsp;&amp;nbsp; &amp;nbsp;--exclude-from=/usr/local/bin/timemachine_backup_excluded.list \&lt;/div&gt;&lt;div&gt;&amp;nbsp;&amp;nbsp; &amp;nbsp;--link-dest=$BACKUP_BASE_DIR/current \&lt;/div&gt;&lt;div&gt;&amp;nbsp;&amp;nbsp; &amp;nbsp;/ \&lt;/div&gt;&lt;div&gt;&amp;nbsp;&amp;nbsp; &amp;nbsp;$BACKUP_BASE_DIR/$date.tmp&lt;/div&gt;&lt;div&gt;# 임시 디렉토리 제거 &amp;nbsp; &amp;nbsp;&lt;/div&gt;&lt;div&gt;mv $BACKUP_BASE_DIR/$date.tmp $BACKUP_BASE_DIR/$date&lt;/div&gt;&lt;div&gt;# current를 방금 백업한 디렉토리로 재설정&lt;/div&gt;&lt;div&gt;rm -f $BACKUP_BASE_DIR/current&lt;/div&gt;&lt;div&gt;ln -s $BACKUP_BASE_DIR/$date $BACKUP_BASE_DIR/current&lt;/div&gt;&lt;div&gt;touch $BACKUP_BASE_DIR/$date/BACKUP_TIMESTAMP_FILE&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;br&gt;&lt;/div&gt;&lt;div&gt;&lt;br&gt;&lt;/div&gt;&lt;div&gt;&lt;b&gt;2. 백업 배제 파일 리스트 (/usr/local/bin/timemachine_backup_excluded.list)&lt;/b&gt;&lt;/div&gt;&lt;div&gt;&lt;br&gt;&lt;/div&gt;&lt;div&gt;&lt;div style=&quot;padding:10px; background-color:#E4E4E4&quot;&gt;&lt;div&gt;/dev&lt;/div&gt;&lt;div&gt;/backup&lt;/div&gt;&lt;div&gt;/proc&lt;/div&gt;&lt;div&gt;/cdrom&lt;/div&gt;&lt;div&gt;/lost+found&lt;/div&gt;&lt;div&gt;/media&lt;/div&gt;&lt;div&gt;/mnt&lt;/div&gt;&lt;div&gt;/home/superkkt/.VirtualBox&lt;/div&gt;&lt;div&gt;/home/superkkt/vmware&lt;/div&gt;&lt;div&gt;/home/superkkt/.gvfs&lt;/div&gt;&lt;div&gt;/sys&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;br&gt;&lt;/div&gt;&lt;div&gt;&lt;br&gt;&lt;/div&gt;&lt;div&gt;&lt;b&gt;3. crontab에 매 시간 실행되도록 등록&lt;/b&gt;&lt;/div&gt;&lt;div&gt;&lt;br&gt;&lt;/div&gt;&lt;div style=&quot;padding:10px; background-color:#E4E4E4&quot;&gt;&lt;div&gt;$ sudo vi /etc/crontab&lt;/div&gt;&lt;div&gt;..중략..&lt;/div&gt;&lt;div&gt;1 * * * * &amp;nbsp; root &amp;nbsp; &amp;nbsp;/usr/local/bin/timemachine_backup.sh&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;br&gt;&lt;/div&gt;&lt;div&gt;&lt;br&gt;&lt;/div&gt;&lt;div&gt;&lt;br&gt;&lt;/div&gt;&lt;div&gt;&lt;b&gt;&lt;font size=&quot;4&quot;&gt;&amp;lt;References&amp;gt;&lt;/font&gt;&lt;/b&gt;&lt;/div&gt;&lt;div&gt;&lt;br&gt;&lt;/div&gt;&lt;div&gt;&lt;meta http-equiv=&quot;content-type&quot; content=&quot;text/html; charset=utf-8&quot;&gt;&lt;a href=&quot;http://blog.interlinked.org/tutorials/rsync_time_machine.html&quot;&gt;http://blog.interlinked.org/tutorials/rsync_time_machine.html&lt;/a&gt;&lt;br&gt;&lt;/div&gt;&lt;div&gt;&lt;br&gt;&lt;/div&gt;&lt;div&gt;&lt;br&gt;&lt;/div&gt;</description>
			<category>컴퓨터</category>
			<category>rsync</category>
			<category>리눅스</category>
			<category>백업</category>
			<category>타임머신</category>
			<author>(김기태)</author>
			<guid>http://superkkt.com/625</guid>
			<comments>http://superkkt.com/625#entry625comment</comments>
			<pubDate>Wed, 09 Feb 2011 23:14:09 +0900</pubDate>
		</item>
		<item>
			<title>SQLyog의 대체 프로그램 Sequel Pro(on Mac OS X)</title>
			<link>http://superkkt.com/623</link>
			<description>SQLyog는 Mac OS용 바이너리를 제공하지 않는다. 그래서 대체품으로 Sequel Pro를 사용한다. Sequel Pro도 오픈소스 프로그램이며 Mac OS native binary를 제공한다.&lt;div&gt;&lt;br&gt;&lt;/div&gt;&lt;div&gt;&lt;a href=&quot;http://www.sequelpro.com/&quot; target=&quot;_blank&quot;&gt;http://www.sequelpro.com/&lt;/a&gt;&lt;br&gt;&lt;/div&gt;</description>
			<category>프로그래밍</category>
			<category>Mac</category>
			<category>Sqeuel Pro</category>
			<category>SQLyog</category>
			<author>(김기태)</author>
			<guid>http://superkkt.com/623</guid>
			<comments>http://superkkt.com/623#entry623comment</comments>
			<pubDate>Mon, 07 Feb 2011 15:16:57 +0900</pubDate>
		</item>
		<item>
			<title>Ubuntu 10.10 Backup Tool (Simple Backup)</title>
			<link>http://superkkt.com/620</link>
			<description>Simple Backup(이하 SBackup)은 Ubuntu 10.10에서 사용 가능한 간단한 백업툴이다. 시넵틱 패키지 관리자에서 sbackup 패키지를 설치하면 아래 위치에 새로운 메뉴가 생성된다.&lt;div&gt;&lt;br&gt;&lt;/div&gt;&lt;div style=&quot;padding:10px; background-color:#E4E4E4&quot;&gt;&lt;div&gt;* 프로그램 -&amp;gt; 보조프로그램 -&amp;gt; Simple Backup Configuration-Restoration&lt;/div&gt;&lt;div&gt;* 프로그램 -&amp;gt; 시스템도구 -&amp;gt; Simple Backup Configuration-Restoration&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;br&gt;&lt;/div&gt;&lt;div&gt;사실 둘 다 동일한 프로그램인데 시스템도구 쪽에 설치된 메뉴는 root 권한으로 실행된다. SBackup에는 스케줄 메뉴가 있는데, 이게 cron을 사용하기 때문에 root 권한으로 실행될 때에만 활성화가 된다. 따라서 보조프로그램 메뉴에 있는 프로그램을 실행하면 스케쥴 메뉴가 비활성화되고, 시스템도구에 있는 메뉴를 실행하면 스케쥴 메뉴가 활성화 된다.&lt;/div&gt;&lt;div&gt;&lt;br&gt;&lt;/div&gt;&lt;div&gt;스케줄 메뉴도 사용하기 위해서 시스템도구에 있는 Simple Backup Configuration을 실행하고 아래와 같이 설정하자.&lt;/div&gt;&lt;div&gt;&lt;br&gt;&lt;/div&gt;&lt;div style=&quot;padding:10px; background-color:#E4E4E4&quot;&gt;&lt;div&gt;1. 일반 메뉴는 기본값 그대로 사용 (Full backup 7일; non-compression; unlimited split)&lt;/div&gt;&lt;div&gt;&lt;br&gt;&lt;/div&gt;&lt;div&gt;2. &amp;nbsp;포함 메뉴에 백업 대상을 지정 (일반적으로 /etc, /home, /usr/local, /var를 지정)&lt;/div&gt;&lt;div&gt;&lt;br&gt;&lt;/div&gt;&lt;div&gt;3. 제외할 파일 메뉴에서 백업에서 제외할 대상 지정 (기본값 그대로 사용)&lt;/div&gt;&lt;div&gt;&lt;br&gt;&lt;/div&gt;&lt;div&gt;4. 대상 메뉴에서 백업 파일을 저장할 디렉토리 지정 (백업 대상과 다른 하드디스크에 만들어진 파티션 사용 권장)&lt;/div&gt;&lt;div&gt;&lt;br&gt;&lt;/div&gt;&lt;div&gt;5. 스케쥴 메뉴에서 백업 주기를 지정 (기본값 그대로 사용)&lt;/div&gt;&lt;div&gt;&lt;br&gt;&lt;/div&gt;&lt;div&gt;6. 자동삭제 및 리포트 메뉴는 기본값 그대로 사용&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;br&gt;&lt;/div&gt;&lt;div&gt;이제 상단의 툴바에서 &#039;Save configuration&#039; 버튼을 누른 후, &#039;Make a backup&#039; 버튼을 눌러서 백업 프로세스를 백그라운드로 실행시킨다. 그럼 화면 우측 상단(시계 옆)에 백업 아이콘이 뜨면서 현재 얼만큼 백업이 진행되었는지를 보여준다.&lt;/div&gt;&lt;div&gt;&lt;br&gt;&lt;/div&gt;&lt;div&gt;그리고 나중에 실수로 파일이나 디렉토리가 유실되었을 때 프로그램 -&amp;gt; 시스템도구 -&amp;gt; Simple Backup Restoration을 실행해서 복구할 데이터의 날짜를 선택하고 선별적으로 파일 또는 디렉토리를 복구할 수 있다.&lt;/div&gt;&lt;div&gt;&lt;br&gt;&lt;/div&gt;&lt;meta http-equiv=&quot;content-type&quot; content=&quot;text/html; charset=utf-8&quot;&gt;</description>
			<category>컴퓨터</category>
			<category>SBackup</category>
			<category>Simple Backup</category>
			<category>ubuntu</category>
			<category>우분투</category>
			<author>(김기태)</author>
			<guid>http://superkkt.com/620</guid>
			<comments>http://superkkt.com/620#entry620comment</comments>
			<pubDate>Fri, 04 Feb 2011 14:01:55 +0900</pubDate>
		</item>
		<item>
			<title>nautilus-open-terminal</title>
			<link>http://superkkt.com/619</link>
			<description>&lt;div&gt;우분투의 파일 매니저인 노틸러스에서 현재 위치한 폴더에서 터미널을 시작할 수 있는 확장 기능을 설치할 수 있다.&lt;/div&gt;&lt;div&gt;&lt;br&gt;&lt;/div&gt;&lt;div style=&quot;padding:10px; background-color:#E4E4E4&quot;&gt;$ sudo apt-get install nautilus-open-terminal&lt;/div&gt;&lt;div style=&quot;padding:10px; background-color:#E4E4E4&quot;&gt;$ killall nautilus&lt;/div&gt;&lt;div&gt;&lt;br&gt;&lt;/div&gt;&lt;div&gt;이제 노틸러스에서 오른쪽 클릭을 하면 &#039;Open in terminal&#039; 메뉴가 보일것이다.&lt;/div&gt;</description>
			<category>컴퓨터</category>
			<category>nautilus</category>
			<category>노틸러스</category>
			<category>우분투</category>
			<author>(김기태)</author>
			<guid>http://superkkt.com/619</guid>
			<comments>http://superkkt.com/619#entry619comment</comments>
			<pubDate>Sun, 30 Jan 2011 23:41:47 +0900</pubDate>
		</item>
		<item>
			<title>MySQL++ (MySQL C++ library bindings)</title>
			<link>http://superkkt.com/618</link>
			<description>&lt;a href=&quot;http://tangentsoft.net/mysql++/&quot; target=&quot;_blank&quot;&gt;MySQL++&lt;/a&gt;는 MySQL C API의 Wrapper Library이다. &lt;div&gt;&lt;br&gt;&lt;/div&gt;&lt;div&gt;라이센스는 LGPL이고, 우분투에서도 libmysql++-dev 패키지로 설치할 수 있다.&lt;div&gt;&lt;br&gt;&lt;/div&gt;&lt;div&gt;API 사용법은 &lt;a href=&quot;http://tangentsoft.net/mysql++/doc/html/userman/&quot; target=&quot;_blank&quot;&gt;여기&lt;/a&gt;를 참조한다.&lt;/div&gt;&lt;/div&gt;</description>
			<category>프로그래밍</category>
			<category>MySQL</category>
			<category>MySQL++</category>
			<author>(김기태)</author>
			<guid>http://superkkt.com/618</guid>
			<comments>http://superkkt.com/618#entry618comment</comments>
			<pubDate>Sat, 29 Jan 2011 16:29:32 +0900</pubDate>
		</item>
		<item>
			<title>Ubuntu 10.10 터미널 단축기 변경 방법</title>
			<link>http://superkkt.com/616</link>
			<description>그놈 터미널의 단축키를 변경하려면 gconf-editor를 실행하고 desktop -&amp;gt; gnome -&amp;gt; interface에서 can_change_accels를 체크하면 된다. &lt;div&gt;&lt;br&gt;&lt;/div&gt;&lt;div&gt;위 옵션이 체크된 상태에서 변경을 원하는 그놈 터미널의 메뉴 위에 마우스 커서를 올리고 변경할 단축키를 누르면 된다. 단, 이미 전역적으로 사용되는 단축키는 사용할 수 없다.&lt;/div&gt;&lt;div&gt;&lt;br&gt;&lt;/div&gt;&lt;div&gt;그리고 변경이 완료되면 이 옵션을 체크 해제해야만 사용 중에 실수로 단축키가 변경되는걸 막을 수 있다.&lt;/div&gt;&lt;div&gt;&lt;br&gt;&lt;/div&gt;&lt;div&gt;&amp;nbsp; &lt;br&gt;&lt;div&gt;&lt;br&gt;&lt;/div&gt;&lt;/div&gt;</description>
			<category>컴퓨터</category>
			<author>(김기태)</author>
			<guid>http://superkkt.com/616</guid>
			<comments>http://superkkt.com/616#entry616comment</comments>
			<pubDate>Tue, 25 Jan 2011 21:22:47 +0900</pubDate>
		</item>
		<item>
			<title>Ubuntu 10.10 기본 테마 윈도우의 resize가 어려운 문제</title>
			<link>http://superkkt.com/614</link>
			<description>Ubuntu 10.10의 기본 테마를 사용하면 resize grab을 마우스로 잡기가 어려워서 윈도우 크기 조정이 쉽지가 않다. 따라서 아래와 같이 테마 파일을 수정해서 문제를 해결한다.&lt;div&gt;&lt;br&gt;&lt;/div&gt;&lt;div&gt;참고로 시스템-&amp;gt;기본설정-&amp;gt;모양에서 Radiance를 고른 상태를 기준으로 설명한다.&lt;/div&gt;&lt;div&gt;&lt;br&gt;&lt;/div&gt;&lt;div&gt;/usr/share/themes/Radiance/metacity-1/metacity-theme-1.xml 파일에서 아래 부분을 찾아서 기본값 1을 5로 바꿔준다. (빨간색으로 표시된 부분) &lt;/div&gt;&lt;div&gt;&lt;br&gt;&lt;/div&gt;&lt;div style=&quot;padding:10px; background-color:#E4E4E4&quot;&gt;&lt;div&gt;.. 중략&lt;/div&gt;&lt;div&gt;&lt;div&gt;&amp;lt;!-- General window layout --&amp;gt;&lt;/div&gt;&lt;div&gt;&amp;lt;frame_geometry name=&quot;frame_geometry_normal&quot; title_scale=&quot;medium&quot; rounded_top_left=&quot;true&quot; rounded_top_right=&quot;true&quot; &amp;nbsp;rounded_bottom_left=&quot;false&quot; rounded_bottom_right=&quot;false&quot;&amp;gt;&lt;/div&gt;&lt;div&gt;&amp;nbsp;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;&amp;lt;distance name=&quot;left_width&quot; value=&quot;&lt;font class=&quot;Apple-style-span&quot; color=&quot;#D41A01&quot;&gt;5&lt;/font&gt;&quot;/&amp;gt;&lt;/div&gt;&lt;div&gt;&amp;nbsp;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;&amp;lt;distance name=&quot;right_width&quot; value=&quot;&lt;font class=&quot;Apple-style-span&quot; color=&quot;#D41A01&quot;&gt;5&lt;/font&gt;&quot;/&amp;gt;&lt;/div&gt;&lt;div&gt;&amp;nbsp;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;&amp;lt;distance name=&quot;bottom_height&quot; value=&quot;&lt;font class=&quot;Apple-style-span&quot; color=&quot;#D41A01&quot;&gt;5&lt;/font&gt;&quot;/&amp;gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;.. 중략..&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;br&gt;&lt;/div&gt;&lt;div&gt;그리고 아래와 같이 X 윈도우를 재시작하면 적용이 된다.&lt;/div&gt;&lt;div&gt;&lt;br&gt;&lt;/div&gt;&lt;div&gt;&lt;div style=&quot;padding:10px; background-color:#E4E4E4&quot;&gt;$ sudo /etc/init.d/gdm restart&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;br&gt;&lt;/div&gt;&lt;div&gt;&lt;br&gt;&lt;/div&gt;</description>
			<category>컴퓨터</category>
			<category>gdm</category>
			<category>Radiance</category>
			<category>thema</category>
			<category>ubuntu</category>
			<author>(김기태)</author>
			<guid>http://superkkt.com/614</guid>
			<comments>http://superkkt.com/614#entry614comment</comments>
			<pubDate>Tue, 25 Jan 2011 10:23:59 +0900</pubDate>
		</item>
		<item>
			<title>Backtrace function in C/C++</title>
			<link>http://superkkt.com/612</link>
			<description>GNU 확장 기능인 backtrace, backtrace_symbols 함수를 사용하면 프로그램이 비정상 종료되는 상황에서 call stack을 로그로 남길 수 있다.&amp;nbsp; 아래는 예제 코드이고 반드시 -rdynamic 옵션이 링크시에 주어져야만 콜스택에서 심볼명이 보이게 된다.&lt;br&gt;&lt;br&gt;&lt;div style=&quot;padding: 10px; background-color: rgb(228, 228, 228);&quot;&gt;#include &amp;lt;execinfo.h&amp;gt;&lt;br&gt;#include &amp;lt;stdio.h&amp;gt;&lt;br&gt;#include &amp;lt;stdlib.h&amp;gt;&lt;br&gt;&lt;br&gt;#define BACKTRACE_BUFFER_SIZE 256&lt;br&gt;&lt;br&gt;void func_2(void)&lt;br&gt;{&lt;br&gt;&amp;nbsp; &amp;nbsp; int i, nptrs;&lt;br&gt;&amp;nbsp; &amp;nbsp; void *buffer[BACKTRACE_BUFFER_SIZE];&lt;br&gt;&amp;nbsp; &amp;nbsp; char **strings = NULL;&lt;br&gt;&lt;br&gt;&amp;nbsp; &amp;nbsp; nptrs = backtrace(buffer, BACKTRACE_BUFFER_SIZE);&lt;br&gt;&amp;nbsp; &amp;nbsp; strings = backtrace_symbols(buffer, nptrs);&lt;br&gt;&amp;nbsp; &amp;nbsp; if (!strings) {&lt;br&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; perror(&quot;backtrace_symbols&quot;);&lt;br&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; exit(EXIT_FAILURE);&lt;br&gt;&amp;nbsp; &amp;nbsp; }&lt;br&gt;&lt;br&gt;&amp;nbsp; &amp;nbsp; for (i = 0; i &amp;lt; nptrs; i++) {&lt;br&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; printf(&quot;%s\n&quot;, strings[i]);&lt;br&gt;&amp;nbsp; &amp;nbsp; }&lt;br&gt;&lt;br&gt;&amp;nbsp; &amp;nbsp; free(strings);&lt;br&gt;}&lt;br&gt;&lt;br&gt;void func_1(void)&lt;br&gt;{&lt;br&gt;&amp;nbsp; &amp;nbsp; func_2();&lt;br&gt;}&lt;br&gt;&lt;br&gt;int main(void)&lt;br&gt;{&lt;br&gt;&amp;nbsp; &amp;nbsp; func_1();&lt;br&gt;&amp;nbsp; &amp;nbsp; return 0;&lt;br&gt;}&lt;/div&gt;&lt;br&gt;아래는 예제 코드를 컴파일하고 실행한 결과이다. 참고로 -O2 등의 최적화가 들어가면 콜스택이 변할 수 있다. 불필요한 함수 호출을 컴파일러가 제거하기 때문이다.&lt;br&gt;&lt;br&gt;&lt;div style=&quot;padding: 10px; background-color: rgb(228, 228, 228);&quot;&gt;superkkt@~/tmp$ gcc -Wall -g -rdynamic -o backtrace backtrace.c &lt;br&gt;superkkt@~/tmp$ ./backtrace &lt;br&gt;./backtrace(func_2+0x27) [0x4008db]&lt;br&gt;./backtrace(func_1+0x9) [0x400955]&lt;br&gt;./backtrace(main+0x9) [0x400960]&lt;br&gt;/lib/libc.so.6(__libc_start_main+0xfe) [0x7f7fcbaacd8e]&lt;br&gt;./backtrace() [0x4007f9]&lt;/div&gt;&lt;br&gt;Segmentation Fault 상황에서 시그널 핸들러를 사용해서 로그를 남기는 방법은 참조된 사이트를 참고한다.&lt;br&gt;&lt;br&gt;&lt;span style=&quot;font-weight: bold;&quot;&gt;&amp;lt;References&amp;gt;&lt;/span&gt;&lt;br&gt;&lt;br&gt;&lt;a href=&quot;http://www.linuxjournal.com/article/6391?page=0,0&quot; target=&quot;_blank&quot;&gt;Stack Backtracing Inside Your Program&lt;/a&gt;&lt;br&gt;</description>
			<category>프로그래밍</category>
			<category>backtrace</category>
			<category>backtrace_symbols</category>
			<category>GCC</category>
			<category>GNU</category>
			<category>LINUX</category>
			<author>(김기태)</author>
			<guid>http://superkkt.com/612</guid>
			<comments>http://superkkt.com/612#entry612comment</comments>
			<pubDate>Fri, 21 Jan 2011 09:34:12 +0900</pubDate>
		</item>
		<item>
			<title>SQLite3 Online Backup</title>
			<link>http://superkkt.com/610</link>
			<description>SQLite3는 &lt;a href=&quot;http://www.sqlite.org/backup.html&quot; target=&quot;_blank&quot;&gt;Online Backup C API&lt;/a&gt;를 제공해준다. API는 데이터베이스에 lock을 걸고 모든 데이터를 한번에 복사하는 방식과 lock, unlock을 반복적으로 수행하면서 조금씩 데이터를 복사하는 방식이 있다. 참고로 두번째 방식의 API는 아래와 같이 Online Backup을 구현한다.&lt;br&gt;&lt;br&gt;1. 데이터베이스 lock&lt;br&gt;2. 일부 데이터 백업&lt;br&gt;3. 데이터베이스 unlock&lt;br&gt;4. 남은 데이터가 있으면 잠시 대기 후 1번 과정으로 반복&lt;br&gt;&lt;br&gt;그런데 이와 같은 방식으로 백업을 하면 시간이 오래 걸리는데, 중간에 다른 프로세스에서 해당 데이터베이스에 새로운 데이터를 기록하면 자동으로 백업을 멈추고 처음부터 다시 시작하게 된다. 따라서 계속 바쁘게 사용하는 시스템에 이 방법을 사용하면 백업이 영원히 종료되지 않는 문제가 생길 수 있다.&lt;br&gt;&lt;br&gt;아래 코드는 SQLite 사이트에 있는 샘플 코드를 사용해서 첫번째 방법(한번에 모두 백업)으로 간단하게 백업툴을 만든 것이다.&lt;br&gt;&lt;br&gt;&lt;div style=&quot;padding: 10px; background-color: rgb(228, 228, 228);&quot;&gt;/* &lt;br&gt;&amp;nbsp;* SQLite3 Online Backup Tool&lt;br&gt;&amp;nbsp;* &lt;br&gt;&amp;nbsp;* Kitae Kim &amp;lt;superkkt@sds.co.kr&amp;gt;&lt;br&gt;&amp;nbsp;*&lt;br&gt;&amp;nbsp;* &amp;lt;Compile Instruction&amp;gt;&lt;br&gt;&amp;nbsp;*&amp;nbsp; $ sudo apt-get install libsqlite3-dev&lt;br&gt;&amp;nbsp;*&amp;nbsp; $ g++ -Wall -O2 -o sqlite_online_backup sqlite_online_backup.cpp -lsqlite3&lt;br&gt;&amp;nbsp;*/&lt;br&gt;#include &amp;lt;iostream&amp;gt;&lt;br&gt;#include &amp;lt;cstdlib&amp;gt;&lt;br&gt;#include &amp;lt;cstdio&amp;gt;&lt;br&gt;&lt;br&gt;#include &amp;lt;sqlite3.h&amp;gt;&lt;br&gt;&lt;br&gt;/*&lt;br&gt;** This function is used to load the contents of a database file on disk &lt;br&gt;** into the &quot;main&quot; database of open database connection pInMemory, or&lt;br&gt;** to save the current contents of the database opened by pInMemory into&lt;br&gt;** a database file on disk. pInMemory is probably an in-memory database, &lt;br&gt;** but this function will also work fine if it is not.&lt;br&gt;**&lt;br&gt;** Parameter zFilename points to a nul-terminated string containing the&lt;br&gt;** name of the database file on disk to load from or save to. If parameter&lt;br&gt;** isSave is non-zero, then the contents of the file zFilename are &lt;br&gt;** overwritten with the contents of the database opened by pInMemory. If&lt;br&gt;** parameter isSave is zero, then the contents of the database opened by&lt;br&gt;** pInMemory are replaced by data loaded from the file zFilename.&lt;br&gt;**&lt;br&gt;** If the operation is successful, SQLITE_OK is returned. Otherwise, if&lt;br&gt;** an error occurs, an SQLite error code is returned.&lt;br&gt;*/&lt;br&gt;int loadOrSaveDb(sqlite3 *pInMemory, const char *zFilename, int isSave){&lt;br&gt;&amp;nbsp; int rc; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; /* Function return code */&lt;br&gt;&amp;nbsp; sqlite3 *pFile; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; /* Database connection opened on zFilename */&lt;br&gt;&amp;nbsp; sqlite3_backup *pBackup;&amp;nbsp; /* Backup object used to copy data */&lt;br&gt;&amp;nbsp; sqlite3 *pTo; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; /* Database to copy to (pFile or pInMemory) */&lt;br&gt;&amp;nbsp; sqlite3 *pFrom; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; /* Database to copy from (pFile or pInMemory) */&lt;br&gt;&lt;br&gt;&amp;nbsp; /* Open the database file identified by zFilename. Exit early if this fails&lt;br&gt;&amp;nbsp; ** for any reason. */&lt;br&gt;&amp;nbsp; rc = sqlite3_open(zFilename, &amp;amp;pFile);&lt;br&gt;&amp;nbsp; if( rc==SQLITE_OK ){&lt;br&gt;&lt;br&gt;&amp;nbsp; &amp;nbsp; /* If this is a &#039;load&#039; operation (isSave==0), then data is copied&lt;br&gt;&amp;nbsp; &amp;nbsp; ** from the database file just opened to database pInMemory. &lt;br&gt;&amp;nbsp; &amp;nbsp; ** Otherwise, if this is a &#039;save&#039; operation (isSave==1), then data&lt;br&gt;&amp;nbsp; &amp;nbsp; ** is copied from pInMemory to pFile.&amp;nbsp; Set the variables pFrom and&lt;br&gt;&amp;nbsp; &amp;nbsp; ** pTo accordingly. */&lt;br&gt;&amp;nbsp; &amp;nbsp; pFrom = (isSave ? pInMemory : pFile);&lt;br&gt;&amp;nbsp; &amp;nbsp; pTo &amp;nbsp; = (isSave ? pFile &amp;nbsp; &amp;nbsp; : pInMemory);&lt;br&gt;&lt;br&gt;&amp;nbsp; &amp;nbsp; /* Set up the backup procedure to copy from the &quot;main&quot; database of &lt;br&gt;&amp;nbsp; &amp;nbsp; ** connection pFile to the main database of connection pInMemory.&lt;br&gt;&amp;nbsp; &amp;nbsp; ** If something goes wrong, pBackup will be set to NULL and an error&lt;br&gt;&amp;nbsp; &amp;nbsp; ** code and&amp;nbsp; message left in connection pTo.&lt;br&gt;&amp;nbsp; &amp;nbsp; **&lt;br&gt;&amp;nbsp; &amp;nbsp; ** If the backup object is successfully created, call backup_step()&lt;br&gt;&amp;nbsp; &amp;nbsp; ** to copy data from pFile to pInMemory. Then call backup_finish()&lt;br&gt;&amp;nbsp; &amp;nbsp; ** to release resources associated with the pBackup object.&amp;nbsp; If an&lt;br&gt;&amp;nbsp; &amp;nbsp; ** error occurred, then&amp;nbsp; an error code and message will be left in&lt;br&gt;&amp;nbsp; &amp;nbsp; ** connection pTo. If no error occurred, then the error code belonging&lt;br&gt;&amp;nbsp; &amp;nbsp; ** to pTo is set to SQLITE_OK.&lt;br&gt;&amp;nbsp; &amp;nbsp; */&lt;br&gt;&amp;nbsp; &amp;nbsp; pBackup = sqlite3_backup_init(pTo, &quot;main&quot;, pFrom, &quot;main&quot;);&lt;br&gt;&amp;nbsp; &amp;nbsp; if( pBackup ){&lt;br&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; (void)sqlite3_backup_step(pBackup, -1);&lt;br&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; (void)sqlite3_backup_finish(pBackup);&lt;br&gt;&amp;nbsp; &amp;nbsp; }&lt;br&gt;&amp;nbsp; &amp;nbsp; rc = sqlite3_errcode(pTo);&lt;br&gt;&amp;nbsp; }&lt;br&gt;&lt;br&gt;&amp;nbsp; /* Close the database connection opened on database file zFilename&lt;br&gt;&amp;nbsp; ** and return the result of this function. */&lt;br&gt;&amp;nbsp; (void)sqlite3_close(pFile);&lt;br&gt;&amp;nbsp; return rc;&lt;br&gt;}&lt;br&gt;&lt;br&gt;int main(int argc, char **argv)&lt;br&gt;{&lt;br&gt;&amp;nbsp; &amp;nbsp; if (argc != 3) {&lt;br&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; std::cerr &amp;lt;&amp;lt; &quot;Usage: &quot; &amp;lt;&amp;lt; argv[0] &amp;lt;&amp;lt; &quot; db_file backup_file\n&quot;;&lt;br&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; exit(EXIT_FAILURE);&lt;br&gt;&amp;nbsp; &amp;nbsp; }&lt;br&gt;&lt;br&gt;&amp;nbsp; &amp;nbsp; sqlite3 *db = NULL;&lt;br&gt;&amp;nbsp; &amp;nbsp; if (sqlite3_open(argv[1], &amp;amp;db) != SQLITE_OK) {&lt;br&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; std::cerr &amp;lt;&amp;lt; &quot;Failed to open the database file..\n&quot;;&lt;br&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; exit(EXIT_FAILURE);&lt;br&gt;&amp;nbsp; &amp;nbsp; }&lt;br&gt;&lt;br&gt;&amp;nbsp; &amp;nbsp; int rc = loadOrSaveDb(db, argv[2], 1);&lt;br&gt;&amp;nbsp; &amp;nbsp; if (rc != SQLITE_OK) {&lt;br&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; (void) sqlite3_close(db);&lt;br&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; std::cerr &amp;lt;&amp;lt; &quot;Failed to backup the database file.. (errno: &quot; &amp;lt;&amp;lt; rc &amp;lt;&amp;lt; &quot;)\n&quot;;&lt;br&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; exit(EXIT_FAILURE);&lt;br&gt;&amp;nbsp; &amp;nbsp; }&lt;br&gt;&lt;br&gt;&amp;nbsp; &amp;nbsp; (void) sqlite3_close(db);&lt;br&gt;&lt;br&gt;&amp;nbsp; &amp;nbsp; return 0;&lt;br&gt;}&lt;br&gt;&lt;/div&gt;&lt;br&gt;&lt;br&gt;</description>
			<category>프로그래밍</category>
			<category>SQLite3</category>
			<author>(김기태)</author>
			<guid>http://superkkt.com/610</guid>
			<comments>http://superkkt.com/610#entry610comment</comments>
			<pubDate>Mon, 13 Dec 2010 16:08:32 +0900</pubDate>
		</item>
		<item>
			<title>AsmXml - A Fast XML Parser Written in pure assembler</title>
			<link>http://superkkt.com/597</link>
			<description>&lt;a href=&quot;http://tibleiz.net/asm-xml/index.html&quot; target=&quot;_blank&quot;&gt;http://tibleiz.net/asm-xml/index.html&lt;/a&gt;&lt;div&gt;&lt;br&gt;&lt;/div&gt;&lt;div&gt;어셈블리로 개발된 XML Parser로 Windows, Linux, Mac에서 모두 사용 가능하고 오브젝트 파일 형태로 배포되기 때문에 소스트리에 직접 추가해서 사용하면 된다. 링크 방식 때문에 그런지 우분투 레포지토리에는 등록되어 있지 않다.&lt;/div&gt;&lt;div&gt;&lt;br&gt;&lt;/div&gt;&lt;div&gt;-참고&lt;/div&gt;&lt;div&gt;&lt;br&gt;&lt;/div&gt;&lt;div&gt;기본 제공되는 x86용 오브젝트 파일은 32비트로 컴파일되어 있는데, 64비트 시스템에서 사용할 때는 소스코드를 새로 컴파일해서 만들어야 하는지 확인해봐야 한다.&lt;/div&gt;</description>
			<category>프로그래밍</category>
			<category>AsmXML</category>
			<category>Assembler</category>
			<category>Assembly</category>
			<category>XML</category>
			<author>(김기태)</author>
			<guid>http://superkkt.com/597</guid>
			<comments>http://superkkt.com/597#entry597comment</comments>
			<pubDate>Fri, 15 Oct 2010 00:14:47 +0900</pubDate>
		</item>
		<item>
			<title>Matlab에서 삼각함수에 Degree를 사용하는 방법</title>
			<link>http://superkkt.com/569</link>
			<description>Matlab의 삼각함수는 기본적으로 radian 각도를 입력으로 받는다. 따라서 degree로 각도를 사용하려면 아래와 같이 &#039;d&#039;가 추가된 함수를 사용해야 한다.&lt;div&gt;&lt;br&gt;&lt;/div&gt;&lt;div style=&quot;padding:10px; background-color:#E4E4E4&quot;&gt;&lt;div&gt;sind()&lt;/div&gt;&lt;div&gt;cosd()&lt;/div&gt;&lt;div&gt;tand()&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;br&gt;&lt;/div&gt;&lt;div&gt;&lt;br&gt;&lt;/div&gt;</description>
			<category>프로그래밍</category>
			<category>degree</category>
			<category>Radian</category>
			<category>삼각함수</category>
			<author>(김기태)</author>
			<guid>http://superkkt.com/569</guid>
			<comments>http://superkkt.com/569#entry569comment</comments>
			<pubDate>Mon, 02 Aug 2010 16:36:28 +0900</pubDate>
		</item>
		<item>
			<title>MySQL 패키지 버전 업그레이드시 시스템 테이블 업그레이드 방법</title>
			<link>http://superkkt.com/568</link>
			<description>MySQL이 버전업이 되면 시스템 테이블의 내용도 달라지는 경우가 있다. 그런데 패키지로 MySQL을 설치하면 버전업시 사용자가 별도로 테이블을 업그레이드하지 않아도 정상적으로 잘 동작을 한다. 이건 패키지가 업그레이드 될때 mysql_upgrade 명령어가 실행되면서 시스템에 설치된 MySQL 버전에 맞도록 모든 데이터베이스 테이블을 업그레이드 해주기 때문이다.&lt;div&gt;&lt;br&gt;&lt;/div&gt;&lt;div&gt;먼저 아래 로그 예제는 MySQL 버전이 서로 다른 서버 사이에서 데이터베이스 파일을 그대로 옮겨서 사용할 때 발생한 것이다.&lt;/div&gt;&lt;div&gt;&lt;br&gt;&lt;/div&gt;&lt;div style=&quot;padding:10px; background-color:#E4E4E4&quot;&gt;&lt;div&gt;Aug &amp;nbsp;2 12:02:47 wiz-1 mysqld: 100802 12:02:47 [ERROR] Column count of mysql.db is wrong. Expected 22, found 20. Created with MySQL 50075, now running 50137. Please use mysql_upgrade to fix this error.&lt;/div&gt;&lt;div&gt;Aug &amp;nbsp;2 12:02:47 wiz-1 mysqld: 100802 12:02:47 [ERROR] mysql.user has no `Event_priv` column at position 29&lt;/div&gt;&lt;div&gt;Aug &amp;nbsp;2 12:02:47 wiz-1 mysqld: 100802 12:02:47 [ERROR] Cannot open mysql.event&lt;/div&gt;&lt;div&gt;Aug &amp;nbsp;2 12:02:47 wiz-1 mysqld: 100802 12:02:47 [ERROR] Event Scheduler: An error occurred when initializing system tables. Disabling the Event Scheduler.&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;br&gt;&lt;/div&gt;&lt;div&gt;기존 서버의 MySQL 버전에서는 mysql.user 테이블에 Event_priv 필드가 없었는데, 새로운 버전에서 추가되어서 문제가 생긴것이다.&lt;/div&gt;&lt;div&gt;&lt;br&gt;&lt;/div&gt;&lt;div&gt;그래서 아래와 같이 mysql_upgrade를 사용해서 자동으로 교정을 해준다. 이때 MySQL 서버는 운영 중인 상태로 두어야 한다.&lt;/div&gt;&lt;div&gt;&lt;br&gt;&lt;/div&gt;&lt;div&gt;&lt;div style=&quot;padding:10px; background-color:#E4E4E4&quot;&gt;mysql_upgrade -u root --password&lt;/div&gt;&lt;br&gt;&lt;/div&gt;&lt;div&gt;그리고나서 MySQL 재시작시켜주면 업그레이드된 테이블의 내용이 반영된다.&lt;/div&gt;&lt;div&gt;&lt;br&gt;&lt;/div&gt;&lt;div&gt;참고로 MySQL 재시작 과정에서 아래와 같은 에러 로그가 나온다면 debian-sys-maint 사용자를 등록해줘야한다.&lt;/div&gt;&lt;div&gt;&lt;br&gt;&lt;/div&gt;&lt;div&gt;&lt;div style=&quot;padding:10px; background-color:#E4E4E4&quot;&gt;Aug &amp;nbsp;2 13:45:53 wiz-1 /etc/mysql/debian-start[3827]: /usr/bin/mysqlcheck: Got error: 1045: Access denied for user &#039;debian-sys-maint&#039;@&#039;localhost&#039; (using password: YES) when trying to connect&lt;/div&gt;&lt;div style=&quot;padding:10px; background-color:#E4E4E4&quot;&gt;Aug &amp;nbsp;2 13:45:53 wiz-1 /etc/mysql/debian-start[3827]: FATAL ERROR: Upgrade failed&lt;/div&gt;&lt;br&gt;&lt;/div&gt;&lt;div&gt;먼저 /etc/mysql/debian.cnf 파일에서 mysql-upgrade 영역에 있는 debian-sys-maint 사용자의 패스워드를 복사한다. 이 예제에서는 &lt;font color=&quot;#D41A01&quot;&gt;TEXSvTrT215CxmAx&lt;/font&gt; 이다. 그 다음에 MySQL에 root로 접속해서 아래와 같이 사용자를 등록해준다.&lt;/div&gt;&lt;div&gt;&lt;br&gt;&lt;/div&gt;&lt;div&gt;&lt;div style=&quot;padding:10px; background-color:#E4E4E4&quot;&gt;GRANT ALL PRIVILEGES ON *.* TO &#039;debian-sys-maint&#039;@&#039;localhost&#039; IDENTIFIED BY &#039;&lt;i&gt;&lt;font color=&quot;#D41A01&quot;&gt;TEXSvTrT215CxmAx&lt;/font&gt;&lt;/i&gt;&#039; WITH GRANT OPTION;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;br&gt;&lt;/div&gt;</description>
			<category>컴퓨터</category>
			<category>MySQL</category>
			<category>mysql_upgrade</category>
			<author>(김기태)</author>
			<guid>http://superkkt.com/568</guid>
			<comments>http://superkkt.com/568#entry568comment</comments>
			<pubDate>Mon, 02 Aug 2010 14:21:24 +0900</pubDate>
		</item>
		<item>
			<title>Linux Kernel in a Nutshell</title>
			<link>http://superkkt.com/560</link>
			<description>&lt;a href=&quot;http://www.kroah.com/lkn/&quot; target=&quot;_blank&quot;&gt;http://www.kroah.com/lkn/&lt;/a&gt;</description>
			<category>책</category>
			<category>Kernel</category>
			<author>(김기태)</author>
			<guid>http://superkkt.com/560</guid>
			<comments>http://superkkt.com/560#entry560comment</comments>
			<pubDate>Tue, 13 Jul 2010 14:05:13 +0900</pubDate>
		</item>
	</channel>
</rss>

