Autotools 관련 좋은 링크들

Autotools 는 Unix 계열에서 Makefile 을 만들어주고, 의존성 체크를 해주는 툴이다.

(그러나 사용법은 조금 이해가 안가는 T.T)

인터넷을 뒤지다가 좋은 링크들을 발견해서 기억해두기 위해서 적어둔다.

http://blog.sdnkorea.com/blog/65

http://blog.naver.com/bamtol1216?Redirect=Log&logNo=100107833137

어떤 모바일 단말에 뛰어들어야 하나요?

요새 확실히 모바일이 대세이긴 대세다. 수 많은 포탈들에서도 모바일 지원을 천명하고 있고

(g 모사에서는 CEO가 향후 g모사의 핵심은 모바일 이라고 외치기도 하셨고) 그렇다면 과연

모바일에 운명을 걸고자 하는 사람들은 과연 어디로 뛰어들어야 할까?

플랫폼도 다양하다. 아이폰, 안드로이드, 곧 나올 윈도우모바일7 까지(나머지 플랫폼들도 있지만,

현재는 이 3개의 임팩트가 가장 강하다. 미안하다. 심비안아!!!)

결론부터 말하자면, 현재 돈을 벌고자 한다면, 한국에서는 무조건 아이폰이다!!!

위에서 “현재 돈을 벌고자 한다면” 을 강조한 이유는  단 한가지이다.

아이폰 이외에는 일반 개발자가 돈을 벌기는 힘들기 때문이다.

기본적으로는 벌지 못한다고 생각하면 된다. 분명히, 그럼 다른 플랫폼을 무시하는 것이냐고

한다면, 이유는 간단하다. 현재 한국 소속으로는 안드로이드와 MS앱스토어에 유료 어플을

올릴 수 없다!, 오직 가능한 곳은 아이폰의 애플앱스토어 뿐이다.

현재 구글 안드로이드 마켓에서는 미국 주소지의 신용카드가 있어야만 paymant account(유료계정)

을 등록할 수 있다. 현재 한국에서는 유료 어플의 다운로드 자체도 가능하지가 않다.

MS도 마찬가지이다. 아직 윈도우 모바일 7폰 자체도 안나왔을 뿐더러, MS스토어도 아직 활성화 되지

않았다. 활성화 되더다로 한국의 순서는?

그렇다면, 아이폰이 무조건 해답인가? 그건 아니다. 실제로 위의 세 플랫폼 모두에서 유료등록과

상관없이 돈을 벌 수 있다. 그건 벅스나, 소리바다 처럼, 웹 사이트등에서 매달 결제하게 하고,

해당 유료 등록자만, 서비스를 들을 수 있게 하는 방식을 택하면 가능하긴 하다. 그러나, 1인 개발자가

이런 방식을 하기는 힘들지 않을까 싶다.

간단하게 각 플랫폼의 특성을 정리해보면 다음과 같다.

  아이폰 안드로이드 윈도우모바일7
주체 애플 구글 MS
주언어 Objective-C Java C#(Siverlight, XNA)
장점 1. 동일한 하드웨어
2. 유료 마켓 활성화
1. 소스 공개
2. 멀티태스킹
1. 기본적으로 아이폰을 닮아감!
2. 하드웨어 기본 사양 강제
단점 – 아이패드로 인해서 동일한 하드웨어가 깨졌음
– 부분적 멀티태스킹으로 힘듬
– 다양한 하드웨어가 존재 – 유료 OS

뭐, 간단하게 이런식이지만, –_- 결론은 HTML5가 짱일 것이라는 허망한 결론이 나온다.

하나로 다양한 플랫폼이 커버가 되니, 하드웨어 종속적인 기능이 필요한 경우가 아니라면

몇년 내로 HTML5가 대세이지 않을까?

코드 스니핏 – urlencode, urldecode 샘플

갑자기 필요해졌는데 –_-, 괜찮은 소스코드가 없었다.

