2008-10-26 2 views
11

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

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

+0

Файла name - это имя, указанное компилятору. – 2008-10-26 04:32:31

+0

У моего источника есть структура каталогов, поэтому я не могу передать только имя файла компилятору. Кроме того, я использую CMake, который, кажется, всегда дает полный путь. Я думаю, что этот вопрос должен содержать тег C++, потому что шаблонное метапрограммирование может быть допустимым ответом? – Imbue 2008-10-26 04:40:52

ответ

10

Если вы используете программу грим, вы должны быть в состоянии munge имя файла заранее и передать его в качестве макроса ССАГПЗ для использования в вашей программе.

В вашем сборочном файле измените строку:

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».

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

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 

Файл ЦСИ/main.c:

#include <stdio.h> 

int main (int argc, char *argv[]) { 
    printf ("file = %s\n", __MYFILE__); 
    return 0; 
} 

Run из оболочки:

[email protected]:~$ mainprog 
file = main.c 
[email protected]:~$ 

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

3

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

EDIT: Hm, коррекция. Согласно one page I just saw, GCC использует путь, который он задает для файла. Если ему дано полное имя, оно будет вставлять его; если он будет дан только относительный, он будет только внедрять это. Я сам не пробовал.

+0

Я думал о метапрограммировании, но я даже не преуспел в передаче __FILE__ в качестве аргумента шаблона. – peterchen 2008-10-26 20:39:24

+0

Я изучаю, как это сделать с помощью метапрограммирования, в основном для моего личного просветления. Похоже, это должно быть возможно. Я отредактирую свой ответ, если/когда я придумаю решение. – 2008-10-27 16:53:23

2

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

#line 1 "filename.c" 

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

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

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

+0

Мессинг с предопределенными макросами - не очень хорошая идея. Поскольку они не определяются так же, как другие макросы, попытки их изменения будут специфичны для компилятора. – 2008-10-26 04:37:39

-4

Вы могли бы использовать:

bool IsDebugBuild() 
{ 
    return !NDEBUG; 
} 

Или, вы можете использовать NDEBUG в ваш макрос, чтобы включить/выключить эти файловые пути.

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 
} 
+0

Это останавливает полное имя файла, которое выводится в журналы, но все еще содержит его в исполняемом файле. Я думаю, это то, о чем спрашивал этот вопрос. Тем не менее, это хорошее решение, так что ни один downvote. – paxdiablo 2008-10-26 05:56:21

0

Вы можете взять __FILE__ и полосу от той части пути, которую вы не хотите (программно). Если basedir удовлетворяет ваши потребности, то штраф. В противном случае получите исходный корневой каталог из вашей системы сборки, а остальная часть должна быть выполнимой.

5

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

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

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

2

Принимая идею от Glomek, это может быть автоматизировано, как это:

Источник файла хс

#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».

0

Может быть сделано ТОЛЬКО программно.

может быть, это полезно ...

filename = __FILE__ 
len = strlen(filename) 

char *temp = &filename[len -1] 
while(*temp!= filename) 
    if(*temp == '\') break; 
1

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

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

0

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

В файле заголовка включен во все другие мои файлы:

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

Надежда это полезно для кого-то еще, а :)

2

Поскольку вы отметили 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}\"")