g++이 탐색하는 기본 include 경로 확인법

g++ -v -E –

이렇게 하면 아래와 같이 나온다.

Using built-in specs.
COLLECT_GCC=g++
COLLECT_LTO_WRAPPER=/usr/lib/gcc/x86_64-linux-gnu/4.6/lto-wrapper
Target: x86_64-linux-gnu
Configured with: ../src/configure -v –with-pkgversion=’Ubuntu/Linaro 4.6.3-1ubuntu5′ –with-bugurl=file:///usr/share/doc/gcc-4.6/README.Bugs –enable-languages=c,c++,fortran,objc,obj-c++ –prefix=/usr –program-suffix=-4.6 –enable-shared –enable-linker-build-id –with-system-zlib –libexecdir=/usr/lib –without-included-gettext –enable-threads=posix –with-gxx-include-dir=/usr/include/c++/4.6 –libdir=/usr/lib –enable-nls –with-sysroot=/ –enable-clocale=gnu –enable-libstdcxx-debug –enable-libstdcxx-time=yes –enable-gnu-unique-object –enable-plugin –enable-objc-gc –disable-werror –with-arch-32=i686 –with-tune=generic –enable-checking=release –build=x86_64-linux-gnu –host=x86_64-linux-gnu –target=x86_64-linux-gnu
Thread model: posix
gcc version 4.6.3 (Ubuntu/Linaro 4.6.3-1ubuntu5) 
COLLECT_GCC_OPTIONS=’-v’ ‘-E’ ‘-shared-libgcc’ ‘-mtune=generic’ ‘-march=x86-64’
 /usr/lib/gcc/x86_64-linux-gnu/4.6/cc1 -E -quiet -v -imultilib . -imultiarch x86_64-linux-gnu – -mtune=generic -march=x86-64 -fstack-protector
ignoring nonexistent directory “/usr/local/include/x86_64-linux-gnu”
ignoring nonexistent directory “/usr/lib/gcc/x86_64-linux-gnu/4.6/../../../../x86_64-linux-gnu/include”
#include “…” search starts here:
#include <…> search starts here:
 /usr/lib/gcc/x86_64-linux-gnu/4.6/include
 /usr/local/include
 /usr/lib/gcc/x86_64-linux-gnu/4.6/include-fixed
 /usr/include/x86_64-linux-gnu
 /usr/include
End of search list.

시스템 콜을 후킹?

뭐 시간이 없어서 직접 해보고 예제 만들고 하지를 못했네요.
간단하게 설명하고 링크 남깁니다.

LD_PRELOAD를 사용해서 어플리케이션 실행전에 미리 로드해두고
어플리케이션에서 시스템 함수가 호출되면 미리 로드된 다른 함수가 불리는 방식입니다.

참고자료 링크

BS의 Makefile 예제

BS가 만든 Makefile 인데 조금 지저분합니다.


뭐 Linux로 프로그래밍을 하면서 Makefile 안쓰시는 분은 없겠지만서도


BS는 매번 Makefile을 만드느라 Manual을 뒤지고 있는 실정이라서


블로그에 정리 삼아 올려 봅니다.


 


Makefile, Makefile.release, Makefile.debug


이렇게 3개 파일로 구성되어 있습니다.


Makefile.release와 Makefile.debug 는 각각 release 버전과 debug 버전으로의 빌드를 처리하며


Makefile 은 release, debug에 맞게 sub 명령을 수행하고


예제에서는 생성된 Library를 특정 경로로 복사합니다.


 


cfile24.uf.121EC240500631CC2EDAA9


cfile27.uf.194DD33C500631CD343D59.release


cfile23.uf.151EF340500631CC2DF66B.debug


 


확장자가 없는 Makefile은 블로그 프로그램에서 자동으로 txt 확장자를 붙이는 것 같네요.


받으실때 주의하시기 바랍니다.


파일명은 순서대로 Makefile, Makefile.release, Makefile.debug 입니다.


 


Makefile은 -j 옵션을 사용하지 않고 실행하면


submake (Makefile 안에서 다시 make 실행 하는 것)에 직접 옵션을 주었습니다.