그렇다고 내가 만든건 아니고 qDecoder 에서 decode 부분을 –_-( qDecoder에서는 한글이 인코딩이 안되네) 또 어디에서(어디더라, ) encode 부분을 가져와서 간단하게 인터페이스만 살짝 바꾼 버전이다.

고로 –_- 아무것도 내가 한건 없다라고 보면 될듯

MAC에서는 NSString 이 기본적으로 해주는데, c 쪽은 다 직접 해줘야 한다라는 –_-

#include <stdio.h>
#include <string.h>
#include <memory.h>
static const unsigned char hexchars[] = “0123456789ABCDEF”;

char *url_encode(char const *s, int len, int *new_length)
{
    register unsigned char c;
    unsigned char *to, *start;
    unsigned char const *from, *end;

    from = s;
    end = s + len;
    start = to = (unsigned char *) malloc(3 * len + 1);

    while (from < end) {
        c = *from++;
        if (c == ‘ ‘) {
            *to++ = ‘+’;
#ifndef CHARSET_EBCDIC
        } else if ((c < ‘0’ && c != ‘-‘ && c != ‘.’) ||
            (c < ‘A’ && c > ‘9’) ||
            (c > ‘Z’ && c < ‘a’ && c != ‘_’) ||
            (c > ‘z’)) {
                to[0] = ‘%’;
                to[1] = hexchars[c >> 4];
                to[2] = hexchars[c & 15];
                to += 3;
#else /*CHARSET_EBCDIC*/
        } else if (!isalnum(c) && strchr(“_-.”, c) == NULL) {
            /* Allow only alphanumeric chars and ‘_’, ‘-‘, ‘.’; escape the rest */
            to[0] = ‘%’;
            to[1] = hexchars[os_toascii[c] >> 4];
            to[2] = hexchars[os_toascii[c] & 15];
            to += 3;

#endif /*CHARSET_EBCDIC*/
        } else {
            *to++ = c;
        }
    }

    *to = 0;
    if (new_length) {
        *new_length = to – start;
    }

    return (char *) start;
}

/**
* Decode URL encoded string.
*
* @param str    a pointer of URL encoded string.
*
* @return    the length of bytes stored in str in case of successful, otherwise returns NULL
*
* @note
* This modify str directly. And the ‘str’ is always terminated by NULL character.
*/
static char _x2c(char hex_up, char hex_low)
{
    char digit;

    digit = 16 * (hex_up >= ‘A’
        ? ((hex_up & 0xdf) – ‘A’) + 10 : (hex_up – ‘0’));
    digit += (hex_low >= ‘A’
        ? ((hex_low & 0xdf) – ‘A’) + 10 : (hex_low – ‘0’));
    return (digit);
}

int url_decode(char *str, char *target, int size) {
    char *pEncPt, *pBinPt, *pTarPt;

    if (str == NULL || target == NULL || size == 0 ) {
        return 0;
    }

    pBinPt = str;
    pTarPt = target;

    for(pEncPt = str; *pEncPt != ”; pEncPt++) {
        if( (pTarPt – target) >= size )
        {
            pTarPt–;
            break;
        }

        switch (*pEncPt) {
            case ‘+’: {
                *pTarPt++ = ‘ ‘;
                break;
            }
            case ‘%’: {
                *pTarPt++ = _x2c(*(pEncPt + 1), *(pEncPt + 2));
                pEncPt += 2;
                break;
            }
            default: {
                *pTarPt++ = *pEncPt;
                break;
            }
        }
    }
    *pTarPt = ”;

    return (pTarPt – target);
}

int main()
{
    int i, n;
    unsigned char dest[256] = {0x00,};
    unsigned char test[256] = {0x00,};
    char *pTarget;
    unsigned char *str[] = {
        “안녕하세요”,
        “hello world 안녕하세요n”,
         “hello%20world%20%be%c8”,
        “A B C D E F G”,
        NULL
    };

    int count = 0;
    char *pDest = str[count];
    while( NULL != pDest){
        printf(“Original : %d %srn”, strlen(pDest), pDest);
        pTarget = url_encode(pDest, strlen(pDest), NULL);
        printf(“encode   : %d %sn”, strlen(pTarget), pTarget);

        n = url_decode(pTarget, test, 256);
        test[n] = 0;
        printf(“decode   : %d %sn”, n, test);

        free(pTarget);
        count++;
        pDest = str[count];
    }

    return 0;
}

