コンパイル時にソースファイルのベース名を取得する
-
04-07-2019 - |
質問
GCCを使用しています。 __FILE__は、現在のソースファイルの完全なパスと名前を返します: /path/to/file.cpp
。コンパイル時にファイル名 file.cpp
を(パスなしで)取得する方法はありますか?ポータブルな方法でこれを行うことは可能ですか?テンプレートメタプログラミングを文字列に適用できますか?
これをエラーログマクロで使用しています。私は、ソースの完全なパスが実行可能ファイルに進むことを本当に望んでいません。
解決
makeプログラムを使用している場合は、事前にファイル名を変更して、プログラムで使用するgccにマクロとして渡すことができるはずです。
メイクファイルで、次の行を変更します。
file.o: file.c
gcc -c -o file.o src/file.c
to:
file.o: src/file.c
gcc "-D__MYFILE__=\"`basename mainprog: main.o makefile
gcc -o mainprog main.o
main.o: src/main.c makefile
gcc "-D__MYFILE__=\"`basename #include <stdio.h>
int main (int argc, char *argv[]) {
printf ("file = %s\n", __MYFILE__);
return 0;
}
lt;`\"" -c -o main.o src/main.c
lt;`\"" -c -o file.o src/file.c
これにより、コードで __ FILE __
の代わりに __ MYFILE __
を使用できます。
ソースファイルのベース名($&lt;)を使用することは、&quot; .c.o&quot;などの一般的なルールで使用できることを意味します。
次のコードは、その仕組みを示しています。
ファイルmakefile:
pax@pax-desktop:~$ mainprog
file = main.c
pax@pax-desktop:~$
ファイルsrc / main.c:
<*>シェルから実行:
<*>&quot; file =&quot;に注意してください。 dirnameではなく、ファイルのベース名のみを含む行。
他のヒント
この単純なソースコードを検討してください:
#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
then __FILE__はフルパス( ' /work1/jleffler/tmp/x.c
')にマッピングされます。次を使用してコンパイルする場合:
gcc -o x ../tmp/x.c && ./x
then __FILE__は「 ../ tmp / x.c
」にマップされます。
したがって、基本的に、__ FILE__はソースファイルのパス名です。オブジェクトに表示したい名前でビルドすれば、すべてうまくいきます。
(何らかの理由で)それが不可能な場合は、他の人から提案された修正を行う必要があります。
直接的な方法は知りません。次を使用できます。
#line 1 "filename.c"
ソースファイルの先頭で __ FILE __
の値を設定しますが、ハードコーディングするよりもはるかに優れているかどうかはわかりません。または#defineを使用して独自のマクロを作成します。
別のオプションは、-Dおよび$(shell basename $&lt;)を使用して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}\"")
テンプレートのメタプログラミングでそれを行うことができるかもしれませんが、組み込みの方法はありません。
編集:ふむ、訂正。 今見たページ、GCCはファイルに指定されたパスを使用します。フルネームが与えられている場合は、埋め込みます。相対的なものだけが指定されている場合は、それだけが埋め込まれます。自分で試したことはありません。
Glomekからアイデアを得て、次のように自動化できます。
ソースファイルx.c
#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__を取り、パスの不要な部分を(プログラムで)取り除くことができます。 basedirがニーズを満たしている場合は、問題ありません。それ以外の場合は、ビルドシステムからソースディレクトリルートを取得します。残りは実行可能になります。
同じ問題が発生しました。別の解像度を見つけたので、共有したいと思いました:
他のすべてのファイルに含まれるヘッダーファイル:
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 ..&amp;&amp;きれいにする&amp;&amp; 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-私のエラー
PS config.h.in
で明確にする方が良い-&gt; config.h
#ifndef __RELATIVE_FILE_PATH__
#define __RELATIVE_FILE_PATH__ __FILE__
#endif
だからあなたのリンターはエラーの雨を提供しません。
次を使用できます:
bool IsDebugBuild()
{
return !NDEBUG;
}
または、マクロでNDEBUGを使用して、これらのファイルパスをオンまたはオフにすることができます。