Получение базового имени исходного файла во время компиляции - PullRequest
15 голосов
/ 26 октября 2008

Я использую GCC; __FILE__ возвращает полный путь и имя текущего исходного файла: /path/to/file.cpp. Есть ли способ получить только имя файла file.cpp (без его пути) во время компиляции? Можно ли сделать это портативным способом? Может ли шаблонное метапрограммирование применяться к строкам?

Я использую это в макросе регистрации ошибок. Я действительно не хочу, чтобы полный путь моего источника попадал в исполняемый файл.

Ответы [ 13 ]

12 голосов
/ 26 октября 2008

Если вы используете программу 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". </p>

Следующий код иллюстрирует, как это работает.

Файл 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:~$

Обратите внимание на строку "file =", которая содержит только базовое имя файла, а не dirname.

5 голосов
/ 26 октября 2008

Рассмотрим этот простой исходный код:

#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__ - это путь к исходному файлу. Если вы строите с именем, которое хотите видеть в объекте, все хорошо.

Если это невозможно (по какой-либо причине), то вам придется заняться исправлениями, предложенными другими людьми.

4 голосов
/ 04 марта 2014

Поскольку вы отметили 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}\"")
4 голосов
/ 26 октября 2008

Что делает ваш макрос регистрации ошибок? Я бы предположил, что в какой-то момент макрос в конечном итоге вызывает какую-то функцию для ведения журнала, почему бы не вызвать вызываемую функцию срезать компонент пути во время выполнения?

#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 голосов
/ 26 октября 2008

Я не знаю прямого пути. Вы можете использовать:

#line 1 "filename.c"

в верхней части исходного файла для установки значения __FILE__, но я не уверен, что это намного лучше, чем жесткое его кодирование. или просто используйте #define для создания собственного макроса.

Другим вариантом может быть передача имени из вашего Makefile с использованием -D и $ (базовое имя оболочки $ <) </p>

Редактировать: если вы используете параметр #define или -D, вы должны создать свое собственное новое имя и не пытаться переопределять __FILE__.

3 голосов
/ 26 октября 2008

Возможно, вы сможете сделать это с помощью метапрограммирования шаблонов, но нет встроенного способа сделать это.

РЕДАКТИРОВАТЬ: Хм, коррекция. В соответствии с одной страницей, которую я только что увидел , GCC использует путь, указанный для файла. Если ему дадут полное имя, он его вставит; если ему дано только относительное, оно будет только встроено. Я сам не пробовал.

2 голосов
/ 26 октября 2008

Принимая идею от 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».

1 голос
/ 20 ноября 2008

Вы можете присвоить __FILE__ строке, а затем вызвать _splitpath (), чтобы вырвать из нее части. Это может быть решение только для Windows / MSVC, честно говоря, я не знаю.

Я знаю, что вы искали решение во время компиляции, и это решение во время выполнения, но я подумал, что поскольку вы используете имя файла для ведения (предположительно во время выполнения) регистрации ошибок, это может быть простой прямой способ чтобы получить то, что вам нужно.

0 голосов
/ 26 января 2019

Это легко с помощью 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 Лучше объявить в config.h.in -> config.h

#ifndef __RELATIVE_FILE_PATH__
#define __RELATIVE_FILE_PATH__ __FILE__
#endif

Так что ваш линтер не даст дождей ошибок.

0 голосов
/ 12 февраля 2010

Только что получил ту же проблему; нашел другое разрешение, просто решил поделиться им:

В заголовочном файле, включенном во все остальные мои файлы:

static char * file_bname = NULL;
#define __STRIPPED_FILE__   (file_bname ?: (file_bname = basename(__FILE__)))

Надеюсь, это будет полезно и кому-то еще:)

...