Makefile Sample

그냥 내가 보통 사용하는 Makefile Sample

sample 을 잘 보면 몇 가지 안 쓰는 부분들이 있지만, Makefile 의 문법을 알기 위해서 나중에 쓸 수 있는

부분들이라서 같이 올린다.

.SUFFIXES   =   .cpp .o
AR          =   ar
CC          =   g++
CFLAGS      =
LIBS        =
INCS        =
OBJS        =   cs_socket_addr.o
                cs_socket.o
                cs_netutil.o
                cs_acceptor_socket.o
                cs_connector_socket.o
SRCS        =   $(OBJS: .o=.cpp)

TARGET      =   netlib.a
TEST1       =   client_test
TEST2       =   server_test

all     :       $(TARGET) $(TEST1) $(TEST2)

$(TARGET) :     $(OBJS)
                $(AR) rcv $(TARGET) $(OBJS)

$(TEST1)    :   $(TARGET) $(TEST1).o
                $(CC) -o $(TEST1) $(TEST1).o $(TARGET)

$(TEST2)    :   $(TARGET) $(TEST2).o
                $(CC) -o $(TEST2) $(TEST2).o $(TARGET)
.cpp.o      :
                $(CC) -c $(CFLAGS) $*.cpp

dep         :
                    gccmakedepend $(SRCS)
clean       :
                    rm -rf $(OBJS) $(TARGET) $(TEST1) $(TEST2) core

재미나고 유용한 VC 옵션 한가지

한방빌드를 만들어서 쓰다보면, 다음과 같은 경우가 생깁니다.

1. 소스 트리는 하나로 유지하고 싶다.

2. 나가는 대상에 따라서 서로 다른 기능이 동작해야 한다.(바이너리에서 완전히 빠져있게)

사실 결론은 하나입니다. #ifdef 등으로 기능이 다르게 동작하게 하는 것.

그럼 여기에 적용할 수 있는 간단한 방법은 다음과 같습니다.

1. 소스 트리를 따로 유지한다. –> 1번에 위배되고, 유지보수에 손이 많이 갑니다.

2. 프로젝트 속성을 여러개 만들어서, 사용한다. 하지만, 이것도, 한 솔루션에 프로젝트가 여러 개 있다면, 굉장히 번거로운 작업이 생깁니다.

3. 하나의 프로젝트 속성을 쓰데, 매번, 빌드 할 때, #define 속성을 변경해준다.

4. 빌드 시, 자동으로 소스 코드에 설정에 맞는 #define 이 들어가도록 빌드 스크립트를 작성한다.

위에 것들을 보면 4번이 그래도 가장 나아보입니다. 그리고, 설정 작업이 복잡해 진다면, 4번 형태로 가는게 좋을듯 합니다.

그런데, 지금부터 알려드릴(이미 공개된 ㅋㅋ) 옵션을 사용하게 되면, 한방에 처리가 됩니다.

뭐냐 하면,  CL 이라는 환경 변수입니다.

먼저 자세한 건 다음 사이트에서 알 수 있습니다.

http://msdn.microsoft.com/en-us/library/kezkeayy.aspx

간단하게 설명하자면 set CL=-D_TEST_A_

이런식으로 지정하면 빌드시에 자동으로 _TEST_A_ 옵션이 적용됩니다. –D 뿐만 아니라 다른 것들도 쉽게 바뀌게 됩니다. 즉, 같은 빌드 프로세스를 타면서 앞쪽에 CL옵션을 설정해서 #define 한것과 같은 효과를 낼 수 있습니다.

간단한 빌드 프로세스에서는 위의 4번과 같은 방법을 쓰지 않고도 효과적으로 사용할 수 있습니다.