자세한 사항은 The GNU Make Manual(http://www.gnu.org/software/make/manual/)을 참고하세요.

Linux에서 GetTickCount()와 같은 함수가 필요할 때에는

Windows 환경에서 작업을 하면…

2개 이벤트 사이에 소요된 시간을 구할 때

GetTickCount() 함수를 이용해서 시간을 구해서 그 차이로 알 수 있는데요.

(물론 GetTickCount() 는 32비트, GetTickCount64()는 64비트 범위 내의 millisecond 단위 값으로 약 49일)

Linux에서는 이와 같은 함수를 찾으니 없는 건지 못찾는 건지…

 

clock_t clock(void);

뭐 이런 함수는 있지만서도… 이 함수는 해당 프로그램이 CPU를 얼마나 사용했는지를 구하는 녀석이고…

sleep() 과 같은 함수에서 CPU 사용없이 쉰 시간은 계산되지 않습니다.

 

int clock_gettime(clockid_t clk_id, struct timespec *tp);

clk_id를 CLOCK_REALTIME으로 주면 GetTickCount() 비슷하게 사용할 수 있을지도 모르겠으나,

CPU 클럭 수를 반환하도록 되어 있어, 혹여나 시스템에서 클럭이 동적으로 변경되는 시스템이면 이것도

무리가 있습니다.

 

역시 이 함수가 편하네요

int gettimeofday(struct timeval *tv, struct timezone *tz);

 

이 함수를 GetTickCount() 처럼 만들면 아래처럼 되겠네요.

#include <sys/time.h>
#include <unistd.h>
#include <iostream>

namespace
{
	class __GET_TICK_COUNT
	{
	public:
		__GET_TICK_COUNT()
		{
		if (gettimeofday(&tv_, NULL) != 0)
			throw 0;
		}
		timeval tv_;
	};
	__GET_TICK_COUNT timeStart;
}

unsigned long GetTickCount()
{
	static time_t	secStart	= timeStart.tv_.tv_sec;
	static time_t	usecStart	= timeStart.tv_.tv_usec;
					timeval tv;
	gettimeofday(&tv, NULL);
	return (tv.tv_sec - secStart) * 1000 + (tv.tv_usec - usecStart) / 1000;
}

unsigned long GetTickCount2()
{
	timeval tv;
	gettimeofday(&tv, NULL);
	return (unsigned long)(tv.tv_sec * 1000 + tv.tv_usec / 1000);
}

using namespace std;

int main()
{
	unsigned long t1 = GetTickCount();
	usleep(1 * 1000 * 1000);
	unsigned long t2 = GetTickCount();
	cout << (t2 - t1) << endl;
	unsigned long t3 = GetTickCount2();
	usleep(1 * 1000 * 1000);
	unsigned long t4 = GetTickCount2();
	cout << (t4 - t3) << endl;
	return 0;
}

 

Win32 API의 QueryPerformance*()보다 빠르다고 하는 사람도 있군요

BS는 Sun VirtualBox 에서 테스트를 해서 그런지 1001 ~ 1004 까지 다양한 값이 나온다는…

Interlocked*() 함수를 Linux 에서 사용하기

뭐 이전까지는 이런 함수가 Linux에서 필요한 경우가 없었는데…

Windows와 Linux에서 모두 동작하는 서버를 만드려다보니…

Win32 API에 있는 Interlocked*() 함수가 필요하게 되었습니다.

 

여기저기 찾다보니 이런! 인라인 어셈으로 만들어 쓰는 소스도 있고…

(아~~~ 이건 아니지)

 

역시 GNU 였습니다. 다 있더군요…

 

http://gcc.gnu.org/onlinedocs/gcc-4.4.2/gcc/Atomic-Builtins.html#Atomic-Builtins

(GCC 사이트에서 Documentation>Manual>GCC 4.4.2 Manual>Extensions to the C Language Family>Built-in functions for atomic memory access)

 

요거 #define 등으로 잘 해두면 Windows Interlocked 처럼 쓸 수 있을 것 같습니다.

 

샘플코드로 테스트 했습니다.


#include <iostream>
using namespace std;
int main(void)
{
        volatile long long a = 10;
        cout << __sync_val_compare_and_swap(&a, 11, 11) << endl;
        cout << a << endl;
        cout << __sync_val_compare_and_swap(&a, 10, 11) << endl;
        cout << a << endl;
        return 0;
}

 

g++ -march=i586 test.cpp

./a.out

10

10

10

11

 

오호라 됩니다!!! 일단 실행은 잘 되는군요.

문제는 -march=i586 입니다. 요놈이 없으면 link에서 실패하는군요.

g++ test.cpp

/tmp/ccAAhEVI.o: In function `main’:
test.cpp:(.text+0xb8): undefined reference to `__sync_val_compare_and_swap_8′
test.cpp:(.text+0x131): undefined reference to `__sync_val_compare_and_swap_8′
collect2: ld returned 1 exit status

i386, i486 도 안되는 것은 마찬가지 입니다.

결론은 타겟 CPU에 따라 안될 수도 있다 입니다.

BS는 게임서버를 x86 계열을 생각하고 작업하기에 충분하네요

 

추가 정보)

찾아보니 gcc 4.1.2 부터 지원하는군요.

GCC에서 시스템 헤더때문에 경고가 발생할 때…

Linux에 boost 1.40.0 을 세팅해서 어플리케이션 하나를 만들었습니다.


그리고 습관적으로 -Werror -Wall 옵션을 주어 컴파일을 했습니다.


 


아 이런!!!


 


boost 헤더에서 경고가 발생하여 빌드가 되지 않는군요.


그렇다고 boost 헤더를 수정하기엔 무리가 있고…


 


찾다보니 이런게 있었네요…


 


보통 include 경로를 “-I” 옵션으로 주어 사용 했었는데


시스템 헤더를 위한 옵션이 따로 있습니다.


-isystem <path>


 


이걸로 boost 헤더파일 경로를 지정하니 boost 헤더에서의 경고가 무시되네요…


이런 방법이 있었는데 왜 몰랐을까요?

VIM 에서 사용자 정의 키워드 색깔 넣기

VIM에서 키워드로 내가 원하는 단어를 넣는 방법은…


 


1. .vimrc 파일 (Windows 환경이라면 _vimrc) 수정


설정 파일에 아래 내용을 입력한다.


아래와 같이 설정하면 cpp 적용시 각 키워드가 cppType 으로 등록되어 표시된다.



au Syntax cpp syn keyword cppType int8_t int16_t int32_t int64_t uint8_t uint16_t uint32_t uint64_t


2. cpp.vim (or c.vim) 수정


vim 설치된 경로에 가면 syntax 디렉토리가 있는데 이 안에 c.vim이나 cpp.vim을 수정하면 된다.


아래 내용을 해당 파일에 추가하면 됨




syn keyword cppType int8_t int16_t int32_t int64_t uint8_t uint16_t uint32_t uint64_t


1번 방법을 쓰면 자신의 계정에만 설정할 수 있고


2번 방법을 쓰면 모든 유저에게 적용된다.

초간단 Linux 라이브러리 만들기

아주 간단하게 설명하겠습니다.


즉, C++에 대한 기초 지식?이 있다는 가정하에


 


1. 정적 라이브러리 1
  1) Object 파일 생성
    $ gcc -c test.c
  2) 라이브러리 생성
    $ ar r libtest.a test.o
  3) 인덱스 생성
    $ ranlib libtest.a
  4) extern 형태로 선언된 헤더 파일 만들기


 


2. 정적 라이브러리 2
  1) Object 파일 생성
    $ gcc -c test.c
  2) 라이브러리 생성
    $ ar rs libtest.a test.o
  3) extern 형태로 선언된 헤더 파일 만들기


 


3. 공유 라이브러리
  1) 컴파일
    $ gcc -c -fpic test.c
  2) 라이브러리 생성
    $ gcc -shared -o libtest.so test.o
  3) extern 형태로 선언된 헤더 파일 만들기


 


아주 간단히 설명했지만… 여기서 조금 더 추가하면 완성된답니다… 귀차니즘의 압박으로 여기까지만…

gdb 로 실행중인 프로세스 디버깅

gdb 로 실행 중인 프로세스를 디버깅할 수 있는데 (물론 MS VC++ 도 됨)
대학의 리눅스 시스템 프로그래밍 수업에서도 알려주지 않고
책에서도 간략히 설명하고 끝내는 수준이라 모르거나 대충 알아서 실무에서는 활용을 하지 못하는 사람이 많습니다.


 


gdb 로 디버깅 할 때에 보통은
$ gdb filename
이렇게 실행하고 gdb 프롬프트에서 run 으로 실행합니다.


 


여기에서 실제 수행중인 프로세스를 디버깅 하려면




방법1
$ gdb filename pid



방법2
$ gdb filename
gdb> attach pid
이렇게 하면 gdb에 들어가는 순간 break 가 걸립니다. 즉, 프로그램이 일시 정지 상태가 됩니다.
그럼 원하는 디버깅 액션을 하고 continue 를 하면 프로그램은 수행을 계속합니다.
그리고 프로그램을 계속 실행 상태로 두고 gdb 를 종료할 때에는




gdb> detach
gdb> quit

이렇게 하면 프로세스와 분리되고 종료됩니다.


 


이것을 이전에 올린 batch 모드와 섞어 쓰게 되면…




$ cat gdbcmd.txt
b MyApp.cpp:1234
c
set flag=true
detach
quit


 


$ gdb -batch -command gdbcmd.txt MyApp 1234

위와 같이 실행하면,
PID 1234로 실행 중인 MyApp 프로그램이 디비깅 시작이 되고
batch 모드를 따라 MyApp.cpp의 1234 라인에 브레이크를 걸고 실행을 계속 합니다.
그리고 break 가 걸리면 flag 변수의 값을 true 로 변경하고
실행을 계속하도록 하면서 gdb 만 종료합니다.


 


잘 응용을 하면 런타임에 원하는 변수 값을 수행할 수도 있습니다.