私は GCC を使用しています。__FILE__ は、現在のソース ファイルの完全なパスと名前を返します: /path/to/file.cpp
. file.cpp
コンパイル時にファイルの名前だけを (パスなしで) 取得する方法はありますか? これをポータブルな方法で行うことは可能ですか?テンプレート メタ プログラミングを文字列に適用できますか?
これをエラー ログ マクロで使用しています。ソースのフルパスが実行可能ファイルに入るのを本当に望んでいません。
私は GCC を使用しています。__FILE__ は、現在のソース ファイルの完全なパスと名前を返します: /path/to/file.cpp
. file.cpp
コンパイル時にファイルの名前だけを (パスなしで) 取得する方法はありますか? これをポータブルな方法で行うことは可能ですか?テンプレート メタ プログラミングを文字列に適用できますか?
これをエラー ログ マクロで使用しています。ソースのフルパスが実行可能ファイルに入るのを本当に望んでいません。
プログラムを使用している場合はmake
、事前にファイル名を変更して、プログラムで使用するマクロとして渡すことができるはずですgcc
。たとえば、makefile
の行を次のように変更します。
file.o: file.c
gcc -c -o file.o src/file.c
に:
file.o: src/file.c
gcc "-DMYFILE=\"`basename $<`\"" -c -o file.o src/file.c
MYFILE
これにより、コードで の代わりに使用できるようになります__FILE__
。
basename
ソース ファイルを使用$<
すると、.c.o
. 次のコードは、その仕組みを示しています。makefile
まず、
mainprog: main.o makefile
gcc -o mainprog main.o
main.o: src/main.c makefile
gcc "-DMYFILE=\"`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:~$ mainprog
file = main.c
ディレクトリ名ではなく、ファイルのベース名のみfile =
を含む行に注意してください。
直接的な方法はわかりません。あなたが使用することができます:
#line 1 "filename.c"
ソースファイルの先頭に の値を設定しますが__FILE__
、それがハードコーディングよりもはるかに優れているかどうかはわかりません。または、#define を使用して独自のマクロを作成します。
別のオプションとして、-D と $(shell basename $<) を使用して Makefile から名前を渡すこともできます。
編集: #define または -D オプションを使用する場合は、独自の新しい名前を作成し、再定義しようとしないでください__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__ はソース ファイルのパス名です。オブジェクトに表示したい名前でビルドすれば、すべて問題ありません。
それが (何らかの理由で) 不可能な場合は、他の人が提案した修正に取り掛かる必要があります。
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}\"")
エラー ログ マクロは何をしますか? ある時点で、マクロが最終的に何らかの関数を呼び出してログを記録すると思いますが、呼び出された関数が実行時にパス コンポーネントを削除しないのはなぜですか?
#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
}
テンプレートのメタプログラミングでできるかもしれませんが、組み込みの方法はありません。
編集:うーん、訂正。私が見たあるページによると、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__を取り、パスの不要な部分を(プログラムで)削除することができます。basedirがあなたのニーズを満たしているなら、それなら大丈夫です。それ以外の場合は、ビルドシステムからソースディレクトリルートを取得し、残りは実行可能である必要があります。
同じ問題が発生しました。別の解決策を見つけたので、共有したいと思いました:
他のすべてのファイルに含まれるヘッダー ファイル:
static char * file_bname = NULL;
#define __STRIPPED_FILE__ (file_bname ?: (file_bname = basename(__FILE__)))
これが他の誰かにも役立つことを願っています:)