급히 수정해야 하는 버그는 또 다른 버그를 만든다.

크, 역시 급히 수정해야 하는 버그는 새로운 버그군을 만들어 낸다.

오늘 급히 수정해야 할 버그를 고치기 위해서, 코드에 변경을 했다.

그 다음부터 –_-, 동작이 하나씩 안되기 시작하더니, 급기야 –_-, 주요 기능이 동작하지 않게 되었다.

물론, 원인을 하나하나 분석하기 시작해서 이전 코드의 동작이 제대로 되도록 수정을 하기는 했지만 –_-

흑흑흑…

급한 마음으로 코드를 짜면, 역시 버그가 나올 수 밖에 없다.

좋은 테스트 코드가 있다면 좋겠지만, 아직 그러기에는 힘든 T.T

바람풍과 바담뿡

혹시 예전에 이런 얘기를 들어본 적이 있는가?

어미 게가 아기 게는 바르게 걷기를 바래서, 아기 게의 걸음을 보정해 주려고 노력하는 이야기…

이 이야기의 요점은… 어미 게의 감동적인 자식 교육이 아니라, 잘못된 교육이라는 것이다.

이걸 아주 강하게 느끼는 것이, 현재의 나다 T.T

내 코드는 좀 더럽다 –_-, 아주 깔끔하게 짜는 것도 아니고, 시간이 없을 때에는 더더욱, 더러운 코드를 생산한다. 스멜이 강하게 나는!!!

그런데, 이번에 프로젝트를 진행하면서, 나와 신입 프로그래머 한명이 담당하게 되었다.

그런데, 코드 리뷰를 해주고, 해당 코드를 수정할 일이 있어서, 코드를 보는데, 우어어어어, 알아보는 데 시간이 걸렸다. 그런데 재미있는 것은, 이 친구가 작성한 다른 코드를 보면, 아주 깜끔한 코드 부터, 아주 더러운 코드까지 각양각생이었다.

그 이유가 무엇일까?

원인은 바로 기존 코드의 참고이다. 즉, 참고한 코드가 깔끔한 코드이면, 신입이 작성한 코드도 깔끔한 코드가 되고, 참고한 코드가 더러운 코드가 되면, 신입이 작성한 코드도 매우 더러운 코드가 되어버리는 것이다.

그리고 가슴아프게도, 더러운 코드 부분은 나의 더러운 코드를 보고 흉내를 낸것이었다.

그걸 보니, 코드를 깔끔하게 짜야겠다라는 생각이 부쩍든다. 왜냐하면, 참고할 코드를 작성하는 선배가

바담뿡 하고 있는데, 그걸 보고 배우는 신입사원이 바람풍 할리는 없기 때문이다.

결국, 누구의 잘못이 아니라, 나의 잘못이다. 더더욱 깔끔한 코드를 생성하려고 노력해야겠다.

Continuous Integration

Continuous Integration(이하 CI) – 지속적인 통합이라는 의미다.

요새 꽤나 “이슈” 가 많이 되고 있는(사실은 좀 이전에~~~) 주제이기도 하다.

 

보통 CI 라고 하면, CI 툴을 사용해서 설치하면 되지 않는가 라고 생각하기 쉽다.

사실 이 말도 맞다. 하지만, 모든 것이 그렇듯이 CI의 핵심은 “사람” 이고 “팀원” 이다.

 

먼저 CI의 구성 요소를 살펴보자.

1. 소스 형상 관리 시스템( SVN, CVS, VSS 등등 뭐든지 좋다. )

– 소스 형상 관리 시스템이 없다면,  솔직히 CI가 구성되지 않는다. 상상해보자.

특정 시간마다, 수많은 사람들이 USB나, 이메일 등 을 통해서 서로 다른 소스를 던져준다면?

수많은 버그와 함께, 코드 되돌리기 신공이 난무하게 될 것이다.  SVN을 쓰더라도 머지가 힘들 수도

있지만 (사실 SVN 등을 쓸 때, 머지의 책임은 뒤에 커밋하는 사람이 지는 것이다. ) 과연 어느 것이

