2009-12-02 4 views
1

"$ Revision : 9 $"또는 "$ Revision : 9999999 $"와 같은 임의의 SVN 리비전을 정수 나 정수로 변환 할 수있는 C/C++ 매크로를 찾고 있습니다. 끈.SVN 리비전을 정수로 변환하는 C 매크로

이 간단한 함수가 있음을 알고 있지만이 컴파일 시간에 만들 싶습니다. unsigned int rev = SVN_TO_INT("$Revision$");

+0

컴파일러와 좋은 것은 당신 만 사용하는 상수 시간 컴파일하는 경우 실제로 결과 값으로 함수 호출을 대체 할 수 있다는 것입니다이다.벤처 캐피털 (VC)은 가치를 교환하는 몇 가지 방법을 비교하기 위해 한 때 저에게 그렇게했습니다. 결과 어셈블러 코드 (/ O2 포함)는 더 이상 함수 호출을 포함하지 않았습니다. 단지 상수. – Joey

+2

수정 번호를 실행 파일에 자동으로 포함시키려는 경우 svn 키워드를 통해 포함 된 수정 번호는 * 수정 된 파일 *을 커밋 할 때만 변경되기 때문에 잘못된 경로에 있다고 생각합니다. 따라서 SVN_TO_INT 매크로가있는 파일은 항상 프로젝트의 개정판을 반영합니다. –

+0

귀하의 의견에 동의하지만, 파일 단위 수정 시스템이 내 용도에 적합합니다 (파일 당 하나의 클래스와 클래스 당 하나의 개정판). –

답변

1

매크로로는 처리 할 수 ​​없다는 것에 동의하지만 컴파일러 최적화를 사용하여 트릭을 발견했습니다. 하나의 부호없는 정수로 감소된다 : 결과는 표현 JL_SvnRevToInt ("12345 $ $ 개정이")이다 12345

inline unsigned int JL_SvnRevToInt(const char *r) { 


    if (r == NULL || r[0] == '\0' || r[10] == '\0' || r[11] == '\0' || r[12] == '\0' || r[13] == '\0') 
    return 0; 

    const unsigned int count = 
      r[11] == ' ' ? 1 
     : r[12] == ' ' ? 10 
     : r[13] == ' ' ? 100 
     : r[14] == ' ' ? 1000 
     : r[15] == ' ' ? 10000 
     : r[16] == ' ' ? 100000 
     : r[17] == ' ' ? 1000000 
     : r[18] == ' ' ? 10000000 
     : r[19] == ' ' ? 100000000 
     : 0; 

    return 
     (r[11] == ' ' ? 0 : (r[11]-'0') * (count/10) + 
     (r[12] == ' ' ? 0 : (r[12]-'0') * (count/100) + 
     (r[13] == ' ' ? 0 : (r[13]-'0') * (count/1000) + 
     (r[14] == ' ' ? 0 : (r[14]-'0') * (count/10000) + 
     (r[15] == ' ' ? 0 : (r[15]-'0') * (count/100000) + 
     (r[16] == ' ' ? 0 : (r[16]-'0') * (count/1000000) + 
     (r[17] == ' ' ? 0 : (r[17]-'0') * (count/10000000) + 
     (r[18] == ' ' ? 0 : (r[18]-'0') * (count/100000000) + 
     (r[19] == ' ' ? 0 : (r[19]-'0') * (count/1000000000) + 
     0))))))))); 
} 

그것은 NULL 빈과 "$ 개정 $"문자열 자리 개정 번호를 supports9.

2

나는 이것이 매크로 불가능하다는 것을 상대적으로 확신 :

내 소원은 같은 것들을 작성하는 것입니다.

템플릿 메타 프로그래밍을 사용하는 것이 가능할 수는 있지만 가까이 가지 않았습니다.

SVN_TO_INT를 원하는 텍스트로 바꾸는 사전 빌드 스크립트에서도 가능합니다.

컴파일 타임에 알기 때문에 버전 번호를 하드 코딩하는 것이 쉽기 때문에 왜 이것을 원하는지 이해할 수 없습니다.

+0

그래도 문제는 매번 변경해야합니다 :) – Jacob

+2

실제로 해킹 할 수 있습니다 makefile에서 실행되는 스크립트와 함께 -DSVN_REVISION = 89278을 명령 행에 넣습니다. – Joey

+1

+1 기본적으로 "내가 편집하기 전에 할 수 있다면 어째서"내가 생각하기에 정신을 차려야했다. –

1

당신은 완전히 사전에 문자열과 함께 일하거나 시간을 컴파일 할 수 없습니다 -하지만 같은 이유 뭔가 뭔가를 사용하지 :

int svn_version() 
{ 
    static const int v = extract_svn_version(REVISION); 
    return v; 
} 
+0

내 바이너리 파일 ("$ Revision : XXXX $")에 저장 될 리비전 문자열을 피하려고합니다. –

+0

그런 다음 소스 외부에서이를 수행하고 빌드 환경에서이를 정의해야합니다. C++ 0x 컴파일 타임 스트링 처리 (전에는 아무 것도 없다)가있는 것 같습니다. 문자열 리터럴이 바이너리에서 제거된다는 것을 여전히 보장하지는 않습니다 - 컴파일러는 그렇게하지 않을 수도 있습니다. –

+2

왜 바이너리 파일에 저장 하시겠습니까? 우리가 CVS에서 사용했던 것은 바이너리에서 빌드 정보를 찾을 수 있기 때문입니다. 일단 바이너리가 고객에게 갔다면, 우리는 그들이 어디로 갔는지에 대해 아무런 통제권도 없었고, 때로는 특정 고객 시스템이 어떤 버전을 실행하고 있는지를 아는 것이 실질적으로 유용했습니다. –

2

당신은 컴파일 시간에 원하는 문자열 조작의 종류를 할 수 없다 C 전처리 기 (매크로) 또는 템플리트 (C++) 빌드 프로세스에서 호출 할 수있는 외부 유틸리티 또는 스크립트를 사용해야합니다.

일부 유틸리티/스크립트/코드 당신을 도울 수있는 그 :

6

당신이 컴파일에서 문자열과 함께 작동하지 않을 수 있음에 동의 매크로 또는 템플릿을 통한 시간. 그래서 ... 문자열을 사용하지 마십시오.

이것은 못생긴 해킹이지만 모든 요구 사항을 충족한다고 생각합니다. 나는 그것을 추천하지 않는다.

#define $Revision struct REV_STR { unsigned foo 
#define $ * 64; }; 

$Revision: 4521 $ 

enum { REV = sizeof(REV_STR)/8 }; 

#undef $Revision 
#undef $ 

#include <iostream> 
int main() 
{ 
    std::cout << REV << std::endl; 
    return 0; 
} 

// $ g++ -Wall -Wextra revision.cpp && ./a.exe 
// revision.cpp:4: warning: width of `REV_STR::foo' exceeds its type 
// 4521 
+6

그건 아름답게 구역질이 나는데, 나는 너에게 경의를 표한다! – caf

+0

존경합니다! 나는 그것을 사랑한다! 나는 그것을 좋아하는 사람을 쓰는 것에 반대하는 사람을 추천 하겠지만. – dudico

1

makefile 기반 빌드 시스템을 사용하는 경우 make 시간마다 파일을 만드는 특별 규칙을 만들 수 있습니다.

.PHONY: svn_revision.c 

svn_revision.c: 
     echo -n "int svn_revision = " > svn_revision.c 
     svn info | grep Revision | cut -f2 -d" " >> svn_revision.c 
     echo ";" >> svn_revision.c 

svn_revision.o: svn_revision.c 
2

내 솔루션

#define $Revision (false?1 
#define $ +0) 

int codeRevision() { return $Revision: $; } 

#undef $Revision 
#undef $ 
관련 문제