컴파일 타임에서 소스 파일의 기본 이름 가져 오기
-
04-07-2019 - |
문제
GCC를 사용하고 있습니다. __file__ 현재 소스 파일의 전체 경로 및 이름을 반환합니다. /path/to/file.cpp
. 파일 이름 만 얻는 방법이 있습니까? file.cpp
컴파일 시간에 (경로없이)? 휴대용으로 이것을 할 수 있습니까? 템플릿 메타 프로그래밍을 문자열에 적용 할 수 있습니까?
오류 로깅 매크로에서 이것을 사용하고 있습니다. 나는 내 소스의 전체 경로가 실행 파일로 들어가는 것을 정말로 원하지 않습니다.
해결책
Make 프로그램을 사용하는 경우 프라이팬을 미리 MUNGE로하여 프로그램에서 사용할 수있는 매크로로 GCC로 전달할 수 있어야합니다.
makefile에서 선을 변경하십시오.
file.o: file.c
gcc -c -o file.o src/file.c
에게:
file.o: src/file.c
gcc "-D__MYFILE__=\"`basename $<`\"" -c -o file.o src/file.c
이것은 당신이 사용할 수있게합니다 __MYFILE__
대신 코드에서 __FILE__
.
소스 파일 ($ <)의베이스 이름을 사용한다는 것은 ".co"와 같은 일반 규칙에서 사용할 수 있음을 의미합니다.
다음 코드는 작동 방식을 보여줍니다.
파일 makefile :
mainprog: main.o makefile
gcc -o mainprog main.o
main.o: src/main.c makefile
gcc "-D__MYFILE__=\"`basename $<`\"" -c -o main.o src/main.c
파일 src/main.c :
#include <stdio.h>
int main (int argc, char *argv[]) {
printf ("file = %s\n", __MYFILE__);
return 0;
}
쉘에서 실행 :
pax@pax-desktop:~$ mainprog
file = main.c
pax@pax-desktop:~$
Dirname이 아닌 파일의베이스 이름 만 포함하는 "file ="라인에 주목하십시오.
다른 팁
이 간단한 소스 코드를 고려하십시오.
#include <stdio.h>
int main(void)
{
puts(__FILE__);
return(0);
}
Solaris에서 GCC 4.3.1을 사용하여 다음을 사용하면 다음을 컴파일합니다.
gcc -o x x.c && ./x
출력은 'x.c
'내가 그것을 사용하여 컴파일하면 :
gcc -o x $PWD/x.c && ./x
그런 다음 __file__는 전체 경로에 맵핑됩니다 ( '/work1/jleffler/tmp/x.c
'). 사용하여 컴파일하는 경우 :
gcc -o x ../tmp/x.c && ./x
그런 다음 __file__지도../tmp/x.c
'.
따라서 기본적으로 __file__는 소스 파일의 경로 이름입니다. 객체에서보고 싶은 이름으로 빌드하면 모든 것이 좋습니다.
그것이 불가능하다면 (어떤 이유로 든) 다른 사람들이 제안한 수정 사항에 들어가야합니다.
나는 직접적인 방법을 모른다. 당신은 사용할 수 있습니다 :
#line 1 "filename.c"
소스 파일의 상단에서 __FILE__
, 그러나 나는 그것이 하드 코딩하는 것보다 훨씬 낫다고 확신하지 못한다. 또는 #define을 사용하여 자신의 매크로를 만듭니다.
또 다른 옵션은 -d 및 $ (Shell Basename $ <)를 사용하여 makefile에서 이름을 전달하는 것입니다.
편집 : #define 또는 -d 옵션을 사용하는 경우 자신만의 새 이름을 만들고 재정의하지 않아야합니다. __FILE__
.
오류 로깅 매크로는 무엇을합니까? 나는 매크로가 결국 로깅을하기 위해 어떤 종류의 함수를 호출한다고 가정 할 것입니다. 왜 런타임에서 경로 구성 요소에서 호출 된 함수를 제거하지 않겠습니까?
#define LOG(message) _log(__FILE__, message)
void _log(file, message)
{
#ifndef DEBUG
strippath(file); // in some suitable way
#endif
cerr << "Log: " << file << ": " << message; // or whatever
}
cmake에 태그가 지정된 이후, cmakelists.txt에 추가 할 수있는 깔끔한 솔루션이 있습니다. http://www.cmake.org/pipermail/cmake/2011-december/048281.html ). (참고 : 일부 컴파일러는 파일 별 compile_definitions를 지원하지 않지만 GCC에서 작동합니다).
set(SRCS a/a.cpp b/b.cpp c/c.cpp d/d.cpp)
foreach(f IN LISTS SRCS)
get_filename_component(b ${f} NAME)
set_source_files_properties(${f} PROPERTIES
COMPILE_DEFINITIONS "MYSRCNAME=${b}")
endforeach()
add_executable(foo ${SRCS})
참고 : 내 응용 프로그램의 경우 다음과 같은 파일 이름 문자열을 피해야했습니다.
COMPILE_DEFINITIONS "MYSRCNAME=\"${b}\"")
템플릿 Metaprogramming으로 수행 할 수는 있지만 내장 방법은 없습니다.
편집 : HM, 수정. 에 따르면 방금 본 한 페이지, GCC는 파일에 주어진 경로를 사용합니다. 전체 이름이 주어지면 그것을 포함시킬 것입니다. 그것이 상대적으로 만 주어지면, 그것은 단지 그것을 포함시킬 것입니다. 나는 그것을 직접 시도하지 않았다.
Glomek의 아이디어를 가져 오면 다음과 같이 자동화 할 수 있습니다.
소스 파일 XC
#line 1 MY_FILE_NAME
#include <stdio.h>
int main(void)
{
puts(__FILE__);
return(0);
}
컴파일 라인 (이중 인용구 외부의 단일 따옴표를 조심하십시오) :
gcc -DMY_FILE_NAME='"abcd.c"' -o x x.c
출력은 'abcd.c
'.
당신은 할당 할 수 있습니다 __FILE__
문자열로, _splitpath ()를 호출하여 조각을 찢어 버립니다. 이것은 Windows/MSVC 전용 솔루션 일 수 있습니다. 솔직히 모르겠습니다.
나는 당신이 컴파일 타임 솔루션을 찾고 있다는 것을 알고 있으며 이것은 런타임 솔루션이지만, 파일 이름을 사용하여 (아마도 런타임) 오류 로깅을했기 때문에 이것은 당신을 얻는 간단한 간단한 방법 일 수 있습니다. 필요한 것.
당신은 __file__와 스트립을 원하지 않는 경로의 일부에서 제거 할 수 있습니다 (프로그래밍적으로). 기반이 당신의 요구를 충족 시키면 괜찮습니다. 그렇지 않으면 빌드 시스템에서 소스 딥 루트를 가져 오면 나머지는 가능해야합니다.
방금 같은 문제를 겪었습니다. 다른 결의안을 찾았고 그냥 공유 할 것이라고 생각했습니다.
다른 모든 파일에 포함 된 헤더 파일에서 :
static char * file_bname = NULL;
#define __STRIPPED_FILE__ (file_bname ?: (file_bname = basename(__FILE__)))
이것이 다른 사람에게도 유용하기를 바랍니다 :)
프로그래밍 방식으로 만 수행 할 수 있습니다.
아마도 이것은 유용 할 것입니다 ...
filename = __FILE__
len = strlen(filename)
char *temp = &filename[len -1]
while(*temp!= filename)
if(*temp == '\') break;
cmake는 쉽습니다.
DefineRelativeFilePaths.cmake
function (cmake_define_relative_file_paths SOURCES)
foreach (SOURCE IN LISTS SOURCES)
file (
RELATIVE_PATH RELATIVE_SOURCE_PATH
${PROJECT_SOURCE_DIR} ${SOURCE}
)
set_source_files_properties (
${SOURCE} PROPERTIES
COMPILE_DEFINITIONS __RELATIVE_FILE_PATH__="${RELATIVE_SOURCE_PATH}"
)
endforeach ()
endfunction ()
어딘가 CMakeLists.txt
set (SOURCES ${SOURCES}
"${CMAKE_CURRENT_SOURCE_DIR}/common.c"
"${CMAKE_CURRENT_SOURCE_DIR}/main.c"
)
include (DefineRelativeFilePaths)
cmake_define_relative_file_paths ("${SOURCES}")
cmake .. && make clean && make VERBOSE=1
cc ... -D__RELATIVE_FILE_PATH__="src/main.c" ... -c src/main.c
그게 다야. 이제 예쁜 로그 메시지를 만들 수 있습니다.
#define ..._LOG_HEADER(target) \
fprintf(target, "%s %s:%u - ", __func__, __RELATIVE_FILE_PATH__, __LINE__);
func src/main.c : 22- 내 오류
추신 : 쇠약 해지는 것이 좋습니다 config.h.in
-> config.h
#ifndef __RELATIVE_FILE_PATH__
#define __RELATIVE_FILE_PATH__ __FILE__
#endif
그래서 당신의 린터는 오류의 비를 제공하지 않습니다.
당신은 사용할 수 있습니다 :
bool IsDebugBuild()
{
return !NDEBUG;
}
또는 매크로에서 ndebug를 사용하여 해당 파일 경로를 켜거나 끕니다.