쉬울지는 잠시만 적응해 보면 안다.

 

2. 빌드 머신 과 한방 빌드

보통 빌드라는 건, 개발자가 자신의 로컬 머신에서 VS등에서 F7 등을 눌리면 되는 것으로 생각하기 쉽다. 그러나, 빌드라는 것도, 공식 빌드, QA 빌드, 개발자 테스트 빌드, 개발도중의 빌드 등으로 나눌 수 있다. 여기서 개발 도중에 개발자가 하는 빌드를 빼고는 개발자 테스트 빌드 조차도 한방 빌드라는 공식화된 빌드 루틴을 타야 한다.

한방 빌드라는 것은, 그냥 배치 스크립트 등을 딱 한번 누르면, 깨끗한 머신에서 알아서 소스코드를 가져오고, 필요한 라이브러리를 링크해서 빌드 결과를 알려줄 수 있는 시스템이다. 그 안에는 사람의 손이 추가로 가서는 안 된다.

일일 빌드라는 유명한 것도, 이 한방 빌드로 만들어져야 한다.

3. CI 툴

사실 CI 툴은 편의를 도와주는 것이지만 사용하기 힘들다면 꼭 안써도 된다. 그냥 2의 한방 빌드를 예약 작업으로 걸어놓고, 10분이나, 1시간 단위로 돌려서 결과를 확인해도 된다. 하지만, 편의를 도와준다는 것은 생산성을 향상시켜준다는 것을 알아야 한다.

4. 사람(별표 백만개)

위의 시스템이 잘 갖춰져 있어도, 쓰는 사람들에 따라서 천지 차이다. –_-

SVN이 있더라도 하루에 한번 체크인을 한다든지, 3개월에 한번 한다든지 한다면, 별 의미가 없다.

같은 한방 빌드라도, 필요한 부분을 빨리 체크해서 결과를 알려주는 것과, 모두 끝난뒤에야 결과를 알려주는 등의 것도 어떻게 구성하는지에 따라서 매우 결과가 달라진다.

CI툴의 리포트도 사람이 신경쓰지 않으면 전혀 의미가 없다.

그래서 결국 사람이 가장 중요하다.

위에 것들이 관심이 있다면, 최소 1,2번 까지라도 설정해 보길 바란다.

CI 툴중에 소스코드를 커밋한걸 감지하고 있다가 소스코드가 커밋될 때마다 빌드해서 알려주는

기능도 있으니, 누군가 커밋을 빼 먹어 생기는 문제가 많다면, 이런 기능을 이용해 보는것도 어떨까?

SVN의 External 기능

최근에 발견한(검색한) 기능 중에서 SVN에 External 이라는 기능이 있다는 것을 알게 됬다.

그런데 바로 이 기능이 대박이다.

프로젝트를 진행하다 보면 다음과 같은 구성이 될 때가 있다.

A,B,C 라는 프로젝트가 있고, 공통 Component D 가 있다.

image

그럼 SVN 의 구조는 위와 같은 형태가 된다. 이러면 소스 트리에 공통 Component를 같이 넣어두던지

매번 따로 소스코드를 CheckOut 받아줘야 한다. 이러면 문제가, 최상위에서 Update 를 받아도 해당

공통 Component 는 따로 Update를 받아야 한다.

 

이것을 해결해 주는 것이 바로 External 키워드이다. 타 SVN Repogitory 를 자신의 하위 디렉토리처럼

인식시켜서, 한방에 다운로드를 받을 수 있게 한다. 이것을 설정하는 방법은 간단하다. SVN에서는 커맨드

를 이용해서 주면 되고, TortoiseSVN에서는 TortoiseSVN->Properties 를 선택한 다음

Property Name 으로 svn:externals 라고 설정하고, Value 로 다운로드 받을 디렉토리 경로명으로

지정하면 된다.

 

value : component http://sample.svn.com/sampleproject/sample_component

위와 같이 지정해주면 끝!!!

Technorati 태그: