Получение базового имени исходного файла во время компиляции
Я использую GCC; __FILE__ возвращает текущий полный файл и имя исходного файла: /path/to/file.cpp
. Есть ли способ получить только имя файла file.cpp
(без его пути) во время компиляции? Можно ли это сделать переносным способом? Можно ли применять метапрограммирование шаблона к строкам?
Я использую это в макрос регистрации ошибок. Я действительно не хочу, чтобы мой исходный полный путь пробивался в исполняемый файл.
Ответы
Ответ 1
Если вы используете программу make, вы должны заранее указать имя файла и передать его в качестве макроса для gcc, который будет использоваться в вашей программе.
В своем make файле измените строку:
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__
.
Использование базового имени исходного файла ($ <) означает, что вы можете использовать его в обобщенных правилах, таких как ".c.o".
Следующий код иллюстрирует, как он работает.
Файл файла:
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;
}
Выполнить из оболочки:
[email protected]:~$ mainprog
file = main.c
[email protected]:~$
Обратите внимание на строку "file =", которая содержит только базовое имя файла, а не имя_файла.
Ответ 2
Рассмотрим этот простой исходный код:
#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__ - это путь к исходному файлу. Если вы создаете имя, которое хотите увидеть в объекте, все хорошо.
Если это невозможно (по какой-либо причине), вам придется попасть в исправления, предложенные другими людьми.
Ответ 3
Что делает ваш журнал регистрации ошибок? Я бы предположил, что в какой-то момент макрос в конечном итоге вызывает какую-то функцию для ведения журнала, почему бы не вызывать функцию вызова из компонента пути во время выполнения?
#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
}
Ответ 4
Возможно, вы сможете сделать это с помощью метапрограммирования шаблонов, но нет встроенного способа сделать это.
EDIT: Hm, коррекция. Согласно одна страница, которую я только что видел, GCC использует путь, который он дал для файла. Если он дал полное имя, он будет вставлять его; если он дает только относительный, он будет только вставлять это. Я не пробовал это сам, хотя.
Ответ 5
Я не знаю прямого пути. Вы можете использовать:
#line 1 "filename.c"
в верхней части исходного файла, чтобы установить значение __FILE__
, но я не уверен, что это намного лучше, чем жесткое его кодирование. или просто используя #define для создания собственного макроса.
Другой вариант может состоять в том, чтобы передать имя из вашего Makefile, используя -D и $(shell basename $<)
Изменить: если вы используете опцию #define или -D, вы должны создать свое собственное новое имя и не пытаться переопределить __FILE__
.
Ответ 6
Поскольку вы отметили 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}\"")
Ответ 7
Взяв эту идею из 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
'.
Ответ 8
Вы можете назначить __FILE__
строке, а затем вызвать _splitpath(), чтобы вырезать фрагменты из нее. Это может быть решение для Windows/MSVC, честно говоря, я не знаю.
Я знаю, что вы искали решение для компиляции, и это решение во время выполнения, но я понял, что, поскольку вы использовали регистрацию файла (предположительно во время выполнения), это может быть простым простым способом чтобы получить то, что вам нужно.
Ответ 9
Вы можете взять __FILE__ и полосу с той части пути, которую вы не хотите (программно). Если basedir удовлетворяет ваши потребности, то штраф. В противном случае получите исходный корневой каталог из вашей системы сборки, а остальная часть должна быть выполнимой.
Ответ 10
Может быть сделано ТОЛЬКО программно.
возможно, это полезно...
filename = __FILE__
len = strlen(filename)
char *temp = &filename[len -1]
while(*temp!= filename)
if(*temp == '\') break;
Ответ 11
Только та же проблема; нашел другое решение, просто подумал, что я поделюсь им:
В заголовочном файле, включенном во все мои другие файлы:
static char * file_bname = NULL;
#define __STRIPPED_FILE__ (file_bname ?: (file_bname = basename(__FILE__)))
Надеюсь, это полезно и для кого-то другого:)
Ответ 12
Это легко с 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 - моя ошибка
PS Лучше declear в config.h.in
→ config.h
#ifndef __RELATIVE_FILE_PATH__
#define __RELATIVE_FILE_PATH__ __FILE__
#endif
Таким образом, ваш линтер не даст дождя ошибок.
Ответ 13
Вы можете использовать:
bool IsDebugBuild()
{
return !NDEBUG;
}
Или вы можете использовать NDEBUG в своем Макро, чтобы включить/выключить эти пути к файлу.