2014년 4월 23일 수요일
2014년 4월 22일 화요일
2014년 4월 15일 화요일
로그를 좀더 이쁘게 박아보자(g++ 기준)
로그를 작성할 때 그냥 막 적어도 상관은 없다만 이왕이면 해당 파일명과 소스라인 위치 함수명까지 알면 더욱 좋을것이다. 언제나 그렇듯이 긴말 말고 아래 매크로 또는 클래스들을 보자.
- __FILE__ : 소스코드가 포함된 파일 이름을 반환
- __LINE__ : 소스코드의 줄 번호를 반환
- __func__ : 소스코드가 포함된 함수 이름을 반환
- __PRETTY_FUNCTION__ : 소스코드가 포함된 클래스 이름과 함수 이름을 '이쁘게' 반환
- typeid(T t).name() : 맹글링된 클래스 이름이나 타입 이름을 반환
다시 말하지만 위 매크로들은 g++ 기준이다. MSVC나 clang에서는 이와 같거나 다른 이름을 가지지만 같은 역할을 하는 매크로가 있을 것이다. 아래는 위 매크로를 이용한 간단한 예제이다.
1 #include <iostream>
2 #include <typeinfo>
3
4
5 class CPrettyLog
6 {
7 public:
8 void Print(void)
9 {
10 std::cout
11 << "__PRETTY_FUNCTION__ = " << __PRETTY_FUNCTION__ << std::endl
12 << "__func__ = " << __func__ << std::endl
13 << "__LINE__ = " << __LINE__ << std::endl
14 << "__FILE__ = " << __FILE__ << std::endl
15 << "typeid(this).name() = " << typeid(this).name() << std::endl
16 << std::endl;
17 }
18 };
19
20
21 void Print(void)
22 {
23 std::cout
24 << "__PRETTY_FUNCTION__ = " << __PRETTY_FUNCTION__ << std::endl
25 << "__func__ = " << __func__ << std::endl
26 << "__LINE__ = " << __LINE__ << std::endl
27 << "__FILE__ = " << __FILE__ << std::endl
28 << std::endl;
29 }
30
31
32 int main(int argc, char** argv)
33 {
34 CPrettyLog pl;
35 pl.Print();
36
37 Print();
38
39 std::cout
40 << "__PRETTY_FUNCTION__ = " << __PRETTY_FUNCTION__ << std::endl
41 << "__func__ = " << __func__ << std::endl
42 << "__LINE__ = " << __LINE__ << std::endl
43 << "__FILE__ = " << __FILE__ << std::endl
44 << std::endl;
45
46 return 0;
47 }
48
1 #include <iostream>
2 #include <typeinfo>
3
4
5 class CPrettyLog
6 {
7 public:
8 void Print(void)
9 {
10 std::cout
11 << "__PRETTY_FUNCTION__ = " << __PRETTY_FUNCTION__ << std::endl
12 << "__func__ = " << __func__ << std::endl
13 << "__LINE__ = " << __LINE__ << std::endl
14 << "__FILE__ = " << __FILE__ << std::endl
15 << "typeid(this).name() = " << typeid(this).name() << std::endl
16 << std::endl;
17 }
18 };
19
20
21 void Print(void)
22 {
23 std::cout
24 << "__PRETTY_FUNCTION__ = " << __PRETTY_FUNCTION__ << std::endl
25 << "__func__ = " << __func__ << std::endl
26 << "__LINE__ = " << __LINE__ << std::endl
27 << "__FILE__ = " << __FILE__ << std::endl
28 << std::endl;
29 }
30
31
32 int main(int argc, char** argv)
33 {
34 CPrettyLog pl;
35 pl.Print();
36
37 Print();
38
39 std::cout
40 << "__PRETTY_FUNCTION__ = " << __PRETTY_FUNCTION__ << std::endl
41 << "__func__ = " << __func__ << std::endl
42 << "__LINE__ = " << __LINE__ << std::endl
43 << "__FILE__ = " << __FILE__ << std::endl
44 << std::endl;
45
46 return 0;
47 }
48
위 예제를 컴파일 후 실행하면 아래와 같은 결과를 얻을 수 있다.
__PRETTY_FUNCTION__ = void CPrettyLog::Print()
__func__ = Print
__LINE__ = 13
__FILE__ = main.cpp
typeid(this).name() = P10CPrettyLog
__PRETTY_FUNCTION__ = void Print()
__func__ = Print
__LINE__ = 26
__FILE__ = main.cpp
__PRETTY_FUNCTION__ = int main(int, char**)
__func__ = main
__LINE__ = 42
__FILE__ = main.cpp
2014년 4월 8일 화요일
리눅스의 디렉토리 구조와 역할
리눅스의 각 디렉토리 구조는 커널버전과 제품군에 따라 조금씩 다르지만 기본적인 맥락은 거의 비슷하다. 개인적으로 장문의 글로 장황하게 설명하는 걸 싫어하니 아래 트리와 주석을 보도록 하자.
물론 모든 리눅스 시스템과 프로젝트들이 위 규칙을 따르는 건 아니지만 적어도 몇십년동안 많은 개발자와 관리자들에게 사랑을 받아온 구조에는 그만한 이유가 있다. 필자 또한 처음에는 이런저런 구조를 도입해보려 했었지만 결국 종착역은 위 구조였다. 그 이유는 아래와 같다.
일단 이번 포스트는 이쯤에서 마무리 지으려고 한다. 쓰다보면 끝이 없을 것 같다.
~
├── bin/
├── lib/
├── include/
├── src/
├── etc/
├── var/
└── tmp/
- ~
- 유저의 홈 디렉토리
- 유저 디렉토리의 모든 시작지점
- bin/
- 실행 바이너리 및 쉘 스크립트들이 있음
- binary file, .sh, .java 등
- lib/
- 라이브러리 파일들이 있음
- .a, .so, .jar 등
- include/
- 헤더 및 전처리 파일들이 있음
- 주로 lib/에서 필요한 헤더들이 있음
- .h, .hh, .hpp, .py 등
- src/
- 작업중이거나 빌드 전의 소스코드들이 있음
- etc/
- 설정값이나 정보와 같이 고정적인 값들을 저장한 파일들이 있음
- 주로 바이너리 이름 뒤에 확장자를 붙여 사용함
- .conf, .nfo, .info 등
- var/
- 로그나 상태값과 같은 수시로 변하는 의미있는 정보들을 저장한 파일들이 있음
- 주로 바이너리 이름을 가지는 디렉토리 내에 저장됨
- .log, .stat, .queue, .pool 등
- tmp/
- 작업 중 임시로 사용되거나 수시로 생성/삭제되는 파일들이 있음
- 주로 바이너리 이름을 가지는 디렉토리 내에 저장됨
- .dummy, .buffer, 작업중인 파일 등
물론 모든 리눅스 시스템과 프로젝트들이 위 규칙을 따르는 건 아니지만 적어도 몇십년동안 많은 개발자와 관리자들에게 사랑을 받아온 구조에는 그만한 이유가 있다. 필자 또한 처음에는 이런저런 구조를 도입해보려 했었지만 결국 종착역은 위 구조였다. 그 이유는 아래와 같다.
- 한 솔루션 내 여러 프로젝트 사이에서 일어나는 사이드 이펙트를 빠르고 직접적(?)으로 파악할 수 있음(이 얘기에 대해서는 추후 리눅스의 이상적인 솔루션(프로젝트) 구조에서 다루도록 하겠음)
- 프로젝트의 유지보수 및 패치작업이 수월함
- 관리자와 개발자 간 의사소통이 원활해짐
일단 이번 포스트는 이쯤에서 마무리 지으려고 한다. 쓰다보면 끝이 없을 것 같다.
이번 포스트의 핵심은 '몇십년동안 사랑을 받아온 구조에는 그만한 이유가 있다'
blogDevCrazyBird.Start();
다시 블로그를 운영하기로 마음 먹었다.
이유는 일반 SNS로는 다 표현하기 힘든 일기성 글이라던가 각종 정보성 기사들의 스크랩 및 개인적인 개발 공부를 위해서다. 앞으로 리눅스 및 C++(특히 C++11/14) 위주의 포스트가 주를 이룰 듯 하다. 매주 화/수/목 진행하는 아프리카 방송 다시보기도 업로드할 예정이다.
부디 이번에는 귀차니즘과 게임에 빠져서 유령 블로그가 되지는 않았으면 한다.
피드 구독하기:
글 (Atom)